Browse Source

Implemented LinearGradientBrush

pull/96/head
Nelson Carrillo 11 years ago
parent
commit
454b1547ee
  1. 10
      src/Perspex.SceneGraph/Media/Brush.cs
  2. 14
      src/Perspex.SceneGraph/Media/BrushMappingMode.cs
  3. 38
      src/Perspex.SceneGraph/Media/GradientBrush.cs
  4. 15
      src/Perspex.SceneGraph/Media/GradientSpreadMethod.cs
  5. 36
      src/Perspex.SceneGraph/Media/GradientStop.cs
  6. 23
      src/Perspex.SceneGraph/Media/LinearGradientBrush.cs
  7. 5
      src/Perspex.SceneGraph/Perspex.SceneGraph.csproj
  8. 19
      src/Windows/Perspex.Direct2D1/Media/BrushImpl.cs
  9. 44
      src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs
  10. 43
      src/Windows/Perspex.Direct2D1/Media/LinearGradientBrushImpl.cs
  11. 11
      src/Windows/Perspex.Direct2D1/Media/PerspexTextRenderer.cs
  12. 17
      src/Windows/Perspex.Direct2D1/Media/SolidColorBrushImpl.cs
  13. 3
      src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj
  14. 9
      src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs

10
src/Perspex.SceneGraph/Media/Brush.cs

@ -9,7 +9,15 @@ namespace Perspex.Media
/// <summary>
/// Describes how an area is painted.
/// </summary>
public abstract class Brush
public abstract class Brush : PerspexObject
{
public static readonly PerspexProperty<double> OpacityProperty =
PerspexProperty.Register<Brush, double>(nameof(Opacity), 1.0);
public double Opacity
{
get { return this.GetValue(OpacityProperty); }
set { this.SetValue(OpacityProperty, value); }
}
}
}

14
src/Perspex.SceneGraph/Media/BrushMappingMode.cs

@ -0,0 +1,14 @@
namespace Perspex.Media
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public enum BrushMappingMode
{
Absolute,
RelativeToBoundingBox
}
}

38
src/Perspex.SceneGraph/Media/GradientBrush.cs

@ -0,0 +1,38 @@
namespace Perspex.Media
{
using System.Collections.Generic;
public abstract class GradientBrush : Brush
{
public static readonly PerspexProperty<BrushMappingMode> MappingModeProperty =
PerspexProperty.Register<GradientBrush, BrushMappingMode>(nameof(MappingMode), BrushMappingMode.RelativeToBoundingBox);
public static readonly PerspexProperty<GradientSpreadMethod> SpreadMethodProperty =
PerspexProperty.Register<GradientBrush, GradientSpreadMethod>(nameof(SpreadMethod), GradientSpreadMethod.Pad);
public static readonly PerspexProperty<List<GradientStop>> GradientStopsProperty =
PerspexProperty.Register<GradientBrush, List<GradientStop>>(nameof(Opacity), new List<GradientStop>());
public GradientBrush()
{
}
public BrushMappingMode MappingMode
{
get { return this.GetValue(MappingModeProperty); }
set { this.SetValue(MappingModeProperty, value); }
}
public GradientSpreadMethod SpreadMethod
{
get { return this.GetValue(SpreadMethodProperty); }
set { this.SetValue(SpreadMethodProperty, value); }
}
public List<GradientStop> GradientStops
{
get { return this.GetValue(GradientStopsProperty); }
set { this.SetValue(GradientStopsProperty, value); }
}
}
}

15
src/Perspex.SceneGraph/Media/GradientSpreadMethod.cs

@ -0,0 +1,15 @@
namespace Perspex.Media
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public enum GradientSpreadMethod
{
Pad,
Reflect,
Repeat
}
}

36
src/Perspex.SceneGraph/Media/GradientStop.cs

@ -0,0 +1,36 @@
namespace Perspex.Media
{
/// <summary>
/// GradientStop
/// </summary>
public sealed class GradientStop
{
/// <summary>
/// Initializes a new instance of the <see cref="GradientStop"/> class.
/// </summary>
public GradientStop() { }
/// <summary>
/// Initializes a new instance of the <see cref="GradientStop"/> class.
/// </summary>
/// <param name="color">The color</param>
/// <param name="offset">The offset</param>
public GradientStop(Color color, double offset)
{
this.Color = color;
this.Offset = offset;
}
// TODO: Make these dependency properties.
/// <summary>
/// The offset
/// </summary>
public double Offset { get; set; }
/// <summary>
/// The color
/// </summary>
public Color Color { get; set; }
}
}

23
src/Perspex.SceneGraph/Media/LinearGradientBrush.cs

@ -0,0 +1,23 @@
namespace Perspex.Media
{
public class LinearGradientBrush : GradientBrush
{
public static readonly PerspexProperty<Point> StartPointProperty =
PerspexProperty.Register<LinearGradientBrush, Point>(nameof(StartPoint), new Point(0,0));
public static readonly PerspexProperty<Point> EndPointProperty =
PerspexProperty.Register<LinearGradientBrush, Point>(nameof(EndPoint), new Point(0, 0));
public Point StartPoint
{
get { return this.GetValue(StartPointProperty); }
set { this.SetValue(StartPointProperty, value); }
}
public Point EndPoint
{
get { return this.GetValue(EndPointProperty); }
set { this.SetValue(EndPointProperty, value); }
}
}
}

5
src/Perspex.SceneGraph/Perspex.SceneGraph.csproj

@ -59,8 +59,13 @@
<Compile Include="Matrix.cs" />
<Compile Include="Media\Brush.cs" />
<Compile Include="Media\Brushes.cs" />
<Compile Include="Media\BrushMappingMode.cs" />
<Compile Include="Media\Color.cs" />
<Compile Include="Media\Colors.cs" />
<Compile Include="Media\GradientBrush.cs" />
<Compile Include="Media\GradientSpreadMethod.cs" />
<Compile Include="Media\GradientStop.cs" />
<Compile Include="Media\LinearGradientBrush.cs" />
<Compile Include="Media\TextAlignment.cs" />
<Compile Include="Media\FontWeight.cs" />
<Compile Include="Media\FontStyle.cs" />

19
src/Windows/Perspex.Direct2D1/Media/BrushImpl.cs

@ -0,0 +1,19 @@
using System;
namespace Perspex.Direct2D1.Media
{
public abstract class BrushImpl : IDisposable
{
public SharpDX.Direct2D1.Brush PlatformBrush { get; set; }
public BrushImpl(Perspex.Media.Brush brush, SharpDX.Direct2D1.RenderTarget target, Size destinationSize)
{
}
public virtual void Dispose()
{
if (this.PlatformBrush != null)
this.PlatformBrush.Dispose();
}
}
}

44
src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs

@ -89,13 +89,15 @@ namespace Perspex.Direct2D1.Media
{
if (pen != null)
{
using (var d2dBrush = pen.Brush.ToDirect2D(this.renderTarget))
var size = new Rect(p1, p2).Size;
using (var d2dBrush = this.CreateBrush(pen.Brush, size))
using (var d2dStroke = pen.ToDirect2DStrokeStyle(this.renderTarget))
{
this.renderTarget.DrawLine(
p1.ToSharpDX(),
p2.ToSharpDX(),
d2dBrush,
d2dBrush.PlatformBrush,
(float)pen.Thickness,
d2dStroke);
}
@ -112,20 +114,20 @@ namespace Perspex.Direct2D1.Media
{
if (brush != null)
{
using (var d2dBrush = brush.ToDirect2D(this.renderTarget))
using (var d2dBrush = this.CreateBrush(brush, geometry.Bounds.Size))
{
GeometryImpl impl = (GeometryImpl)geometry.PlatformImpl;
this.renderTarget.FillGeometry(impl.Geometry, d2dBrush);
this.renderTarget.FillGeometry(impl.Geometry, d2dBrush.PlatformBrush);
}
}
if (pen != null)
{
using (var d2dBrush = pen.Brush.ToDirect2D(this.renderTarget))
using (var d2dBrush = this.CreateBrush(pen.Brush, geometry.GetRenderBounds(pen.Thickness).Size))
using (var d2dStroke = pen.ToDirect2DStrokeStyle(this.renderTarget))
{
GeometryImpl impl = (GeometryImpl)geometry.PlatformImpl;
this.renderTarget.DrawGeometry(impl.Geometry, d2dBrush, (float)pen.Thickness, d2dStroke);
this.renderTarget.DrawGeometry(impl.Geometry, d2dBrush.PlatformBrush, (float)pen.Thickness, d2dStroke);
}
}
}
@ -138,12 +140,12 @@ namespace Perspex.Direct2D1.Media
/// <param name="cornerRadius">The corner radius.</param>
public void DrawRectange(Pen pen, Rect rect, float cornerRadius)
{
using (var brush = pen.Brush.ToDirect2D(this.renderTarget))
using (var brush = this.CreateBrush(pen.Brush, rect.Size))
using (var d2dStroke = pen.ToDirect2DStrokeStyle(this.renderTarget))
{
this.renderTarget.DrawRoundedRectangle(
new RoundedRectangle { Rect = rect.ToDirect2D(), RadiusX = cornerRadius, RadiusY = cornerRadius },
brush,
brush.PlatformBrush,
(float)pen.Thickness,
d2dStroke);
}
@ -161,7 +163,8 @@ namespace Perspex.Direct2D1.Media
{
var impl = (FormattedTextImpl)text.PlatformImpl;
using (var renderer = new PerspexTextRenderer(this.renderTarget, foreground.ToDirect2D(this.renderTarget)))
using (var brush = this.CreateBrush(foreground, impl.Measure()))
using (var renderer = new PerspexTextRenderer(this, this.renderTarget, brush.PlatformBrush))
{
impl.TextLayout.Draw(renderer, (float)origin.X, (float)origin.Y);
}
@ -176,7 +179,7 @@ namespace Perspex.Direct2D1.Media
/// <param name="cornerRadius">The corner radius.</param>
public void FillRectange(Perspex.Media.Brush brush, Rect rect, float cornerRadius)
{
using (var b = brush.ToDirect2D(this.renderTarget))
using (var b = this.CreateBrush(brush, rect.Size))
{
this.renderTarget.FillRoundedRectangle(
new RoundedRectangle
@ -189,7 +192,7 @@ namespace Perspex.Direct2D1.Media
RadiusX = cornerRadius,
RadiusY = cornerRadius
},
b);
b.PlatformBrush);
}
}
@ -256,5 +259,24 @@ namespace Perspex.Direct2D1.Media
this.renderTarget.Transform = transform * m3x2;
});
}
public BrushImpl CreateBrush(Perspex.Media.Brush brush, Size destinationSize)
{
Perspex.Media.SolidColorBrush solidColorBrush = brush as Perspex.Media.SolidColorBrush;
Perspex.Media.LinearGradientBrush linearGradientBrush = brush as Perspex.Media.LinearGradientBrush;
if (solidColorBrush != null)
{
return new SolidColorBrushImpl(solidColorBrush, this.renderTarget, destinationSize);
}
else if (linearGradientBrush != null)
{
return new LinearGradientBrushImpl(linearGradientBrush, this.renderTarget, destinationSize);
}
else
{
return new SolidColorBrushImpl(null, this.renderTarget, destinationSize);
}
}
}
}

43
src/Windows/Perspex.Direct2D1/Media/LinearGradientBrushImpl.cs

@ -0,0 +1,43 @@
namespace Perspex.Direct2D1.Media
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class LinearGradientBrushImpl : BrushImpl
{
public LinearGradientBrushImpl(Perspex.Media.LinearGradientBrush brush, SharpDX.Direct2D1.RenderTarget target, Size destinationSize)
: base(brush, target, destinationSize)
{
if (brush != null)
{
var gradientStops = brush.GradientStops.Select(s => new SharpDX.Direct2D1.GradientStop { Color = s.Color.ToDirect2D(), Position = (float)s.Offset }).ToArray();
Point startPoint = new Point(0, 0);
Point endPoint = new Point(0, 0);
switch (brush.MappingMode)
{
case Perspex.Media.BrushMappingMode.Absolute:
// TODO:
break;
case Perspex.Media.BrushMappingMode.RelativeToBoundingBox:
startPoint = new Point(brush.StartPoint.X * destinationSize.Width, brush.StartPoint.Y * destinationSize.Height);
endPoint = new Point(brush.EndPoint.X * destinationSize.Width, brush.EndPoint.Y * destinationSize.Height);
break;
}
this.PlatformBrush = new SharpDX.Direct2D1.LinearGradientBrush(
target,
new SharpDX.Direct2D1.LinearGradientBrushProperties { StartPoint = startPoint.ToSharpDX(), EndPoint = endPoint.ToSharpDX() },
new SharpDX.Direct2D1.BrushProperties { Opacity = (float)brush.Opacity, Transform = target.Transform },
new SharpDX.Direct2D1.GradientStopCollection(target, gradientStops, brush.SpreadMethod.ToDirect2D())
);
}
}
}
}

11
src/Windows/Perspex.Direct2D1/Media/PerspexTextRenderer.cs

@ -13,14 +13,18 @@ namespace Perspex.Direct2D1.Media
internal class PerspexTextRenderer : TextRenderer
{
private DrawingContext context;
private RenderTarget renderTarget;
private Brush foreground;
public PerspexTextRenderer(
DrawingContext context,
RenderTarget target,
Brush foreground)
{
this.context = context;
this.renderTarget = target;
this.foreground = foreground;
}
@ -33,7 +37,6 @@ namespace Perspex.Direct2D1.Media
public void Dispose()
{
this.foreground.Dispose();
}
public Result DrawGlyphRun(
@ -46,9 +49,11 @@ namespace Perspex.Direct2D1.Media
ComObject clientDrawingEffect)
{
var wrapper = clientDrawingEffect as BrushWrapper;
// TODO: Work out how to get the size below rather than passing new Size().
var brush = (wrapper == null) ?
this.foreground :
wrapper.Brush.ToDirect2D(this.renderTarget);
this.context.CreateBrush(wrapper.Brush, new Size()).PlatformBrush;
this.renderTarget.DrawGlyphRun(
new Vector2(baselineOriginX, baselineOriginY),
@ -94,4 +99,4 @@ namespace Perspex.Direct2D1.Media
return false;
}
}
}
}

17
src/Windows/Perspex.Direct2D1/Media/SolidColorBrushImpl.cs

@ -0,0 +1,17 @@
namespace Perspex.Direct2D1.Media
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class SolidColorBrushImpl : BrushImpl
{
public SolidColorBrushImpl(Perspex.Media.SolidColorBrush brush, SharpDX.Direct2D1.RenderTarget target, Size destinationSize)
: base(brush, target, destinationSize)
{
this.PlatformBrush = new SharpDX.Direct2D1.SolidColorBrush(target, brush?.Color.ToDirect2D() ?? new SharpDX.Color4());
}
}
}

3
src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj

@ -75,11 +75,14 @@
</Compile>
<Compile Include="Direct2D1Platform.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Media\BrushImpl.cs" />
<Compile Include="Media\BrushWrapper.cs" />
<Compile Include="Media\DrawingContext.cs" />
<Compile Include="Media\Imaging\RenderTargetBitmapImpl.cs" />
<Compile Include="Media\Imaging\BitmapImpl.cs" />
<Compile Include="Media\LinearGradientBrushImpl.cs" />
<Compile Include="Media\PerspexTextRenderer.cs" />
<Compile Include="Media\SolidColorBrushImpl.cs" />
<Compile Include="Media\StreamGeometryContextImpl.cs" />
<Compile Include="Media\GeometryImpl.cs" />
<Compile Include="Media\StreamGeometryImpl.cs" />

9
src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs

@ -34,6 +34,15 @@ namespace Perspex.Direct2D1
return new Size2F((float)p.Width, (float)p.Height);
}
public static SharpDX.Direct2D1.ExtendMode ToDirect2D(this Perspex.Media.GradientSpreadMethod spreadMethod)
{
if (spreadMethod == Perspex.Media.GradientSpreadMethod.Pad)
return ExtendMode.Clamp;
else if (spreadMethod == Perspex.Media.GradientSpreadMethod.Reflect)
return ExtendMode.Mirror;
else
return ExtendMode.Wrap;
}
/// <summary>
/// Converts a brush to Direct2D.
/// </summary>

Loading…
Cancel
Save