Browse Source

Documented Layoutable and friends.

pull/81/head
Steven Kirk 11 years ago
parent
commit
f1a15335aa
  1. 9
      Perspex.Layout/ILayoutRoot.cs
  2. 77
      Perspex.Layout/ILayoutable.cs
  3. 358
      Perspex.Layout/Layoutable.cs
  4. 1
      Perspex.Layout/Perspex.Layout.csproj

9
Perspex.Layout/ILayoutRoot.cs

@ -6,10 +6,19 @@
namespace Perspex.Layout namespace Perspex.Layout
{ {
/// <summary>
/// Defines the root of a layoutable tree.
/// </summary>
public interface ILayoutRoot : ILayoutable public interface ILayoutRoot : ILayoutable
{ {
/// <summary>
/// The size available to layout the controls.
/// </summary>
Size ClientSize { get; } Size ClientSize { get; }
/// <summary>
/// The layout manager to use for laying out the tree.
/// </summary>
ILayoutManager LayoutManager { get; } ILayoutManager LayoutManager { get; }
} }
} }

77
Perspex.Layout/ILayoutable.cs

@ -1,48 +1,119 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// <copyright file="ILayoutable.cs" company="Steven Kirk"> // <copyright file="ILayoutable.cs" company="Steven Kirk">
// Copyright 2013 MIT Licence. See licence.md for more information. // Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright> // </copyright>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
namespace Perspex.Layout namespace Perspex.Layout
{ {
// TODO: Probably want to move width/height/etc properties to different interface. /// <summary>
/// Defines layout-related functionality for a control.
/// </summary>
public interface ILayoutable : IVisual public interface ILayoutable : IVisual
{ {
/// <summary>
/// Gets the size that this element computed during the measure pass of the layout process.
/// </summary>
Size DesiredSize { get; } Size DesiredSize { get; }
double Width { get; } /// <summary>
/// Gets the width of the element.
/// </summary>
double Width { get; }
/// <summary>
/// Gets the height of the element.
/// </summary>
double Height { get; } double Height { get; }
/// <summary>
/// Gets the minimum width of the element.
/// </summary>
double MinWidth { get; } double MinWidth { get; }
/// <summary>
/// Gets the maximum width of the element.
/// </summary>
double MaxWidth { get; } double MaxWidth { get; }
/// <summary>
/// Gets the minimum height of the element.
/// </summary>
double MinHeight { get; } double MinHeight { get; }
/// <summary>
/// Gets the maximum height of the element.
/// </summary>
double MaxHeight { get; } double MaxHeight { get; }
/// <summary>
/// Gets the margin around the element.
/// </summary>
Thickness Margin { get; }
/// <summary>
/// Gets the element's preferred horizontal alignment in its parent.
/// </summary>
HorizontalAlignment HorizontalAlignment { get; } HorizontalAlignment HorizontalAlignment { get; }
/// <summary>
/// Gets the element's preferred vertical alignment in its parent.
/// </summary>
VerticalAlignment VerticalAlignment { get; } VerticalAlignment VerticalAlignment { get; }
/// <summary>
/// Gets a value indicating whether the control's layout measure is valid.
/// </summary>
bool IsMeasureValid { get; } bool IsMeasureValid { get; }
/// <summary>
/// Gets a value indicating whether the control's layouts arrange is valid.
/// </summary>
bool IsArrangeValid { get; } bool IsArrangeValid { get; }
/// <summary>
/// Gets the available size passed in the previous layout pass, if any.
/// </summary>
Size? PreviousMeasure { get; } Size? PreviousMeasure { get; }
/// <summary>
/// Gets the layout rect passed in the previous layout pass, if any.
/// </summary>
Rect? PreviousArrange { get; } Rect? PreviousArrange { get; }
/// <summary>
/// Creates the visual children of the control, if necessary
/// </summary>
void ApplyTemplate(); void ApplyTemplate();
/// <summary>
/// Carries out a measure of the control.
/// </summary>
/// <param name="availableSize">The available size for the control.</param>
/// <param name="force">
/// If true, the control will be measured even if <paramref name="availableSize"/> has not
/// changed from the last measure.
/// </param>
void Measure(Size availableSize, bool force = false); void Measure(Size availableSize, bool force = false);
/// <summary>
/// Arranges the control and its children.
/// </summary>
/// <param name="rect">The control's new bounds.</param>
/// <param name="force">
/// If true, the control will be arranged even if <paramref name="rect"/> has not changed
/// from the last arrange.
/// </param>
void Arrange(Rect rect, bool force = false); void Arrange(Rect rect, bool force = false);
/// <summary>
/// Invalidates the measurement of the control and queues a new layout pass.
/// </summary>
void InvalidateMeasure(); void InvalidateMeasure();
/// <summary>
/// Invalidates the arrangement of the control and queues a new layout pass.
/// </summary>
void InvalidateArrange(); void InvalidateArrange();
} }
} }

358
Perspex.Layout/Layoutable.cs

@ -12,53 +12,122 @@ namespace Perspex.Layout
using Serilog; using Serilog;
using Serilog.Core.Enrichers; using Serilog.Core.Enrichers;
/// <summary>
/// Defines how a control aligns itself horizontally in its parent control.
/// </summary>
public enum HorizontalAlignment public enum HorizontalAlignment
{ {
/// <summary>
/// The control stretches to fill the width of the parent control.
/// </summary>
Stretch, Stretch,
/// <summary>
/// The control aligns itself to the left of the parent control.
/// </summary>
Left, Left,
/// <summary>
/// The control centers itself in the parent control.
/// </summary>
Center, Center,
/// <summary>
/// The control aligns itself to the right of the parent control.
/// </summary>
Right, Right,
} }
/// <summary>
/// Defines how a control aligns itself vertically in its parent control.
/// </summary>
public enum VerticalAlignment public enum VerticalAlignment
{ {
/// <summary>
/// The control stretches to fill the height of the parent control.
/// </summary>
Stretch, Stretch,
/// <summary>
/// The control aligns itself to the top of the parent control.
/// </summary>
Top, Top,
/// <summary>
/// The control centers itself within the parent control.
/// </summary>
Center, Center,
/// <summary>
/// The control aligns itself to the bottom of the parent control.
/// </summary>
Bottom, Bottom,
} }
/// <summary>
/// Implements layout-related functionality for a control.
/// </summary>
public class Layoutable : Visual, ILayoutable public class Layoutable : Visual, ILayoutable
{ {
/// <summary>
/// Defines the <see cref="Width"/> property.
/// </summary>
public static readonly PerspexProperty<double> WidthProperty = public static readonly PerspexProperty<double> WidthProperty =
PerspexProperty.Register<Layoutable, double>("Width", double.NaN); PerspexProperty.Register<Layoutable, double>(nameof(Width), double.NaN);
/// <summary>
/// Defines the <see cref="Height"/> property.
/// </summary>
public static readonly PerspexProperty<double> HeightProperty = public static readonly PerspexProperty<double> HeightProperty =
PerspexProperty.Register<Layoutable, double>("Height", double.NaN); PerspexProperty.Register<Layoutable, double>(nameof(Height), double.NaN);
/// <summary>
/// Defines the <see cref="MinWidth"/> property.
/// </summary>
public static readonly PerspexProperty<double> MinWidthProperty = public static readonly PerspexProperty<double> MinWidthProperty =
PerspexProperty.Register<Layoutable, double>("MinWidth"); PerspexProperty.Register<Layoutable, double>(nameof(MinWidth));
/// <summary>
/// Defines the <see cref="MaxWidth"/> property.
/// </summary>
public static readonly PerspexProperty<double> MaxWidthProperty = public static readonly PerspexProperty<double> MaxWidthProperty =
PerspexProperty.Register<Layoutable, double>("MaxWidth", double.PositiveInfinity); PerspexProperty.Register<Layoutable, double>(nameof(MaxWidth), double.PositiveInfinity);
/// <summary>
/// Defines the <see cref="MinHeight"/> property.
/// </summary>
public static readonly PerspexProperty<double> MinHeightProperty = public static readonly PerspexProperty<double> MinHeightProperty =
PerspexProperty.Register<Layoutable, double>("MinHeight"); PerspexProperty.Register<Layoutable, double>(nameof(MinHeight));
/// <summary>
/// Defines the <see cref="MaxHeight"/> property.
/// </summary>
public static readonly PerspexProperty<double> MaxHeightProperty = public static readonly PerspexProperty<double> MaxHeightProperty =
PerspexProperty.Register<Layoutable, double>("MaxHeight", double.PositiveInfinity); PerspexProperty.Register<Layoutable, double>(nameof(MaxHeight), double.PositiveInfinity);
/// <summary>
/// Defines the <see cref="Margin"/> property.
/// </summary>
public static readonly PerspexProperty<Thickness> MarginProperty = public static readonly PerspexProperty<Thickness> MarginProperty =
PerspexProperty.Register<Layoutable, Thickness>("Margin"); PerspexProperty.Register<Layoutable, Thickness>(nameof(Margin));
/// <summary>
/// Defines the <see cref="HorizontalAlignment"/> property.
/// </summary>
public static readonly PerspexProperty<HorizontalAlignment> HorizontalAlignmentProperty = public static readonly PerspexProperty<HorizontalAlignment> HorizontalAlignmentProperty =
PerspexProperty.Register<Layoutable, HorizontalAlignment>("HorizontalAlignment"); PerspexProperty.Register<Layoutable, HorizontalAlignment>(nameof(HorizontalAlignment));
/// <summary>
/// Defines the <see cref="VerticalAlignment"/> property.
/// </summary>
public static readonly PerspexProperty<VerticalAlignment> VerticalAlignmentProperty = public static readonly PerspexProperty<VerticalAlignment> VerticalAlignmentProperty =
PerspexProperty.Register<Layoutable, VerticalAlignment>("VerticalAlignment"); PerspexProperty.Register<Layoutable, VerticalAlignment>(nameof(VerticalAlignment));
/// <summary>
/// Defines the <see cref="UseLayoutRoundingProperty"/> property.
/// </summary>
public static readonly PerspexProperty<bool> UseLayoutRoundingProperty = public static readonly PerspexProperty<bool> UseLayoutRoundingProperty =
PerspexProperty.Register<Layoutable, bool>("UseLayoutRounding", defaultValue: true, inherits: true); PerspexProperty.Register<Layoutable, bool>(nameof(UseLayoutRounding), defaultValue: true, inherits: true);
private Size? previousMeasure; private Size? previousMeasure;
@ -66,6 +135,9 @@ namespace Perspex.Layout
private ILogger layoutLog; private ILogger layoutLog;
/// <summary>
/// Initializes static members of the <see cref="Layoutable"/> class.
/// </summary>
static Layoutable() static Layoutable()
{ {
Layoutable.AffectsMeasure(Visual.IsVisibleProperty); Layoutable.AffectsMeasure(Visual.IsVisibleProperty);
@ -80,6 +152,9 @@ namespace Perspex.Layout
Layoutable.AffectsMeasure(Layoutable.VerticalAlignmentProperty); Layoutable.AffectsMeasure(Layoutable.VerticalAlignmentProperty);
} }
/// <summary>
/// Initializes a new instance of the <see cref="Layoutable"/> class.
/// </summary>
public Layoutable() public Layoutable()
{ {
this.layoutLog = Log.ForContext(new[] this.layoutLog = Log.ForContext(new[]
@ -90,98 +165,155 @@ namespace Perspex.Layout
}); });
} }
/// <summary>
/// Gets or sets the width of the element.
/// </summary>
public double Width public double Width
{ {
get { return this.GetValue(WidthProperty); } get { return this.GetValue(WidthProperty); }
set { this.SetValue(WidthProperty, value); } set { this.SetValue(WidthProperty, value); }
} }
/// <summary>
/// Gets or sets the height of the element.
/// </summary>
public double Height public double Height
{ {
get { return this.GetValue(HeightProperty); } get { return this.GetValue(HeightProperty); }
set { this.SetValue(HeightProperty, value); } set { this.SetValue(HeightProperty, value); }
} }
/// <summary>
/// Gets or sets the minimum width of the element.
/// </summary>
public double MinWidth public double MinWidth
{ {
get { return this.GetValue(MinWidthProperty); } get { return this.GetValue(MinWidthProperty); }
set { this.SetValue(MinWidthProperty, value); } set { this.SetValue(MinWidthProperty, value); }
} }
/// <summary>
/// Gets or sets the maximum width of the element.
/// </summary>
public double MaxWidth public double MaxWidth
{ {
get { return this.GetValue(MaxWidthProperty); } get { return this.GetValue(MaxWidthProperty); }
set { this.SetValue(MaxWidthProperty, value); } set { this.SetValue(MaxWidthProperty, value); }
} }
/// <summary>
/// Gets or sets the minimum height of the element.
/// </summary>
public double MinHeight public double MinHeight
{ {
get { return this.GetValue(MinHeightProperty); } get { return this.GetValue(MinHeightProperty); }
set { this.SetValue(MinHeightProperty, value); } set { this.SetValue(MinHeightProperty, value); }
} }
/// <summary>
/// Gets or sets the maximum height of the element.
/// </summary>
public double MaxHeight public double MaxHeight
{ {
get { return this.GetValue(MaxHeightProperty); } get { return this.GetValue(MaxHeightProperty); }
set { this.SetValue(MaxHeightProperty, value); } set { this.SetValue(MaxHeightProperty, value); }
} }
/// <summary>
/// Gets or sets the margin around the element.
/// </summary>
public Thickness Margin public Thickness Margin
{ {
get { return this.GetValue(MarginProperty); } get { return this.GetValue(MarginProperty); }
set { this.SetValue(MarginProperty, value); } set { this.SetValue(MarginProperty, value); }
} }
/// <summary>
/// Gets or sets the element's preferred horizontal alignment in its parent.
/// </summary>
public HorizontalAlignment HorizontalAlignment public HorizontalAlignment HorizontalAlignment
{ {
get { return this.GetValue(HorizontalAlignmentProperty); } get { return this.GetValue(HorizontalAlignmentProperty); }
set { this.SetValue(HorizontalAlignmentProperty, value); } set { this.SetValue(HorizontalAlignmentProperty, value); }
} }
/// <summary>
/// Gets or sets the element's preferred vertical alignment in its parent.
/// </summary>
public VerticalAlignment VerticalAlignment public VerticalAlignment VerticalAlignment
{ {
get { return this.GetValue(VerticalAlignmentProperty); } get { return this.GetValue(VerticalAlignmentProperty); }
set { this.SetValue(VerticalAlignmentProperty, value); } set { this.SetValue(VerticalAlignmentProperty, value); }
} }
/// <summary>
/// Gets the size that this element computed during the measure pass of the layout process.
/// </summary>
public Size DesiredSize public Size DesiredSize
{ {
get; get;
set; set;
} }
/// <summary>
/// Gets a value indicating whether the control's layout measure is valid.
/// </summary>
public bool IsMeasureValid public bool IsMeasureValid
{ {
get; get;
private set; private set;
} }
/// <summary>
/// Gets a value indicating whether the control's layouts arrange is valid.
/// </summary>
public bool IsArrangeValid public bool IsArrangeValid
{ {
get; get;
private set; private set;
} }
/// <summary>
/// Gets or sets a value that determines whether the element should be snapped to pixel
/// boundaries at layout time.
/// </summary>
public bool UseLayoutRounding public bool UseLayoutRounding
{ {
get { return this.GetValue(UseLayoutRoundingProperty); } get { return this.GetValue(UseLayoutRoundingProperty); }
set { this.SetValue(UseLayoutRoundingProperty, value); } set { this.SetValue(UseLayoutRoundingProperty, value); }
} }
/// <summary>
/// Gets the available size passed in the previous layout pass, if any.
/// </summary>
Size? ILayoutable.PreviousMeasure Size? ILayoutable.PreviousMeasure
{ {
get { return this.previousMeasure; } get { return this.previousMeasure; }
} }
/// <summary>
/// Gets the layout rect passed in the previous layout pass, if any.
/// </summary>
Rect? ILayoutable.PreviousArrange Rect? ILayoutable.PreviousArrange
{ {
get { return this.previousArrange; } get { return this.previousArrange; }
} }
/// <summary>
/// Creates the visual children of the control, if necessary
/// </summary>
public virtual void ApplyTemplate() public virtual void ApplyTemplate()
{ {
} }
/// <summary>
/// Carries out a measure of the control.
/// </summary>
/// <param name="availableSize">The available size for the control.</param>
/// <param name="force">
/// If true, the control will be measured even if <paramref name="availableSize"/> has not
/// changed from the last measure.
/// </param>
public void Measure(Size availableSize, bool force = false) public void Measure(Size availableSize, bool force = false)
{ {
if (double.IsNaN(availableSize.Width) || double.IsNaN(availableSize.Height)) if (double.IsNaN(availableSize.Width) || double.IsNaN(availableSize.Height))
@ -207,6 +339,14 @@ namespace Perspex.Layout
} }
} }
/// <summary>
/// Arranges the control and its children.
/// </summary>
/// <param name="rect">The control's new bounds.</param>
/// <param name="force">
/// If true, the control will be arranged even if <paramref name="rect"/> has not changed
/// from the last arrange.
/// </param>
public void Arrange(Rect rect, bool force = false) public void Arrange(Rect rect, bool force = false)
{ {
if (IsInvalidRect(rect)) if (IsInvalidRect(rect))
@ -231,6 +371,9 @@ namespace Perspex.Layout
} }
} }
/// <summary>
/// Invalidates the measurement of the control and queues a new layout pass.
/// </summary>
public void InvalidateMeasure() public void InvalidateMeasure()
{ {
var parent = this.GetVisualParent<ILayoutable>(); var parent = this.GetVisualParent<ILayoutable>();
@ -260,6 +403,9 @@ namespace Perspex.Layout
} }
} }
/// <summary>
/// Invalidates the arrangement of the control and queues a new layout pass.
/// </summary>
public void InvalidateArrange() public void InvalidateArrange()
{ {
var root = this.GetLayoutRoot(); var root = this.GetLayoutRoot();
@ -278,16 +424,107 @@ namespace Perspex.Layout
} }
} }
/// <summary>
/// Marks a property as affecting the control's measurement.
/// </summary>
/// <param name="property">The property.</param>
/// <remarks>
/// After a call to this method in a control's static constructor, any change to the
/// property will cause <see cref="InvalidateMeasure"/> to be called on the element.
/// </remarks>
protected static void AffectsMeasure(PerspexProperty property)
{
property.Changed.Subscribe(AffectsMeasureInvalidate);
}
/// <summary>
/// Marks a property as affecting the control's arrangement.
/// </summary>
/// <param name="property">The property.</param>
/// <remarks>
/// After a call to this method in a control's static constructor, any change to the
/// property will cause <see cref="InvalidateArrange"/> to be called on the element.
/// </remarks>
protected static void AffectsArrange(PerspexProperty property) protected static void AffectsArrange(PerspexProperty property)
{ {
property.Changed.Subscribe(AffectsArrangeInvalidate); property.Changed.Subscribe(AffectsArrangeInvalidate);
} }
protected static void AffectsMeasure(PerspexProperty property) /// <summary>
/// The default implementation of the control's measure pass.
/// </summary>
/// <param name="availableSize">The size available to the control.</param>
/// <returns>The desired size for the control.</returns>
/// <remarks>
/// This method calls <see cref="MeasureOverride(Size)"/> which is probably the method you
/// want to override in order to modify a control's arrangement.
/// </remarks>
protected virtual Size MeasureCore(Size availableSize)
{ {
property.Changed.Subscribe(AffectsMeasureInvalidate); if (this.IsVisible)
{
this.ApplyTemplate();
var constrained = LayoutHelper
.ApplyLayoutConstraints(this, availableSize)
.Deflate(this.Margin);
var measured = this.MeasureOverride(constrained);
var width = measured.Width;
var height = measured.Height;
if (!double.IsNaN(this.Width))
{
width = this.Width;
}
width = Math.Min(width, this.MaxWidth);
width = Math.Max(width, this.MinWidth);
if (!double.IsNaN(this.Height))
{
height = this.Height;
}
height = Math.Min(height, this.MaxHeight);
height = Math.Max(height, this.MinHeight);
return new Size(width, height).Inflate(this.Margin);
}
else
{
return new Size();
}
}
/// <summary>
/// Measures the control and its child elements as part of a layout pass.
/// </summary>
/// <param name="availableSize">The size available to the control.</param>
/// <returns>The desired size for the control.</returns>
protected virtual Size MeasureOverride(Size availableSize)
{
double width = 0;
double height = 0;
foreach (ILayoutable child in this.GetVisualChildren().OfType<ILayoutable>())
{
child.Measure(availableSize);
width = Math.Max(width, child.DesiredSize.Width);
height = Math.Max(height, child.DesiredSize.Height);
}
return new Size(width, height);
} }
/// <summary>
/// The default implementation of the control's arrange pass.
/// </summary>
/// <param name="finalRect">The control's new bounds.</param>
/// <remarks>
/// This method calls <see cref="ArrangeOverride(Size)"/> which is probably the method you
/// want to override in order to modify a control's arrangement.
/// </remarks>
protected virtual void ArrangeCore(Rect finalRect) protected virtual void ArrangeCore(Rect finalRect)
{ {
if (this.IsVisible) if (this.IsVisible)
@ -349,6 +586,11 @@ namespace Perspex.Layout
} }
} }
/// <summary>
/// Positions child elements as part of a layout pass.
/// </summary>
/// <param name="finalSize">The size available to the control.</param>
/// <returns>The actual size used.</returns>
protected virtual Size ArrangeOverride(Size finalSize) protected virtual Size ArrangeOverride(Size finalSize)
{ {
foreach (ILayoutable child in this.GetVisualChildren().OfType<ILayoutable>()) foreach (ILayoutable child in this.GetVisualChildren().OfType<ILayoutable>())
@ -359,84 +601,50 @@ namespace Perspex.Layout
return finalSize; return finalSize;
} }
protected virtual Size MeasureCore(Size availableSize) /// <summary>
{ /// Calls <see cref="InvalidateMeasure"/> on the control on which a property changed.
if (this.IsVisible) /// </summary>
{ /// <param name="e">The event args.</param>
this.ApplyTemplate(); private static void AffectsMeasureInvalidate(PerspexPropertyChangedEventArgs e)
var constrained = LayoutHelper
.ApplyLayoutConstraints(this, availableSize)
.Deflate(this.Margin);
var measured = this.MeasureOverride(constrained);
var width = measured.Width;
var height = measured.Height;
if (!double.IsNaN(this.Width))
{
width = this.Width;
}
width = Math.Min(width, this.MaxWidth);
width = Math.Max(width, this.MinWidth);
if (!double.IsNaN(this.Height))
{
height = this.Height;
}
height = Math.Min(height, this.MaxHeight);
height = Math.Max(height, this.MinHeight);
return new Size(width, height).Inflate(this.Margin);
}
else
{
return new Size();
}
}
protected virtual Size MeasureOverride(Size availableSize)
{
double width = 0;
double height = 0;
foreach (ILayoutable child in this.GetVisualChildren().OfType<ILayoutable>())
{
child.Measure(availableSize);
width = Math.Max(width, child.DesiredSize.Width);
height = Math.Max(height, child.DesiredSize.Height);
}
return new Size(width, height);
}
private static void AffectsArrangeInvalidate(PerspexPropertyChangedEventArgs e)
{ {
ILayoutable control = e.Sender as ILayoutable; ILayoutable control = e.Sender as ILayoutable;
if (control != null) if (control != null)
{ {
control.InvalidateArrange(); control.InvalidateMeasure();
} }
} }
private static void AffectsMeasureInvalidate(PerspexPropertyChangedEventArgs e) /// <summary>
/// Calls <see cref="InvalidateArrange"/> on the control on which a property changed.
/// </summary>
/// <param name="e">The event args.</param>
private static void AffectsArrangeInvalidate(PerspexPropertyChangedEventArgs e)
{ {
ILayoutable control = e.Sender as ILayoutable; ILayoutable control = e.Sender as ILayoutable;
if (control != null) if (control != null)
{ {
control.InvalidateMeasure(); control.InvalidateArrange();
} }
} }
/// <summary>
/// Tests whether a control's size can be changed by a layout pass.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>True if the control's size can change; otherwise false.</returns>
private static bool IsResizable(ILayoutable control) private static bool IsResizable(ILayoutable control)
{ {
return double.IsNaN(control.Width) || double.IsNaN(control.Height); return double.IsNaN(control.Width) || double.IsNaN(control.Height);
} }
/// <summary>
/// Tests whether any of a <see cref="Rect"/>'s properties incude nagative values,
/// a NaN or Infinity.
/// </summary>
/// <param name="rect">The rect.</param>
/// <returns>True if the rect is invalid; otherwise false.</returns>
private static bool IsInvalidRect(Rect rect) private static bool IsInvalidRect(Rect rect)
{ {
return rect.Width < 0 || rect.Height < 0 || return rect.Width < 0 || rect.Height < 0 ||
@ -446,6 +654,12 @@ namespace Perspex.Layout
double.IsNaN(rect.Width) || double.IsNaN(rect.Height); double.IsNaN(rect.Width) || double.IsNaN(rect.Height);
} }
/// <summary>
/// Tests whether any of a <see cref="Size"/>'s properties incude nagative values,
/// a NaN or Infinity.
/// </summary>
/// <param name="size">The size.</param>
/// <returns>True if the size is invalid; otherwise false.</returns>
private static bool IsInvalidSize(Size size) private static bool IsInvalidSize(Size size)
{ {
return size.Width < 0 || size.Height < 0 || return size.Width < 0 || size.Height < 0 ||
@ -453,6 +667,12 @@ namespace Perspex.Layout
double.IsNaN(size.Width) || double.IsNaN(size.Height); double.IsNaN(size.Width) || double.IsNaN(size.Height);
} }
/// <summary>
/// Gets the layout root, together with its distance.
/// </summary>
/// <returns>
/// A tuple containing the layout root and the root's distance from this control.
/// </returns>
private Tuple<ILayoutRoot, int> GetLayoutRoot() private Tuple<ILayoutRoot, int> GetLayoutRoot()
{ {
var control = (IVisual)this; var control = (IVisual)this;

1
Perspex.Layout/Perspex.Layout.csproj

@ -56,6 +56,7 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="ILayoutable.cs" /> <Compile Include="ILayoutable.cs" />
<Compile Include="ILayoutManager.cs" /> <Compile Include="ILayoutManager.cs" />
<Compile Include="ILayoutRoot.cs" /> <Compile Include="ILayoutRoot.cs" />

Loading…
Cancel
Save