mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 10:46:33 +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:
@@ -13,8 +13,8 @@ Global
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|Any CPU.ActiveCfg = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|Any CPU.Build.0 = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|Any CPU.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -3,4 +3,7 @@
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
|
||||
</startup>
|
||||
<runtime>
|
||||
<AppContextSwitchOverrides value = "Switch.System.Windows.DoNotScaleForDpiChanges=false"/>
|
||||
</runtime>
|
||||
</configuration>
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
// 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.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using FancyZonesEditor.Models;
|
||||
using FancyZonesEditor.Utils;
|
||||
using ManagedCommon;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
@@ -24,6 +23,7 @@ namespace FancyZonesEditor
|
||||
{
|
||||
// Non-localizable strings
|
||||
private const string CrashReportLogFile = "FZEditorCrashLog.txt";
|
||||
private const string ErrorReportLogFile = "FZEditorErrorLog.txt";
|
||||
private const string PowerToysIssuesURL = "https://aka.ms/powerToysReportBug";
|
||||
|
||||
private const string CrashReportExceptionTag = "Exception";
|
||||
@@ -44,57 +44,76 @@ namespace FancyZonesEditor
|
||||
|
||||
private readonly IFileSystem _fileSystem = new FileSystem();
|
||||
|
||||
public Settings ZoneSettings { get; }
|
||||
public MainWindowSettingsModel MainWindowSettings { get; }
|
||||
|
||||
public static FancyZonesEditorIO FancyZonesEditorIO { get; private set; }
|
||||
|
||||
public static Overlay Overlay { get; private set; }
|
||||
|
||||
public static int PowerToysPID { get; set; }
|
||||
|
||||
public static bool DebugMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _debugMode;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool _debugMode = false;
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void DebugModeCheck()
|
||||
{
|
||||
_debugMode = true;
|
||||
}
|
||||
|
||||
public App()
|
||||
{
|
||||
ZoneSettings = new Settings();
|
||||
DebugModeCheck();
|
||||
FancyZonesEditorIO = new FancyZonesEditorIO();
|
||||
Overlay = new Overlay();
|
||||
MainWindowSettings = new MainWindowSettingsModel();
|
||||
}
|
||||
|
||||
private void OnStartup(object sender, StartupEventArgs e)
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(Settings.PowerToysPID, () =>
|
||||
RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>
|
||||
{
|
||||
Environment.Exit(0);
|
||||
});
|
||||
|
||||
LayoutModel foundModel = null;
|
||||
FancyZonesEditorIO.ParseCommandLineArguments();
|
||||
FancyZonesEditorIO.ParseDeviceInfoData();
|
||||
|
||||
foreach (LayoutModel model in ZoneSettings.DefaultModels)
|
||||
MainWindowSettingsModel settings = ((App)Current).MainWindowSettings;
|
||||
settings.UpdateSelectedLayoutModel();
|
||||
|
||||
Overlay.Show();
|
||||
}
|
||||
|
||||
public static void ShowExceptionMessageBox(string message, Exception exception = null)
|
||||
{
|
||||
string fullMessage = FancyZonesEditor.Properties.Resources.Error_Report + PowerToysIssuesURL + " \n" + message;
|
||||
if (exception != null)
|
||||
{
|
||||
if (model.Type == Settings.ActiveZoneSetLayoutType)
|
||||
{
|
||||
// found match
|
||||
foundModel = model;
|
||||
break;
|
||||
}
|
||||
fullMessage += ": " + exception.Message;
|
||||
}
|
||||
|
||||
if (foundModel == null)
|
||||
{
|
||||
foreach (LayoutModel model in Settings.CustomModels)
|
||||
{
|
||||
if ("{" + model.Guid.ToString().ToUpper() + "}" == Settings.ActiveZoneSetUUid.ToUpper())
|
||||
{
|
||||
// found match
|
||||
foundModel = model;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
MessageBox.Show(fullMessage, FancyZonesEditor.Properties.Resources.Error_Exception_Message_Box_Title);
|
||||
}
|
||||
|
||||
if (foundModel == null)
|
||||
{
|
||||
foundModel = ZoneSettings.DefaultModels[0];
|
||||
}
|
||||
public static void ShowExceptionReportMessageBox(string reportData)
|
||||
{
|
||||
var fileStream = File.OpenWrite(ErrorReportLogFile);
|
||||
var sw = new StreamWriter(fileStream);
|
||||
sw.Write(reportData);
|
||||
sw.Flush();
|
||||
fileStream.Close();
|
||||
|
||||
foundModel.IsSelected = true;
|
||||
|
||||
EditorOverlay overlay = new EditorOverlay();
|
||||
overlay.Show();
|
||||
overlay.DataContext = foundModel;
|
||||
ShowReportMessageBox(fileStream.Name);
|
||||
}
|
||||
|
||||
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs args)
|
||||
@@ -103,16 +122,22 @@ namespace FancyZonesEditor
|
||||
var sw = new StreamWriter(fileStream);
|
||||
sw.Write(FormatException((Exception)args.ExceptionObject));
|
||||
fileStream.Close();
|
||||
|
||||
ShowReportMessageBox(fileStream.Name);
|
||||
}
|
||||
|
||||
private static void ShowReportMessageBox(string fileName)
|
||||
{
|
||||
MessageBox.Show(
|
||||
FancyZonesEditor.Properties.Resources.Crash_Report_Message_Box_Text_Part1 +
|
||||
Path.GetFullPath(fileStream.Name) +
|
||||
Path.GetFullPath(fileName) +
|
||||
"\n" +
|
||||
FancyZonesEditor.Properties.Resources.Crash_Report_Message_Box_Text_Part2 +
|
||||
PowerToysIssuesURL,
|
||||
FancyZonesEditor.Properties.Resources.Fancy_Zones_Editor_App_Title);
|
||||
}
|
||||
|
||||
private string FormatException(Exception ex)
|
||||
private static string FormatException(Exception ex)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine();
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<Grid>
|
||||
<Canvas x:Name="Preview"/>
|
||||
<Grid x:Name="Body">
|
||||
<Viewbox Stretch="Uniform">
|
||||
<Canvas x:Name="Preview"/>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// 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.Windows;
|
||||
using System.Windows.Controls;
|
||||
using FancyZonesEditor.Models;
|
||||
using FancyZonesEditor.Utils;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
@@ -46,6 +47,10 @@ namespace FancyZonesEditor
|
||||
|
||||
private void UpdateZoneRects()
|
||||
{
|
||||
var workArea = App.Overlay.WorkArea;
|
||||
Preview.Width = workArea.Width;
|
||||
Preview.Height = workArea.Height;
|
||||
|
||||
UIElementCollection previewChildren = Preview.Children;
|
||||
int previewChildrenCount = previewChildren.Count;
|
||||
while (previewChildrenCount < _model.Zones.Count)
|
||||
@@ -54,6 +59,7 @@ namespace FancyZonesEditor
|
||||
{
|
||||
Model = _model,
|
||||
};
|
||||
|
||||
Preview.Children.Add(zone);
|
||||
previewChildrenCount++;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
SizeToContent="Height"
|
||||
Background="White"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Closed="OnClosed">
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -19,24 +19,28 @@ namespace FancyZonesEditor
|
||||
|
||||
KeyUp += CanvasEditorWindow_KeyUp;
|
||||
|
||||
_model = EditorOverlay.Current.DataContext as CanvasLayoutModel;
|
||||
_model = App.Overlay.CurrentDataContext as CanvasLayoutModel;
|
||||
_stashedModel = (CanvasLayoutModel)_model.Clone();
|
||||
}
|
||||
|
||||
private void OnAddZone(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_offset + (int)(Settings.WorkArea.Width * 0.4) < (int)Settings.WorkArea.Width
|
||||
&& _offset + (int)(Settings.WorkArea.Height * 0.4) < (int)Settings.WorkArea.Height)
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
int offset = (int)App.Overlay.ScaleCoordinateWithCurrentMonitorDpi(_offset);
|
||||
|
||||
if (offset + (int)(workingArea.Width * 0.4) < (int)workingArea.Width
|
||||
&& offset + (int)(workingArea.Height * 0.4) < (int)workingArea.Height)
|
||||
{
|
||||
_model.AddZone(new Int32Rect(_offset, _offset, (int)(Settings.WorkArea.Width * 0.4), (int)(Settings.WorkArea.Height * 0.4)));
|
||||
_model.AddZone(new Int32Rect(offset, offset, (int)(workingArea.Width * 0.4), (int)(workingArea.Height * 0.4)));
|
||||
}
|
||||
else
|
||||
{
|
||||
_offset = 100;
|
||||
_model.AddZone(new Int32Rect(_offset, _offset, (int)(Settings.WorkArea.Width * 0.4), (int)(Settings.WorkArea.Height * 0.4)));
|
||||
offset = (int)App.Overlay.ScaleCoordinateWithCurrentMonitorDpi(_offset);
|
||||
_model.AddZone(new Int32Rect(offset, offset, (int)(workingArea.Width * 0.4), (int)(workingArea.Height * 0.4)));
|
||||
}
|
||||
|
||||
_offset += 50;
|
||||
_offset += 50; // TODO: replace hardcoded numbers
|
||||
}
|
||||
|
||||
protected new void OnCancel(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using FancyZonesEditor.Models;
|
||||
using FancyZonesEditor.Utils;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
@@ -84,7 +85,7 @@ namespace FancyZonesEditor
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Rect singleMonitor in Settings.UsedWorkAreas)
|
||||
foreach (Rect singleMonitor in App.Overlay.WorkAreas)
|
||||
{
|
||||
int monitorPositionLow = (int)(isX ? singleMonitor.Left : singleMonitor.Top);
|
||||
int monitorPositionHigh = (int)(isX ? singleMonitor.Right : singleMonitor.Bottom);
|
||||
@@ -213,8 +214,9 @@ namespace FancyZonesEditor
|
||||
|
||||
private SnappyHelperBase NewDefaultSnappyHelper(bool isX, ResizeMode mode)
|
||||
{
|
||||
int screenAxisOrigin = (int)(isX ? Settings.WorkArea.Left : Settings.WorkArea.Top);
|
||||
int screenAxisSize = (int)(isX ? Settings.WorkArea.Width : Settings.WorkArea.Height);
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
int screenAxisOrigin = (int)(isX ? workingArea.Left : workingArea.Top);
|
||||
int screenAxisSize = (int)(isX ? workingArea.Width : workingArea.Height);
|
||||
return new SnappyHelperMagnetic(Model.Zones, ZoneIndex, isX, mode, screenAxisOrigin, screenAxisSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace FancyZonesEditor.Converters
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
return Settings.IsPredefinedLayout((LayoutModel)value) ? Visibility.Collapsed : Visibility.Visible;
|
||||
return MainWindowSettingsModel.IsPredefinedLayout((LayoutModel)value) ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
// 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.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using FancyZonesEditor.Models;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for EditorOverlay.xaml
|
||||
/// </summary>
|
||||
public partial class EditorOverlay : Window
|
||||
{
|
||||
public static EditorOverlay Current { get; set; }
|
||||
|
||||
private readonly Settings _settings = ((App)Application.Current).ZoneSettings;
|
||||
private LayoutPreview _layoutPreview;
|
||||
|
||||
private UserControl _editor;
|
||||
|
||||
private static MainWindow _mainWindow = new MainWindow();
|
||||
|
||||
public Int32Rect[] GetZoneRects()
|
||||
{
|
||||
if (_editor != null)
|
||||
{
|
||||
if (_editor is GridEditor gridEditor)
|
||||
{
|
||||
return ZoneRectsFromPanel(gridEditor.PreviewPanel);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CanvasEditor
|
||||
return ZoneRectsFromPanel(((CanvasEditor)_editor).Preview);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// One of the predefined zones (neither grid or canvas editor used).
|
||||
return _layoutPreview.GetZoneRects();
|
||||
}
|
||||
}
|
||||
|
||||
private Int32Rect[] ZoneRectsFromPanel(Panel previewPanel)
|
||||
{
|
||||
// TODO: the ideal here is that the ArrangeRects logic is entirely inside the model, so we don't have to walk the UIElement children to get the rect info
|
||||
int count = previewPanel.Children.Count;
|
||||
Int32Rect[] zones = new Int32Rect[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
FrameworkElement child = (FrameworkElement)previewPanel.Children[i];
|
||||
Point topLeft = child.TransformToAncestor(previewPanel).Transform(default);
|
||||
|
||||
zones[i].X = (int)topLeft.X;
|
||||
zones[i].Y = (int)topLeft.Y;
|
||||
zones[i].Width = (int)child.ActualWidth;
|
||||
zones[i].Height = (int)child.ActualHeight;
|
||||
}
|
||||
|
||||
return zones;
|
||||
}
|
||||
|
||||
public EditorOverlay()
|
||||
{
|
||||
InitializeComponent();
|
||||
Current = this;
|
||||
|
||||
Left = Settings.WorkArea.Left;
|
||||
Top = Settings.WorkArea.Top;
|
||||
Width = Settings.WorkArea.Width;
|
||||
Height = Settings.WorkArea.Height;
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ShowLayoutPicker();
|
||||
}
|
||||
|
||||
public void ShowLayoutPicker()
|
||||
{
|
||||
_editor = null;
|
||||
_layoutPreview = new LayoutPreview
|
||||
{
|
||||
IsActualSize = true,
|
||||
Opacity = 0.5,
|
||||
};
|
||||
|
||||
Content = _layoutPreview;
|
||||
|
||||
_mainWindow.Owner = this;
|
||||
_mainWindow.ShowActivated = true;
|
||||
_mainWindow.Topmost = true;
|
||||
_mainWindow.Show();
|
||||
_mainWindow.LeftWindowCommands = null;
|
||||
_mainWindow.RightWindowCommands = null;
|
||||
|
||||
// window is set to topmost to make sure it shows on top of PowerToys settings page
|
||||
// we can reset topmost flag now
|
||||
_mainWindow.Topmost = false;
|
||||
}
|
||||
|
||||
// These event handlers are used to track the current state of the Shift and Ctrl keys on the keyboard
|
||||
// They reflect that current state into properties on the Settings object, which the Zone view will listen to in editing mode
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||
{
|
||||
_settings.IsShiftKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift);
|
||||
_settings.IsCtrlKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Control);
|
||||
base.OnPreviewKeyDown(e);
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyUp(KeyEventArgs e)
|
||||
{
|
||||
_settings.IsShiftKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift);
|
||||
_settings.IsCtrlKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Control);
|
||||
base.OnPreviewKeyUp(e);
|
||||
}
|
||||
|
||||
public void Edit()
|
||||
{
|
||||
_layoutPreview = null;
|
||||
if (DataContext is GridLayoutModel)
|
||||
{
|
||||
_editor = new GridEditor();
|
||||
}
|
||||
else if (DataContext is CanvasLayoutModel)
|
||||
{
|
||||
_editor = new CanvasEditor();
|
||||
}
|
||||
|
||||
Content = _editor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,8 @@ namespace FancyZonesEditor
|
||||
{
|
||||
protected void OnSaveApplyTemplate(object sender, RoutedEventArgs e)
|
||||
{
|
||||
EditorOverlay mainEditor = EditorOverlay.Current;
|
||||
if (mainEditor.DataContext is LayoutModel model)
|
||||
var mainEditor = App.Overlay;
|
||||
if (mainEditor.CurrentDataContext is LayoutModel model)
|
||||
{
|
||||
// If new custom Canvas layout is created (i.e. edited Blank layout),
|
||||
// it's type needs to be updated
|
||||
@@ -30,14 +30,14 @@ namespace FancyZonesEditor
|
||||
|
||||
_backToLayoutPicker = false;
|
||||
Close();
|
||||
EditorOverlay.Current.Close();
|
||||
mainEditor.CloseEditor();
|
||||
}
|
||||
|
||||
protected void OnClosed(object sender, EventArgs e)
|
||||
{
|
||||
if (_backToLayoutPicker)
|
||||
{
|
||||
EditorOverlay.Current.ShowLayoutPicker();
|
||||
App.Overlay.CloseEditor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,9 @@
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>images\FancyZonesEditor.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
@@ -118,9 +121,16 @@
|
||||
<Compile Include="..\..\..\..\codeAnalysis\GlobalSuppressions.cs">
|
||||
<Link>GlobalSuppressions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Models\LayoutSettings.cs" />
|
||||
<Compile Include="DashCaseNamingPolicy.cs" />
|
||||
<Compile Include="GridData.cs" />
|
||||
<Compile Include="GridDragHandles.cs" />
|
||||
<Compile Include="LayoutOverlayWindow.xaml.cs">
|
||||
<DependentUpon>LayoutOverlayWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Models\LayoutType.cs" />
|
||||
<Compile Include="Models\Monitor.cs" />
|
||||
<Compile Include="Overlay.cs" />
|
||||
<Compile Include="StringUtils.cs" />
|
||||
<Compile Include="Converters\BooleanToBrushConverter.xaml.cs" />
|
||||
<Compile Include="Converters\BooleanToIntConverter.xaml.cs" />
|
||||
@@ -140,10 +150,7 @@
|
||||
<Compile Include="Models\CanvasLayoutModel.cs" />
|
||||
<Compile Include="Models\GridLayoutModel.cs" />
|
||||
<Compile Include="Models\LayoutModel.cs" />
|
||||
<Compile Include="Models\Settings.cs" />
|
||||
<Compile Include="EditorOverlay.xaml.cs">
|
||||
<DependentUpon>EditorOverlay.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Models\MainWindowSettingsModel.cs" />
|
||||
<Compile Include="Converters\ModelToVisibilityConverter.xaml.cs" />
|
||||
<Compile Include="Native.cs" />
|
||||
<Compile Include="RowColInfo.cs" />
|
||||
@@ -151,6 +158,15 @@
|
||||
<DependentUpon>GridEditorWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="SplitEventArgs.cs" />
|
||||
<Compile Include="Utils\FancyZonesEditorIO.cs" />
|
||||
<Compile Include="Utils\EventArgs`1.cs" />
|
||||
<Compile Include="Utils\EventRaiser.cs" />
|
||||
<Compile Include="Utils\MonitorChangedEventArgs.cs" />
|
||||
<Compile Include="Models\MonitorInfoModel.cs" />
|
||||
<Compile Include="Utils\RelayCommand.cs" />
|
||||
<Compile Include="Utils\RelayCommand`1.cs" />
|
||||
<Compile Include="Models\Device.cs" />
|
||||
<Compile Include="ViewModels\MonitorViewModel.cs" />
|
||||
<Compile Include="WindowLayout.xaml.cs">
|
||||
<DependentUpon>WindowLayout.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -175,6 +191,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="LayoutOverlayWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="LayoutPreview.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -191,10 +211,6 @@
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Page Include="EditorOverlay.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="GridEditorWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -235,6 +251,7 @@
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.*.resx" />
|
||||
<None Include="app.manifest" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
@@ -253,6 +270,9 @@
|
||||
<PackageReference Include="System.IO.Abstractions">
|
||||
<Version>12.2.5</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.DpiAwareness">
|
||||
<Version>6.6.30107</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Text.Json">
|
||||
<Version>4.7.2</Version>
|
||||
</PackageReference>
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using FancyZonesEditor.Models;
|
||||
using FancyZonesEditor.Utils;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
|
||||
@@ -19,33 +19,35 @@
|
||||
<Setter Property="Width" Value="150" />
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Canvas x:Name="Preview" />
|
||||
<Canvas x:Name="AdornerLayer" />
|
||||
<Canvas
|
||||
x:Name="MergePanel"
|
||||
MouseUp="MergePanelMouseUp"
|
||||
Visibility="Collapsed">
|
||||
<Viewbox Stretch="Uniform">
|
||||
<Grid>
|
||||
<Canvas x:Name="Preview" />
|
||||
<Canvas x:Name="AdornerLayer" />
|
||||
<Canvas
|
||||
x:Name="MergePanel"
|
||||
MouseUp="MergePanelMouseUp"
|
||||
Visibility="Collapsed">
|
||||
|
||||
<StackPanel
|
||||
x:Name="MergeButtons"
|
||||
Background="Gray"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
Width="134"
|
||||
Height="36"
|
||||
Margin="0"
|
||||
Click="MergeClick">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image
|
||||
Height="16"
|
||||
Margin="0,0,12,0"
|
||||
HorizontalAlignment="Left"
|
||||
Source="images/Merge.png" />
|
||||
<TextBlock Text="Merge zones" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
<StackPanel
|
||||
x:Name="MergeButtons"
|
||||
Background="Gray"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
Width="134"
|
||||
Height="36"
|
||||
Margin="0"
|
||||
Click="MergeClick">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image
|
||||
Height="16"
|
||||
Margin="0,0,12,0"
|
||||
HorizontalAlignment="Left"
|
||||
Source="images/Merge.png" />
|
||||
<TextBlock Text="Merge zones" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -8,6 +8,7 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using FancyZonesEditor.Models;
|
||||
using FancyZonesEditor.Utils;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
@@ -32,7 +33,7 @@ namespace FancyZonesEditor
|
||||
InitializeComponent();
|
||||
Loaded += GridEditor_Loaded;
|
||||
Unloaded += GridEditor_Unloaded;
|
||||
((App)Application.Current).ZoneSettings.PropertyChanged += ZoneSettings_PropertyChanged;
|
||||
((App)Application.Current).MainWindowSettings.PropertyChanged += ZoneSettings_PropertyChanged;
|
||||
gridEditorUniqueId = ++gridEditorUniqueIdCounter;
|
||||
}
|
||||
|
||||
@@ -69,7 +70,8 @@ namespace FancyZonesEditor
|
||||
|
||||
private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
Size actualSize = new Size(ActualWidth, ActualHeight);
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workingArea.Width, workingArea.Height);
|
||||
|
||||
// Only enter if this is the newest instance
|
||||
if (actualSize.Width > 0 && gridEditorUniqueId == gridEditorUniqueIdCounter)
|
||||
@@ -248,7 +250,7 @@ namespace FancyZonesEditor
|
||||
}
|
||||
|
||||
_dragHandles.UpdateAfterVerticalSplit(foundCol);
|
||||
_data.SplitColumn(foundCol, spliteeIndex, newChildIndex, space, offset, ActualWidth);
|
||||
_data.SplitColumn(foundCol, spliteeIndex, newChildIndex, space, offset, App.Overlay.WorkArea.Width);
|
||||
_dragHandles.AddDragHandle(Orientation.Vertical, foundRow, foundCol, model);
|
||||
}
|
||||
else
|
||||
@@ -298,11 +300,12 @@ namespace FancyZonesEditor
|
||||
}
|
||||
|
||||
_dragHandles.UpdateAfterHorizontalSplit(foundRow);
|
||||
_data.SplitRow(foundRow, spliteeIndex, newChildIndex, space, offset, ActualHeight);
|
||||
_data.SplitRow(foundRow, spliteeIndex, newChildIndex, space, offset, App.Overlay.WorkArea.Height);
|
||||
_dragHandles.AddDragHandle(Orientation.Horizontal, foundRow, foundCol, model);
|
||||
}
|
||||
|
||||
Size actualSize = new Size(ActualWidth, ActualHeight);
|
||||
var workArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workArea.Width, workArea.Height);
|
||||
ArrangeGridRects(actualSize);
|
||||
}
|
||||
|
||||
@@ -354,7 +357,8 @@ namespace FancyZonesEditor
|
||||
|
||||
private void OnGridDimensionsChanged()
|
||||
{
|
||||
Size actualSize = new Size(ActualWidth, ActualHeight);
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workingArea.Width, workingArea.Height);
|
||||
if (actualSize.Width > 0)
|
||||
{
|
||||
ArrangeGridRects(actualSize);
|
||||
@@ -363,6 +367,10 @@ namespace FancyZonesEditor
|
||||
|
||||
private void ArrangeGridRects(Size arrangeSize)
|
||||
{
|
||||
var workArea = App.Overlay.WorkArea;
|
||||
Preview.Width = workArea.Width;
|
||||
Preview.Height = workArea.Height;
|
||||
|
||||
GridLayoutModel model = Model;
|
||||
if (model == null)
|
||||
{
|
||||
@@ -375,7 +383,7 @@ namespace FancyZonesEditor
|
||||
return;
|
||||
}
|
||||
|
||||
Settings settings = ((App)Application.Current).ZoneSettings;
|
||||
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
|
||||
|
||||
int spacing = settings.ShowSpacing ? settings.Spacing : 0;
|
||||
|
||||
@@ -403,7 +411,7 @@ namespace FancyZonesEditor
|
||||
if (_dragHandles.HasSnappedNonAdjacentResizers(resizer))
|
||||
{
|
||||
double spacing = 0;
|
||||
Settings settings = ((App)Application.Current).ZoneSettings;
|
||||
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
|
||||
if (settings.ShowSpacing)
|
||||
{
|
||||
spacing = settings.Spacing;
|
||||
@@ -422,7 +430,8 @@ namespace FancyZonesEditor
|
||||
}
|
||||
}
|
||||
|
||||
Size actualSize = new Size(ActualWidth, ActualHeight);
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workingArea.Width, workingArea.Height);
|
||||
ArrangeGridRects(actualSize);
|
||||
AdornerLayer.UpdateLayout();
|
||||
}
|
||||
@@ -433,7 +442,8 @@ namespace FancyZonesEditor
|
||||
int index = _data.SwappedIndexAfterResize(resizer);
|
||||
if (index != -1)
|
||||
{
|
||||
Size actualSize = new Size(ActualWidth, ActualHeight);
|
||||
Rect workingArea = App.Overlay.WorkArea;
|
||||
Size actualSize = new Size(workingArea.Width, workingArea.Height);
|
||||
ArrangeGridRects(actualSize);
|
||||
}
|
||||
}
|
||||
@@ -478,7 +488,6 @@ namespace FancyZonesEditor
|
||||
if (_startDragPos.X != -1)
|
||||
{
|
||||
Point dragPos = e.GetPosition(Preview);
|
||||
|
||||
_startRow = -1;
|
||||
_endRow = -1;
|
||||
_startCol = -1;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
SizeToContent="Height"
|
||||
Background="White"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Closed="OnClosed">
|
||||
|
||||
<Window.Resources>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using FancyZonesEditor.Models;
|
||||
using FancyZonesEditor.Utils;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
@@ -19,13 +20,13 @@ namespace FancyZonesEditor
|
||||
|
||||
KeyUp += GridEditorWindow_KeyUp;
|
||||
|
||||
_stashedModel = (GridLayoutModel)(EditorOverlay.Current.DataContext as GridLayoutModel).Clone();
|
||||
_stashedModel = (GridLayoutModel)(App.Overlay.CurrentDataContext as GridLayoutModel).Clone();
|
||||
}
|
||||
|
||||
protected new void OnCancel(object sender, RoutedEventArgs e)
|
||||
{
|
||||
base.OnCancel(sender, e);
|
||||
GridLayoutModel model = EditorOverlay.Current.DataContext as GridLayoutModel;
|
||||
GridLayoutModel model = App.Overlay.CurrentDataContext as GridLayoutModel;
|
||||
_stashedModel.RestoreTo(model);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,14 +69,14 @@ namespace FancyZonesEditor
|
||||
};
|
||||
Body.Children.Add(_splitter);
|
||||
|
||||
((App)Application.Current).ZoneSettings.PropertyChanged += ZoneSettings_PropertyChanged;
|
||||
((App)Application.Current).MainWindowSettings.PropertyChanged += ZoneSettings_PropertyChanged;
|
||||
}
|
||||
|
||||
private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == PropertyIsShiftKeyPressedID)
|
||||
{
|
||||
_switchOrientation = ((App)Application.Current).ZoneSettings.IsShiftKeyPressed;
|
||||
_switchOrientation = ((App)Application.Current).MainWindowSettings.IsShiftKeyPressed;
|
||||
if (_lastPos.X != -1)
|
||||
{
|
||||
UpdateSplitter();
|
||||
@@ -108,7 +108,7 @@ namespace FancyZonesEditor
|
||||
{
|
||||
get
|
||||
{
|
||||
Settings settings = ((App)Application.Current).ZoneSettings;
|
||||
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
|
||||
if (!settings.ShowSpacing)
|
||||
{
|
||||
return 1;
|
||||
@@ -283,7 +283,7 @@ namespace FancyZonesEditor
|
||||
private void DoSplit(Orientation orientation, double offset)
|
||||
{
|
||||
int spacing = 0;
|
||||
Settings settings = ((App)Application.Current).ZoneSettings;
|
||||
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
|
||||
if (settings.ShowSpacing)
|
||||
{
|
||||
spacing = settings.Spacing;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
<Window x:Class="FancyZonesEditor.EditorOverlay"
|
||||
<Window x:Class="FancyZonesEditor.LayoutOverlayWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:FancyZonesEditor"
|
||||
mc:Ignorable="d"
|
||||
Title="FancyZones Editor" Height="450" Width="800"
|
||||
Title="FancyZones Layout" Height="450" Width="800"
|
||||
ShowInTaskbar="False"
|
||||
ResizeMode="NoResize"
|
||||
WindowStyle="None"
|
||||
AllowsTransparency="True"
|
||||
Background="Transparent"
|
||||
Loaded="OnLoaded"/>
|
||||
Background="Transparent"/>
|
||||
@@ -0,0 +1,21 @@
|
||||
// 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.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for LayoutOverlayWindow.xaml
|
||||
/// </summary>
|
||||
public partial class LayoutOverlayWindow : Window
|
||||
{
|
||||
public LayoutOverlayWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -29,11 +29,22 @@ namespace FancyZonesEditor
|
||||
private LayoutModel _model;
|
||||
private List<Int32Rect> _zones = new List<Int32Rect>();
|
||||
|
||||
public bool IsActualSize
|
||||
{
|
||||
get { return (bool)GetValue(IsActualSizeProperty); }
|
||||
set { SetValue(IsActualSizeProperty, value); }
|
||||
}
|
||||
|
||||
public LayoutPreview()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += LayoutPreview_DataContextChanged;
|
||||
((App)Application.Current).ZoneSettings.PropertyChanged += ZoneSettings_PropertyChanged;
|
||||
((App)Application.Current).MainWindowSettings.PropertyChanged += ZoneSettings_PropertyChanged;
|
||||
}
|
||||
|
||||
public void UpdatePreview()
|
||||
{
|
||||
RenderPreview();
|
||||
}
|
||||
|
||||
private void LayoutPreview_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
@@ -42,12 +53,6 @@ namespace FancyZonesEditor
|
||||
RenderPreview();
|
||||
}
|
||||
|
||||
public bool IsActualSize
|
||||
{
|
||||
get { return (bool)GetValue(IsActualSizeProperty); }
|
||||
set { SetValue(IsActualSizeProperty, value); }
|
||||
}
|
||||
|
||||
private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == PropertyZoneCountID)
|
||||
@@ -109,27 +114,25 @@ namespace FancyZonesEditor
|
||||
RowColInfo[] colInfo = (from percent in grid.ColumnPercents
|
||||
select new RowColInfo(percent)).ToArray();
|
||||
|
||||
Settings settings = ((App)Application.Current).ZoneSettings;
|
||||
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
|
||||
|
||||
int spacing = settings.ShowSpacing ? settings.Spacing : 0;
|
||||
|
||||
int width = (int)Settings.WorkArea.Width;
|
||||
int height = (int)Settings.WorkArea.Height;
|
||||
|
||||
double totalWidth = width - (spacing * (cols + 1));
|
||||
double totalHeight = height - (spacing * (rows + 1));
|
||||
var workArea = App.Overlay.WorkArea;
|
||||
double width = workArea.Width - (spacing * (cols + 1));
|
||||
double height = workArea.Height - (spacing * (rows + 1));
|
||||
|
||||
double top = spacing;
|
||||
for (int row = 0; row < rows; row++)
|
||||
{
|
||||
double cellHeight = rowInfo[row].Recalculate(top, totalHeight);
|
||||
double cellHeight = rowInfo[row].Recalculate(top, height);
|
||||
top += cellHeight + spacing;
|
||||
}
|
||||
|
||||
double left = spacing;
|
||||
for (int col = 0; col < cols; col++)
|
||||
{
|
||||
double cellWidth = colInfo[col].Recalculate(left, totalWidth);
|
||||
double cellWidth = colInfo[col].Recalculate(left, width);
|
||||
left += cellWidth + spacing;
|
||||
}
|
||||
|
||||
@@ -140,8 +143,8 @@ namespace FancyZonesEditor
|
||||
Body.Children.Add(viewbox);
|
||||
Canvas frame = new Canvas
|
||||
{
|
||||
Width = width,
|
||||
Height = height,
|
||||
Width = workArea.Width,
|
||||
Height = workArea.Height,
|
||||
};
|
||||
viewbox.Child = frame;
|
||||
|
||||
@@ -183,6 +186,14 @@ namespace FancyZonesEditor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (App.DebugMode)
|
||||
{
|
||||
TextBlock text = new TextBlock();
|
||||
text.Text = "(" + workArea.X + "," + workArea.Y + ")";
|
||||
text.FontSize = 42;
|
||||
frame.Children.Add(text);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderSmallScalePreview(GridLayoutModel grid)
|
||||
@@ -205,7 +216,7 @@ namespace FancyZonesEditor
|
||||
Body.ColumnDefinitions.Add(def);
|
||||
}
|
||||
|
||||
Settings settings = ((App)Application.Current).ZoneSettings;
|
||||
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
|
||||
Thickness margin = new Thickness(settings.ShowSpacing ? settings.Spacing / 20 : 0);
|
||||
|
||||
List<int> visited = new List<int>();
|
||||
@@ -265,6 +276,12 @@ namespace FancyZonesEditor
|
||||
|
||||
private void RenderCanvasPreview(CanvasLayoutModel canvas)
|
||||
{
|
||||
var workArea = canvas.CanvasRect;
|
||||
if (workArea.Width == 0 || workArea.Height == 0 || App.Overlay.SpanZonesAcrossMonitors)
|
||||
{
|
||||
workArea = App.Overlay.WorkArea;
|
||||
}
|
||||
|
||||
Viewbox viewbox = new Viewbox
|
||||
{
|
||||
Stretch = Stretch.Uniform,
|
||||
@@ -272,10 +289,11 @@ namespace FancyZonesEditor
|
||||
Body.Children.Add(viewbox);
|
||||
Canvas frame = new Canvas
|
||||
{
|
||||
Width = Settings.WorkArea.Width,
|
||||
Height = Settings.WorkArea.Height,
|
||||
Width = workArea.Width,
|
||||
Height = workArea.Height,
|
||||
};
|
||||
viewbox.Child = frame;
|
||||
|
||||
foreach (Int32Rect zone in canvas.Zones)
|
||||
{
|
||||
Rectangle rect = new Rectangle();
|
||||
@@ -288,6 +306,14 @@ namespace FancyZonesEditor
|
||||
rect.Fill = Brushes.LightGray;
|
||||
frame.Children.Add(rect);
|
||||
}
|
||||
|
||||
if (App.DebugMode)
|
||||
{
|
||||
TextBlock text = new TextBlock();
|
||||
text.Text = "(" + App.Overlay.WorkArea.X + "," + App.Overlay.WorkArea.Y + ")";
|
||||
text.FontSize = 42;
|
||||
frame.Children.Add(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,324 +1,464 @@
|
||||
<Controls:MetroWindow x:Class="FancyZonesEditor.MainWindow"
|
||||
x:Name="MainWindow1"
|
||||
AutomationProperties.Name="{x:Static props:Resources.Fancy_Zones_Main_Editor}"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
|
||||
xmlns:local="clr-namespace:FancyZonesEditor"
|
||||
xmlns:Converters="clr-namespace:FancyZonesEditor.Converters"
|
||||
xmlns:props="clr-namespace:FancyZonesEditor.Properties"
|
||||
mc:Ignorable="d"
|
||||
Title=""
|
||||
Width="810"
|
||||
SizeToContent="Height"
|
||||
Background="White"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Initialized="OnInitialized"
|
||||
Closing="OnClosing">
|
||||
<Window.Resources>
|
||||
<Converters:BooleanToBrushConverter x:Key="BooleanToBrushConverter" />
|
||||
<Converters:ModelToVisibilityConverter x:Key="ModelToVisibilityConverter" />
|
||||
<Converters:BooleanToIntConverter x:Key="BooleanToIntConverter" />
|
||||
|
||||
<Style x:Key="titleText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="Bold" />
|
||||
<Setter Property="LineHeight" Value="24" />
|
||||
<Setter Property="FontSize" Value="18"/>
|
||||
<Setter Property="Margin" Value="16,20,0,0" />
|
||||
</Style>
|
||||
<Style x:Key="zoneCount" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="Regular" />
|
||||
<Setter Property="FontSize" Value="24"/>
|
||||
<Setter Property="LineHeight" Value="24" />
|
||||
<Setter Property="Margin" Value="20,0,20,0" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
<Style x:Key="tabText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="#767676"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="LineHeight" Value="20" />
|
||||
<Setter Property="Margin" Value="24,20,0,0" />
|
||||
<Setter Property="TextAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style x:Key="settingText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="LineHeight" Value="20" />
|
||||
<Setter Property="Margin" Value="7,10,0,0" />
|
||||
<Setter Property="TextAlignment" Value="Left" />
|
||||
</Style>
|
||||
<Style x:Key="settingCheckBoxText" TargetType="CheckBox">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Margin" Value="5,10,0,0" />
|
||||
</Style>
|
||||
<Style x:Key="templateTitleText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="TextAlignment" Value="Center" />
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
<Style x:Key="customButtonFocusVisualStyle">
|
||||
<Setter Property="Control.Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Rectangle Margin="1" Stroke="White" StrokeDashArray="1 2" StrokeThickness="1" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="secondaryButton" TargetType="Button">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="0,5,0,5"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="#767676"/>
|
||||
<Setter Property="Margin" Value="16,0,0,0" />
|
||||
<Setter Property="Width" Value="378"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{DynamicResource customButtonFocusVisualStyle}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border Background="{TemplateBinding Background}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#5D5D5D"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="primaryButton" TargetType="Button">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="0,5,0,5"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="#0078D7"/>
|
||||
<Setter Property="Margin" Value="16,0,16,0" />
|
||||
<Setter Property="Width" Value="377"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{DynamicResource customButtonFocusVisualStyle}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border Background="{TemplateBinding Background}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#024D89"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="spinnerButton" TargetType="Button">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="FontSize" Value="24"/>
|
||||
<Setter Property="Padding" Value="0,0,0,5"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="#F2F2F2"/>
|
||||
<Setter Property="Margin" Value="0,0,0,0" />
|
||||
</Style>
|
||||
<Style x:Key="newLayoutButton" TargetType="Button">
|
||||
<Setter Property="Background" Value="#f2f2f2"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="FontFamily" Value="SegoeUI"/>
|
||||
<Setter Property="FontWeight" Value="Light"/>
|
||||
<Setter Property="FontSize" Value="148"/>
|
||||
</Style>
|
||||
<Style x:Key="textBox" TargetType="TextBox">
|
||||
<Setter Property="BorderBrush" Value="#cccccc"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="FontFamily" Value="SegoeUI"/>
|
||||
<Setter Property="FontWeight" Value="Regular"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="16,6,0,0"/>
|
||||
<Setter Property="Padding" Value="5,5,5,5"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="templateBackground" TargetType="Border">
|
||||
<Setter Property="Background" Value="#F2F2F2"/>
|
||||
<Setter Property="CornerRadius" Value="4"/>
|
||||
<Setter Property="BorderThickness" Value="2"/>
|
||||
</Style>
|
||||
|
||||
<ControlTemplate x:Key="myTabs">
|
||||
<Grid Width="404">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40"/>
|
||||
<RowDefinition Height="2"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Name="myTabText" Text="{TemplateBinding TabItem.Header}" Style="{StaticResource tabText}" />
|
||||
<Rectangle Grid.Row="1" x:Name="myTabLine" Fill="#F2F2F2" Height="1"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="TabItem.IsSelected" Value="True">
|
||||
<Setter TargetName="myTabText" Property="Foreground" Value="#2A79D7"/>
|
||||
<Setter TargetName="myTabLine" Property="Fill" Value="#2A79D7" />
|
||||
<Setter TargetName="myTabLine" Property="Height" Value="2"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Window.Resources>
|
||||
|
||||
<StackPanel FocusManager.FocusedElement="{Binding ElementName=decrementZones}">
|
||||
|
||||
<TextBlock Name="DialogTitle" Text="{x:Static props:Resources.Choose_Layout}" Style="{StaticResource titleText}" />
|
||||
|
||||
<TabControl BorderThickness="0" x:Name="TemplateTab" AutomationProperties.LabeledBy="{Binding ElementName=DialogTitle}" SelectedIndex="{Binding IsCustomLayoutActive, Mode=OneWay, Converter={StaticResource BooleanToIntConverter}}">
|
||||
<TabItem Header="{x:Static props:Resources.Templates}" Template="{StaticResource myTabs}" AutomationProperties.Name="{x:Static props:Resources.Tab_Item_Templates}">
|
||||
<StackPanel>
|
||||
<StackPanel Margin="0,15,0,8" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button x:Name="decrementZones" Width="40" Height="40" AutomationProperties.Name="{x:Static props:Resources.Zone_Count_Decrement}" Content="-" Style="{StaticResource spinnerButton}" Click="DecrementZones_Click"/>
|
||||
<TextBlock x:Name="zoneCount" Text="{Binding ZoneCount}" Style="{StaticResource zoneCount}"/>
|
||||
<Button x:Name="incrementZones" Width="40" Height="40" AutomationProperties.Name="{x:Static props:Resources.Zone_Count_Increment}" Content="+" Style="{StaticResource spinnerButton}" Click="IncrementZones_Click"/>
|
||||
</StackPanel>
|
||||
<ItemsControl ItemsSource="{Binding DefaultModels}" Margin="8,0,0,0">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel Orientation="Horizontal" ItemWidth="{Binding ElementName=MainWindow1, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, Path=WrapPanelItemSize}" ItemHeight="{Binding ElementName=WrapPanel1, Path=ItemWidth}" x:Name="WrapPanel1" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="8"
|
||||
BorderBrush="{Binding Path=IsSelected, Converter={StaticResource BooleanToBrushConverter}}"
|
||||
Style="{StaticResource templateBackground}"
|
||||
MouseDown="LayoutItem_Click"
|
||||
Focusable="True"
|
||||
FocusManager.GotFocus="LayoutItem_Focused"
|
||||
KeyDown="LayoutItem_Apply">
|
||||
<DockPanel Margin="0,20,0,0"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
LastChildFill="True">
|
||||
<TextBlock Padding="8,0,8,0"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
DockPanel.Dock="Top"
|
||||
Text="{Binding Name}"
|
||||
Style="{StaticResource templateTitleText}" />
|
||||
<local:LayoutPreview Margin="16" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
|
||||
|
||||
<TabItem Header="{x:Static props:Resources.Custom}" Template="{StaticResource myTabs}" AutomationProperties.Name="{x:Static props:Resources.Tab_Item_Custom}">
|
||||
<StackPanel>
|
||||
<ItemsControl ItemsSource="{Binding CustomModels}" Margin="8,8,0,0">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel Orientation="Horizontal" ItemWidth="{Binding ElementName=MainWindow1, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, Path=WrapPanelItemSize}" ItemHeight="{Binding ElementName=WrapPanel2, Path=ItemWidth}" x:Name="WrapPanel2" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="8"
|
||||
BorderBrush="{Binding Path=IsSelected, Converter={StaticResource BooleanToBrushConverter}}"
|
||||
Style="{StaticResource templateBackground}"
|
||||
MouseDown="LayoutItem_Click"
|
||||
Focusable="True"
|
||||
FocusManager.GotFocus="LayoutItem_Focused"
|
||||
KeyDown="LayoutItem_Apply">
|
||||
<DockPanel Margin="0,20,0,0"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
LastChildFill="True">
|
||||
<DockPanel DockPanel.Dock="Top" LastChildFill="True" >
|
||||
<Button x:Name="DeleteButton" AutomationProperties.Name="{x:Static props:Resources.Custom_Layout_Delete_Button}"
|
||||
Visibility="{Binding Converter={StaticResource ModelToVisibilityConverter}}"
|
||||
DockPanel.Dock="Right"
|
||||
MaxHeight="10"
|
||||
Click="OnDelete"
|
||||
Padding="8,4,8,4"
|
||||
Margin="0,0,8,0"
|
||||
BorderThickness="0"
|
||||
Background="#f2f2f2">
|
||||
<Image Source="images/Delete.png" />
|
||||
</Button>
|
||||
<TextBlock DockPanel.Dock="Top"
|
||||
TextTrimming="CharacterEllipsis" Padding="8,0,8,0"
|
||||
Text="{Binding Name}"
|
||||
Style="{StaticResource templateTitleText}" />
|
||||
</DockPanel>
|
||||
<local:LayoutPreview Margin="16" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
<Grid Margin="10,4,10,8" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox x:Name="spaceAroundSetting" Content="{x:Static props:Resources.Show_Space_Zones}" Style="{StaticResource settingCheckBoxText}" IsChecked="{Binding ShowSpacing}" Grid.Row="0" Grid.Column="0"/>
|
||||
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
|
||||
<TextBlock x:Name="paddingValue"
|
||||
Text="{x:Static props:Resources.Space_Around_Zones}"
|
||||
Style="{StaticResource settingText}"
|
||||
IsEnabled="{Binding ShowSpacing}"
|
||||
MaxWidth="{Binding Path=SettingsTextMaxWidth, ElementName=MainWindow1}"
|
||||
TextWrapping="Wrap"/>
|
||||
<TextBox AutomationProperties.LabeledBy="{Binding ElementName=paddingValue}" Text="{Binding Path=Spacing,Mode=TwoWay}" Style="{StaticResource textBox}" MinWidth="32" IsEnabled="{Binding ShowSpacing}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal">
|
||||
<TextBlock x:Name="sensitivityRadiusValue"
|
||||
Text="{x:Static props:Resources.Distance_adjacent_zones}"
|
||||
Style="{StaticResource settingText}"
|
||||
MaxWidth="{Binding Path=SettingsTextMaxWidth, ElementName=MainWindow1}"
|
||||
TextWrapping="Wrap"/>
|
||||
<TextBox AutomationProperties.LabeledBy="{Binding ElementName=sensitivityRadiusValue}" Text="{Binding Path=SensitivityRadius,Mode=TwoWay}" Style="{StaticResource textBox}" MinWidth="40"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,16">
|
||||
<Button x:Name="EditCustomButton" Content="{x:Static props:Resources.Edit_Selected_Layout}" Padding="8" Style="{StaticResource secondaryButton}" Click="EditLayout_Click"/>
|
||||
<Button x:Name="ApplyCustomButton" Content="{x:Static props:Resources.Apply}" Padding="8" Style="{StaticResource primaryButton}" Click="Apply_Click"/>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Controls:MetroWindow>
|
||||
<Controls:MetroWindow x:Class="FancyZonesEditor.MainWindow"
|
||||
x:Name="MainWindow1"
|
||||
AutomationProperties.Name="{x:Static props:Resources.Fancy_Zones_Main_Editor}"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
|
||||
xmlns:local="clr-namespace:FancyZonesEditor"
|
||||
xmlns:Converters="clr-namespace:FancyZonesEditor.Converters"
|
||||
xmlns:props="clr-namespace:FancyZonesEditor.Properties" xmlns:local1="clr-namespace:FancyZonesEditor.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
Title=""
|
||||
Width="810"
|
||||
SizeToContent="Height"
|
||||
Background="White"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Initialized="OnInitialized"
|
||||
Closing="OnClosing">
|
||||
<Window.Resources>
|
||||
<Converters:BooleanToBrushConverter x:Key="BooleanToBrushConverter" />
|
||||
<Converters:ModelToVisibilityConverter x:Key="ModelToVisibilityConverter" />
|
||||
<Converters:BooleanToIntConverter x:Key="BooleanToIntConverter" />
|
||||
|
||||
<Style x:Key="titleText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="Bold" />
|
||||
<Setter Property="LineHeight" Value="24" />
|
||||
<Setter Property="FontSize" Value="18"/>
|
||||
<Setter Property="Margin" Value="16,20,0,0" />
|
||||
</Style>
|
||||
<Style x:Key="zoneCount" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="Regular" />
|
||||
<Setter Property="FontSize" Value="24"/>
|
||||
<Setter Property="LineHeight" Value="24" />
|
||||
<Setter Property="Margin" Value="20,0,20,0" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
<Style x:Key="tabText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="#767676"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="LineHeight" Value="20" />
|
||||
<Setter Property="Margin" Value="24,20,0,0" />
|
||||
<Setter Property="TextAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style x:Key="settingText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="LineHeight" Value="20" />
|
||||
<Setter Property="Margin" Value="7,10,0,0" />
|
||||
<Setter Property="TextAlignment" Value="Left" />
|
||||
</Style>
|
||||
<Style x:Key="settingCheckBoxText" TargetType="CheckBox">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Margin" Value="5,10,0,0" />
|
||||
</Style>
|
||||
<Style x:Key="templateTitleText" TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="TextAlignment" Value="Center" />
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
<Style x:Key="customButtonFocusVisualStyle">
|
||||
<Setter Property="Control.Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Rectangle Margin="1" Stroke="White" StrokeDashArray="1 2" StrokeThickness="1" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="secondaryButton" TargetType="Button">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="0,5,0,5"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="#767676"/>
|
||||
<Setter Property="Margin" Value="16,0,0,0" />
|
||||
<Setter Property="Width" Value="245"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{DynamicResource customButtonFocusVisualStyle}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border Background="{TemplateBinding Background}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#5D5D5D"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="primaryButton" TargetType="Button">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="0,5,0,5"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="#0078D7"/>
|
||||
<Setter Property="Margin" Value="16,0,0,0" />
|
||||
<Setter Property="Width" Value="245"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{DynamicResource customButtonFocusVisualStyle}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border Background="{TemplateBinding Background}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#024D89"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style x:Key="spinnerButton" TargetType="Button">
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="SemiBold" />
|
||||
<Setter Property="Foreground" Value="Black"/>
|
||||
<Setter Property="FontSize" Value="24"/>
|
||||
<Setter Property="Padding" Value="0,0,0,5"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Background" Value="#F2F2F2"/>
|
||||
<Setter Property="Margin" Value="0,0,0,0" />
|
||||
</Style>
|
||||
<Style x:Key="newLayoutButton" TargetType="Button">
|
||||
<Setter Property="Background" Value="#f2f2f2"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="FontFamily" Value="SegoeUI"/>
|
||||
<Setter Property="FontWeight" Value="Light"/>
|
||||
<Setter Property="FontSize" Value="148"/>
|
||||
</Style>
|
||||
<Style x:Key="textBox" TargetType="TextBox">
|
||||
<Setter Property="BorderBrush" Value="#cccccc"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="FontFamily" Value="SegoeUI"/>
|
||||
<Setter Property="FontWeight" Value="Regular"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="16,6,0,0"/>
|
||||
<Setter Property="Padding" Value="5,5,5,5"/>
|
||||
</Style>
|
||||
<Style x:Key="desktopIdText" TargetType="TextBlock">
|
||||
<Setter Property="TextAlignment" Value="Center" />
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="Light" />
|
||||
<Setter Property="FontSize" Value="42" />
|
||||
<Setter Property="Foreground" Value="#303030" />
|
||||
</Style>
|
||||
<Style x:Key="desktopDimensionsText" TargetType="TextBlock">
|
||||
<Setter Property="TextAlignment" Value="Center" />
|
||||
<Setter Property="FontFamily" Value="Segoe UI" />
|
||||
<Setter Property="FontWeight" Value="Light" />
|
||||
<Setter Property="FontSize" Value="10" />
|
||||
<Setter Property="Foreground" Value="#303030" />
|
||||
</Style>
|
||||
<Style x:Key="desktopButtonStyle" TargetType="Button">
|
||||
<Setter Property="Background" Value="#DADADA" />
|
||||
<Setter Property="Width" Value="{Binding DisplayWidth}" />
|
||||
<Setter Property="Height" Value="{Binding DisplayHeight}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
CornerRadius="0"
|
||||
BorderBrush="#303030"
|
||||
BorderThickness="2" >
|
||||
<ContentPresenter x:Name="contentPresenter"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
Content="{TemplateBinding Content}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Margin="{TemplateBinding Padding}" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#C2C2C2" />
|
||||
</Trigger>
|
||||
<DataTrigger Binding="{Binding Selected}" Value="true">
|
||||
<Setter Property="Background" Value="#0078D7" />
|
||||
</DataTrigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="templateBackground" TargetType="Border">
|
||||
<Setter Property="Background" Value="#F2F2F2"/>
|
||||
<Setter Property="CornerRadius" Value="4"/>
|
||||
<Setter Property="BorderThickness" Value="2"/>
|
||||
</Style>
|
||||
|
||||
<ControlTemplate x:Key="myTabs">
|
||||
<Grid Width="404">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40"/>
|
||||
<RowDefinition Height="2"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Name="myTabText" Text="{TemplateBinding TabItem.Header}" Style="{StaticResource tabText}" />
|
||||
<Rectangle Grid.Row="1" x:Name="myTabLine" Fill="#F2F2F2" Height="1"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="TabItem.IsSelected" Value="True">
|
||||
<Setter TargetName="myTabText" Property="Foreground" Value="#2A79D7"/>
|
||||
<Setter TargetName="myTabLine" Property="Fill" Value="#2A79D7" />
|
||||
<Setter TargetName="myTabLine" Property="Height" Value="2"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="desktopButton">
|
||||
<Button Style="{StaticResource desktopButtonStyle}"
|
||||
Command="{Binding DataContext.SelectCommand, ElementName= MainWindowItemControl}"
|
||||
CommandParameter="{Binding}"
|
||||
Margin="1,6,1,6">
|
||||
<Button.Content>
|
||||
<Grid Name="MonitorsGrid">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="0.40*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Name="desktopId" Text="{Binding Index}" Style="{StaticResource desktopIdText}" Grid.Row="0"/>
|
||||
<TextBlock Name="desktopDimensions" Text="{Binding Dimensions}" Style="{StaticResource desktopDimensionsText}" Grid.Row="1" />
|
||||
</Grid>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<ControlTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding Selected}" Value="true">
|
||||
<Setter TargetName="desktopId" Property="Foreground" Value="#F2F2F2" />
|
||||
<Setter TargetName="desktopDimensions" Property="Foreground" Value="#F2F2F2" />
|
||||
</DataTrigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Window.Resources>
|
||||
|
||||
<StackPanel FocusManager.FocusedElement="{Binding ElementName=decrementZones}">
|
||||
|
||||
<TextBlock Name="DialogTitle" Text="{x:Static props:Resources.Choose_Layout}" Style="{StaticResource titleText}" />
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||
ScrollViewer.CanContentScroll="True"
|
||||
ScrollViewer.PanningMode="HorizontalOnly"
|
||||
Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UIElement}}"
|
||||
PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">
|
||||
<ScrollViewer.DataContext>
|
||||
<local1:MonitorViewModel></local1:MonitorViewModel>
|
||||
</ScrollViewer.DataContext>
|
||||
<ItemsControl x:Name="MainWindowItemControl"
|
||||
ItemsSource="{Binding MonitorInfoForViewModel}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Background="Transparent"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="8, 16, 8, 8"
|
||||
Visibility="{Binding DesktopsPanelVisibility}"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button Template="{StaticResource desktopButton}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<TabControl BorderThickness="0" x:Name="TemplateTab" AutomationProperties.LabeledBy="{Binding ElementName=DialogTitle}" SelectedIndex="{Binding IsCustomLayoutActive, Mode=OneWay, Converter={StaticResource BooleanToIntConverter}}">
|
||||
<TabItem Header="{x:Static props:Resources.Templates}" Template="{StaticResource myTabs}" AutomationProperties.Name="{x:Static props:Resources.Tab_Item_Templates}">
|
||||
<StackPanel>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Margin="0,15,0,8" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button x:Name="decrementZones" Width="40" Height="40" AutomationProperties.Name="{x:Static props:Resources.Zone_Count_Decrement}" Content="-" Style="{StaticResource spinnerButton}" Click="DecrementZones_Click"/>
|
||||
<TextBlock x:Name="zoneCount" Text="{Binding ZoneCount}" Style="{StaticResource zoneCount}"/>
|
||||
<Button x:Name="incrementZones" Width="40" Height="40" AutomationProperties.Name="{x:Static props:Resources.Zone_Count_Increment}" Content="+" Style="{StaticResource spinnerButton}" Click="IncrementZones_Click"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<ItemsControl ItemsSource="{Binding DefaultModels}" Margin="8,0,0,0">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel Orientation="Horizontal"
|
||||
Margin="2"
|
||||
ItemWidth="{Binding ElementName=MainWindow1, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, Path=WrapPanelItemSize}"
|
||||
ItemHeight="{Binding ElementName=WrapPanel1, Path=ItemWidth}"
|
||||
x:Name="WrapPanel1" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="8"
|
||||
BorderBrush="{Binding Path=IsSelected, Converter={StaticResource BooleanToBrushConverter}}"
|
||||
Background="{Binding Path=IsApplied, Converter={StaticResource BooleanToBrushConverter}}"
|
||||
Style="{StaticResource templateBackground}"
|
||||
MouseDown="LayoutItem_Click"
|
||||
Focusable="True"
|
||||
FocusManager.GotFocus="LayoutItem_Focused"
|
||||
KeyDown="LayoutItem_Apply">
|
||||
<DockPanel Margin="0,20,0,0"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
LastChildFill="True">
|
||||
<TextBlock Name="layoutName"
|
||||
Padding="8,0,8,0"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
DockPanel.Dock="Top"
|
||||
Text="{Binding Name}"
|
||||
Style="{StaticResource templateTitleText}" />
|
||||
<local:LayoutPreview Margin="16" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding IsApplied}" Value="true">
|
||||
<Setter TargetName="layoutName" Property="Foreground" Value="#F2F2F2" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
|
||||
|
||||
<TabItem Header="{x:Static props:Resources.Custom}" Template="{StaticResource myTabs}" AutomationProperties.Name="{x:Static props:Resources.Tab_Item_Custom}">
|
||||
<StackPanel>
|
||||
<ItemsControl ItemsSource="{Binding CustomModels}" Margin="8,8,0,0">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel Orientation="Horizontal" ItemWidth="{Binding ElementName=MainWindow1, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, Path=WrapPanelItemSize}" ItemHeight="{Binding ElementName=WrapPanel2, Path=ItemWidth}" x:Name="WrapPanel2" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="8"
|
||||
BorderBrush="{Binding Path=IsSelected, Converter={StaticResource BooleanToBrushConverter}}"
|
||||
Background="{Binding Path=IsApplied, Converter={StaticResource BooleanToBrushConverter}}"
|
||||
Style="{StaticResource templateBackground}"
|
||||
MouseDown="LayoutItem_Click"
|
||||
Focusable="True"
|
||||
FocusManager.GotFocus="LayoutItem_Focused"
|
||||
KeyDown="LayoutItem_Apply">
|
||||
<DockPanel Margin="0,20,0,0"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
LastChildFill="True">
|
||||
<DockPanel DockPanel.Dock="Top" LastChildFill="True" >
|
||||
<Button x:Name="DeleteButton" AutomationProperties.Name="{x:Static props:Resources.Custom_Layout_Delete_Button}"
|
||||
Visibility="{Binding Converter={StaticResource ModelToVisibilityConverter}}"
|
||||
DockPanel.Dock="Right"
|
||||
MaxHeight="10"
|
||||
Click="OnDelete"
|
||||
Padding="8,4,8,4"
|
||||
Margin="0,0,8,0"
|
||||
BorderThickness="0"
|
||||
Background="#f2f2f2">
|
||||
<Image Source="images/Delete.png" />
|
||||
</Button>
|
||||
<TextBlock Name="layoutName"
|
||||
DockPanel.Dock="Top"
|
||||
TextTrimming="CharacterEllipsis" Padding="8,0,8,0"
|
||||
Text="{Binding Name}"
|
||||
Style="{StaticResource templateTitleText}" />
|
||||
</DockPanel>
|
||||
<local:LayoutPreview Margin="16" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding IsApplied}" Value="true">
|
||||
<Setter TargetName="layoutName" Property="Foreground" Value="#F2F2F2" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
<Grid Margin="10,4,10,8" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox x:Name="spaceAroundSetting" Content="{x:Static props:Resources.Show_Space_Zones}" Style="{StaticResource settingCheckBoxText}" IsChecked="{Binding ShowSpacing}" Grid.Row="0" Grid.Column="0"/>
|
||||
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
|
||||
<TextBlock x:Name="paddingValue"
|
||||
Text="{x:Static props:Resources.Space_Around_Zones}"
|
||||
Style="{StaticResource settingText}"
|
||||
IsEnabled="{Binding ShowSpacing}"
|
||||
MaxWidth="{Binding Path=SettingsTextMaxWidth, ElementName=MainWindow1}"
|
||||
TextWrapping="Wrap"/>
|
||||
<TextBox AutomationProperties.LabeledBy="{Binding ElementName=paddingValue}" Text="{Binding Path=Spacing,Mode=TwoWay}" Style="{StaticResource textBox}" MinWidth="32" IsEnabled="{Binding ShowSpacing}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal">
|
||||
<TextBlock x:Name="sensitivityRadiusValue"
|
||||
Text="{x:Static props:Resources.Distance_adjacent_zones}"
|
||||
Style="{StaticResource settingText}"
|
||||
MaxWidth="{Binding Path=SettingsTextMaxWidth, ElementName=MainWindow1}"
|
||||
TextWrapping="Wrap"/>
|
||||
<TextBox AutomationProperties.LabeledBy="{Binding ElementName=sensitivityRadiusValue}" Text="{Binding Path=SensitivityRadius,Mode=TwoWay}" Style="{StaticResource textBox}" MinWidth="40"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,16">
|
||||
<Button x:Name="EditCustomButton" Content="{x:Static props:Resources.Edit_Selected_Layout}" Padding="8" Style="{StaticResource secondaryButton}" Click="EditLayout_Click"/>
|
||||
<Button x:Name="ApplyCustomButton" Content="{x:Static props:Resources.Apply}" Padding="8" Style="{StaticResource primaryButton}" Click="Apply_Click"/>
|
||||
|
||||
<Button x:Name="CloseButton"
|
||||
Content="{x:Static props:Resources.Close}"
|
||||
Visibility="{Binding DesktopsPanelVisibility}"
|
||||
Padding="8"
|
||||
Style="{StaticResource secondaryButton}"
|
||||
Click="CloseButton_Click" >
|
||||
<Button.DataContext>
|
||||
<local1:MonitorViewModel></local1:MonitorViewModel>
|
||||
</Button.DataContext>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</Controls:MetroWindow>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
@@ -19,12 +18,16 @@ namespace FancyZonesEditor
|
||||
{
|
||||
// TODO: share the constants b/w C# Editor and FancyZoneLib
|
||||
public const int MaxZones = 40;
|
||||
private readonly Settings _settings = ((App)Application.Current).ZoneSettings;
|
||||
private const int DefaultWrapPanelItemSize = 262;
|
||||
private const int SmallWrapPanelItemSize = 180;
|
||||
private const int MinimalForDefaultWrapPanelsHeight = 900;
|
||||
|
||||
private readonly MainWindowSettingsModel _settings = ((App)Application.Current).MainWindowSettings;
|
||||
|
||||
// Localizable string
|
||||
private static readonly string _defaultNamePrefix = "Custom Layout ";
|
||||
|
||||
public int WrapPanelItemSize { get; set; } = 262;
|
||||
public int WrapPanelItemSize { get; set; } = DefaultWrapPanelItemSize;
|
||||
|
||||
public double SettingsTextMaxWidth
|
||||
{
|
||||
@@ -34,20 +37,31 @@ namespace FancyZonesEditor
|
||||
}
|
||||
}
|
||||
|
||||
public MainWindow()
|
||||
public MainWindow(bool spanZonesAcrossMonitors, Rect workArea)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = _settings;
|
||||
|
||||
KeyUp += MainWindow_KeyUp;
|
||||
|
||||
if (Settings.WorkArea.Height < 900)
|
||||
if (spanZonesAcrossMonitors)
|
||||
{
|
||||
WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||
}
|
||||
|
||||
if (workArea.Height < MinimalForDefaultWrapPanelsHeight || App.Overlay.MultiMonitorMode)
|
||||
{
|
||||
SizeToContent = SizeToContent.WidthAndHeight;
|
||||
WrapPanelItemSize = 180;
|
||||
WrapPanelItemSize = SmallWrapPanelItemSize;
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
DataContext = _settings;
|
||||
SetSelectedItem();
|
||||
}
|
||||
|
||||
private void MainWindow_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Escape)
|
||||
@@ -101,19 +115,19 @@ namespace FancyZonesEditor
|
||||
|
||||
private void Select(LayoutModel newSelection)
|
||||
{
|
||||
if (EditorOverlay.Current.DataContext is LayoutModel currentSelection)
|
||||
if (App.Overlay.CurrentDataContext is LayoutModel currentSelection)
|
||||
{
|
||||
currentSelection.IsSelected = false;
|
||||
}
|
||||
|
||||
newSelection.IsSelected = true;
|
||||
EditorOverlay.Current.DataContext = newSelection;
|
||||
App.Overlay.CurrentDataContext = newSelection;
|
||||
}
|
||||
|
||||
private void EditLayout_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
EditorOverlay mainEditor = EditorOverlay.Current;
|
||||
if (!(mainEditor.DataContext is LayoutModel model))
|
||||
var mainEditor = App.Overlay;
|
||||
if (!(mainEditor.CurrentDataContext is LayoutModel model))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -121,19 +135,19 @@ namespace FancyZonesEditor
|
||||
model.IsSelected = false;
|
||||
Hide();
|
||||
|
||||
bool isPredefinedLayout = Settings.IsPredefinedLayout(model);
|
||||
bool isPredefinedLayout = MainWindowSettingsModel.IsPredefinedLayout(model);
|
||||
|
||||
if (!Settings.CustomModels.Contains(model) || isPredefinedLayout)
|
||||
if (!MainWindowSettingsModel.CustomModels.Contains(model) || isPredefinedLayout)
|
||||
{
|
||||
if (isPredefinedLayout)
|
||||
{
|
||||
// make a copy
|
||||
model = model.Clone();
|
||||
mainEditor.DataContext = model;
|
||||
mainEditor.CurrentDataContext = model;
|
||||
}
|
||||
|
||||
int maxCustomIndex = 0;
|
||||
foreach (LayoutModel customModel in Settings.CustomModels)
|
||||
foreach (LayoutModel customModel in MainWindowSettingsModel.CustomModels)
|
||||
{
|
||||
string name = customModel.Name;
|
||||
if (name.StartsWith(_defaultNamePrefix))
|
||||
@@ -151,32 +165,7 @@ namespace FancyZonesEditor
|
||||
model.Name = _defaultNamePrefix + (++maxCustomIndex);
|
||||
}
|
||||
|
||||
mainEditor.Edit();
|
||||
|
||||
EditorWindow window;
|
||||
bool isGrid = false;
|
||||
if (model is GridLayoutModel)
|
||||
{
|
||||
window = new GridEditorWindow();
|
||||
isGrid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
window = new CanvasEditorWindow();
|
||||
}
|
||||
|
||||
window.Owner = EditorOverlay.Current;
|
||||
|
||||
window.DataContext = model;
|
||||
window.Show();
|
||||
|
||||
if (isGrid)
|
||||
{
|
||||
(window as GridEditorWindow).NameTextBox().Focus();
|
||||
}
|
||||
|
||||
window.LeftWindowCommands = null;
|
||||
window.RightWindowCommands = null;
|
||||
mainEditor.OpenEditor(model);
|
||||
}
|
||||
|
||||
private void Apply_Click(object sender, RoutedEventArgs e)
|
||||
@@ -186,20 +175,16 @@ namespace FancyZonesEditor
|
||||
|
||||
private void Apply()
|
||||
{
|
||||
EditorOverlay mainEditor = EditorOverlay.Current;
|
||||
((App)Application.Current).MainWindowSettings.ResetAppliedModel();
|
||||
|
||||
if (mainEditor.DataContext is LayoutModel model)
|
||||
var mainEditor = App.Overlay;
|
||||
if (mainEditor.CurrentDataContext is LayoutModel model)
|
||||
{
|
||||
// If custom canvas layout has been scaled, persisting is needed
|
||||
if (model is CanvasLayoutModel && (model as CanvasLayoutModel).IsScaled)
|
||||
{
|
||||
model.Persist();
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Apply();
|
||||
}
|
||||
model.Apply();
|
||||
}
|
||||
|
||||
if (!mainEditor.MultiMonitorMode)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
@@ -207,7 +192,7 @@ namespace FancyZonesEditor
|
||||
private void OnClosing(object sender, EventArgs e)
|
||||
{
|
||||
LayoutModel.SerializeDeletedCustomZoneSets();
|
||||
EditorOverlay.Current.Close();
|
||||
App.Overlay.CloseLayoutWindow();
|
||||
}
|
||||
|
||||
private void OnInitialized(object sender, EventArgs e)
|
||||
@@ -217,7 +202,7 @@ namespace FancyZonesEditor
|
||||
|
||||
private void SetSelectedItem()
|
||||
{
|
||||
foreach (LayoutModel model in Settings.CustomModels)
|
||||
foreach (LayoutModel model in MainWindowSettingsModel.CustomModels)
|
||||
{
|
||||
if (model.IsSelected)
|
||||
{
|
||||
@@ -237,5 +222,25 @@ namespace FancyZonesEditor
|
||||
|
||||
model.Delete();
|
||||
}
|
||||
|
||||
private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
ScrollViewer scrollviewer = sender as ScrollViewer;
|
||||
if (e.Delta > 0)
|
||||
{
|
||||
scrollviewer.LineLeft();
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollviewer.LineRight();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void CloseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
397
src/modules/fancyzones/editor/FancyZonesEditor/Overlay.cs
Normal file
397
src/modules/fancyzones/editor/FancyZonesEditor/Overlay.cs
Normal file
@@ -0,0 +1,397 @@
|
||||
// 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.Windows;
|
||||
using System.Windows.Controls;
|
||||
using FancyZonesEditor.Models;
|
||||
|
||||
namespace FancyZonesEditor
|
||||
{
|
||||
public class Overlay
|
||||
{
|
||||
private MainWindow _mainWindow;
|
||||
|
||||
private LayoutPreview _layoutPreview;
|
||||
private UserControl _editor;
|
||||
|
||||
public List<Monitor> Monitors { get; private set; }
|
||||
|
||||
public Rect WorkArea
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Monitors.Count > 0 && CurrentDesktop < Monitors.Count)
|
||||
{
|
||||
return Monitors[CurrentDesktop].Device.WorkAreaRect;
|
||||
}
|
||||
|
||||
return default(Rect);
|
||||
}
|
||||
}
|
||||
|
||||
public LayoutSettings CurrentLayoutSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Monitors.Count > 0 && CurrentDesktop < Monitors.Count)
|
||||
{
|
||||
return Monitors[CurrentDesktop].Settings;
|
||||
}
|
||||
|
||||
return new LayoutSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public Window CurrentLayoutWindow
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Monitors.Count > 0 && CurrentDesktop < Monitors.Count)
|
||||
{
|
||||
return Monitors[CurrentDesktop].Window;
|
||||
}
|
||||
|
||||
return default(Window);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Rect> WorkAreas { get; private set; }
|
||||
|
||||
public object CurrentDataContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return _dataContext;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_dataContext = value;
|
||||
CurrentLayoutWindow.DataContext = value;
|
||||
}
|
||||
}
|
||||
|
||||
private object _dataContext;
|
||||
|
||||
public int DesktopsCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return Monitors.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public int CurrentDesktop
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentDesktop;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value != _currentDesktop)
|
||||
{
|
||||
if (value < 0 || value >= DesktopsCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var prevSettings = CurrentLayoutSettings;
|
||||
_currentDesktop = value;
|
||||
|
||||
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
|
||||
if (settings != null)
|
||||
{
|
||||
settings.ResetAppliedModel();
|
||||
settings.UpdateDesktopDependantProperties(prevSettings);
|
||||
}
|
||||
|
||||
Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _currentDesktop = 0;
|
||||
|
||||
public bool SpanZonesAcrossMonitors
|
||||
{
|
||||
get
|
||||
{
|
||||
return _spanZonesAcrossMonitors;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_spanZonesAcrossMonitors = value;
|
||||
|
||||
if (_spanZonesAcrossMonitors)
|
||||
{
|
||||
Rect workArea = default(Rect);
|
||||
Rect bounds = default(Rect);
|
||||
|
||||
foreach (Monitor monitor in Monitors)
|
||||
{
|
||||
workArea = Rect.Union(workArea, monitor.Device.WorkAreaRect);
|
||||
bounds = Rect.Union(bounds, monitor.Device.ScaledBounds);
|
||||
}
|
||||
|
||||
Monitors.Clear();
|
||||
Monitors.Add(new Monitor(bounds, workArea, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _spanZonesAcrossMonitors;
|
||||
|
||||
public bool MultiMonitorMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return DesktopsCount > 1 && !SpanZonesAcrossMonitors;
|
||||
}
|
||||
}
|
||||
|
||||
public Overlay()
|
||||
{
|
||||
WorkAreas = new List<Rect>();
|
||||
Monitors = new List<Monitor>();
|
||||
|
||||
var screens = System.Windows.Forms.Screen.AllScreens;
|
||||
foreach (System.Windows.Forms.Screen screen in screens)
|
||||
{
|
||||
Rect bounds = new Rect(screen.Bounds.X, screen.Bounds.Y, screen.Bounds.Width, screen.Bounds.Height);
|
||||
Rect workArea = new Rect(screen.WorkingArea.X, screen.WorkingArea.Y, screen.WorkingArea.Width, screen.WorkingArea.Height);
|
||||
Add(bounds, workArea, screen.Primary);
|
||||
}
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
_layoutPreview = new LayoutPreview
|
||||
{
|
||||
IsActualSize = true,
|
||||
Opacity = 0.5,
|
||||
};
|
||||
|
||||
ShowLayout();
|
||||
OpenMainWindow();
|
||||
}
|
||||
|
||||
public void ShowLayout()
|
||||
{
|
||||
MainWindowSettingsModel settings = ((App)Application.Current).MainWindowSettings;
|
||||
CurrentDataContext = settings.UpdateSelectedLayoutModel();
|
||||
|
||||
var window = CurrentLayoutWindow;
|
||||
window.Content = _layoutPreview;
|
||||
window.DataContext = CurrentDataContext;
|
||||
|
||||
if (_layoutPreview != null)
|
||||
{
|
||||
_layoutPreview.UpdatePreview();
|
||||
}
|
||||
|
||||
for (int i = 0; i < DesktopsCount; i++)
|
||||
{
|
||||
Monitors[i].Window.Show();
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenEditor(LayoutModel model)
|
||||
{
|
||||
_layoutPreview = null;
|
||||
if (CurrentDataContext is GridLayoutModel)
|
||||
{
|
||||
_editor = new GridEditor();
|
||||
}
|
||||
else if (CurrentDataContext is CanvasLayoutModel)
|
||||
{
|
||||
_editor = new CanvasEditor();
|
||||
}
|
||||
|
||||
CurrentLayoutWindow.Content = _editor;
|
||||
|
||||
EditorWindow window;
|
||||
bool isGrid = false;
|
||||
if (model is GridLayoutModel)
|
||||
{
|
||||
window = new GridEditorWindow();
|
||||
isGrid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
window = new CanvasEditorWindow();
|
||||
}
|
||||
|
||||
window.Owner = Monitors[App.Overlay.CurrentDesktop].Window;
|
||||
window.DataContext = model;
|
||||
window.Show();
|
||||
|
||||
if (isGrid)
|
||||
{
|
||||
(window as GridEditorWindow).NameTextBox().Focus();
|
||||
}
|
||||
|
||||
window.LeftWindowCommands = null;
|
||||
window.RightWindowCommands = null;
|
||||
}
|
||||
|
||||
public void CloseEditor()
|
||||
{
|
||||
_editor = null;
|
||||
_layoutPreview = new LayoutPreview
|
||||
{
|
||||
IsActualSize = true,
|
||||
Opacity = 0.5,
|
||||
};
|
||||
|
||||
CurrentLayoutWindow.Content = _layoutPreview;
|
||||
|
||||
OpenMainWindow();
|
||||
}
|
||||
|
||||
public void CloseLayoutWindow()
|
||||
{
|
||||
for (int i = 0; i < DesktopsCount; i++)
|
||||
{
|
||||
Monitors[i].Window.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public double ScaleCoordinateWithCurrentMonitorDpi(double coordinate)
|
||||
{
|
||||
if (Monitors.Count == 0)
|
||||
{
|
||||
return coordinate;
|
||||
}
|
||||
|
||||
double minimalDpi = Monitors[0].Device.Dpi;
|
||||
foreach (Monitor monitor in Monitors)
|
||||
{
|
||||
if (minimalDpi > monitor.Device.Dpi)
|
||||
{
|
||||
minimalDpi = monitor.Device.Dpi;
|
||||
}
|
||||
}
|
||||
|
||||
if (minimalDpi == 0 || Monitors[CurrentDesktop].Device.Dpi == 0)
|
||||
{
|
||||
return coordinate;
|
||||
}
|
||||
|
||||
double scaleFactor = minimalDpi / Monitors[CurrentDesktop].Device.Dpi;
|
||||
return Math.Round(coordinate * scaleFactor);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
CloseLayout();
|
||||
|
||||
if (_mainWindow != null)
|
||||
{
|
||||
_mainWindow.Update();
|
||||
}
|
||||
|
||||
ShowLayout();
|
||||
}
|
||||
|
||||
private void CloseLayout()
|
||||
{
|
||||
var window = CurrentLayoutWindow;
|
||||
window.Content = null;
|
||||
window.DataContext = null;
|
||||
}
|
||||
|
||||
private void OpenMainWindow()
|
||||
{
|
||||
if (_mainWindow == null)
|
||||
{
|
||||
_mainWindow = new MainWindow(SpanZonesAcrossMonitors, WorkArea);
|
||||
}
|
||||
|
||||
// reset main window owner to keep it on the top
|
||||
_mainWindow.Owner = CurrentLayoutWindow;
|
||||
_mainWindow.ShowActivated = true;
|
||||
_mainWindow.Topmost = true;
|
||||
_mainWindow.Show();
|
||||
_mainWindow.LeftWindowCommands = null;
|
||||
_mainWindow.RightWindowCommands = null;
|
||||
|
||||
// window is set to topmost to make sure it shows on top of PowerToys settings page
|
||||
// we can reset topmost flag now
|
||||
_mainWindow.Topmost = false;
|
||||
}
|
||||
|
||||
private void Add(Rect bounds, Rect workArea, bool primary)
|
||||
{
|
||||
var monitor = new Monitor(bounds, workArea, primary);
|
||||
|
||||
bool inserted = false;
|
||||
var workAreaRect = workArea;
|
||||
for (int i = 0; i < Monitors.Count && !inserted; i++)
|
||||
{
|
||||
var rect = Monitors[i].Device.WorkAreaRect;
|
||||
if (workAreaRect.Left < rect.Left && (workAreaRect.Top <= rect.Top || workAreaRect.Top == 0))
|
||||
{
|
||||
Monitors.Insert(i, monitor);
|
||||
inserted = true;
|
||||
}
|
||||
else if (workAreaRect.Left == rect.Left && workAreaRect.Top < rect.Top)
|
||||
{
|
||||
Monitors.Insert(i, monitor);
|
||||
inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inserted)
|
||||
{
|
||||
Monitors.Add(monitor);
|
||||
}
|
||||
}
|
||||
|
||||
public Int32Rect[] GetZoneRects()
|
||||
{
|
||||
if (_editor != null)
|
||||
{
|
||||
if (_editor is GridEditor gridEditor)
|
||||
{
|
||||
return ZoneRectsFromPanel(gridEditor.PreviewPanel);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CanvasEditor
|
||||
return ZoneRectsFromPanel(((CanvasEditor)_editor).Preview);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// One of the predefined zones (neither grid or canvas editor used).
|
||||
return _layoutPreview.GetZoneRects();
|
||||
}
|
||||
}
|
||||
|
||||
private Int32Rect[] ZoneRectsFromPanel(Panel previewPanel)
|
||||
{
|
||||
// TODO: the ideal here is that the ArrangeRects logic is entirely inside the model, so we don't have to walk the UIElement children to get the rect info
|
||||
int count = previewPanel.Children.Count;
|
||||
Int32Rect[] zones = new Int32Rect[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
FrameworkElement child = (FrameworkElement)previewPanel.Children[i];
|
||||
Point topLeft = child.TransformToAncestor(previewPanel).Transform(default);
|
||||
|
||||
zones[i].X = (int)topLeft.X;
|
||||
zones[i].Y = (int)topLeft.Y;
|
||||
zones[i].Width = (int)child.ActualWidth;
|
||||
zones[i].Height = (int)child.ActualHeight;
|
||||
}
|
||||
|
||||
return zones;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,15 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Close.
|
||||
/// </summary>
|
||||
public static string Close {
|
||||
get {
|
||||
return ResourceManager.GetString("Close", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error logged to .
|
||||
/// </summary>
|
||||
@@ -186,6 +195,24 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error applying layout.
|
||||
/// </summary>
|
||||
public static string Error_Applying_Layout {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Applying_Layout", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to FancyZones Editor Exception Handler.
|
||||
/// </summary>
|
||||
public static string Error_Exception_Message_Box_Title {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Exception_Message_Box_Title", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to FancyZones Editor arguments are invalid..
|
||||
/// </summary>
|
||||
@@ -195,6 +222,24 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Layout '{0}' has malformed data.
|
||||
/// </summary>
|
||||
public static string Error_Layout_Malformed_Data {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Layout_Malformed_Data", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error loading custom layouts.
|
||||
/// </summary>
|
||||
public static string Error_Loading_Custom_Layouts {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Loading_Custom_Layouts", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to FancyZones Editor Error.
|
||||
/// </summary>
|
||||
@@ -204,6 +249,15 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Match not found ({0}).
|
||||
/// </summary>
|
||||
public static string Error_Monitor_Match_Not_Found {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Monitor_Match_Not_Found", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to FancyZones Editor should not be run as standalone application..
|
||||
/// </summary>
|
||||
@@ -222,6 +276,33 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error persisting custom layout.
|
||||
/// </summary>
|
||||
public static string Error_Persisting_Custom_Layout {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Persisting_Custom_Layout", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please report the bug to .
|
||||
/// </summary>
|
||||
public static string Error_Report {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Report", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error serializing deleted layouts.
|
||||
/// </summary>
|
||||
public static string Error_Serializing_Deleted_Layouts {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Serializing_Deleted_Layouts", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to FancyZones Editor.
|
||||
/// </summary>
|
||||
|
||||
@@ -226,4 +226,31 @@
|
||||
<data name="Tab_Item_Templates" xml:space="preserve">
|
||||
<value>Templates tab selected, press ctrl + tab to switch to Custom</value>
|
||||
</data>
|
||||
<data name="Close" xml:space="preserve">
|
||||
<value>Close</value>
|
||||
</data>
|
||||
<data name="Error_Applying_Layout" xml:space="preserve">
|
||||
<value>Error applying layout</value>
|
||||
</data>
|
||||
<data name="Error_Layout_Malformed_Data" xml:space="preserve">
|
||||
<value>Layout '{0}' has malformed data</value>
|
||||
</data>
|
||||
<data name="Error_Loading_Custom_Layouts" xml:space="preserve">
|
||||
<value>Error loading custom layouts</value>
|
||||
</data>
|
||||
<data name="Error_Persisting_Custom_Layout" xml:space="preserve">
|
||||
<value>Error persisting custom layout</value>
|
||||
</data>
|
||||
<data name="Error_Serializing_Deleted_Layouts" xml:space="preserve">
|
||||
<value>Error serializing deleted layouts</value>
|
||||
</data>
|
||||
<data name="Error_Exception_Message_Box_Title" xml:space="preserve">
|
||||
<value>FancyZones Editor Exception Handler</value>
|
||||
</data>
|
||||
<data name="Error_Report" xml:space="preserve">
|
||||
<value>Please report the bug to </value>
|
||||
</data>
|
||||
<data name="Error_Monitor_Match_Not_Found" xml:space="preserve">
|
||||
<value>Match not found ({0})</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,18 @@
|
||||
// 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;
|
||||
|
||||
namespace FancyZonesEditor.Utils
|
||||
{
|
||||
public class EventArgs<T> : EventArgs
|
||||
{
|
||||
public EventArgs(T value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public T Value { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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;
|
||||
|
||||
namespace FancyZonesEditor.Utils
|
||||
{
|
||||
public static class EventRaiser
|
||||
{
|
||||
public static void Raise(this EventHandler handler, object sender)
|
||||
{
|
||||
handler?.Invoke(sender, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, T value)
|
||||
{
|
||||
handler?.Invoke(sender, new EventArgs<T>(value));
|
||||
}
|
||||
|
||||
public static void Raise<T>(this EventHandler<T> handler, object sender, T value)
|
||||
where T : EventArgs
|
||||
{
|
||||
handler?.Invoke(sender, value);
|
||||
}
|
||||
|
||||
public static void Raise<T>(this EventHandler<EventArgs<T>> handler, object sender, EventArgs<T> value)
|
||||
{
|
||||
handler?.Invoke(sender, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,678 @@
|
||||
// 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.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
using FancyZonesEditor.Models;
|
||||
|
||||
namespace FancyZonesEditor.Utils
|
||||
{
|
||||
public class FancyZonesEditorIO
|
||||
{
|
||||
// Non-localizable strings: JSON tags
|
||||
private const string AppliedZonesetsJsonTag = "applied-zonesets";
|
||||
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 NameJsonTag = "name";
|
||||
private const string CustomZoneSetsJsonTag = "custom-zone-sets";
|
||||
private const string InfoJsonTag = "info";
|
||||
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";
|
||||
|
||||
// Non-localizable strings: Files
|
||||
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 readonly IFileSystem _fileSystem = new FileSystem();
|
||||
|
||||
private JsonSerializerOptions _options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = new DashCaseNamingPolicy(),
|
||||
};
|
||||
|
||||
public string ActiveZoneSetTmpFile { get; private set; }
|
||||
|
||||
public string AppliedZoneSetTmpFile { get; private set; }
|
||||
|
||||
public string DeletedCustomZoneSetsTmpFile { get; private set; }
|
||||
|
||||
public string FancyZonesSettingsFile { get; private set; }
|
||||
|
||||
private enum CmdArgs
|
||||
{
|
||||
PowerToysPID = 0,
|
||||
SpanZones,
|
||||
TargetMonitorId,
|
||||
MonitorsCount,
|
||||
MonitorId,
|
||||
DPI,
|
||||
MonitorLeft,
|
||||
MonitorTop,
|
||||
}
|
||||
|
||||
private struct NativeMonitorData
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public int Dpi { get; set; }
|
||||
|
||||
public int X { get; set; }
|
||||
|
||||
public int Y { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append("ID: ");
|
||||
sb.AppendLine(Id);
|
||||
sb.Append("DPI: ");
|
||||
sb.AppendLine(Dpi.ToString());
|
||||
|
||||
sb.Append("X: ");
|
||||
sb.AppendLine(X.ToString());
|
||||
sb.Append("Y: ");
|
||||
sb.AppendLine(Y.ToString());
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
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; }
|
||||
}
|
||||
|
||||
private struct AppliedZonesetsToDesktops
|
||||
{
|
||||
public List<AppliedZoneSet> AppliedZonesets { get; set; }
|
||||
}
|
||||
|
||||
private struct DeletedCustomZoneSetsWrapper
|
||||
{
|
||||
public List<string> DeletedCustomZoneSets { get; set; }
|
||||
}
|
||||
|
||||
private struct CreatedCustomZoneSetsWrapper
|
||||
{
|
||||
public List<JsonElement> CreatedCustomZoneSets { get; set; }
|
||||
}
|
||||
|
||||
public FancyZonesEditorIO()
|
||||
{
|
||||
string tmpDirPath = _fileSystem.Path.GetTempPath();
|
||||
|
||||
ActiveZoneSetTmpFile = tmpDirPath + ActiveZoneSetsTmpFileName;
|
||||
AppliedZoneSetTmpFile = tmpDirPath + AppliedZoneSetsTmpFileName;
|
||||
DeletedCustomZoneSetsTmpFile = tmpDirPath + DeletedCustomZoneSetsTmpFileName;
|
||||
|
||||
var localAppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
FancyZonesSettingsFile = localAppDataDir + ZonesSettingsFile;
|
||||
}
|
||||
|
||||
// All strings in this function shouldn't be localized.
|
||||
public static void ParseCommandLineArguments()
|
||||
{
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
|
||||
if (args.Length < 2 && !App.DebugMode)
|
||||
{
|
||||
MessageBox.Show(Properties.Resources.Error_Not_Standalone_App, Properties.Resources.Error_Message_Box_Title);
|
||||
((App)Application.Current).Shutdown();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
/*
|
||||
* Divider: /
|
||||
* Parts:
|
||||
* (1) Process id
|
||||
* (2) Span zones across monitors
|
||||
* (3) Monitor id where the Editor should be opened
|
||||
* (4) Monitors count
|
||||
*
|
||||
* Data for each monitor:
|
||||
* (5) Monitor id
|
||||
* (6) DPI
|
||||
* (7) monitor left
|
||||
* (8) monitor top
|
||||
* ...
|
||||
*/
|
||||
var argsParts = args[1].Split('/');
|
||||
|
||||
// Process ID
|
||||
App.PowerToysPID = int.Parse(argsParts[(int)CmdArgs.PowerToysPID]);
|
||||
|
||||
// Span zones across monitors
|
||||
App.Overlay.SpanZonesAcrossMonitors = int.Parse(argsParts[(int)CmdArgs.SpanZones]) == 1;
|
||||
|
||||
if (!App.Overlay.SpanZonesAcrossMonitors)
|
||||
{
|
||||
// Target monitor id
|
||||
string targetMonitorName = argsParts[(int)CmdArgs.TargetMonitorId];
|
||||
|
||||
// Monitors count
|
||||
int count = int.Parse(argsParts[(int)CmdArgs.MonitorsCount]);
|
||||
if (count != App.Overlay.DesktopsCount)
|
||||
{
|
||||
MessageBox.Show(Properties.Resources.Error_Invalid_Arguments, Properties.Resources.Error_Message_Box_Title);
|
||||
((App)Application.Current).Shutdown();
|
||||
}
|
||||
|
||||
double primaryMonitorDPI = 96f;
|
||||
double minimalUsedMonitorDPI = double.MaxValue;
|
||||
|
||||
// Parse the native monitor data
|
||||
List<NativeMonitorData> nativeMonitorData = new List<NativeMonitorData>();
|
||||
const int monitorArgsCount = 4;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var nativeData = default(NativeMonitorData);
|
||||
nativeData.Id = argsParts[(int)CmdArgs.MonitorId + (i * monitorArgsCount)];
|
||||
nativeData.Dpi = int.Parse(argsParts[(int)CmdArgs.DPI + (i * monitorArgsCount)]);
|
||||
nativeData.X = int.Parse(argsParts[(int)CmdArgs.MonitorLeft + (i * monitorArgsCount)]);
|
||||
nativeData.Y = int.Parse(argsParts[(int)CmdArgs.MonitorTop + (i * monitorArgsCount)]);
|
||||
nativeMonitorData.Add(nativeData);
|
||||
|
||||
if (nativeData.X == 0 && nativeData.Y == 0)
|
||||
{
|
||||
primaryMonitorDPI = nativeData.Dpi;
|
||||
}
|
||||
|
||||
if (minimalUsedMonitorDPI > nativeData.Dpi)
|
||||
{
|
||||
minimalUsedMonitorDPI = nativeData.Dpi;
|
||||
}
|
||||
}
|
||||
|
||||
var monitors = App.Overlay.Monitors;
|
||||
double identifyScaleFactor = minimalUsedMonitorDPI / primaryMonitorDPI;
|
||||
double scaleFactor = 96f / primaryMonitorDPI;
|
||||
|
||||
// Update monitors data
|
||||
foreach (Monitor monitor in monitors)
|
||||
{
|
||||
bool matchFound = false;
|
||||
monitor.Scale(scaleFactor);
|
||||
|
||||
double scaledBoundX = (int)(monitor.Device.UnscaledBounds.X * identifyScaleFactor);
|
||||
double scaledBoundY = (int)(monitor.Device.UnscaledBounds.Y * identifyScaleFactor);
|
||||
|
||||
foreach (NativeMonitorData nativeData in nativeMonitorData)
|
||||
{
|
||||
// Can't do an exact match since the rounding algorithm used by the framework is different from ours
|
||||
if (scaledBoundX >= (nativeData.X - 1) && scaledBoundX <= (nativeData.X + 1) &&
|
||||
scaledBoundY >= (nativeData.Y - 1) && scaledBoundY <= (nativeData.Y + 1))
|
||||
{
|
||||
monitor.Device.Id = nativeData.Id;
|
||||
monitor.Device.Dpi = nativeData.Dpi;
|
||||
matchFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchFound == false)
|
||||
{
|
||||
MessageBox.Show(string.Format(Properties.Resources.Error_Monitor_Match_Not_Found, monitor.Device.UnscaledBounds.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
// Set active desktop
|
||||
for (int i = 0; i < monitors.Count; i++)
|
||||
{
|
||||
var monitor = monitors[i];
|
||||
if (monitor.Device.Id == targetMonitorName)
|
||||
{
|
||||
App.Overlay.CurrentDesktop = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
MessageBox.Show(Properties.Resources.Error_Invalid_Arguments, Properties.Resources.Error_Message_Box_Title);
|
||||
((App)Application.Current).Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void ParseDeviceInfoData()
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonElement jsonObject = default(JsonElement);
|
||||
|
||||
if (_fileSystem.File.Exists(ActiveZoneSetTmpFile))
|
||||
{
|
||||
Stream inputStream = _fileSystem.File.Open(ActiveZoneSetTmpFile, FileMode.Open);
|
||||
jsonObject = JsonDocument.Parse(inputStream, options: default).RootElement;
|
||||
inputStream.Close();
|
||||
|
||||
JsonElement json = jsonObject.GetProperty(AppliedZonesetsJsonTag);
|
||||
|
||||
int layoutId = 0;
|
||||
for (int i = 0; i < json.GetArrayLength() && layoutId < App.Overlay.DesktopsCount; i++)
|
||||
{
|
||||
var zonesetData = json[i];
|
||||
|
||||
string deviceId = zonesetData.GetProperty(DeviceIdJsonTag).GetString();
|
||||
|
||||
string currentLayoutType = zonesetData.GetProperty(ActiveZoneSetJsonTag).GetProperty(TypeJsonTag).GetString();
|
||||
LayoutType type = JsonTagToLayoutType(currentLayoutType);
|
||||
|
||||
if (!App.Overlay.SpanZonesAcrossMonitors)
|
||||
{
|
||||
var monitors = App.Overlay.Monitors;
|
||||
for (int monitorIndex = 0; monitorIndex < monitors.Count; monitorIndex++)
|
||||
{
|
||||
if (monitors[monitorIndex].Device.Id == deviceId)
|
||||
{
|
||||
monitors[monitorIndex].Settings = new LayoutSettings
|
||||
{
|
||||
DeviceId = deviceId,
|
||||
ZonesetUuid = zonesetData.GetProperty(ActiveZoneSetJsonTag).GetProperty(UuidJsonTag).GetString(),
|
||||
ShowSpacing = zonesetData.GetProperty(EditorShowSpacingJsonTag).GetBoolean(),
|
||||
Spacing = zonesetData.GetProperty(EditorSpacingJsonTag).GetInt32(),
|
||||
Type = type,
|
||||
ZoneCount = zonesetData.GetProperty(EditorZoneCountJsonTag).GetInt32(),
|
||||
SensitivityRadius = zonesetData.GetProperty(EditorSensitivityRadiusJsonTag).GetInt32(),
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isLayoutMultiMonitor = deviceId.StartsWith("FancyZones#MultiMonitorDevice");
|
||||
if (isLayoutMultiMonitor)
|
||||
{
|
||||
// one zoneset for all desktops
|
||||
App.Overlay.Monitors[App.Overlay.CurrentDesktop].Settings = new LayoutSettings
|
||||
{
|
||||
DeviceId = deviceId,
|
||||
ZonesetUuid = zonesetData.GetProperty(ActiveZoneSetJsonTag).GetProperty(UuidJsonTag).GetString(),
|
||||
ShowSpacing = zonesetData.GetProperty(EditorShowSpacingJsonTag).GetBoolean(),
|
||||
Spacing = zonesetData.GetProperty(EditorSpacingJsonTag).GetInt32(),
|
||||
Type = type,
|
||||
ZoneCount = zonesetData.GetProperty(EditorZoneCountJsonTag).GetInt32(),
|
||||
SensitivityRadius = zonesetData.GetProperty(EditorSensitivityRadiusJsonTag).GetInt32(),
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.ShowExceptionMessageBox(Properties.Resources.Error_Parsing_Device_Info, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void ParseLayouts(ref ObservableCollection<LayoutModel> custom, ref List<string> deleted)
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream inputStream = _fileSystem.File.Open(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(NameJsonTag).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)
|
||||
{
|
||||
App.ShowExceptionMessageBox(string.Format(Properties.Resources.Error_Layout_Malformed_Data, name));
|
||||
deleted.Add(Guid.Parse(uuid).ToString().ToUpper());
|
||||
continue;
|
||||
}
|
||||
|
||||
custom.Add(new GridLayoutModel(uuid, name, LayoutType.Custom, rows, columns, rowsPercentage, columnsPercentage, cellChildMap));
|
||||
}
|
||||
else if (type.Equals(CanvasJsonTag))
|
||||
{
|
||||
int workAreaWidth = info.GetProperty(RefWidthJsonTag).GetInt32();
|
||||
int workAreaHeight = info.GetProperty(RefHeightJsonTag).GetInt32();
|
||||
|
||||
JsonElement.ArrayEnumerator zonesEnumerator = info.GetProperty(ZonesJsonTag).EnumerateArray();
|
||||
IList<Int32Rect> zones = new List<Int32Rect>();
|
||||
|
||||
bool error = false;
|
||||
|
||||
if (workAreaWidth <= 0 || workAreaHeight <= 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)
|
||||
{
|
||||
App.ShowExceptionMessageBox(string.Format(Properties.Resources.Error_Layout_Malformed_Data, name));
|
||||
deleted.Add(Guid.Parse(uuid).ToString().ToUpper());
|
||||
continue;
|
||||
}
|
||||
|
||||
custom.Add(new CanvasLayoutModel(uuid, name, LayoutType.Custom, zones, workAreaWidth, workAreaHeight));
|
||||
}
|
||||
}
|
||||
|
||||
inputStream.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.ShowExceptionMessageBox(Properties.Resources.Error_Loading_Custom_Layouts, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void SerializeAppliedLayouts()
|
||||
{
|
||||
AppliedZonesetsToDesktops applied = new AppliedZonesetsToDesktops { };
|
||||
applied.AppliedZonesets = new List<AppliedZoneSet>();
|
||||
|
||||
foreach (var monitor in App.Overlay.Monitors)
|
||||
{
|
||||
LayoutSettings zoneset = monitor.Settings;
|
||||
if (zoneset.ZonesetUuid.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ActiveZoneSetWrapper activeZoneSet = new ActiveZoneSetWrapper
|
||||
{
|
||||
Uuid = zoneset.ZonesetUuid,
|
||||
};
|
||||
|
||||
activeZoneSet.Type = LayoutTypeToJsonTag(zoneset.Type);
|
||||
|
||||
applied.AppliedZonesets.Add(new AppliedZoneSet
|
||||
{
|
||||
DeviceId = zoneset.DeviceId,
|
||||
ActiveZoneset = activeZoneSet,
|
||||
EditorShowSpacing = zoneset.ShowSpacing,
|
||||
EditorSpacing = zoneset.Spacing,
|
||||
EditorZoneCount = zoneset.ZoneCount,
|
||||
EditorSensitivityRadius = zoneset.SensitivityRadius,
|
||||
});
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(applied, _options);
|
||||
_fileSystem.File.WriteAllText(ActiveZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.ShowExceptionMessageBox(Properties.Resources.Error_Applying_Layout, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void SerializeDeletedCustomZoneSets(List<string> models)
|
||||
{
|
||||
DeletedCustomZoneSetsWrapper deletedLayouts = new DeletedCustomZoneSetsWrapper
|
||||
{
|
||||
DeletedCustomZoneSets = models,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(deletedLayouts, _options);
|
||||
_fileSystem.File.WriteAllText(DeletedCustomZoneSetsTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.ShowExceptionMessageBox(Properties.Resources.Error_Serializing_Deleted_Layouts, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void SerializeCreatedCustomZonesets(List<JsonElement> models)
|
||||
{
|
||||
CreatedCustomZoneSetsWrapper layouts = new CreatedCustomZoneSetsWrapper
|
||||
{
|
||||
CreatedCustomZoneSets = models,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
string jsonString = JsonSerializer.Serialize(layouts, _options);
|
||||
_fileSystem.File.WriteAllText(AppliedZoneSetTmpFile, jsonString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.ShowExceptionMessageBox(Properties.Resources.Error_Persisting_Custom_Layout, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private LayoutType JsonTagToLayoutType(string tag)
|
||||
{
|
||||
LayoutType type = LayoutType.Blank;
|
||||
switch (tag)
|
||||
{
|
||||
case FocusJsonTag:
|
||||
type = LayoutType.Focus;
|
||||
break;
|
||||
case ColumnsJsonTag:
|
||||
type = LayoutType.Columns;
|
||||
break;
|
||||
case RowsJsonTag:
|
||||
type = LayoutType.Rows;
|
||||
break;
|
||||
case GridJsonTag:
|
||||
type = LayoutType.Grid;
|
||||
break;
|
||||
case PriorityGridJsonTag:
|
||||
type = LayoutType.PriorityGrid;
|
||||
break;
|
||||
case CustomJsonTag:
|
||||
type = LayoutType.Custom;
|
||||
break;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private string LayoutTypeToJsonTag(LayoutType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LayoutType.Focus:
|
||||
return FocusJsonTag;
|
||||
case LayoutType.Rows:
|
||||
return RowsJsonTag;
|
||||
case LayoutType.Columns:
|
||||
return ColumnsJsonTag;
|
||||
case LayoutType.Grid:
|
||||
return GridJsonTag;
|
||||
case LayoutType.PriorityGrid:
|
||||
return PriorityGridJsonTag;
|
||||
case LayoutType.Custom:
|
||||
return CustomJsonTag;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private static string ParsingCmdArgsErrorReport(string args, int count, string targetMonitorName, List<NativeMonitorData> monitorData, List<Monitor> monitors)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("```");
|
||||
sb.AppendLine(" ## Command-line arguments:");
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(args);
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("```");
|
||||
sb.AppendLine(" ## Parsed command-line arguments:");
|
||||
sb.AppendLine();
|
||||
|
||||
sb.Append("Span zones across monitors: ");
|
||||
sb.AppendLine(App.Overlay.SpanZonesAcrossMonitors.ToString());
|
||||
sb.Append("Monitors count: ");
|
||||
sb.AppendLine(count.ToString());
|
||||
sb.Append("Target monitor: ");
|
||||
sb.AppendLine(targetMonitorName);
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(" # Per monitor data:");
|
||||
sb.AppendLine();
|
||||
foreach (NativeMonitorData data in monitorData)
|
||||
{
|
||||
sb.AppendLine(data.ToString());
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("```");
|
||||
sb.AppendLine(" ## Monitors discovered:");
|
||||
sb.AppendLine();
|
||||
|
||||
foreach (Monitor m in monitors)
|
||||
{
|
||||
sb.AppendLine(m.Device.ToString());
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// 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;
|
||||
|
||||
namespace FancyZonesEditor.Utils
|
||||
{
|
||||
public class MonitorChangedEventArgs : EventArgs
|
||||
{
|
||||
public int LastMonitor { get; }
|
||||
|
||||
public MonitorChangedEventArgs(int lastMonitor)
|
||||
{
|
||||
LastMonitor = lastMonitor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// 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.Windows.Input;
|
||||
|
||||
namespace FancyZonesEditor.Utils
|
||||
{
|
||||
public class RelayCommand : ICommand
|
||||
{
|
||||
private readonly Predicate<object> _canExecute;
|
||||
private readonly Action<object> _execute;
|
||||
|
||||
public RelayCommand(Action<object> execute)
|
||||
: this(execute, null)
|
||||
{
|
||||
_execute = execute;
|
||||
}
|
||||
|
||||
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
|
||||
{
|
||||
if (execute == null)
|
||||
{
|
||||
throw new ArgumentNullException("execute");
|
||||
}
|
||||
|
||||
_execute = execute;
|
||||
_canExecute = canExecute;
|
||||
}
|
||||
|
||||
public bool CanExecute(object parameter)
|
||||
{
|
||||
return _canExecute == null || _canExecute(parameter);
|
||||
}
|
||||
|
||||
public void Execute(object parameter)
|
||||
{
|
||||
_execute(parameter);
|
||||
}
|
||||
|
||||
// Ensures WPF commanding infrastructure asks all RelayCommand objects whether their
|
||||
// associated views should be enabled whenever a command is invoked
|
||||
public event EventHandler CanExecuteChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
CommandManager.RequerySuggested += value;
|
||||
CanExecuteChangedInternal += value;
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
CommandManager.RequerySuggested -= value;
|
||||
CanExecuteChangedInternal -= value;
|
||||
}
|
||||
}
|
||||
|
||||
private event EventHandler CanExecuteChangedInternal;
|
||||
|
||||
public void RaiseCanExecuteChanged()
|
||||
{
|
||||
CanExecuteChangedInternal.Invoke(this, null);
|
||||
/*CanExecuteChangedInternal.Raise(this);*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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.Windows.Input;
|
||||
|
||||
namespace FancyZonesEditor.Utils
|
||||
{
|
||||
public class RelayCommand<T> : ICommand
|
||||
{
|
||||
private readonly Predicate<T> _canExecute;
|
||||
private readonly Action<T> _execute;
|
||||
|
||||
public RelayCommand(Action<T> execute)
|
||||
: this(execute, null)
|
||||
{
|
||||
_execute = execute;
|
||||
}
|
||||
|
||||
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
|
||||
{
|
||||
if (execute == null)
|
||||
{
|
||||
throw new ArgumentNullException("execute");
|
||||
}
|
||||
|
||||
_execute = execute;
|
||||
_canExecute = canExecute;
|
||||
}
|
||||
|
||||
public bool CanExecute(object parameter)
|
||||
{
|
||||
return _canExecute == null || _canExecute((T)parameter);
|
||||
}
|
||||
|
||||
public void Execute(object parameter)
|
||||
{
|
||||
_execute((T)parameter);
|
||||
}
|
||||
|
||||
public event EventHandler CanExecuteChanged
|
||||
{
|
||||
add { CommandManager.RequerySuggested += value; }
|
||||
remove { CommandManager.RequerySuggested -= value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using FancyZonesEditor.Utils;
|
||||
|
||||
namespace FancyZonesEditor.ViewModels
|
||||
{
|
||||
public class MonitorViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private const int MaxPreviewDisplaySize = 160;
|
||||
private const int MinPreviewDisplaySize = 98;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public delegate void MonitorChangedEventHandler(MonitorChangedEventArgs args);
|
||||
|
||||
public ObservableCollection<MonitorInfoModel> MonitorInfoForViewModel { get; set; }
|
||||
|
||||
public static double DesktopPreviewMultiplier { get; private set; }
|
||||
|
||||
public Visibility DesktopsPanelVisibility
|
||||
{
|
||||
get
|
||||
{
|
||||
return App.Overlay.MultiMonitorMode ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public RelayCommand AddCommand { get; set; }
|
||||
|
||||
public RelayCommand DeleteCommand { get; set; }
|
||||
|
||||
public RelayCommand<MonitorInfoModel> SelectCommand { get; set; }
|
||||
|
||||
public MonitorViewModel()
|
||||
{
|
||||
SelectCommand = new RelayCommand<MonitorInfoModel>(SelectCommandExecute, SelectCommandCanExecute);
|
||||
|
||||
MonitorInfoForViewModel = new ObservableCollection<MonitorInfoModel>();
|
||||
double maxDimension = 0, minDimension = double.MaxValue;
|
||||
|
||||
int i = 1;
|
||||
foreach (var monitor in App.Overlay.Monitors)
|
||||
{
|
||||
Device device = monitor.Device;
|
||||
var bounds = device.ScaledBounds;
|
||||
maxDimension = System.Math.Max(System.Math.Max(maxDimension, bounds.Height), bounds.Width);
|
||||
minDimension = System.Math.Min(System.Math.Min(minDimension, bounds.Height), bounds.Width);
|
||||
|
||||
MonitorInfoForViewModel.Add(new MonitorInfoModel(i, (int)bounds.Height, (int)bounds.Width, device.Dpi, App.Overlay.CurrentDesktop == i - 1));
|
||||
i++;
|
||||
}
|
||||
|
||||
double maxMultiplier = MaxPreviewDisplaySize / maxDimension;
|
||||
double minMultiplier = MinPreviewDisplaySize / minDimension;
|
||||
DesktopPreviewMultiplier = (minMultiplier + maxMultiplier) / 2;
|
||||
}
|
||||
|
||||
private void RaisePropertyChanged(string propertyName)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
private bool SelectCommandCanExecute(MonitorInfoModel monitorInfo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SelectCommandExecute(MonitorInfoModel monitorInfo)
|
||||
{
|
||||
MonitorInfoForViewModel[App.Overlay.CurrentDesktop].Selected = false;
|
||||
MonitorInfoForViewModel[monitorInfo.Index - 1].Selected = true;
|
||||
|
||||
App.Overlay.CurrentDesktop = monitorInfo.Index - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
74
src/modules/fancyzones/editor/FancyZonesEditor/app.manifest
Normal file
74
src/modules/fancyzones/editor/FancyZonesEditor/app.manifest
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<!-- UAC Manifest Options
|
||||
If you want to change the Windows User Account Control level replace the
|
||||
requestedExecutionLevel node with one of the following.
|
||||
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||
|
||||
Specifying requestedExecutionLevel element will disable file and registry virtualization.
|
||||
Remove this element if your application requires this virtualization for backwards
|
||||
compatibility.
|
||||
-->
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
|
||||
<!-- Windows Vista -->
|
||||
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
|
||||
|
||||
<!-- Windows 7 -->
|
||||
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
|
||||
|
||||
<!-- Windows 8 -->
|
||||
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
|
||||
|
||||
<!-- Windows 8.1 -->
|
||||
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
|
||||
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
|
||||
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
|
||||
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
|
||||
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. -->
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">System</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
|
||||
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
|
||||
<!--
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
</assembly>
|
||||
Reference in New Issue
Block a user