Skip to content

Commit

Permalink
[FancyZones] Rework grid editor (#10116)
Browse files Browse the repository at this point in the history
* Started rewriting

* Making progress

* Fix resizers not moving around

* Implemented splitting, fixed some bugs

* Removed more code, renamed methods

* Merging zones works

* Fix Shift key behavior

* Added spacing (has bugs)

* Implement minimum size restriction

* Match preview and editor visuals

* Snapping works

* Show when splitting is not possible

* Fix spell checker complaining

* Tweak FZ Lib function computing grid zones

* Fix potential crash when loading old zone layouts

* Fix dead objects talking

* Fix splitters being shown when they shouldn't be

* Fix index numbering

* Fix small glitch with the shift key

* Do not snap to borders outside the zone
  • Loading branch information
ivan100sic committed Mar 10, 2021
1 parent 9a2c195 commit e586a7a
Show file tree
Hide file tree
Showing 12 changed files with 759 additions and 2,141 deletions.
1,179 changes: 342 additions & 837 deletions src/modules/fancyzones/editor/FancyZonesEditor/GridData.cs

Large diffs are not rendered by default.

604 changes: 0 additions & 604 deletions src/modules/fancyzones/editor/FancyZonesEditor/GridDragHandles.cs

This file was deleted.

680 changes: 251 additions & 429 deletions src/modules/fancyzones/editor/FancyZonesEditor/GridEditor.xaml.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ public partial class GridResizer : Thumb
{
private static readonly RotateTransform _rotateTransform = new RotateTransform(90, 24, 24);

public int StartRow { get; set; }
public int LeftReferenceZone { get; set; }

public int EndRow { get; set; }
public int RightReferenceZone { get; set; }

public int StartCol { get; set; }
public int TopReferenceZone { get; set; }

public int EndCol { get; set; }
public int BottomReferenceZone { get; set; }

public LayoutModel Model { get; set; }

Expand Down
156 changes: 52 additions & 104 deletions src/modules/fancyzones/editor/FancyZonesEditor/GridZone.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,28 @@ public partial class GridZone : UserControl
// Non-localizable strings
private const string ObjectDependencyID = "IsSelected";
private const string GridZoneBackgroundBrushID = "GridZoneBackgroundBrush";
private const string PropertyIsShiftKeyPressedID = "IsShiftKeyPressed";
private const string SecondaryForegroundBrushID = "SecondaryForegroundBrush";

public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(ObjectDependencyID, 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;
private bool _switchOrientation = false;
private Point _lastPos = new Point(-1, -1);
private int _snappedPositionX;
private int _snappedPositionY;
private Point _mouseDownPos = new Point(-1, -1);
private bool _inMergeDrag;
private Orientation _splitOrientation;
private MagneticSnap _snapX;
private MagneticSnap _snapY;
private Func<Orientation, int, bool> _canSplit;
private bool _hovering;
private GridData.Zone _zone;

private static void OnSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Expand All @@ -59,7 +59,7 @@ public bool IsSelected
set { SetValue(IsSelectedProperty, value); }
}

public GridZone(int spacing)
public GridZone(int spacing, MagneticSnap snapX, MagneticSnap snapY, Func<Orientation, int, bool> canSplit, GridData.Zone zone)
{
InitializeComponent();
OnSelectionChanged();
Expand All @@ -69,11 +69,14 @@ public GridZone(int spacing)
};
Body.Children.Add(_splitter);

Spacing = spacing;
SplitterThickness = Math.Max(spacing, 1);

((App)Application.Current).MainWindowSettings.PropertyChanged += ZoneSettings_PropertyChanged;
SizeChanged += GridZone_SizeChanged;

_snapX = snapX;
_snapY = snapY;
_canSplit = canSplit;
_zone = zone;
}

private void GridZone_SizeChanged(object sender, SizeChangedEventArgs e)
Expand All @@ -82,91 +85,76 @@ private void GridZone_SizeChanged(object sender, SizeChangedEventArgs e)
HeightLabel.Text = Math.Round(ActualHeight).ToString();
}

private void ZoneSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
public void UpdateShiftState(bool shiftState)
{
if (e.PropertyName == PropertyIsShiftKeyPressedID)
_switchOrientation = shiftState;

if (_lastPos.X != -1)
{
_switchOrientation = ((App)Application.Current).MainWindowSettings.IsShiftKeyPressed;
if (_lastPos.X != -1)
{
UpdateSplitter();
}
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;
}
get => (ActualWidth > ActualHeight) ^ _switchOrientation;
}

private int Spacing { get; set; }

private int SplitterThickness { get; set; }

private void UpdateSplitter()
{
if (!_hovering)
{
_splitter.Fill = Brushes.Transparent;
return;
}

bool enabled;

if (IsVerticalSplit)
{
double bodyWidth = Body.ActualWidth;
double pos = _lastPos.X - (SplitterThickness / 2);
if (pos < 0)
{
pos = 0;
}
else if (pos > (bodyWidth - SplitterThickness))
{
pos = bodyWidth - SplitterThickness;
}
double pos = _snapX.DataToPixelWithoutSnapping(_snappedPositionX) - Canvas.GetLeft(this) - (SplitterThickness / 2);
pos = Math.Clamp(pos, 0, bodyWidth - SplitterThickness);

Canvas.SetLeft(_splitter, pos);
Canvas.SetTop(_splitter, 0);
_splitter.MinWidth = SplitterThickness;
_splitter.MinHeight = Body.ActualHeight;

enabled = _canSplit(Orientation.Vertical, _snappedPositionX);
}
else
{
double bodyHeight = Body.ActualHeight;
double pos = _lastPos.Y - (SplitterThickness / 2);
if (pos < 0)
{
pos = 0;
}
else if (pos > (bodyHeight - SplitterThickness))
{
pos = bodyHeight - SplitterThickness;
}
double pos = _snapY.DataToPixelWithoutSnapping(_snappedPositionY) - Canvas.GetTop(this) - (SplitterThickness / 2);
pos = Math.Clamp(pos, 0, bodyHeight - SplitterThickness);

Canvas.SetLeft(_splitter, 0);
Canvas.SetTop(_splitter, pos);
_splitter.MinWidth = Body.ActualWidth;
_splitter.MinHeight = SplitterThickness;

enabled = _canSplit(Orientation.Horizontal, _snappedPositionY);
}

Brush disabledBrush = App.Current.Resources[SecondaryForegroundBrushID] as SolidColorBrush;
Brush enabledBrush = SystemParameters.WindowGlassBrush; // Active Accent color
_splitter.Fill = enabled ? enabledBrush : disabledBrush;
}

protected override void OnMouseEnter(MouseEventArgs e)
{
_splitter.Fill = SystemParameters.WindowGlassBrush; // Active Accent color
base.OnMouseEnter(e);
_hovering = true;
UpdateSplitter();
_splitter.Fill = SystemParameters.WindowGlassBrush;
}

protected override void OnMouseLeave(MouseEventArgs e)
{
_splitter.Fill = Brushes.Transparent;
_hovering = false;
UpdateSplitter();
base.OnMouseLeave(e);
}

Expand All @@ -185,38 +173,8 @@ protected override void OnMouseMove(MouseEventArgs 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;
}
}
}
}
_snappedPositionX = _snapX.PixelToDataWithSnapping(e.GetPosition(Parent as GridEditor).X, _zone.Left, _zone.Right);
_snappedPositionY = _snapY.PixelToDataWithSnapping(e.GetPosition(Parent as GridEditor).Y, _zone.Top, _zone.Bottom);

if (_mouseDownPos.X == -1)
{
Expand Down Expand Up @@ -257,11 +215,11 @@ protected override void OnMouseUp(MouseButtonEventArgs e)
{
if (IsVerticalSplit)
{
DoSplit(Orientation.Vertical, _lastPos.X - (thickness / 2));
DoSplit(Orientation.Vertical, _snappedPositionX);
}
else
{
DoSplit(Orientation.Horizontal, _lastPos.Y - (thickness / 2));
DoSplit(Orientation.Horizontal, _snappedPositionY);
}
}
}
Expand All @@ -280,19 +238,9 @@ private void DoMergeComplete(MouseButtonEventArgs e)
MergeComplete?.Invoke(this, e);
}

private void DoSplit(Orientation orientation, double offset)
{
Split?.Invoke(this, new SplitEventArgs(orientation, offset, Spacing));
}

private void FullSplit_Click(object sender, RoutedEventArgs e)
{
DoFullSplit();
}

private void DoFullSplit()
private void DoSplit(Orientation orientation, int offset)
{
FullSplit?.Invoke(this, new SplitEventArgs());
Split?.Invoke(this, new SplitEventArgs(orientation, offset));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
Expand All @@ -27,7 +26,6 @@ public partial class LayoutPreview : UserControl

public static readonly DependencyProperty IsActualSizeProperty = DependencyProperty.Register(ObjectDependencyID, typeof(bool), typeof(LayoutPreview), new PropertyMetadata(false));
private LayoutModel _model;
private List<Int32Rect> _zones = new List<Int32Rect>();

public bool IsActualSize
{
Expand Down Expand Up @@ -82,11 +80,6 @@ private void LayoutModel_PropertyChanged(object sender, System.ComponentModel.Pr
RenderPreview();
}

public Int32Rect[] GetZoneRects()
{
return _zones.ToArray();
}

private void OnLoaded(object sender, RoutedEventArgs e)
{
_model = (LayoutModel)DataContext;
Expand All @@ -105,8 +98,6 @@ private void RenderPreview()
Body.RowDefinitions.Clear();
Body.ColumnDefinitions.Clear();

_zones.Clear();

if (_model is GridLayoutModel gridModel)
{
RenderGridPreview(gridModel);
Expand All @@ -121,32 +112,12 @@ private void RenderActualScalePreview(GridLayoutModel grid)
{
int rows = grid.Rows;
int cols = grid.Columns;
double spacing = grid.ShowSpacing ? grid.Spacing : 0;

RowColInfo[] rowInfo = (from percent in grid.RowPercents
select new RowColInfo(percent)).ToArray();

RowColInfo[] colInfo = (from percent in grid.ColumnPercents
select new RowColInfo(percent)).ToArray();

int spacing = grid.ShowSpacing ? grid.Spacing : 0;
var rowData = GridData.PrefixSum(grid.RowPercents);
var columnData = GridData.PrefixSum(grid.ColumnPercents);

var workArea = App.Overlay.WorkArea;
double width = workArea.Width - (spacing * (cols + 1));
double height = workArea.Height - (spacing * (rows + 1));

double top = spacing;
for (int row = 0; row < rows; row++)
{
double cellHeight = rowInfo[row].Recalculate(top, height);
top += cellHeight + spacing;
}

double left = spacing;
for (int col = 0; col < cols; col++)
{
double cellWidth = colInfo[col].Recalculate(left, width);
left += cellWidth + spacing;
}

Viewbox viewbox = new Viewbox
{
Expand All @@ -170,10 +141,8 @@ private void RenderActualScalePreview(GridLayoutModel grid)
{
// this is not a continuation of a span
Border rect = new Border();
left = colInfo[col].Start;
top = rowInfo[row].Start;
Canvas.SetTop(rect, top);
Canvas.SetLeft(rect, left);
double left = columnData[col] * workArea.Width / GridData.Multiplier;
double top = rowData[row] * workArea.Height / GridData.Multiplier;

int maxRow = row;
while (((maxRow + 1) < rows) && (grid.CellChildMap[maxRow + 1, col] == childIndex))
Expand All @@ -187,12 +156,21 @@ private void RenderActualScalePreview(GridLayoutModel grid)
maxCol++;
}

rect.Width = Math.Max(0, colInfo[maxCol].End - left);
rect.Height = Math.Max(0, rowInfo[maxRow].End - top);
double right = columnData[maxCol + 1] * workArea.Width / GridData.Multiplier;
double bottom = rowData[maxRow + 1] * workArea.Height / GridData.Multiplier;

left += col == 0 ? spacing : spacing / 2;
right -= maxCol == cols - 1 ? spacing : spacing / 2;
top += row == 0 ? spacing : spacing / 2;
bottom -= maxRow == rows - 1 ? spacing : spacing / 2;

Canvas.SetTop(rect, top);
Canvas.SetLeft(rect, left);
rect.Width = Math.Max(1, right - left);
rect.Height = Math.Max(1, bottom - top);

rect.Style = (Style)FindResource("GridLayoutActualScalePreviewStyle");
frame.Children.Add(rect);
_zones.Add(new Int32Rect(
(int)left, (int)top, (int)rect.Width, (int)rect.Height));
}
}
}
Expand Down

0 comments on commit e586a7a

Please sign in to comment.