Files
PowerToys/src/modules/fancyzones/editor/FancyZonesEditor/GridZone.xaml.cs

310 lines
9.6 KiB
C#
Raw Normal View History

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;
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
/// using splitters
/// </summary>
public partial class GridZone : UserControl
{
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register("IsSelected", typeof(bool), typeof(GridZone), new PropertyMetadata(false, OnSelectionChanged));
private static void OnSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((GridZone)d).OnSelectionChanged();
}
private void OnSelectionChanged()
{
Background = IsSelected ? Brushes.SteelBlue : Brushes.LightGray;
}
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set { SetValue(IsSelectedProperty, value); }
}
public double[] VerticalSnapPoints;
public double[] HorizontalSnapPoints;
public GridZone()
{
InitializeComponent();
OnSelectionChanged();
_splitter = new Rectangle();
_splitter.Fill = Brushes.DarkGray;
Body.Children.Add(_splitter);
((App) Application.Current).ZoneSettings.PropertyChanged += ZoneSettings_PropertyChanged;
}
private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsShiftKeyPressed")
{
_switchOrientation = ((App)Application.Current).ZoneSettings.IsShiftKeyPressed;
if (_lastPos.X != -1)
{
UpdateSplitter();
}
}
}
protected override Size ArrangeOverride(Size size)
{
_splitOrientation = (size.Width > size.Height) ? Orientation.Vertical : Orientation.Horizontal;
return base.ArrangeOverride(size);
}
private bool IsVerticalSplit
{
get
{
bool isVertical = _splitOrientation == Orientation.Vertical;
if (_switchOrientation)
{
isVertical = !isVertical;
}
return isVertical;
}
}
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;
if (pos < 0)
{
pos = 0;
}
else if (pos > (bodyWidth - thickness))
{
pos = bodyWidth - thickness;
}
Canvas.SetLeft(_splitter, pos);
Canvas.SetTop(_splitter, 0);
_splitter.MinWidth = thickness;
_splitter.MinHeight = Body.ActualHeight;
}
else
{
double bodyHeight = Body.ActualHeight;
double pos = _lastPos.Y - thickness / 2;
if (pos < 0)
{
pos = 0;
}
else if (pos > (bodyHeight - thickness))
{
pos = bodyHeight - thickness;
}
Canvas.SetLeft(_splitter, 0);
Canvas.SetTop(_splitter, pos);
_splitter.MinWidth = Body.ActualWidth;
_splitter.MinHeight = thickness;
}
}
protected override void OnMouseEnter(MouseEventArgs e)
{
Frame.Visibility = Visibility.Visible;
base.OnMouseEnter(e);
}
protected override void OnMouseLeave(MouseEventArgs e)
{
Frame.Visibility = Visibility.Collapsed;
base.OnMouseLeave(e);
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
_mouseDownPos = _lastPos;
base.OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (_inMergeDrag)
{
DoMergeDrag(e);
}
else
{
_lastPos = e.GetPosition(Body);
if (IsVerticalSplit)
{
if (VerticalSnapPoints != null)
{
int thickness = SplitterThickness;
foreach (double snapPoint in VerticalSnapPoints)
{
if (Math.Abs(_lastPos.X - snapPoint) <= (thickness * 2))
{
_lastPos.X = snapPoint;
break;
}
}
}
}
else // horizontal split
{
if (HorizontalSnapPoints != null)
{
int thickness = SplitterThickness;
foreach (double snapPoint in HorizontalSnapPoints)
{
if (Math.Abs(_lastPos.Y - snapPoint) <= (thickness * 2))
{
_lastPos.Y = snapPoint;
break;
}
}
}
}
if (_mouseDownPos.X == -1)
{
UpdateSplitter();
}
else
{
double threshold = SplitterThickness / 2;
if ((Math.Abs(_mouseDownPos.X - _lastPos.X) > threshold) || (Math.Abs(_mouseDownPos.Y - _lastPos.Y) > threshold))
{
// switch to merge (which is handled by parent GridEditor)
_inMergeDrag = true;
Mouse.Capture(this, CaptureMode.Element);
DoMergeDrag(e);
_splitter.Visibility = Visibility.Hidden;
}
}
}
base.OnMouseMove(e);
}
protected override void OnMouseUp(MouseButtonEventArgs e)
{
if (_inMergeDrag)
{
Mouse.Capture(this, CaptureMode.None);
DoMergeComplete(e);
_inMergeDrag = false;
_splitter.Visibility = Visibility.Visible;
}
else
{
int thickness = SplitterThickness;
double delta = IsVerticalSplit ? _mouseDownPos.X - _lastPos.X : _mouseDownPos.Y - _lastPos.Y;
if (Math.Abs(delta) <= thickness / 2)
{
if (IsVerticalSplit)
{
DoSplit(Orientation.Vertical, _lastPos.X - (thickness / 2));
}
else
{
DoSplit(Orientation.Horizontal, _lastPos.Y - (thickness / 2));
}
}
}
_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);
}
}
private void DoMergeComplete(MouseButtonEventArgs e)
{
if (MergeComplete != null)
{
MergeComplete(this, e);
}
}
private void DoSplit(Orientation orientation, double offset)
{
if (Split != null)
{
Split(this, new SplitEventArgs(orientation, offset));
}
}
private void FullSplit_Click(object sender, RoutedEventArgs e)
{
DoFullSplit();
}
private void DoFullSplit()
{
if (FullSplit != null)
{
FullSplit(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);
}