Merge pull request #927 from microsoft/dev/crutkas/codeAnalysis

code analysis / style cop adjustments for .NET
This commit is contained in:
Clint Rutkas 2019-12-13 14:09:19 -08:00 committed by GitHub
commit 511f71c369
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 1025 additions and 746 deletions

View file

@ -0,0 +1,47 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1009:ClosingParenthesisMustBeSpacedCorrectly", Justification = "All current violations are due to Tuple shorthand and so valid.")]
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:PrefixLocalCallsWithThis", Justification = "We follow the C# Core Coding Style which avoids using `this` unless absolutely necessary.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1200:UsingDirectivesMustBePlacedWithinNamespace", Justification = "We follow the C# Core Coding Style which puts using statements outside the namespace.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:ElementsMustAppearInTheCorrectOrder", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:ElementsMustBeOrderedByAccess", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1203:ConstantsMustAppearBeforeFields", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:StaticElementsMustAppearBeforeInstanceElements", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1309:FieldNamesMustNotBeginWithUnderscore", Justification = "We follow the C# Core Coding Style which uses underscores as prefixes rather than using `this.`.")]
[assembly: SuppressMessage("StyleCop.CSharp.SpecialRules", "SA0001:XmlCommentAnalysisDisabled", Justification = "Not enabled as we don't want or need XML documentation.")]
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1629:DocumentationTextMustEndWithAPeriod", Justification = "Not enabled as we don't want or need XML documentation.")]
[assembly: SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly", Scope = "member", Target = "Microsoft.Templates.Core.Locations.TemplatesSynchronization.#SyncStatusChanged", Justification = "Using an Action<object, SyncStatusEventArgs> does not allow the required notation")]
// Non general supressions
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "The WebBrowser is loading source code to be shown to the user. No localization required.", MessageId = "System.Windows.Controls.WebBrowser.NavigateToString(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Controls.CodeViewer.#UpdateCodeView(System.Func`2<System.String,System.String>,System.String,System.String,System.Boolean)")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "This is part of the markdown processing", MessageId = "System.Windows.Documents.Run.#ctor(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Controls.Markdown.#ImageInlineEvaluator(System.Text.RegularExpressions.Match)")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We need to have the names of these keys in lowercase to be able to compare with the keys becoming form the template json. ContainsKey does not allow StringComparer especification to IgnoreCase", Scope = "member", Target = "Microsoft.Templates.Core.ITemplateInfoExtensions.#GetQueryableProperties(Microsoft.TemplateEngine.Abstractions.ITemplateInfo)")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We need to have the names of these keys in lowercase to be able to compare with the keys becoming form the template json. ContainsKey does not allow StringComparer especification to IgnoreCase", Scope = "member", Target = "Microsoft.Templates.Core.Composition.CompositionQuery.#Match(System.Collections.Generic.IEnumerable`1<Microsoft.Templates.Core.Composition.QueryNode>,Microsoft.Templates.Core.Composition.QueryablePropertyDictionary)")]
[assembly: SuppressMessage("Usage", "VSTHRD103:Call async methods when in an async method", Justification = "Resource DictionaryWriter does not implement flush async", Scope = "member", Target = "~M:Microsoft.Templates.Core.PostActions.Catalog.Merge.MergeResourceDictionaryPostAction.ExecuteInternalAsync~System.Threading.Tasks.Task")]
// Threading supressions
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.Controls.Notification.OnClose")]
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.SavedTemplateViewModel.OnDelete")]
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.WizardNavigation.GoBack")]
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.WizardNavigation.GoForward")]
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.SavedTemplateViewModel.OnDelete(Microsoft.Templates.UI.ViewModels.Common.SavedTemplateViewModel)")]
// Localization suppressions
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#CreateJunction(System.String,System.String,System.Boolean)", Justification = "Only used for local generation")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#DeleteJunction(System.String)", Justification = "Only used for local generation")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#InternalGetTarget(Microsoft.Win32.SafeHandles.SafeFileHandle)", Justification = "Only used for local generation")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#OpenReparsePoint(System.String,Microsoft.Templates.Core.Locations.JunctionNativeMethods+EFileAccess)", Justification = "Only used for local generation")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Windows.Documents.InlineCollection.Add(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Extensions.TextBlockExtensions.#OnSequentialFlowStepChanged(System.Windows.DependencyObject,System.Windows.DependencyPropertyChangedEventArgs)", Justification = "No text here")]

View file

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="PowerToys Rules" Description="Based on Microsoft Minimum Recomended Rules and customized to include other required rules. These rules focus on the most critical problems in your code, including potential security holes, application crashes, and other important logic and design errors. It is recommended to include this rule set in any custom rule set you create for your projects." ToolsVersion="15.0">
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
<Rule Id="CA1001" Action="Warning" />
<Rule Id="CA1009" Action="Warning" />
<Rule Id="CA1016" Action="Warning" />
<Rule Id="CA1033" Action="Warning" />
<Rule Id="CA1049" Action="Warning" />
<Rule Id="CA1060" Action="Warning" />
<Rule Id="CA1061" Action="Warning" />
<Rule Id="CA1063" Action="Warning" />
<Rule Id="CA1065" Action="Warning" />
<Rule Id="CA1301" Action="Warning" />
<Rule Id="CA1302" Action="Warning" />
<Rule Id="CA1303" Action="Warning" />
<Rule Id="CA1304" Action="Warning" />
<Rule Id="CA1306" Action="Warning" />
<Rule Id="CA1307" Action="Warning" />
<Rule Id="CA1308" Action="Warning" />
<Rule Id="CA1309" Action="Warning" />
<Rule Id="CA1400" Action="Warning" />
<Rule Id="CA1401" Action="Warning" />
<Rule Id="CA1403" Action="Warning" />
<Rule Id="CA1404" Action="Warning" />
<Rule Id="CA1405" Action="Warning" />
<Rule Id="CA1410" Action="Warning" />
<Rule Id="CA1415" Action="Warning" />
<Rule Id="CA1821" Action="Warning" />
<Rule Id="CA1900" Action="Warning" />
<Rule Id="CA1901" Action="Warning" />
<Rule Id="CA2002" Action="Warning" />
<Rule Id="CA2100" Action="Warning" />
<Rule Id="CA2101" Action="Warning" />
<Rule Id="CA2108" Action="Warning" />
<Rule Id="CA2111" Action="Warning" />
<Rule Id="CA2112" Action="Warning" />
<Rule Id="CA2114" Action="Warning" />
<Rule Id="CA2116" Action="Warning" />
<Rule Id="CA2117" Action="Warning" />
<Rule Id="CA2122" Action="Warning" />
<Rule Id="CA2123" Action="Warning" />
<Rule Id="CA2124" Action="Warning" />
<Rule Id="CA2126" Action="Warning" />
<Rule Id="CA2131" Action="Warning" />
<Rule Id="CA2132" Action="Warning" />
<Rule Id="CA2133" Action="Warning" />
<Rule Id="CA2134" Action="Warning" />
<Rule Id="CA2137" Action="Warning" />
<Rule Id="CA2138" Action="Warning" />
<Rule Id="CA2140" Action="Warning" />
<Rule Id="CA2141" Action="Warning" />
<Rule Id="CA2146" Action="Warning" />
<Rule Id="CA2147" Action="Warning" />
<Rule Id="CA2149" Action="Warning" />
<Rule Id="CA2200" Action="Warning" />
<Rule Id="CA2202" Action="Warning" />
<Rule Id="CA2207" Action="Warning" />
<Rule Id="CA2212" Action="Warning" />
<Rule Id="CA2213" Action="Warning" />
<Rule Id="CA2214" Action="Warning" />
<Rule Id="CA2216" Action="Warning" />
<Rule Id="CA2220" Action="Warning" />
<Rule Id="CA2229" Action="Warning" />
<Rule Id="CA2231" Action="Warning" />
<Rule Id="CA2232" Action="Warning" />
<Rule Id="CA2235" Action="Warning" />
<Rule Id="CA2236" Action="Warning" />
<Rule Id="CA2237" Action="Warning" />
<Rule Id="CA2238" Action="Warning" />
<Rule Id="CA2240" Action="Warning" />
<Rule Id="CA2241" Action="Warning" />
<Rule Id="CA2242" Action="Warning" />
</Rules>
</RuleSet>

View file

@ -0,0 +1,21 @@
{
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"documentationRules": {
"companyName": "Microsoft Corporation",
"copyrightText": "Copyright (c) {companyName}\r\nThe {companyName} licenses this file to you under the MIT license.\r\nSee the LICENSE file in the project root for more information.",
"xmlHeader": false,
"headerDecoration": "",
"fileNamingConvention": "metadata",
"documentInterfaces": false,
"documentExposedElements": false,
"documentInternalElements": false
},
"layoutRules": {
"newlineAtEndOfFile": "require"
},
"orderingRules": {
"usingDirectivesPlacement": "outsideNamespace"
}
}
}

View file

@ -12,7 +12,9 @@ Global
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|Any CPU.ActiveCfg = Debug|x64
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|Any CPU.ActiveCfg = Release|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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -1,10 +1,8 @@
using FancyZonesEditor;
// 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.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using FancyZonesEditor.Models;
@ -15,26 +13,27 @@ namespace FancyZonesEditor
/// </summary>
public partial class App : Application
{
public Settings ZoneSettings { get { return _settings; } }
private Settings _settings;
public Settings ZoneSettings { get; }
private ushort _idInitial = 0;
public App()
{
_settings = new Settings();
ZoneSettings = new Settings();
}
private void OnStartup(object sender, StartupEventArgs e)
{
if (e.Args.Length > 1)
{
UInt16.TryParse(e.Args[1], out _idInitial);
ushort.TryParse(e.Args[1], out _idInitial);
}
LayoutModel foundModel = null;
if (_idInitial != 0)
{
foreach (LayoutModel model in _settings.DefaultModels)
foreach (LayoutModel model in ZoneSettings.DefaultModels)
{
if (model.Id == _idInitial)
{
@ -46,7 +45,7 @@ namespace FancyZonesEditor
if (foundModel == null)
{
foreach (LayoutModel model in _settings.CustomModels)
foreach (LayoutModel model in ZoneSettings.CustomModels)
{
if (model.Id == _idInitial)
{
@ -57,9 +56,10 @@ namespace FancyZonesEditor
}
}
}
if (foundModel == null)
{
foundModel = _settings.DefaultModels[0];
foundModel = ZoneSettings.DefaultModels[0];
}
foundModel.IsSelected = true;

View file

@ -3,7 +3,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FancyZonesEditor"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>

View file

@ -1,17 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 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.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
@ -21,18 +13,20 @@ namespace FancyZonesEditor
/// </summary>
public partial class CanvasEditor : UserControl
{
private CanvasLayoutModel _model;
public CanvasEditor()
{
InitializeComponent();
Loaded += CanvasEditor_Loaded;
Loaded += OnLoaded;
}
private void CanvasEditor_Loaded(object sender, RoutedEventArgs e)
private void OnLoaded(object sender, RoutedEventArgs e)
{
CanvasLayoutModel model = (CanvasLayoutModel)DataContext;
if (model != null)
{
Model = model;
_model = model;
UpdateZoneRects();
model.PropertyChanged += OnModelChanged;
@ -51,17 +45,19 @@ namespace FancyZonesEditor
{
UIElementCollection previewChildren = Preview.Children;
int previewChildrenCount = previewChildren.Count;
while (previewChildrenCount < Model.Zones.Count)
while (previewChildrenCount < _model.Zones.Count)
{
CanvasZone zone = new CanvasZone();
zone.Model = Model;
CanvasZone zone = new CanvasZone
{
Model = _model,
};
Preview.Children.Add(zone);
previewChildrenCount++;
}
for (int i = 0; i < previewChildrenCount; i++)
{
Int32Rect rect = Model.Zones[i];
Int32Rect rect = _model.Zones[i];
CanvasZone zone = previewChildren[i] as CanvasZone;
zone.ZoneIndex = i;
@ -71,7 +67,5 @@ namespace FancyZonesEditor
zone.MinWidth = rect.Width;
}
}
public CanvasLayoutModel Model;
}
}

View file

@ -1,17 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 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.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using MahApps.Metro.Controls;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
@ -24,16 +15,16 @@ namespace FancyZonesEditor
public CanvasEditorWindow()
{
InitializeComponent();
Model = EditorOverlay.Current.DataContext as CanvasLayoutModel;
_model = EditorOverlay.Current.DataContext as CanvasLayoutModel;
}
private void OnAddZone(object sender, RoutedEventArgs e)
{
Model.AddZone(new Int32Rect(_offset, _offset, (int) (Model.ReferenceWidth * 0.6), (int) (Model.ReferenceHeight * 0.6)));
_model.AddZone(new Int32Rect(_offset, _offset, (int)(_model.ReferenceWidth * 0.6), (int)(_model.ReferenceHeight * 0.6)));
_offset += 100;
}
private int _offset = 100;
private CanvasLayoutModel Model;
private CanvasLayoutModel _model;
}
}

View file

@ -1,37 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 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.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
{
/// <summary>
/// Once you've "Committ"ed the starter grid, then the Zones within the grid come to life for you to be able to further subdivide them
/// Once you've "Committ"ed the starter grid, then the Zones within the grid come to life for you to be able to further subdivide them
/// using splitters
/// </summary>
public partial class CanvasZone : UserControl
{
public CanvasLayoutModel Model { get; set; }
public int ZoneIndex { get; set; }
private readonly Settings _settings = ((App)Application.Current).ZoneSettings;
private static readonly int _minZoneWidth = 64;
private static readonly int _minZoneHeight = 72;
private static int _zIndex = 0;
public CanvasZone()
{
InitializeComponent();
Canvas.SetZIndex(this, c_zIndex++);
Panel.SetZIndex(this, _zIndex++);
}
public CanvasLayoutModel Model;
public int ZoneIndex;
private void Move(double xDelta, double yDelta)
{
Int32Rect rect = Model.Zones[ZoneIndex];
@ -53,8 +53,8 @@ namespace FancyZonesEditor
yDelta = Math.Min(yDelta, _settings.WorkArea.Height - rect.Height - rect.Y);
}
rect.X += (int) xDelta;
rect.Y += (int) yDelta;
rect.X += (int)xDelta;
rect.Y += (int)yDelta;
Canvas.SetLeft(this, rect.X);
Canvas.SetTop(this, rect.Y);
@ -73,9 +73,9 @@ namespace FancyZonesEditor
}
else if (xDelta > 0)
{
if ((rect.Width - (int)xDelta) < c_minZoneWidth)
if ((rect.Width - (int)xDelta) < _minZoneWidth)
{
xDelta = rect.Width - c_minZoneWidth;
xDelta = rect.Width - _minZoneWidth;
}
}
@ -88,9 +88,9 @@ namespace FancyZonesEditor
}
else if (yDelta > 0)
{
if ((rect.Height - (int)yDelta) < c_minZoneHeight)
if ((rect.Height - (int)yDelta) < _minZoneHeight)
{
yDelta = rect.Height - c_minZoneHeight;
yDelta = rect.Height - _minZoneHeight;
}
}
@ -112,16 +112,17 @@ namespace FancyZonesEditor
Int32Rect rect = Model.Zones[ZoneIndex];
if (xDelta != 0)
{
int newWidth = rect.Width + (int) xDelta;
int newWidth = rect.Width + (int)xDelta;
if (newWidth < c_minZoneWidth)
if (newWidth < _minZoneWidth)
{
newWidth = c_minZoneWidth;
newWidth = _minZoneWidth;
}
else if (newWidth > (_settings.WorkArea.Width - rect.X))
{
newWidth = (int) _settings.WorkArea.Width - rect.X;
newWidth = (int)_settings.WorkArea.Width - rect.X;
}
MinWidth = rect.Width = newWidth;
}
@ -129,28 +130,27 @@ namespace FancyZonesEditor
{
int newHeight = rect.Height + (int)yDelta;
if (newHeight < c_minZoneHeight)
if (newHeight < _minZoneHeight)
{
newHeight = c_minZoneHeight;
newHeight = _minZoneHeight;
}
else if (newHeight > (_settings.WorkArea.Height - rect.Y))
{
newHeight = (int)_settings.WorkArea.Height - rect.Y;
}
MinHeight = rect.Height = newHeight;
}
Model.Zones[ZoneIndex] = rect;
}
private static int c_zIndex = 0;
private static int c_minZoneWidth = 64;
private static int c_minZoneHeight = 72;
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
Canvas.SetZIndex(this, c_zIndex++);
Panel.SetZIndex(this, _zIndex++);
base.OnPreviewMouseDown(e);
}
private void NWResize_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
SizeMove(e.HorizontalChange, e.VerticalChange);
@ -203,7 +203,5 @@ namespace FancyZonesEditor
((Panel)Parent).Children.Remove(this);
Model.RemoveZoneAt(ZoneIndex);
}
private Settings _settings = ((App)Application.Current).ZoneSettings;
}
}

View file

@ -0,0 +1,26 @@
// 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.Data;
using System.Windows.Media;
namespace FancyZonesEditor.Converters
{
public class BooleanToBrushConverter : IValueConverter
{
private static readonly Brush _selectedBrush = new SolidColorBrush(Color.FromRgb(0x00, 0x78, 0xD7));
private static readonly Brush _normalBrush = new SolidColorBrush(Color.FromRgb(0xF2, 0xF2, 0xF2));
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((bool)value) ? _selectedBrush : _normalBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value == _selectedBrush;
}
}
}

View file

@ -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;
using System.Windows.Data;
namespace FancyZonesEditor.Converters
{
public class BooleanToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return (bool)value == true ? 1 : 0;
}
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is int)
{
return (int)value == 1;
}
return false;
}
}
}

View file

@ -0,0 +1,24 @@
// 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.Data;
using FancyZonesEditor.Models;
namespace FancyZonesEditor.Converters
{
public class ModelToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Settings.IsPredefinedLayout((LayoutModel)value) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
}

View file

@ -11,5 +11,4 @@
WindowStyle="None"
AllowsTransparency="True"
Background="Transparent"
Loaded="onLoad"/>
Loaded="OnLoaded"/>

View file

@ -1,19 +1,11 @@
using FancyZonesEditor.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Security.RightsManagement;
using System.Text;
using System.Threading.Tasks;
// 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.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
{
@ -22,21 +14,25 @@ namespace FancyZonesEditor
/// </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;
public Int32Rect[] GetZoneRects()
{
// 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
Panel previewPanel = null;
Panel previewPanel;
if (_editor != null)
{
GridEditor gridEditor = _editor as GridEditor;
if (gridEditor != null)
if (_editor is GridEditor gridEditor)
{
previewPanel = gridEditor.PreviewPanel;
}
else
{
//CanvasEditor
// CanvasEditor
previewPanel = ((CanvasEditor)_editor).Preview;
}
}
@ -51,7 +47,7 @@ namespace FancyZonesEditor
int i = 0;
foreach (FrameworkElement child in previewPanel.Children)
{
Point topLeft = child.TransformToAncestor(previewPanel).Transform(new Point());
Point topLeft = child.TransformToAncestor(previewPanel).Transform(default);
var right = topLeft.X + child.ActualWidth;
var bottom = topLeft.Y + child.ActualHeight;
@ -65,7 +61,6 @@ namespace FancyZonesEditor
return zones;
}
public static EditorOverlay Current;
public EditorOverlay()
{
InitializeComponent();
@ -77,7 +72,7 @@ namespace FancyZonesEditor
Height = _settings.WorkArea.Height;
}
void onLoad(object sender, RoutedEventArgs e)
private void OnLoaded(object sender, RoutedEventArgs e)
{
ShowLayoutPicker();
}
@ -87,15 +82,19 @@ namespace FancyZonesEditor
DataContext = null;
_editor = null;
_layoutPreview = new LayoutPreview();
_layoutPreview.IsActualSize = true;
_layoutPreview.Opacity = 0.5;
_layoutPreview = new LayoutPreview
{
IsActualSize = true,
Opacity = 0.5,
};
Content = _layoutPreview;
MainWindow window = new MainWindow();
window.Owner = this;
window.ShowActivated = true;
window.Topmost = true;
MainWindow window = new MainWindow
{
Owner = this,
ShowActivated = true,
Topmost = true,
};
window.Show();
// window is set to topmost to make sure it shows on top of PowerToys settings page
@ -130,11 +129,8 @@ namespace FancyZonesEditor
{
_editor = new CanvasEditor();
}
Content = _editor;
}
private Settings _settings = ((App)Application.Current).ZoneSettings;
private LayoutPreview _layoutPreview;
private UserControl _editor;
}
}

View file

@ -1,16 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 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.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using FancyZonesEditor.Models;
using MahApps.Metro.Controls;
@ -21,13 +14,13 @@ namespace FancyZonesEditor
protected void OnSaveApplyTemplate(object sender, RoutedEventArgs e)
{
EditorOverlay mainEditor = EditorOverlay.Current;
LayoutModel model = mainEditor.DataContext as LayoutModel;
if (model != null)
if (mainEditor.DataContext is LayoutModel model)
{
model.Persist(mainEditor.GetZoneRects());
}
_choosing = true;
this.Close();
Close();
EditorOverlay.Current.Close();
}
@ -42,7 +35,7 @@ namespace FancyZonesEditor
protected void OnCancel(object sender, RoutedEventArgs e)
{
_choosing = true;
this.Close();
Close();
EditorOverlay.Current.ShowLayoutPicker();
}

View file

@ -27,6 +27,8 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<CodeAnalysisRuleSet>..\..\..\..\codeAnalysis\Rules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>false</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<PlatformTarget>x64</PlatformTarget>
@ -36,6 +38,8 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<RunCodeAnalysis>false</RunCodeAnalysis>
<CodeAnalysisRuleSet>..\..\..\..\codeAnalysis\Rules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -62,10 +66,13 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Converters\BooleanToBrushConverter.xaml.cs" />
<Compile Include="Converters\BooleanToIntConverter.xaml.cs" />
<Compile Include="CanvasEditor.xaml.cs">
<DependentUpon>CanvasEditor.xaml</DependentUpon>
</Compile>
<Compile Include="EditorWindow.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="GridEditor.xaml.cs">
<DependentUpon>GridEditor.xaml</DependentUpon>
</Compile>
@ -82,10 +89,13 @@
<Compile Include="EditorOverlay.xaml.cs">
<DependentUpon>EditorOverlay.xaml</DependentUpon>
</Compile>
<Compile Include="Converters\ModelToVisibilityConverter.xaml.cs" />
<Compile Include="Native.cs" />
<Compile Include="RowColInfo.cs" />
<Compile Include="GridEditorWindow.xaml.cs">
<DependentUpon>GridEditorWindow.xaml</DependentUpon>
</Compile>
<Compile Include="SplitEventArgs.cs" />
<Compile Include="WindowLayout.xaml.cs">
<DependentUpon>WindowLayout.xaml</DependentUpon>
</Compile>
@ -175,12 +185,20 @@
</None>
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\..\..\codeAnalysis\StyleCop.json">
<Link>StyleCop.json</Link>
</AdditionalFiles>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MahApps.Metro">
<Version>2.0.0-alpha0455</Version>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers">
<Version>1.1.118</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Resource Include="images\ChromeClose.png" />

View file

@ -0,0 +1,47 @@
// 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.
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1009:ClosingParenthesisMustBeSpacedCorrectly", Justification = "All current violations are due to Tuple shorthand and so valid.")]
[assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:PrefixLocalCallsWithThis", Justification = "We follow the C# Core Coding Style which avoids using `this` unless absolutely necessary.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1200:UsingDirectivesMustBePlacedWithinNamespace", Justification = "We follow the C# Core Coding Style which puts using statements outside the namespace.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:ElementsMustAppearInTheCorrectOrder", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:ElementsMustBeOrderedByAccess", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1203:ConstantsMustAppearBeforeFields", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:StaticElementsMustAppearBeforeInstanceElements", Justification = "It is not a priority and have hight impact in code changes.")]
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1309:FieldNamesMustNotBeginWithUnderscore", Justification = "We follow the C# Core Coding Style which uses underscores as prefixes rather than using `this.`.")]
[assembly: SuppressMessage("StyleCop.CSharp.SpecialRules", "SA0001:XmlCommentAnalysisDisabled", Justification = "Not enabled as we don't want or need XML documentation.")]
[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1629:DocumentationTextMustEndWithAPeriod", Justification = "Not enabled as we don't want or need XML documentation.")]
[assembly: SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly", Scope = "member", Target = "Microsoft.Templates.Core.Locations.TemplatesSynchronization.#SyncStatusChanged", Justification = "Using an Action<object, SyncStatusEventArgs> does not allow the required notation")]
// Non general supressions
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "The WebBrowser is loading source code to be shown to the user. No localization required.", MessageId = "System.Windows.Controls.WebBrowser.NavigateToString(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Controls.CodeViewer.#UpdateCodeView(System.Func`2<System.String,System.String>,System.String,System.String,System.Boolean)")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "This is part of the markdown processing", MessageId = "System.Windows.Documents.Run.#ctor(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Controls.Markdown.#ImageInlineEvaluator(System.Text.RegularExpressions.Match)")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We need to have the names of these keys in lowercase to be able to compare with the keys becoming form the template json. ContainsKey does not allow StringComparer especification to IgnoreCase", Scope = "member", Target = "Microsoft.Templates.Core.ITemplateInfoExtensions.#GetQueryableProperties(Microsoft.TemplateEngine.Abstractions.ITemplateInfo)")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We need to have the names of these keys in lowercase to be able to compare with the keys becoming form the template json. ContainsKey does not allow StringComparer especification to IgnoreCase", Scope = "member", Target = "Microsoft.Templates.Core.Composition.CompositionQuery.#Match(System.Collections.Generic.IEnumerable`1<Microsoft.Templates.Core.Composition.QueryNode>,Microsoft.Templates.Core.Composition.QueryablePropertyDictionary)")]
[assembly: SuppressMessage("Usage", "VSTHRD103:Call async methods when in an async method", Justification = "Resource DictionaryWriter does not implement flush async", Scope = "member", Target = "~M:Microsoft.Templates.Core.PostActions.Catalog.Merge.MergeResourceDictionaryPostAction.ExecuteInternalAsync~System.Threading.Tasks.Task")]
// Threading supressions
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.Controls.Notification.OnClose")]
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.SavedTemplateViewModel.OnDelete")]
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.WizardNavigation.GoBack")]
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.WizardNavigation.GoForward")]
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.ViewModels.Common.SavedTemplateViewModel.OnDelete(Microsoft.Templates.UI.ViewModels.Common.SavedTemplateViewModel)")]
// Localization suppressions
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#CreateJunction(System.String,System.String,System.Boolean)", Justification = "Only used for local generation")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#DeleteJunction(System.String)", Justification = "Only used for local generation")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#InternalGetTarget(Microsoft.Win32.SafeHandles.SafeFileHandle)", Justification = "Only used for local generation")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.ThrowLastWin32Error(System.String)", Scope = "member", Target = "Microsoft.Templates.Core.Locations.JunctionNativeMethods.#OpenReparsePoint(System.String,Microsoft.Templates.Core.Locations.JunctionNativeMethods+EFileAccess)", Justification = "Only used for local generation")]
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Windows.Documents.InlineCollection.Add(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Extensions.TextBlockExtensions.#OnSequentialFlowStepChanged(System.Windows.DependencyObject,System.Windows.DependencyPropertyChangedEventArgs)", Justification = "No text here")]

View file

@ -1,20 +1,14 @@
using System;
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
{
/// <summary>
@ -43,6 +37,7 @@ namespace FancyZonesEditor
{
_rowInfo[row] = new RowColInfo(model.RowPercents[row]);
}
_colInfo = new RowColInfo[cols];
for (int col = 0; col < cols; col++)
{
@ -57,6 +52,7 @@ namespace FancyZonesEditor
maxIndex = Math.Max(maxIndex, model.CellChildMap[row, col]);
}
}
for (int i = 0; i <= maxIndex; i++)
{
AddZone();
@ -69,6 +65,7 @@ namespace FancyZonesEditor
Model = new GridLayoutModel();
DataContext = Model;
}
Model.PropertyChanged += OnGridDimensionsChanged;
AddDragHandles();
}
@ -88,7 +85,10 @@ namespace FancyZonesEditor
set { SetValue(ModelProperty, value); }
}
public Panel PreviewPanel { get { return Preview; } }
public Panel PreviewPanel
{
get { return Preview; }
}
private void OnFullSplit(object o, SplitEventArgs e)
{
@ -124,6 +124,7 @@ namespace FancyZonesEditor
}
}
}
OnGridDimensionsChanged();
return;
}
@ -134,7 +135,6 @@ namespace FancyZonesEditor
private void ExtendRangeToHaveEvenCellEdges()
{
// extend each edge of the [(_startCol, _startRow) - (_endCol, _endRow)] range based on merged cells until you have 4 straight edges with no "straddling cells"
GridLayoutModel model = Model;
while (_startRow > 0)
@ -149,6 +149,7 @@ namespace FancyZonesEditor
break;
}
}
if (!dirty)
{
break;
@ -167,6 +168,7 @@ namespace FancyZonesEditor
break;
}
}
if (!dirty)
{
break;
@ -185,6 +187,7 @@ namespace FancyZonesEditor
break;
}
}
if (!dirty)
{
break;
@ -203,12 +206,12 @@ namespace FancyZonesEditor
break;
}
}
if (!dirty)
{
break;
}
}
}
private void OnSplit(object o, SplitEventArgs e)
@ -242,12 +245,10 @@ namespace FancyZonesEditor
}
}
int newChildIndex = AddZone();
double offset = e.Offset;
if (e.Orientation == Orientation.Vertical)
{
if (splitee.VerticalSnapPoints != null)
@ -266,9 +267,11 @@ namespace FancyZonesEditor
model.CellChildMap[walkRow++, foundCol + i] = newChildIndex;
}
}
if (_colInfo[foundCol + i].End == offset)
{
foundExistingSplit = true;
// use existing division
}
}
@ -283,6 +286,7 @@ namespace FancyZonesEditor
{
foundCol++;
}
offset -= _colInfo[foundCol].Start;
}
@ -306,11 +310,13 @@ namespace FancyZonesEditor
newCellChildMap[row, col] = model.CellChildMap[row, sourceCol];
}
}
if (col != foundCol)
{
sourceCol++;
}
}
model.CellChildMap = newCellChildMap;
sourceCol = 0;
@ -331,14 +337,15 @@ namespace FancyZonesEditor
newColInfo[col] = _colInfo[sourceCol++];
}
}
_colInfo = newColInfo;
model.ColumnPercents = newColPercents;
model.Columns++;
}
else // Horizontal
else
{
// Horizontal
if (splitee.HorizontalSnapPoints != null)
{
offset += Canvas.GetTop(splitee);
@ -355,9 +362,11 @@ namespace FancyZonesEditor
model.CellChildMap[foundRow + i, walkCol] = newChildIndex;
}
}
if (_rowInfo[foundRow + i].End == offset)
{
foundExistingSplit = true;
// use existing division
}
}
@ -372,8 +381,8 @@ namespace FancyZonesEditor
{
foundRow++;
}
offset -= _rowInfo[foundRow].Start;
offset -= _rowInfo[foundRow].Start;
}
AddDragHandle(Orientation.Horizontal, rows - 1);
@ -396,11 +405,13 @@ namespace FancyZonesEditor
newCellChildMap[row, col] = model.CellChildMap[sourceRow, col];
}
}
if (row != foundRow)
{
sourceRow++;
}
}
model.CellChildMap = newCellChildMap;
sourceRow = 0;
@ -421,6 +432,7 @@ namespace FancyZonesEditor
newRowInfo[row] = _rowInfo[sourceRow++];
}
}
_rowInfo = newRowInfo;
model.RowPercents = newRowPercents;
@ -454,15 +466,19 @@ namespace FancyZonesEditor
private void AddDragHandle(Orientation orientation, int index)
{
GridResizer resizer = new GridResizer();
resizer.Orientation = orientation;
resizer.Index = index;
resizer.Model = Model;
GridResizer resizer = new GridResizer
{
Orientation = orientation,
Index = index,
Model = Model,
};
resizer.DragDelta += Resizer_DragDelta;
if (orientation == Orientation.Vertical)
{
index += (Model.Rows - 1);
index += Model.Rows - 1;
}
AdornerLayer.Children.Insert(index, resizer);
}
@ -476,6 +492,7 @@ namespace FancyZonesEditor
}
freeZones.Add(index);
GridZone zone = (GridZone)Preview.Children[index];
zone.Visibility = Visibility.Hidden;
zone.MinHeight = 0;
@ -516,14 +533,14 @@ namespace FancyZonesEditor
OnGridDimensionsChanged();
}
}
private static void OnGridDimensionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((GridEditor)d).OnGridDimensionsChanged();
}
private void OnGridDimensionsChanged()
{
GridLayoutModel model = Model;
Size actualSize = new Size(ActualWidth, ActualHeight);
if (actualSize.Width > 0)
{
@ -539,7 +556,7 @@ namespace FancyZonesEditor
return;
}
Settings settings = ((App)(Application.Current)).ZoneSettings;
Settings settings = ((App)Application.Current).ZoneSettings;
int spacing = settings.Spacing;
int gutter = settings.Spacing;
@ -552,19 +569,17 @@ namespace FancyZonesEditor
double top = gutter;
for (int row = 0; row < rows; row++)
{
double cellHeight = _rowInfo[row].SetExtent(top, totalHeight);
double cellHeight = _rowInfo[row].Recalculate(top, totalHeight);
top += cellHeight + spacing;
}
double left = gutter;
for (int col = 0; col < cols; col++)
{
double cellWidth = _colInfo[col].SetExtent(left, totalWidth);
double cellWidth = _colInfo[col].Recalculate(left, totalWidth);
left += cellWidth + spacing;
}
for (int row = 0; row < rows; row++)
{
for (int col = 0; col < cols; col++)
@ -585,6 +600,7 @@ namespace FancyZonesEditor
{
maxRow++;
}
zone.HorizontalSnapPoints = null;
if (maxRow > row)
{
@ -639,9 +655,11 @@ namespace FancyZonesEditor
break;
}
}
if (startCol != -1)
{
Canvas.SetTop(resizer, _rowInfo[row].End + (spacing / 2) - 24); // hard coding this as (resizer.ActualHeight / 2) will still evaluate to 0 here ... a layout hasn't yet happened
// hard coding this as (resizer.ActualHeight / 2) will still evaluate to 0 here ... a layout hasn't yet happened
Canvas.SetTop(resizer, _rowInfo[row].End + (spacing / 2) - 24);
Canvas.SetLeft(resizer, (_colInfo[endCol].End + _colInfo[startCol].Start) / 2);
}
else
@ -654,7 +672,7 @@ namespace FancyZonesEditor
{
GridResizer resizer = (GridResizer)adornerChildren[childIndex++];
int startRow = -1;
int endRow = rows - 1;;
int endRow = rows - 1;
for (int row = 0; row < rows; row++)
{
if ((startRow == -1) && (model.CellChildMap[row, col] != model.CellChildMap[row, col + 1]))
@ -667,6 +685,7 @@ namespace FancyZonesEditor
break;
}
}
if (startRow != -1)
{
Canvas.SetLeft(resizer, _colInfo[col].End + (spacing / 2) - 24); // hard coding this as (resizer.ActualWidth / 2) will still evaluate to 0 here ... a layout hasn't yet happened
@ -805,6 +824,7 @@ namespace FancyZonesEditor
break;
}
}
if ((_startRow >= 0) && (_endRow == -1))
{
_endRow = rows - 1;
@ -825,6 +845,7 @@ namespace FancyZonesEditor
break;
}
}
if ((_startCol >= 0) && (_endCol == -1))
{
_endCol = cols - 1;
@ -842,14 +863,15 @@ namespace FancyZonesEditor
e.Handled = true;
}
base.OnPreviewMouseMove(e);
OnPreviewMouseMove(e);
}
private void ClearSelection()
{
foreach (UIElement zone in Preview.Children)
{
((GridZone) zone).IsSelected = false;
((GridZone)zone).IsSelected = false;
}
}
@ -872,6 +894,7 @@ namespace FancyZonesEditor
}
}
}
OnGridDimensionsChanged();
ClearSelection();
}
@ -895,7 +918,6 @@ namespace FancyZonesEditor
return returnSize;
}
Point _mouseDownPos = new Point(-1, -1);
private RowColInfo[] _rowInfo;
private RowColInfo[] _colInfo;
@ -903,9 +925,5 @@ namespace FancyZonesEditor
private int _endRow = -1;
private int _startCol = -1;
private int _endCol = -1;
private const int c_multiplier = 10000;
}
}

View file

@ -1,18 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using FancyZonesEditor.Models;
using MahApps.Metro.Controls;
// 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
{

View file

@ -1,18 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
// 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.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
@ -22,6 +15,14 @@ namespace FancyZonesEditor
/// </summary>
public partial class GridResizer : Thumb
{
private static readonly RotateTransform _rotateTransform = new RotateTransform(90, 24, 24);
public int Index { get; set; }
public LayoutModel Model { get; set; }
private Orientation _orientation;
public GridResizer()
{
InitializeComponent();
@ -33,6 +34,7 @@ namespace FancyZonesEditor
{
return _orientation;
}
set
{
_orientation = value;
@ -45,18 +47,10 @@ namespace FancyZonesEditor
}
else
{
body.RenderTransform = c_rotateTransform;
body.RenderTransform = _rotateTransform;
body.Cursor = Cursors.SizeNS;
}
}
}
private static RotateTransform c_rotateTransform = new RotateTransform(90, 24, 24);
public int Index;
public LayoutModel Model;
private Orientation _orientation;
}
}

View file

@ -1,33 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 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.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace FancyZonesEditor
{
/// <summary>
/// Once you've "Committ"ed the starter grid, then the Zones within the grid come to life for you to be able to further subdivide them
/// Once you've "Committ"ed the starter grid, then the Zones within the grid come to life for you to be able to further subdivide them
/// using splitters
/// </summary>
public partial class GridZone : UserControl
{
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register("IsSelected", typeof(bool), typeof(GridZone), new PropertyMetadata(false, OnSelectionChanged));
public event SplitEventHandler Split;
public event SplitEventHandler FullSplit;
public event MouseEventHandler MergeDrag;
public event MouseButtonEventHandler MergeComplete;
public double[] VerticalSnapPoints { get; set; }
public double[] HorizontalSnapPoints { get; set; }
private readonly Rectangle _splitter;
private bool _switchOrientation = false;
private Point _lastPos = new Point(-1, -1);
private Point _mouseDownPos = new Point(-1, -1);
private bool _inMergeDrag = false;
private Orientation _splitOrientation;
private static void OnSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((GridZone)d).OnSelectionChanged();
}
private void OnSelectionChanged()
{
Background = IsSelected ? Brushes.SteelBlue : Brushes.LightGray;
@ -39,21 +54,17 @@ namespace FancyZonesEditor
set { SetValue(IsSelectedProperty, value); }
}
public double[] VerticalSnapPoints;
public double[] HorizontalSnapPoints;
public GridZone()
{
InitializeComponent();
OnSelectionChanged();
_splitter = new Rectangle();
_splitter.Fill = Brushes.DarkGray;
_splitter = new Rectangle
{
Fill = Brushes.DarkGray,
};
Body.Children.Add(_splitter);
((App) Application.Current).ZoneSettings.PropertyChanged += ZoneSettings_PropertyChanged;
((App)Application.Current).ZoneSettings.PropertyChanged += ZoneSettings_PropertyChanged;
}
private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
@ -67,7 +78,8 @@ namespace FancyZonesEditor
}
}
}
protected override Size ArrangeOverride(Size size)
protected override Size ArrangeOverride(Size size)
{
_splitOrientation = (size.Width > size.Height) ? Orientation.Vertical : Orientation.Horizontal;
return base.ArrangeOverride(size);
@ -82,50 +94,53 @@ namespace FancyZonesEditor
{
isVertical = !isVertical;
}
return isVertical;
}
}
private int SplitterThickness { get { return Math.Max(((App)Application.Current).ZoneSettings.Spacing, 5); } }
private int SplitterThickness
{
get { return Math.Max(((App)Application.Current).ZoneSettings.Spacing, 5); }
}
private void UpdateSplitter()
{
int thickness = SplitterThickness;
{
if (IsVerticalSplit)
{
double bodyWidth = Body.ActualWidth;
double pos = _lastPos.X - thickness/2;
double pos = _lastPos.X - (SplitterThickness / 2);
if (pos < 0)
{
pos = 0;
}
else if (pos > (bodyWidth - thickness))
else if (pos > (bodyWidth - SplitterThickness))
{
pos = bodyWidth - thickness;
pos = bodyWidth - SplitterThickness;
}
Canvas.SetLeft(_splitter, pos);
Canvas.SetTop(_splitter, 0);
_splitter.MinWidth = thickness;
_splitter.MinWidth = SplitterThickness;
_splitter.MinHeight = Body.ActualHeight;
}
else
{
double bodyHeight = Body.ActualHeight;
double pos = _lastPos.Y - thickness / 2;
double pos = _lastPos.Y - (SplitterThickness / 2);
if (pos < 0)
{
pos = 0;
}
else if (pos > (bodyHeight - thickness))
else if (pos > (bodyHeight - SplitterThickness))
{
pos = bodyHeight - thickness;
pos = bodyHeight - SplitterThickness;
}
Canvas.SetLeft(_splitter, 0);
Canvas.SetTop(_splitter, pos);
_splitter.MinWidth = Body.ActualWidth;
_splitter.MinHeight = thickness;
_splitter.MinHeight = SplitterThickness;
}
}
@ -172,8 +187,9 @@ namespace FancyZonesEditor
}
}
}
else // horizontal split
else
{
// horizontal split
if (HorizontalSnapPoints != null)
{
int thickness = SplitterThickness;
@ -205,6 +221,7 @@ namespace FancyZonesEditor
}
}
}
base.OnMouseMove(e);
}
@ -234,45 +251,24 @@ namespace FancyZonesEditor
}
}
}
_mouseDownPos = new Point(-1, -1);
base.OnMouseUp(e);
}
public event SplitEventHandler Split;
public event SplitEventHandler FullSplit;
public event MouseEventHandler MergeDrag;
public event MouseButtonEventHandler MergeComplete;
private Rectangle _splitter;
private bool _switchOrientation = false;
private Point _lastPos = new Point(-1,-1);
private Point _mouseDownPos = new Point(-1,-1);
private bool _inMergeDrag = false;
private Orientation _splitOrientation;
private void DoMergeDrag(MouseEventArgs e)
{
if (MergeDrag != null)
{
MergeDrag(this, e);
}
MergeDrag?.Invoke(this, e);
}
private void DoMergeComplete(MouseButtonEventArgs e)
{
if (MergeComplete != null)
{
MergeComplete(this, e);
}
MergeComplete?.Invoke(this, e);
}
private void DoSplit(Orientation orientation, double offset)
{
if (Split != null)
{
Split(this, new SplitEventArgs(orientation, offset));
}
Split?.Invoke(this, new SplitEventArgs(orientation, offset));
}
private void FullSplit_Click(object sender, RoutedEventArgs e)
@ -282,28 +278,7 @@ namespace FancyZonesEditor
private void DoFullSplit()
{
if (FullSplit != null)
{
FullSplit(this, new SplitEventArgs());
}
FullSplit?.Invoke(this, new SplitEventArgs());
}
}
public class SplitEventArgs : EventArgs
{
public SplitEventArgs() { }
public SplitEventArgs(Orientation orientation, double offset)
{
_orientation = orientation;
_offset = offset;
}
public Orientation Orientation { get { return _orientation; } }
public double Offset { get { return _offset; } }
private Orientation _orientation;
private double _offset;
}
public delegate void SplitEventHandler(object sender, SplitEventArgs args);
}

View file

@ -1,18 +1,13 @@
using FancyZonesEditor.Models;
using System;
// 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.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using FancyZonesEditor.Models;
namespace FancyZonesEditor
{
@ -22,6 +17,9 @@ namespace FancyZonesEditor
public partial class LayoutPreview : UserControl
{
public static readonly DependencyProperty IsActualSizeProperty = DependencyProperty.Register("IsActualSize", typeof(bool), typeof(LayoutPreview), new PropertyMetadata(false));
private LayoutModel _model;
public LayoutPreview()
{
InitializeComponent();
@ -58,6 +56,7 @@ namespace FancyZonesEditor
{
Body.Margin = new Thickness(0);
}
if (_model is GridLayoutModel)
{
RenderPreview();
@ -65,7 +64,10 @@ namespace FancyZonesEditor
}
}
public Panel PreviewPanel { get { return Body; } }
public Panel PreviewPanel
{
get { return Body; }
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
@ -75,7 +77,7 @@ namespace FancyZonesEditor
}
private void RenderPreview()
{
{
if (_model == null)
{
return;
@ -83,15 +85,13 @@ namespace FancyZonesEditor
Body.Children.Clear();
GridLayoutModel gridModel = _model as GridLayoutModel;
if (gridModel != null)
if (_model is GridLayoutModel gridModel)
{
RenderGridPreview(gridModel);
}
else
{
CanvasLayoutModel canvasModel = _model as CanvasLayoutModel;
if (canvasModel != null)
if (_model is CanvasLayoutModel canvasModel)
{
RenderCanvasPreview(canvasModel);
}
@ -103,20 +103,24 @@ namespace FancyZonesEditor
Body.RowDefinitions.Clear();
foreach (int percent in grid.RowPercents)
{
RowDefinition def = new RowDefinition();
def.Height = new GridLength(percent, GridUnitType.Star);
RowDefinition def = new RowDefinition
{
Height = new GridLength(percent, GridUnitType.Star),
};
Body.RowDefinitions.Add(def);
}
Body.ColumnDefinitions.Clear();
foreach (int percent in grid.ColumnPercents)
{
ColumnDefinition def = new ColumnDefinition();
def.Width = new GridLength(percent, GridUnitType.Star);
ColumnDefinition def = new ColumnDefinition
{
Width = new GridLength(percent, GridUnitType.Star),
};
Body.ColumnDefinitions.Add(def);
}
Settings settings = ((App) Application.Current).ZoneSettings;
Settings settings = ((App)Application.Current).ZoneSettings;
int divisor = IsActualSize ? 2 : 20;
Thickness margin = new Thickness(settings.ShowSpacing ? settings.Spacing / divisor : 0);
@ -126,7 +130,7 @@ namespace FancyZonesEditor
{
for (int col = 0; col < grid.Columns; col++)
{
int childIndex = grid.CellChildMap[row,col];
int childIndex = grid.CellChildMap[row, col];
if (!visited.Contains(childIndex))
{
visited.Add(childIndex);
@ -135,11 +139,12 @@ namespace FancyZonesEditor
Grid.SetColumn(rect, col);
int span = 1;
int walk = row + 1;
while ((walk < grid.Rows) && grid.CellChildMap[walk,col] == childIndex)
while ((walk < grid.Rows) && grid.CellChildMap[walk, col] == childIndex)
{
span++;
walk++;
}
Grid.SetRowSpan(rect, span);
span = 1;
@ -149,6 +154,7 @@ namespace FancyZonesEditor
span++;
walk++;
}
Grid.SetColumnSpan(rect, span);
rect.Margin = margin;
@ -166,8 +172,10 @@ namespace FancyZonesEditor
Body.RowDefinitions.Clear();
Body.ColumnDefinitions.Clear();
Viewbox viewbox = new Viewbox();
viewbox.Stretch = Stretch.Uniform;
Viewbox viewbox = new Viewbox
{
Stretch = Stretch.Uniform,
};
Body.Children.Add(viewbox);
Canvas frame = new Canvas();
viewbox.Child = frame;
@ -186,7 +194,5 @@ namespace FancyZonesEditor
frame.Children.Add(rect);
}
}
private LayoutModel _model;
}
}

View file

@ -6,6 +6,7 @@
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"
mc:Ignorable="d"
Title=""
Width="810"
@ -13,12 +14,12 @@
Background="White"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Initialized="InitializedEventHandler"
Closed="OnClosed">
Initialized="OnInitialized"
Closing="OnClosing">
<Window.Resources>
<local:BooleanToBrushConverter x:Key="BooleanToBrushConverter" />
<local:ModelToVisibilityConverter x:Key="ModelToVisibilityConverter" />
<local:BooleanToIntConverter x:Key="BooleanToIntConverter" />
<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" />

View file

@ -1,18 +1,12 @@
// 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.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using FancyZonesEditor.Models;
using MahApps.Metro.Controls;
@ -24,30 +18,32 @@ namespace FancyZonesEditor
public partial class MainWindow : MetroWindow
{
// TODO: share the constants b/w C# Editor and FancyZoneLib
public static int MAX_ZONES = 40;
public const int MaxZones = 40;
private readonly Settings _settings = ((App)Application.Current).ZoneSettings;
private static readonly string _defaultNamePrefix = "Custom Layout ";
private bool _editing = false;
public int WrapPanelItemSize { get; set; } = 262;
public MainWindow()
{
InitializeComponent();
DataContext = _settings;
KeyUp += MainWindow_KeyUp;
if (_settings.WorkArea.Height < 900)
{
this.SizeToContent = SizeToContent.WidthAndHeight;
this.WrapPanelItemSize = 180;
SizeToContent = SizeToContent.WidthAndHeight;
WrapPanelItemSize = 180;
}
}
private int _WrapPanelItemSize = 262;
public int WrapPanelItemSize
private void MainWindow_KeyUp(object sender, KeyEventArgs e)
{
get
if (e.Key == Key.Escape)
{
return _WrapPanelItemSize;
}
set
{
_WrapPanelItemSize = value;
OnClosing(sender, null);
}
}
@ -61,19 +57,17 @@ namespace FancyZonesEditor
private void IncrementZones_Click(object sender, RoutedEventArgs e)
{
if (_settings.ZoneCount < MAX_ZONES)
if (_settings.ZoneCount < MaxZones)
{
_settings.ZoneCount++;
}
}
private Settings _settings = ((App)Application.Current).ZoneSettings;
private void NewCustomLayoutButton_Click(object sender, RoutedEventArgs e)
{
WindowLayout window = new WindowLayout();
window.Show();
this.Close();
Close();
}
private void LayoutItem_Click(object sender, MouseButtonEventArgs e)
@ -82,33 +76,27 @@ namespace FancyZonesEditor
}
private void Select(LayoutModel newSelection)
{
LayoutModel currentSelection = EditorOverlay.Current.DataContext as LayoutModel;
if (currentSelection != null)
{
if (EditorOverlay.Current.DataContext is LayoutModel currentSelection)
{
currentSelection.IsSelected = false;
}
newSelection.IsSelected = true;
EditorOverlay.Current.DataContext = newSelection;
}
private static string c_defaultNamePrefix = "Custom Layout ";
private bool _editing = false;
private void EditLayout_Click(object sender, RoutedEventArgs e)
{
EditorOverlay mainEditor = EditorOverlay.Current;
LayoutModel model = mainEditor.DataContext as LayoutModel;
if (model == null)
if (!(mainEditor.DataContext is LayoutModel model))
{
return;
}
model.IsSelected = false;
_editing = true;
this.Close();
Close();
bool isPredefinedLayout = Settings.IsPredefinedLayout(model);
@ -125,10 +113,9 @@ namespace FancyZonesEditor
foreach (LayoutModel customModel in _settings.CustomModels)
{
string name = customModel.Name;
if (name.StartsWith(c_defaultNamePrefix))
if (name.StartsWith(_defaultNamePrefix))
{
int i;
if (Int32.TryParse(name.Substring(c_defaultNamePrefix.Length), out i))
if (int.TryParse(name.Substring(_defaultNamePrefix.Length), out int i))
{
if (maxCustomIndex < i)
{
@ -137,7 +124,8 @@ namespace FancyZonesEditor
}
}
}
model.Name = c_defaultNamePrefix + (++maxCustomIndex);
model.Name = _defaultNamePrefix + (++maxCustomIndex);
}
mainEditor.Edit();
@ -151,6 +139,7 @@ namespace FancyZonesEditor
{
window = new CanvasEditorWindow();
}
window.Owner = EditorOverlay.Current;
window.DataContext = model;
window.Show();
@ -159,8 +148,7 @@ namespace FancyZonesEditor
private void Apply_Click(object sender, RoutedEventArgs e)
{
EditorOverlay mainEditor = EditorOverlay.Current;
LayoutModel model = mainEditor.DataContext as LayoutModel;
if (model != null)
if (mainEditor.DataContext is LayoutModel model)
{
if (model is GridLayoutModel)
{
@ -170,11 +158,12 @@ namespace FancyZonesEditor
{
model.Apply((model as CanvasLayoutModel).Zones.ToArray());
}
this.Close();
Close();
}
}
private void OnClosed(object sender, EventArgs e)
private void OnClosing(object sender, EventArgs e)
{
if (!_editing)
{
@ -182,7 +171,7 @@ namespace FancyZonesEditor
}
}
private void InitializedEventHandler(object sender, EventArgs e)
private void OnInitialized(object sender, EventArgs e)
{
SetSelectedItem();
}
@ -206,56 +195,8 @@ namespace FancyZonesEditor
{
SetSelectedItem();
}
model.Delete();
}
}
public class BooleanToBrushConverter : IValueConverter
{
private static Brush c_selectedBrush = new SolidColorBrush(Color.FromRgb(0x00, 0x78, 0xD7));
private static Brush c_normalBrush = new SolidColorBrush(Color.FromRgb(0xF2, 0xF2, 0xF2));
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((bool)value) ? c_selectedBrush : c_normalBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value == c_selectedBrush;
}
}
public class ModelToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Settings.IsPredefinedLayout((LayoutModel)value) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
public class BooleanToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return (bool)value == true ? 1 : 0;
}
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is int)
{
return (int)value == 1;
}
return false;
}
}
}

View file

@ -1,42 +1,58 @@
using System;
using System.Collections;
// 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.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Converters;
using System.Windows.Documents;
namespace FancyZonesEditor.Models
{
// CanvasLayoutModel
// CanvasLayoutModel
// Free form Layout Model, which specifies independent zone rects
public class CanvasLayoutModel : LayoutModel
{
public CanvasLayoutModel(ushort version, string name, ushort id, byte[] data) : base(name, id)
private static readonly ushort _latestVersion = 0;
public CanvasLayoutModel(ushort version, string name, ushort id, byte[] data)
: base(name, id)
{
if (version == c_latestVersion)
if (version == _latestVersion)
{
Load(data);
}
}
public CanvasLayoutModel(string name, ushort id, int referenceWidth, int referenceHeight) : base(name, id)
public CanvasLayoutModel(string name, ushort id, int referenceWidth, int referenceHeight)
: base(name, id)
{
// Initialize Reference Size
_referenceWidth = referenceWidth;
_referenceHeight = referenceHeight;
}
public CanvasLayoutModel(string name, ushort id) : base(name, id) { }
public CanvasLayoutModel(string name) : base(name) { }
public CanvasLayoutModel() : base() { }
public CanvasLayoutModel(string name, ushort id)
: base(name, id)
{
}
public CanvasLayoutModel(string name)
: base(name)
{
}
public CanvasLayoutModel()
: base()
{
}
// ReferenceWidth - the reference width for the layout rect that all Zones are relative to
public int ReferenceWidth
{
get { return _referenceWidth; }
get
{
return _referenceWidth;
}
set
{
if (_referenceWidth != value)
@ -46,12 +62,17 @@ namespace FancyZonesEditor.Models
}
}
}
private int _referenceWidth;
// ReferenceHeight - the reference height for the layout rect that all Zones are relative to
public int ReferenceHeight
{
get { return _referenceHeight; }
get
{
return _referenceHeight;
}
set
{
if (_referenceHeight != value)
@ -61,11 +82,11 @@ namespace FancyZonesEditor.Models
}
}
}
private int _referenceHeight;
// Zones - the list of all zones in this layout, described as independent rectangles
public IList<Int32Rect> Zones { get { return _zones; } }
private IList<Int32Rect> _zones = new List<Int32Rect>();
public IList<Int32Rect> Zones { get; } = new List<Int32Rect>();
// RemoveZoneAt
// Removes the specified index from the Zones list, and fires a property changed notification for the Zones property
@ -88,18 +109,18 @@ namespace FancyZonesEditor.Models
// Initialize this CanvasLayoutModel based on the given persistence data
// Skip version (2 bytes), id (2 bytes), and type (1 bytes)
int i = 5;
_referenceWidth = data[i++] * 256 + data[i++];
_referenceHeight = data[i++] * 256 + data[i++];
_referenceWidth = (data[i++] * 256) + data[i++];
_referenceHeight = (data[i++] * 256) + data[i++];
int count = data[i++];
while (count-- > 0)
{
_zones.Add(new Int32Rect(
data[i++] * 256 + data[i++],
data[i++] * 256 + data[i++],
data[i++] * 256 + data[i++],
data[i++] * 256 + data[i++]));
Zones.Add(new Int32Rect(
(data[i++] * 256) + data[i++],
(data[i++] * 256) + data[i++],
(data[i++] * 256) + data[i++],
(data[i++] * 256) + data[i++]));
}
}
@ -108,11 +129,13 @@ namespace FancyZonesEditor.Models
// Clones the data from this CanvasLayoutModel to a new CanvasLayoutModel
public override LayoutModel Clone()
{
CanvasLayoutModel layout = new CanvasLayoutModel(Name);
layout.ReferenceHeight = ReferenceHeight;
layout.ReferenceWidth = ReferenceWidth;
CanvasLayoutModel layout = new CanvasLayoutModel(Name)
{
ReferenceHeight = ReferenceHeight,
ReferenceWidth = ReferenceWidth,
};
foreach(Int32Rect zone in Zones)
foreach (Int32Rect zone in Zones)
{
layout.Zones.Add(zone);
}
@ -125,24 +148,24 @@ namespace FancyZonesEditor.Models
// Returns the state of this GridLayoutModel in persisted format
protected override byte[] GetPersistData()
{
byte[] data = new byte[10 + (_zones.Count * 8)];
byte[] data = new byte[10 + (Zones.Count * 8)];
int i = 0;
// Common persisted values between all layout types
data[i++] = (byte)(c_latestVersion / 256);
data[i++] = (byte)(c_latestVersion % 256);
data[i++] = (byte)(_latestVersion / 256);
data[i++] = (byte)(_latestVersion % 256);
data[i++] = 1; // LayoutModelType: 1 == CanvasLayoutModel
data[i++] = (byte)(Id / 256);
data[i++] = (byte)(Id % 256);
// End common
// End common
data[i++] = (byte)(_referenceWidth / 256);
data[i++] = (byte)(_referenceWidth % 256);
data[i++] = (byte)(_referenceHeight / 256);
data[i++] = (byte)(_referenceHeight % 256);
data[i++] = (byte)_zones.Count;
data[i++] = (byte)Zones.Count;
foreach (Int32Rect rect in _zones)
foreach (Int32Rect rect in Zones)
{
data[i++] = (byte)(rect.X / 256);
data[i++] = (byte)(rect.X % 256);
@ -156,9 +179,8 @@ namespace FancyZonesEditor.Models
data[i++] = (byte)(rect.Height / 256);
data[i++] = (byte)(rect.Height % 256);
}
return data;
}
private static ushort c_latestVersion = 0;
}
}

View file

@ -1,77 +1,97 @@
using System;
using System.Collections;
// 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.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
namespace FancyZonesEditor.Models
{
// GridLayoutModel
// GridLayoutModel
// Grid-styled Layout Model, which specifies rows, columns, percentage sizes, and row/column spans
public class GridLayoutModel : LayoutModel
{
public GridLayoutModel() : base() { }
public GridLayoutModel(string name) : base(name) { }
public GridLayoutModel(string name, ushort id) : base(name, id) { }
public GridLayoutModel(ushort version, string name, ushort id, byte[] data) : base(name, id)
{
if (version == c_latestVersion)
{
Reload(data);
}
}
private static readonly ushort _latestVersion = 0;
// Rows - number of rows in the Grid
public int Rows
{
get { return _rows; }
set
{
get
{
return _rows;
}
set
{
if (_rows != value)
{
_rows = value;
FirePropertyChanged("Rows");
}
}
}
}
}
private int _rows = 1;
// Columns - number of columns in the Grid
public int Columns
{
get { return _cols; }
set
{
get
{
return _cols;
}
set
{
if (_cols != value)
{
_cols = value;
FirePropertyChanged("Columns");
}
}
}
}
}
private int _cols = 1;
// CellChildMap - represents which "children" belong in which grid cells;
// CellChildMap - represents which "children" belong in which grid cells;
// shows spanning children by the same index appearing in adjacent cells
// TODO: ideally no setter here - this means moving logic like "split" over to model
public int[,] CellChildMap { get { return _cellChildMap; } set { _cellChildMap = value; } }
private int[,] _cellChildMap;
// RowPercents - represents the %age height of each row in the grid
public int[] RowPercents { get { return _rowPercents; } set { _rowPercents = value; } }
private int[] _rowPercents;
// ColumnPercents - represents the %age width of each column in the grid
public int[] ColumnPercents { get { return _colPercents; } set { _colPercents = value; } }
private int[] _colPercents;
// FreeZones (not persisted) - used to keep track of child indices that are no longer in use in the CellChildMap,
// making them candidates for re-use when it's needed to add another child
// TODO: do I need FreeZones on the data model? - I think I do
public IList<int> FreeZones { get { return _freeZones; } }
private IList<int> _freeZones = new List<int>();
public int[,] CellChildMap { get; set; }
// RowPercents - represents the %age height of each row in the grid
public int[] RowPercents { get; set; }
// ColumnPercents - represents the %age width of each column in the grid
public int[] ColumnPercents { get; set; }
// FreeZones (not persisted) - used to keep track of child indices that are no longer in use in the CellChildMap,
// making them candidates for re-use when it's needed to add another child
// TODO: do I need FreeZones on the data model? - I think I do
public IList<int> FreeZones { get; } = new List<int>();
public GridLayoutModel()
: base()
{
}
public GridLayoutModel(string name)
: base(name)
{
}
public GridLayoutModel(string name, ushort id)
: base(name, id)
{
}
public GridLayoutModel(ushort version, string name, ushort id, byte[] data)
: base(name, id)
{
if (version == _latestVersion)
{
Reload(data);
}
}
public void Reload(byte[] data)
{
// Skip version (2 bytes), id (2 bytes), and type (1 bytes)
@ -80,24 +100,24 @@ namespace FancyZonesEditor.Models
Rows = data[i++];
Columns = data[i++];
_rowPercents = new int[Rows];
RowPercents = new int[Rows];
for (int row = 0; row < Rows; row++)
{
_rowPercents[row] = data[i++]*256 + data[i++];
RowPercents[row] = (data[i++] * 256) + data[i++];
}
_colPercents = new int[Columns];
ColumnPercents = new int[Columns];
for (int col = 0; col < Columns; col++)
{
_colPercents[col] = data[i++]*256 + data[i++];
ColumnPercents[col] = (data[i++] * 256) + data[i++];
}
_cellChildMap = new int[Rows, Columns];
CellChildMap = new int[Rows, Columns];
for (int row = 0; row < Rows; row++)
{
for (int col = 0; col < Columns; col++)
{
_cellChildMap[row, col] = data[i++];
CellChildMap[row, col] = data[i++];
}
}
}
@ -122,6 +142,7 @@ namespace FancyZonesEditor.Models
cellChildMap[row, col] = CellChildMap[row, col];
}
}
layout.CellChildMap = cellChildMap;
int[] rowPercents = new int[rows];
@ -129,6 +150,7 @@ namespace FancyZonesEditor.Models
{
rowPercents[row] = RowPercents[row];
}
layout.RowPercents = rowPercents;
int[] colPercents = new int[cols];
@ -136,6 +158,7 @@ namespace FancyZonesEditor.Models
{
colPercents[col] = ColumnPercents[col];
}
layout.ColumnPercents = colPercents;
return layout;
@ -151,10 +174,10 @@ namespace FancyZonesEditor.Models
int[,] cellChildMap;
if (_freeZones.Count == 0)
if (FreeZones.Count == 0)
{
// no unused indices -- so we can just use the _cellChildMap as is
cellChildMap = _cellChildMap;
cellChildMap = CellChildMap;
}
else
{
@ -167,7 +190,7 @@ namespace FancyZonesEditor.Models
{
for (int col = 0; col < cols; col++)
{
int source = _cellChildMap[row, col];
int source = CellChildMap[row, col];
int index = mapping.IndexOf(source);
if (index == -1)
@ -175,6 +198,7 @@ namespace FancyZonesEditor.Models
index = mapping.Count;
mapping.Add(source);
}
cellChildMap[row, col] = index;
}
}
@ -183,27 +207,28 @@ namespace FancyZonesEditor.Models
byte[] data = new byte[7 + (Rows * 2) + (Columns * 2) + (Rows * Columns)];
int i = 0;
// Common persisted values between all layout types
data[i++] = (byte)(c_latestVersion / 256);
data[i++] = (byte)(c_latestVersion % 256);
data[i++] = (byte)(_latestVersion / 256);
data[i++] = (byte)(_latestVersion % 256);
data[i++] = 0; // LayoutModelType: 0 == GridLayoutModel
data[i++] = (byte)(Id / 256);
data[i++] = (byte)(Id % 256);
// End common
// End common
data[i++] = (byte)Rows;
data[i++] = (byte)Columns;
for (int row = 0; row < Rows; row++)
{
int rowPercent = _rowPercents[row];
int rowPercent = RowPercents[row];
data[i++] = (byte)(rowPercent / 256);
data[i++] = (byte)(rowPercent % 256);
}
for (int col = 0; col < Columns; col++)
{
int colPercent = _colPercents[col];
int colPercent = ColumnPercents[col];
data[i++] = (byte)(colPercent / 256);
data[i++] = (byte)(colPercent % 256);
}
@ -218,7 +243,5 @@ namespace FancyZonesEditor.Models
return data;
}
private static ushort c_latestVersion = 0;
}
}

View file

@ -1,13 +1,11 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
// 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.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace FancyZonesEditor.Models
@ -16,22 +14,33 @@ namespace FancyZonesEditor.Models
// Manages common properties and base persistence
public abstract class LayoutModel : INotifyPropertyChanged
{
protected LayoutModel() { }
private static readonly string _registryPath = Settings.RegistryPath + "\\Layouts";
private static readonly string _fullRegistryPath = Settings.FullRegistryPath + "\\Layouts";
protected LayoutModel(string name) : this()
protected LayoutModel()
{
}
protected LayoutModel(string name)
: this()
{
Name = name;
}
protected LayoutModel(string name, ushort id) : this(name)
protected LayoutModel(string name, ushort id)
: this(name)
{
_id = id;
}
// Name - the display name for this layout model - is also used as the key in the registry
// Name - the display name for this layout model - is also used as the key in the registry
public string Name
{
get { return _name; }
get
{
return _name;
}
set
{
if (_name != value)
@ -41,6 +50,7 @@ namespace FancyZonesEditor.Models
}
}
}
private string _name;
// Id - the unique ID for this layout model - is used to connect fancy zones' ZonesSets with the editor's Layouts
@ -51,18 +61,24 @@ namespace FancyZonesEditor.Models
{
if (_id == 0)
{
_id = ++s_maxId;
_id = ++_maxId;
}
return _id;
}
}
private ushort _id = 0;
// 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
// TODO: once we switch to a picker per monitor, we need to move this state to the view
public bool IsSelected
{
get { return _isSelected; }
get
{
return _isSelected;
}
set
{
if (_isSelected != value)
@ -72,6 +88,7 @@ namespace FancyZonesEditor.Models
}
}
}
private bool _isSelected;
// implementation of INotifyProeprtyChanged
@ -80,42 +97,41 @@ namespace FancyZonesEditor.Models
// FirePropertyChanged -- wrapper that calls INPC.PropertyChanged
protected virtual void FirePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
// Removes this Layout from the registry and the loaded CustomModels list
public void Delete()
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(c_registryPath, true);
RegistryKey key = Registry.CurrentUser.OpenSubKey(_registryPath, true);
if (key != null)
{
key.DeleteValue(Name);
}
int i = s_customModels.IndexOf(this);
int i = _customModels.IndexOf(this);
if (i != -1)
{
s_customModels.RemoveAt(i);
_customModels.RemoveAt(i);
}
}
// Loads all the Layouts persisted under the Layouts key in the registry
public static ObservableCollection<LayoutModel> LoadCustomModels()
{
s_customModels = new ObservableCollection<LayoutModel>();
_customModels = new ObservableCollection<LayoutModel>();
RegistryKey key = Registry.CurrentUser.OpenSubKey(c_registryPath);
RegistryKey key = Registry.CurrentUser.OpenSubKey(_registryPath);
if (key != null)
{
foreach (string name in key.GetValueNames())
{
LayoutModel model = null;
byte[] data = (byte[])Registry.GetValue(c_fullRegistryPath, name, null);
byte[] data = (byte[])Registry.GetValue(_fullRegistryPath, name, null);
ushort version = (ushort) (data[0]*256 + data[1]);
ushort version = (ushort)((data[0] * 256) + data[1]);
byte type = data[2];
ushort id = (ushort) (data[3]*256 + data[4]);
ushort id = (ushort)((data[3] * 256) + data[4]);
switch (type)
{
@ -125,52 +141,37 @@ namespace FancyZonesEditor.Models
if (model != null)
{
if (s_maxId < id)
if (_maxId < id)
{
s_maxId = id;
_maxId = id;
}
s_customModels.Add(model);
_customModels.Add(model);
}
}
}
return s_customModels;
return _customModels;
}
private static ObservableCollection<LayoutModel> s_customModels = null;
private static ushort s_maxId = 0;
private static ObservableCollection<LayoutModel> _customModels = null;
private static ushort _maxId = 0;
// Callbacks that the base LayoutModel makes to derived types
protected abstract byte[] GetPersistData();
public abstract LayoutModel Clone();
// PInvokes to handshake with fancyzones backend
internal static class Native
{
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
internal delegate int PersistZoneSet(
[MarshalAs(UnmanagedType.LPWStr)] string activeKey,
[MarshalAs(UnmanagedType.LPWStr)] string resolutionKey,
uint monitor,
ushort layoutId,
int zoneCount,
[MarshalAs(UnmanagedType.LPArray)] int[] zoneArray);
}
public void Persist(System.Windows.Int32Rect[] zones)
{
// Persist the editor data
Registry.SetValue(c_fullRegistryPath, Name, GetPersistData(), Microsoft.Win32.RegistryValueKind.Binary);
Registry.SetValue(_fullRegistryPath, Name, GetPersistData(), Microsoft.Win32.RegistryValueKind.Binary);
Apply(zones);
}
public void Apply(System.Windows.Int32Rect[] zones)
{
{
// Persist the zone data back into FZ
var module = Native.LoadLibrary("fancyzones.dll");
if (module == IntPtr.Zero)
@ -196,16 +197,13 @@ namespace FancyZonesEditor.Models
var index = i * 4;
zoneArray[index] = left;
zoneArray[index+1] = top;
zoneArray[index+2] = right;
zoneArray[index+3] = bottom;
zoneArray[index + 1] = top;
zoneArray[index + 2] = right;
zoneArray[index + 3] = bottom;
}
var persistZoneSet = Marshal.GetDelegateForFunctionPointer<Native.PersistZoneSet>(pfn);
persistZoneSet(Settings.UniqueKey, Settings.WorkAreaKey, Settings.Monitor, _id, zoneCount, zoneArray);
}
private static readonly string c_registryPath = Settings.RegistryPath + "\\Layouts";
private static readonly string c_fullRegistryPath = Settings.FullRegistryPath + "\\Layouts";
}
}

View file

@ -1,27 +1,56 @@
using System;
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using FancyZonesEditor.Models;
using System.Windows.Documents;
using System.Windows;
using System.Windows.Controls;
using FancyZonesEditor.Models;
using Microsoft.Win32;
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
{
private readonly CanvasLayoutModel _blankCustomModel;
private readonly CanvasLayoutModel _focusModel;
private readonly GridLayoutModel _rowsModel;
private readonly GridLayoutModel _columnsModel;
private readonly GridLayoutModel _gridModel;
private readonly GridLayoutModel _priorityGridModel;
private static readonly ushort _focusModelId = 0xFFFF;
private static readonly ushort _rowsModelId = 0xFFFE;
private static readonly ushort _columnsModelId = 0xFFFD;
private static readonly ushort _gridModelId = 0xFFFC;
private static readonly ushort _priorityGridModelId = 0xFFFB;
private static readonly ushort _blankCustomModelId = 0xFFFA;
private static readonly ushort _lastPrefinedId = _blankCustomModelId;
// hard coded data for all the "Priority Grid" configurations that are unique to "Grid"
private static readonly byte[][] _priorityData = new byte[][]
{
new byte[] { 0, 0, 0, 0, 0, 1, 1, 39, 16, 39, 16, 0 },
new byte[] { 0, 0, 0, 0, 0, 1, 2, 39, 16, 26, 11, 13, 5, 0, 1 },
new byte[] { 0, 0, 0, 0, 0, 1, 3, 39, 16, 9, 196, 19, 136, 9, 196, 0, 1, 2 },
new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3 },
new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4 },
new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3, 4, 1, 5 },
new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4, 5, 1, 6 },
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 2, 7 },
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 7, 8 },
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 1, 8, 9 },
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 8, 9, 10 },
};
private const int _multiplier = 10000;
public bool IsCustomLayoutActive
{
get
@ -33,6 +62,7 @@ namespace FancyZonesEditor
return true;
}
}
return false;
}
}
@ -42,27 +72,31 @@ namespace FancyZonesEditor
ParseCommandLineArgs();
// Initialize the five default layout models: Focus, Columns, Rows, Grid, and PriorityGrid
_defaultModels = new List<LayoutModel>(5);
_focusModel = new CanvasLayoutModel("Focus", c_focusModelId, (int)_workArea.Width, (int)_workArea.Height);
_defaultModels.Add(_focusModel);
DefaultModels = new List<LayoutModel>(5);
_focusModel = new CanvasLayoutModel("Focus", _focusModelId, (int)_workArea.Width, (int)_workArea.Height);
DefaultModels.Add(_focusModel);
_columnsModel = new GridLayoutModel("Columns", c_columnsModelId);
_columnsModel.Rows = 1;
_columnsModel.RowPercents = new int[1] { c_multiplier };
_defaultModels.Add(_columnsModel);
_columnsModel = new GridLayoutModel("Columns", _columnsModelId)
{
Rows = 1,
RowPercents = new int[1] { _multiplier },
};
DefaultModels.Add(_columnsModel);
_rowsModel = new GridLayoutModel("Rows", c_rowsModelId);
_rowsModel.Columns = 1;
_rowsModel.ColumnPercents = new int[1] { c_multiplier };
_defaultModels.Add(_rowsModel);
_rowsModel = new GridLayoutModel("Rows", _rowsModelId)
{
Columns = 1,
ColumnPercents = new int[1] { _multiplier },
};
DefaultModels.Add(_rowsModel);
_gridModel = new GridLayoutModel("Grid", c_gridModelId);
_defaultModels.Add(_gridModel);
_gridModel = new GridLayoutModel("Grid", _gridModelId);
DefaultModels.Add(_gridModel);
_priorityGridModel = new GridLayoutModel("Priority Grid", c_priorityGridModelId);
_defaultModels.Add(_priorityGridModel);
_priorityGridModel = new GridLayoutModel("Priority Grid", _priorityGridModelId);
DefaultModels.Add(_priorityGridModel);
_blankCustomModel = new CanvasLayoutModel("Create new custom", c_blankCustomModelId, (int)_workArea.Width, (int)_workArea.Height);
_blankCustomModel = new CanvasLayoutModel("Create new custom", _blankCustomModelId, (int)_workArea.Width, (int)_workArea.Height);
_zoneCount = ReadRegistryInt("ZoneCount", 3);
_spacing = ReadRegistryInt("Spacing", 16);
@ -74,7 +108,11 @@ namespace FancyZonesEditor
// ZoneCount - number of zones selected in the picker window
public int ZoneCount
{
get { return _zoneCount; }
get
{
return _zoneCount;
}
set
{
if (_zoneCount != value)
@ -86,12 +124,17 @@ namespace FancyZonesEditor
}
}
}
private int _zoneCount;
// Spacing - how much space in between zones of the grid do you want
public int Spacing
{
get { return _spacing; }
get
{
return _spacing;
}
set
{
if (_spacing != value)
@ -102,12 +145,17 @@ namespace FancyZonesEditor
}
}
}
private int _spacing;
// ShowSpacing - is the Spacing value used or ignored?
public bool ShowSpacing
{
get { return _showSpacing; }
get
{
return _showSpacing;
}
set
{
if (_showSpacing != value)
@ -118,12 +166,17 @@ namespace FancyZonesEditor
}
}
}
private bool _showSpacing;
// IsShiftKeyPressed - is the shift key currently being held down
public bool IsShiftKeyPressed
{
get { return _isShiftKeyPressed; }
get
{
return _isShiftKeyPressed;
}
set
{
if (_isShiftKeyPressed != value)
@ -133,12 +186,17 @@ namespace FancyZonesEditor
}
}
}
private bool _isShiftKeyPressed;
// IsCtrlKeyPressed - is the ctrl key currently being held down
public bool IsCtrlKeyPressed
{
get { return _isCtrlKeyPressed; }
get
{
return _isCtrlKeyPressed;
}
set
{
if (_isCtrlKeyPressed != value)
@ -148,38 +206,25 @@ namespace FancyZonesEditor
}
}
}
private bool _isCtrlKeyPressed;
public Rect WorkArea
{
get { return _workArea; }
}
private Rect _workArea;
public static uint Monitor
{
get { return _monitor; }
}
private static uint _monitor;
public static uint Monitor { get; private set; }
public static String UniqueKey
{
get { return _uniqueKey; }
}
private static String _uniqueKey;
private String _uniqueRegistryPath;
public static string UniqueKey { get; private set; }
public static String WorkAreaKey
{
get { return _workAreaKey; }
}
private static String _workAreaKey;
private string _uniqueRegistryPath;
public static float Dpi
{
get { return _dpi; }
}
private static float _dpi;
public static string WorkAreaKey { get; private set; }
public static float Dpi { get; private set; }
private int ReadRegistryInt(string valueName, int defaultValue)
{
@ -191,8 +236,6 @@ namespace FancyZonesEditor
// Update the five default layouts based on the new ZoneCount
private void UpdateLayoutModels()
{
int previousZoneCount = _focusModel.Zones.Count;
// Update the "Focus" Default Layout
_focusModel.Zones.Clear();
@ -218,19 +261,18 @@ namespace FancyZonesEditor
{
_rowsModel.CellChildMap[i, 0] = i;
_columnsModel.CellChildMap[0, i] = i;
_rowsModel.RowPercents[i] = c_multiplier / ZoneCount; // _columnsModel is sharing the same array
_rowsModel.RowPercents[i] = _multiplier / ZoneCount; // _columnsModel is sharing the same array
}
// Update the "Grid" Default Layout
int rows = 1;
int cols = 1;
int mergeCount = 0;
while (ZoneCount / rows >= rows)
{
rows++;
}
rows--;
cols = ZoneCount / rows;
int cols = ZoneCount / rows;
if (ZoneCount % rows == 0)
{
// even grid
@ -238,8 +280,8 @@ namespace FancyZonesEditor
else
{
cols++;
mergeCount = rows - (ZoneCount % rows);
}
_gridModel.Rows = rows;
_gridModel.Columns = cols;
_gridModel.RowPercents = new int[rows];
@ -248,12 +290,12 @@ namespace FancyZonesEditor
for (int row = 0; row < rows; row++)
{
_gridModel.RowPercents[row] = c_multiplier / rows;
_gridModel.RowPercents[row] = _multiplier / rows;
}
for (int col = 0; col < cols; col++)
{
_gridModel.ColumnPercents[col] = c_multiplier / cols;
_gridModel.ColumnPercents[col] = _multiplier / cols;
}
int index = 0;
@ -266,14 +308,13 @@ namespace FancyZonesEditor
{
index--;
}
}
}
// Update the "Priority Grid" Default Layout
if (ZoneCount <= s_priorityData.Length)
if (ZoneCount <= _priorityData.Length)
{
_priorityGridModel.Reload(s_priorityData[ZoneCount - 1]);
_priorityGridModel.Reload(_priorityData[ZoneCount - 1]);
}
else
{
@ -288,11 +329,11 @@ namespace FancyZonesEditor
private void ParseCommandLineArgs()
{
_workArea = System.Windows.SystemParameters.WorkArea;
_monitor = 0;
_workArea = SystemParameters.WorkArea;
Monitor = 0;
_uniqueRegistryPath = FullRegistryPath;
_uniqueKey = "";
_dpi = 1;
UniqueKey = string.Empty;
Dpi = 1;
string[] args = Environment.GetCommandLineArgs();
if (args.Length == 7)
@ -303,9 +344,8 @@ namespace FancyZonesEditor
// 4 = X_Y_Width_Height in a dpi-scaled-but-unaware coords (where EditorOverlay shows up)
// 5 = resolution key (passed back to engine to persist data)
// 6 = monitor DPI (float)
_uniqueKey = args[1];
_uniqueRegistryPath += "\\" + _uniqueKey;
UniqueKey = args[1];
_uniqueRegistryPath += "\\" + UniqueKey;
var parsedLocation = args[4].Split('_');
var x = int.Parse(parsedLocation[0]);
@ -313,14 +353,14 @@ namespace FancyZonesEditor
var width = int.Parse(parsedLocation[2]);
var height = int.Parse(parsedLocation[3]);
_workAreaKey = args[5];
WorkAreaKey = args[5];
// Try invariant culture first, caller likely uses invariant i.e. "C" locale to construct parameters
foreach (var cultureInfo in new[] { CultureInfo.InvariantCulture, CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture })
{
try
{
_dpi = float.Parse(args[6], cultureInfo);
Dpi = float.Parse(args[6], cultureInfo);
break;
}
catch (FormatException)
@ -330,16 +370,15 @@ namespace FancyZonesEditor
_workArea = new Rect(x, y, width, height);
uint monitor = 0;
if (uint.TryParse(args[4], out monitor))
if (uint.TryParse(args[4], out uint monitor))
{
_monitor = monitor;
Monitor = monitor;
}
}
}
public IList<LayoutModel> DefaultModels { get; }
public IList<LayoutModel> DefaultModels { get { return _defaultModels; } }
public ObservableCollection<LayoutModel> CustomModels
{
get
@ -349,9 +388,11 @@ namespace FancyZonesEditor
_customModels = LayoutModel.LoadCustomModels();
_customModels.Insert(0, _blankCustomModel);
}
return _customModels;
}
}
private ObservableCollection<LayoutModel> _customModels;
public static readonly string RegistryPath = "SOFTWARE\\SuperFancyZones";
@ -359,7 +400,7 @@ namespace FancyZonesEditor
public static bool IsPredefinedLayout(LayoutModel model)
{
return (model.Id >= c_lastPrefinedId);
return model.Id >= _lastPrefinedId;
}
// implementation of INotifyProeprtyChanged
@ -368,43 +409,7 @@ namespace FancyZonesEditor
// FirePropertyChanged -- wrapper that calls INPC.PropertyChanged
protected virtual void FirePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
// storage for Default Layout Models
private IList<LayoutModel> _defaultModels;
private CanvasLayoutModel _focusModel;
private GridLayoutModel _rowsModel;
private GridLayoutModel _columnsModel;
private GridLayoutModel _gridModel;
private GridLayoutModel _priorityGridModel;
private CanvasLayoutModel _blankCustomModel;
private static readonly ushort c_focusModelId = 0xFFFF;
private static readonly ushort c_rowsModelId = 0xFFFE;
private static readonly ushort c_columnsModelId = 0xFFFD;
private static readonly ushort c_gridModelId = 0xFFFC;
private static readonly ushort c_priorityGridModelId = 0xFFFB;
private static readonly ushort c_blankCustomModelId = 0xFFFA;
private static readonly ushort c_lastPrefinedId = c_blankCustomModelId;
// hard coded data for all the "Priority Grid" configurations that are unique to "Grid"
private static byte[][] s_priorityData = new byte[][]
{
new byte[] { 0, 0, 0, 0, 0, 1, 1, 39, 16, 39, 16, 0 },
new byte[] { 0, 0, 0, 0, 0, 1, 2, 39, 16, 26, 11, 13, 5, 0, 1 },
new byte[] { 0, 0, 0, 0, 0, 1, 3, 39, 16, 9, 196, 19, 136, 9, 196, 0, 1, 2 },
new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3 },
new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4 },
new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3, 4, 1, 5 },
new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4, 5, 1, 6 },
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 2, 7 },
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 7, 8 },
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 1, 8, 9 },
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 8, 9, 10 }
};
private const int c_multiplier = 10000;
}
}

View file

@ -0,0 +1,27 @@
// 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.Runtime.InteropServices;
namespace FancyZonesEditor
{
// PInvokes to handshake with fancyzones backend
internal static class Native
{
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
internal delegate int PersistZoneSet(
[MarshalAs(UnmanagedType.LPWStr)] string activeKey,
[MarshalAs(UnmanagedType.LPWStr)] string resolutionKey,
uint monitor,
ushort layoutId,
int zoneCount,
[MarshalAs(UnmanagedType.LPArray)] int[] zoneArray);
}
}

View file

@ -1,6 +1,8 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
// 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.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
@ -21,25 +23,23 @@ using System.Windows;
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
// In order to begin building localizable applications, set
// <UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
// inside a <PropertyGroup>. For example, if you are using US english
// in your source files, set the <UICulture> to en-US. Then uncomment
// the NeutralResourceLanguage attribute below. Update the "en-US" in
// the line below to match the UICulture setting in the project file.
// [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
// ThemeInfo.None = where theme specific resource dictionaries are located
// (used if a resource is not found in the page,
// or application resource dictionaries)
// ThemeInfo.SourceAssembly = where the generic resource dictionary is located
// (used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
ResourceDictionaryLocation.None,
ResourceDictionaryLocation.SourceAssembly)]
// Version information for an assembly consists of the following four values:
//

View file

@ -1,13 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 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
{
public class RowColInfo
{
private const int _multiplier = 10000;
public double Extent { get; set; }
public double Start { get; set; }
public double End { get; set; }
public int Percent { get; set; }
public RowColInfo(int percent)
{
Percent = percent;
@ -15,15 +23,13 @@ namespace FancyZonesEditor
public RowColInfo(int index, int count)
{
Percent = (c_multiplier / count) + ((index == 0) ? (c_multiplier % count) : 0);
Percent = (_multiplier / count) + ((index == 0) ? (_multiplier % count) : 0);
}
private const int c_multiplier = 10000;
public double SetExtent(double start, double totalExtent)
public double Recalculate(double start, double totalExtent)
{
Start = start;
Extent = totalExtent * Percent / c_multiplier;
Extent = totalExtent * Percent / _multiplier;
End = Start + Extent;
return Extent;
}
@ -37,10 +43,5 @@ namespace FancyZonesEditor
info[1] = new RowColInfo(Percent - newPercent);
return info;
}
public int Percent;
public double Extent;
public double Start;
public double End;
}
}

View file

@ -0,0 +1,28 @@
// 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.Controls;
namespace FancyZonesEditor
{
public class SplitEventArgs : EventArgs
{
public SplitEventArgs()
{
}
public SplitEventArgs(Orientation orientation, double offset)
{
Orientation = orientation;
Offset = offset;
}
public Orientation Orientation { get; }
public double Offset { get; }
}
public delegate void SplitEventHandler(object sender, SplitEventArgs args);
}

View file

@ -3,7 +3,6 @@
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="Window1" Height="450" Width="800"
WindowState="Maximized"
@ -12,7 +11,7 @@
WindowStyle="None"
AllowsTransparency="True"
Background="Transparent"
Loaded="onLoad"
Loaded="OnLoaded"
>

View file

@ -1,21 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 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.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace FancyZonesEditor
{
/// <summary>
/// Interaction logic for Window1.xaml
/// Interaction logic for WindowLayout.xaml
/// </summary>
public partial class WindowLayout : Window
{
@ -23,10 +15,10 @@ namespace FancyZonesEditor
{
InitializeComponent();
}
void onLoad(object sender, RoutedEventArgs e)
{
//WindowEditor window = new WindowEditor(); window.Show();
private void OnLoaded(object sender, RoutedEventArgs e)
{
// WindowEditor window = new WindowEditor(); window.Show();
}
}
}