Browse Source

Merge pull request #59 from ncarrillo/feat-cairo-geometry

Implement Geometry support for Cairo/GTK
pull/63/head
Steven Kirk 11 years ago
parent
commit
5a9caee4dc
  1. 56
      Cairo/Perspex.Cairo/Media/DrawingContext.cs
  2. 74
      Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs
  3. 76
      Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs

56
Cairo/Perspex.Cairo/Media/DrawingContext.cs

@ -13,6 +13,8 @@ namespace Perspex.Cairo.Media
using Splat; using Splat;
using Cairo = global::Cairo; using Cairo = global::Cairo;
using IBitmap = Perspex.Media.Imaging.IBitmap; using IBitmap = Perspex.Media.Imaging.IBitmap;
using System.Collections.Generic;
/// <summary> /// <summary>
/// Draws using Direct2D1. /// Draws using Direct2D1.
@ -114,7 +116,58 @@ namespace Perspex.Cairo.Media
/// <param name="geometry">The geometry.</param> /// <param name="geometry">The geometry.</param>
public void DrawGeometry(Perspex.Media.Brush brush, Perspex.Media.Pen pen, Perspex.Media.Geometry geometry) public void DrawGeometry(Perspex.Media.Brush brush, Perspex.Media.Pen pen, Perspex.Media.Geometry geometry)
{ {
// TODO: Implement var impl = geometry.PlatformImpl as StreamGeometryImpl;
var clone = new Queue<GeometryOp>(impl.Operations);
bool useFill = false;
this.SetPen(pen);
this.SetBrush(brush);
using (var pop = this.PushTransform(impl.Transform))
{
while (clone.Count > 0)
{
var current = clone.Dequeue();
if (current is BeginOp)
{
var bo = current as BeginOp;
this.context.MoveTo(bo.Point.ToCairo());
useFill = bo.IsFilled;
System.Diagnostics.Debug.WriteLine("Start");
}
else if (current is LineToOp)
{
var lto = current as LineToOp;
this.context.LineTo(lto.Point.ToCairo());
}
else if (current is EndOp)
{
if (((EndOp)current).IsClosed)
this.context.ClosePath();
System.Diagnostics.Debug.WriteLine("End");
}
else if (current is CurveToOp)
{
var cto = current as CurveToOp;
this.context.CurveTo(cto.Point.ToCairo(), cto.Point2.ToCairo(), cto.Point3.ToCairo());
}
}
if (useFill)
{
this.context.FillPreserve();
}
else
{
this.context.StrokePreserve();
}
}
} }
/// <summary> /// <summary>
@ -139,6 +192,7 @@ namespace Perspex.Cairo.Media
{ {
var layout = ((FormattedTextImpl)text.PlatformImpl).Layout; var layout = ((FormattedTextImpl)text.PlatformImpl).Layout;
this.SetBrush(foreground); this.SetBrush(foreground);
this.context.MoveTo(origin.X, origin.Y); this.context.MoveTo(origin.X, origin.Y);
Pango.CairoHelper.ShowLayout(this.context, layout); Pango.CairoHelper.ShowLayout(this.context, layout);
} }

74
Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs

@ -8,37 +8,97 @@ namespace Perspex.Cairo.Media
{ {
using Perspex.Media; using Perspex.Media;
using Perspex.Platform; using Perspex.Platform;
using System.Collections.Generic;
using Cairo = global::Cairo;
public class StreamGeometryContextImpl : IStreamGeometryContextImpl public class StreamGeometryContextImpl : IStreamGeometryContextImpl
{ {
public StreamGeometryContextImpl() private StreamGeometryImpl impl;
public StreamGeometryContextImpl(StreamGeometryImpl imp)
{ {
// TODO: Implement this.impl = imp;
points = new List<Point>();
} }
private List<Point> points;
public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
{ {
// TODO: Implement points.Add(point);
} }
public void BeginFigure(Point startPoint, bool isFilled) public void BeginFigure(Point startPoint, bool isFilled)
{ {
// TODO: Implement this.impl.Operations.Enqueue(new BeginOp { Point = startPoint, IsFilled = isFilled });
points.Add(startPoint);
} }
public void BezierTo(Point point1, Point point2, Point point3) public void BezierTo(Point point1, Point point2, Point point3)
{ {
// TODO: Implement this.impl.Operations.Enqueue(new CurveToOp { Point = point1, Point2 = point2, Point3 = point3 });
points.Add(point1);
points.Add(point2);
points.Add(point3);
} }
public void LineTo(Point point) public void LineTo(Point point)
{ {
// TODO: Implement this.impl.Operations.Enqueue(new LineToOp { Point = point });
points.Add(point);
} }
public void EndFigure(bool isClosed) public void EndFigure(bool isClosed)
{ {
// TODO: Implement this.impl.Operations.Enqueue(new EndOp { IsClosed = isClosed });
double maxX = 0;
double maxY = 0;
foreach (var p in this.points)
{
maxX = System.Math.Max(p.X, maxX);
maxY = System.Math.Max(p.Y, maxY);
}
var context = new Cairo.Context(new Cairo.ImageSurface(Cairo.Format.Argb32, (int)maxX, (int)maxY));
var clone = new Queue<GeometryOp>(this.impl.Operations);
context.LineWidth = 2;
while (clone.Count > 0)
{
var current = clone.Dequeue();
if (current is BeginOp)
{
var bo = current as BeginOp;
context.MoveTo(bo.Point.ToCairo());
}
else if (current is LineToOp)
{
var lto = current as LineToOp;
context.LineTo(lto.Point.ToCairo());
}
else if (current is EndOp)
{
if (((EndOp)current).IsClosed)
context.ClosePath();
}
else if (current is CurveToOp)
{
var cto = current as CurveToOp;
context.CurveTo(cto.Point.ToCairo(), cto.Point2.ToCairo(), cto.Point3.ToCairo());
}
context.StrokePreserve();
context.FillPreserve();
}
var test = context.StrokeExtents();
this.impl.Bounds = new Rect(test.X, test.Y, test.Width, test.Height);
context.Dispose();
} }
public void Dispose() public void Dispose()

76
Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs

@ -9,43 +9,99 @@ namespace Perspex.Cairo.Media
using System; using System;
using Perspex.Media; using Perspex.Media;
using Perspex.Platform; using Perspex.Platform;
using Cairo = global::Cairo;
using Splat; using Splat;
using System.Collections.Generic;
public enum CairoGeometryType
{
Begin,
ArcTo,
LineTo,
End
}
public class BeginOp : GeometryOp
{
public Point Point { get; set; }
public bool IsFilled { get; set; }
}
public class EndOp : GeometryOp
{
public bool IsClosed { get; set; }
}
public class LineToOp : GeometryOp
{
public Point Point { get; set; }
}
public class CurveToOp : GeometryOp
{
public Point Point { get; set; }
public Point Point2 { get; set; }
public Point Point3 { get; set; }
}
public abstract class GeometryOp
{
}
public class StreamGeometryImpl : IStreamGeometryImpl public class StreamGeometryImpl : IStreamGeometryImpl
{ {
public StreamGeometryImpl() public StreamGeometryImpl()
{ {
// TODO: Implement this.Operations = new Queue<GeometryOp>();
}
public StreamGeometryImpl(Queue<GeometryOp> ops)
{
this.Operations = ops;
}
public Queue<GeometryOp> Operations
{
get;
private set;
} }
public Rect Bounds public Rect Bounds
{ {
get { return new Rect(); } get;
set;
} }
// TODO: Implement // TODO: Implement
private Matrix transform = Matrix.Identity;
public Matrix Transform public Matrix Transform
{ {
get { return Matrix.Identity; } get { return this.transform; }
set { } set
{
if (value != this.Transform)
{
if (!value.IsIdentity)
{
this.transform = value;
}
}
}
} }
public IStreamGeometryImpl Clone() public IStreamGeometryImpl Clone()
{ {
// TODO: Implement return new StreamGeometryImpl(this.Operations);
return new StreamGeometryImpl();
} }
public Rect GetRenderBounds(double strokeThickness) public Rect GetRenderBounds(double strokeThickness)
{ {
// TODO: Implement return this.Bounds;
return new Rect();
} }
public IStreamGeometryContextImpl Open() public IStreamGeometryContextImpl Open()
{ {
// TODO: Implement return new StreamGeometryContextImpl(this);
return new StreamGeometryContextImpl();
} }
} }
} }

Loading…
Cancel
Save