Browse Source

Implement border child alignment.

pull/4/head
Steven Kirk 12 years ago
parent
commit
32c8914609
  1. 200
      Perspex.Direct2D1.RenderTests/Controls/BorderTests.cs
  2. 2
      Perspex.Direct2D1/Renderer.cs
  3. 23
      Perspex/Controls/Border.cs
  4. 2
      Perspex/Controls/ContentControl.cs
  5. 7
      Perspex/Controls/Control.cs
  6. 43
      Perspex/Controls/Decorator.cs
  7. 4
      Perspex/Controls/TextBlock.cs
  8. 2
      Perspex/IVisual.cs
  9. 137
      Perspex/Layout/LayoutHelper.cs
  10. 1
      Perspex/Perspex.csproj
  11. 13
      Perspex/Rect.cs
  12. 14
      Perspex/Visual.cs
  13. BIN
      TestFiles/Direct2D1/Controls/Border/Border_Bottom_Aligns_Content.expected.png
  14. BIN
      TestFiles/Direct2D1/Controls/Border/Border_Centers_Content_Horizontally.expected.png
  15. BIN
      TestFiles/Direct2D1/Controls/Border/Border_Centers_Content_Vertically.expected.png
  16. BIN
      TestFiles/Direct2D1/Controls/Border/Border_Left_Aligns_Content.expected.png
  17. BIN
      TestFiles/Direct2D1/Controls/Border/Border_Right_Aligns_Content.expected.png
  18. BIN
      TestFiles/Direct2D1/Controls/Border/Border_Stretches_Content_Horizontally.expected.png
  19. BIN
      TestFiles/Direct2D1/Controls/Border/Border_Stretches_Content_Vertically.expected.png
  20. BIN
      TestFiles/Direct2D1/Controls/Border/Border_Top_Aligns_Content.expected.png

200
Perspex.Direct2D1.RenderTests/Controls/BorderTests.cs

@ -144,5 +144,205 @@ namespace Perspex.Direct2D1.RenderTests.Controls
this.RenderToFile(target);
this.CompareImages();
}
[TestMethod]
public void Border_Centers_Content_Horizontally()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Content = new Border
{
BorderBrush = Brushes.Black,
BorderThickness = 2,
Content = new TextBlock
{
Text = "Foo",
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Center,
}
}
};
this.RenderToFile(target);
this.CompareImages();
}
[TestMethod]
public void Border_Centers_Content_Vertically()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Content = new Border
{
BorderBrush = Brushes.Black,
BorderThickness = 2,
Content = new TextBlock
{
Text = "Foo",
Background = Brushes.Red,
VerticalAlignment = VerticalAlignment.Center,
}
}
};
this.RenderToFile(target);
this.CompareImages();
}
[TestMethod]
public void Border_Stretches_Content_Horizontally()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Content = new Border
{
BorderBrush = Brushes.Black,
BorderThickness = 2,
Content = new TextBlock
{
Text = "Foo",
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Stretch,
}
}
};
this.RenderToFile(target);
this.CompareImages();
}
[TestMethod]
public void Border_Stretches_Content_Vertically()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Content = new Border
{
BorderBrush = Brushes.Black,
BorderThickness = 2,
Content = new TextBlock
{
Text = "Foo",
Background = Brushes.Red,
VerticalAlignment = VerticalAlignment.Stretch,
}
}
};
this.RenderToFile(target);
this.CompareImages();
}
[TestMethod]
public void Border_Left_Aligns_Content()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Content = new Border
{
BorderBrush = Brushes.Black,
BorderThickness = 2,
Content = new TextBlock
{
Text = "Foo",
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Left,
}
}
};
this.RenderToFile(target);
this.CompareImages();
}
[TestMethod]
public void Border_Right_Aligns_Content()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Content = new Border
{
BorderBrush = Brushes.Black,
BorderThickness = 2,
Content = new TextBlock
{
Text = "Foo",
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Right,
}
}
};
this.RenderToFile(target);
this.CompareImages();
}
[TestMethod]
public void Border_Top_Aligns_Content()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Content = new Border
{
BorderBrush = Brushes.Black,
BorderThickness = 2,
Content = new TextBlock
{
Text = "Foo",
Background = Brushes.Red,
VerticalAlignment = VerticalAlignment.Top,
}
}
};
this.RenderToFile(target);
this.CompareImages();
}
[TestMethod]
public void Border_Bottom_Aligns_Content()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Content = new Border
{
BorderBrush = Brushes.Black,
BorderThickness = 2,
Content = new TextBlock
{
Text = "Foo",
Background = Brushes.Red,
VerticalAlignment = VerticalAlignment.Bottom,
}
}
};
this.RenderToFile(target);
this.CompareImages();
}
}
}

2
Perspex.Direct2D1/Renderer.cs

@ -121,7 +121,7 @@ namespace Perspex.Direct2D1
{
visual.Render(context);
foreach (Visual child in visual.VisualChildren)
foreach (IVisual child in visual.VisualChildren)
{
Matrix translate = Matrix.Translation(child.Bounds.X, child.Bounds.Y);

23
Perspex/Controls/Border.cs

@ -8,6 +8,7 @@ namespace Perspex.Controls
{
using System;
using System.Reactive.Linq;
using Perspex.Layout;
using Perspex.Media;
public class Border : Decorator
@ -27,7 +28,7 @@ namespace Perspex.Controls
Brush background = this.Background;
Brush borderBrush = this.BorderBrush;
double borderThickness = this.BorderThickness;
Rect rect = new Rect(this.Bounds.Size).Deflate(BorderThickness / 2);
Rect rect = new Rect(this.ActualSize).Deflate(BorderThickness / 2);
if (background != null)
{
@ -43,20 +44,20 @@ namespace Perspex.Controls
protected override Size ArrangeContent(Size finalSize)
{
Control content = this.Content;
if (content != null)
{
Thickness padding = this.Padding + new Thickness(this.BorderThickness);
content.Arrange(new Rect(finalSize).Deflate(padding));
}
return finalSize;
return LayoutHelper.ArrangeDecorator(
this,
this.Content,
finalSize,
this.Padding + new Thickness(this.BorderThickness));
}
protected override Size MeasureContent(Size availableSize)
{
return this.DefaultMeasure(availableSize, this.Padding + new Thickness(this.BorderThickness));
return LayoutHelper.MeasureDecorator(
this,
this.Content,
availableSize,
this.Padding + new Thickness(this.BorderThickness));
}
}
}

2
Perspex/Controls/ContentControl.cs

@ -55,7 +55,7 @@ namespace Perspex.Controls
if (child != null)
{
child.Arrange(new Rect(finalSize));
return child.Bounds.Size;
return child.ActualSize;
}
else
{

7
Perspex/Controls/Control.cs

@ -149,6 +149,11 @@ namespace Perspex.Controls
remove { this.RemoveHandler(PointerReleasedEvent, value); }
}
public Size ActualSize
{
get { return ((IVisual)this).Bounds.Size; }
}
public Brush Background
{
get { return this.GetValue(BackgroundProperty); }
@ -329,7 +334,7 @@ namespace Perspex.Controls
{
Thickness margin = this.Margin;
this.Bounds = new Rect(
((IVisual)this).Bounds = new Rect(
new Point(rect.Position.X + margin.Left, rect.Position.Y + margin.Top),
this.ArrangeContent(rect.Size.Deflate(margin).Constrain(rect.Size)));
}

43
Perspex/Controls/Decorator.cs

@ -10,6 +10,7 @@ namespace Perspex.Controls
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using Perspex.Layout;
public class Decorator : Control, IVisual
{
@ -65,50 +66,12 @@ namespace Perspex.Controls
protected override Size ArrangeContent(Size finalSize)
{
Control content = this.Content;
if (content != null)
{
content.Arrange(new Rect(finalSize).Deflate(this.Padding));
}
return finalSize;
return LayoutHelper.ArrangeDecorator(this, this.Content, finalSize, this.Padding);
}
protected override Size MeasureContent(Size availableSize)
{
return this.DefaultMeasure(availableSize, this.Padding);
}
protected Size DefaultMeasure(Size availableSize, Thickness padding)
{
double width = 0;
double height = 0;
if (this.Visibility != Visibility.Collapsed)
{
Control content = this.Content;
if (content != null)
{
content.Measure(availableSize);
Size s = content.DesiredSize.Value.Inflate(this.Padding);
width = s.Width;
height = s.Height;
}
if (this.Width > 0)
{
width = this.Width;
}
if (this.Height > 0)
{
height = this.Height;
}
}
return new Size(width, height);
return LayoutHelper.MeasureDecorator(this, this.Content, availableSize, this.Padding);
}
}
}

4
Perspex/Controls/TextBlock.cs

@ -60,10 +60,10 @@ namespace Perspex.Controls
if (background != null)
{
context.FillRectange(background, this.Bounds);
context.FillRectange(background, new Rect(this.ActualSize));
}
context.DrawText(this.Foreground, new Rect(this.Bounds.Size), this.FormattedText);
context.DrawText(this.Foreground, new Rect(this.ActualSize), this.FormattedText);
}
}

2
Perspex/IVisual.cs

@ -12,7 +12,7 @@ namespace Perspex
public interface IVisual
{
Rect Bounds { get; }
Rect Bounds { get; set; }
IEnumerable<IVisual> ExistingVisualChildren { get; }

137
Perspex/Layout/LayoutHelper.cs

@ -0,0 +1,137 @@
// -----------------------------------------------------------------------
// <copyright file="LayoutHelper.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Layout
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Perspex.Controls;
public static class LayoutHelper
{
public static Size MeasureDecorator(
Control decorator,
Control content,
Size availableSize,
Thickness padding)
{
double width = 0;
double height = 0;
if (decorator.Visibility != Visibility.Collapsed)
{
if (content != null)
{
content.Measure(availableSize);
Size s = content.DesiredSize.Value.Inflate(padding);
width = s.Width;
height = s.Height;
}
if (decorator.Width > 0)
{
width = decorator.Width;
}
if (decorator.Height > 0)
{
height = decorator.Height;
}
}
return new Size(width, height);
}
public static Size ArrangeDecorator(
Control decorator,
Control content,
Size finalSize,
Thickness padding)
{
if (content != null)
{
Rect childRect = AlignChild(
new Rect(finalSize).Deflate(padding),
content.DesiredSize.Value,
content.HorizontalAlignment,
content.VerticalAlignment);
content.Arrange(childRect);
}
return finalSize;
}
public static Rect AlignChild(
Rect parentRect,
Size desiredSize,
HorizontalAlignment horizontalAlignment,
VerticalAlignment verticalAlignment)
{
double x;
double y;
double width;
double height;
switch (horizontalAlignment)
{
case HorizontalAlignment.Stretch:
width = parentRect.Width;
x = parentRect.X;
break;
case HorizontalAlignment.Left:
width = desiredSize.Width;
x = parentRect.X;
break;
case HorizontalAlignment.Center:
width = desiredSize.Width;
x = (parentRect.Width - width) / 2;
break;
case HorizontalAlignment.Right:
width = desiredSize.Width;
x = parentRect.Right - width;
break;
default:
throw new InvalidOperationException("Invalid HorizontalAlignment.");
}
switch (verticalAlignment)
{
case VerticalAlignment.Stretch:
height = parentRect.Height;
y = parentRect.Y;
break;
case VerticalAlignment.Top:
height = desiredSize.Height;
y = parentRect.Y;
break;
case VerticalAlignment.Center:
height = desiredSize.Height;
y = (parentRect.Height - height) / 2;
break;
case VerticalAlignment.Bottom:
height = desiredSize.Height;
y = parentRect.Bottom - height;
break;
default:
throw new InvalidOperationException("Invalid VerticalAlignment.");
}
return new Rect(x, y, width, height);
}
}
}

1
Perspex/Perspex.csproj

@ -89,6 +89,7 @@
<Compile Include="Input\InputManager.cs" />
<Compile Include="Input\Raw\RawInputEventArgs.cs" />
<Compile Include="Input\Raw\RawMouseEventArgs.cs" />
<Compile Include="Layout\LayoutHelper.cs" />
<Compile Include="Media\Brushes.cs" />
<Compile Include="Media\Imaging\Bitmap.cs" />
<Compile Include="Media\Imaging\RenderTargetBitmap.cs" />

13
Perspex/Rect.cs

@ -74,6 +74,19 @@ namespace Perspex
this.height = size.Height;
}
/// <summary>
/// Initializes a new instance of the <see cref="Rect"/> structure.
/// </summary>
/// <param name="position">The top left position of the rectangle.</param>
/// <param name="buttonRight">The bottom right position of the rectangle.</param>
public Rect(Point topLeft, Point bottomRight)
{
this.x = topLeft.X;
this.y = topLeft.Y;
this.width = bottomRight.X - topLeft.X;
this.height = bottomRight.Y - topLeft.Y;
}
/// <summary>
/// Gets the X position.
/// </summary>

14
Perspex/Visual.cs

@ -28,23 +28,25 @@ namespace Perspex
private IVisual visualParent;
private Rect bounds;
public Visual()
{
this.GetObservable(VisibilityProperty).Subscribe(_ => this.InvalidateVisual());
}
public Rect Bounds
{
get;
protected set;
}
public Visibility Visibility
{
get { return this.GetValue(VisibilityProperty); }
set { this.SetValue(VisibilityProperty, value); }
}
Rect IVisual.Bounds
{
get { return this.bounds; }
set { this.bounds = value; }
}
IEnumerable<IVisual> IVisual.ExistingVisualChildren
{
get { return ((IVisual)this).VisualChildren; }

BIN
TestFiles/Direct2D1/Controls/Border/Border_Bottom_Aligns_Content.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 B

BIN
TestFiles/Direct2D1/Controls/Border/Border_Centers_Content_Horizontally.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

BIN
TestFiles/Direct2D1/Controls/Border/Border_Centers_Content_Vertically.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

BIN
TestFiles/Direct2D1/Controls/Border/Border_Left_Aligns_Content.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

BIN
TestFiles/Direct2D1/Controls/Border/Border_Right_Aligns_Content.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

BIN
TestFiles/Direct2D1/Controls/Border/Border_Stretches_Content_Horizontally.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 B

BIN
TestFiles/Direct2D1/Controls/Border/Border_Stretches_Content_Vertically.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 B

BIN
TestFiles/Direct2D1/Controls/Border/Border_Top_Aligns_Content.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

Loading…
Cancel
Save