From e88627e51c3636cbab18a8c6c9531277e0341d32 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 3 Dec 2014 02:06:58 +0100 Subject: [PATCH] More work on Cairo backend. Most things kinda sorta work... --- Cairo/Perspex.Cairo/CairoExtensions.cs | 5 +++ Cairo/Perspex.Cairo/CairoPlatform.cs | 6 +-- Cairo/Perspex.Cairo/Media/DrawingContext.cs | 30 ++++++++++++--- .../Media/StreamGeometryContextImpl.cs | 38 +++++++++++++++++++ .../Perspex.Cairo/Media/StreamGeometryImpl.cs | 38 +++++++++++++++++++ Cairo/Perspex.Cairo/Media/TextService.cs | 20 ++++++++-- Cairo/Perspex.Cairo/Perspex.Cairo.csproj | 2 + Gtk/Perspex.Gtk/GtkPlatform.cs | 11 +++++- Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs | 9 ++++- Gtk/Perspex.Gtk/WindowImpl.cs | 6 ++- .../Platform/IPlatformThreadingInterface.cs | 4 +- 11 files changed, 150 insertions(+), 19 deletions(-) create mode 100644 Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs create mode 100644 Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs diff --git a/Cairo/Perspex.Cairo/CairoExtensions.cs b/Cairo/Perspex.Cairo/CairoExtensions.cs index 791cc2de7d..51a78ab6e8 100644 --- a/Cairo/Perspex.Cairo/CairoExtensions.cs +++ b/Cairo/Perspex.Cairo/CairoExtensions.cs @@ -15,6 +15,11 @@ namespace Perspex.Cairo return new Cairo.Matrix(m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY); } + public static Cairo.PointD ToCairo(this Point p) + { + return new Cairo.PointD(p.X, p.Y); + } + public static Cairo.Rectangle ToCairo(this Rect rect) { return new Cairo.Rectangle(rect.X, rect.Y, rect.Width, rect.Height); diff --git a/Cairo/Perspex.Cairo/CairoPlatform.cs b/Cairo/Perspex.Cairo/CairoPlatform.cs index b3ddc347ed..d9e04a91f5 100644 --- a/Cairo/Perspex.Cairo/CairoPlatform.cs +++ b/Cairo/Perspex.Cairo/CairoPlatform.cs @@ -29,7 +29,7 @@ namespace Perspex.Cairo public ITextService TextService { - get { /*return textService;*/ throw new NotImplementedException(); } + get { return textService; } } public IBitmapImpl CreateBitmap(int width, int height) @@ -51,13 +51,11 @@ namespace Perspex.Cairo public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height) { throw new NotImplementedException(); - //return new RenderTargetBitmapImpl(imagingFactory, d2d1Factory, width, height); } public IStreamGeometryImpl CreateStreamGeometry() { - throw new NotImplementedException(); - //return new StreamGeometryImpl(); + return new StreamGeometryImpl(); } public IBitmapImpl LoadBitmap(string fileName) diff --git a/Cairo/Perspex.Cairo/Media/DrawingContext.cs b/Cairo/Perspex.Cairo/Media/DrawingContext.cs index 200ec37ae1..b44cb0dbed 100644 --- a/Cairo/Perspex.Cairo/Media/DrawingContext.cs +++ b/Cairo/Perspex.Cairo/Media/DrawingContext.cs @@ -44,6 +44,7 @@ namespace Perspex.Cairo.Media this.surface = surface; this.context = new Cairo.Context(surface); this.textService = Locator.Current.GetService() as TextService; + this.CurrentTransform = Matrix.Identity; } /// @@ -55,12 +56,13 @@ namespace Perspex.Cairo.Media this.Drawable = drawable; this.context = Gdk.CairoHelper.Create(drawable); this.textService = Locator.Current.GetService() as TextService; + this.CurrentTransform = Matrix.Identity; } public Matrix CurrentTransform { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } + get; + private set; } public Gdk.Drawable Drawable @@ -85,9 +87,16 @@ namespace Perspex.Cairo.Media public void DrawImage(IBitmap bitmap, double opacity, Rect sourceRect, Rect destRect) { var impl = bitmap.PlatformImpl as BitmapImpl; - this.context.SetSourceSurface(impl.Surface, 0, 0); + var size = new Size(impl.PixelWidth, impl.PixelHeight); + var scaleX = destRect.Size.Width / sourceRect.Size.Width; + var scaleY = destRect.Size.Height / sourceRect.Size.Height; + + this.context.Save(); + this.context.Scale(scaleX, scaleY); + this.context.SetSourceSurface(impl.Surface, (int)sourceRect.X, (int)sourceRect.Y); this.context.Rectangle(destRect.ToCairo()); this.context.Fill(); + this.context.Restore(); } /// @@ -98,7 +107,11 @@ namespace Perspex.Cairo.Media /// The second point of the line. public void DrawLine(Pen pen, Perspex.Point p1, Perspex.Point p2) { - throw new NotImplementedException(); + this.SetBrush(pen.Brush); + this.context.LineWidth = pen.Thickness; + this.context.MoveTo(p1.ToCairo()); + this.context.LineTo(p2.ToCairo()); + this.context.Stroke(); } /// @@ -109,7 +122,7 @@ namespace Perspex.Cairo.Media /// The geometry. public void DrawGeometry(Perspex.Media.Brush brush, Perspex.Media.Pen pen, Perspex.Media.Geometry geometry) { - throw new NotImplementedException(); + // TODO: Implement } /// @@ -173,8 +186,13 @@ namespace Perspex.Cairo.Media { this.context.Save(); this.context.Transform(matrix.ToCairo()); + this.CurrentTransform *= matrix; - return Disposable.Create(() => this.context.Restore()); + return Disposable.Create(() => + { + this.context.Restore(); + this.CurrentTransform *= matrix.Invert(); + }); } private void SetBrush(Brush brush) diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs new file mode 100644 index 0000000000..99e1d4e46b --- /dev/null +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Cairo.Media +{ + using Perspex.Platform; + + public class StreamGeometryContextImpl : IStreamGeometryContextImpl + { + public StreamGeometryContextImpl() + { + // TODO: Implement + } + + public void BeginFigure(Point startPoint, bool isFilled) + { + // TODO: Implement + } + + public void LineTo(Point point) + { + // TODO: Implement + } + + public void EndFigure(bool isClosed) + { + // TODO: Implement + } + + public void Dispose() + { + // TODO: Implement + } + } +} diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs new file mode 100644 index 0000000000..dec4d03727 --- /dev/null +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Cairo.Media +{ + using System; + using Perspex.Media; + using Perspex.Platform; + using Splat; + + public class StreamGeometryImpl : IStreamGeometryImpl + { + public StreamGeometryImpl() + { + // TODO: Implement + } + + public Rect Bounds + { + get { return new Rect(); } + } + + public Rect GetRenderBounds(double strokeThickness) + { + // TODO: Implement + return new Rect(); + } + + public IStreamGeometryContextImpl Open() + { + // TODO: Implement + return new StreamGeometryContextImpl(); + } + } +} diff --git a/Cairo/Perspex.Cairo/Media/TextService.cs b/Cairo/Perspex.Cairo/Media/TextService.cs index ff6c6a5b0d..3032786190 100644 --- a/Cairo/Perspex.Cairo/Media/TextService.cs +++ b/Cairo/Perspex.Cairo/Media/TextService.cs @@ -46,17 +46,31 @@ namespace Perspex.Cairo.Media public int GetCaretIndex(FormattedText text, Point point, Size constraint) { - throw new NotImplementedException(); + var layout = this.CreateLayout(text); + int result; + int trailing; + layout.XyToIndex((int)point.X, (int)point.Y, out result, out trailing); + return result; } public Point GetCaretPosition(FormattedText text, int caretIndex, Size constraint) { - throw new NotImplementedException(); + var layout = this.CreateLayout(text); + var rect = layout.IndexToPos(caretIndex); + return new Point(rect.X, rect.Y); } public double[] GetLineHeights(FormattedText text, Size constraint) { - throw new NotImplementedException(); + var layout = this.CreateLayout(text); + var lines = layout.Lines; + return lines.Select(x => + { + var inkRect = new Pango.Rectangle(); + var logicalRect = new Pango.Rectangle(); + x.GetExtents(ref inkRect, ref logicalRect); + return (double)logicalRect.Height; + }).ToArray(); } public Size Measure(FormattedText text, Size constraint) diff --git a/Cairo/Perspex.Cairo/Perspex.Cairo.csproj b/Cairo/Perspex.Cairo/Perspex.Cairo.csproj index a385fb600a..3a75223eaa 100644 --- a/Cairo/Perspex.Cairo/Perspex.Cairo.csproj +++ b/Cairo/Perspex.Cairo/Perspex.Cairo.csproj @@ -71,6 +71,8 @@ + + diff --git a/Gtk/Perspex.Gtk/GtkPlatform.cs b/Gtk/Perspex.Gtk/GtkPlatform.cs index 7a7a6c5f41..34023ff732 100644 --- a/Gtk/Perspex.Gtk/GtkPlatform.cs +++ b/Gtk/Perspex.Gtk/GtkPlatform.cs @@ -34,9 +34,16 @@ namespace Perspex.Gtk Gtk.Application.RunIteration(); } - public IDisposable StartTimer (TimeSpan interval, Action internalTick) + public IDisposable StartTimer (TimeSpan interval, Action tick) { - return Disposable.Empty; + var result = true; + var handle = GLib.Timeout.Add((uint)interval.TotalMilliseconds, () => + { + tick(); + return result; + }); + + return Disposable.Create(() => result = false); } public void Wake () diff --git a/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs b/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs index 19c1adb90a..e0a7ccaaec 100644 --- a/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs +++ b/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs @@ -11,6 +11,8 @@ namespace Perspex.Gtk { private static GtkMouseDevice instance; + private Point clientPosition; + static GtkMouseDevice() { instance = new GtkMouseDevice(); @@ -25,9 +27,14 @@ namespace Perspex.Gtk get { return instance; } } + internal void SetClientPosition(Point p) + { + this.clientPosition = p; + } + protected override Point GetClientPosition() { - throw new System.NotImplementedException(); + return this.clientPosition; } } } diff --git a/Gtk/Perspex.Gtk/WindowImpl.cs b/Gtk/Perspex.Gtk/WindowImpl.cs index a171e473da..01598bd482 100644 --- a/Gtk/Perspex.Gtk/WindowImpl.cs +++ b/Gtk/Perspex.Gtk/WindowImpl.cs @@ -129,11 +129,15 @@ namespace Perspex.Gtk protected override bool OnMotionNotifyEvent(Gdk.EventMotion evnt) { + var position = new Point(evnt.X, evnt.Y); + + GtkMouseDevice.Instance.SetClientPosition(position); + var e = new RawMouseEventArgs( GtkMouseDevice.Instance, this.owner, RawMouseEventType.Move, - new Point(evnt.X, evnt.Y)); + position); this.Input(e); return true; } diff --git a/Perspex.Base/Platform/IPlatformThreadingInterface.cs b/Perspex.Base/Platform/IPlatformThreadingInterface.cs index 649612dbda..8b72ee6a8e 100644 --- a/Perspex.Base/Platform/IPlatformThreadingInterface.cs +++ b/Perspex.Base/Platform/IPlatformThreadingInterface.cs @@ -25,9 +25,9 @@ namespace Perspex.Platform /// Starts a timer. /// /// The interval. - /// The action to call on each tick. + /// The action to call on each tick. /// An used to stop the timer. - IDisposable StartTimer(TimeSpan interval, Action internalTick); + IDisposable StartTimer(TimeSpan interval, Action tick); /// /// Sends a message that causes to exit.