|
|
|
@ -2,6 +2,8 @@ |
|
|
|
// 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.Collections; |
|
|
|
using Perspex.Controls.Primitives; |
|
|
|
@ -11,8 +13,11 @@ using Perspex.VisualTree; |
|
|
|
namespace Perspex.Controls |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Unlike WPF GridSplitter, Perspex GridSplitter has only one Behavior, GridResizeBehavior.PreviousAndNext
|
|
|
|
/// Represents the control that redistributes space between columns or rows of a Grid control.
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>
|
|
|
|
/// Unlike WPF GridSplitter, Perspex GridSplitter has only one Behavior, GridResizeBehavior.PreviousAndNext.
|
|
|
|
/// </remarks>
|
|
|
|
public class GridSplitter : Thumb |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
@ -23,93 +28,58 @@ namespace Perspex.Controls |
|
|
|
|
|
|
|
protected Grid _grid; |
|
|
|
|
|
|
|
private IGridColumnsResizer _resizer; |
|
|
|
private DefinitionBase _prevDefinition; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the orientation of the GridsSlitter, if null, it's inferred from column/row defenition(should be auto).
|
|
|
|
/// </summary>
|
|
|
|
public Orientation? Orientation { get { return GetValue(OrientationProperty); } set { SetValue(OrientationProperty, value); } } |
|
|
|
private DefinitionBase _nextDefinition; |
|
|
|
|
|
|
|
private bool _isResizingColumns; |
|
|
|
|
|
|
|
static GridSplitter() |
|
|
|
{ |
|
|
|
PseudoClass(OrientationProperty, o => o == Perspex.Controls.Orientation.Vertical, ":vertical"); |
|
|
|
PseudoClass(OrientationProperty, o => o == Perspex.Controls.Orientation.Horizontal, ":horizontal"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected override void OnDragDelta(VectorEventArgs e) |
|
|
|
{ |
|
|
|
_resizer.DragDelta(e); |
|
|
|
} |
|
|
|
private List<DefinitionBase> _definitions; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// If orientation is not set, method automatically calculates orientation based column/row auto size
|
|
|
|
/// Gets or sets the orientation of the GridsSlitter.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns></returns>
|
|
|
|
private void AutoSetOrientation() |
|
|
|
{ |
|
|
|
if (Orientation.HasValue) |
|
|
|
/// <remarks>
|
|
|
|
/// if null, it's inferred from column/row definition (should be auto).
|
|
|
|
/// </remarks>
|
|
|
|
public Orientation? Orientation { |
|
|
|
get |
|
|
|
{ |
|
|
|
return; |
|
|
|
return GetValue(OrientationProperty); |
|
|
|
} |
|
|
|
if (_grid.ColumnDefinitions[GetValue(Grid.ColumnProperty)].Width.IsAuto) |
|
|
|
{ |
|
|
|
Orientation = Perspex.Controls.Orientation.Vertical; |
|
|
|
return; |
|
|
|
} |
|
|
|
if (_grid.RowDefinitions[GetValue(Grid.RowProperty)].Height.IsAuto) |
|
|
|
set |
|
|
|
{ |
|
|
|
Orientation = Perspex.Controls.Orientation.Horizontal; |
|
|
|
return; |
|
|
|
SetValue(OrientationProperty, value); |
|
|
|
} |
|
|
|
throw new InvalidOperationException("GridSpliter Should have Orientation, width or height set."); |
|
|
|
} |
|
|
|
|
|
|
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) |
|
|
|
|
|
|
|
static GridSplitter() |
|
|
|
{ |
|
|
|
_grid = this.GetVisualParent<Grid>(); |
|
|
|
AutoSetOrientation(); |
|
|
|
switch (Orientation) |
|
|
|
{ |
|
|
|
case Perspex.Controls.Orientation.Vertical: |
|
|
|
_resizer = new VerticalColumnsResizer(_grid, GetValue(Grid.ColumnProperty)); |
|
|
|
break; |
|
|
|
case Perspex.Controls.Orientation.Horizontal: |
|
|
|
_resizer = new HorizontalGridColumnsResizer(_grid, GetValue(Grid.RowProperty)); |
|
|
|
break; |
|
|
|
default: |
|
|
|
throw new ArgumentOutOfRangeException(); |
|
|
|
} |
|
|
|
base.OnAttachedToVisualTree(e); |
|
|
|
PseudoClass(OrientationProperty, o => o == Perspex.Controls.Orientation.Vertical, ":vertical"); |
|
|
|
PseudoClass(OrientationProperty, o => o == Perspex.Controls.Orientation.Horizontal, ":horizontal"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
internal interface IGridColumnsResizer |
|
|
|
{ |
|
|
|
void DragDelta(VectorEventArgs e); |
|
|
|
} |
|
|
|
|
|
|
|
internal abstract class GridColumnsResizer<T> : IGridColumnsResizer |
|
|
|
where T : DefinitionBase |
|
|
|
{ |
|
|
|
protected PerspexList<T> _definitions; |
|
|
|
|
|
|
|
protected T _nextDefinition; |
|
|
|
|
|
|
|
protected T _prevDefinition; |
|
|
|
private void GetDeltaConstraints(out double min, out double max) |
|
|
|
{ |
|
|
|
double prevDefinitionLen = GetActualLength(_prevDefinition); |
|
|
|
double prevDefinitionMin = GetMinLength(_prevDefinition); |
|
|
|
double prevDefinitionMax = GetMaxLength(_prevDefinition); |
|
|
|
|
|
|
|
public abstract Cursor Cursor { get; } |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
public void DragDelta(VectorEventArgs e) |
|
|
|
protected override void OnDragDelta(VectorEventArgs e) |
|
|
|
{ |
|
|
|
var delta = GetDelta(e); |
|
|
|
|
|
|
|
var delta = Orientation.Value == Perspex.Controls.Orientation.Vertical ? e.Vector.X : e.Vector.Y; |
|
|
|
double max; |
|
|
|
double min; |
|
|
|
GetDeltaConstraints(out min, out max); |
|
|
|
delta = Math.Min(Math.Max(delta, min), max); |
|
|
|
|
|
|
|
foreach (var definition in _definitions) |
|
|
|
{ |
|
|
|
if (definition == _prevDefinition) |
|
|
|
@ -122,120 +92,92 @@ namespace Perspex.Controls |
|
|
|
} |
|
|
|
else if (IsStar(definition)) |
|
|
|
{ |
|
|
|
SetLengthInStars(definition, GetActualLength(definition)); // same size but in stars
|
|
|
|
SetLengthInStars(definition, GetActualLength(definition)); // same size but in stars.
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
protected abstract double GetActualLength(T definition); |
|
|
|
|
|
|
|
protected abstract double GetMinLength(T definition); |
|
|
|
|
|
|
|
protected abstract double GetMaxLength(T definition); |
|
|
|
|
|
|
|
protected abstract bool IsStar(T definition); |
|
|
|
|
|
|
|
protected abstract void SetLengthInStars(T definition, double value); |
|
|
|
|
|
|
|
protected abstract double GetDelta(VectorEventArgs vectorEventArgs); |
|
|
|
|
|
|
|
protected void GetDeltaConstraints(out double min, out double max) |
|
|
|
{ |
|
|
|
var _prevDefinitionLen = GetActualLength(_prevDefinition); |
|
|
|
var _prevDefinitionMin = GetMinLength(_prevDefinition); |
|
|
|
var _prevDefinitionMax = GetMaxLength(_prevDefinition); |
|
|
|
|
|
|
|
var _nextDefinitionLen = GetActualLength(_nextDefinition); |
|
|
|
var _nextDefinitionMin = GetMinLength(_nextDefinition); |
|
|
|
var _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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
internal class HorizontalGridColumnsResizer : GridColumnsResizer<RowDefinition> |
|
|
|
{ |
|
|
|
public HorizontalGridColumnsResizer(Grid _grid, int splitterRow) |
|
|
|
/// <summary>
|
|
|
|
/// If orientation is not set, method automatically calculates orientation based column/row auto size.
|
|
|
|
/// </summary>
|
|
|
|
private void AutoSetOrientation() |
|
|
|
{ |
|
|
|
_definitions = _grid.RowDefinitions; |
|
|
|
_nextDefinition = _definitions[splitterRow + 1]; |
|
|
|
_prevDefinition = _definitions[splitterRow - 1]; |
|
|
|
if (Orientation.HasValue) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
if (_grid.ColumnDefinitions[GetValue(Grid.ColumnProperty)].Width.IsAuto) |
|
|
|
{ |
|
|
|
Orientation = Perspex.Controls.Orientation.Vertical; |
|
|
|
return; |
|
|
|
} |
|
|
|
if (_grid.RowDefinitions[GetValue(Grid.RowProperty)].Height.IsAuto) |
|
|
|
{ |
|
|
|
Orientation = Perspex.Controls.Orientation.Horizontal; |
|
|
|
return; |
|
|
|
} |
|
|
|
throw new InvalidOperationException("GridSpliter Should have Orientation, width or height set."); |
|
|
|
} |
|
|
|
|
|
|
|
public override Cursor Cursor => new Cursor(StandardCursorType.SizeNorthSouth); |
|
|
|
|
|
|
|
protected override double GetActualLength(RowDefinition definition) |
|
|
|
private double GetActualLength(DefinitionBase definition) |
|
|
|
{ |
|
|
|
return definition.ActualHeight; |
|
|
|
var columnDefinition = definition as ColumnDefinition; |
|
|
|
return columnDefinition?.ActualWidth ?? ((RowDefinition)definition).ActualHeight; |
|
|
|
} |
|
|
|
|
|
|
|
protected override double GetMaxLength(RowDefinition definition) |
|
|
|
private double GetMinLength(DefinitionBase definition) |
|
|
|
{ |
|
|
|
return definition.MaxHeight; |
|
|
|
var columnDefinition = definition as ColumnDefinition; |
|
|
|
return columnDefinition?.MinWidth ?? ((RowDefinition)definition).MinHeight; |
|
|
|
} |
|
|
|
|
|
|
|
protected override double GetMinLength(RowDefinition definition) |
|
|
|
private double GetMaxLength(DefinitionBase definition) |
|
|
|
{ |
|
|
|
return definition.MinHeight; |
|
|
|
var columnDefinition = definition as ColumnDefinition; |
|
|
|
return columnDefinition?.MaxWidth ?? ((RowDefinition)definition).MaxHeight; |
|
|
|
} |
|
|
|
|
|
|
|
protected override bool IsStar(RowDefinition definition) |
|
|
|
private bool IsStar(DefinitionBase definition) |
|
|
|
{ |
|
|
|
return definition.Height.IsStar; |
|
|
|
var columnDefinition = definition as ColumnDefinition; |
|
|
|
return columnDefinition?.Width.IsStar ?? ((RowDefinition)definition).Height.IsStar; |
|
|
|
} |
|
|
|
|
|
|
|
protected override double GetDelta(VectorEventArgs vectorEventArgs) |
|
|
|
private void SetLengthInStars(DefinitionBase definition, double value) |
|
|
|
{ |
|
|
|
return vectorEventArgs.Vector.Y; |
|
|
|
var columnDefinition = definition as ColumnDefinition; |
|
|
|
if (columnDefinition != null) |
|
|
|
{ |
|
|
|
columnDefinition.Width = new GridLength(value, GridUnitType.Star); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
((RowDefinition)definition).Height = new GridLength(value, GridUnitType.Star); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
protected override void SetLengthInStars(RowDefinition definition, double value) |
|
|
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) |
|
|
|
{ |
|
|
|
definition.Height = new GridLength(value, GridUnitType.Star); |
|
|
|
base.OnAttachedToVisualTree(e); |
|
|
|
_grid = this.GetVisualParent<Grid>(); |
|
|
|
AutoSetOrientation(); |
|
|
|
if (Orientation.Value == Perspex.Controls.Orientation.Vertical) |
|
|
|
{ |
|
|
|
Cursor = new Cursor(StandardCursorType.SizeWestEast); |
|
|
|
var col = GetValue(Grid.ColumnProperty); |
|
|
|
_definitions = _grid.ColumnDefinitions.Cast<DefinitionBase>().ToList(); |
|
|
|
_prevDefinition = _definitions[col - 1]; |
|
|
|
_nextDefinition = _definitions[col + 1]; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
Cursor = new Cursor(StandardCursorType.SizeNorthSouth); |
|
|
|
var row = GetValue(Grid.RowProperty); |
|
|
|
_definitions = _grid.RowDefinitions.Cast<DefinitionBase>().ToList(); |
|
|
|
_prevDefinition = _definitions[row - 1]; |
|
|
|
_nextDefinition = _definitions[row + 1]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
internal class VerticalColumnsResizer : GridColumnsResizer<ColumnDefinition> |
|
|
|
{ |
|
|
|
public VerticalColumnsResizer(Grid _grid, int splitterColumn) |
|
|
|
{ |
|
|
|
_definitions = _grid.ColumnDefinitions; |
|
|
|
_nextDefinition = _definitions[splitterColumn + 1]; |
|
|
|
_prevDefinition = _definitions[splitterColumn - 1]; |
|
|
|
} |
|
|
|
|
|
|
|
public override Cursor Cursor => new Cursor(StandardCursorType.SizeWestEast); |
|
|
|
|
|
|
|
protected override double GetActualLength(ColumnDefinition definition) |
|
|
|
{ |
|
|
|
return definition.ActualWidth; |
|
|
|
} |
|
|
|
|
|
|
|
protected override double GetMaxLength(ColumnDefinition definition) |
|
|
|
{ |
|
|
|
return definition.MaxWidth; |
|
|
|
} |
|
|
|
|
|
|
|
protected override double GetMinLength(ColumnDefinition definition) |
|
|
|
{ |
|
|
|
return definition.MinWidth; |
|
|
|
} |
|
|
|
|
|
|
|
protected override bool IsStar(ColumnDefinition definition) |
|
|
|
{ |
|
|
|
return definition.Width.IsStar; |
|
|
|
} |
|
|
|
|
|
|
|
protected override double GetDelta(VectorEventArgs vectorEventArgs) |
|
|
|
{ |
|
|
|
return vectorEventArgs.Vector.X; |
|
|
|
} |
|
|
|
|
|
|
|
protected override void SetLengthInStars(ColumnDefinition definition, double value) |
|
|
|
{ |
|
|
|
definition.Width = new GridLength(value, GridUnitType.Star); |
|
|
|
} |
|
|
|
} |
|
|
|
} |