mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-07 11:46:30 +02:00
whitespace forced changes (#6002)
This commit is contained in:
@@ -1,212 +1,212 @@
|
||||
// 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;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
|
||||
namespace FancyZonesEditor.Models
|
||||
{
|
||||
// CanvasLayoutModel
|
||||
// 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)
|
||||
: base(uuid, name, type)
|
||||
{
|
||||
lastWorkAreaWidth = workAreaWidth;
|
||||
lastWorkAreaHeight = workAreaHeight;
|
||||
IsScaled = false;
|
||||
|
||||
if (ShouldScaleLayout())
|
||||
{
|
||||
ScaleLayout(zones);
|
||||
}
|
||||
else
|
||||
{
|
||||
Zones = zones;
|
||||
}
|
||||
}
|
||||
|
||||
public CanvasLayoutModel(string name, LayoutType type)
|
||||
: base(name, type)
|
||||
{
|
||||
IsScaled = false;
|
||||
}
|
||||
|
||||
public CanvasLayoutModel(string name)
|
||||
: base(name)
|
||||
{
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
Zones.RemoveAt(index);
|
||||
UpdateLayout();
|
||||
}
|
||||
|
||||
// AddZone
|
||||
// Adds the specified Zone to the end of the Zones list, and fires a property changed notification for the Zones property
|
||||
public void AddZone(Int32Rect zone)
|
||||
{
|
||||
Zones.Add(zone);
|
||||
UpdateLayout();
|
||||
}
|
||||
|
||||
private void UpdateLayout()
|
||||
{
|
||||
FirePropertyChanged();
|
||||
}
|
||||
|
||||
// Clone
|
||||
// Implements the LayoutModel.Clone abstract method
|
||||
// Clones the data from this CanvasLayoutModel to a new CanvasLayoutModel
|
||||
public override LayoutModel Clone()
|
||||
{
|
||||
CanvasLayoutModel layout = new CanvasLayoutModel(Name);
|
||||
|
||||
foreach (Int32Rect zone in Zones)
|
||||
{
|
||||
layout.Zones.Add(zone);
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
public void RestoreTo(CanvasLayoutModel other)
|
||||
{
|
||||
other.Zones.Clear();
|
||||
foreach (Int32Rect zone in Zones)
|
||||
{
|
||||
other.Zones.Add(zone);
|
||||
}
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
public int Y { get; set; }
|
||||
|
||||
public int Width { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
}
|
||||
|
||||
private struct CanvasLayoutInfo
|
||||
{
|
||||
public int RefWidth { get; set; }
|
||||
|
||||
public int RefHeight { get; set; }
|
||||
|
||||
public Zone[] Zones { get; set; }
|
||||
}
|
||||
|
||||
private struct CanvasLayoutJson
|
||||
{
|
||||
public string Uuid { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
|
||||
public CanvasLayoutInfo Info { get; set; }
|
||||
}
|
||||
|
||||
// PersistData
|
||||
// Implements the LayoutModel.PersistData abstract method
|
||||
protected override void PersistData()
|
||||
{
|
||||
CanvasLayoutInfo layoutInfo = new CanvasLayoutInfo
|
||||
{
|
||||
RefWidth = lastWorkAreaWidth,
|
||||
RefHeight = lastWorkAreaHeight,
|
||||
|
||||
Zones = new Zone[Zones.Count],
|
||||
};
|
||||
for (int i = 0; i < Zones.Count; ++i)
|
||||
{
|
||||
Zone zone = new Zone
|
||||
{
|
||||
X = Zones[i].X,
|
||||
Y = Zones[i].Y,
|
||||
Width = Zones[i].Width,
|
||||
Height = Zones[i].Height,
|
||||
};
|
||||
|
||||
layoutInfo.Zones[i] = zone;
|
||||
}
|
||||
|
||||
CanvasLayoutJson jsonObj = new CanvasLayoutJson
|
||||
{
|
||||
Uuid = "{" + Guid.ToString().ToUpper() + "}",
|
||||
Name = Name,
|
||||
Type = ModelTypeID,
|
||||
Info = layoutInfo,
|
||||
};
|
||||
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(jsonObj, options);
|
||||
File.WriteAllText(Settings.AppliedZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorPersistingCanvasLayout, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
|
||||
namespace FancyZonesEditor.Models
|
||||
{
|
||||
// CanvasLayoutModel
|
||||
// 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)
|
||||
: base(uuid, name, type)
|
||||
{
|
||||
lastWorkAreaWidth = workAreaWidth;
|
||||
lastWorkAreaHeight = workAreaHeight;
|
||||
IsScaled = false;
|
||||
|
||||
if (ShouldScaleLayout())
|
||||
{
|
||||
ScaleLayout(zones);
|
||||
}
|
||||
else
|
||||
{
|
||||
Zones = zones;
|
||||
}
|
||||
}
|
||||
|
||||
public CanvasLayoutModel(string name, LayoutType type)
|
||||
: base(name, type)
|
||||
{
|
||||
IsScaled = false;
|
||||
}
|
||||
|
||||
public CanvasLayoutModel(string name)
|
||||
: base(name)
|
||||
{
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
Zones.RemoveAt(index);
|
||||
UpdateLayout();
|
||||
}
|
||||
|
||||
// AddZone
|
||||
// Adds the specified Zone to the end of the Zones list, and fires a property changed notification for the Zones property
|
||||
public void AddZone(Int32Rect zone)
|
||||
{
|
||||
Zones.Add(zone);
|
||||
UpdateLayout();
|
||||
}
|
||||
|
||||
private void UpdateLayout()
|
||||
{
|
||||
FirePropertyChanged();
|
||||
}
|
||||
|
||||
// Clone
|
||||
// Implements the LayoutModel.Clone abstract method
|
||||
// Clones the data from this CanvasLayoutModel to a new CanvasLayoutModel
|
||||
public override LayoutModel Clone()
|
||||
{
|
||||
CanvasLayoutModel layout = new CanvasLayoutModel(Name);
|
||||
|
||||
foreach (Int32Rect zone in Zones)
|
||||
{
|
||||
layout.Zones.Add(zone);
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
public void RestoreTo(CanvasLayoutModel other)
|
||||
{
|
||||
other.Zones.Clear();
|
||||
foreach (Int32Rect zone in Zones)
|
||||
{
|
||||
other.Zones.Add(zone);
|
||||
}
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
public int Y { get; set; }
|
||||
|
||||
public int Width { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
}
|
||||
|
||||
private struct CanvasLayoutInfo
|
||||
{
|
||||
public int RefWidth { get; set; }
|
||||
|
||||
public int RefHeight { get; set; }
|
||||
|
||||
public Zone[] Zones { get; set; }
|
||||
}
|
||||
|
||||
private struct CanvasLayoutJson
|
||||
{
|
||||
public string Uuid { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
|
||||
public CanvasLayoutInfo Info { get; set; }
|
||||
}
|
||||
|
||||
// PersistData
|
||||
// Implements the LayoutModel.PersistData abstract method
|
||||
protected override void PersistData()
|
||||
{
|
||||
CanvasLayoutInfo layoutInfo = new CanvasLayoutInfo
|
||||
{
|
||||
RefWidth = lastWorkAreaWidth,
|
||||
RefHeight = lastWorkAreaHeight,
|
||||
|
||||
Zones = new Zone[Zones.Count],
|
||||
};
|
||||
for (int i = 0; i < Zones.Count; ++i)
|
||||
{
|
||||
Zone zone = new Zone
|
||||
{
|
||||
X = Zones[i].X,
|
||||
Y = Zones[i].Y,
|
||||
Width = Zones[i].Width,
|
||||
Height = Zones[i].Height,
|
||||
};
|
||||
|
||||
layoutInfo.Zones[i] = zone;
|
||||
}
|
||||
|
||||
CanvasLayoutJson jsonObj = new CanvasLayoutJson
|
||||
{
|
||||
Uuid = "{" + Guid.ToString().ToUpper() + "}",
|
||||
Name = Name,
|
||||
Type = ModelTypeID,
|
||||
Info = layoutInfo,
|
||||
};
|
||||
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(jsonObj, options);
|
||||
File.WriteAllText(Settings.AppliedZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorPersistingCanvasLayout, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,248 +1,248 @@
|
||||
// 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;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
|
||||
namespace FancyZonesEditor.Models
|
||||
{
|
||||
// GridLayoutModel
|
||||
// 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";
|
||||
|
||||
// Rows - number of rows in the Grid
|
||||
public int Rows
|
||||
{
|
||||
get
|
||||
{
|
||||
return _rows;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_rows != value)
|
||||
{
|
||||
_rows = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _rows = 1;
|
||||
|
||||
// Columns - number of columns in the Grid
|
||||
public int Columns
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cols;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_cols != value)
|
||||
{
|
||||
_cols = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _cols = 1;
|
||||
|
||||
// CellChildMap - represents which "children" belong in which grid cells;
|
||||
// shows spanning children by the same index appearing in adjacent cells
|
||||
// TODO: ideally no setter here - this means moving logic like "split" over to model
|
||||
public int[,] CellChildMap { get; set; }
|
||||
|
||||
// RowPercents - represents the %age height of each row in the grid
|
||||
public List<int> RowPercents { get; set; }
|
||||
|
||||
// ColumnPercents - represents the %age width of each column in the grid
|
||||
public List<int> ColumnPercents { get; set; }
|
||||
|
||||
// FreeZones (not persisted) - used to keep track of child indices that are no longer in use in the CellChildMap,
|
||||
// making them candidates for re-use when it's needed to add another child
|
||||
// TODO: do I need FreeZones on the data model? - I think I do
|
||||
public IList<int> FreeZones { get; } = new List<int>();
|
||||
|
||||
public GridLayoutModel()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public GridLayoutModel(string name)
|
||||
: base(name)
|
||||
{
|
||||
}
|
||||
|
||||
public GridLayoutModel(string name, LayoutType type)
|
||||
: base(name, type)
|
||||
{
|
||||
}
|
||||
|
||||
public GridLayoutModel(string uuid, string name, LayoutType type, int rows, int cols, List<int> rowPercents, List<int> colsPercents, int[,] cellChildMap)
|
||||
: base(uuid, name, type)
|
||||
{
|
||||
_rows = rows;
|
||||
_cols = cols;
|
||||
RowPercents = rowPercents;
|
||||
ColumnPercents = colsPercents;
|
||||
CellChildMap = cellChildMap;
|
||||
}
|
||||
|
||||
public void Reload(byte[] data)
|
||||
{
|
||||
// Skip version (2 bytes), id (2 bytes), and type (1 bytes)
|
||||
int i = 5;
|
||||
|
||||
Rows = data[i++];
|
||||
Columns = data[i++];
|
||||
|
||||
RowPercents = new List<int>(Rows);
|
||||
for (int row = 0; row < Rows; row++)
|
||||
{
|
||||
RowPercents.Add((data[i++] * 256) + data[i++]);
|
||||
}
|
||||
|
||||
ColumnPercents = new List<int>(Columns);
|
||||
for (int col = 0; col < Columns; col++)
|
||||
{
|
||||
ColumnPercents.Add((data[i++] * 256) + data[i++]);
|
||||
}
|
||||
|
||||
CellChildMap = new int[Rows, Columns];
|
||||
for (int row = 0; row < Rows; row++)
|
||||
{
|
||||
for (int col = 0; col < Columns; col++)
|
||||
{
|
||||
CellChildMap[row, col] = data[i++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone
|
||||
// Implements the LayoutModel.Clone abstract method
|
||||
// Clones the data from this GridLayoutModel to a new GridLayoutModel
|
||||
public override LayoutModel Clone()
|
||||
{
|
||||
GridLayoutModel layout = new GridLayoutModel(Name);
|
||||
RestoreTo(layout);
|
||||
return layout;
|
||||
}
|
||||
|
||||
public void RestoreTo(GridLayoutModel layout)
|
||||
{
|
||||
int rows = Rows;
|
||||
int cols = Columns;
|
||||
|
||||
layout.Rows = rows;
|
||||
layout.Columns = cols;
|
||||
|
||||
int[,] cellChildMap = new int[rows, cols];
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
for (int col = 0; col < cols; col++)
|
||||
{
|
||||
cellChildMap[row, col] = CellChildMap[row, col];
|
||||
}
|
||||
}
|
||||
|
||||
layout.CellChildMap = cellChildMap;
|
||||
|
||||
List<int> rowPercents = new List<int>(rows);
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
rowPercents.Add(RowPercents[row]);
|
||||
}
|
||||
|
||||
layout.RowPercents = rowPercents;
|
||||
|
||||
List<int> colPercents = new List<int>(cols);
|
||||
for (int col = 0; col < cols; col++)
|
||||
{
|
||||
colPercents.Add(ColumnPercents[col]);
|
||||
}
|
||||
|
||||
layout.ColumnPercents = colPercents;
|
||||
}
|
||||
|
||||
private struct GridLayoutInfo
|
||||
{
|
||||
public int Rows { get; set; }
|
||||
|
||||
public int Columns { get; set; }
|
||||
|
||||
public List<int> RowsPercentage { get; set; }
|
||||
|
||||
public List<int> ColumnsPercentage { get; set; }
|
||||
|
||||
public int[][] CellChildMap { get; set; }
|
||||
}
|
||||
|
||||
private struct GridLayoutJson
|
||||
{
|
||||
public string Uuid { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
|
||||
public GridLayoutInfo Info { get; set; }
|
||||
}
|
||||
|
||||
// PersistData
|
||||
// Implements the LayoutModel.PersistData abstract method
|
||||
protected override void PersistData()
|
||||
{
|
||||
GridLayoutInfo layoutInfo = new GridLayoutInfo
|
||||
{
|
||||
Rows = Rows,
|
||||
Columns = Columns,
|
||||
RowsPercentage = RowPercents,
|
||||
ColumnsPercentage = ColumnPercents,
|
||||
CellChildMap = new int[Rows][],
|
||||
};
|
||||
for (int row = 0; row < Rows; row++)
|
||||
{
|
||||
layoutInfo.CellChildMap[row] = new int[Columns];
|
||||
for (int col = 0; col < Columns; col++)
|
||||
{
|
||||
layoutInfo.CellChildMap[row][col] = CellChildMap[row, col];
|
||||
}
|
||||
}
|
||||
|
||||
GridLayoutJson jsonObj = new GridLayoutJson
|
||||
{
|
||||
Uuid = "{" + Guid.ToString().ToUpper() + "}",
|
||||
Name = Name,
|
||||
Type = ModelTypeID,
|
||||
Info = layoutInfo,
|
||||
};
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(jsonObj, options);
|
||||
File.WriteAllText(Settings.AppliedZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorPersistingGridLayout, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
|
||||
namespace FancyZonesEditor.Models
|
||||
{
|
||||
// GridLayoutModel
|
||||
// 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";
|
||||
|
||||
// Rows - number of rows in the Grid
|
||||
public int Rows
|
||||
{
|
||||
get
|
||||
{
|
||||
return _rows;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_rows != value)
|
||||
{
|
||||
_rows = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _rows = 1;
|
||||
|
||||
// Columns - number of columns in the Grid
|
||||
public int Columns
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cols;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_cols != value)
|
||||
{
|
||||
_cols = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _cols = 1;
|
||||
|
||||
// CellChildMap - represents which "children" belong in which grid cells;
|
||||
// shows spanning children by the same index appearing in adjacent cells
|
||||
// TODO: ideally no setter here - this means moving logic like "split" over to model
|
||||
public int[,] CellChildMap { get; set; }
|
||||
|
||||
// RowPercents - represents the %age height of each row in the grid
|
||||
public List<int> RowPercents { get; set; }
|
||||
|
||||
// ColumnPercents - represents the %age width of each column in the grid
|
||||
public List<int> ColumnPercents { get; set; }
|
||||
|
||||
// FreeZones (not persisted) - used to keep track of child indices that are no longer in use in the CellChildMap,
|
||||
// making them candidates for re-use when it's needed to add another child
|
||||
// TODO: do I need FreeZones on the data model? - I think I do
|
||||
public IList<int> FreeZones { get; } = new List<int>();
|
||||
|
||||
public GridLayoutModel()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public GridLayoutModel(string name)
|
||||
: base(name)
|
||||
{
|
||||
}
|
||||
|
||||
public GridLayoutModel(string name, LayoutType type)
|
||||
: base(name, type)
|
||||
{
|
||||
}
|
||||
|
||||
public GridLayoutModel(string uuid, string name, LayoutType type, int rows, int cols, List<int> rowPercents, List<int> colsPercents, int[,] cellChildMap)
|
||||
: base(uuid, name, type)
|
||||
{
|
||||
_rows = rows;
|
||||
_cols = cols;
|
||||
RowPercents = rowPercents;
|
||||
ColumnPercents = colsPercents;
|
||||
CellChildMap = cellChildMap;
|
||||
}
|
||||
|
||||
public void Reload(byte[] data)
|
||||
{
|
||||
// Skip version (2 bytes), id (2 bytes), and type (1 bytes)
|
||||
int i = 5;
|
||||
|
||||
Rows = data[i++];
|
||||
Columns = data[i++];
|
||||
|
||||
RowPercents = new List<int>(Rows);
|
||||
for (int row = 0; row < Rows; row++)
|
||||
{
|
||||
RowPercents.Add((data[i++] * 256) + data[i++]);
|
||||
}
|
||||
|
||||
ColumnPercents = new List<int>(Columns);
|
||||
for (int col = 0; col < Columns; col++)
|
||||
{
|
||||
ColumnPercents.Add((data[i++] * 256) + data[i++]);
|
||||
}
|
||||
|
||||
CellChildMap = new int[Rows, Columns];
|
||||
for (int row = 0; row < Rows; row++)
|
||||
{
|
||||
for (int col = 0; col < Columns; col++)
|
||||
{
|
||||
CellChildMap[row, col] = data[i++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone
|
||||
// Implements the LayoutModel.Clone abstract method
|
||||
// Clones the data from this GridLayoutModel to a new GridLayoutModel
|
||||
public override LayoutModel Clone()
|
||||
{
|
||||
GridLayoutModel layout = new GridLayoutModel(Name);
|
||||
RestoreTo(layout);
|
||||
return layout;
|
||||
}
|
||||
|
||||
public void RestoreTo(GridLayoutModel layout)
|
||||
{
|
||||
int rows = Rows;
|
||||
int cols = Columns;
|
||||
|
||||
layout.Rows = rows;
|
||||
layout.Columns = cols;
|
||||
|
||||
int[,] cellChildMap = new int[rows, cols];
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
for (int col = 0; col < cols; col++)
|
||||
{
|
||||
cellChildMap[row, col] = CellChildMap[row, col];
|
||||
}
|
||||
}
|
||||
|
||||
layout.CellChildMap = cellChildMap;
|
||||
|
||||
List<int> rowPercents = new List<int>(rows);
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
rowPercents.Add(RowPercents[row]);
|
||||
}
|
||||
|
||||
layout.RowPercents = rowPercents;
|
||||
|
||||
List<int> colPercents = new List<int>(cols);
|
||||
for (int col = 0; col < cols; col++)
|
||||
{
|
||||
colPercents.Add(ColumnPercents[col]);
|
||||
}
|
||||
|
||||
layout.ColumnPercents = colPercents;
|
||||
}
|
||||
|
||||
private struct GridLayoutInfo
|
||||
{
|
||||
public int Rows { get; set; }
|
||||
|
||||
public int Columns { get; set; }
|
||||
|
||||
public List<int> RowsPercentage { get; set; }
|
||||
|
||||
public List<int> ColumnsPercentage { get; set; }
|
||||
|
||||
public int[][] CellChildMap { get; set; }
|
||||
}
|
||||
|
||||
private struct GridLayoutJson
|
||||
{
|
||||
public string Uuid { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
|
||||
public GridLayoutInfo Info { get; set; }
|
||||
}
|
||||
|
||||
// PersistData
|
||||
// Implements the LayoutModel.PersistData abstract method
|
||||
protected override void PersistData()
|
||||
{
|
||||
GridLayoutInfo layoutInfo = new GridLayoutInfo
|
||||
{
|
||||
Rows = Rows,
|
||||
Columns = Columns,
|
||||
RowsPercentage = RowPercents,
|
||||
ColumnsPercentage = ColumnPercents,
|
||||
CellChildMap = new int[Rows][],
|
||||
};
|
||||
for (int row = 0; row < Rows; row++)
|
||||
{
|
||||
layoutInfo.CellChildMap[row] = new int[Columns];
|
||||
for (int col = 0; col < Columns; col++)
|
||||
{
|
||||
layoutInfo.CellChildMap[row][col] = CellChildMap[row, col];
|
||||
}
|
||||
}
|
||||
|
||||
GridLayoutJson jsonObj = new GridLayoutJson
|
||||
{
|
||||
Uuid = "{" + Guid.ToString().ToUpper() + "}",
|
||||
Name = Name,
|
||||
Type = ModelTypeID,
|
||||
Info = layoutInfo,
|
||||
};
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(jsonObj, options);
|
||||
File.WriteAllText(Settings.AppliedZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorPersistingGridLayout, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,443 +1,443 @@
|
||||
// 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.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
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
|
||||
{
|
||||
// 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 PowerToysIssuesLink = "https://aka.ms/powerToysReportBug";
|
||||
|
||||
public static void ShowExceptionMessageBox(string message, Exception exception = null)
|
||||
{
|
||||
string fullMessage = ErrorMessageBoxMessage + PowerToysIssuesLink + " \n" + message;
|
||||
if (exception != null)
|
||||
{
|
||||
fullMessage += ": " + exception.Message;
|
||||
}
|
||||
|
||||
MessageBox.Show(fullMessage, ErrorMessageBoxTitle);
|
||||
}
|
||||
|
||||
protected LayoutModel()
|
||||
{
|
||||
_guid = Guid.NewGuid();
|
||||
Type = LayoutType.Custom;
|
||||
}
|
||||
|
||||
protected LayoutModel(string name)
|
||||
: this()
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
protected LayoutModel(string uuid, string name, LayoutType type)
|
||||
: this()
|
||||
{
|
||||
_guid = Guid.Parse(uuid);
|
||||
Name = name;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
protected LayoutModel(string name, LayoutType type)
|
||||
: this(name)
|
||||
{
|
||||
_guid = Guid.NewGuid();
|
||||
Type = type;
|
||||
}
|
||||
|
||||
// Name - the display name for this layout model - is also used as the key in the registry
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_name != value)
|
||||
{
|
||||
_name = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _name;
|
||||
|
||||
public LayoutType Type { get; set; }
|
||||
|
||||
public Guid Guid
|
||||
{
|
||||
get
|
||||
{
|
||||
return _guid;
|
||||
}
|
||||
}
|
||||
|
||||
private Guid _guid;
|
||||
|
||||
// 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
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isSelected;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_isSelected != value)
|
||||
{
|
||||
_isSelected = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isSelected;
|
||||
|
||||
// implementation of INotifyPropertyChanged
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
// FirePropertyChanged -- wrapper that calls INPC.PropertyChanged
|
||||
protected virtual void FirePropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
// Removes this Layout from the registry and the loaded CustomModels list
|
||||
public void Delete()
|
||||
{
|
||||
int i = _customModels.IndexOf(this);
|
||||
if (i != -1)
|
||||
{
|
||||
_customModels.RemoveAt(i);
|
||||
_deletedCustomModels.Add(Guid.ToString().ToUpper());
|
||||
}
|
||||
}
|
||||
|
||||
private struct DeletedCustomZoneSetsWrapper
|
||||
{
|
||||
public List<string> DeletedCustomZoneSets { get; set; }
|
||||
}
|
||||
|
||||
public static void SerializeDeletedCustomZoneSets()
|
||||
{
|
||||
DeletedCustomZoneSetsWrapper deletedLayouts = new DeletedCustomZoneSetsWrapper
|
||||
{
|
||||
DeletedCustomZoneSets = _deletedCustomModels,
|
||||
};
|
||||
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(deletedLayouts, options);
|
||||
File.WriteAllText(Settings.DeletedCustomZoneSetsTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorSerializingDeletedLayouts, ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Loads all the custom Layouts from tmp file passed by FancyZonesLib
|
||||
public static ObservableCollection<LayoutModel> LoadCustomModels()
|
||||
{
|
||||
_customModels = new ObservableCollection<LayoutModel>();
|
||||
|
||||
try
|
||||
{
|
||||
FileStream inputStream = 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));
|
||||
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));
|
||||
continue;
|
||||
}
|
||||
|
||||
_customModels.Add(new CanvasLayoutModel(uuid, name, LayoutType.Custom, zones, lastWorkAreaWidth, lastWorkAreaHeight));
|
||||
}
|
||||
}
|
||||
|
||||
inputStream.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorLoadingCustomLayouts, ex);
|
||||
return new ObservableCollection<LayoutModel>();
|
||||
}
|
||||
|
||||
return _customModels;
|
||||
}
|
||||
|
||||
private static ObservableCollection<LayoutModel> _customModels = null;
|
||||
private static List<string> _deletedCustomModels = new List<string>();
|
||||
|
||||
// Callbacks that the base LayoutModel makes to derived types
|
||||
protected abstract void PersistData();
|
||||
|
||||
public abstract LayoutModel Clone();
|
||||
|
||||
public void Persist()
|
||||
{
|
||||
PersistData();
|
||||
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 void Apply()
|
||||
{
|
||||
ActiveZoneSetWrapper activeZoneSet = new ActiveZoneSetWrapper
|
||||
{
|
||||
Uuid = "{" + Guid.ToString().ToUpper() + "}",
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Settings settings = ((App)Application.Current).ZoneSettings;
|
||||
|
||||
AppliedZoneSet zoneSet = new AppliedZoneSet
|
||||
{
|
||||
DeviceId = Settings.UniqueKey,
|
||||
ActiveZoneset = activeZoneSet,
|
||||
EditorShowSpacing = settings.ShowSpacing,
|
||||
EditorSpacing = settings.Spacing,
|
||||
EditorZoneCount = settings.ZoneCount,
|
||||
};
|
||||
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(zoneSet, options);
|
||||
File.WriteAllText(Settings.ActiveZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorApplyingLayout, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
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
|
||||
{
|
||||
// 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 PowerToysIssuesLink = "https://aka.ms/powerToysReportBug";
|
||||
|
||||
public static void ShowExceptionMessageBox(string message, Exception exception = null)
|
||||
{
|
||||
string fullMessage = ErrorMessageBoxMessage + PowerToysIssuesLink + " \n" + message;
|
||||
if (exception != null)
|
||||
{
|
||||
fullMessage += ": " + exception.Message;
|
||||
}
|
||||
|
||||
MessageBox.Show(fullMessage, ErrorMessageBoxTitle);
|
||||
}
|
||||
|
||||
protected LayoutModel()
|
||||
{
|
||||
_guid = Guid.NewGuid();
|
||||
Type = LayoutType.Custom;
|
||||
}
|
||||
|
||||
protected LayoutModel(string name)
|
||||
: this()
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
protected LayoutModel(string uuid, string name, LayoutType type)
|
||||
: this()
|
||||
{
|
||||
_guid = Guid.Parse(uuid);
|
||||
Name = name;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
protected LayoutModel(string name, LayoutType type)
|
||||
: this(name)
|
||||
{
|
||||
_guid = Guid.NewGuid();
|
||||
Type = type;
|
||||
}
|
||||
|
||||
// Name - the display name for this layout model - is also used as the key in the registry
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_name != value)
|
||||
{
|
||||
_name = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _name;
|
||||
|
||||
public LayoutType Type { get; set; }
|
||||
|
||||
public Guid Guid
|
||||
{
|
||||
get
|
||||
{
|
||||
return _guid;
|
||||
}
|
||||
}
|
||||
|
||||
private Guid _guid;
|
||||
|
||||
// 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
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isSelected;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_isSelected != value)
|
||||
{
|
||||
_isSelected = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isSelected;
|
||||
|
||||
// implementation of INotifyPropertyChanged
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
// FirePropertyChanged -- wrapper that calls INPC.PropertyChanged
|
||||
protected virtual void FirePropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
// Removes this Layout from the registry and the loaded CustomModels list
|
||||
public void Delete()
|
||||
{
|
||||
int i = _customModels.IndexOf(this);
|
||||
if (i != -1)
|
||||
{
|
||||
_customModels.RemoveAt(i);
|
||||
_deletedCustomModels.Add(Guid.ToString().ToUpper());
|
||||
}
|
||||
}
|
||||
|
||||
private struct DeletedCustomZoneSetsWrapper
|
||||
{
|
||||
public List<string> DeletedCustomZoneSets { get; set; }
|
||||
}
|
||||
|
||||
public static void SerializeDeletedCustomZoneSets()
|
||||
{
|
||||
DeletedCustomZoneSetsWrapper deletedLayouts = new DeletedCustomZoneSetsWrapper
|
||||
{
|
||||
DeletedCustomZoneSets = _deletedCustomModels,
|
||||
};
|
||||
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(deletedLayouts, options);
|
||||
File.WriteAllText(Settings.DeletedCustomZoneSetsTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorSerializingDeletedLayouts, ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Loads all the custom Layouts from tmp file passed by FancyZonesLib
|
||||
public static ObservableCollection<LayoutModel> LoadCustomModels()
|
||||
{
|
||||
_customModels = new ObservableCollection<LayoutModel>();
|
||||
|
||||
try
|
||||
{
|
||||
FileStream inputStream = 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));
|
||||
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));
|
||||
continue;
|
||||
}
|
||||
|
||||
_customModels.Add(new CanvasLayoutModel(uuid, name, LayoutType.Custom, zones, lastWorkAreaWidth, lastWorkAreaHeight));
|
||||
}
|
||||
}
|
||||
|
||||
inputStream.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorLoadingCustomLayouts, ex);
|
||||
return new ObservableCollection<LayoutModel>();
|
||||
}
|
||||
|
||||
return _customModels;
|
||||
}
|
||||
|
||||
private static ObservableCollection<LayoutModel> _customModels = null;
|
||||
private static List<string> _deletedCustomModels = new List<string>();
|
||||
|
||||
// Callbacks that the base LayoutModel makes to derived types
|
||||
protected abstract void PersistData();
|
||||
|
||||
public abstract LayoutModel Clone();
|
||||
|
||||
public void Persist()
|
||||
{
|
||||
PersistData();
|
||||
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 void Apply()
|
||||
{
|
||||
ActiveZoneSetWrapper activeZoneSet = new ActiveZoneSetWrapper
|
||||
{
|
||||
Uuid = "{" + Guid.ToString().ToUpper() + "}",
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Settings settings = ((App)Application.Current).ZoneSettings;
|
||||
|
||||
AppliedZoneSet zoneSet = new AppliedZoneSet
|
||||
{
|
||||
DeviceId = Settings.UniqueKey,
|
||||
ActiveZoneset = activeZoneSet,
|
||||
EditorShowSpacing = settings.ShowSpacing,
|
||||
EditorSpacing = settings.Spacing,
|
||||
EditorZoneCount = settings.ZoneCount,
|
||||
};
|
||||
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(zoneSet, options);
|
||||
File.WriteAllText(Settings.ActiveZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowExceptionMessageBox(ErrorApplyingLayout, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user