2020-04-20 11:54:25 +03:00
|
|
|
// Copyright (c) Microsoft Corporation
|
2019-12-12 12:13:31 -08:00
|
|
|
// 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;
|
2019-09-04 18:26:26 +02:00
|
|
|
using System.Windows;
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
using System.Windows.Input;
|
|
|
|
|
using System.Windows.Media;
|
|
|
|
|
using System.Windows.Shapes;
|
|
|
|
|
|
|
|
|
|
namespace FancyZonesEditor
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
2020-05-26 10:56:25 -04:00
|
|
|
/// 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
|
2019-09-04 18:26:26 +02:00
|
|
|
/// using splitters
|
|
|
|
|
/// </summary>
|
|
|
|
|
public partial class GridZone : UserControl
|
|
|
|
|
{
|
2020-08-11 13:51:06 +02:00
|
|
|
// Non-localizable strings
|
|
|
|
|
private const string ObjectDependencyID = "IsSelected";
|
|
|
|
|
private const string GridZoneBackgroundBrushID = "GridZoneBackgroundBrush";
|
|
|
|
|
private const string PropertyIsShiftKeyPressedID = "IsShiftKeyPressed";
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(ObjectDependencyID, typeof(bool), typeof(GridZone), new PropertyMetadata(false, OnSelectionChanged));
|
2019-09-04 18:26:26 +02:00
|
|
|
|
2019-12-12 14:34:25 -08:00
|
|
|
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; }
|
|
|
|
|
|
2019-12-12 15:00:24 -08:00
|
|
|
private readonly Rectangle _splitter;
|
2020-11-18 11:40:59 -08:00
|
|
|
private bool _switchOrientation;
|
2019-12-12 14:34:25 -08:00
|
|
|
private Point _lastPos = new Point(-1, -1);
|
|
|
|
|
private Point _mouseDownPos = new Point(-1, -1);
|
2020-11-18 11:40:59 -08:00
|
|
|
private bool _inMergeDrag;
|
2019-12-12 14:34:25 -08:00
|
|
|
private Orientation _splitOrientation;
|
|
|
|
|
|
2019-09-04 18:26:26 +02:00
|
|
|
private static void OnSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
((GridZone)d).OnSelectionChanged();
|
|
|
|
|
}
|
2019-12-12 12:13:31 -08:00
|
|
|
|
2019-09-04 18:26:26 +02:00
|
|
|
private void OnSelectionChanged()
|
|
|
|
|
{
|
2020-08-11 13:51:06 +02:00
|
|
|
Background = IsSelected ? SystemParameters.WindowGlassBrush : App.Current.Resources[GridZoneBackgroundBrushID] as SolidColorBrush;
|
2019-09-04 18:26:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsSelected
|
|
|
|
|
{
|
|
|
|
|
get { return (bool)GetValue(IsSelectedProperty); }
|
|
|
|
|
set { SetValue(IsSelectedProperty, value); }
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-27 21:33:52 +03:00
|
|
|
public GridZone(int spacing)
|
2019-09-04 18:26:26 +02:00
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
OnSelectionChanged();
|
2019-12-12 14:34:25 -08:00
|
|
|
_splitter = new Rectangle
|
|
|
|
|
{
|
2020-04-08 14:46:05 +02:00
|
|
|
Fill = SystemParameters.WindowGlassBrush,
|
2019-12-12 14:34:25 -08:00
|
|
|
};
|
2019-09-04 18:26:26 +02:00
|
|
|
Body.Children.Add(_splitter);
|
|
|
|
|
|
2021-01-27 21:33:52 +03:00
|
|
|
Spacing = spacing;
|
|
|
|
|
SplitterThickness = Math.Max(spacing, 1);
|
|
|
|
|
|
2020-11-17 11:38:19 +03:00
|
|
|
((App)Application.Current).MainWindowSettings.PropertyChanged += ZoneSettings_PropertyChanged;
|
2019-09-04 18:26:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
|
|
|
|
{
|
2020-08-11 13:51:06 +02:00
|
|
|
if (e.PropertyName == PropertyIsShiftKeyPressedID)
|
2019-09-04 18:26:26 +02:00
|
|
|
{
|
2020-11-17 11:38:19 +03:00
|
|
|
_switchOrientation = ((App)Application.Current).MainWindowSettings.IsShiftKeyPressed;
|
2019-09-04 18:26:26 +02:00
|
|
|
if (_lastPos.X != -1)
|
|
|
|
|
{
|
|
|
|
|
UpdateSplitter();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-12 12:13:31 -08:00
|
|
|
|
|
|
|
|
protected override Size ArrangeOverride(Size size)
|
2019-09-04 18:26:26 +02:00
|
|
|
{
|
|
|
|
|
_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;
|
|
|
|
|
}
|
2019-12-12 13:26:02 -08:00
|
|
|
|
2019-09-04 18:26:26 +02:00
|
|
|
return isVertical;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-27 21:33:52 +03:00
|
|
|
private int Spacing { get; set; }
|
2020-08-17 10:00:56 -07:00
|
|
|
|
2021-01-27 21:33:52 +03:00
|
|
|
private int SplitterThickness { get; set; }
|
2019-09-04 18:26:26 +02:00
|
|
|
|
|
|
|
|
private void UpdateSplitter()
|
2019-12-12 12:13:31 -08:00
|
|
|
{
|
2019-09-04 18:26:26 +02:00
|
|
|
if (IsVerticalSplit)
|
|
|
|
|
{
|
|
|
|
|
double bodyWidth = Body.ActualWidth;
|
2019-12-12 12:13:31 -08:00
|
|
|
double pos = _lastPos.X - (SplitterThickness / 2);
|
2019-09-04 18:26:26 +02:00
|
|
|
if (pos < 0)
|
|
|
|
|
{
|
|
|
|
|
pos = 0;
|
|
|
|
|
}
|
2019-12-12 12:13:31 -08:00
|
|
|
else if (pos > (bodyWidth - SplitterThickness))
|
2019-09-04 18:26:26 +02:00
|
|
|
{
|
2019-12-12 12:13:31 -08:00
|
|
|
pos = bodyWidth - SplitterThickness;
|
2019-09-04 18:26:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Canvas.SetLeft(_splitter, pos);
|
|
|
|
|
Canvas.SetTop(_splitter, 0);
|
2019-12-12 12:13:31 -08:00
|
|
|
_splitter.MinWidth = SplitterThickness;
|
2019-09-04 18:26:26 +02:00
|
|
|
_splitter.MinHeight = Body.ActualHeight;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
double bodyHeight = Body.ActualHeight;
|
2019-12-12 12:13:31 -08:00
|
|
|
double pos = _lastPos.Y - (SplitterThickness / 2);
|
2019-09-04 18:26:26 +02:00
|
|
|
if (pos < 0)
|
|
|
|
|
{
|
|
|
|
|
pos = 0;
|
|
|
|
|
}
|
2019-12-12 12:13:31 -08:00
|
|
|
else if (pos > (bodyHeight - SplitterThickness))
|
2019-09-04 18:26:26 +02:00
|
|
|
{
|
2019-12-12 12:13:31 -08:00
|
|
|
pos = bodyHeight - SplitterThickness;
|
2019-09-04 18:26:26 +02:00
|
|
|
}
|
2019-12-12 13:26:02 -08:00
|
|
|
|
2019-09-04 18:26:26 +02:00
|
|
|
Canvas.SetLeft(_splitter, 0);
|
|
|
|
|
Canvas.SetTop(_splitter, pos);
|
|
|
|
|
_splitter.MinWidth = Body.ActualWidth;
|
2019-12-12 12:13:31 -08:00
|
|
|
_splitter.MinHeight = SplitterThickness;
|
2019-09-04 18:26:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnMouseEnter(MouseEventArgs e)
|
|
|
|
|
{
|
2020-04-08 14:46:05 +02:00
|
|
|
_splitter.Fill = SystemParameters.WindowGlassBrush; // Active Accent color
|
2019-09-04 18:26:26 +02:00
|
|
|
base.OnMouseEnter(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnMouseLeave(MouseEventArgs e)
|
|
|
|
|
{
|
2020-03-27 16:01:24 +01:00
|
|
|
_splitter.Fill = Brushes.Transparent;
|
2019-09-04 18:26:26 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-12 14:34:25 -08:00
|
|
|
else
|
2019-09-04 18:26:26 +02:00
|
|
|
{
|
2019-12-12 14:34:25 -08:00
|
|
|
// horizontal split
|
2019-09-04 18:26:26 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-12 13:26:02 -08:00
|
|
|
|
2019-09-04 18:26:26 +02:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-12 13:26:02 -08:00
|
|
|
|
2019-09-04 18:26:26 +02:00
|
|
|
_mouseDownPos = new Point(-1, -1);
|
|
|
|
|
base.OnMouseUp(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DoMergeDrag(MouseEventArgs e)
|
|
|
|
|
{
|
2019-12-12 14:50:25 -08:00
|
|
|
MergeDrag?.Invoke(this, e);
|
2019-09-04 18:26:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DoMergeComplete(MouseButtonEventArgs e)
|
|
|
|
|
{
|
2019-12-12 14:50:25 -08:00
|
|
|
MergeComplete?.Invoke(this, e);
|
2019-09-04 18:26:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DoSplit(Orientation orientation, double offset)
|
2020-08-17 10:00:56 -07:00
|
|
|
{
|
2021-01-27 21:33:52 +03:00
|
|
|
Split?.Invoke(this, new SplitEventArgs(orientation, offset, Spacing));
|
2019-09-04 18:26:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void FullSplit_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
DoFullSplit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DoFullSplit()
|
|
|
|
|
{
|
2019-12-12 14:50:25 -08:00
|
|
|
FullSplit?.Invoke(this, new SplitEventArgs());
|
2019-09-04 18:26:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|