mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-07 11:46:30 +02:00
[FancyZones] Editor multi monitor support (#6562)
Co-authored-by: Enrico Giordani <enrico.giordani@gmail.com> Co-authored-by: Enrico Giordani <enricogior@users.noreply.github.com>
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Abstractions;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
|
||||
@@ -14,33 +13,21 @@ namespace FancyZonesEditor.Models
|
||||
// Free form Layout Model, which specifies independent zone rects
|
||||
public class CanvasLayoutModel : LayoutModel
|
||||
{
|
||||
// Localizable strings
|
||||
private const string ErrorPersistingCanvasLayout = "Error persisting canvas layout";
|
||||
|
||||
// Non-localizable strings
|
||||
private const string ModelTypeID = "canvas";
|
||||
|
||||
public CanvasLayoutModel(string uuid, string name, LayoutType type, IList<Int32Rect> zones, int workAreaWidth, int workAreaHeight)
|
||||
public Rect CanvasRect { get; private set; }
|
||||
|
||||
public CanvasLayoutModel(string uuid, string name, LayoutType type, IList<Int32Rect> zones, int width, int height)
|
||||
: base(uuid, name, type)
|
||||
{
|
||||
lastWorkAreaWidth = workAreaWidth;
|
||||
lastWorkAreaHeight = workAreaHeight;
|
||||
IsScaled = false;
|
||||
|
||||
if (ShouldScaleLayout())
|
||||
{
|
||||
ScaleLayout(zones);
|
||||
}
|
||||
else
|
||||
{
|
||||
Zones = zones;
|
||||
}
|
||||
Zones = zones;
|
||||
CanvasRect = new Rect(new Size(width, height));
|
||||
}
|
||||
|
||||
public CanvasLayoutModel(string name, LayoutType type)
|
||||
: base(name, type)
|
||||
{
|
||||
IsScaled = false;
|
||||
}
|
||||
|
||||
public CanvasLayoutModel(string name)
|
||||
@@ -51,12 +38,6 @@ namespace FancyZonesEditor.Models
|
||||
// Zones - the list of all zones in this layout, described as independent rectangles
|
||||
public IList<Int32Rect> Zones { get; private set; } = new List<Int32Rect>();
|
||||
|
||||
private int lastWorkAreaWidth = (int)Settings.WorkArea.Width;
|
||||
|
||||
private int lastWorkAreaHeight = (int)Settings.WorkArea.Height;
|
||||
|
||||
public bool IsScaled { get; private set; }
|
||||
|
||||
// RemoveZoneAt
|
||||
// Removes the specified index from the Zones list, and fires a property changed notification for the Zones property
|
||||
public void RemoveZoneAt(int index)
|
||||
@@ -102,34 +83,6 @@ namespace FancyZonesEditor.Models
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldScaleLayout()
|
||||
{
|
||||
// Scale if:
|
||||
// - at least one dimension changed
|
||||
// - orientation remained the same
|
||||
return (lastWorkAreaHeight != Settings.WorkArea.Height || lastWorkAreaWidth != Settings.WorkArea.Width) &&
|
||||
((lastWorkAreaHeight > lastWorkAreaWidth && Settings.WorkArea.Height > Settings.WorkArea.Width) ||
|
||||
(lastWorkAreaWidth > lastWorkAreaHeight && Settings.WorkArea.Width > Settings.WorkArea.Height));
|
||||
}
|
||||
|
||||
private void ScaleLayout(IList<Int32Rect> zones)
|
||||
{
|
||||
foreach (Int32Rect zone in zones)
|
||||
{
|
||||
double widthFactor = (double)Settings.WorkArea.Width / lastWorkAreaWidth;
|
||||
double heightFactor = (double)Settings.WorkArea.Height / lastWorkAreaHeight;
|
||||
int scaledX = (int)(zone.X * widthFactor);
|
||||
int scaledY = (int)(zone.Y * heightFactor);
|
||||
int scaledWidth = (int)(zone.Width * widthFactor);
|
||||
int scaledHeight = (int)(zone.Height * heightFactor);
|
||||
Zones.Add(new Int32Rect(scaledX, scaledY, scaledWidth, scaledHeight));
|
||||
}
|
||||
|
||||
lastWorkAreaHeight = (int)Settings.WorkArea.Height;
|
||||
lastWorkAreaWidth = (int)Settings.WorkArea.Width;
|
||||
IsScaled = true;
|
||||
}
|
||||
|
||||
private struct Zone
|
||||
{
|
||||
public int X { get; set; }
|
||||
@@ -165,13 +118,15 @@ namespace FancyZonesEditor.Models
|
||||
// Implements the LayoutModel.PersistData abstract method
|
||||
protected override void PersistData()
|
||||
{
|
||||
AddCustomLayout(this);
|
||||
|
||||
CanvasLayoutInfo layoutInfo = new CanvasLayoutInfo
|
||||
{
|
||||
RefWidth = lastWorkAreaWidth,
|
||||
RefHeight = lastWorkAreaHeight,
|
||||
|
||||
RefWidth = (int)CanvasRect.Width,
|
||||
RefHeight = (int)CanvasRect.Height,
|
||||
Zones = new Zone[Zones.Count],
|
||||
};
|
||||
|
||||
for (int i = 0; i < Zones.Count; ++i)
|
||||
{
|
||||
Zone zone = new Zone
|
||||
@@ -187,26 +142,19 @@ namespace FancyZonesEditor.Models
|
||||
|
||||
CanvasLayoutJson jsonObj = new CanvasLayoutJson
|
||||
{
|
||||
Uuid = "{" + Guid.ToString().ToUpper() + "}",
|
||||
Uuid = Uuid,
|
||||
Name = Name,
|
||||
Type = ModelTypeID,
|
||||
Info = layoutInfo,
|
||||
};
|
||||
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(jsonObj, options);
|
||||
FileSystem.File.WriteAllText(Settings.AppliedZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorPersistingCanvasLayout, ex);
|
||||
}
|
||||
string jsonString = JsonSerializer.Serialize(jsonObj, options);
|
||||
AddCustomLayoutJson(JsonSerializer.Deserialize<JsonElement>(jsonString));
|
||||
SerializeCreatedCustomZonesets();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace FancyZonesEditor.Utils
|
||||
{
|
||||
public class Device
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public Rect UnscaledBounds { get; private set; }
|
||||
|
||||
public Rect ScaledBounds { get; private set; }
|
||||
|
||||
public Rect WorkAreaRect { get; private set; }
|
||||
|
||||
public int Dpi { get; set; }
|
||||
|
||||
public bool Primary { get; private set; }
|
||||
|
||||
public Device(string id, int dpi, Rect bounds, Rect workArea, bool primary)
|
||||
{
|
||||
Id = id;
|
||||
Dpi = dpi;
|
||||
WorkAreaRect = workArea;
|
||||
UnscaledBounds = bounds;
|
||||
ScaledBounds = bounds;
|
||||
Primary = primary;
|
||||
}
|
||||
|
||||
public Device(Rect bounds, Rect workArea, bool primary)
|
||||
{
|
||||
WorkAreaRect = workArea;
|
||||
UnscaledBounds = bounds;
|
||||
ScaledBounds = bounds;
|
||||
Primary = primary;
|
||||
}
|
||||
|
||||
public void Scale(double scaleFactor)
|
||||
{
|
||||
WorkAreaRect = new Rect(Math.Round(WorkAreaRect.X * scaleFactor), Math.Round(WorkAreaRect.Y * scaleFactor), Math.Round(WorkAreaRect.Width * scaleFactor), Math.Round(WorkAreaRect.Height * scaleFactor));
|
||||
ScaledBounds = new Rect(Math.Round(ScaledBounds.X * scaleFactor), Math.Round(ScaledBounds.Y * scaleFactor), Math.Round(ScaledBounds.Width * scaleFactor), Math.Round(ScaledBounds.Height * scaleFactor));
|
||||
}
|
||||
|
||||
public double ScaleCoordinate(double coordinate)
|
||||
{
|
||||
float dpi = Dpi != 0 ? Dpi : 96f;
|
||||
double scaleFactor = 96f / dpi;
|
||||
return Math.Round(coordinate * scaleFactor);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append("ID: ");
|
||||
sb.AppendLine(Id);
|
||||
sb.Append("DPI: ");
|
||||
sb.AppendLine(Dpi.ToString());
|
||||
sb.Append("Is primary: ");
|
||||
sb.AppendLine(Primary.ToString());
|
||||
|
||||
string workArea = string.Format("({0}, {1}, {2}, {3})", WorkAreaRect.X, WorkAreaRect.Y, WorkAreaRect.Width, WorkAreaRect.Height);
|
||||
string bounds = string.Format("({0}, {1}, {2}, {3})", UnscaledBounds.X, UnscaledBounds.Y, UnscaledBounds.Width, UnscaledBounds.Height);
|
||||
string scaledBounds = string.Format("({0}, {1}, {2}, {3})", ScaledBounds.X, ScaledBounds.Y, ScaledBounds.Width, ScaledBounds.Height);
|
||||
|
||||
sb.Append("Work area: ");
|
||||
sb.AppendLine(workArea);
|
||||
sb.Append("Unscaled bounds: ");
|
||||
sb.AppendLine(bounds);
|
||||
sb.Append("Scaled bounds: ");
|
||||
sb.AppendLine(scaledBounds);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,6 @@ namespace FancyZonesEditor.Models
|
||||
// Grid-styled Layout Model, which specifies rows, columns, percentage sizes, and row/column spans
|
||||
public class GridLayoutModel : LayoutModel
|
||||
{
|
||||
// Localizable strings
|
||||
private const string ErrorPersistingGridLayout = "Error persisting grid layout";
|
||||
|
||||
// Non-localizable strings
|
||||
private const string ModelTypeID = "grid";
|
||||
|
||||
@@ -204,6 +201,8 @@ namespace FancyZonesEditor.Models
|
||||
// Implements the LayoutModel.PersistData abstract method
|
||||
protected override void PersistData()
|
||||
{
|
||||
AddCustomLayout(this);
|
||||
|
||||
GridLayoutInfo layoutInfo = new GridLayoutInfo
|
||||
{
|
||||
Rows = Rows,
|
||||
@@ -212,6 +211,7 @@ namespace FancyZonesEditor.Models
|
||||
ColumnsPercentage = ColumnPercents,
|
||||
CellChildMap = new int[Rows][],
|
||||
};
|
||||
|
||||
for (int row = 0; row < Rows; row++)
|
||||
{
|
||||
layoutInfo.CellChildMap[row] = new int[Columns];
|
||||
@@ -223,7 +223,7 @@ namespace FancyZonesEditor.Models
|
||||
|
||||
GridLayoutJson jsonObj = new GridLayoutJson
|
||||
{
|
||||
Uuid = "{" + Guid.ToString().ToUpper() + "}",
|
||||
Uuid = Uuid,
|
||||
Name = Name,
|
||||
Type = ModelTypeID,
|
||||
Info = layoutInfo,
|
||||
@@ -233,15 +233,9 @@ namespace FancyZonesEditor.Models
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(jsonObj, options);
|
||||
FileSystem.File.WriteAllText(Settings.AppliedZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorPersistingGridLayout, ex);
|
||||
}
|
||||
string jsonString = JsonSerializer.Serialize(jsonObj, options);
|
||||
AddCustomLayoutJson(JsonSerializer.Deserialize<JsonElement>(jsonString));
|
||||
SerializeCreatedCustomZonesets();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,77 +6,15 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
|
||||
namespace FancyZonesEditor.Models
|
||||
{
|
||||
public enum LayoutType
|
||||
{
|
||||
Blank = -1,
|
||||
Focus,
|
||||
Columns,
|
||||
Rows,
|
||||
Grid,
|
||||
PriorityGrid,
|
||||
Custom,
|
||||
}
|
||||
|
||||
// Base LayoutModel
|
||||
// Manages common properties and base persistence
|
||||
public abstract class LayoutModel : INotifyPropertyChanged
|
||||
{
|
||||
protected static readonly IFileSystem FileSystem = new FileSystem();
|
||||
|
||||
// Localizable strings
|
||||
private const string ErrorMessageBoxTitle = "FancyZones Editor Exception Handler";
|
||||
private const string ErrorMessageBoxMessage = "Please report the bug to ";
|
||||
private const string ErrorLayoutMalformedData = "Layout '{0}' has malformed data";
|
||||
private const string ErrorSerializingDeletedLayouts = "Error serializing deleted layouts";
|
||||
private const string ErrorLoadingCustomLayouts = "Error loading custom layouts";
|
||||
private const string ErrorApplyingLayout = "Error applying layout";
|
||||
|
||||
// Non-localizable strings
|
||||
private const string NameStr = "name";
|
||||
private const string CustomZoneSetsJsonTag = "custom-zone-sets";
|
||||
private const string TypeJsonTag = "type";
|
||||
private const string UuidJsonTag = "uuid";
|
||||
private const string InfoJsonTag = "info";
|
||||
private const string GridJsonTag = "grid";
|
||||
private const string RowsJsonTag = "rows";
|
||||
private const string ColumnsJsonTag = "columns";
|
||||
private const string RowsPercentageJsonTag = "rows-percentage";
|
||||
private const string ColumnsPercentageJsonTag = "columns-percentage";
|
||||
private const string CellChildMapJsonTag = "cell-child-map";
|
||||
private const string ZonesJsonTag = "zones";
|
||||
private const string CanvasJsonTag = "canvas";
|
||||
private const string RefWidthJsonTag = "ref-width";
|
||||
private const string RefHeightJsonTag = "ref-height";
|
||||
private const string XJsonTag = "X";
|
||||
private const string YJsonTag = "Y";
|
||||
private const string WidthJsonTag = "width";
|
||||
private const string HeightJsonTag = "height";
|
||||
private const string FocusJsonTag = "focus";
|
||||
private const string PriorityGridJsonTag = "priority-grid";
|
||||
private const string CustomJsonTag = "custom";
|
||||
|
||||
private const string PowerToysIssuesURL = "https://aka.ms/powerToysReportBug";
|
||||
|
||||
public static void ShowExceptionMessageBox(string message, Exception exception = null)
|
||||
{
|
||||
string fullMessage = ErrorMessageBoxMessage + PowerToysIssuesURL + " \n" + message;
|
||||
if (exception != null)
|
||||
{
|
||||
fullMessage += ": " + exception.Message;
|
||||
}
|
||||
|
||||
MessageBox.Show(fullMessage, ErrorMessageBoxTitle);
|
||||
}
|
||||
|
||||
protected LayoutModel()
|
||||
{
|
||||
_guid = Guid.NewGuid();
|
||||
@@ -136,6 +74,14 @@ namespace FancyZonesEditor.Models
|
||||
|
||||
private Guid _guid;
|
||||
|
||||
public string Uuid
|
||||
{
|
||||
get
|
||||
{
|
||||
return "{" + Guid.ToString().ToUpper() + "}";
|
||||
}
|
||||
}
|
||||
|
||||
// IsSelected (not-persisted) - tracks whether or not this LayoutModel is selected in the picker
|
||||
// TODO: once we switch to a picker per monitor, we need to move this state to the view
|
||||
public bool IsSelected
|
||||
@@ -157,6 +103,25 @@ namespace FancyZonesEditor.Models
|
||||
|
||||
private bool _isSelected;
|
||||
|
||||
public bool IsApplied
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isApplied;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_isApplied != value)
|
||||
{
|
||||
_isApplied = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isApplied;
|
||||
|
||||
// implementation of INotifyPropertyChanged
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
@@ -177,186 +142,52 @@ namespace FancyZonesEditor.Models
|
||||
}
|
||||
}
|
||||
|
||||
private struct DeletedCustomZoneSetsWrapper
|
||||
// Adds new custom Layout
|
||||
public void AddCustomLayout(LayoutModel model)
|
||||
{
|
||||
public List<string> DeletedCustomZoneSets { get; set; }
|
||||
bool updated = false;
|
||||
for (int i = 0; i < _customModels.Count && !updated; i++)
|
||||
{
|
||||
if (_customModels[i].Uuid == model.Uuid)
|
||||
{
|
||||
_customModels[i] = model;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!updated)
|
||||
{
|
||||
_customModels.Add(model);
|
||||
}
|
||||
}
|
||||
|
||||
// Add custom layouts json data that would be serialized to a temp file
|
||||
public void AddCustomLayoutJson(JsonElement json)
|
||||
{
|
||||
_createdCustomLayouts.Add(json);
|
||||
}
|
||||
|
||||
public static void SerializeDeletedCustomZoneSets()
|
||||
{
|
||||
DeletedCustomZoneSetsWrapper deletedLayouts = new DeletedCustomZoneSetsWrapper
|
||||
{
|
||||
DeletedCustomZoneSets = _deletedCustomModels,
|
||||
};
|
||||
App.FancyZonesEditorIO.SerializeDeletedCustomZoneSets(_deletedCustomModels);
|
||||
}
|
||||
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(deletedLayouts, options);
|
||||
FileSystem.File.WriteAllText(Settings.DeletedCustomZoneSetsTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorSerializingDeletedLayouts, ex);
|
||||
}
|
||||
public static void SerializeCreatedCustomZonesets()
|
||||
{
|
||||
App.FancyZonesEditorIO.SerializeCreatedCustomZonesets(_createdCustomLayouts);
|
||||
}
|
||||
|
||||
// Loads all the custom Layouts from tmp file passed by FancyZonesLib
|
||||
public static ObservableCollection<LayoutModel> LoadCustomModels()
|
||||
{
|
||||
_customModels = new ObservableCollection<LayoutModel>();
|
||||
|
||||
try
|
||||
{
|
||||
Stream inputStream = FileSystem.File.Open(Settings.FancyZonesSettingsFile, FileMode.Open);
|
||||
JsonDocument jsonObject = JsonDocument.Parse(inputStream, options: default);
|
||||
JsonElement.ArrayEnumerator customZoneSetsEnumerator = jsonObject.RootElement.GetProperty(CustomZoneSetsJsonTag).EnumerateArray();
|
||||
|
||||
while (customZoneSetsEnumerator.MoveNext())
|
||||
{
|
||||
var current = customZoneSetsEnumerator.Current;
|
||||
string name = current.GetProperty(NameStr).GetString();
|
||||
string type = current.GetProperty(TypeJsonTag).GetString();
|
||||
string uuid = current.GetProperty(UuidJsonTag).GetString();
|
||||
var info = current.GetProperty(InfoJsonTag);
|
||||
|
||||
if (type.Equals(GridJsonTag))
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
int rows = info.GetProperty(RowsJsonTag).GetInt32();
|
||||
int columns = info.GetProperty(ColumnsJsonTag).GetInt32();
|
||||
|
||||
List<int> rowsPercentage = new List<int>(rows);
|
||||
JsonElement.ArrayEnumerator rowsPercentageEnumerator = info.GetProperty(RowsPercentageJsonTag).EnumerateArray();
|
||||
|
||||
List<int> columnsPercentage = new List<int>(columns);
|
||||
JsonElement.ArrayEnumerator columnsPercentageEnumerator = info.GetProperty(ColumnsPercentageJsonTag).EnumerateArray();
|
||||
|
||||
if (rows <= 0 || columns <= 0 || rowsPercentageEnumerator.Count() != rows || columnsPercentageEnumerator.Count() != columns)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
|
||||
while (!error && rowsPercentageEnumerator.MoveNext())
|
||||
{
|
||||
int percentage = rowsPercentageEnumerator.Current.GetInt32();
|
||||
if (percentage <= 0)
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
rowsPercentage.Add(percentage);
|
||||
}
|
||||
|
||||
while (!error && columnsPercentageEnumerator.MoveNext())
|
||||
{
|
||||
int percentage = columnsPercentageEnumerator.Current.GetInt32();
|
||||
if (percentage <= 0)
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
columnsPercentage.Add(percentage);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
JsonElement.ArrayEnumerator cellChildMapRows = info.GetProperty(CellChildMapJsonTag).EnumerateArray();
|
||||
int[,] cellChildMap = new int[rows, columns];
|
||||
|
||||
if (cellChildMapRows.Count() != rows)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
|
||||
while (!error && cellChildMapRows.MoveNext())
|
||||
{
|
||||
int j = 0;
|
||||
JsonElement.ArrayEnumerator cellChildMapRowElems = cellChildMapRows.Current.EnumerateArray();
|
||||
if (cellChildMapRowElems.Count() != columns)
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
while (cellChildMapRowElems.MoveNext())
|
||||
{
|
||||
cellChildMap[i, j++] = cellChildMapRowElems.Current.GetInt32();
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
ShowExceptionMessageBox(string.Format(ErrorLayoutMalformedData, name));
|
||||
_deletedCustomModels.Add(Guid.Parse(uuid).ToString().ToUpper());
|
||||
continue;
|
||||
}
|
||||
|
||||
_customModels.Add(new GridLayoutModel(uuid, name, LayoutType.Custom, rows, columns, rowsPercentage, columnsPercentage, cellChildMap));
|
||||
}
|
||||
else if (type.Equals(CanvasJsonTag))
|
||||
{
|
||||
int lastWorkAreaWidth = info.GetProperty(RefWidthJsonTag).GetInt32();
|
||||
int lastWorkAreaHeight = info.GetProperty(RefHeightJsonTag).GetInt32();
|
||||
|
||||
JsonElement.ArrayEnumerator zonesEnumerator = info.GetProperty(ZonesJsonTag).EnumerateArray();
|
||||
IList<Int32Rect> zones = new List<Int32Rect>();
|
||||
|
||||
bool error = false;
|
||||
|
||||
if (lastWorkAreaWidth <= 0 || lastWorkAreaHeight <= 0)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
|
||||
while (!error && zonesEnumerator.MoveNext())
|
||||
{
|
||||
int x = zonesEnumerator.Current.GetProperty(XJsonTag).GetInt32();
|
||||
int y = zonesEnumerator.Current.GetProperty(YJsonTag).GetInt32();
|
||||
int width = zonesEnumerator.Current.GetProperty(WidthJsonTag).GetInt32();
|
||||
int height = zonesEnumerator.Current.GetProperty(HeightJsonTag).GetInt32();
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
zones.Add(new Int32Rect(x, y, width, height));
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
ShowExceptionMessageBox(string.Format(ErrorLayoutMalformedData, name));
|
||||
_deletedCustomModels.Add(Guid.Parse(uuid).ToString().ToUpper());
|
||||
continue;
|
||||
}
|
||||
|
||||
_customModels.Add(new CanvasLayoutModel(uuid, name, LayoutType.Custom, zones, lastWorkAreaWidth, lastWorkAreaHeight));
|
||||
}
|
||||
}
|
||||
|
||||
inputStream.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorLoadingCustomLayouts, ex);
|
||||
return new ObservableCollection<LayoutModel>();
|
||||
}
|
||||
|
||||
App.FancyZonesEditorIO.ParseLayouts(ref _customModels, ref _deletedCustomModels);
|
||||
return _customModels;
|
||||
}
|
||||
|
||||
private static ObservableCollection<LayoutModel> _customModels = null;
|
||||
private static List<string> _deletedCustomModels = new List<string>();
|
||||
private static List<JsonElement> _createdCustomLayouts = new List<JsonElement>();
|
||||
|
||||
// Callbacks that the base LayoutModel makes to derived types
|
||||
protected abstract void PersistData();
|
||||
@@ -369,83 +200,18 @@ namespace FancyZonesEditor.Models
|
||||
Apply();
|
||||
}
|
||||
|
||||
private struct ActiveZoneSetWrapper
|
||||
{
|
||||
public string Uuid { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
}
|
||||
|
||||
private struct AppliedZoneSet
|
||||
{
|
||||
public string DeviceId { get; set; }
|
||||
|
||||
public ActiveZoneSetWrapper ActiveZoneset { get; set; }
|
||||
|
||||
public bool EditorShowSpacing { get; set; }
|
||||
|
||||
public int EditorSpacing { get; set; }
|
||||
|
||||
public int EditorZoneCount { get; set; }
|
||||
|
||||
public int EditorSensitivityRadius { get; set; }
|
||||
}
|
||||
|
||||
public void Apply()
|
||||
{
|
||||
ActiveZoneSetWrapper activeZoneSet = new ActiveZoneSetWrapper
|
||||
{
|
||||
Uuid = "{" + Guid.ToString().ToUpper() + "}",
|
||||
};
|
||||
MainWindowSettingsModel settings = ((App)App.Current).MainWindowSettings;
|
||||
settings.ResetAppliedModel();
|
||||
IsApplied = true;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case LayoutType.Focus:
|
||||
activeZoneSet.Type = FocusJsonTag;
|
||||
break;
|
||||
case LayoutType.Rows:
|
||||
activeZoneSet.Type = RowsJsonTag;
|
||||
break;
|
||||
case LayoutType.Columns:
|
||||
activeZoneSet.Type = ColumnsJsonTag;
|
||||
break;
|
||||
case LayoutType.Grid:
|
||||
activeZoneSet.Type = GridJsonTag;
|
||||
break;
|
||||
case LayoutType.PriorityGrid:
|
||||
activeZoneSet.Type = PriorityGridJsonTag;
|
||||
break;
|
||||
case LayoutType.Custom:
|
||||
activeZoneSet.Type = CustomJsonTag;
|
||||
break;
|
||||
}
|
||||
// update settings
|
||||
App.Overlay.CurrentLayoutSettings.ZonesetUuid = Uuid;
|
||||
App.Overlay.CurrentLayoutSettings.Type = Type;
|
||||
|
||||
Settings settings = ((App)Application.Current).ZoneSettings;
|
||||
|
||||
AppliedZoneSet zoneSet = new AppliedZoneSet
|
||||
{
|
||||
DeviceId = Settings.UniqueKey,
|
||||
ActiveZoneset = activeZoneSet,
|
||||
EditorShowSpacing = settings.ShowSpacing,
|
||||
EditorSpacing = settings.Spacing,
|
||||
EditorZoneCount = settings.ZoneCount,
|
||||
EditorSensitivityRadius = settings.SensitivityRadius,
|
||||
};
|
||||
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(zoneSet, options);
|
||||
FileSystem.File.WriteAllText(Settings.ActiveZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorApplyingLayout, ex);
|
||||
}
|
||||
// update temp file
|
||||
App.FancyZonesEditorIO.SerializeAppliedLayouts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using FancyZonesEditor.Models;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
public class LayoutSettings
|
||||
{
|
||||
public static bool DefaultShowSpacing => true;
|
||||
|
||||
public static int DefaultSpacing => 16;
|
||||
|
||||
public static int DefaultZoneCount => 3;
|
||||
|
||||
public static int DefaultSensitivityRadius => 20;
|
||||
|
||||
public string DeviceId { get; set; } = string.Empty;
|
||||
|
||||
public string ZonesetUuid { get; set; } = string.Empty;
|
||||
|
||||
public LayoutType Type { get; set; } = LayoutType.PriorityGrid;
|
||||
|
||||
public bool ShowSpacing { get; set; } = DefaultShowSpacing;
|
||||
|
||||
public int Spacing { get; set; } = DefaultSpacing;
|
||||
|
||||
public int ZoneCount { get; set; } = DefaultZoneCount;
|
||||
|
||||
public int SensitivityRadius { get; set; } = DefaultSensitivityRadius;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace FancyZonesEditor.Models
|
||||
{
|
||||
public enum LayoutType
|
||||
{
|
||||
Blank = -1,
|
||||
Focus,
|
||||
Columns,
|
||||
Rows,
|
||||
Grid,
|
||||
PriorityGrid,
|
||||
Custom,
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
@@ -6,10 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
using FancyZonesEditor.Models;
|
||||
|
||||
@@ -18,30 +15,16 @@ namespace FancyZonesEditor
|
||||
// Settings
|
||||
// These are the configuration settings used by the rest of the editor
|
||||
// Other UIs in the editor will subscribe to change events on the properties to stay up to date as these properties change
|
||||
public class Settings : INotifyPropertyChanged
|
||||
public class MainWindowSettingsModel : INotifyPropertyChanged
|
||||
{
|
||||
private enum CmdArgs
|
||||
private enum DeviceIdParts
|
||||
{
|
||||
WorkAreaSize = 1,
|
||||
PowerToysPID,
|
||||
}
|
||||
|
||||
private enum WorkAreaCmdArgElements
|
||||
{
|
||||
X = 0,
|
||||
Y,
|
||||
Name = 0,
|
||||
Width,
|
||||
Height,
|
||||
VirtualDesktopId,
|
||||
}
|
||||
|
||||
private enum ParseDeviceMode
|
||||
{
|
||||
Prod,
|
||||
Debug,
|
||||
}
|
||||
|
||||
private static readonly IFileSystem _fileSystem = new FileSystem();
|
||||
|
||||
private static CanvasLayoutModel _blankCustomModel;
|
||||
private readonly CanvasLayoutModel _focusModel;
|
||||
private readonly GridLayoutModel _rowsModel;
|
||||
@@ -63,33 +46,9 @@ namespace FancyZonesEditor
|
||||
public static readonly string RegistryPath = "SOFTWARE\\SuperFancyZones";
|
||||
public static readonly string FullRegistryPath = "HKEY_CURRENT_USER\\" + RegistryPath;
|
||||
|
||||
private const string ZonesSettingsFile = "\\Microsoft\\PowerToys\\FancyZones\\zones-settings.json";
|
||||
private const string ActiveZoneSetsTmpFileName = "FancyZonesActiveZoneSets.json";
|
||||
private const string AppliedZoneSetsTmpFileName = "FancyZonesAppliedZoneSets.json";
|
||||
private const string DeletedCustomZoneSetsTmpFileName = "FancyZonesDeletedCustomZoneSets.json";
|
||||
|
||||
private const string LayoutTypeBlankStr = "blank";
|
||||
private const string NullUuidStr = "null";
|
||||
|
||||
// DeviceInfo JSON tags
|
||||
private const string DeviceIdJsonTag = "device-id";
|
||||
private const string ActiveZoneSetJsonTag = "active-zoneset";
|
||||
private const string UuidJsonTag = "uuid";
|
||||
private const string TypeJsonTag = "type";
|
||||
private const string EditorShowSpacingJsonTag = "editor-show-spacing";
|
||||
private const string EditorSpacingJsonTag = "editor-spacing";
|
||||
private const string EditorZoneCountJsonTag = "editor-zone-count";
|
||||
private const string EditorSensitivityRadiusJsonTag = "editor-sensitivity-radius";
|
||||
|
||||
private const string FocusJsonTag = "focus";
|
||||
private const string ColumnsJsonTag = "columns";
|
||||
private const string RowsJsonTag = "rows";
|
||||
private const string GridJsonTag = "grid";
|
||||
private const string PriorityGridJsonTag = "priority-grid";
|
||||
private const string CustomJsonTag = "custom";
|
||||
|
||||
private const string DebugMode = "Debug";
|
||||
|
||||
// hard coded data for all the "Priority Grid" configurations that are unique to "Grid"
|
||||
private static readonly byte[][] _priorityData = new byte[][]
|
||||
{
|
||||
@@ -124,19 +83,8 @@ namespace FancyZonesEditor
|
||||
}
|
||||
}
|
||||
|
||||
public Settings()
|
||||
public MainWindowSettingsModel()
|
||||
{
|
||||
string tmpDirPath = _fileSystem.Path.GetTempPath();
|
||||
|
||||
ActiveZoneSetTmpFile = tmpDirPath + ActiveZoneSetsTmpFileName;
|
||||
AppliedZoneSetTmpFile = tmpDirPath + AppliedZoneSetsTmpFileName;
|
||||
DeletedCustomZoneSetsTmpFile = tmpDirPath + DeletedCustomZoneSetsTmpFileName;
|
||||
|
||||
var localAppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
FancyZonesSettingsFile = localAppDataDir + ZonesSettingsFile;
|
||||
|
||||
ParseCommandLineArgs();
|
||||
|
||||
// Initialize the five default layout models: Focus, Columns, Rows, Grid, and PriorityGrid
|
||||
DefaultModels = new List<LayoutModel>(5);
|
||||
_focusModel = new CanvasLayoutModel(Properties.Resources.Template_Layout_Focus, LayoutType.Focus);
|
||||
@@ -164,7 +112,7 @@ namespace FancyZonesEditor
|
||||
|
||||
_blankCustomModel = new CanvasLayoutModel(Properties.Resources.Custom_Layout_Create_New, LayoutType.Blank);
|
||||
|
||||
UpdateLayoutModels();
|
||||
UpdateTemplateLayoutModels();
|
||||
}
|
||||
|
||||
// ZoneCount - number of zones selected in the picker window
|
||||
@@ -172,82 +120,79 @@ namespace FancyZonesEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
return _zoneCount;
|
||||
return App.Overlay.CurrentLayoutSettings.ZoneCount;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_zoneCount != value)
|
||||
if (App.Overlay.CurrentLayoutSettings.ZoneCount != value)
|
||||
{
|
||||
_zoneCount = value;
|
||||
UpdateLayoutModels();
|
||||
FirePropertyChanged();
|
||||
App.Overlay.CurrentLayoutSettings.ZoneCount = value;
|
||||
UpdateTemplateLayoutModels();
|
||||
FirePropertyChanged(nameof(ZoneCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _zoneCount;
|
||||
|
||||
// Spacing - how much space in between zones of the grid do you want
|
||||
public int Spacing
|
||||
{
|
||||
get
|
||||
{
|
||||
return _spacing;
|
||||
return App.Overlay.CurrentLayoutSettings.Spacing;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_spacing != value)
|
||||
value = Math.Max(0, value);
|
||||
if (App.Overlay.CurrentLayoutSettings.Spacing != value)
|
||||
{
|
||||
_spacing = Math.Max(MaxNegativeSpacing, value);
|
||||
FirePropertyChanged();
|
||||
App.Overlay.CurrentLayoutSettings.Spacing = value;
|
||||
UpdateTemplateLayoutModels();
|
||||
FirePropertyChanged(nameof(Spacing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _spacing;
|
||||
|
||||
// ShowSpacing - is the Spacing value used or ignored?
|
||||
public bool ShowSpacing
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showSpacing;
|
||||
return App.Overlay.CurrentLayoutSettings.ShowSpacing;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_showSpacing != value)
|
||||
if (App.Overlay.CurrentLayoutSettings.ShowSpacing != value)
|
||||
{
|
||||
_showSpacing = value;
|
||||
FirePropertyChanged();
|
||||
App.Overlay.CurrentLayoutSettings.ShowSpacing = value;
|
||||
UpdateTemplateLayoutModels();
|
||||
FirePropertyChanged(nameof(ShowSpacing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _showSpacing;
|
||||
|
||||
// SensitivityRadius - how much space inside the zone to highlight the adjacent zone too
|
||||
public int SensitivityRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return _sensitivityRadius;
|
||||
return App.Overlay.CurrentLayoutSettings.SensitivityRadius;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_sensitivityRadius != value)
|
||||
value = Math.Max(0, value);
|
||||
if (App.Overlay.CurrentLayoutSettings.SensitivityRadius != value)
|
||||
{
|
||||
_sensitivityRadius = Math.Max(0, value);
|
||||
FirePropertyChanged();
|
||||
App.Overlay.CurrentLayoutSettings.SensitivityRadius = value;
|
||||
UpdateTemplateLayoutModels();
|
||||
FirePropertyChanged(nameof(SensitivityRadius));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _sensitivityRadius;
|
||||
|
||||
// IsShiftKeyPressed - is the shift key currently being held down
|
||||
public bool IsShiftKeyPressed
|
||||
{
|
||||
@@ -261,7 +206,7 @@ namespace FancyZonesEditor
|
||||
if (_isShiftKeyPressed != value)
|
||||
{
|
||||
_isShiftKeyPressed = value;
|
||||
FirePropertyChanged();
|
||||
FirePropertyChanged(nameof(IsShiftKeyPressed));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,41 +226,16 @@ namespace FancyZonesEditor
|
||||
if (_isCtrlKeyPressed != value)
|
||||
{
|
||||
_isCtrlKeyPressed = value;
|
||||
FirePropertyChanged();
|
||||
FirePropertyChanged(nameof(IsCtrlKeyPressed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isCtrlKeyPressed;
|
||||
|
||||
public static Rect WorkArea { get; private set; }
|
||||
|
||||
public static List<Rect> UsedWorkAreas { get; private set; }
|
||||
|
||||
public static string UniqueKey { get; private set; }
|
||||
|
||||
public static string ActiveZoneSetUUid { get; private set; }
|
||||
|
||||
public static LayoutType ActiveZoneSetLayoutType { get; private set; }
|
||||
|
||||
public static string ActiveZoneSetTmpFile { get; private set; }
|
||||
|
||||
public static string AppliedZoneSetTmpFile { get; private set; }
|
||||
|
||||
public static string DeletedCustomZoneSetsTmpFile { get; private set; }
|
||||
|
||||
public static string FancyZonesSettingsFile { get; private set; }
|
||||
|
||||
public static int PowerToysPID
|
||||
{
|
||||
get { return _powerToysPID; }
|
||||
}
|
||||
|
||||
private static int _powerToysPID;
|
||||
|
||||
// UpdateLayoutModels
|
||||
// Update the five default layouts based on the new ZoneCount
|
||||
private void UpdateLayoutModels()
|
||||
private void UpdateTemplateLayoutModels()
|
||||
{
|
||||
// Update the "Focus" Default Layout
|
||||
_focusModel.Zones.Clear();
|
||||
@@ -328,9 +248,13 @@ namespace FancyZonesEditor
|
||||
|
||||
// If changing focus layout zones size and/or increment,
|
||||
// same change should be applied in ZoneSet.cpp (ZoneSet::CalculateFocusLayout)
|
||||
Int32Rect focusZoneRect = new Int32Rect(100, 100, (int)(WorkArea.Width * 0.4), (int)(WorkArea.Height * 0.4));
|
||||
int focusRectXIncrement = (ZoneCount <= 1) ? 0 : 50;
|
||||
int focusRectYIncrement = (ZoneCount <= 1) ? 0 : 50;
|
||||
var workingArea = App.Overlay.WorkArea;
|
||||
int topLeftCoordinate = (int)App.Overlay.ScaleCoordinateWithCurrentMonitorDpi(100); // TODO: replace magic numbers
|
||||
int width = (int)(workingArea.Width * 0.4);
|
||||
int height = (int)(workingArea.Height * 0.4);
|
||||
Int32Rect focusZoneRect = new Int32Rect(topLeftCoordinate, topLeftCoordinate, width, height);
|
||||
int focusRectXIncrement = (ZoneCount <= 1) ? 0 : (int)App.Overlay.ScaleCoordinateWithCurrentMonitorDpi(50);
|
||||
int focusRectYIncrement = (ZoneCount <= 1) ? 0 : (int)App.Overlay.ScaleCoordinateWithCurrentMonitorDpi(50);
|
||||
|
||||
for (int i = 0; i < ZoneCount; i++)
|
||||
{
|
||||
@@ -422,128 +346,6 @@ namespace FancyZonesEditor
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseDeviceInfoData(ParseDeviceMode mode = ParseDeviceMode.Prod)
|
||||
{
|
||||
try
|
||||
{
|
||||
string layoutType = LayoutTypeBlankStr;
|
||||
ActiveZoneSetUUid = NullUuidStr;
|
||||
JsonElement jsonObject = default(JsonElement);
|
||||
|
||||
if (_fileSystem.File.Exists(Settings.ActiveZoneSetTmpFile))
|
||||
{
|
||||
Stream inputStream = _fileSystem.File.Open(Settings.ActiveZoneSetTmpFile, FileMode.Open);
|
||||
jsonObject = JsonDocument.Parse(inputStream, options: default).RootElement;
|
||||
inputStream.Close();
|
||||
UniqueKey = jsonObject.GetProperty(DeviceIdJsonTag).GetString();
|
||||
ActiveZoneSetUUid = jsonObject.GetProperty(ActiveZoneSetJsonTag).GetProperty(UuidJsonTag).GetString();
|
||||
layoutType = jsonObject.GetProperty(ActiveZoneSetJsonTag).GetProperty(TypeJsonTag).GetString();
|
||||
}
|
||||
|
||||
if (mode == ParseDeviceMode.Debug || ActiveZoneSetUUid == NullUuidStr || layoutType == LayoutTypeBlankStr)
|
||||
{
|
||||
// Default or there is no active layout on current device
|
||||
ActiveZoneSetLayoutType = LayoutType.Focus;
|
||||
_showSpacing = true;
|
||||
_spacing = 16;
|
||||
_zoneCount = 3;
|
||||
_sensitivityRadius = 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (layoutType)
|
||||
{
|
||||
case FocusJsonTag:
|
||||
ActiveZoneSetLayoutType = LayoutType.Focus;
|
||||
break;
|
||||
case ColumnsJsonTag:
|
||||
ActiveZoneSetLayoutType = LayoutType.Columns;
|
||||
break;
|
||||
case RowsJsonTag:
|
||||
ActiveZoneSetLayoutType = LayoutType.Rows;
|
||||
break;
|
||||
case GridJsonTag:
|
||||
ActiveZoneSetLayoutType = LayoutType.Grid;
|
||||
break;
|
||||
case PriorityGridJsonTag:
|
||||
ActiveZoneSetLayoutType = LayoutType.PriorityGrid;
|
||||
break;
|
||||
case CustomJsonTag:
|
||||
ActiveZoneSetLayoutType = LayoutType.Custom;
|
||||
break;
|
||||
}
|
||||
|
||||
_showSpacing = jsonObject.GetProperty(EditorShowSpacingJsonTag).GetBoolean();
|
||||
_spacing = jsonObject.GetProperty(EditorSpacingJsonTag).GetInt32();
|
||||
_zoneCount = jsonObject.GetProperty(EditorZoneCountJsonTag).GetInt32();
|
||||
_sensitivityRadius = jsonObject.GetProperty(EditorSensitivityRadiusJsonTag).GetInt32();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LayoutModel.ShowExceptionMessageBox(Properties.Resources.Error_Parsing_Device_Info, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseCommandLineArgs()
|
||||
{
|
||||
WorkArea = SystemParameters.WorkArea;
|
||||
UsedWorkAreas = new List<Rect> { WorkArea };
|
||||
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
|
||||
if (args.Length == 2)
|
||||
{
|
||||
if (args[1].Equals(DebugMode))
|
||||
{
|
||||
ParseDeviceInfoData(ParseDeviceMode.Debug);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Properties.Resources.Error_Invalid_Arguments, Properties.Resources.Error_Message_Box_Title);
|
||||
((App)Application.Current).Shutdown();
|
||||
}
|
||||
}
|
||||
else if (args.Length == 3)
|
||||
{
|
||||
UsedWorkAreas.Clear();
|
||||
foreach (var singleMonitorString in args[(int)CmdArgs.WorkAreaSize].Split('/'))
|
||||
{
|
||||
var parsedLocation = singleMonitorString.Split('_');
|
||||
if (parsedLocation.Length != 4)
|
||||
{
|
||||
MessageBox.Show(Properties.Resources.Error_Invalid_Arguments, Properties.Resources.Error_Message_Box_Title);
|
||||
((App)Application.Current).Shutdown();
|
||||
}
|
||||
|
||||
var x = int.Parse(parsedLocation[(int)WorkAreaCmdArgElements.X]);
|
||||
var y = int.Parse(parsedLocation[(int)WorkAreaCmdArgElements.Y]);
|
||||
var width = int.Parse(parsedLocation[(int)WorkAreaCmdArgElements.Width]);
|
||||
var height = int.Parse(parsedLocation[(int)WorkAreaCmdArgElements.Height]);
|
||||
|
||||
Rect thisMonitor = new Rect(x, y, width, height);
|
||||
if (UsedWorkAreas.Count == 0)
|
||||
{
|
||||
WorkArea = thisMonitor;
|
||||
}
|
||||
else
|
||||
{
|
||||
WorkArea = Rect.Union(WorkArea, thisMonitor);
|
||||
}
|
||||
|
||||
UsedWorkAreas.Add(thisMonitor);
|
||||
}
|
||||
|
||||
int.TryParse(args[(int)CmdArgs.PowerToysPID], out _powerToysPID);
|
||||
ParseDeviceInfoData();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(Properties.Resources.Error_Invalid_Arguments, Properties.Resources.Error_Message_Box_Title);
|
||||
((App)Application.Current).Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public IList<LayoutModel> DefaultModels { get; }
|
||||
|
||||
public static ObservableCollection<LayoutModel> CustomModels
|
||||
@@ -567,6 +369,120 @@ namespace FancyZonesEditor
|
||||
return model.Type != LayoutType.Custom;
|
||||
}
|
||||
|
||||
public LayoutModel UpdateSelectedLayoutModel()
|
||||
{
|
||||
UpdateTemplateLayoutModels();
|
||||
ResetAppliedModel();
|
||||
ResetSelectedModel();
|
||||
|
||||
LayoutModel foundModel = null;
|
||||
LayoutSettings currentApplied = App.Overlay.CurrentLayoutSettings;
|
||||
|
||||
// set new layout
|
||||
if (currentApplied.Type == LayoutType.Custom)
|
||||
{
|
||||
foreach (LayoutModel model in MainWindowSettingsModel.CustomModels)
|
||||
{
|
||||
if ("{" + model.Guid.ToString().ToUpper() + "}" == currentApplied.ZonesetUuid.ToUpper())
|
||||
{
|
||||
// found match
|
||||
foundModel = model;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (LayoutModel model in DefaultModels)
|
||||
{
|
||||
if (model.Type == currentApplied.Type)
|
||||
{
|
||||
// found match
|
||||
foundModel = model;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundModel == null)
|
||||
{
|
||||
foundModel = DefaultModels[0];
|
||||
}
|
||||
|
||||
foundModel.IsSelected = true;
|
||||
foundModel.IsApplied = true;
|
||||
|
||||
FirePropertyChanged(nameof(IsCustomLayoutActive));
|
||||
return foundModel;
|
||||
}
|
||||
|
||||
public void ResetSelectedModel()
|
||||
{
|
||||
foreach (LayoutModel model in CustomModels)
|
||||
{
|
||||
if (model.IsSelected)
|
||||
{
|
||||
model.IsSelected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (LayoutModel model in DefaultModels)
|
||||
{
|
||||
if (model.IsSelected)
|
||||
{
|
||||
model.IsSelected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetAppliedModel()
|
||||
{
|
||||
foreach (LayoutModel model in CustomModels)
|
||||
{
|
||||
if (model.IsApplied)
|
||||
{
|
||||
model.IsApplied = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (LayoutModel model in DefaultModels)
|
||||
{
|
||||
if (model.IsApplied)
|
||||
{
|
||||
model.IsApplied = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateDesktopDependantProperties(LayoutSettings prevSettings)
|
||||
{
|
||||
UpdateTemplateLayoutModels();
|
||||
|
||||
if (prevSettings.ZoneCount != ZoneCount)
|
||||
{
|
||||
FirePropertyChanged(nameof(ZoneCount));
|
||||
}
|
||||
|
||||
if (prevSettings.Spacing != Spacing)
|
||||
{
|
||||
FirePropertyChanged(nameof(Spacing));
|
||||
}
|
||||
|
||||
if (prevSettings.ShowSpacing != ShowSpacing)
|
||||
{
|
||||
FirePropertyChanged(nameof(ShowSpacing));
|
||||
}
|
||||
|
||||
if (prevSettings.SensitivityRadius != SensitivityRadius)
|
||||
{
|
||||
FirePropertyChanged(nameof(SensitivityRadius));
|
||||
}
|
||||
}
|
||||
|
||||
// implementation of INotifyPropertyChanged
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using FancyZonesEditor.Utils;
|
||||
|
||||
namespace FancyZonesEditor.Models
|
||||
{
|
||||
public class Monitor
|
||||
{
|
||||
public LayoutOverlayWindow Window { get; private set; }
|
||||
|
||||
public LayoutSettings Settings { get; set; }
|
||||
|
||||
public Device Device { get; set; }
|
||||
|
||||
public Monitor(Rect bounds, Rect workArea, bool primary)
|
||||
{
|
||||
Window = new LayoutOverlayWindow();
|
||||
Settings = new LayoutSettings();
|
||||
Device = new Device(bounds, workArea, primary);
|
||||
|
||||
if (App.DebugMode)
|
||||
{
|
||||
long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
|
||||
PropertyInfo[] properties = typeof(Brushes).GetProperties();
|
||||
Window.Opacity = 0.5;
|
||||
Window.Background = (Brush)properties[milliseconds % properties.Length].GetValue(null, null);
|
||||
}
|
||||
|
||||
Window.Left = workArea.X;
|
||||
Window.Top = workArea.Y;
|
||||
Window.Width = workArea.Width;
|
||||
Window.Height = workArea.Height;
|
||||
}
|
||||
|
||||
public Monitor(string id, int dpi, Rect bounds, Rect workArea, bool primary)
|
||||
: this(bounds, workArea, primary)
|
||||
{
|
||||
Device = new Device(id, dpi, bounds, workArea, primary);
|
||||
}
|
||||
|
||||
public void Scale(double scaleFactor)
|
||||
{
|
||||
Device.Scale(scaleFactor);
|
||||
|
||||
var workArea = Device.WorkAreaRect;
|
||||
Window.Left = workArea.X;
|
||||
Window.Top = workArea.Y;
|
||||
Window.Width = workArea.Width;
|
||||
Window.Height = workArea.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.ComponentModel;
|
||||
using FancyZonesEditor.ViewModels;
|
||||
|
||||
namespace FancyZonesEditor.Utils
|
||||
{
|
||||
public class MonitorInfoModel : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public MonitorInfoModel(int index, int height, int width, int dpi, bool selected = false)
|
||||
{
|
||||
Index = index;
|
||||
ScreenBoundsHeight = height;
|
||||
ScreenBoundsWidth = width;
|
||||
DPI = dpi;
|
||||
Selected = selected;
|
||||
}
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public int ScreenBoundsHeight { get; set; }
|
||||
|
||||
public double DisplayHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScreenBoundsHeight * MonitorViewModel.DesktopPreviewMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
public int ScreenBoundsWidth { get; set; }
|
||||
|
||||
public double DisplayWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScreenBoundsWidth * MonitorViewModel.DesktopPreviewMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
public int DPI { get; set; }
|
||||
|
||||
public string Dimensions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (App.DebugMode)
|
||||
{
|
||||
var rect = App.Overlay.Monitors[Index - 1].Device.WorkAreaRect;
|
||||
return "Screen: (" + rect.X + ", " + rect.Y + "); (" + rect.Width + ", " + rect.Height + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
return ScreenBoundsWidth + " x " + ScreenBoundsHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Selected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _selected;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_selected == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_selected = value;
|
||||
OnPropertyChanged(nameof(Selected));
|
||||
}
|
||||
}
|
||||
|
||||
private bool _selected;
|
||||
|
||||
protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user