A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

193 lines
6.0 KiB

// -----------------------------------------------------------------------
// <copyright file="Shape.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls.Shapes
{
using System;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Media;
public abstract class Shape : Control
{
public static readonly PerspexProperty<Brush> FillProperty =
PerspexProperty.Register<Shape, Brush>("Fill");
public static readonly PerspexProperty<Stretch> StretchProperty =
PerspexProperty.Register<Shape, Stretch>("Stretch");
public static readonly PerspexProperty<Brush> StrokeProperty =
PerspexProperty.Register<Shape, Brush>("Stroke");
public static readonly PerspexProperty<PerspexList<double>> StrokeDashArrayProperty =
PerspexProperty.Register<Shape, PerspexList<double>>("StrokeDashArray");
public static readonly PerspexProperty<double> StrokeThicknessProperty =
PerspexProperty.Register<Shape, double>("StrokeThickness");
private Matrix transform = Matrix.Identity;
private Geometry renderedGeometry;
static Shape()
{
Control.AffectsRender(FillProperty);
Control.AffectsMeasure(StretchProperty);
Control.AffectsRender(StrokeProperty);
Control.AffectsRender(StrokeDashArrayProperty);
Control.AffectsMeasure(StrokeThicknessProperty);
}
public abstract Geometry DefiningGeometry
{
get;
}
public Brush Fill
{
get { return this.GetValue(FillProperty); }
set { this.SetValue(FillProperty, value); }
}
public Geometry RenderedGeometry
{
get
{
if (this.renderedGeometry == null)
{
if (this.DefiningGeometry != null)
{
this.renderedGeometry = this.DefiningGeometry.Clone();
this.renderedGeometry.Transform = new MatrixTransform(this.transform);
}
}
return this.renderedGeometry;
}
}
public Stretch Stretch
{
get { return this.GetValue(StretchProperty); }
set { this.SetValue(StretchProperty, value); }
}
public Brush Stroke
{
get { return this.GetValue(StrokeProperty); }
set { this.SetValue(StrokeProperty, value); }
}
public PerspexList<double> StrokeDashArray
{
get { return this.GetValue(StrokeDashArrayProperty); }
set { this.SetValue(StrokeDashArrayProperty, value); }
}
public double StrokeThickness
{
get { return this.GetValue(StrokeThicknessProperty); }
set { this.SetValue(StrokeThicknessProperty, value); }
}
public override void Render(IDrawingContext context)
{
var geometry = this.RenderedGeometry;
if (geometry != null)
{
var pen = new Pen(this.Stroke, this.StrokeThickness, this.StrokeDashArray);
context.DrawGeometry(this.Fill, pen, geometry);
}
}
protected override Size MeasureOverride(Size availableSize)
{
// This should probably use GetRenderBounds(strokeThickness) but then the calculations
// will multiply the stroke thickness as well, which isn't correct.
Rect shapeBounds = this.DefiningGeometry.Bounds;
Size shapeSize = new Size(shapeBounds.Right, shapeBounds.Bottom);
Matrix translate = Matrix.Identity;
double width = this.Width;
double height = this.Height;
double desiredX = availableSize.Width;
double desiredY = availableSize.Height;
double sx = 0.0;
double sy = 0.0;
if (this.Stretch != Stretch.None)
{
shapeSize = shapeBounds.Size;
translate = Matrix.Translation(-(Vector)shapeBounds.Position);
}
if (double.IsInfinity(availableSize.Width))
{
desiredX = shapeSize.Width;
}
if (double.IsInfinity(availableSize.Height))
{
desiredY = shapeSize.Height;
}
if (shapeBounds.Width > 0)
{
sx = desiredX / shapeSize.Width;
}
if (shapeBounds.Height > 0)
{
sy = desiredY / shapeSize.Height;
}
if (double.IsInfinity(availableSize.Width))
{
sx = sy;
}
if (double.IsInfinity(availableSize.Height))
{
sy = sx;
}
switch (this.Stretch)
{
case Stretch.Uniform:
sx = sy = Math.Min(sx, sy);
break;
case Stretch.UniformToFill:
sx = sy = Math.Max(sx, sy);
break;
case Stretch.Fill:
if (double.IsInfinity(availableSize.Width))
{
sx = 1.0;
}
if (double.IsInfinity(availableSize.Height))
{
sy = 1.0;
}
break;
default:
sx = sy = 1;
break;
}
var t = translate * Matrix.Scaling(sx, sy);
if (this.transform != t)
{
this.transform = t;
this.renderedGeometry = null;
}
return new Size(shapeSize.Width * sx, shapeSize.Height * sy);
}
}
}