mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 02:36:19 +02:00
* [Dev][Build] .NET 8 Upgrade Silenced errors first fix. * [Dev][Build] .NET 8 Upgrade Silenced errors. CA1859 * [Dev][Build] .NET 8 Upgrade Silenced errors. CA1854. * [Dev][Build] .NET 8 Upgrade Silenced errors. CA1860 * [Dev][Build] .NET 8 Upgrade Silenced errors. CA1861 * [Dev][Build] .NET 8 Upgrade Silenced errors. CA1862 * [Dev][Build] .NET 8 Upgrade Silenced errors. CA1863 * [Dev][Build] .NET 8 Upgrade Silenced errors. CA1864 * [Dev][Build] .NET 8 Upgrade Silenced errors. CA1865 * [Dev][Build] .NET 8 Upgrade Silenced errors. CA2208 * [Dev][Build] .NET 8 Upgrade Silenced errors. CS9191 * [Dev][Build] .NET 8 Upgrade Silenced errors. Spell check * [Dev][Build] .NET 8 Upgrade Silenced errors. Spell check * [Dev][Build] .NET 8 Upgrade Silenced errors. - CompositeFormat variables used more than once in the same file were assigned to a single variable. - GetProcessesByName logic fix. - String comparion fix. - ArgumentOutOfRangeException message change. * [Dev][Build] .NET 8 Upgrade Silenced errors. - Null check added. - static readonly CompositeFormat added for all fields.
541 lines
20 KiB
C#
541 lines
20 KiB
C#
// 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.Globalization;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Input;
|
|
using FancyZonesEditor.Models;
|
|
|
|
namespace FancyZonesEditor
|
|
{
|
|
/// <summary>
|
|
/// Once you've "Commit"ted 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
|
|
{
|
|
private readonly int defaultMoveAmount = 10;
|
|
private readonly int smallMoveAmount = 1;
|
|
|
|
public CanvasZone()
|
|
{
|
|
InitializeComponent();
|
|
Canvas.SetZIndex(this, zIndex++);
|
|
SizeChanged += CanvasZone_SizeChanged;
|
|
}
|
|
|
|
private void CanvasZone_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
{
|
|
// using current culture as this is end user facing
|
|
WidthLabel.Text = Width.ToString(CultureInfo.CurrentCulture);
|
|
HeightLabel.Text = Height.ToString(CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
private CanvasLayoutModel model;
|
|
|
|
private int zoneIndex;
|
|
|
|
public enum ResizeMode
|
|
{
|
|
BottomEdge,
|
|
TopEdge,
|
|
BothEdges,
|
|
}
|
|
|
|
private abstract class SnappyHelperBase
|
|
{
|
|
public int ScreenW { get; private set; }
|
|
|
|
protected List<int> Snaps { get; private set; }
|
|
|
|
protected int MinValue { get; private set; }
|
|
|
|
protected int MaxValue { get; private set; }
|
|
|
|
public int Position { get; protected set; }
|
|
|
|
public ResizeMode Mode { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="SnappyHelperBase"/> class.
|
|
/// Just pass it the canvas arguments. Use mode
|
|
/// to tell it which edges of the existing masks to use when building its list
|
|
/// of snap points, and generally which edges to track. There will be two
|
|
/// SnappyHelpers, one for X-coordinates and one for
|
|
/// Y-coordinates, they work independently but share the same logic.
|
|
/// </summary>
|
|
/// <param name="zones">The list of rectangles describing all zones</param>
|
|
/// <param name="zoneIndex">The index of the zone to track</param>
|
|
/// <param name="isX"> Whether this is the X or Y SnappyHelper</param>
|
|
/// <param name="mode"> One of the three modes of operation (for example: tracking left/right/both edges)</param>
|
|
/// <param name="screenAxisOrigin"> The origin (left/top) of the screen in this (X or Y) dimension</param>
|
|
/// <param name="screenAxisSize"> The size of the screen in this (X or Y) dimension</param>
|
|
public SnappyHelperBase(IList<Int32Rect> zones, int zoneIndex, bool isX, ResizeMode mode, int screenAxisOrigin, int screenAxisSize)
|
|
{
|
|
int zonePosition = isX ? zones[zoneIndex].X : zones[zoneIndex].Y;
|
|
int zoneAxisSize = isX ? zones[zoneIndex].Width : zones[zoneIndex].Height;
|
|
int minAxisSize = isX ? MinZoneWidth : MinZoneHeight;
|
|
List<int> keyPositions = new List<int>();
|
|
for (int i = 0; i < zones.Count; ++i)
|
|
{
|
|
if (i != zoneIndex)
|
|
{
|
|
int ithZonePosition = isX ? zones[i].X : zones[i].Y;
|
|
int ithZoneAxisSize = isX ? zones[i].Width : zones[i].Height;
|
|
keyPositions.Add(ithZonePosition);
|
|
keyPositions.Add(ithZonePosition + ithZoneAxisSize);
|
|
if (mode == ResizeMode.BothEdges)
|
|
{
|
|
keyPositions.Add(ithZonePosition - zoneAxisSize);
|
|
keyPositions.Add(ithZonePosition + ithZoneAxisSize - zoneAxisSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (Rect singleMonitor in App.Overlay.WorkAreas)
|
|
{
|
|
int monitorPositionLow = (int)(isX ? singleMonitor.Left : singleMonitor.Top);
|
|
int monitorPositionHigh = (int)(isX ? singleMonitor.Right : singleMonitor.Bottom);
|
|
keyPositions.Add(monitorPositionLow - screenAxisOrigin);
|
|
keyPositions.Add(monitorPositionHigh - screenAxisOrigin);
|
|
if (mode == ResizeMode.BothEdges)
|
|
{
|
|
keyPositions.Add(monitorPositionLow - screenAxisOrigin - zoneAxisSize);
|
|
keyPositions.Add(monitorPositionHigh - screenAxisOrigin - zoneAxisSize);
|
|
}
|
|
}
|
|
|
|
// Remove duplicates and sort
|
|
keyPositions.Sort();
|
|
Snaps = new List<int>();
|
|
if (keyPositions.Count > 0)
|
|
{
|
|
Snaps.Add(keyPositions[0]);
|
|
for (int i = 1; i < keyPositions.Count; ++i)
|
|
{
|
|
if (keyPositions[i] != keyPositions[i - 1])
|
|
{
|
|
Snaps.Add(keyPositions[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case ResizeMode.BottomEdge:
|
|
// We're dragging the low edge, don't go below zero
|
|
MinValue = 0;
|
|
|
|
// It can't make the zone smaller than minAxisSize
|
|
MaxValue = zonePosition + zoneAxisSize - minAxisSize;
|
|
Position = zonePosition;
|
|
break;
|
|
case ResizeMode.TopEdge:
|
|
// We're dragging the high edge, don't make the zone smaller than minAxisSize
|
|
MinValue = zonePosition + minAxisSize;
|
|
|
|
// Don't go off the screen
|
|
MaxValue = screenAxisSize;
|
|
Position = zonePosition + zoneAxisSize;
|
|
break;
|
|
case ResizeMode.BothEdges:
|
|
// We're moving the window, don't move it below zero
|
|
MinValue = 0;
|
|
|
|
// Don't go off the screen (this time the lower edge is tracked)
|
|
MaxValue = screenAxisSize - zoneAxisSize;
|
|
Position = zonePosition;
|
|
break;
|
|
}
|
|
|
|
Mode = mode;
|
|
this.ScreenW = screenAxisSize;
|
|
}
|
|
|
|
public abstract void Move(int delta);
|
|
}
|
|
|
|
private sealed class SnappyHelperMagnetic : SnappyHelperBase
|
|
{
|
|
private List<int> magnetZoneSizes;
|
|
private int freePosition;
|
|
|
|
private int MagnetZoneMaxSize
|
|
{
|
|
get => (int)(0.08 * ScreenW);
|
|
}
|
|
|
|
public SnappyHelperMagnetic(IList<Int32Rect> zones, int zoneIndex, bool isX, ResizeMode mode, int screenAxisOrigin, int screenAxisSize)
|
|
: base(zones, zoneIndex, isX, mode, screenAxisOrigin, screenAxisSize)
|
|
{
|
|
freePosition = Position;
|
|
magnetZoneSizes = new List<int>();
|
|
for (int i = 0; i < Snaps.Count; ++i)
|
|
{
|
|
int previous = i == 0 ? 0 : Snaps[i - 1];
|
|
int next = i == Snaps.Count - 1 ? ScreenW : Snaps[i + 1];
|
|
magnetZoneSizes.Add(Math.Min(Snaps[i] - previous, Math.Min(next - Snaps[i], MagnetZoneMaxSize)) / 2);
|
|
}
|
|
}
|
|
|
|
public override void Move(int delta)
|
|
{
|
|
freePosition = Position + delta;
|
|
int snapId = -1;
|
|
for (int i = 0; i < Snaps.Count; ++i)
|
|
{
|
|
if (Math.Abs(freePosition - Snaps[i]) <= magnetZoneSizes[i])
|
|
{
|
|
snapId = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (snapId == -1)
|
|
{
|
|
Position = freePosition;
|
|
}
|
|
else
|
|
{
|
|
int deadZoneWidth = (magnetZoneSizes[snapId] + 1) / 2;
|
|
if (Math.Abs(freePosition - Snaps[snapId]) <= deadZoneWidth)
|
|
{
|
|
Position = Snaps[snapId];
|
|
}
|
|
else if (freePosition < Snaps[snapId])
|
|
{
|
|
Position = freePosition + (freePosition - (Snaps[snapId] - magnetZoneSizes[snapId]));
|
|
}
|
|
else
|
|
{
|
|
Position = freePosition - ((Snaps[snapId] + magnetZoneSizes[snapId]) - freePosition);
|
|
}
|
|
}
|
|
|
|
Position = Math.Max(Math.Min(MaxValue, Position), MinValue);
|
|
}
|
|
}
|
|
|
|
private sealed class SnappyHelperNonMagnetic : SnappyHelperBase
|
|
{
|
|
public SnappyHelperNonMagnetic(IList<Int32Rect> zones, int zoneIndex, bool isX, ResizeMode mode, int screenAxisOrigin, int screenAxisSize)
|
|
: base(zones, zoneIndex, isX, mode, screenAxisOrigin, screenAxisSize)
|
|
{
|
|
}
|
|
|
|
public override void Move(int delta)
|
|
{
|
|
var pos = Position + delta;
|
|
Position = Math.Max(Math.Min(MaxValue, pos), MinValue);
|
|
}
|
|
}
|
|
|
|
private SnappyHelperBase snappyX;
|
|
private SnappyHelperBase snappyY;
|
|
|
|
private SnappyHelperMagnetic NewMagneticSnapper(bool isX, ResizeMode mode)
|
|
{
|
|
Rect workingArea = App.Overlay.WorkArea;
|
|
int screenAxisOrigin = (int)(isX ? workingArea.Left : workingArea.Top);
|
|
int screenAxisSize = (int)(isX ? workingArea.Width : workingArea.Height);
|
|
return new SnappyHelperMagnetic(Model.Zones, ZoneIndex, isX, mode, screenAxisOrigin, screenAxisSize);
|
|
}
|
|
|
|
private SnappyHelperNonMagnetic NewNonMagneticSnapper(bool isX, ResizeMode mode)
|
|
{
|
|
Rect workingArea = App.Overlay.WorkArea;
|
|
int screenAxisOrigin = (int)(isX ? workingArea.Left : workingArea.Top);
|
|
int screenAxisSize = (int)(isX ? workingArea.Width : workingArea.Height);
|
|
return new SnappyHelperNonMagnetic(Model.Zones, ZoneIndex, isX, mode, screenAxisOrigin, screenAxisSize);
|
|
}
|
|
|
|
private void UpdateFromSnappyHelpers()
|
|
{
|
|
if (ZoneIndex >= Model.Zones.Count)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Int32Rect rect = Model.Zones[ZoneIndex];
|
|
|
|
if (snappyX != null)
|
|
{
|
|
if (snappyX.Mode == ResizeMode.BottomEdge)
|
|
{
|
|
int changeX = snappyX.Position - rect.X;
|
|
rect.X += changeX;
|
|
rect.Width -= changeX;
|
|
}
|
|
else if (snappyX.Mode == ResizeMode.TopEdge)
|
|
{
|
|
rect.Width = snappyX.Position - rect.X;
|
|
}
|
|
else
|
|
{
|
|
int changeX = snappyX.Position - rect.X;
|
|
rect.X += changeX;
|
|
}
|
|
|
|
Canvas.SetLeft(this, rect.X);
|
|
Width = rect.Width;
|
|
}
|
|
|
|
if (snappyY != null)
|
|
{
|
|
if (snappyY.Mode == ResizeMode.BottomEdge)
|
|
{
|
|
int changeY = snappyY.Position - rect.Y;
|
|
rect.Y += changeY;
|
|
rect.Height -= changeY;
|
|
}
|
|
else if (snappyY.Mode == ResizeMode.TopEdge)
|
|
{
|
|
rect.Height = snappyY.Position - rect.Y;
|
|
}
|
|
else
|
|
{
|
|
int changeY = snappyY.Position - rect.Y;
|
|
rect.Y += changeY;
|
|
}
|
|
|
|
Canvas.SetTop(this, rect.Y);
|
|
Height = rect.Height;
|
|
}
|
|
|
|
Model.Zones[ZoneIndex] = rect;
|
|
}
|
|
|
|
private static int zIndex;
|
|
private const int MinZoneWidth = 64;
|
|
private const int MinZoneHeight = 72;
|
|
|
|
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
|
|
{
|
|
Canvas.SetZIndex(this, zIndex++);
|
|
base.OnPreviewMouseDown(e);
|
|
}
|
|
|
|
private void UniversalDragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
|
|
{
|
|
if (snappyX != null)
|
|
{
|
|
snappyX.Move((int)e.HorizontalChange);
|
|
}
|
|
|
|
if (snappyY != null)
|
|
{
|
|
snappyY.Move((int)e.VerticalChange);
|
|
}
|
|
|
|
UpdateFromSnappyHelpers();
|
|
}
|
|
|
|
// Corner dragging
|
|
private void Caption_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
|
|
{
|
|
snappyX = NewMagneticSnapper(true, ResizeMode.BothEdges);
|
|
snappyY = NewMagneticSnapper(false, ResizeMode.BothEdges);
|
|
}
|
|
|
|
public CanvasLayoutModel Model { get => model; set => model = value; }
|
|
|
|
public int ZoneIndex { get => zoneIndex; set => zoneIndex = value; }
|
|
|
|
public void FocusZone()
|
|
{
|
|
Keyboard.Focus(RootBorder);
|
|
}
|
|
|
|
private void NWResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
|
|
{
|
|
snappyX = NewMagneticSnapper(true, ResizeMode.BottomEdge);
|
|
snappyY = NewMagneticSnapper(false, ResizeMode.BottomEdge);
|
|
}
|
|
|
|
private void NEResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
|
|
{
|
|
snappyX = NewMagneticSnapper(true, ResizeMode.TopEdge);
|
|
snappyY = NewMagneticSnapper(false, ResizeMode.BottomEdge);
|
|
}
|
|
|
|
private void SWResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
|
|
{
|
|
snappyX = NewMagneticSnapper(true, ResizeMode.BottomEdge);
|
|
snappyY = NewMagneticSnapper(false, ResizeMode.TopEdge);
|
|
}
|
|
|
|
private void SEResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
|
|
{
|
|
snappyX = NewMagneticSnapper(true, ResizeMode.TopEdge);
|
|
snappyY = NewMagneticSnapper(false, ResizeMode.TopEdge);
|
|
}
|
|
|
|
// Edge dragging
|
|
private void NResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
|
|
{
|
|
snappyX = null;
|
|
snappyY = NewMagneticSnapper(false, ResizeMode.BottomEdge);
|
|
}
|
|
|
|
private void SResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
|
|
{
|
|
snappyX = null;
|
|
snappyY = NewMagneticSnapper(false, ResizeMode.TopEdge);
|
|
}
|
|
|
|
private void WResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
|
|
{
|
|
snappyX = NewMagneticSnapper(true, ResizeMode.BottomEdge);
|
|
snappyY = null;
|
|
}
|
|
|
|
private void EResize_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
|
|
{
|
|
snappyX = NewMagneticSnapper(true, ResizeMode.TopEdge);
|
|
snappyY = null;
|
|
}
|
|
|
|
private void OnClose(object sender, RoutedEventArgs e)
|
|
{
|
|
RemoveZone();
|
|
}
|
|
|
|
private void RemoveZone()
|
|
{
|
|
((Panel)Parent).Children.Remove(this);
|
|
Model.RemoveZoneAt(ZoneIndex);
|
|
}
|
|
|
|
private void Border_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (e.Key == Key.Tab)
|
|
{
|
|
return;
|
|
}
|
|
|
|
e.Handled = true;
|
|
|
|
if (e.Key == Key.Delete)
|
|
{
|
|
RemoveZone();
|
|
return;
|
|
}
|
|
|
|
var moveValue = IsCtrlKeyDown() ? smallMoveAmount : defaultMoveAmount;
|
|
if (IsShiftKeyDown())
|
|
{
|
|
moveValue = Math.Max(1, moveValue / 2);
|
|
}
|
|
|
|
if (e.Key == Key.Right)
|
|
{
|
|
if (IsShiftKeyDown())
|
|
{
|
|
// Make the zone larger (width)
|
|
MoveZoneX(moveValue, ResizeMode.TopEdge, ResizeMode.BottomEdge);
|
|
MoveZoneX(-moveValue, ResizeMode.BottomEdge, ResizeMode.BottomEdge);
|
|
}
|
|
else
|
|
{
|
|
// Move zone right
|
|
MoveZoneX(moveValue, ResizeMode.BothEdges, ResizeMode.BothEdges);
|
|
}
|
|
}
|
|
else if (e.Key == Key.Left)
|
|
{
|
|
if (IsShiftKeyDown())
|
|
{
|
|
// Make the zone smaller (width)
|
|
MoveZoneX(-moveValue, ResizeMode.TopEdge, ResizeMode.BottomEdge);
|
|
MoveZoneX(moveValue, ResizeMode.BottomEdge, ResizeMode.BottomEdge);
|
|
}
|
|
else
|
|
{
|
|
// Move zone left
|
|
MoveZoneX(-moveValue, ResizeMode.BothEdges, ResizeMode.BothEdges);
|
|
}
|
|
}
|
|
else if (e.Key == Key.Up)
|
|
{
|
|
if (IsShiftKeyDown())
|
|
{
|
|
// Make the zone larger (height)
|
|
MoveZoneY(moveValue, ResizeMode.TopEdge, ResizeMode.BottomEdge);
|
|
MoveZoneY(-moveValue, ResizeMode.BottomEdge, ResizeMode.BottomEdge);
|
|
}
|
|
else
|
|
{
|
|
// Move zone up
|
|
MoveZoneY(-moveValue, ResizeMode.BothEdges, ResizeMode.BothEdges);
|
|
}
|
|
}
|
|
else if (e.Key == Key.Down)
|
|
{
|
|
if (IsShiftKeyDown())
|
|
{
|
|
// Make the zone smaller (height)
|
|
MoveZoneY(-moveValue, ResizeMode.TopEdge, ResizeMode.BottomEdge);
|
|
MoveZoneY(moveValue, ResizeMode.BottomEdge, ResizeMode.BottomEdge);
|
|
}
|
|
else
|
|
{
|
|
// Move zone down
|
|
MoveZoneY(moveValue, ResizeMode.BothEdges, ResizeMode.BothEdges);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void MoveZoneX(int value, ResizeMode top, ResizeMode bottom)
|
|
{
|
|
snappyX = NewNonMagneticSnapper(true, top);
|
|
snappyY = NewNonMagneticSnapper(false, bottom);
|
|
snappyX.Move(value);
|
|
UpdateFromSnappyHelpers();
|
|
}
|
|
|
|
private void MoveZoneY(int value, ResizeMode top, ResizeMode bottom)
|
|
{
|
|
snappyX = NewNonMagneticSnapper(true, bottom);
|
|
snappyY = NewNonMagneticSnapper(false, top);
|
|
snappyY.Move(value);
|
|
UpdateFromSnappyHelpers();
|
|
}
|
|
|
|
private bool IsShiftKeyDown()
|
|
{
|
|
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private bool IsCtrlKeyDown()
|
|
{
|
|
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private void Border_PreviewMouseDown(object sender, MouseButtonEventArgs e)
|
|
{
|
|
// Set (keyboard)focus on this zone when click
|
|
Border selectedBorder = sender as Border;
|
|
selectedBorder.Focus();
|
|
Keyboard.Focus(selectedBorder);
|
|
}
|
|
}
|
|
}
|