From 121dbfb25d3f20285c16b19456f64674677079da Mon Sep 17 00:00:00 2001 From: ncarrillo Date: Mon, 20 Apr 2015 18:53:40 -0400 Subject: [PATCH 1/4] Implemented RenderTargetBitmap support for Cairo Make Render Tests run for Cairo Implemented RenderTargetBitmap support for Cairo Reverted virtual on save --- Cairo/Perspex.Cairo/CairoPlatform.cs | 5 +- Cairo/Perspex.Cairo/Media/DrawingContext.cs | 2 +- .../Perspex.Cairo/Media/Imaging/BitmapImpl.cs | 2 +- .../Media/Imaging/RenderTargetBitmapImpl.cs | 33 ++++++++++++ Cairo/Perspex.Cairo/Perspex.Cairo.csproj | 1 + Cairo/Perspex.Cairo/Renderer.cs | 8 +++ .../Media/Imaging/RenderTargetBitmap.cs | 8 ++- .../Platform/IRenderTargetBitmapImpl.cs | 4 +- TestApplication/Program.cs | 47 ------------------ .../Border/Border_1px_Border.expected.png | Bin 0 -> 609 bytes .../Border/Border_2px_Border.expected.png | Bin 0 -> 611 bytes .../Border_Bottom_Aligns_Content.expected.png | Bin 0 -> 797 bytes .../Border_Brush_Offsets_Content.expected.png | Bin 0 -> 615 bytes ..._Centers_Content_Horizontally.expected.png | Bin 0 -> 830 bytes ...er_Centers_Content_Vertically.expected.png | Bin 0 -> 811 bytes .../Controls/Border/Border_Fill.expected.png | Bin 0 -> 601 bytes .../Border_Left_Aligns_Content.expected.png | Bin 0 -> 838 bytes ...Border_Margin_Offsets_Content.expected.png | Bin 0 -> 640 bytes .../Border/Border_Nested_Rotate.expected.png | Bin 0 -> 1405 bytes ...order_Padding_Offsets_Content.expected.png | Bin 0 -> 640 bytes .../Border_Right_Aligns_Content.expected.png | Bin 0 -> 800 bytes ...tretches_Content_Horizontally.expected.png | Bin 0 -> 793 bytes ..._Stretches_Content_Vertically.expected.png | Bin 0 -> 793 bytes .../Border_Top_Aligns_Content.expected.png | Bin 0 -> 801 bytes .../Image/Image_Stretch_Fill.expected.png | Bin 0 -> 7705 bytes .../Image/Image_Stretch_None.expected.png | Bin 0 -> 3320 bytes .../Image/Image_Stretch_Uniform.expected.png | Bin 0 -> 6939 bytes .../Image_Stretch_UniformToFill.expected.png | Bin 0 -> 7542 bytes TestFiles/Cairo/Controls/Image/test.png | Bin 0 -> 17223 bytes .../Ellipse/Circle_1px_Stroke.expected.png | Bin 0 -> 3323 bytes .../Path_100px_Triangle_Centered.expected.png | Bin 0 -> 1213 bytes .../Path_Expander_With_Border.expected.png | Bin 0 -> 1311 bytes .../Shapes/Path/Path_Tick_Scaled.expected.png | Bin 0 -> 6192 bytes .../Rectangle_1px_Stroke.expected.png | Bin 0 -> 628 bytes .../Rectangle_2px_Stroke.expected.png | Bin 0 -> 619 bytes .../Rectangle_Stroke_Fill.expected.png | Bin 0 -> 620 bytes .../Media/Imaging/RenderTargetBitmapImpl.cs | 7 ++- 37 files changed, 62 insertions(+), 55 deletions(-) create mode 100644 Cairo/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs create mode 100644 TestFiles/Cairo/Controls/Border/Border_1px_Border.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_2px_Border.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Bottom_Aligns_Content.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Brush_Offsets_Content.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Centers_Content_Horizontally.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Centers_Content_Vertically.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Fill.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Left_Aligns_Content.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Margin_Offsets_Content.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Nested_Rotate.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Padding_Offsets_Content.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Right_Aligns_Content.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Stretches_Content_Horizontally.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Stretches_Content_Vertically.expected.png create mode 100644 TestFiles/Cairo/Controls/Border/Border_Top_Aligns_Content.expected.png create mode 100644 TestFiles/Cairo/Controls/Image/Image_Stretch_Fill.expected.png create mode 100644 TestFiles/Cairo/Controls/Image/Image_Stretch_None.expected.png create mode 100644 TestFiles/Cairo/Controls/Image/Image_Stretch_Uniform.expected.png create mode 100644 TestFiles/Cairo/Controls/Image/Image_Stretch_UniformToFill.expected.png create mode 100644 TestFiles/Cairo/Controls/Image/test.png create mode 100644 TestFiles/Cairo/Shapes/Ellipse/Circle_1px_Stroke.expected.png create mode 100644 TestFiles/Cairo/Shapes/Path/Path_100px_Triangle_Centered.expected.png create mode 100644 TestFiles/Cairo/Shapes/Path/Path_Expander_With_Border.expected.png create mode 100644 TestFiles/Cairo/Shapes/Path/Path_Tick_Scaled.expected.png create mode 100644 TestFiles/Cairo/Shapes/Rectangle/Rectangle_1px_Stroke.expected.png create mode 100644 TestFiles/Cairo/Shapes/Rectangle/Rectangle_2px_Stroke.expected.png create mode 100644 TestFiles/Cairo/Shapes/Rectangle/Rectangle_Stroke_Fill.expected.png diff --git a/Cairo/Perspex.Cairo/CairoPlatform.cs b/Cairo/Perspex.Cairo/CairoPlatform.cs index 902a621cf4..f1841fe31a 100644 --- a/Cairo/Perspex.Cairo/CairoPlatform.cs +++ b/Cairo/Perspex.Cairo/CairoPlatform.cs @@ -27,8 +27,7 @@ namespace Perspex.Cairo public IBitmapImpl CreateBitmap(int width, int height) { - throw new NotImplementedException(); - ////return new BitmapImpl(imagingFactory, width, height); + return new BitmapImpl(new ImageSurface(Format.Argb32, width, height)); } public IFormattedTextImpl CreateFormattedText( @@ -49,7 +48,7 @@ namespace Perspex.Cairo public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height) { - throw new NotImplementedException(); + return new RenderTargetBitmapImpl(new ImageSurface(Format.Argb32, width, height)); } public IStreamGeometryImpl CreateStreamGeometry() diff --git a/Cairo/Perspex.Cairo/Media/DrawingContext.cs b/Cairo/Perspex.Cairo/Media/DrawingContext.cs index 5b79613e21..1d6d2a146a 100644 --- a/Cairo/Perspex.Cairo/Media/DrawingContext.cs +++ b/Cairo/Perspex.Cairo/Media/DrawingContext.cs @@ -70,7 +70,7 @@ namespace Perspex.Cairo.Media { this.context.Dispose(); - if (this.surface != null) + if (this.surface is Cairo.Win32Surface) { this.surface.Dispose(); } diff --git a/Cairo/Perspex.Cairo/Media/Imaging/BitmapImpl.cs b/Cairo/Perspex.Cairo/Media/Imaging/BitmapImpl.cs index 457e7fc179..34961e7795 100644 --- a/Cairo/Perspex.Cairo/Media/Imaging/BitmapImpl.cs +++ b/Cairo/Perspex.Cairo/Media/Imaging/BitmapImpl.cs @@ -35,7 +35,7 @@ namespace Perspex.Cairo.Media.Imaging public void Save(string fileName) { - throw new NotImplementedException(); + this.Surface.WriteToPng(fileName); } } } diff --git a/Cairo/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs b/Cairo/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs new file mode 100644 index 0000000000..c0ccc372ab --- /dev/null +++ b/Cairo/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs @@ -0,0 +1,33 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Cairo.Media.Imaging +{ + using System; + using Perspex.Platform; + using Cairo = global::Cairo; + + public class RenderTargetBitmapImpl : BitmapImpl, IRenderTargetBitmapImpl + { + + public RenderTargetBitmapImpl( + Cairo.ImageSurface surface) + : base(surface) + { + } + + public void Dispose() + { + this.Surface.Dispose(); + } + + public void Render(IVisual visual) + { + Renderer renderer = new Renderer(this.Surface); + renderer.Render(visual, new PlatformHandle(IntPtr.Zero, "RTB")); + } + } +} \ No newline at end of file diff --git a/Cairo/Perspex.Cairo/Perspex.Cairo.csproj b/Cairo/Perspex.Cairo/Perspex.Cairo.csproj index 9a6ae92dee..eaad49e49d 100644 --- a/Cairo/Perspex.Cairo/Perspex.Cairo.csproj +++ b/Cairo/Perspex.Cairo/Perspex.Cairo.csproj @@ -70,6 +70,7 @@ + diff --git a/Cairo/Perspex.Cairo/Renderer.cs b/Cairo/Perspex.Cairo/Renderer.cs index dfce3c8c11..ad4b7aeee6 100644 --- a/Cairo/Perspex.Cairo/Renderer.cs +++ b/Cairo/Perspex.Cairo/Renderer.cs @@ -30,6 +30,12 @@ namespace Perspex.Cairo { } + private ImageSurface surface; + public Renderer(ImageSurface surface) + { + this.surface = surface; + } + /// /// Resizes the renderer. /// @@ -51,6 +57,8 @@ namespace Perspex.Cairo { case "HWND": return new DrawingContext(new Win32Surface(GetDC(handle.Handle))); + case "RTB": + return new DrawingContext(this.surface); case "HDC": return new DrawingContext(new Win32Surface(handle.Handle)); case "GdkWindow": diff --git a/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs b/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs index 3f436941da..15d8252b3b 100644 --- a/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs +++ b/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs @@ -8,8 +8,9 @@ namespace Perspex.Media.Imaging { using Perspex.Platform; using Splat; + using System; - public class RenderTargetBitmap : Bitmap + public class RenderTargetBitmap : Bitmap, IDisposable { public RenderTargetBitmap(int width, int height) : base(CreateImpl(width, height)) @@ -31,5 +32,10 @@ namespace Perspex.Media.Imaging IPlatformRenderInterface factory = Locator.Current.GetService(); return factory.CreateRenderTargetBitmap(width, height); } + + public void Dispose() + { + this.PlatformImpl.Dispose(); + } } } diff --git a/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs b/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs index dc20a78304..c61bd549af 100644 --- a/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs +++ b/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs @@ -4,9 +4,11 @@ // // ----------------------------------------------------------------------- +using System; + namespace Perspex.Platform { - public interface IRenderTargetBitmapImpl : IBitmapImpl + public interface IRenderTargetBitmapImpl : IBitmapImpl, IDisposable { void Render(IVisual visual); } diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index 7300b48556..648129f9aa 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -15,26 +15,9 @@ using Perspex.Threading; #if PERSPEX_GTK using Perspex.Gtk; #endif -using ReactiveUI; -using Splat; namespace TestApplication { - class TestLogger : ILogger - { - public LogLevel Level - { - get; - set; - } - - public void Write(string message, LogLevel logLevel) - { - if ((int)logLevel < (int)Level) return; - System.Diagnostics.Debug.WriteLine(message); - } - } - class Item { public string Name { get; set; } @@ -188,8 +171,6 @@ namespace TestApplication private static TabItem ButtonsTab() { Button defaultButton; - - var showDialog = ReactiveCommand.Create(); Button showDialogButton; var result = new TabItem @@ -204,11 +185,6 @@ namespace TestApplication MinWidth = 120, Children = new Controls { - (showDialogButton = new Button - { - Content = "Button", - Command = showDialog, - }), new Button { Content = "Button", @@ -261,29 +237,6 @@ namespace TestApplication defaultButton.Content = ((string)defaultButton.Content == "Default") ? "Clicked" : "Default"; }; - showDialog.Subscribe(async _ => - { - var close = ReactiveCommand.Create(); - - var dialog = new Window - { - Content = new StackPanel - { - Width = 200, - Height = 200, - Children = new Controls - { - new Button { Content = "Yes", Command = close, CommandParameter = "Yes" }, - new Button { Content = "No", Command = close, CommandParameter = "No" }, - } - } - }; - - close.Subscribe(x => dialog.Close(x)); - - showDialogButton.Content = await dialog.ShowDialog(); - }); - return result; } diff --git a/TestFiles/Cairo/Controls/Border/Border_1px_Border.expected.png b/TestFiles/Cairo/Controls/Border/Border_1px_Border.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..24239d5799ab3308d44bf2ab283758dc0202c9b3 GIT binary patch literal 609 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggiQCh~F{C2y?d6Sv%?<)A2iyM?yPcbPh2!_C+c#Ot_<%YX7!CwopH zT&&Nl(zxO3{rvlz4{$d+2yn2B5<@o(TC%sVM%xNb!1@J z*w6hZk(GggiPzJ`F{C2y?bVIE4Gugk2iyNuvng7}DIQ8!+sU@)6BAGi1H+9ghSBRH zZv>hZoMV!=l|Le$Xukg4E%rtQ0S=~7Vu*%8!I^2VM%xNb!1@J z*w6hZk(Ggg>A0thV@O5Z+nWb{?>I;_TvRQ6A`-;*vRN$1ON-OAz)j{wqs(QtnVmT) zieC<@DIBQs|7Ey_KjvBV`4j9w;}{qk=2}Irdz!cNkX$PB{At=B`kx6O32xb2d2QD> zmPQ2u4yI9JkcC0PrkK-r|MK7HJbUOon~kFa2TPNKf{f^i>xRXLx1BpGabxr1`3l>U zpEcH=`}v2V?2H)qp>7tV?NPVaUcWjc^ltO_ymdF1-`USTGkwC&qfuw?*Z2Q4ORM$& zlzryqjOFiYXUZRtzNzyk=fVDS3dIxS`+pjyncDxhdzR*Nx4Hkp)pH8-r@u~qCAUZ2 zJ%6L#@tp1MpM5^wFw6QE`~89L-dkd?7j8DRKYr%FQMzriPbt4$)0*^;-?{H^x2xV1 y`Qv88cLf0!riVA9b#7=z>wwZ914F{=f*;J+jZAx%e2_c<67Y2Ob6Mw<&;$Sx0qU9n literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Controls/Border/Border_Brush_Offsets_Content.expected.png b/TestFiles/Cairo/Controls/Border/Border_Brush_Offsets_Content.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..d1c13a9e57f842dc1c881f387fe80db1d00510c0 GIT binary patch literal 615 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggNzl{9F{C2y?Nvj*!v;JojyM1R-+XC9L84C6lv6&%@(-H0ftnZ?9t2#^ zxw*MuQO<*TtZ_Ae9rpbP0l+XkKY#Dbw literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Controls/Border/Border_Centers_Content_Horizontally.expected.png b/TestFiles/Cairo/Controls/Border/Border_Centers_Content_Horizontally.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..18ecd01c7a707b53da0ef2d890604cd900c6658c GIT binary patch literal 830 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(Ggg>4m3@V@O5Z+ZzXaFFPhBWn?|xYI zX7kH^+nOB&I9M7T1Wt(7N+nl4uoZe}; z`Fx`8^TVZO6SSqxzu(vXoY*rzxkmDF#;-S@CH5a%Q5@6mkay*Gs@>9ag|)M{Dcy=V zF!_JdT3ffd*5+y7EZ01(*>V18-HVC6tTBIQe}66UIsDnjU)I^rj~V`!xo+ZH-!rH9 z&qUq(sYjRQzbZ70>8~}rd;OlH0tZWz!zeL0!{E?oqv_LA+p4GV-TVM%xNb!1@J z*w6hZk(Ggg>8huTV@O5Z+nbJlB90Ob7bVX>^s;5Ub6C4V#D7tGfp0_wdrVdD##1Ge z`xNDSJQ}|3eX=~E>fo|{FJFCO1e(Xdkg&Y(bd=v|uIeegdm_Ug=%2Oj*v(P>c|q-4 zJ|;&60hZxFJlwJ7X~}QqvZT!)H#3$Ca4VM%xNb!1@J z*w6hZk(GggiP_V|F{C2y?d5}<4F(J>2Q&WLuJ)K$$lYNq6T@l^)Bpr#rDy(^>}|HS vWlUjyUX$RcAi%;jN(}Wd07osue&b`j+h#Kt7)_eY2omvh^>bP0l+XkKIR;Xb literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Controls/Border/Border_Left_Aligns_Content.expected.png b/TestFiles/Cairo/Controls/Border/Border_Left_Aligns_Content.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..73be4dcdc681499910fec417ba65e4cab9a23a79 GIT binary patch literal 838 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(Ggg>4T?>V@O5Z+goRIuLMXq1h(_~9%!1sD5EiG1WydCUVFOs`fkJBR_x0Y?gsWw|D3+REc|uP+iO2>zpa=z-}wIScXyVj{xl1-SoSq; zkHwx_YxgzV$bPOnv)XX?&wHm0<&VddzB|0hCgy%a^}F@8?3G*Aw%f!_dw*N;&*y9G z$0{PXM-HoenOFHy3a!?$b1XPN(4=HVouv@7v=ocoy+^fnu7)8rBPyVhJnTHYeoCk7IbZ5^cMi9 eQ-&Y!bx!-6X>_?Q<`GQ>33VM%xNb!1@J z*w6hZk(GggNz2p4F{C2y?R7`4LkOBO=WnG(qD2zKPHVGB?Rkap}xW zbKStxFP8mkyg24rnF!4Px%Te;$2=A|Fr+yr+%f!4pg+bnI=VgZX+_1b?~l1x$0|S3 ztwJI(*YoJkhC7w!@jQH9guS_kE|Oby*tE3=6;gv43HbA6wbY1&3OD)OWLJ$g{$YYX ziC-k_`t2MzHyg3TvcupsA)Alqfb#)LZ9ExtR%zcj6AR7}VYXp_P;=cgZBhBxIjeoT zCFX7#n~9f4*pC+gBH4)TA7TNKha_Xm0C59#>u!79WOkKy5)%&ypRlaH7o4d}v3IA= zgw|H6JF6a8{uJc?`fh;tD{Y6D)+nT&MacbiM?u)8w9PI)1VRe3%jJOHwk&MQt?2+8 zj`UZr1bSJmwjgf~!2XW(i_UfeY>q{fw-AK6k$wwNAn`Om4zb3#%){e#f4P1N1_RvQr!5XfZMqYtE(``(tG3k!1MK|B;s_!}PDK@+ z39Fg1SudU&WfL-avzj}TP9K;EXx z!MvM{_*0RTAx2Qo#u*@+<*Da)V_s%4zP(&b%APa+lcg3$q2e@8Bn;t|dg^P8Qldk7 zH>A~_QCd?{*>#NZb3{R3JSFD|=kwfQt%Ms=vV-YDp0Ov=YbGbzNPNKR+j9ajkXFZg6%h*nw+d;MCCl(ll^BW(u!9v*7a7ELm%u9E4V>YoIC;M?IBZqWCnl zY*VtnDiH|f-dTk~#+oFytV#@m$vbOnF9;f`epg30&yccz!e5K`M6{vpg z`=Pue#!B>kt+EyEr<}Jtk67@x^>TLSDKTC#GW@%N)3qK zl3Fc~0^);=P`(-vBPKw6PC3yI-hy*5A-fsIlhrs3GQxTCP;hV)1_yD3)=1q_P9t$; zAg`|Vag1+{<#N*&+)Eg-631jKp^~~o&ysQ$zTauhu$d>qvg;0xDNL|zd&`7-?`2^L zKTE8{zo>gsJxq@Zo9>(jN($2U(Zwy>n^WrUs2h4ZQ`IXMd?bhpxWW6KgbnJojco3}3-SSN+PwtG0Hu_sU?xbQHy<)GV&ASkNXq6#;Cp*GMls1E uVM%xNb!1@J z*w6hZk(GggNz2p4F{C2y?R7`4LkOBO=WnG(qD2zVM%xNb!1@J z*w6hZk(Ggg>6E97V@O5Z+glfNF9%38T%6)4ki>T{QB*8}eMXC|gUtr!B;iAQr}AoM z**QgV3!R%-cUNWGrzif`^L8-f33q>l)G(o7Nn#{g=XS`84Lnk?nWi zz23nvUpHU=&4Z+E%?Ea}FgYp+upByCVVY)Vu;z2#nQJVETz?v*{kxiRZuZZE$3XHi zd-{|4^7r2BkG#6^_@;LmAFiLd?-=)Qk63>CoxHdEb=E((io0`8^Z2t}KAV~g0{P}U z#`XNPdG>Y2^W?Dn<26#j$Nf|V)?K=sy4PRU`nYGbU{2=VqqDZVKTi5%csy_Mv)@)` z*Hh)*T-?WTu2g4&<$jysJC@IHY-~P%sb<6fxnI5gEXBVM%xNb!1@J z*w6hZk(Ggg>9D7ZV@O5Z+nbJlB90Ob7aNOr1obWa{(wuab@B_z2x;*RvC}9+TL=sqynuE}4(V^99xmeoOiM zpt||MeIX8(Mh6Sc3EhUphqs-(Znz;`eZOPg@iWZ7=bWx&E;}Q}eP}X^(e|j@Yp-uN zTpiVXJLi}RqT(|NPNC=>vtt{+=*ug&$In|$zvq{ z>3#CLV{4x6J)fL+?26PL*7Id-mD^+bSDIG%`rS*4?Z27V|7_-?8)jMm;mdKI;Vst0BgwS(EtDd literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Controls/Border/Border_Stretches_Content_Vertically.expected.png b/TestFiles/Cairo/Controls/Border/Border_Stretches_Content_Vertically.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..e255633894cf752016d95467835891c05972557a GIT binary patch literal 793 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(Ggg>9D7ZV@O5Z+nbJlB90Ob7aNOr1obWa{(wuab@B_z2x;*RvC}9+TL=sqynuE}4(V^99xmeoOiM zpt||MeIX8(Mh6Sc3EhUphqs-(Znz;`eZOPg@iWZ7=bWx&E;}Q}eP}X^(e|j@Yp-uN zTpiVXJLi}RqT(|NPNC=>vtt{+=*ug&$In|$zvq{ z>3#CLV{4x6J)fL+?26PL*7Id-mD^+bSDIG%`rS*4?Z27V|7_-?8)jMm;mdKI;Vst0BgwS(EtDd literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Controls/Border/Border_Top_Aligns_Content.expected.png b/TestFiles/Cairo/Controls/Border/Border_Top_Aligns_Content.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..1c48ec82c6db22a4c459a5c16d17f35325487b8f GIT binary patch literal 801 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(Ggg>9nVdV@O5Z+nbJlB90Ob7Y`Qi5b9s}{Q;L;>*NEHG1B7q9H+-Iul6v1 zIpZX|vcQ5`{hyaF?499T9~?T98E75@!vVj!y4Q;~$0YV|YAio3YVqixc1LQ9?ae(u z!UTSVGc_s*aHz9>Dm-&%!`fn7wr_8qh(38fqcUNBv0?s!zMDyo6_XsEg=O#l`pYaW z^!$UZv){j|eOJdmGkwC&qfuw~*Z2RlN&7qZ$@LkZ4Zqv|HpoA~4K(@YfyL((KCAw> zdscKN>)vmpXUAt$vE?7!JlFA_{`KTnl6%zD^EdA6yP4PjZ04gIW?BE@&p%MLy)E`S zfBvzU-kI}_(ruG{zVh5_T9aP*yY+qae2{Z*Hr#hq;9!x|WE@OA(I literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Controls/Image/Image_Stretch_Fill.expected.png b/TestFiles/Cairo/Controls/Image/Image_Stretch_Fill.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..2980a94b70dc5bd933e4c659586d093cee9bfc76 GIT binary patch literal 7705 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 EZxLVt5C8xG literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Controls/Image/Image_Stretch_Uniform.expected.png b/TestFiles/Cairo/Controls/Image/Image_Stretch_Uniform.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..588c6515c5a22b67f55511cafbcd6412ff826e7f GIT binary patch literal 6939 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 literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Controls/Image/Image_Stretch_UniformToFill.expected.png b/TestFiles/Cairo/Controls/Image/Image_Stretch_UniformToFill.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..98d421f98cb971998bf8fac7c8e6d842b4e45a8a GIT binary patch literal 7542 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 C)09^L literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Controls/Image/test.png b/TestFiles/Cairo/Controls/Image/test.png new file mode 100644 index 0000000000000000000000000000000000000000..ed4f82f847472e8d6f681a05a3a6a2deb401e23f GIT binary patch literal 17223 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 FV1fjw84dsd literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Shapes/Path/Path_100px_Triangle_Centered.expected.png b/TestFiles/Cairo/Shapes/Path/Path_100px_Triangle_Centered.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..dab965f9885e0922ffae590303905b56125a1bb1 GIT binary patch literal 1213 zcmajei%(N`6bJBPSz}m%vPjnQC=Jw26nROUFq+*0KWVKiSn8$)6h{$(jclzw&f=pvSfqU`*#KfosKxu-ej^S$?% z+>_bTOn<)+KN^kZFBWCUpxW?vJp+EP?=!bU@lne%(`e>D!k$3mTP*xkNTYQ(yt{hn z9o&jDg!0M*^OJ(|(9hX*cTaZ6zMr5XOY-`X@+{7Ed6g0O<#%2P`{gAvey+%1Oya8} zYbfO&=jznOwko?%tSDfTb>jU%A^`BWeu&^>)~}P>|B`Hf_-NU-y*icqu)90#7wf-| zE9JhozG44%#oG6Ad)Cm%?R}>Ulix(>^tYo569x~hR#j9iEqQP13AQB2yS!qpw_GeQ zmn+j(^?M%-J*%5}wPrTgJ-B}>yyp1A;pN9KN%oC1&!&%mr(ha8yIJ)Mn(8+m%Q0)~ z$jHp%qc4_cU%#qc>(x7pcol-Hnc0o=@zgHqc$CTZEn6h`&=VwAhBA${YVZ2ZJ^l>Y z&?M;_eAQ0)os%_mM0zYTeC00&*vw zVyY$p;V_yqCjc3?6Yp)o$O=b9B0%_Ybg@YZh`Wea5{!{*CciNRkfsK$F$W{h<0;=# zjBpuEJI4VL+lkNarNNG|nCJPb6Gr|_q=J8z16#terJTdhbCjvPv=uLi)B6ON{dVH;y>wu@ig^q3n3+hRIE$F^ux+Up%*-;CodRHNDn{aTEIwQg zy{*6wOwVcU?p_ZtZFb_oU3@pA#k?D3nE5+_+NQwU8m4>TGCZU*g{~2vf~CX@+JUZN zyfjEikMzOpy3Na2+|Y8*yLc zvAjFd(bI}#mbdbPe#&!`HX^ed`BTNMCeH4SRo=eLGR2(1}^ljT%>?>r6UI!Al*HdgA}pQ zJ0-{v2E9vy6kB!V21hzFgzCtav2>(>{0&YL86dyKMIr^{%N;6YfPCke3Mn98?kq(H z$alI*kpl9+Bu)hSW4qHr*7axZrq43~~h94#LY z#||&&F4?vA;V%oM-leb972T}*gzFR@m@?^P+#pA(D;vu6?LImqFuG$= z%d?%mX9l>O$v>mri+yZ~C0)(|&eBQG0iK^SU#EE?FfC-$+2{oR7Hhpi z-QW9>?(aRW`^%iN$KG!bj3%4^pxX27{o@1IoaSaCGFz##%YSqG@et*$M&A^$BI&m( ztW%D1jWWJZduOAQAQJwm3Tu=9j8&%fxR);(sRBfp87;m-7HKIBWRi5G#QsiMVf>HDUpJ10i3`Ptn zTF=*{$S;F_4~ib+Yd{tKu_$_qp9`w!&qbn}oksJFy?Y;CPkT2a(ZfzA*%YP3F1K^!12hh0h3 zKH{nac$bg;im3gK`=C?rx z9=Cm0{_N3{FSenxp<-rW5hu35UH130hWe`MgLqZyW(Mfkp>yUQo%SWbrqty+9i=*F zuF+}V2yAt2(dpc&Gi9$%j)6DK5waarv!yK+^)C?0lBqbM%tnQU1CT&lBI?LvED(zT zvFr)Y0+DWmta6!&5TF17J_}#k52?06s(H+0f=v-1>RsU?1@iYm{<+LFijUX2f_TIw znMie;*42bZoKhm87HC}}9&t#Cr22-|brO%*q!>b-q-6$ik4uUn)h$|P6YgHz8UrHKNPrr>2rEr^tHlG|@-ajtPJp_79ll`+Tw@c~Qtgwpd!|6P zIrdeOV|wLi9`na@OnxYx5;F46fw*}!qGRj*1jnRJ0q4bK5fI-k z0%s`)PWUh=p|JD{4!cXs(euoqyBVXy8A$_44_c2DJb4i<`gUIYe=#T8liIJmC>(}Q O&fs0*<1Xa9v;TjC((*R| literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Shapes/Path/Path_Tick_Scaled.expected.png b/TestFiles/Cairo/Shapes/Path/Path_Tick_Scaled.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..cb4466a21f9200f05c912322df2e749d27c501e1 GIT binary patch literal 6192 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 fgu&7MV1CYRX|MHcxlLgVM%xNb!1@J z*w6hZk(GggNz~KDF{C2y?Nvjr!wv#02PgmkpDuZL*>$E=yH%5Z9x&St)Wg8=BmMfD zbGF>-x63}vWR3e#D-hojY{`Z6 W#q7DC*bgd#1Uy~+T-G@yGywo`EMoxx literal 0 HcmV?d00001 diff --git a/TestFiles/Cairo/Shapes/Rectangle/Rectangle_Stroke_Fill.expected.png b/TestFiles/Cairo/Shapes/Rectangle/Rectangle_Stroke_Fill.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..2eb5c946cee0c765bd2948e8172a1f4c3062a8a4 GIT binary patch literal 620 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF%}28J29*~C-V}>VM%xNb!1@J z*w6hZk(GggNzBv5F{C2y?Nvj*!v;Joj+X!bZ@#?2BT=`hL@;gEZwB!gpe6=}Kby15 zp3iHYoNHZimWhAgFNJ#?>c1@N Date: Tue, 21 Apr 2015 18:12:44 -0400 Subject: [PATCH 2/4] Initial geometry testing --- Cairo/Perspex.Cairo/Media/DrawingContext.cs | 53 ++++++++++++++ .../Media/StreamGeometryContextImpl.cs | 73 +++++++++++++++++-- .../Perspex.Cairo/Media/StreamGeometryImpl.cs | 73 +++++++++++++++++-- Perspex.Controls/Shapes/Shape.cs | 2 + .../Media/StreamGeometryContextImpl.cs | 1 + 5 files changed, 190 insertions(+), 12 deletions(-) diff --git a/Cairo/Perspex.Cairo/Media/DrawingContext.cs b/Cairo/Perspex.Cairo/Media/DrawingContext.cs index 1d6d2a146a..8349da6bde 100644 --- a/Cairo/Perspex.Cairo/Media/DrawingContext.cs +++ b/Cairo/Perspex.Cairo/Media/DrawingContext.cs @@ -13,6 +13,8 @@ namespace Perspex.Cairo.Media using Splat; using Cairo = global::Cairo; using IBitmap = Perspex.Media.Imaging.IBitmap; + using System.Collections.Generic; + /// /// Draws using Direct2D1. @@ -115,6 +117,57 @@ namespace Perspex.Cairo.Media public void DrawGeometry(Perspex.Media.Brush brush, Perspex.Media.Pen pen, Perspex.Media.Geometry geometry) { // TODO: Implement + System.Diagnostics.Debug.WriteLine("Geometry {0}", geometry.GetType()); + var impl = geometry.PlatformImpl as StreamGeometryImpl; + var clone = new Queue(impl.Operations); + bool useFill = false; + + //this.context.Save(); + var pop = this.PushTransform(impl.Transform); + + while (clone.Count > 0) + { + // this.SetBrush(brush); + this.SetPen(new Pen(brush, 0.5)); + + var current = clone.Dequeue(); + + if (current is BeginOp) + { + var bo = current as BeginOp; + this.context.MoveTo(bo.Point.ToCairo()); + + useFill = bo.IsFilled; + } + 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(); + } + 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.StrokePreserve(); + this.context.Fill(); + } + else + { + this.context.Stroke(); + } + + pop.Dispose(); } /// diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs index e49c7ab450..3b04123481 100644 --- a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs @@ -8,37 +8,100 @@ namespace Perspex.Cairo.Media { using Perspex.Media; using Perspex.Platform; + using System.Collections.Generic; + using Cairo = global::Cairo; public class StreamGeometryContextImpl : IStreamGeometryContextImpl { - public StreamGeometryContextImpl() + private Queue ops; + private StreamGeometryImpl impl; + public StreamGeometryContextImpl(Queue ops, StreamGeometryImpl imp) { - // TODO: Implement + this.ops = ops; + this.impl = imp; + points = new List(); } + private List points; + public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) { // TODO: Implement + int i = 10; + points.Add(point); } public void BeginFigure(Point startPoint, bool isFilled) { - // TODO: Implement + System.Diagnostics.Debug.WriteLine("IS filled {0}", isFilled); + ops.Enqueue(new BeginOp { Point = startPoint, IsFilled = isFilled }); + points.Add(startPoint); } public void BezierTo(Point point1, Point point2, Point point3) { // TODO: Implement + ops.Enqueue(new CurveToOp { Point = point1, Point2 = point2, Point3 = point3 }); + points.Add(point1); + points.Add(point2); + points.Add(point3); } public void LineTo(Point point) { - // TODO: Implement + ops.Enqueue(new LineToOp { Point = point }); + points.Add(point); } public void EndFigure(bool isClosed) { - // TODO: Implement + this.ops.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(this.ops); + bool useFill = false; + + 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(); + } + + var test = context.StrokeExtents(); + this.impl.Bounds = new Rect(test.X, test.Y, test.Width, test.Height); + + context.Dispose(); } public void Dispose() diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs index 70150a17d9..f949d7382b 100644 --- a/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs @@ -9,43 +9,102 @@ namespace Perspex.Cairo.Media using System; using Perspex.Media; using Perspex.Platform; + using Cairo = global::Cairo; 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 StreamGeometryImpl() { - // TODO: Implement + this.Operations = new Queue(); + } + + public StreamGeometryImpl(Queue ops) + { + this.Operations = ops; + } + + public Queue Operations + { + get; + private set; } public Rect Bounds { - get { return new Rect(); } + get; + set; } // TODO: Implement + private Matrix transform = Matrix.Identity; public Matrix Transform { - get { return Matrix.Identity; } - set { } + get { return transform; } + set + { + if (value != this.Transform) + { + if (!value.IsIdentity) + { + this.transform = value; + } + } + } } public IStreamGeometryImpl Clone() { // TODO: Implement - return new StreamGeometryImpl(); + return new StreamGeometryImpl(this.Operations); } public Rect GetRenderBounds(double strokeThickness) { // TODO: Implement - return new Rect(); + return this.Bounds; } public IStreamGeometryContextImpl Open() { // TODO: Implement - return new StreamGeometryContextImpl(); + return new StreamGeometryContextImpl(this.Operations, this); } } } diff --git a/Perspex.Controls/Shapes/Shape.cs b/Perspex.Controls/Shapes/Shape.cs index 3f296c6b00..530bc0f6a6 100644 --- a/Perspex.Controls/Shapes/Shape.cs +++ b/Perspex.Controls/Shapes/Shape.cs @@ -39,6 +39,8 @@ namespace Perspex.Controls.Shapes Control.AffectsRender(StrokeProperty); Control.AffectsRender(StrokeDashArrayProperty); Control.AffectsMeasure(StrokeThicknessProperty); + + } public abstract Geometry DefiningGeometry diff --git a/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs b/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs index 15fb88d7d0..17b5105ba2 100644 --- a/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs +++ b/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs @@ -37,6 +37,7 @@ namespace Perspex.Direct2D1.Media public void BeginFigure(Point startPoint, bool isFilled) { + System.Diagnostics.Debug.WriteLine("IS FILLED {0}", isFilled); this.sink.BeginFigure(startPoint.ToSharpDX(), isFilled ? FigureBegin.Filled : FigureBegin.Hollow); } From f2e511a0143c4d9f79cdf827fbd400228980bbf9 Mon Sep 17 00:00:00 2001 From: ncarrillo Date: Tue, 21 Apr 2015 19:11:01 -0400 Subject: [PATCH 3/4] More work. --- Cairo/Perspex.Cairo/Media/DrawingContext.cs | 11 +++++------ .../Media/StreamGeometryContextImpl.cs | 19 +++++++++---------- .../Perspex.Cairo/Media/StreamGeometryImpl.cs | 7 ++----- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Cairo/Perspex.Cairo/Media/DrawingContext.cs b/Cairo/Perspex.Cairo/Media/DrawingContext.cs index 8349da6bde..47fc45048b 100644 --- a/Cairo/Perspex.Cairo/Media/DrawingContext.cs +++ b/Cairo/Perspex.Cairo/Media/DrawingContext.cs @@ -116,19 +116,16 @@ namespace Perspex.Cairo.Media /// The geometry. public void DrawGeometry(Perspex.Media.Brush brush, Perspex.Media.Pen pen, Perspex.Media.Geometry geometry) { - // TODO: Implement - System.Diagnostics.Debug.WriteLine("Geometry {0}", geometry.GetType()); var impl = geometry.PlatformImpl as StreamGeometryImpl; var clone = new Queue(impl.Operations); bool useFill = false; - - //this.context.Save(); + var pop = this.PushTransform(impl.Transform); + this.SetPen(pen); + while (clone.Count > 0) { - // this.SetBrush(brush); - this.SetPen(new Pen(brush, 0.5)); var current = clone.Dequeue(); @@ -192,6 +189,7 @@ namespace Perspex.Cairo.Media { var layout = ((FormattedTextImpl)text.PlatformImpl).Layout; this.SetBrush(foreground); + this.context.MoveTo(origin.X, origin.Y); Pango.CairoHelper.ShowLayout(this.context, layout); } @@ -203,6 +201,7 @@ namespace Perspex.Cairo.Media /// The rectangle bounds. public void FillRectange(Perspex.Media.Brush brush, Rect rect) { + this.SetBrush(brush); this.context.Rectangle(rect.ToCairo()); this.context.Fill(); diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs index 3b04123481..1d53ef6ec4 100644 --- a/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs @@ -13,11 +13,9 @@ namespace Perspex.Cairo.Media public class StreamGeometryContextImpl : IStreamGeometryContextImpl { - private Queue ops; private StreamGeometryImpl impl; - public StreamGeometryContextImpl(Queue ops, StreamGeometryImpl imp) + public StreamGeometryContextImpl(StreamGeometryImpl imp) { - this.ops = ops; this.impl = imp; points = new List(); } @@ -34,14 +32,14 @@ namespace Perspex.Cairo.Media public void BeginFigure(Point startPoint, bool isFilled) { System.Diagnostics.Debug.WriteLine("IS filled {0}", isFilled); - ops.Enqueue(new BeginOp { Point = startPoint, IsFilled = isFilled }); + this.impl.Operations.Enqueue(new BeginOp { Point = startPoint, IsFilled = isFilled }); points.Add(startPoint); } public void BezierTo(Point point1, Point point2, Point point3) { // TODO: Implement - ops.Enqueue(new CurveToOp { Point = point1, Point2 = point2, Point3 = point3 }); + this.impl.Operations.Enqueue(new CurveToOp { Point = point1, Point2 = point2, Point3 = point3 }); points.Add(point1); points.Add(point2); points.Add(point3); @@ -49,13 +47,13 @@ namespace Perspex.Cairo.Media public void LineTo(Point point) { - ops.Enqueue(new LineToOp { Point = point }); + this.impl.Operations.Enqueue(new LineToOp { Point = point }); points.Add(point); } public void EndFigure(bool isClosed) { - this.ops.Enqueue(new EndOp { IsClosed = isClosed }); + this.impl.Operations.Enqueue(new EndOp { IsClosed = isClosed }); double maxX = 0; double maxY = 0; @@ -67,9 +65,10 @@ namespace Perspex.Cairo.Media } var context = new Cairo.Context(new Cairo.ImageSurface(Cairo.Format.Argb32, (int)maxX, (int)maxY)); - var clone = new Queue(this.ops); - bool useFill = false; - + var clone = new Queue(this.impl.Operations); + + context.LineWidth = 2; + while (clone.Count > 0) { var current = clone.Dequeue(); diff --git a/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs index f949d7382b..cf423dbc17 100644 --- a/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs +++ b/Cairo/Perspex.Cairo/Media/StreamGeometryImpl.cs @@ -76,7 +76,7 @@ namespace Perspex.Cairo.Media private Matrix transform = Matrix.Identity; public Matrix Transform { - get { return transform; } + get { return this.transform; } set { if (value != this.Transform) @@ -91,20 +91,17 @@ namespace Perspex.Cairo.Media public IStreamGeometryImpl Clone() { - // TODO: Implement return new StreamGeometryImpl(this.Operations); } public Rect GetRenderBounds(double strokeThickness) { - // TODO: Implement return this.Bounds; } public IStreamGeometryContextImpl Open() { - // TODO: Implement - return new StreamGeometryContextImpl(this.Operations, this); + return new StreamGeometryContextImpl(this); } } } From 95d5ce56a4bddf1bdcb032d510447323970d44ca Mon Sep 17 00:00:00 2001 From: Nelson Carrillo Date: Sun, 19 Jul 2015 18:58:33 -0400 Subject: [PATCH 4/4] Began implementing Geometry support for Cairo/Gtk --- Cairo/Perspex.Cairo/CairoExtensions.cs | 2 +- Cairo/Perspex.Cairo/Media/DrawingContext.cs | 5 +--- Cairo/Perspex.Cairo/Renderer.cs | 2 +- Perspex.Controls/Shapes/Shape.cs | 2 -- .../Platform/IRenderTargetBitmapImpl.cs | 4 +-- TestApplication/Program.cs | 29 +++++++++++++++++++ .../Media/StreamGeometryContextImpl.cs | 1 - 7 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Cairo/Perspex.Cairo/CairoExtensions.cs b/Cairo/Perspex.Cairo/CairoExtensions.cs index 364e330c09..e9969ee90e 100644 --- a/Cairo/Perspex.Cairo/CairoExtensions.cs +++ b/Cairo/Perspex.Cairo/CairoExtensions.cs @@ -76,7 +76,7 @@ namespace Perspex.Cairo return Pango.Alignment.Left; } - if (alignment == Perspex.Media.TextAlignment.Center) + if (alignment == Perspex.Media.TextAlignment.Centered) { return Pango.Alignment.Center; } diff --git a/Cairo/Perspex.Cairo/Media/DrawingContext.cs b/Cairo/Perspex.Cairo/Media/DrawingContext.cs index d7a18ace50..ece359923d 100644 --- a/Cairo/Perspex.Cairo/Media/DrawingContext.cs +++ b/Cairo/Perspex.Cairo/Media/DrawingContext.cs @@ -158,8 +158,7 @@ namespace Perspex.Cairo.Media this.context.CurveTo(cto.Point.ToCairo(), cto.Point2.ToCairo(), cto.Point3.ToCairo()); } } - - System.Diagnostics.Debug.WriteLine("Render"); + if (useFill) { this.context.FillPreserve(); @@ -205,7 +204,6 @@ namespace Perspex.Cairo.Media /// The rectangle bounds. public void FillRectange(Perspex.Media.Brush brush, Rect rect) { - this.SetBrush(brush); this.context.Rectangle(rect.ToCairo()); this.context.Fill(); @@ -268,7 +266,6 @@ namespace Perspex.Cairo.Media { this.SetBrush(pen.Brush); this.context.LineWidth = pen.Thickness; - } } } diff --git a/Cairo/Perspex.Cairo/Renderer.cs b/Cairo/Perspex.Cairo/Renderer.cs index 53a307303f..046be3e5b4 100644 --- a/Cairo/Perspex.Cairo/Renderer.cs +++ b/Cairo/Perspex.Cairo/Renderer.cs @@ -31,7 +31,7 @@ namespace Perspex.Cairo public Renderer(IPlatformHandle handle, double width, double height) { } - + public Renderer(ImageSurface surface) { this.surface = surface; diff --git a/Perspex.Controls/Shapes/Shape.cs b/Perspex.Controls/Shapes/Shape.cs index 530bc0f6a6..3f296c6b00 100644 --- a/Perspex.Controls/Shapes/Shape.cs +++ b/Perspex.Controls/Shapes/Shape.cs @@ -39,8 +39,6 @@ namespace Perspex.Controls.Shapes Control.AffectsRender(StrokeProperty); Control.AffectsRender(StrokeDashArrayProperty); Control.AffectsMeasure(StrokeThicknessProperty); - - } public abstract Geometry DefiningGeometry diff --git a/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs b/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs index c61bd549af..7478de1e60 100644 --- a/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs +++ b/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs @@ -4,10 +4,10 @@ // // ----------------------------------------------------------------------- -using System; - namespace Perspex.Platform { + using System; + public interface IRenderTargetBitmapImpl : IBitmapImpl, IDisposable { void Render(IVisual visual); diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index d67164d1e1..9071f51fbc 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -17,6 +17,9 @@ using Perspex.Gtk; #endif using ReactiveUI; using Splat; +using Serilog; +using Serilog.Filters; +using Serilog.Events; namespace TestApplication { @@ -262,6 +265,8 @@ namespace TestApplication private static TabItem ButtonsTab() { Button defaultButton; + + var showDialog = ReactiveCommand.Create(); Button showDialogButton; var result = new TabItem @@ -279,6 +284,7 @@ namespace TestApplication (showDialogButton = new Button { Content = "Button", + Command = showDialog, [ToolTip.TipProperty] = "Hello World!", }), new Button @@ -334,6 +340,29 @@ namespace TestApplication defaultButton.Content = ((string)defaultButton.Content == "Default") ? "Clicked" : "Default"; }; + showDialog.Subscribe(async _ => + { + var close = ReactiveCommand.Create(); + + var dialog = new Window + { + Content = new StackPanel + { + Width = 200, + Height = 200, + Children = new Controls + { + new Button { Content = "Yes", Command = close, CommandParameter = "Yes" }, + new Button { Content = "No", Command = close, CommandParameter = "No" }, + } + } + }; + + close.Subscribe(x => dialog.Close(x)); + + showDialogButton.Content = await dialog.ShowDialog(); + }); + return result; } diff --git a/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs b/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs index 17b5105ba2..15fb88d7d0 100644 --- a/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs +++ b/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs @@ -37,7 +37,6 @@ namespace Perspex.Direct2D1.Media public void BeginFigure(Point startPoint, bool isFilled) { - System.Diagnostics.Debug.WriteLine("IS FILLED {0}", isFilled); this.sink.BeginFigure(startPoint.ToSharpDX(), isFilled ? FigureBegin.Filled : FigureBegin.Hollow); }