From ef06e796674b206bcacdd38fb70de9028cae8d0e Mon Sep 17 00:00:00 2001 From: susloparov Date: Thu, 10 Dec 2015 18:57:25 +0600 Subject: [PATCH] First grid splitter implementation --- src/Perspex.Controls/GridSplitter.cs | 130 ++++++++++++++++++++++++--- 1 file changed, 120 insertions(+), 10 deletions(-) diff --git a/src/Perspex.Controls/GridSplitter.cs b/src/Perspex.Controls/GridSplitter.cs index 9a0ef0b988..cb77cb6aad 100644 --- a/src/Perspex.Controls/GridSplitter.cs +++ b/src/Perspex.Controls/GridSplitter.cs @@ -2,42 +2,152 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using System.Collections.Generic; +using System.Linq; using Perspex.Controls.Primitives; using Perspex.Input; -using Perspex.Rendering; using Perspex.VisualTree; namespace Perspex.Controls { + /// + /// Unlike WPF GridSplitter, Perspex GridSplitter has only one Behavior. It's GridResizeBehavior.PreviousAndNext + /// public class GridSplitter : Thumb { private Grid _grid; + private DefinitionBase _prevDefinition; + + private DefinitionBase _nextDefinition; + + private bool _isResizingColumns; + + private List _definitions; + /// - /// Initializes a new instance of the class. + /// Decide depending on set size /// - public GridSplitter() + /// + private bool IsResizingColumns() + { + if (!double.IsNaN(Width)) + { + return true; + } + if (!double.IsNaN(Height)) + { + return false; + } + throw new InvalidOperationException("GridSpliter Should have width or height set. It affects whether columns or rows it resizes"); + } + + private double GetActualLength(DefinitionBase definition) { - Cursor = new Cursor(StandardCursorType.SizeWestEast); + var columnDefinition = definition as ColumnDefinition; + return columnDefinition?.ActualWidth ?? ((RowDefinition)definition).ActualHeight; } + private double GetMinLength(DefinitionBase definition) + { + var columnDefinition = definition as ColumnDefinition; + return columnDefinition?.MinWidth ?? ((RowDefinition)definition).MinHeight; + } + + private double GetMaxLength(DefinitionBase definition) + { + var columnDefinition = definition as ColumnDefinition; + return columnDefinition?.MaxWidth ?? ((RowDefinition)definition).MaxHeight; + } + + private bool IsStar(DefinitionBase definition) + { + var columnDefinition = definition as ColumnDefinition; + return columnDefinition?.Width.IsStar ?? ((RowDefinition)definition).Height.IsStar; + } + + private void SetLengthInStars(DefinitionBase definition, double value) + { + var columnDefinition = definition as ColumnDefinition; + if (columnDefinition != null) + { + columnDefinition.Width = new GridLength(value, GridUnitType.Star); + } + else + { + ((RowDefinition)definition).Height = new GridLength(value, GridUnitType.Star); + } + } + + + + + private void GetDeltaConstraints(out double min, out double max) + { + double prevDefinitionLen = GetActualLength(_prevDefinition); + double prevDefinitionMin = GetMinLength(_prevDefinition); + double prevDefinitionMax = GetMaxLength(_prevDefinition); + + double nextDefinitionLen = GetActualLength(_nextDefinition); + double nextDefinitionMin = GetMinLength(_nextDefinition); + double nextDefinitionMax = GetMaxLength(_nextDefinition); + + + // Determine the minimum and maximum the columns can be resized + min = -Math.Min(prevDefinitionLen - prevDefinitionMin, nextDefinitionMax - nextDefinitionLen); + max = Math.Min(prevDefinitionMax - prevDefinitionLen, nextDefinitionLen - nextDefinitionMin); + } + + protected override void OnDragDelta(VectorEventArgs e) { - int col = GetValue(Grid.ColumnProperty); + var delta = _isResizingColumns ? e.Vector.X : e.Vector.Y; + + double max; + double min; + GetDeltaConstraints(out min, out max); + delta = Math.Min(Math.Max(delta, min), max); - if (_grid != null && col > 0) + + foreach (var definition in _definitions) { - var size = _grid.ColumnDefinitions[col - 1].ActualWidth + e.Vector.X; - _grid.ColumnDefinitions[col - 1].Width = new GridLength( - Math.Max(0, size), - GridUnitType.Pixel); + if (definition == _prevDefinition) + { + SetLengthInStars(_prevDefinition, GetActualLength(_prevDefinition) + delta); + } + else if (definition == _nextDefinition) + { + SetLengthInStars(_nextDefinition, GetActualLength(_nextDefinition) - delta); + } + else if(IsStar(definition)) + { + SetLengthInStars(definition, GetActualLength(definition)); // same size but in stars + } } } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { + //new Range base.OnAttachedToVisualTree(e); _grid = this.GetVisualParent(); + _isResizingColumns = IsResizingColumns(); + if (_isResizingColumns) + { + Cursor = new Cursor(StandardCursorType.SizeWestEast); + var col = GetValue(Grid.ColumnProperty); + _definitions = _grid.ColumnDefinitions.Cast().ToList(); + _prevDefinition = _definitions[col - 1]; + _nextDefinition = _definitions[col + 1]; + } + else + { + Cursor = new Cursor(StandardCursorType.SizeNorthSouth); + var row = GetValue(Grid.RowProperty); + _definitions = _grid.RowDefinitions.Cast().ToList(); + _prevDefinition = _definitions[row - 1]; + _nextDefinition = _definitions[row + 1]; + } } } }