Browse Source

Merge pull request #1 from Perspex/master

Merge latest commits.
pull/196/head
danwalmsley 11 years ago
parent
commit
736dc4d083
  1. 11
      .editorconfig
  2. 7
      .gitmodules
  3. 150
      Perspex.sln
  4. 17
      Perspex.sln.DotSettings
  5. BIN
      Perspex.v2.ncrunchsolution
  6. 44
      Tests/Perspex.Controls.UnitTests/DockPanelTests/AlignerTests.cs
  7. 38
      Tests/Perspex.Controls.UnitTests/DockPanelTests/LeftDockerTests.cs
  8. 40
      Tests/Perspex.Controls.UnitTests/DockPanelTests/RectAlignerTests.cs
  9. 38
      Tests/Perspex.Controls.UnitTests/DockPanelTests/RightDockerTests.cs
  10. 16
      appveyor.yml
  11. BIN
      docs/add-dialogs.png
  12. BIN
      docs/add-packages.png
  13. 5
      docs/build.md
  14. 22
      docs/contributing.md
  15. 15
      docs/gettingstarted.md
  16. BIN
      docs/perspex-video.png
  17. BIN
      docs/screen.png
  18. 93
      docs/styles.md
  19. 2
      fileheader.txt
  20. 7
      nuget/.gitignore
  21. 33
      nuget/build-appveyor.ps1
  22. 47
      nuget/build-version.ps1
  23. 39
      nuget/build.bat
  24. 1
      nuget/build.ps1
  25. 14
      nuget/template/Perspex.nuspec
  26. 0
      nuget/template/build/net45/perspex.targets
  27. 16
      readme.md
  28. 20
      samples/TestApplication/App.cs
  29. 123
      samples/TestApplication/GalleryStyle.cs
  30. 8
      samples/TestApplication/Item.cs
  31. 16
      samples/TestApplication/Node.cs
  32. 1087
      samples/TestApplication/Program.cs
  33. 7
      samples/TestApplication/Properties/AssemblyInfo.cs
  34. 42
      samples/TestApplication/TestApplication.csproj
  35. 128
      samples/TestApplication/html.htm
  36. BIN
      samples/TestApplication/pattern.jpg
  37. 2
      samples/XamlTestApplication/App.config
  38. 19
      samples/XamlTestApplication/App.cs
  39. 25
      samples/XamlTestApplication/MainViewModel.cs
  40. 39
      samples/XamlTestApplication/Program.cs
  41. 7
      samples/XamlTestApplication/Properties/AssemblyInfo.cs
  42. 27
      samples/XamlTestApplication/Views/MainWindow.cs
  43. 32
      samples/XamlTestApplication/Views/MainWindow.paml
  44. 96
      samples/XamlTestApplication/XamlTestApplication.csproj
  45. 4
      samples/XamlTestApplication/packages.config
  46. 49
      src/Gtk/Perspex.Cairo/CairoExtensions.cs
  47. 65
      src/Gtk/Perspex.Cairo/CairoPlatform.cs
  48. 17
      src/Gtk/Perspex.Cairo/Media/BrushImpl.cs
  49. 312
      src/Gtk/Perspex.Cairo/Media/DrawingContext.cs
  50. 94
      src/Gtk/Perspex.Cairo/Media/FormattedTextImpl.cs
  51. 14
      src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs
  52. 32
      src/Gtk/Perspex.Cairo/Media/Imaging/BitmapImpl.cs
  53. 38
      src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs
  54. 22
      src/Gtk/Perspex.Cairo/Media/LinearGradientBrushImpl.cs
  55. 25
      src/Gtk/Perspex.Cairo/Media/RadialGradientBrushImpl.cs
  56. 22
      src/Gtk/Perspex.Cairo/Media/SolidColorBrushImpl.cs
  57. 88
      src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs
  58. 101
      src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs
  59. 224
      src/Gtk/Perspex.Cairo/Media/TileBrushes.cs
  60. 14
      src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs
  61. 41
      src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj
  62. 9
      src/Gtk/Perspex.Cairo/Properties/AssemblyInfo.cs
  63. 44
      src/Gtk/Perspex.Cairo/Renderer.cs
  64. 11
      src/Gtk/Perspex.Cairo/app.config
  65. 2
      src/Gtk/Perspex.Cairo/packages.config
  66. 48
      src/Gtk/Perspex.Gtk/AssetLoader.cs
  67. 42
      src/Gtk/Perspex.Gtk/ClipboardImpl.cs
  68. 77
      src/Gtk/Perspex.Gtk/CursorFactory.cs
  69. 7
      src/Gtk/Perspex.Gtk/GtkExtensions.cs
  70. 48
      src/Gtk/Perspex.Gtk/GtkPlatform.cs
  71. 263
      src/Gtk/Perspex.Gtk/Input/GtkKeyboardDevice.cs
  72. 24
      src/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs
  73. 30
      src/Gtk/Perspex.Gtk/Perspex.Gtk.csproj
  74. 20
      src/Gtk/Perspex.Gtk/PopupImpl.cs
  75. 7
      src/Gtk/Perspex.Gtk/Properties/AssemblyInfo.cs
  76. 57
      src/Gtk/Perspex.Gtk/SystemDialogImpl.cs
  77. 153
      src/Gtk/Perspex.Gtk/WindowImpl.cs
  78. 31
      src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs
  79. 37
      src/Markup/Perspex.Markup.Xaml/Context/PerspexParserFactory.cs
  80. 29
      src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeRepository.cs
  81. 134
      src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs
  82. 21
      src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMember.cs
  83. 80
      src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs
  84. 25
      src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs
  85. 37
      src/Markup/Perspex.Markup.Xaml/Converters/BitmapConverter.cs
  86. 33
      src/Markup/Perspex.Markup.Xaml/Converters/BitmapTypeConverter.cs
  87. 89
      src/Markup/Perspex.Markup.Xaml/Converters/BrushConverter.cs
  88. 33
      src/Markup/Perspex.Markup.Xaml/Converters/BrushTypeConverter.cs
  89. 33
      src/Markup/Perspex.Markup.Xaml/Converters/ClassesTypeConverter.cs
  90. 33
      src/Markup/Perspex.Markup.Xaml/Converters/ColorTypeConverter.cs
  91. 33
      src/Markup/Perspex.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs
  92. 48
      src/Markup/Perspex.Markup.Xaml/Converters/GridLengthTypeConverter.cs
  93. 72
      src/Markup/Perspex.Markup.Xaml/Converters/PerspexPropertyTypeConverter.cs
  94. 32
      src/Markup/Perspex.Markup.Xaml/Converters/PointTypeConverter.cs
  95. 32
      src/Markup/Perspex.Markup.Xaml/Converters/RelativePointTypeConverter.cs
  96. 33
      src/Markup/Perspex.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs
  97. 34
      src/Markup/Perspex.Markup.Xaml/Converters/SelectorTypeConverter.cs
  98. 81
      src/Markup/Perspex.Markup.Xaml/Converters/ThicknessConverter.cs
  99. 32
      src/Markup/Perspex.Markup.Xaml/Converters/ThicknessTypeConverter.cs
  100. 98
      src/Markup/Perspex.Markup.Xaml/DataBinding/ChangeTracking/ObservablePropertyBranch.cs

11
.editorconfig

@ -0,0 +1,11 @@
; This file is for unifying the coding style for different editors and IDEs.
; More information at http://EditorConfig.org
root = true
[*]
end_of_line = CRLF
[*.cs]
indent_style = space
indent_size = 4

7
.gitmodules

@ -1,3 +1,10 @@
[submodule "src/Perspex.ReactiveUI/src"]
path = src/Perspex.ReactiveUI/src
url = https://github.com/reactiveui/ReactiveUI.git
[submodule "src/Perspex.HtmlRenderer/external"]
path = src/Perspex.HtmlRenderer/external
url = https://github.com/Perspex/HTML-Renderer.git
branch = perspex-pcl
[submodule "src/Markup/Perspex.Markup.Xaml/OmniXAML"]
path = src/Markup/Perspex.Markup.Xaml/OmniXAML
url = https://github.com/SuperJMN/OmniXAML.git

150
Perspex.sln

@ -3,18 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Win32", "src\Windows\Perspex.Win32\Perspex.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication", "samples\TestApplication\TestApplication.csproj", "{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}"
ProjectSection(ProjectDependencies) = postProject
{3E908F67-5543-4879-A1DC-08EACE79B3CD} = {3E908F67-5543-4879-A1DC-08EACE79B3CD}
{FB05AC90-89BA-4F2F-A924-F37875FB547C} = {FB05AC90-89BA-4F2F-A924-F37875FB547C}
{811A76CF-1CF6-440F-963B-BBE31BD72A82} = {811A76CF-1CF6-440F-963B-BBE31BD72A82}
{54F237D5-A70A-4752-9656-0C70B1A7B047} = {54F237D5-A70A-4752-9656-0C70B1A7B047}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Direct2D1", "src\Windows\Perspex.Direct2D1\Perspex.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Base", "src\Perspex.Base\Perspex.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.SceneGraph", "src\Perspex.SceneGraph\Perspex.SceneGraph.csproj", "{EB582467-6ABB-43A1-B052-E981BA910E3A}"
@ -23,6 +11,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Layout", "src\Persp
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Windows", "Windows", "{B39A8919-9F95-48FE-AD7B-76E08B509888}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Win32", "src\Windows\Perspex.Win32\Perspex.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Direct2D1", "src\Windows\Perspex.Direct2D1\Perspex.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Designer", "src\Windows\Perspex.Designer\Perspex.Designer.csproj", "{EC42600F-049B-43FF-AED1-8314D61B2749}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Input", "src\Perspex.Input\Perspex.Input.csproj", "{62024B2D-53EB-4638-B26B-85EEAA54866E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Interactivity", "src\Perspex.Interactivity\Perspex.Interactivity.csproj", "{6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}"
@ -31,29 +25,25 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Controls", "src\Per
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Styling", "src\Perspex.Styling\Perspex.Styling.csproj", "{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Styling.UnitTests", "tests\Perspex.Styling.UnitTests\Perspex.Styling.UnitTests.csproj", "{47ECDF59-DEF8-4C53-87B1-2098A3429059}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Controls.UnitTests", "tests\Perspex.Controls.UnitTests\Perspex.Controls.UnitTests.csproj", "{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Themes.Default", "src\Perspex.Themes.Default\Perspex.Themes.Default.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.SceneGraph.UnitTests", "tests\Perspex.SceneGraph.UnitTests\Perspex.SceneGraph.UnitTests.csproj", "{76716382-3159-460E-BDA6-C5715CF606D7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Application", "src\Perspex.Application\Perspex.Application.csproj", "{799A7BB5-3C2C-48B6-85A7-406A12C420DA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Diagnostics", "src\Perspex.Diagnostics\Perspex.Diagnostics.csproj", "{7062AE20-5DCC-4442-9645-8195BDECE63E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Base.UnitTests", "tests\Perspex.Base.UnitTests\Perspex.Base.UnitTests.csproj", "{2905FF23-53FB-45E6-AA49-6AF47A172056}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Animation", "src\Perspex.Animation\Perspex.Animation.csproj", "{D211E587-D8BC-45B9-95A4-F297C8FA5200}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{2BAFBE53-7FA4-4BB9-976F-9AFCC4F9847D}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NGenerics", "src\NGenerics\NGenerics.csproj", "{415E048E-4611-4815-9CF2-D774E29079AC}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Styling.UnitTests", "tests\Perspex.Styling.UnitTests\Perspex.Styling.UnitTests.csproj", "{47ECDF59-DEF8-4C53-87B1-2098A3429059}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Layout.UnitTests", "tests\Perspex.Layout.UnitTests\Perspex.Layout.UnitTests.csproj", "{DB070A10-BF39-4752-8456-86E9D5928478}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Controls.UnitTests", "tests\Perspex.Controls.UnitTests\Perspex.Controls.UnitTests.csproj", "{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Animation", "src\Perspex.Animation\Perspex.Animation.csproj", "{D211E587-D8BC-45B9-95A4-F297C8FA5200}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.SceneGraph.UnitTests", "tests\Perspex.SceneGraph.UnitTests\Perspex.SceneGraph.UnitTests.csproj", "{76716382-3159-460E-BDA6-C5715CF606D7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Base.UnitTests", "tests\Perspex.Base.UnitTests\Perspex.Base.UnitTests.csproj", "{2905FF23-53FB-45E6-AA49-6AF47A172056}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Layout.UnitTests", "tests\Perspex.Layout.UnitTests\Perspex.Layout.UnitTests.csproj", "{DB070A10-BF39-4752-8456-86E9D5928478}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Interactivity.UnitTests", "tests\Perspex.Interactivity.UnitTests\Perspex.Interactivity.UnitTests.csproj", "{08478EF5-44E8-42E9-92D6-15E00EC038D8}"
EndProject
@ -63,9 +53,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Input.UnitTests", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Direct2D1.UnitTests", "tests\Perspex.Direct2D1.UnitTests\Perspex.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Cairo.RenderTests", "tests\Perspex.RenderTests\Perspex.Cairo.RenderTests.csproj", "{E106CF37-4066-4615-B684-172A6D30B058}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Markup.Xaml.UnitTests", "tests\Perspex.Markup.Xaml.UnitTests\Perspex.Markup.Xaml.UnitTests.csproj", "{99135EAB-653D-47E4-A378-C96E1278CA44}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Markup", "Markup", "{8B6A8209-894F-4BA1-B880-965FD453982C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Markup.Xaml", "src\Markup\Perspex.Markup.Xaml\Perspex.Markup.Xaml.csproj", "{3E53A01A-B331-47F3-B828-4A5717E77A24}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplication", "samples\XamlTestApplication\XamlTestApplication.csproj", "{78CAFE33-DBEB-4132-8A28-81CFE8A4933C}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{9B9E3891-2366-4253-A952-D08BCEB71098}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication", "samples\TestApplication\TestApplication.csproj", "{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}"
ProjectSection(ProjectDependencies) = postProject
{3E908F67-5543-4879-A1DC-08EACE79B3CD} = {3E908F67-5543-4879-A1DC-08EACE79B3CD}
{FB05AC90-89BA-4F2F-A924-F37875FB547C} = {FB05AC90-89BA-4F2F-A924-F37875FB547C}
@ -73,9 +71,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplication", "samp
{54F237D5-A70A-4752-9656-0C70B1A7B047} = {54F237D5-A70A-4752-9656-0C70B1A7B047}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Markup", "Markup", "{8B6A8209-894F-4BA1-B880-965FD453982C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{9B9E3891-2366-4253-A952-D08BCEB71098}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplication", "samples\XamlTestApplication\XamlTestApplication.csproj", "{78CAFE33-DBEB-4132-8A28-81CFE8A4933C}"
ProjectSection(ProjectDependencies) = postProject
{3E908F67-5543-4879-A1DC-08EACE79B3CD} = {3E908F67-5543-4879-A1DC-08EACE79B3CD}
{FB05AC90-89BA-4F2F-A924-F37875FB547C} = {FB05AC90-89BA-4F2F-A924-F37875FB547C}
{811A76CF-1CF6-440F-963B-BBE31BD72A82} = {811A76CF-1CF6-440F-963B-BBE31BD72A82}
{54F237D5-A70A-4752-9656-0C70B1A7B047} = {54F237D5-A70A-4752-9656-0C70B1A7B047}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DEF5-D50F-4975-8B72-124C9EB54066}"
ProjectSection(SolutionItems) = preProject
@ -90,24 +92,21 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Cairo", "src\Gtk\Pe
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.ReactiveUI", "src\Perspex.ReactiveUI\Perspex.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.HtmlRenderer", "src\Perspex.HtmlRenderer\Perspex.HtmlRenderer.csproj", "{5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlatformSupport", "src\Shared\PlatformSupport\PlatformSupport.shproj", "{E4D9629C-F168-4224-3F51-A5E482FFBC42}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13
src\Shared\PlatformSupport\PlatformSupport.projitems*{54f237d5-a70a-4752-9656-0c70b1a7b047}*SharedItemsImports = 4
src\Shared\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.Build.0 = Release|Any CPU
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|Any CPU.Build.0 = Release|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.Build.0 = Release|Any CPU
{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -120,6 +119,18 @@ Global
{42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42472427-4774-4C81-8AFF-9F27B8E31721}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42472427-4774-4C81-8AFF-9F27B8E31721}.Release|Any CPU.Build.0 = Release|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.Build.0 = Release|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.Build.0 = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC42600F-049B-43FF-AED1-8314D61B2749}.Release|Any CPU.Build.0 = Release|Any CPU
{62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -136,22 +147,10 @@ Global
{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|Any CPU.Build.0 = Release|Any CPU
{47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|Any CPU.Build.0 = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.Build.0 = Release|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.Build.0 = Release|Any CPU
{76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.Build.0 = Release|Any CPU
{799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -160,22 +159,30 @@ Global
{7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|Any CPU.Build.0 = Release|Any CPU
{D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|Any CPU.Build.0 = Release|Any CPU
{47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|Any CPU.Build.0 = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.Build.0 = Release|Any CPU
{76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.Build.0 = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.Build.0 = Release|Any CPU
{415E048E-4611-4815-9CF2-D774E29079AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{415E048E-4611-4815-9CF2-D774E29079AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{415E048E-4611-4815-9CF2-D774E29079AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{415E048E-4611-4815-9CF2-D774E29079AC}.Release|Any CPU.Build.0 = Release|Any CPU
{DB070A10-BF39-4752-8456-86E9D5928478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB070A10-BF39-4752-8456-86E9D5928478}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB070A10-BF39-4752-8456-86E9D5928478}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB070A10-BF39-4752-8456-86E9D5928478}.Release|Any CPU.Build.0 = Release|Any CPU
{D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|Any CPU.Build.0 = Release|Any CPU
{08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -192,10 +199,22 @@ Global
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.Build.0 = Release|Any CPU
{E106CF37-4066-4615-B684-172A6D30B058}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E106CF37-4066-4615-B684-172A6D30B058}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E106CF37-4066-4615-B684-172A6D30B058}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E106CF37-4066-4615-B684-172A6D30B058}.Release|Any CPU.Build.0 = Release|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.Build.0 = Release|Any CPU
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.Build.0 = Release|Any CPU
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|Any CPU.Build.0 = Release|Any CPU
{78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -212,27 +231,34 @@ Global
{6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.Build.0 = Release|Any CPU
{5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{811A76CF-1CF6-440F-963B-BBE31BD72A82} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{3E908F67-5543-4879-A1DC-08EACE79B3CD} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{EC42600F-049B-43FF-AED1-8314D61B2749} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{47ECDF59-DEF8-4C53-87B1-2098A3429059} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{5CCB5571-7C30-4E7D-967D-0E2158EBD91F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{76716382-3159-460E-BDA6-C5715CF606D7} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{2905FF23-53FB-45E6-AA49-6AF47A172056} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{415E048E-4611-4815-9CF2-D774E29079AC} = {2BAFBE53-7FA4-4BB9-976F-9AFCC4F9847D}
{DB070A10-BF39-4752-8456-86E9D5928478} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{08478EF5-44E8-42E9-92D6-15E00EC038D8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{AC18926A-E784-40FE-B09D-BB0FE2B599F0} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{E106CF37-4066-4615-B684-172A6D30B058} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{78CAFE33-DBEB-4132-8A28-81CFE8A4933C} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{54F237D5-A70A-4752-9656-0C70B1A7B047} = {B9894058-278A-46B5-B6ED-AD613FCC03B3}
{FB05AC90-89BA-4F2F-A924-F37875FB547C} = {B9894058-278A-46B5-B6ED-AD613FCC03B3}
{E4D9629C-F168-4224-3F51-A5E482FFBC42} = {A689DEF5-D50F-4975-8B72-124C9EB54066}
EndGlobalSection
EndGlobal

17
Perspex.sln.DotSettings

@ -0,0 +1,17 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=6417B24E_002D49C2_002D4985_002D8DB2_002D3AB9D898EC91/@EntryIndexedValue">ExplicitlyExcluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=E3A1060B_002D50D0_002D44E8_002D88B6_002DF44EF2E5BD72_002Ff_003Ahtml_002Ehtm/@EntryIndexedValue">ExplicitlyExcluded</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantUsingDirective/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Interfaces/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="I" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Locals/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=MethodPropertyEvent/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Other/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Parameters/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="s_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="s_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String></wpf:ResourceDictionary>

BIN
Perspex.v2.ncrunchsolution

Binary file not shown.

44
Tests/Perspex.Controls.UnitTests/DockPanelTests/AlignerTests.cs

@ -0,0 +1,44 @@
namespace Perspex.Controls.UnitTests.DockPanelTests
{
using Xunit;
public class AlignerTests
{
[Fact]
public void ToStartTest()
{
Segment container = new Segment(2, 5);
var aligned = container.AlignToStart(2);
Assert.Equal(new Segment(2, 4), aligned);
}
[Fact]
public void ToEndTest()
{
Segment container = new Segment(2, 5);
var aligned = container.AlignToEnd(2);
Assert.Equal(new Segment(3, 5), aligned);
}
[Fact]
public void ToMiddleTest()
{
Segment container = new Segment(2, 5);
var aligned = container.AlignToMiddle(2);
Assert.Equal(new Segment(2.5, 4.5), aligned);
}
[Fact]
public void ToMiddleTest2()
{
Segment container = new Segment(0, 500);
var aligned = container.AlignToMiddle(200);
Assert.Equal(new Segment(150, 350), aligned);
}
}
}

38
Tests/Perspex.Controls.UnitTests/DockPanelTests/LeftDockerTests.cs

@ -0,0 +1,38 @@
namespace Perspex.Controls.UnitTests.DockPanelTests
{
using System.Collections.Generic;
using Layout;
using Moq;
using Xunit;
public class LeftDockerTests
{
private readonly ILayoutable _layoutable;
public LeftDockerTests()
{
var layoutableMock = new Mock<ILayoutable>();
layoutableMock.Setup(l => l.DesiredSize).Returns(new Size(40, 30));
_layoutable = layoutableMock.Object;
}
[Theory]
[MemberData("Source")]
public void Dock(Margins margins, Rect expectedRect)
{
var sut = new LeftDocker(new Size(100, 50));
var actualRect = sut.GetDockingRect(_layoutable.DesiredSize, margins, new Alignments(Alignment.Middle, Alignment.Stretch));
Assert.Equal(expectedRect, actualRect);
}
// ReSharper disable once UnusedMember.Global
public static IEnumerable<object[]> Source => new[]
{
new object[] { new Margins(), new Rect(0, 0, 40, 50)},
new object[] { new Margins { VerticalMargin = new Segment(15, 0) }, new Rect(0, 15, 40, 35)},
new object[] { new Margins { VerticalMargin = new Segment(0, 15) }, new Rect(0, 0, 40, 35)},
new object[] { new Margins { VerticalMargin = new Segment(20, 15) }, new Rect(0, 20, 40, 15)},
};
}
}

40
Tests/Perspex.Controls.UnitTests/DockPanelTests/RectAlignerTests.cs

@ -0,0 +1,40 @@
namespace Perspex.Controls.UnitTests.DockPanelTests
{
using Layout;
using Xunit;
public class RectAlignerTests
{
private readonly Rect _container = new Rect(0, 0, 40, 40);
private readonly Size _child = new Size(20, 20);
[Theory]
[MemberData("TestData")]
public void LefTopTest(Alignment horz, Alignment vert, Rect expectedRect)
{
var actualRect = _container.AlignChild(_child, horz, vert);
Assert.Equal(expectedRect, actualRect);
}
// ReSharper disable once UnusedMember.Global
public static object[] TestData => new object[]
{
new object[] {Alignment.Start, Alignment.Start, new Rect(0, 0, 20, 20)},
new object[] {Alignment.Middle, Alignment.Start, new Rect(10, 0, 20, 20)},
new object[] {Alignment.End, Alignment.Start, new Rect(20, 0, 20, 20)},
new object[] {Alignment.Stretch, Alignment.Start, new Rect(0, 0, 40, 20)},
new object[] {Alignment.Start, Alignment.Middle, new Rect(0, 10, 20, 20)},
new object[] {Alignment.Middle, Alignment.Middle, new Rect(10, 10, 20, 20)},
new object[] {Alignment.End, Alignment.Middle, new Rect(20, 10, 20, 20)},
new object[] {Alignment.Stretch, Alignment.Middle, new Rect(0, 10, 40, 20)},
new object[] {Alignment.Start, VerticalAlignment.Bottom, new Rect(0, 20, 20, 20)},
new object[] {Alignment.Middle, VerticalAlignment.Bottom, new Rect(10, 20, 20, 20)},
new object[] {Alignment.End, VerticalAlignment.Bottom, new Rect(20, 20, 20, 20)},
new object[] {Alignment.Stretch, VerticalAlignment.Bottom, new Rect(0, 20, 40, 20)},
new object[] {Alignment.Stretch, VerticalAlignment.Stretch, new Rect(0, 0, 40, 40)},
};
}
}

38
Tests/Perspex.Controls.UnitTests/DockPanelTests/RightDockerTests.cs

@ -0,0 +1,38 @@
namespace Perspex.Controls.UnitTests.DockPanelTests
{
using System.Collections.Generic;
using Layout;
using Moq;
using Xunit;
public class RightDockerTests
{
private readonly ILayoutable _layoutable;
public RightDockerTests()
{
var layoutableMock = new Mock<ILayoutable>();
layoutableMock.Setup(l => l.DesiredSize).Returns(new Size(40, 30));
_layoutable = layoutableMock.Object;
}
[Theory]
[MemberData("Source")]
public void Dock(Margins margins, Rect expectedRect)
{
var sut = new RightDocker(new Size(100, 50));
var actualRect = sut.GetDockingRect(_layoutable.DesiredSize, margins, new Alignments(Alignment.Middle, Alignment.Stretch));
Assert.Equal(expectedRect, actualRect);
}
// ReSharper disable once UnusedMember.Global
public static IEnumerable<object[]> Source => new[]
{
new object[] { new Margins(), new Rect(60, 0, 40, 50)},
new object[] { new Margins { VerticalMargin = new Segment(0, 15) }, new Rect(60, 0, 40, 35)},
new object[] { new Margins { VerticalMargin = new Segment(15, 0) }, new Rect(60, 15, 40, 35)},
new object[] { new Margins { VerticalMargin = new Segment(20, 15) }, new Rect(60, 20, 40, 15)},
};
}
}

16
appveyor.yml

@ -3,6 +3,20 @@ os: Visual Studio 2015
before_build:
- git submodule update --init
- nuget restore Perspex.sln
environment:
myget_key:
secure: XOgD5bJUKNOS2kDDgb+affS4pDcslxALh+xvvnr1Koy0PjXlhILsBdNhxRe0KcNm
configuration:
- Release
after_test:
- ps: nuget\build-appveyor.ps1
artifacts:
- path: nuget\*.nupkg
build:
project: Perspex.sln
verbosity: minimal
verbosity: minimal

BIN
docs/add-dialogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
docs/add-packages.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

5
docs/build.md

@ -6,7 +6,7 @@ Perspex requires Visual Studio 2015 to build on Windows.
### Install GTK Sharp
To compile the full project under windows, you must have gtk-sharp installed. However, if you're
To compile the full project under windows, you must have [gtk-sharp](http://www.mono-project.com/download/#download-win) installed. However, if you're
not interested in building the cross-platform bits you can simply unload the Perspex.Cairo and
Perspex.Gtk project in Visual Studio.
@ -27,8 +27,7 @@ please submit a PR if you have anything to add.
### Install Latest Mono
That the time of writing, mono 4.2 aplha was needed to build. Add mono package sources by following
instructions below for the stable channel, and then add the alpha channel to
`/etc/apt/sources.list.d/mono-xamarin-alpha.list` as well.
instructions below for the stable channel and then add the alpha channel as well.
http://www.mono-project.com/docs/getting-started/install/linux/#debian-ubuntu-and-derivatives

22
docs/contributing.md

@ -1,24 +1,16 @@
# Contributing #
## Style ##
## Before You Start ##
The codebase uses StyleCop with default settings[1] to enforce coding style. Yes, some of the
decisions it makes are downright bizarre, and are certainly not what I would've personally chosen
but the less time spent debating coding style the more time left for coding.
Drop into our [gitter chat room](https://gitter.im/Perspex/Perspex) and let us know what you're thinking of doing. We might be able to give you guidance or let you know if someone else is already working on the feature.
StyleCop should run on each build and give warnings for any violations. So please, follow the style;
you'll get used to it in the end (I know I have).
## Style ##
If the .NET core team decide on a style and write an automatic checker/tidy tool for that style,
I'll gladly adopt it! I'm certainly not tied to the current style, I'm just tired of endless coding
style debates. Someone decide for me goddammit!
The codebase uses [.net core](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md) coding style.
Try to keep lines of code around 100 characters in length or less, though this is not a hard limit.
If you're a few characters over then don't worry too much.
Documentation comments should also be formatted to a 100 character length to help keep them
readable.
**DO NOT USE #REGIONS** full stop.
## Pull requests ##
@ -45,8 +37,7 @@ unless you see something that is obviously wrong or that could be written in a m
idiomatic style. It takes time to review each pull request - time that I'd prefer to spend writing
new features!
Prefer terseness to verbosity (yes I know that StyleCop will often be working against you here
:weary:) but don't try to be too clever.
Prefer terseness to verbosity but don't try to be too clever.
## Tests ##
@ -67,6 +58,3 @@ English what the test is testing, e.g.
Render tests should describe what the produced image is:
void Rectangle_2px_Stroke_Filled()
----
[1] Documentation rules are disabled because there's currently so much missing documentation, sorry!

15
docs/gettingstarted.md

@ -0,0 +1,15 @@
# Getting Started
## Windows
![](add-dialogs.png)
The easiest way to try out Perspex is to install the Visual Studio Extension.
This will add a Perspex project template and a Window template to the standard Visual Studo “Add” dialog (yes, icons still to come :) ):
## OSX / Linux
It is a little more manual on non-Windows platforms, but using Xamarin Studio you can install the Perspex NuGet package.
![](add-packages.png)

BIN
docs/perspex-video.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
docs/screen.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 104 KiB

93
docs/styles.md

@ -0,0 +1,93 @@
# Styling in Perspex
The main difference between Perspex and existing XAML toolkits such as WPF and
UWP is in styling. Styling in Perspex uses a CSS-like system that aims to be
more powerful and flexible than existing XAML styling systems. For convenience
for the rest of this document we'll refer to existing XAML toolkit's styling as
"WPF styling" as that's where it originated.
## Basics
- Styles are defined on the `Control.Styles` collection (as opposed to in
`ResourceDictionaries` in WPF).
- Styles have a `Selector` and a collection of `Setter`s
- Selector works like a CSS selector.
- Setters function like WPF's setters.
- Styles are applied to a control and all its descendants, depending on whether
the selector matches.
## Simple example
Make all `Button`s in a `StackPanel` have a blue `Background`:
<StackPanel>
<StackPanel.Styles>
<Style Selector="Button">
<Setter Property="Button.Background" Value="Blue"/>
</Style>
</StackPanel.Styles>
<Button>I will have a blue background.</Button>
</StackPanel>
This is very similar to WPF, except `TargetType` is replaced by `Selector`.
*Note that currently (as of Alpha 2) you **always** need to specify the fully
qualified property name (i.e. `Button.Background` instead of simply
`Background`). This restriction will be lifted in future.*
## Style Classes
As in CSS, controls can be given *style classes* which can be used in selectors:
<StackPanel>
<StackPanel.Styles>
<Style Selector="Button.blue">
<Setter Property="Button.Background" Value="Blue"/>
</Style>
</StackPanel.Styles>
<Button Classes="blue">I will have a blue background.</Button>
<Button>I will not.</Button>
</StackPanel>
## Pseudoclasses
Also as in CSS, controls can have pseudoclasses; these are classes that are
defined by the control itself rather than by the user. Pseudoclasses start
with a `:` character.
One example of a pseudoclass is the `:pointerover`
pseudoclass (`:hover` in CSS - we may change to that in future).
Pseudoclasses provide the functionality of `Triggers` in WPF and
`VisualStateManager` in UWP:
<StackPanel>
<StackPanel.Styles>
<Style Selector="Button:pointerover">
<Setter Property="Button.Foreground" Value="Red"/>
</Style>
</StackPanel.Styles>
<Button>I will have red text when hovered.</Button>
</StackPanel>
Other pseudoclasses include `:focus`, `:disabled`, `:pressed` for buttons,
`:checked` for checkboxes etc.
## Named Controls
Named controls can be selected using `#` as in CSS, e.g. `Button#Name`.
## Children
As with CSS, you can select children and descendants:
- `StackPanel > Button#Foo` selects a `Button` named `"Foo"` that is the child
of a `StackPanel`.
- `StackPanel Button.foo` selects all `Button`s with the `foo` class that are
descendants of a `StackPanel`.
## Templates
You can select controls in the template of a lookless control by using the
`/template/` selector, so `Button /template/ Border#outline` selects `Border`
controls named `"outline"` in the template of a `Button`.

2
fileheader.txt

@ -0,0 +1,2 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.

7
nuget/.gitignore

@ -1,7 +1,2 @@
- build/
**/lib/**/*.dll
**/lib/**/*.xml
**/build/**/*.dll
**/build/**/*.xml
Perspex
*.nupkg

33
nuget/build-appveyor.ps1

@ -0,0 +1,33 @@
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Push-Location $dir
sv version $env:APPVEYOR_BUILD_NUMBER
#sv version "1-debug"
sv version 9999.0.$version-nightly
sv key $env:myget_key
sv file Perspex.$version.nupkg
.\build-version.ps1 $version
sv reponame $env:APPVEYOR_REPO_NAME
sv repobranch $env:APPVEYOR_REPO_BRANCH
sv pullreq $env:APPVEYOR_PULL_REQUEST_NUMBER
echo "Checking for publishing"
echo $reponame $repobranch $pullreq
if ($reponame -eq "Perspex/Perspex")
{
echo Repo name matched
if($repobranch -eq "master")
{
echo Repo branch matched
nuget.exe push $file $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package
}
}

47
nuget/build-version.ps1

@ -0,0 +1,47 @@
rm -Force -Recurse .\Perspex -ErrorAction SilentlyContinue
rm -Force -Recurse *.nupkg -ErrorAction SilentlyContinue
Copy-Item template Perspex -Recurse
sv lib "Perspex\lib\portable-windows8+net45"
sv build "Perspex\build\net45"
mkdir $lib -ErrorAction SilentlyContinue
mkdir $build -ErrorAction SilentlyContinue
Copy-Item ..\src\Perspex.Animation\bin\Release\Perspex.Animation.dll $lib
Copy-Item ..\src\Perspex.Animation\bin\Release\Perspex.Animation.xml $lib
Copy-Item ..\src\Perspex.Application\bin\Release\Perspex.Application.dll $lib
Copy-Item ..\src\Perspex.Application\bin\Release\Perspex.Application.xml $lib
Copy-Item ..\src\Perspex.Base\bin\Release\Perspex.Base.dll $lib
Copy-Item ..\src\Perspex.Base\bin\Release\Perspex.Base.xml $lib
Copy-Item ..\src\Perspex.Controls\bin\Release\Perspex.Controls.dll $lib
Copy-Item ..\src\Perspex.Controls\bin\Release\Perspex.Controls.xml $lib
Copy-Item ..\src\Perspex.Diagnostics\bin\Release\\Perspex.Diagnostics.dll $lib
Copy-Item ..\src\Perspex.Diagnostics\bin\Release\\Perspex.Diagnostics.xml $lib
Copy-Item ..\src\Perspex.Input\bin\Release\Perspex.Input.dll $lib
Copy-Item ..\src\Perspex.Input\bin\Release\Perspex.Input.xml $lib
Copy-Item ..\src\Perspex.Interactivity\bin\Release\Perspex.Interactivity.dll $lib
Copy-Item ..\src\Perspex.Interactivity\bin\Release\Perspex.Interactivity.xml $lib
Copy-Item ..\src\Perspex.Layout\bin\Release\Perspex.Layout.dll $lib
Copy-Item ..\src\Perspex.Layout\bin\Release\Perspex.Layout.xml $lib
Copy-Item ..\src\Perspex.SceneGraph\bin\Release\Perspex.SceneGraph.dll $lib
Copy-Item ..\src\Perspex.SceneGraph\bin\Release\Perspex.SceneGraph.xml $lib
Copy-Item ..\src\Perspex.Styling\bin\Release\Perspex.Styling.dll $lib
Copy-Item ..\src\Perspex.Styling\bin\Release\Perspex.Styling.xml $lib
Copy-Item ..\src\Perspex.Themes.Default\bin\Release\Perspex.Themes.Default.dll $lib
Copy-Item ..\src\Perspex.Themes.Default\bin\Release\Perspex.Themes.Default.xml $lib
Copy-Item ..\src\Markup\Perspex.Markup.Xaml\bin\Release\Perspex.Markup.Xaml.dll $lib
Copy-Item ..\src\Markup\Perspex.Markup.Xaml\bin\Release\Perspex.Markup.Xaml.xml $lib
Copy-Item ..\src\Perspex.HtmlRenderer\bin\Release\Perspex.HtmlRenderer.dll $lib
Copy-Item ..\src\Perspex.ReactiveUI\bin\Release\Perspex.ReactiveUI.dll $lib
Copy-Item ..\src\Windows\Perspex.Direct2D1\bin\Release\Perspex.Direct2D1.dll $build
Copy-Item ..\src\Windows\Perspex.Direct2D1\bin\Release\SharpDX.dll $build
Copy-Item ..\src\Windows\Perspex.Direct2D1\bin\Release\SharpDX.Direct2D1.dll $build
Copy-Item ..\src\Windows\Perspex.Direct2D1\bin\Release\SharpDX.DXGI.dll $build
Copy-Item ..\src\Windows\Perspex.Win32\bin\Release\Perspex.Win32.dll $build
Copy-Item ..\src\Gtk\Perspex.Gtk\bin\Release\Perspex.Gtk.dll $build
Copy-Item ..\src\Gtk\Perspex.Cairo\bin\Release\Perspex.Cairo.dll $build
(gc Perspex\Perspex.nuspec).replace('#VERSION#', $args[0]) | sc Perspex\Perspex.nuspec
nuget.exe pack Perspex\Perspex.nuspec
rm -Force -Recurse .\Perspex

39
nuget/build.bat

@ -1,39 +0,0 @@
SET lib="Perspex\lib\portable-windows8+net45"
SET build="Perspex\build\net45"
mkdir %lib%
mkdir %build%
copy ..\src\Perspex.Animation\bin\Release\Perspex.Animation.dll %lib%
copy ..\src\Perspex.Animation\bin\Release\Perspex.Animation.xml %lib%
copy ..\src\Perspex.Application\bin\Release\Perspex.Application.dll %lib%
copy ..\src\Perspex.Application\bin\Release\Perspex.Application.xml %lib%
copy ..\src\Perspex.Base\bin\Release\Perspex.Base.dll %lib%
copy ..\src\Perspex.Base\bin\Release\Perspex.Base.xml %lib%
copy ..\src\Perspex.Controls\bin\Release\Perspex.Controls.dll %lib%
copy ..\src\Perspex.Controls\bin\Release\Perspex.Controls.xml %lib%
copy ..\src\Perspex.Diagnostics\bin\Release\\Perspex.Diagnostics.dll %lib%
copy ..\src\Perspex.Diagnostics\bin\Release\\Perspex.Diagnostics.xml %lib%
copy ..\src\Perspex.Input\bin\Release\Perspex.Input.dll %lib%
copy ..\src\Perspex.Input\bin\Release\Perspex.Input.xml %lib%
copy ..\src\Perspex.Interactivity\bin\Release\Perspex.Interactivity.dll %lib%
copy ..\src\Perspex.Interactivity\bin\Release\Perspex.Interactivity.xml %lib%
copy ..\src\Perspex.Layout\bin\Release\Perspex.Layout.dll %lib%
copy ..\src\Perspex.Layout\bin\Release\Perspex.Layout.xml %lib%
copy ..\src\Perspex.SceneGraph\bin\Release\Perspex.SceneGraph.dll %lib%
copy ..\src\Perspex.SceneGraph\bin\Release\Perspex.SceneGraph.xml %lib%
copy ..\src\Perspex.Styling\bin\Release\Perspex.Styling.dll %lib%
copy ..\src\Perspex.Styling\bin\Release\Perspex.Styling.xml %lib%
copy ..\src\Perspex.Themes.Default\bin\Release\Perspex.Themes.Default.dll %lib%
copy ..\src\Perspex.Themes.Default\bin\Release\Perspex.Themes.Default.xml %lib%
copy ..\src\Markup\Perspex.Markup.Xaml\bin\Release\Perspex.Markup.Xaml.dll %lib%
copy ..\src\Markup\Perspex.Markup.Xaml\bin\Release\Perspex.Markup.Xaml.xml %lib%
copy ..\src\NGenerics\bin\Release\NGenerics.dll %lib%
copy ..\src\Windows\Perspex.Direct2D1\bin\Release\Perspex.Direct2D1.dll %build%
copy ..\src\Windows\Perspex.Direct2D1\bin\Release\SharpDX.dll %build%
copy ..\src\Windows\Perspex.Direct2D1\bin\Release\SharpDX.Direct2D1.dll %build%
copy ..\src\Windows\Perspex.Direct2D1\bin\Release\SharpDX.DXGI.dll %build%
copy ..\src\Windows\Perspex.Win32\bin\Release\Perspex.Win32.dll %build%
nuget.exe pack Perspex\Perspex.nuspec

1
nuget/build.ps1

@ -0,0 +1 @@
.\build-version.ps1 0.1.1-alpha2

14
nuget/Perspex/Perspex.nuspec → nuget/template/Perspex.nuspec

@ -1,8 +1,8 @@
<?xml version="1.0"?>
<package >
<package>
<metadata>
<id>Perspex</id>
<version>0.0.1-alpha</version>
<version>#VERSION#</version>
<authors>stevenk</authors>
<owners>stevenk</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
@ -13,12 +13,14 @@
<copyright>Copyright 2015</copyright>
<tags>Perspex</tags>
<dependencies>
<dependency id="Glass" version="1.4.4.0" />
<dependency id="OmniXaml" version="1.4.4.0" />
<dependency id="reactiveui" version="6.5.0" />
<dependency id="reactiveui-core" version="6.5.0" />
<dependency id="Serilog" version="1.5.9" />
<dependency id="Splat" version="1.6.2" />
<dependency id="Sprache" version="2.0.0.47" />
<dependency id="Rx-Core" version="2.2.5" />
<dependency id="Rx-Interfaces" version="2.2.5" />
<dependency id="Rx-Linq" version="2.2.5" />
<dependency id="Rx-Main" version="2.2.5" />
<dependency id="Rx-PlatformServices" version="2.2.5" />
</dependencies>
</metadata>
</package>

0
nuget/Perspex/build/net45/perspex.targets → nuget/template/build/net45/perspex.targets

16
readme.md

@ -7,6 +7,16 @@ A multi-platform .NET UI framework.
![](docs/screen.png)
<a href='https://www.youtube.com/watch?t=28&v=c_AB_XSILp0' target='_blank'>![](docs/perspex-video.png)<a/>
## NuGet
Perspex is delivered as a NuGet package.
You can find the packages here: ([stable(ish)](https://www.nuget.org/packages/Perspex/), [nightly](https://github.com/Perspex/Perspex/wiki/Using-nightly-build-feed))
You can install the package like this:
`Install-Package Perspex -Pre`
## Background
Perspex is a multi-platform windowing toolkit - somewhat like WPF - that is intended to be multi-
@ -17,7 +27,7 @@ using Direct2D and other operating systems using Gtk & Cairo.
Perspex is now in alpha. What does "alpha mean? Well, it means that it's now at a stage where you
can have a play and hopefully create simple applications. There's now a [Visual
Studio Extension](https://visualstudiogallery.msdn.microsoft.com/87db356c-cec9-4a07-b7db-a4ed8a921ac9)
Studio Extension](https://visualstudiogallery.msdn.microsoft.com/a4542e8a-b56c-4295-8df1-7e220178b873)
containing project and item templates that will help you get started, and
there's an initial complement of controls. There's still a lot missing, and you
*will* find bugs, and the API *will* change, but this represents the first time
@ -26,8 +36,8 @@ framework.
## Documentation
As mentioned above, Perspex is still in alpha and as such there's not much documentation yet. You can
take a look at the [alpha release announcement](http://grokys.github.io/perspex/perspex-alpha/) for an
As mentioned above, Perspex is still in alpha and as such there's not much documentation yet. You can
take a look at the [getting started page](docs/gettingstarted.md) for an
overview of how to get started but probably the best thing to do for now is to already know a little bit
about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/grokys/Perspex).

20
samples/TestApplication/App.cs

@ -1,16 +1,20 @@
namespace TestApplication
{
using System;
using Perspex;
using Perspex.Themes.Default;
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Perspex;
using Perspex.Themes.Default;
namespace TestApplication
{
public class App : Application
{
public App()
{
this.RegisterServices();
this.InitializeSubsystems((int)Environment.OSVersion.Platform);
this.Styles = new DefaultTheme();
RegisterServices();
InitializeSubsystems((int)Environment.OSVersion.Platform);
Styles = new DefaultTheme();
Styles.Add(new SampleTabStyle());
}
}
}

123
samples/TestApplication/GalleryStyle.cs

@ -0,0 +1,123 @@
using Perspex;
using Perspex.Controls;
using Perspex.Controls.Presenters;
using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
using Perspex.Media;
using Perspex.Styling;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestApplication
{
internal class SampleTabStyle : Styles
{
public SampleTabStyle()
{
this.AddRange(new[]
{
new Style (s => s.Class(":container").OfType<TabControl> ())
{
Setters = new[]
{
new Setter (TemplatedControl.TemplateProperty, new ControlTemplate<TabControl> (TabControlTemplate))
}
},
new Style(s => s.Class(":container").OfType<TabControl>().Child().Child().Child().Child().Child().OfType<TabItem>())
{
Setters = new[]
{
new Setter (TemplatedControl.TemplateProperty, new ControlTemplate<TabItem> (TabItemTemplate)),
}
},
new Style(s => s.Name("internalStrip").OfType<TabStrip>().Child().OfType<TabItem>())
{
Setters = new[]
{
new Setter(TemplatedControl.FontSizeProperty, 14.0),
new Setter(TemplatedControl.ForegroundProperty, Brushes.White)
}
},
new Style(s => s.Name("internalStrip").OfType<TabStrip>().Child().OfType<TabItem>().Class("selected"))
{
Setters = new[]
{
new Setter(TemplatedControl.ForegroundProperty, Brushes.White),
new Setter(TemplatedControl.BackgroundProperty, new SolidColorBrush(Colors.White) { Opacity = 0.1 }),
},
},
});
}
public static Control TabItemTemplate(TabItem control)
{
return new ContentPresenter
{
DataTemplates = new DataTemplates
{
new DataTemplate<string>(x => new Border
{
[~Border.BackgroundProperty] = control[~TemplatedControl.BackgroundProperty],
Padding = new Thickness(10),
Child = new TextBlock
{
VerticalAlignment = Perspex.Layout.VerticalAlignment.Center,
Text = x
}
})
},
Name = "headerPresenter",
[~ContentPresenter.ContentProperty] = control[~HeaderedContentControl.HeaderProperty],
};
}
public static Control TabControlTemplate(TabControl control)
{
return new Grid
{
ColumnDefinitions = new ColumnDefinitions
{
new ColumnDefinition(GridLength.Auto),
new ColumnDefinition(new GridLength(1, GridUnitType.Star)),
},
Children = new Controls
{
new Border
{
Width = 190,
Background = SolidColorBrush.Parse("#1976D2"),
Child = new ScrollViewer
{
Content = new TabStrip
{
ItemsPanel = new FuncTemplate<IPanel>(() => new StackPanel { Orientation = Orientation.Vertical, Gap = 4 }),
Margin = new Thickness(0, 10, 0, 0),
Name = "internalStrip",
[!ItemsControl.ItemsProperty] = control[!ItemsControl.ItemsProperty],
[!!SelectingItemsControl.SelectedItemProperty] = control[!!SelectingItemsControl.SelectedItemProperty],
}
}
},
new Deck
{
Name = "deck",
DataTemplates = new DataTemplates
{
new DataTemplate<TabItem>(x => (Control)control.MaterializeDataTemplate(x.Content)),
},
[~Deck.TransitionProperty] = control[~TabControl.TransitionProperty],
[!ItemsControl.ItemsProperty] = control[!ItemsControl.ItemsProperty],
[!SelectingItemsControl.SelectedItemProperty] = control[!SelectingItemsControl.SelectedItemProperty],
[Grid.ColumnProperty] = 1,
}
}
};
}
}
}

8
samples/TestApplication/Item.cs

@ -0,0 +1,8 @@
namespace TestApplication
{
internal class Item
{
public string Name { get; set; }
public string Value { get; set; }
}
}

16
samples/TestApplication/Node.cs

@ -0,0 +1,16 @@
using Perspex.Collections;
namespace TestApplication
{
internal class Node
{
public Node()
{
Children = new PerspexList<Node>();
}
public string Name { get; set; }
public PerspexList<Node> Children { get; set; }
}
}

1087
samples/TestApplication/Program.cs

File diff suppressed because it is too large

7
samples/TestApplication/Properties/AssemblyInfo.cs

@ -1,4 +1,7 @@
using System.Reflection;
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -10,7 +13,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TestApplication")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyCopyright("Copyright \u00A9 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

42
samples/TestApplication/TestApplication.csproj

@ -35,18 +35,6 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Serilog, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<HintPath>..\..\packages\Serilog.1.5.9\lib\net45\Serilog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Serilog.FullNetFx, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<HintPath>..\..\packages\Serilog.1.5.9\lib\net45\Serilog.FullNetFx.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
@ -72,9 +60,21 @@
<Reference Include="System.Reactive.PlatformServices">
<HintPath>..\..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll</HintPath>
</Reference>
<Reference Include="Serilog, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10">
<HintPath>..\..\packages\Serilog.1.5.9\lib\net45\Serilog.dll</HintPath>
</Reference>
<Reference Include="Serilog.FullNetFx, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10">
<HintPath>..\..\packages\Serilog.1.5.9\lib\net45\Serilog.FullNetFx.dll</HintPath>
</Reference>
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="App.cs" />
<Compile Include="GalleryStyle.cs" />
<Compile Include="Item.cs" />
<Compile Include="Node.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
@ -83,8 +83,12 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Gtk\Perspex.Cairo\Perspex.Cairo.csproj">
<Project>{FB05AC90-89BA-4F2F-A924-F37875FB547C}</Project>
<Name>Perspex.Cairo</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Animation\Perspex.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Project>{D211E587-D8BC-45B9-95A4-F297C8FA5200}</Project>
<Name>Perspex.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Application\Perspex.Application.csproj">
@ -103,6 +107,10 @@
<Project>{7062AE20-5DCC-4442-9645-8195BDECE63E}</Project>
<Name>Perspex.Diagnostics</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.HtmlRenderer\Perspex.HtmlRenderer.csproj">
<Project>{5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}</Project>
<Name>Perspex.HtmlRenderer</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Input\Perspex.Input.csproj">
<Project>{62024B2D-53EB-4638-B26B-85EEAA54866E}</Project>
<Name>Perspex.Input</Name>
@ -132,11 +140,11 @@
<Name>Perspex.Themes.Default</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Windows\Perspex.Direct2D1\Perspex.Direct2D1.csproj">
<Project>{3e908f67-5543-4879-a1dc-08eace79b3cd}</Project>
<Project>{3E908F67-5543-4879-A1DC-08EACE79B3CD}</Project>
<Name>Perspex.Direct2D1</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Windows\Perspex.Win32\Perspex.Win32.csproj">
<Project>{811a76cf-1cf6-440f-963b-bbe31bd72a82}</Project>
<Project>{811A76CF-1CF6-440F-963B-BBE31BD72A82}</Project>
<Name>Perspex.Win32</Name>
</ProjectReference>
</ItemGroup>
@ -144,6 +152,10 @@
<Content Include="github_icon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<EmbeddedResource Include="html.htm" />
<Content Include="pattern.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\src\Shared\perspex.platform.targets" />

128
samples/TestApplication/html.htm

@ -0,0 +1,128 @@
<html>
<head>
<title>Intro</title>
<style>
h1, h2, h3 { color: navy; font-weight:normal; }
h1 { margin-bottom: .47em }
h2 { margin-bottom: .3em }
h3 { margin-bottom: .4em }
ul { margin-top: .5em }
ul li {margin: .25em}
body { font:10pt Tahoma }
pre { border:solid 1px gray; background-color:#eee; padding:1em }
a:link { text-decoration: none; }
a:hover { text-decoration: underline; }
.gray { color:gray; }
.example { background-color:#efefef; corner-radius:5px; padding:0.5em; }
.whitehole { background-color:white; corner-radius:10px; padding:15px; }
.caption { font-size: 1.1em }
.comment { color: green; margin-bottom: 5px; margin-left: 3px; }
.comment2 { color: green; }
</style>
</head>
<body style=" margin: 0; background-color: #333; background-gradient: #707; background-gradient-angle: 60;">
<h1 align="center" style="color: white;">
HTML Renderer Project - Perspex port
<br />
<span style="font-size: x-small;">Beta support</span>
</h1>
<blockquote class="whitehole">
<p style="margin-top: 0px">
<table border="0" width="100%">
<tr style="vertical-align: top>
<td>
Everything you see on this panel (see samples on the left) is <b>custom-painted</b>
by the <b>HTML Renderer</b>, including tables, images, links and videos.<br />
This project allows you to have the rich format power of HTML on your desktop applications
without <b>WebBrowser</b> control or <b>MSHTML</b>.<br />
The library is <b>100% managed code</b> without any external dependencies, the only
requirement is <b>.NET 2.0 or higher</b>, including support for Client Profile.
</td>
</tr>
</table>
</p>
<h3>
Text selection (copy to clipboard)
</h3>
<div>
The rendered html has full support for <b>text selection</b> including <b>drag-and-drop</b>
and <b>copy</b> to clipboard of rich html and plain text to handle <b>paste</b>
operation to editor that support rich or/and plain text.<br />
Additionally there is a <b>context-menu</b> with select all, copy text, copy image,
save image, open link, copy link url, open video, copy video url.
</div>
<h3>
Cascading Style Sheets (CSS) support
</h3>
<div>
The core layout engine of the renderer was builded according to <b>CSS Level 2 specification</b>,
so you can use Cascading Style Sheets to format your html documents.<br />
Additionally there are a couple extensions: <b>Gradients</b> on backgrounds and
<b>rounded corners</b>.
</div>
<h3>
Benefits
</h3>
<ul>
<li>100% managed code and no external dependencies.</li>
<li>Supports .NET 2.0 or higher including Client Profile.</li>
<li>Handles "real world" malformed HTML, it doesn't have to be XHTML.</li>
<li>Lightweight (~300K).</li>
<li>High performance and low memory footprint.</li>
<li>Extendable and configurable.</li>
</ul>
<h3>
Limitations
</h3>
<ul>
<li>All HTML <b>end tags</b> marked as <a href="http://www.w3.org/TR/1999/REC-html401-19991224/index/elements.html">
optional</a> should be there. No problem with tags marked as forbidden.</li>
</ul>
<hr />
<h3>
On the roadmap</h3>
Of course it's not quite finished yet. Here are some of the important things to
do.
<ul>
<li>Better performance</li>
<li>Support of position CSS property</li>
<li>Support of height and min-height CSS property</li>
<li>Better tables support, especially layouts</li>
<li>Support image align</li>
<li>Handle :hover selector</li>
<li>Selection by shift+arrows</li>
<li>Better HTML tag parsing (optional closing tags)</li>
<li>More styles support</li>
</ul>
<h3>
Vision
</h3>
<ul>
<li>Most complete static HTML Renderer (no java script).</li>
<li>Commercial web browser performance level.</li>
</ul>
<hr />
<h3>
2015 - Nikita Tsukanov (Perspex Port)
</h3>
<blockquote>
<a href="https://perspex.github.io/">https://perspex.github.io/</a>
</blockquote>
<h3>
2012 - Arthur Teplitzki
</h3>
<blockquote>
<a href="http://theartofdev.com/">http://TheArtOfDev.com</a>
</blockquote>
<h3>
2009 - Jose Manuel Menendez Poo
</h3>
<blockquote>
<a href="http://www.menendezpoo.com">www.menendezpoo.com</a>
</blockquote>
</blockquote>
</body>
</html>

BIN
samples/TestApplication/pattern.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

2
samples/XamlTestApplication/App.config

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

19
samples/XamlTestApplication/App.cs

@ -1,16 +1,19 @@
namespace XamlTestApplication
{
using System;
using Perspex;
using Perspex.Themes.Default;
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Perspex;
using Perspex.Themes.Default;
namespace XamlTestApplication
{
public class App : Application
{
public App()
{
this.RegisterServices();
this.InitializeSubsystems((int)Environment.OSVersion.Platform);
this.Styles = new DefaultTheme();
RegisterServices();
InitializeSubsystems((int)Environment.OSVersion.Platform);
Styles = new DefaultTheme();
}
}
}

25
samples/XamlTestApplication/MainViewModel.cs

@ -1,15 +1,18 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Collections.Generic;
using ReactiveUI;
namespace XamlTestApplication
{
using System.Collections.Generic;
using ReactiveUI;
public class MainViewModel : ReactiveObject
{
private string name;
private string _name;
public MainViewModel()
{
Name = "José Manuel";
Name = "Jos\u00E9 Manuel";
People = new List<Person>
{
new Person("a little bit of Monica in my life"),
@ -24,8 +27,8 @@ namespace XamlTestApplication
public string Name
{
get { return name; }
set { this.RaiseAndSetIfChanged(ref name, value); }
get { return _name; }
set { this.RaiseAndSetIfChanged(ref _name, value); }
}
public List<Person> People { get; set; }
@ -33,17 +36,17 @@ namespace XamlTestApplication
public class Person
{
private string name;
private string _name;
public Person(string name)
{
this.name = name;
_name = name;
}
public string Name
{
get { return name; }
set { name = value; }
get { return _name; }
set { _name = value; }
}
}
}

39
samples/XamlTestApplication/Program.cs

@ -1,35 +1,38 @@
namespace XamlTestApplication
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Diagnostics;
using System.Windows.Threading;
using Perspex;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Controls.Templates;
using ReactiveUI;
using XamlTestApplication.Views;
namespace XamlTestApplication
{
using System;
using System.Diagnostics;
using System.Windows.Threading;
using Perspex;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Controls.Templates;
using ReactiveUI;
using Views;
class Item
internal class Item
{
public string Name { get; set; }
public string Value { get; set; }
}
class Node
internal class Node
{
public Node()
{
this.Children = new PerspexList<Node>();
Children = new PerspexList<Node>();
}
public string Name { get; set; }
public PerspexList<Node> Children { get; set; }
}
class Program
internal class Program
{
static void Main()
private static void Main()
{
var foo = Dispatcher.CurrentDispatcher;
@ -46,10 +49,10 @@
var testCommand = ReactiveCommand.Create();
testCommand.Subscribe(_ => Debug.WriteLine("Test command executed."));
var window = new MainWindow();
window.Show();
Application.Current.Run(window);
}
}
}
}

7
samples/XamlTestApplication/Properties/AssemblyInfo.cs

@ -1,4 +1,7 @@
using System.Reflection;
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -10,7 +13,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TestApplication")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyCopyright("Copyright \u00A9 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

27
samples/XamlTestApplication/Views/MainWindow.cs

@ -1,20 +1,23 @@
namespace XamlTestApplication.Views
{
using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Resources;
using OmniXaml;
using Perspex.Controls;
using Perspex.Diagnostics;
using Perspex.Markup.Xaml;
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Resources;
using OmniXaml;
using Perspex.Controls;
using Perspex.Diagnostics;
using Perspex.Markup.Xaml;
namespace XamlTestApplication.Views
{
public class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
InitializeComponent();
DevTools.Attach(this);
}

32
samples/XamlTestApplication/Views/MainWindow.xaml → samples/XamlTestApplication/Views/MainWindow.paml

@ -1,19 +1,21 @@
<Window x:Class="XamlTestApplication.MainWindow"
xmlns="https://github.com/grokys/Perspex"
xmlns="https://github.com/perspex"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Perspex Test Application" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
Title="Perspex Test Application" Height="350" Width="525" SizeToContent="WidthAndHeight" >
<Grid RowDefinitions="Auto,*">
<TabControl Grid.Row="1">
<TabItem Header="Buttons">
<StackPanel HorizontalAlignment="Center" Width="200" VerticalAlignment="Center">
<StackPanel.Styles>
<Style Selector="Button.italic">
<Setter Property="TextBlock.FontStyle" Value="Italic"/>
</Style>
</StackPanel.Styles>
<Button Content="Button" />
<Button Content="Button" Background="#119EDA" ToolTip.Tip="Goodbye Cruel World!" />
<Button Content="Default" IsDefault="True" />
<Button Content="Disabled" IsEnabled="False" />
<Button Content="Disabled" IsEnabled="False" Classes="italic"/>
<Button Content="Disabled" IsEnabled="False" Background="#119eda" />
<ToggleButton Content="Toggle" />
<ToggleButton Content="Toggle" IsEnabled="False" />
@ -24,9 +26,9 @@
</TabItem>
<TabItem Header="Text">
<StackPanel HorizontalAlignment="Center" Width="200" VerticalAlignment="Center">
<TextBlock
Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin venenatis dui quis libero suscipit tincidunt."
TextWrapping="Wrap" TextAlignment="Center" />
<TextBlock TextWrapping="Wrap" TextAlignment="Center">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin venenatis dui quis libero suscipit tincidunt.
</TextBlock>
<TextBlock Text="Italic text." TextWrapping="Wrap" TextAlignment="Left" FontStyle="Italic" />
<TextBlock TextWrapping="Wrap" TextAlignment="Right" FontWeight="Bold">Bold text.</TextBlock>
<TextBox Text="A non-wrapping text box. Lorem ipsum dolor sit amet." TextWrapping="NoWrap" />
@ -100,7 +102,13 @@
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Width="100" Height="100" Background="Crimson">
<Border Width="100" Height="100">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%">
<GradientStop Color="Red" Offset="0"/>
<GradientStop Color="Green" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Text="hello!"></TextBox>
</Border>
<Border Grid.Row="0" Grid.Column="1" Background="Coral" HorizontalAlignment="Center"

96
samples/XamlTestApplication/XamlTestApplication.csproj

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>XamlTestApplication</RootNamespace>
<AssemblyName>XamlTestApplication</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
@ -36,59 +36,43 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Glass, Version=0.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Glass.0.1.0\lib\portable-net45+win+Xamarin.iOS10+MonoAndroid10+MonoTouch10\Glass.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OmniXaml, Version=0.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\OmniXaml.0.1.0\lib\portable-net45+win+Xamarin.iOS10+MonoAndroid10+MonoTouch10\OmniXaml.dll</HintPath>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Reactive.Windows.Threading, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Rx-XAML.2.2.5\lib\net45\System.Reactive.Windows.Threading.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Serilog, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
<Reference Include="Serilog, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10">
<HintPath>..\..\packages\Serilog.1.5.9\lib\net45\Serilog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Serilog.FullNetFx, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<Reference Include="Serilog.FullNetFx, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10">
<HintPath>..\..\packages\Serilog.1.5.9\lib\net45\Serilog.FullNetFx.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Sprache, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Sprache.SuperJMN.2.0.0.50\lib\portable-net451+netcore451+wpa81\Sprache.dll</HintPath>
<Private>True</Private>
<Reference Include="Sprache, Version=2.0.0.47, Culture=neutral, PublicKeyToken=null">
<HintPath>..\..\packages\Sprache.2.0.0.47\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid1+MonoTouch1\Sprache.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Reactive.Core, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Reactive.Core, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>..\..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Interfaces, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Reactive.Interfaces, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Linq, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Reactive.Linq, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>..\..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.PlatformServices, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Reference Include="System.Reactive.PlatformServices, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>..\..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Windows.Threading, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Rx-XAML.2.2.5\lib\net45\System.Reactive.Windows.Threading.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="App.cs" />
@ -101,40 +85,36 @@
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\NGenerics\NGenerics.csproj">
<Project>{415e048e-4611-4815-9cf2-d774e29079ac}</Project>
<Name>NGenerics</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Animation\Perspex.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Project>{D211E587-D8BC-45B9-95A4-F297C8FA5200}</Project>
<Name>Perspex.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Application\Perspex.Application.csproj">
<Project>{799a7bb5-3c2c-48b6-85a7-406a12c420da}</Project>
<Project>{799A7BB5-3C2C-48B6-85A7-406A12C420DA}</Project>
<Name>Perspex.Application</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Base\Perspex.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Perspex.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Controls\Perspex.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Project>{D2221C82-4A25-4583-9B43-D791E3F6820C}</Project>
<Name>Perspex.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Diagnostics\Perspex.Diagnostics.csproj">
<Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
<Project>{7062AE20-5DCC-4442-9645-8195BDECE63E}</Project>
<Name>Perspex.Diagnostics</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Input\Perspex.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Project>{62024B2D-53EB-4638-B26B-85EEAA54866E}</Project>
<Name>Perspex.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Interactivity\Perspex.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Project>{6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}</Project>
<Name>Perspex.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Layout\Perspex.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Project>{42472427-4774-4C81-8AFF-9F27B8E31721}</Project>
<Name>Perspex.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.ReactiveUI\Perspex.ReactiveUI.csproj">
@ -142,27 +122,27 @@
<Name>Perspex.ReactiveUI</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.SceneGraph\Perspex.SceneGraph.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Project>{EB582467-6ABB-43A1-B052-E981BA910E3A}</Project>
<Name>Perspex.SceneGraph</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Styling\Perspex.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Perspex.Themes.Default\Perspex.Themes.Default.csproj">
<Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
<Project>{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}</Project>
<Name>Perspex.Themes.Default</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Markup\Perspex.Markup.Xaml\Perspex.Markup.Xaml.csproj">
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
<Project>{3E53A01A-B331-47F3-B828-4A5717E77A24}</Project>
<Name>Perspex.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Windows\Perspex.Direct2D1\Perspex.Direct2D1.csproj">
<Project>{3e908f67-5543-4879-a1dc-08eace79b3cd}</Project>
<Project>{3E908F67-5543-4879-A1DC-08EACE79B3CD}</Project>
<Name>Perspex.Direct2D1</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Windows\Perspex.Win32\Perspex.Win32.csproj">
<Project>{811a76cf-1cf6-440f-963b-bbe31bd72a82}</Project>
<Project>{811A76CF-1CF6-440F-963B-BBE31BD72A82}</Project>
<Name>Perspex.Win32</Name>
</ProjectReference>
</ItemGroup>
@ -173,9 +153,9 @@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<Resource Include="Views\MainWindow.xaml">
<EmbeddedResource Include="Views\MainWindow.paml">
<SubType>Designer</SubType>
</Resource>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\src\Shared\perspex.platform.targets" />

4
samples/XamlTestApplication/packages.config

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Glass" version="0.1.0" targetFramework="net451" />
<package id="OmniXaml" version="0.1.0" targetFramework="net451" />
<package id="Rx-Core" version="2.2.5" targetFramework="net46" />
<package id="Rx-Interfaces" version="2.2.5" targetFramework="net46" />
<package id="Rx-Linq" version="2.2.5" targetFramework="net46" />
@ -10,5 +8,5 @@
<package id="Rx-XAML" version="2.2.5" targetFramework="net46" />
<package id="Serilog" version="1.5.9" targetFramework="net46" />
<package id="Splat" version="1.6.2" targetFramework="net46" />
<package id="Sprache.SuperJMN" version="2.0.0.50" targetFramework="net451" />
<package id="Sprache" version="2.0.0.47" targetFramework="net451" />
</packages>

49
src/Gtk/Perspex.Cairo/CairoExtensions.cs

@ -1,8 +1,5 @@
// -----------------------------------------------------------------------
// <copyright file="CairoExtensions.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Perspex.Cairo
{
@ -10,6 +7,11 @@ namespace Perspex.Cairo
public static class CairoExtensions
{
public static Cairo.Color ToCairo(this Perspex.Media.Color color)
{
return new Cairo.Color(color.R / 255.0, color.G / 255.0, color.B / 255.0, color.A / 255.0);
}
public static Cairo.Matrix ToCairo(this Matrix m)
{
return new Cairo.Matrix(m.M11, m.M12, m.M21, m.M22, m.M31, m.M32);
@ -25,6 +27,11 @@ namespace Perspex.Cairo
return new Cairo.Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
}
public static Rect ToPerspex(this Cairo.Rectangle rect)
{
return new Rect(rect.X, rect.Y, rect.Width, rect.Height);
}
public static Rect ToPerspex(this Pango.Rectangle rect)
{
return new Rect(
@ -36,37 +43,7 @@ namespace Perspex.Cairo
public static Pango.Weight ToCairo(this Perspex.Media.FontWeight weight)
{
if (weight == Perspex.Media.FontWeight.Light)
{
return Pango.Weight.Light;
}
if (weight == Perspex.Media.FontWeight.Normal || weight == Perspex.Media.FontWeight.Regular)
{
return Pango.Weight.Normal;
}
if (weight == Perspex.Media.FontWeight.DemiBold || weight == Perspex.Media.FontWeight.Medium)
{
return Pango.Weight.Semibold;
}
if (weight == Perspex.Media.FontWeight.Bold)
{
return Pango.Weight.Bold;
}
if (weight == Perspex.Media.FontWeight.UltraBold || weight == Perspex.Media.FontWeight.ExtraBold)
{
return Pango.Weight.Ultrabold;
}
if (weight == Perspex.Media.FontWeight.Black || weight == Perspex.Media.FontWeight.Heavy || weight == Perspex.Media.FontWeight.UltraBlack)
{
return Pango.Weight.Heavy;
}
return Pango.Weight.Ultralight;
return (Pango.Weight)weight;
}
public static Pango.Alignment ToCairo(this Perspex.Media.TextAlignment alignment)

65
src/Gtk/Perspex.Cairo/CairoPlatform.cs

@ -1,49 +1,48 @@
// -----------------------------------------------------------------------
// <copyright file="CairoPlatform.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Perspex.Cairo.Media;
using Perspex.Cairo.Media.Imaging;
using Perspex.Media;
using Perspex.Platform;
using Splat;
namespace Perspex.Cairo
{
using System;
using System.IO;
using global::Cairo;
using Perspex.Cairo.Media;
using Perspex.Cairo.Media.Imaging;
using Perspex.Media;
using Perspex.Platform;
using Perspex.Threading;
using Splat;
public class CairoPlatform : IPlatformRenderInterface
{
private static CairoPlatform instance = new CairoPlatform();
private static readonly CairoPlatform s_instance = new CairoPlatform();
private static Pango.Context s_pangoContext = CreatePangoContext();
public static void Initialize()
{
var locator = Locator.CurrentMutable;
locator.Register(() => instance, typeof(IPlatformRenderInterface));
locator.Register(() => s_instance, typeof(IPlatformRenderInterface));
}
public IBitmapImpl CreateBitmap(int width, int height)
{
return new BitmapImpl(new ImageSurface(Format.Argb32, width, height));
return new BitmapImpl(new Gdk.Pixbuf(Gdk.Colorspace.Rgb, true, 32, width, height));
}
public IFormattedTextImpl CreateFormattedText(
string text,
string fontFamily,
double fontSize,
string text,
string fontFamily,
double fontSize,
FontStyle fontStyle,
TextAlignment textAlignment,
Perspex.Media.FontWeight fontWeight)
{
return new FormattedTextImpl(text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight);
return new FormattedTextImpl(s_pangoContext, text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight);
}
public IRenderer CreateRenderer(IPlatformHandle handle, double width, double height)
{
Locator.CurrentMutable.RegisterConstant(this.GetPangoContext(handle), typeof(Pango.Context));
return new Renderer(handle, width, height);
}
@ -59,22 +58,22 @@ namespace Perspex.Cairo
public IBitmapImpl LoadBitmap(string fileName)
{
ImageSurface result = new ImageSurface(fileName);
return new BitmapImpl(result);
var pixbuf = new Gdk.Pixbuf(fileName);
return new BitmapImpl(pixbuf);
}
public IBitmapImpl LoadBitmap(Stream stream)
{
var pixbuf = new Gdk.Pixbuf(stream);
return new BitmapImpl(pixbuf);
}
private Pango.Context GetPangoContext(IPlatformHandle handle)
private static Pango.Context CreatePangoContext()
{
switch (handle.HandleDescriptor)
{
case "GtkWindow":
var window = GLib.Object.GetObject(handle.Handle) as Gtk.Window;
return window.PangoContext;
default:
throw new NotSupportedException(string.Format(
"Don't know how to get a Pango Context from a '{0}'.",
handle.HandleDescriptor));
}
Gtk.Application.Init();
return new Gtk.Invisible().CreatePangoContext();
}
}
}

17
src/Gtk/Perspex.Cairo/Media/BrushImpl.cs

@ -0,0 +1,17 @@
using System;
using global::Cairo;
namespace Perspex.Cairo
{
public abstract class BrushImpl : IDisposable
{
public Pattern PlatformBrush { get; protected set; }
public void Dispose()
{
if (this.PlatformBrush != null)
this.PlatformBrush.Dispose();
}
}
}

312
src/Gtk/Perspex.Cairo/Media/DrawingContext.cs

@ -1,19 +1,16 @@
// -----------------------------------------------------------------------
// <copyright file="DrawingContext.cs" company="Steven Kirk">
// Copyright 2013 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Linq;
using System.Reactive.Disposables;
using Perspex.Cairo.Media.Imaging;
using Perspex.Media;
namespace Perspex.Cairo.Media
{
using System;
using System.Reactive.Disposables;
using Perspex.Cairo.Media.Imaging;
using Perspex.Media;
using Perspex.Platform;
using Splat;
using Perspex.Media.Imaging;
using Cairo = global::Cairo;
using IBitmap = Perspex.Media.Imaging.IBitmap;
using System.Collections.Generic;
/// <summary>
/// Draws using Direct2D1.
@ -23,12 +20,7 @@ namespace Perspex.Cairo.Media
/// <summary>
/// The cairo context.
/// </summary>
private Cairo.Context context;
/// <summary>
/// The cairo surface.
/// </summary>
private Cairo.Surface surface;
private readonly Cairo.Context _context;
/// <summary>
/// Initializes a new instance of the <see cref="DrawingContext"/> class.
@ -36,9 +28,8 @@ namespace Perspex.Cairo.Media
/// <param name="surface">The target surface.</param>
public DrawingContext(Cairo.Surface surface)
{
this.surface = surface;
this.context = new Cairo.Context(surface);
this.CurrentTransform = Matrix.Identity;
_context = new Cairo.Context(surface);
CurrentTransform = Matrix.Identity;
}
/// <summary>
@ -47,50 +38,68 @@ namespace Perspex.Cairo.Media
/// <param name="surface">The GDK drawable.</param>
public DrawingContext(Gdk.Drawable drawable)
{
this.Drawable = drawable;
this.context = Gdk.CairoHelper.Create(drawable);
this.CurrentTransform = Matrix.Identity;
_context = Gdk.CairoHelper.Create(drawable);
CurrentTransform = Matrix.Identity;
}
/// <summary>
/// Gets the current transform of the drawing context.
/// </summary>
public Matrix CurrentTransform
{
get;
private set;
}
public Gdk.Drawable Drawable
{
get;
private set;
}
get; }
/// <summary>
/// Ends a draw operation.
/// </summary>
public void Dispose()
{
this.context.Dispose();
// if (this.surface is Cairo.Win32Surface)
// {
if (this.surface != null)
this.surface.Dispose();
// }
_context.Dispose();
}
/// <summary>
/// Draws a bitmap image.
/// </summary>
/// <param name="source">The bitmap image.</param>
/// <param name="opacity">The opacity to draw with.</param>
/// <param name="sourceRect">The rect in the image to draw.</param>
/// <param name="destRect">The rect in the output to draw to.</param>
public void DrawImage(IBitmap bitmap, double opacity, Rect sourceRect, Rect destRect)
{
var impl = bitmap.PlatformImpl as BitmapImpl;
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(sourceRect.ToCairo());
this.context.Fill();
this.context.Restore();
var scale = new Vector(destRect.Width / sourceRect.Width, destRect.Height / sourceRect.Height);
_context.Save();
_context.Scale(scale.X, scale.Y);
destRect /= scale;
if (opacityOverride < 1.0f) {
_context.PushGroup ();
Gdk.CairoHelper.SetSourcePixbuf (
_context,
impl.Surface,
-sourceRect.X + destRect.X,
-sourceRect.Y + destRect.Y);
_context.Rectangle (destRect.ToCairo ());
_context.Fill ();
_context.PopGroupToSource ();
_context.PaintWithAlpha (opacityOverride);
} else {
_context.PushGroup ();
Gdk.CairoHelper.SetSourcePixbuf (
_context,
impl.Surface,
-sourceRect.X + destRect.X,
-sourceRect.Y + destRect.Y);
_context.Rectangle (destRect.ToCairo ());
_context.Fill ();
_context.PopGroupToSource ();
_context.PaintWithAlpha (opacityOverride);
}
_context.Restore();
}
/// <summary>
@ -99,15 +108,16 @@ namespace Perspex.Cairo.Media
/// <param name="pen">The stroke pen.</param>
/// <param name="p1">The first point of the line.</param>
/// <param name="p1">The second point of the line.</param>
public void DrawLine(Pen pen, Perspex.Point p1, Perspex.Point p2)
public void DrawLine(Pen pen, Point p1, Point p2)
{
var size = new Rect(p1, p2).Size;
this.SetBrush(pen.Brush, size);
this.context.LineWidth = pen.Thickness;
this.context.MoveTo(p1.ToCairo());
this.context.LineTo(p2.ToCairo());
this.context.Stroke();
using (var p = SetPen(pen, size))
{
_context.MoveTo(p1.ToCairo());
_context.LineTo(p2.ToCairo());
_context.Stroke();
}
}
/// <summary>
@ -116,55 +126,32 @@ namespace Perspex.Cairo.Media
/// <param name="brush">The fill brush.</param>
/// <param name="pen">The stroke pen.</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(Brush brush, Pen pen, Geometry geometry)
{
var impl = geometry.PlatformImpl as StreamGeometryImpl;
var clone = new Queue<GeometryOp>(impl.Operations);
using (var pop = this.PushTransform(impl.Transform))
using (var pop = 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());
}
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());
}
}
_context.AppendPath(impl.Path);
if (brush != null)
{
this.SetBrush(brush, geometry.Bounds.Size);
if (pen != null)
this.context.FillPreserve();
else
this.context.Fill();
using (var b = SetBrush(brush, geometry.Bounds.Size))
{
if (pen != null)
_context.FillPreserve();
else
_context.Fill();
}
}
}
if (pen != null)
{
this.SetPen(pen, geometry.Bounds.Size);
this.context.Stroke();
}
if (pen != null)
{
using (var p = SetPen(pen, geometry.Bounds.Size))
{
_context.Stroke();
}
}
}
@ -175,9 +162,11 @@ namespace Perspex.Cairo.Media
/// <param name="rect">The rectangle bounds.</param>
public void DrawRectange(Pen pen, Rect rect, float cornerRadius)
{
this.SetPen(pen, rect.Size);
this.context.Rectangle(rect.ToCairo());
this.context.Stroke();
using (var p = SetPen(pen, rect.Size))
{
_context.Rectangle(rect.ToCairo ());
_context.Stroke();
}
}
/// <summary>
@ -189,10 +178,12 @@ namespace Perspex.Cairo.Media
public void DrawText(Brush foreground, Point origin, FormattedText text)
{
var layout = ((FormattedTextImpl)text.PlatformImpl).Layout;
this.SetBrush(foreground, new Size(0, 0));
this.context.MoveTo(origin.X, origin.Y);
Pango.CairoHelper.ShowLayout(this.context, layout);
_context.MoveTo(origin.X, origin.Y);
using (var b = SetBrush(foreground, new Size(0, 0)))
{
Pango.CairoHelper.ShowLayout(_context, layout);
}
}
/// <summary>
@ -200,11 +191,13 @@ namespace Perspex.Cairo.Media
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="rect">The rectangle bounds.</param>
public void FillRectange(Perspex.Media.Brush brush, Rect rect, float cornerRadius)
public void FillRectange(Brush brush, Rect rect, float cornerRadius)
{
this.SetBrush(brush, rect.Size);
this.context.Rectangle(rect.ToCairo());
this.context.Fill();
using (var b = SetBrush(brush, rect.Size))
{
_context.Rectangle(rect.ToCairo ());
_context.Fill();
}
}
/// <summary>
@ -214,10 +207,10 @@ namespace Perspex.Cairo.Media
/// <returns>A disposable used to undo the clip rectangle.</returns>
public IDisposable PushClip(Rect clip)
{
this.context.Rectangle(clip.ToCairo());
this.context.Clip();
_context.Rectangle(clip.ToCairo());
_context.Clip();
return Disposable.Create(() => this.context.ResetClip());
return Disposable.Create(() => _context.ResetClip());
}
/// <summary>
@ -227,8 +220,15 @@ namespace Perspex.Cairo.Media
/// <returns>A disposable used to undo the opacity.</returns>
public IDisposable PushOpacity(double opacity)
{
// TODO: Implement
return Disposable.Empty;
var tmp = opacityOverride;
if (opacity < 1.0f)
opacityOverride = opacity;
return Disposable.Create(() =>
{
opacityOverride = tmp;
});
}
/// <summary>
@ -238,44 +238,84 @@ namespace Perspex.Cairo.Media
/// <returns>A disposable used to undo the transformation.</returns>
public IDisposable PushTransform(Matrix matrix)
{
this.context.Transform(matrix.ToCairo());
_context.Transform(matrix.ToCairo());
return Disposable.Create(() =>
{
this.context.Transform(matrix.Invert().ToCairo());
_context.Transform(matrix.Invert().ToCairo());
});
}
private double opacityOverride = 1.0f;
private void SetBrush(Brush brush, Size destinationSize)
private IDisposable SetBrush(Brush brush, Size destinationSize)
{
_context.Save ();
var solid = brush as SolidColorBrush;
var linearGradientBrush = brush as LinearGradientBrush;
var radialGradientBrush = brush as RadialGradientBrush;
var imageBrush = brush as ImageBrush;
var visualBrush = brush as VisualBrush;
BrushImpl impl = null;
if (solid != null)
if (solid != null)
{
impl = new SolidColorBrushImpl(solid, opacityOverride);
}
else if (linearGradientBrush != null)
{
impl = new LinearGradientBrushImpl(linearGradientBrush, destinationSize);
}
else if (radialGradientBrush != null)
{
this.context.SetSourceRGBA(
solid.Color.R / 255.0,
solid.Color.G / 255.0,
solid.Color.B / 255.0,
solid.Color.A / 255.0);
impl = new RadialGradientBrushImpl(radialGradientBrush, destinationSize);
}
else if (linearGradientBrush != null)
{
Cairo.LinearGradient g = new Cairo.LinearGradient(linearGradientBrush.StartPoint.X * destinationSize.Width, linearGradientBrush.StartPoint.Y * destinationSize.Height, linearGradientBrush.EndPoint.X * destinationSize.Width, linearGradientBrush.EndPoint.Y * destinationSize.Height);
foreach (var s in linearGradientBrush.GradientStops)
g.AddColorStopRgb(s.Offset, new Cairo.Color(s.Color.R, s.Color.G, s.Color.B, s.Color.A));
g.Extend = Cairo.Extend.Pad;
else if (imageBrush != null)
{
impl = new ImageBrushImpl(imageBrush, destinationSize);
}
else if (visualBrush != null)
{
impl = new VisualBrushImpl(visualBrush, destinationSize);
}
else
{
impl = new SolidColorBrushImpl(null, opacityOverride);
}
this.context.SetSource(g);
}
_context.SetSource(impl.PlatformBrush);
return Disposable.Create(() =>
{
impl.Dispose();
_context.Restore();
});
}
private void SetPen(Pen pen, Size destinationSize)
private IDisposable SetPen(Pen pen, Size destinationSize)
{
this.SetBrush(pen.Brush, destinationSize);
this.context.LineWidth = pen.Thickness;
if (pen.DashStyle != null)
{
if (pen.DashStyle.Dashes != null && pen.DashStyle.Dashes.Count > 0)
{
var cray = pen.DashStyle.Dashes.ToArray();
_context.SetDash(cray, pen.DashStyle.Offset);
}
}
_context.LineWidth = pen.Thickness;
_context.MiterLimit = pen.MiterLimit;
// Line caps and joins are currently broken on Cairo. I've defaulted them to sensible defaults for now.
// Cairo does not have StartLineCap, EndLineCap, and DashCap properties, whereas Direct2D does.
// TODO: Figure out a solution for this.
_context.LineJoin = Cairo.LineJoin.Miter;
_context.LineCap = Cairo.LineCap.Butt;
if (pen.Brush == null)
return Disposable.Empty;
return SetBrush(pen.Brush, destinationSize);
}
}
}

94
src/Gtk/Perspex.Cairo/Media/FormattedTextImpl.cs

@ -1,21 +1,23 @@
// -----------------------------------------------------------------------
// <copyright file="FormattedTextImpl.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Perspex.Media;
using Perspex.Platform;
using Splat;
namespace Perspex.Cairo.Media
{
using System;
using System.Collections.Generic;
using System.Linq;
using Perspex.Media;
using Perspex.Platform;
using Splat;
public class FormattedTextImpl : IFormattedTextImpl
{
private Size _size;
private string _text;
public FormattedTextImpl(
Pango.Context context,
string text,
string fontFamily,
double fontSize,
@ -23,44 +25,46 @@ namespace Perspex.Cairo.Media
TextAlignment textAlignment,
FontWeight fontWeight)
{
var context = Locator.Current.GetService<Pango.Context>();
this.Layout = new Pango.Layout(context);
this.Layout.SetText(text);
this.Layout.FontDescription = new Pango.FontDescription
Contract.Requires<NullReferenceException>(context != null);
Layout = new Pango.Layout(context);
_text = text;
Layout.SetText(text);
Layout.FontDescription = new Pango.FontDescription
{
Family = fontFamily,
Size = Pango.Units.FromDouble(fontSize * 0.73),
Size = Pango.Units.FromDouble(fontSize),
Style = (Pango.Style)fontStyle,
Weight = fontWeight.ToCairo()
};
this.Layout.Alignment = textAlignment.ToCairo();
Layout.Alignment = textAlignment.ToCairo();
Layout.Attributes = new Pango.AttrList();
}
private Size size;
public Size Constraint
{
get
{
return size;
return _size;
}
set
{
this.size = value;
this.Layout.Width = Pango.Units.FromDouble(value.Width);
_size = value;
Layout.Width = double.IsPositiveInfinity(value.Width) ?
-1 : Pango.Units.FromDouble(value.Width);
}
}
public Pango.Layout Layout
{
get;
private set;
}
public void Dispose()
{
this.Layout.Dispose();
Layout.Dispose();
}
public IEnumerable<FormattedTextLine> GetLines()
@ -73,12 +77,14 @@ namespace Perspex.Cairo.Media
int textPosition;
int trailing;
var isInside = this.Layout.XyToIndex(
var isInside = Layout.XyToIndex(
Pango.Units.FromDouble(point.X),
Pango.Units.FromDouble(point.Y),
out textPosition,
out trailing);
textPosition = PangoIndexToTextIndex(textPosition);
return new TextHitTestResult
{
IsInside = isInside,
@ -87,20 +93,30 @@ namespace Perspex.Cairo.Media
};
}
int PangoIndexToTextIndex(int pangoIndex)
{
return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(_text), 0, Math.Min(pangoIndex, _text.Length)).Length;
}
public Rect HitTestTextPosition(int index)
{
return this.Layout.IndexToPos(index).ToPerspex();
return Layout.IndexToPos(TextIndexToPangoIndex(index)).ToPerspex();
}
int TextIndexToPangoIndex(int textIndex)
{
return Encoding.UTF8.GetByteCount(textIndex < _text.Length ? _text.Remove(textIndex) : _text);
}
public IEnumerable<Rect> HitTestTextRange(int index, int length)
{
var ranges = new List<Rect>();
for (var i = 0; i < length; i++)
{
ranges.Add(this.HitTestTextPosition(index+i));
ranges.Add(HitTestTextPosition(index + i));
}
return ranges;
}
@ -108,14 +124,26 @@ namespace Perspex.Cairo.Media
{
int width;
int height;
this.Layout.GetPixelSize(out width, out height);
Layout.GetPixelSize(out width, out height);
return new Size(width, height);
}
public void SetForegroundBrush(Brush brush, int startIndex, int count)
{
// TODO: Implement.
var scb = brush as SolidColorBrush;
if (scb != null)
{
var color = new Pango.Color();
color.Parse(string.Format("#{0}", scb.Color.ToString().Substring(3)));
var brushAttr = new Pango.AttrForeground(color);
brushAttr.StartIndex = (uint)TextIndexToPangoIndex(startIndex);
brushAttr.EndIndex = (uint)TextIndexToPangoIndex(startIndex + count);
Layout.Attributes.Insert(brushAttr);
}
}
}
}

14
src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs

@ -0,0 +1,14 @@
using System;
using global::Cairo;
namespace Perspex.Cairo.Media
{
public class ImageBrushImpl : BrushImpl
{
public ImageBrushImpl(Perspex.Media.ImageBrush brush, Size destinationSize)
{
this.PlatformBrush = TileBrushes.CreateImageBrush(brush, destinationSize);
}
}
}

32
src/Gtk/Perspex.Cairo/Media/Imaging/BitmapImpl.cs

@ -1,41 +1,33 @@
// -----------------------------------------------------------------------
// <copyright file="BitmapImpl.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Perspex.Platform;
namespace Perspex.Cairo.Media.Imaging
{
using System;
using Perspex.Platform;
using Cairo = global::Cairo;
public class BitmapImpl : IBitmapImpl
{
public BitmapImpl(Cairo.ImageSurface surface)
public BitmapImpl(Gdk.Pixbuf pixbuf)
{
this.Surface = surface;
Surface = pixbuf;
}
public int PixelWidth
{
get { return this.Surface.Width; }
}
public int PixelWidth => Surface.Width;
public int PixelHeight
{
get { return this.Surface.Height; }
}
public int PixelHeight => Surface.Height;
public Cairo.ImageSurface Surface
public Gdk.Pixbuf Surface
{
get;
private set;
}
public void Save(string fileName)
{
this.Surface.WriteToPng(fileName);
// TODO: Test
Surface.Save(fileName, "png");
}
}
}

38
src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs

@ -1,32 +1,44 @@
// -----------------------------------------------------------------------
// <copyright file="RenderTargetBitmapImpl.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Perspex.Platform;
namespace Perspex.Cairo.Media.Imaging
{
using System;
using Perspex.Platform;
using Cairo = global::Cairo;
public class RenderTargetBitmapImpl : BitmapImpl, IRenderTargetBitmapImpl
public class RenderTargetBitmapImpl : IRenderTargetBitmapImpl
{
public RenderTargetBitmapImpl(
Cairo.ImageSurface surface)
: base(surface)
public RenderTargetBitmapImpl(Cairo.ImageSurface surface)
{
Surface = surface;
renderer = new Renderer(Surface);
}
public int PixelWidth => Surface.Width;
public int PixelHeight => Surface.Height;
public void Dispose()
{
this.Surface.Dispose();
renderer.Dispose();
}
public Cairo.ImageSurface Surface
{
get;
}
private Renderer renderer;
public void Render(IVisual visual)
{
Renderer renderer = new Renderer(this.Surface);
renderer.Render(visual, new PlatformHandle(IntPtr.Zero, "RTB"));
}
public void Save(string fileName)
{
Surface.WriteToPng(fileName);
}
}
}

22
src/Gtk/Perspex.Cairo/Media/LinearGradientBrushImpl.cs

@ -0,0 +1,22 @@
using System;
using global::Cairo;
namespace Perspex.Cairo
{
public class LinearGradientBrushImpl : BrushImpl
{
public LinearGradientBrushImpl(Perspex.Media.LinearGradientBrush brush, Size destinationSize)
{
var start = brush.StartPoint.ToPixels(destinationSize);
var end = brush.EndPoint.ToPixels(destinationSize);
this.PlatformBrush = new LinearGradient(start.X, start.Y, end.X, end.Y);
foreach (var stop in brush.GradientStops)
((LinearGradient)this.PlatformBrush).AddColorStop(stop.Offset, stop.Color.ToCairo());
((LinearGradient)this.PlatformBrush).Extend = Extend.Pad;
}
}
}

25
src/Gtk/Perspex.Cairo/Media/RadialGradientBrushImpl.cs

@ -0,0 +1,25 @@
using System;
using global::Cairo;
namespace Perspex.Cairo
{
public class RadialGradientBrushImpl : BrushImpl
{
public RadialGradientBrushImpl(Perspex.Media.RadialGradientBrush brush, Size destinationSize)
{
var center = brush.Center.ToPixels(destinationSize);
var gradientOrigin = brush.GradientOrigin.ToPixels(destinationSize);
var radius = brush.Radius;
this.PlatformBrush = new RadialGradient(center.X, center.Y, radius, gradientOrigin.X, gradientOrigin.Y, radius);
foreach (var stop in brush.GradientStops)
{
((LinearGradient)this.PlatformBrush).AddColorStop(stop.Offset, stop.Color.ToCairo());
}
((LinearGradient)this.PlatformBrush).Extend = Extend.Pad;
}
}
}

22
src/Gtk/Perspex.Cairo/Media/SolidColorBrushImpl.cs

@ -0,0 +1,22 @@
using System;
using global::Cairo;
namespace Perspex.Cairo
{
public class SolidColorBrushImpl : BrushImpl
{
public SolidColorBrushImpl(Perspex.Media.SolidColorBrush brush, double opacityOverride = 1.0f)
{
var color = brush?.Color.ToCairo() ?? new Color();
if (brush != null)
color.A = Math.Min(brush.Opacity, color.A);
if (opacityOverride < 1.0f)
color.A = Math.Min(opacityOverride, color.A);
this.PlatformBrush = new SolidPattern(color);
}
}
}

88
src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs

@ -1,25 +1,28 @@
// -----------------------------------------------------------------------
// <copyright file="StreamGeometryContextImpl.cs" company="Steven Kirk">
// Copyright 2013 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Perspex.Media;
using Perspex.Platform;
namespace Perspex.Cairo.Media
{
using Perspex.Media;
using Perspex.Platform;
using System;
using System.Collections.Generic;
using Cairo = global::Cairo;
public class StreamGeometryContextImpl : IStreamGeometryContextImpl
{
private StreamGeometryImpl impl;
public StreamGeometryContextImpl(StreamGeometryImpl imp)
public StreamGeometryContextImpl(Cairo.Path path = null)
{
this.impl = imp;
this.surf = new Cairo.ImageSurface(Cairo.Format.Argb32, 0, 0);
this.context = new Cairo.Context(this.surf);
_surf = new Cairo.ImageSurface (Cairo.Format.Argb32, 0, 0);
_context = new Cairo.Context (_surf);
this.Path = path;
if (this.Path != null)
{
_context.AppendPath(this.Path);
}
}
public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
@ -28,62 +31,43 @@ namespace Perspex.Cairo.Media
public void BeginFigure(Point startPoint, bool isFilled)
{
this.impl.Operations.Enqueue(new BeginOp { Point = startPoint, IsFilled = isFilled });
if (this.Path == null)
_context.MoveTo(startPoint.ToCairo());
}
public void BezierTo(Point point1, Point point2, Point point3)
{
this.impl.Operations.Enqueue(new CurveToOp { Point = point1, Point2 = point2, Point3 = point3 });
if (this.Path == null)
_context.CurveTo(point1.ToCairo(), point2.ToCairo(), point3.ToCairo());
}
public void LineTo(Point point)
{
this.impl.Operations.Enqueue(new LineToOp { Point = point });
if (this.Path == null)
_context.LineTo(point.ToCairo());
}
private Cairo.Context context;
private Cairo.ImageSurface surf;
private readonly Cairo.Context _context;
private readonly Cairo.ImageSurface _surf;
public Cairo.Path Path { get; private set; }
public Rect Bounds { get; private set; }
public void EndFigure(bool isClosed)
{
this.impl.Operations.Enqueue(new EndOp { IsClosed = isClosed });
var clone = new Queue<GeometryOp>(this.impl.Operations);
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());
}
}
if (this.Path == null)
{
if (isClosed)
_context.ClosePath ();
var extents = context.StrokeExtents();
this.impl.Bounds = new Rect(extents.X, extents.Y, extents.Width, extents.Height);
Path = _context.CopyPath ();
Bounds = _context.FillExtents ().ToPerspex ();
}
}
public void Dispose()
{
context.Dispose();
surf.Dispose();
_context.Dispose ();
_surf.Dispose ();
}
}
}

101
src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs

@ -1,107 +1,70 @@
// -----------------------------------------------------------------------
// <copyright file="StreamGeometryImpl.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Perspex.Media;
using Perspex.Platform;
using Splat;
using System.Collections.Generic;
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()
{
this.Operations = new Queue<GeometryOp>();
_impl = new StreamGeometryContextImpl(null);
}
public StreamGeometryImpl(Queue<GeometryOp> ops)
public StreamGeometryImpl(StreamGeometryContextImpl impl)
{
this.Operations = ops;
}
public Queue<GeometryOp> Operations
{
get;
private set;
_impl = impl;
}
public Rect Bounds
{
get;
set;
}
get { return _impl.Bounds; }
}
// TODO: Implement
private Matrix transform = Matrix.Identity;
public Cairo.Path Path
{
get { return _impl.Path; }
}
private readonly StreamGeometryContextImpl _impl;
private Matrix _transform = Matrix.Identity;
public Matrix Transform
{
get { return this.transform; }
get { return _transform; }
set
{
if (value != this.Transform)
if (value != Transform)
{
if (!value.IsIdentity)
{
this.transform = value;
}
if (!value.IsIdentity)
{
_transform = value;
}
}
}
}
public IStreamGeometryImpl Clone()
{
return new StreamGeometryImpl(this.Operations);
{
return new StreamGeometryImpl(_impl);
}
public Rect GetRenderBounds(double strokeThickness)
{
return this.Bounds;
// TODO: Calculate properly.
return Bounds.Inflate(strokeThickness);
}
public IStreamGeometryContextImpl Open()
{
return new StreamGeometryContextImpl(this);
return _impl;
}
}
}

224
src/Gtk/Perspex.Cairo/Media/TileBrushes.cs

@ -0,0 +1,224 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Cairo;
using Perspex.Cairo.Media.Imaging;
using Perspex.Layout;
using Perspex.Media;
using Perspex.Platform;
namespace Perspex.Cairo.Media
{
internal static class TileBrushes
{
public static SurfacePattern CreateImageBrush(ImageBrush brush, Size targetSize)
{
if (brush.Source == null)
{
return null;
}
// TODO: This is directly ported from Direct2D and could probably be made more
// efficient on cairo by taking advantage of the fact that cairo has Extend.None.
var image = ((BitmapImpl)brush.Source.PlatformImpl).Surface;
var imageSize = new Size(brush.Source.PixelWidth, brush.Source.PixelHeight);
var tileMode = brush.TileMode;
var sourceRect = brush.SourceRect.ToPixels(imageSize);
var destinationRect = brush.DestinationRect.ToPixels(targetSize);
var scale = brush.Stretch.CalculateScaling(destinationRect.Size, sourceRect.Size);
var translate = CalculateTranslate(brush, sourceRect, destinationRect, scale);
var intermediateSize = CalculateIntermediateSize(tileMode, targetSize, destinationRect.Size);
var intermediate = new ImageSurface (Format.ARGB32, (int)intermediateSize.Width, (int)intermediateSize.Height);
using (var context = new Context(intermediate))
{
Rect drawRect;
var transform = CalculateIntermediateTransform(
tileMode,
sourceRect,
destinationRect,
scale,
translate,
out drawRect);
context.Rectangle(drawRect.ToCairo());
context.Clip();
context.Transform(transform.ToCairo());
Gdk.CairoHelper.SetSourcePixbuf(context, image, 0, 0);
context.Rectangle(0, 0, imageSize.Width, imageSize.Height);
context.Fill();
var result = new SurfacePattern(intermediate);
if ((brush.TileMode & TileMode.FlipXY) != 0)
{
// TODO: Currently always FlipXY as that's all cairo supports natively.
// Support separate FlipX and FlipY by drawing flipped images to intermediate
// surface.
result.Extend = Extend.Reflect;
}
else
{
result.Extend = Extend.Repeat;
}
if (brush.TileMode != TileMode.None)
{
var matrix = result.Matrix;
matrix.InitTranslate(-destinationRect.X, -destinationRect.Y);
result.Matrix = matrix;
}
return result;
}
}
public static SurfacePattern CreateVisualBrush(VisualBrush brush, Size targetSize)
{
var visual = brush.Visual;
if (visual == null)
{
return null;
}
var layoutable = visual as ILayoutable;
if (layoutable?.IsArrangeValid == false)
{
layoutable.Measure(Size.Infinity);
layoutable.Arrange(new Rect(layoutable.DesiredSize));
}
// TODO: This is directly ported from Direct2D and could probably be made more
// efficient on cairo by taking advantage of the fact that cairo has Extend.None.
var tileMode = brush.TileMode;
var sourceRect = brush.SourceRect.ToPixels(layoutable.Bounds.Size);
var destinationRect = brush.DestinationRect.ToPixels(targetSize);
var scale = brush.Stretch.CalculateScaling(destinationRect.Size, sourceRect.Size);
var translate = CalculateTranslate(brush, sourceRect, destinationRect, scale);
var intermediateSize = CalculateIntermediateSize(tileMode, targetSize, destinationRect.Size);
using (var intermediate = new ImageSurface(Format.ARGB32, (int)intermediateSize.Width, (int)intermediateSize.Height))
using (var context = new Context(intermediate))
{
Rect drawRect;
var transform = CalculateIntermediateTransform(
tileMode,
sourceRect,
destinationRect,
scale,
translate,
out drawRect);
var renderer = new Renderer(intermediate);
context.Rectangle(drawRect.ToCairo());
context.Clip();
context.Transform(transform.ToCairo());
renderer.Render(visual, new PlatformHandle(IntPtr.Zero, "RTB"), transform, drawRect);
var result = new SurfacePattern(intermediate);
if ((brush.TileMode & TileMode.FlipXY) != 0)
{
// TODO: Currently always FlipXY as that's all cairo supports natively.
// Support separate FlipX and FlipY by drawing flipped images to intermediate
// surface.
result.Extend = Extend.Reflect;
}
else
{
result.Extend = Extend.Repeat;
}
if (brush.TileMode != TileMode.None)
{
var matrix = result.Matrix;
matrix.InitTranslate(-destinationRect.X, -destinationRect.Y);
result.Matrix = matrix;
}
return result;
}
}
/// <summary>
/// Calculates a translate based on a <see cref="TileBrush"/>, a source and destination
/// rectangle and a scale.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="sourceRect">The source rectangle.</param>
/// <param name="destinationRect">The destination rectangle.</param>
/// <param name="scale">The scale factor.</param>
/// <returns>A vector with the X and Y translate.</returns>
private static Vector CalculateTranslate(
TileBrush brush,
Rect sourceRect,
Rect destinationRect,
Vector scale)
{
var x = 0.0;
var y = 0.0;
var size = sourceRect.Size * scale;
switch (brush.AlignmentX)
{
case AlignmentX.Center:
x += (destinationRect.Width - size.Width) / 2;
break;
case AlignmentX.Right:
x += destinationRect.Width - size.Width;
break;
}
switch (brush.AlignmentY)
{
case AlignmentY.Center:
y += (destinationRect.Height - size.Height) / 2;
break;
case AlignmentY.Bottom:
y += destinationRect.Height - size.Height;
break;
}
return new Vector(x, y);
}
private static Size CalculateIntermediateSize(
TileMode tileMode,
Size targetSize,
Size destinationSize)
{
var result = tileMode == TileMode.None ? targetSize : destinationSize;
return result;
}
private static Matrix CalculateIntermediateTransform(
TileMode tileMode,
Rect sourceRect,
Rect destinationRect,
Vector scale,
Vector translate,
out Rect drawRect)
{
var transform = Matrix.CreateTranslation(-sourceRect.Position) *
Matrix.CreateScale(scale) *
Matrix.CreateTranslation(translate);
Rect dr;
if (tileMode == TileMode.None)
{
dr = destinationRect;
transform *= Matrix.CreateTranslation(destinationRect.Position);
}
else
{
dr = new Rect(destinationRect.Size);
}
drawRect = dr;
return transform;
}
}
}

14
src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs

@ -0,0 +1,14 @@
using System;
using global::Cairo;
namespace Perspex.Cairo.Media
{
public class VisualBrushImpl : BrushImpl
{
public VisualBrushImpl(Perspex.Media.VisualBrush brush, Size destinationSize)
{
this.PlatformBrush = TileBrushes.CreateVisualBrush(brush, destinationSize);
}
}
}

41
src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj

@ -32,22 +32,10 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL">
<Package>gtk-sharp-2.0</Package>
</Reference>
<Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL">
<Package>glib-sharp-2.0</Package>
</Reference>
<Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL">
<Package>gtk-sharp-2.0</Package>
</Reference>
<Reference Include="pango-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL">
<Package>gtk-sharp-2.0</Package>
</Reference>
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
<Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
<Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
<Reference Include="pango-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@ -62,8 +50,9 @@
<Reference Include="System.Reactive.Interfaces">
<HintPath>..\..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll</HintPath>
</Reference>
<Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<Package>gtk-sharp-2.0</Package>
<Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\..\..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@ -72,31 +61,43 @@
<Compile Include="Media\FormattedTextImpl.cs" />
<Compile Include="Media\Imaging\BitmapImpl.cs" />
<Compile Include="Media\Imaging\RenderTargetBitmapImpl.cs" />
<Compile Include="Media\RadialGradientBrushImpl.cs" />
<Compile Include="Media\TileBrushes.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Renderer.cs" />
<Compile Include="CairoExtensions.cs" />
<Compile Include="Media\StreamGeometryContextImpl.cs" />
<Compile Include="Media\StreamGeometryImpl.cs" />
<Compile Include="Media\BrushImpl.cs" />
<Compile Include="Media\SolidColorBrushImpl.cs" />
<Compile Include="Media\LinearGradientBrushImpl.cs" />
<Compile Include="Media\ImageBrushImpl.cs" />
<Compile Include="Media\VisualBrushImpl.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Perspex.Animation\Perspex.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Project>{D211E587-D8BC-45B9-95A4-F297C8FA5200}</Project>
<Name>Perspex.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Base\Perspex.Base.csproj">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Perspex.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Layout\Perspex.Layout.csproj">
<Project>{42472427-4774-4C81-8AFF-9F27B8E31721}</Project>
<Name>Perspex.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.SceneGraph\Perspex.SceneGraph.csproj">
<Project>{EB582467-6ABB-43A1-B052-E981BA910E3A}</Project>
<Name>Perspex.SceneGraph</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>

9
src/Gtk/Perspex.Cairo/Properties/AssemblyInfo.cs

@ -1,8 +1,5 @@
// -----------------------------------------------------------------------
// <copyright file="AssemblyInfo.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Reflection;
using System.Runtime.CompilerServices;
@ -16,7 +13,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Perspex.Cairo")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyCopyright("Copyright \u00A9 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

44
src/Gtk/Perspex.Cairo/Renderer.cs

@ -1,26 +1,24 @@
// -----------------------------------------------------------------------
// <copyright file="Renderer.cs" company="Steven Kirk">
// Copyright 2013 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Runtime.InteropServices;
using Perspex.Cairo.Media;
using Perspex.Media;
using Perspex.Platform;
using Perspex.Rendering;
namespace Perspex.Cairo
{
using System;
using System.Runtime.InteropServices;
using global::Cairo;
using Perspex.Cairo.Media;
using Perspex.Media;
using Perspex.Platform;
using Perspex.Rendering;
using Matrix = Perspex.Matrix;
/// <summary>
/// A cairo renderer.
/// </summary>
public class Renderer : RendererBase
{
private ImageSurface surface;
private readonly Surface _surface;
private Gdk.Window _window;
/// <summary>
/// Initializes a new instance of the <see cref="Renderer"/> class.
@ -34,7 +32,7 @@ namespace Perspex.Cairo
public Renderer(ImageSurface surface)
{
this.surface = surface;
_surface = surface;
}
/// <summary>
@ -47,6 +45,7 @@ namespace Perspex.Cairo
// Don't need to do anything here.
}
/// <summary>
/// Creates a cairo surface that targets a platform-specific resource.
/// </summary>
@ -56,14 +55,13 @@ namespace Perspex.Cairo
{
switch (handle.HandleDescriptor)
{
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));
return new DrawingContext(_surface);
case "GdkWindow":
return new DrawingContext(new Gdk.Window(handle.Handle));
if (_window == null)
_window = new Gdk.Window(handle.Handle);
return new DrawingContext(_window);
default:
throw new NotSupportedException(string.Format(
"Don't know how to create a Cairo renderer from a '{0}' handle",
@ -73,5 +71,11 @@ namespace Perspex.Cairo
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);
public override void Dispose()
{
if (_surface != null)
_surface.Dispose();
}
}
}

11
src/Gtk/Perspex.Cairo/app.config

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Mono.Cairo" publicKeyToken="0738eb9f132ed756" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

2
src/Gtk/Perspex.Cairo/packages.config

@ -3,4 +3,4 @@
<package id="Rx-Core" version="2.2.5" targetFramework="net45" userInstalled="true" />
<package id="Rx-Interfaces" version="2.2.5" targetFramework="net45" userInstalled="true" />
<package id="Splat" version="1.6.2" targetFramework="net45" userInstalled="true" />
</packages>
</packages>

48
src/Gtk/Perspex.Gtk/AssetLoader.cs

@ -1,48 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="AssetLoader.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Gtk
{
using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Resources;
using Perspex.Platform;
/// <summary>
/// Loads assets compiled into the application binary.
/// </summary>
public class AssetLoader : IAssetLoader
{
/// <summary>
/// Opens the resource with the requested URI.
/// </summary>
/// <param name="uri">The URI.</param>
/// <returns>A stream containing the resource contents.</returns>
/// <exception cref="FileNotFoundException">
/// The resource was not found.
/// </exception>
public Stream Open(Uri uri)
{
var assembly = Assembly.GetEntryAssembly();
var resourceName = assembly.GetName().Name + ".g";
var manager = new ResourceManager(resourceName, assembly);
using (var resourceSet = manager.GetResourceSet(CultureInfo.CurrentCulture, true, true))
{
var stream = (Stream)resourceSet.GetObject(uri.ToString(), true);
if (stream == null)
{
throw new FileNotFoundException($"The requested asset could not be found: {uri}");
}
return stream;
}
}
}
}

42
src/Gtk/Perspex.Gtk/ClipboardImpl.cs

@ -0,0 +1,42 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Threading.Tasks;
using Gdk;
using Perspex.Input.Platform;
namespace Perspex.Gtk
{
using Gtk = global::Gtk;
internal class ClipboardImpl : IClipboard
{
private static Gtk.Clipboard GetClipboard() => Gtk.Clipboard.GetForDisplay(Display.Default, new Atom(IntPtr.Zero));
public Task<string> GetTextAsync()
{
var clip = GetClipboard();
var tcs = new TaskCompletionSource<string>();
clip.RequestText((_, text) =>
{
tcs.TrySetResult(text);
});
return tcs.Task;
}
public Task SetTextAsync(string text)
{
using (var cl = GetClipboard())
cl.Text = text;
return Task.FromResult(0);
}
public Task ClearAsync()
{
using (var cl = GetClipboard())
cl.Clear();
return Task.FromResult(0);
}
}
}

77
src/Gtk/Perspex.Gtk/CursorFactory.cs

@ -0,0 +1,77 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Collections.Generic;
using Gdk;
using Perspex.Input;
using Perspex.Platform;
namespace Perspex.Gtk
{
using Gtk = global::Gtk;
internal class CursorFactory : IStandardCursorFactory
{
public static CursorFactory Instance { get; } = new CursorFactory();
private CursorFactory()
{
}
private static readonly Dictionary<StandardCursorType, object> CursorTypeMapping = new Dictionary
<StandardCursorType, object>
{
{ StandardCursorType.AppStarting, CursorType.Watch },
{ StandardCursorType.Arrow, CursorType.LeftPtr },
{ StandardCursorType.Cross, CursorType.Cross },
{ StandardCursorType.Hand, CursorType.Hand1 },
{ StandardCursorType.Ibeam, CursorType.Xterm },
{ StandardCursorType.No, Gtk.Stock.Cancel},
{ StandardCursorType.SizeAll, CursorType.Sizing },
//{ StandardCursorType.SizeNorthEastSouthWest, 32643 },
{ StandardCursorType.SizeNorthSouth, CursorType.SbVDoubleArrow},
//{ StandardCursorType.SizeNorthWestSouthEast, 32642 },
{ StandardCursorType.SizeWestEast, CursorType.SbHDoubleArrow },
{ StandardCursorType.UpArrow, CursorType.BasedArrowUp },
{ StandardCursorType.Wait, CursorType.Watch },
{ StandardCursorType.Help, Gtk.Stock.Help }
};
private static readonly Dictionary<StandardCursorType, IPlatformHandle> Cache =
new Dictionary<StandardCursorType, IPlatformHandle>();
private Gdk.Cursor GetCursor(object desc)
{
Gdk.Cursor rv;
var name = desc as string;
if (name != null)
{
var theme = Gtk.IconTheme.Default;
var icon = theme.LoadIcon(name, 32, default(Gtk.IconLookupFlags));
rv = icon == null ? new Gdk.Cursor(CursorType.XCursor) : new Gdk.Cursor(Display.Default, icon, 0, 0);
}
else
{
rv = new Gdk.Cursor((CursorType)desc);
}
rv.Owned = false;
return rv;
}
public IPlatformHandle GetCursor(StandardCursorType cursorType)
{
IPlatformHandle rv;
if (!Cache.TryGetValue(cursorType, out rv))
{
Cache[cursorType] =
rv =
new PlatformHandle(
GetCursor(CursorTypeMapping[cursorType]).Handle,
"GTKCURSOR");
}
return rv;
}
}
}

7
src/Gtk/Perspex.Gtk/GtkExtensions.cs

@ -1,8 +1,5 @@
// -----------------------------------------------------------------------
// <copyright file="GtkExtensions.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Perspex.Gtk
{

48
src/Gtk/Perspex.Gtk/GtkPlatform.cs

@ -1,50 +1,44 @@
// -----------------------------------------------------------------------
// <copyright file="GtkPlatform.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Disposables;
using Perspex.Controls.Platform;
using Perspex.Input.Platform;
using Perspex.Input;
using Perspex.Platform;
using Perspex.Shared.PlatformSupport;
using Splat;
namespace Perspex.Gtk
{
using System;
using System.Reactive.Disposables;
using Perspex.Input;
using Perspex.Platform;
using Splat;
using Gtk = global::Gtk;
public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings
{
private static GtkPlatform instance = new GtkPlatform();
private static readonly GtkPlatform s_instance = new GtkPlatform();
public GtkPlatform()
{
Gtk.Application.Init();
}
public Size DoubleClickSize
{
get
{
// TODO: Is there a setting for this somewhere?
return new Size(4, 4);
}
}
public Size DoubleClickSize => new Size(4, 4);
public TimeSpan DoubleClickTime
{
get { return TimeSpan.FromMilliseconds(Gtk.Settings.Default.DoubleClickTime); }
}
public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(Gtk.Settings.Default.DoubleClickTime);
public static void Initialize()
{
var locator = Locator.CurrentMutable;
locator.Register(() => new WindowImpl(), typeof(IWindowImpl));
locator.Register(() => new PopupImpl(), typeof(IPopupImpl));
locator.Register(() => new ClipboardImpl(), typeof(IClipboard));
locator.Register(() => CursorFactory.Instance, typeof(IStandardCursorFactory));
locator.Register(() => GtkKeyboardDevice.Instance, typeof(IKeyboardDevice));
locator.Register(() => instance, typeof(IPlatformSettings));
locator.Register(() => instance, typeof(IPlatformThreadingInterface));
locator.RegisterConstant(new AssetLoader(), typeof(IAssetLoader));
locator.Register(() => s_instance, typeof(IPlatformSettings));
locator.Register(() => s_instance, typeof(IPlatformThreadingInterface));
locator.Register(() => new SystemDialogImpl(), typeof (ISystemDialogImpl));
SharedPlatform.Register();
}
public bool HasMessages()
@ -61,7 +55,7 @@ namespace Perspex.Gtk
{
var result = true;
var handle = GLib.Timeout.Add(
(uint)interval.TotalMilliseconds,
(uint)interval.TotalMilliseconds,
() =>
{
tick();

263
src/Gtk/Perspex.Gtk/Input/GtkKeyboardDevice.cs

@ -1,62 +1,225 @@
// -----------------------------------------------------------------------
// <copyright file="GtkKeyboardDevice.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Perspex.Input;
namespace Perspex.Gtk
{
using System;
using Perspex.Input;
public class GtkKeyboardDevice : KeyboardDevice
{
private static GtkKeyboardDevice instance;
static GtkKeyboardDevice()
private static readonly Dictionary<Gdk.Key, Key> KeyDic = new Dictionary<Gdk.Key, Key>
{
instance = new GtkKeyboardDevice();
}
{ Gdk.Key.Cancel, Key.Cancel },
{ Gdk.Key.BackSpace, Key.Back },
{ Gdk.Key.Tab, Key.Tab },
{ Gdk.Key.Linefeed, Key.LineFeed },
{ Gdk.Key.Clear, Key.Clear },
{ Gdk.Key.Return, Key.Return },
{ Gdk.Key.Pause, Key.Pause },
//{ Gdk.Key.?, Key.CapsLock }
//{ Gdk.Key.?, Key.HangulMode }
//{ Gdk.Key.?, Key.JunjaMode }
//{ Gdk.Key.?, Key.FinalMode }
//{ Gdk.Key.?, Key.KanjiMode }
{ Gdk.Key.Escape, Key.Escape },
//{ Gdk.Key.?, Key.ImeConvert }
//{ Gdk.Key.?, Key.ImeNonConvert }
//{ Gdk.Key.?, Key.ImeAccept }
//{ Gdk.Key.?, Key.ImeModeChange }
{ Gdk.Key.space, Key.Space },
{ Gdk.Key.Prior, Key.Prior },
//{ Gdk.Key.?, Key.PageDown }
{ Gdk.Key.End, Key.End },
{ Gdk.Key.Home, Key.Home },
{ Gdk.Key.Left, Key.Left },
{ Gdk.Key.Up, Key.Up },
{ Gdk.Key.Right, Key.Right },
{ Gdk.Key.Down, Key.Down },
{ Gdk.Key.Select, Key.Select },
{ Gdk.Key.Print, Key.Print },
{ Gdk.Key.Execute, Key.Execute },
//{ Gdk.Key.?, Key.Snapshot }
{ Gdk.Key.Insert, Key.Insert },
{ Gdk.Key.Delete, Key.Delete },
{ Gdk.Key.Help, Key.Help },
//{ Gdk.Key.?, Key.D0 }
//{ Gdk.Key.?, Key.D1 }
//{ Gdk.Key.?, Key.D2 }
//{ Gdk.Key.?, Key.D3 }
//{ Gdk.Key.?, Key.D4 }
//{ Gdk.Key.?, Key.D5 }
//{ Gdk.Key.?, Key.D6 }
//{ Gdk.Key.?, Key.D7 }
//{ Gdk.Key.?, Key.D8 }
//{ Gdk.Key.?, Key.D9 }
{ Gdk.Key.A, Key.A },
{ Gdk.Key.B, Key.B },
{ Gdk.Key.C, Key.C },
{ Gdk.Key.D, Key.D },
{ Gdk.Key.E, Key.E },
{ Gdk.Key.F, Key.F },
{ Gdk.Key.G, Key.G },
{ Gdk.Key.H, Key.H },
{ Gdk.Key.I, Key.I },
{ Gdk.Key.J, Key.J },
{ Gdk.Key.K, Key.K },
{ Gdk.Key.L, Key.L },
{ Gdk.Key.M, Key.M },
{ Gdk.Key.N, Key.N },
{ Gdk.Key.O, Key.O },
{ Gdk.Key.P, Key.P },
{ Gdk.Key.Q, Key.Q },
{ Gdk.Key.R, Key.R },
{ Gdk.Key.S, Key.S },
{ Gdk.Key.T, Key.T },
{ Gdk.Key.U, Key.U },
{ Gdk.Key.V, Key.V },
{ Gdk.Key.W, Key.W },
{ Gdk.Key.X, Key.X },
{ Gdk.Key.Y, Key.Y },
{ Gdk.Key.Z, Key.Z },
{ Gdk.Key.a, Key.A },
{ Gdk.Key.b, Key.B },
{ Gdk.Key.c, Key.C },
{ Gdk.Key.d, Key.D },
{ Gdk.Key.e, Key.E },
{ Gdk.Key.f, Key.F },
{ Gdk.Key.g, Key.G },
{ Gdk.Key.h, Key.H },
{ Gdk.Key.i, Key.I },
{ Gdk.Key.j, Key.J },
{ Gdk.Key.k, Key.K },
{ Gdk.Key.l, Key.L },
{ Gdk.Key.m, Key.M },
{ Gdk.Key.n, Key.N },
{ Gdk.Key.o, Key.O },
{ Gdk.Key.p, Key.P },
{ Gdk.Key.q, Key.Q },
{ Gdk.Key.r, Key.R },
{ Gdk.Key.s, Key.S },
{ Gdk.Key.t, Key.T },
{ Gdk.Key.u, Key.U },
{ Gdk.Key.v, Key.V },
{ Gdk.Key.w, Key.W },
{ Gdk.Key.x, Key.X },
{ Gdk.Key.y, Key.Y },
{ Gdk.Key.z, Key.Z },
//{ Gdk.Key.?, Key.LWin }
//{ Gdk.Key.?, Key.RWin }
//{ Gdk.Key.?, Key.Apps }
//{ Gdk.Key.?, Key.Sleep }
//{ Gdk.Key.?, Key.NumPad0 }
//{ Gdk.Key.?, Key.NumPad1 }
//{ Gdk.Key.?, Key.NumPad2 }
//{ Gdk.Key.?, Key.NumPad3 }
//{ Gdk.Key.?, Key.NumPad4 }
//{ Gdk.Key.?, Key.NumPad5 }
//{ Gdk.Key.?, Key.NumPad6 }
//{ Gdk.Key.?, Key.NumPad7 }
//{ Gdk.Key.?, Key.NumPad8 }
//{ Gdk.Key.?, Key.NumPad9 }
{ Gdk.Key.multiply, Key.Multiply },
//{ Gdk.Key.?, Key.Add }
//{ Gdk.Key.?, Key.Separator }
//{ Gdk.Key.?, Key.Subtract }
//{ Gdk.Key.?, Key.Decimal }
//{ Gdk.Key.?, Key.Divide }
{ Gdk.Key.F1, Key.F1 },
{ Gdk.Key.F2, Key.F2 },
{ Gdk.Key.F3, Key.F3 },
{ Gdk.Key.F4, Key.F4 },
{ Gdk.Key.F5, Key.F5 },
{ Gdk.Key.F6, Key.F6 },
{ Gdk.Key.F7, Key.F7 },
{ Gdk.Key.F8, Key.F8 },
{ Gdk.Key.F9, Key.F9 },
{ Gdk.Key.F10, Key.F10 },
{ Gdk.Key.F11, Key.F11 },
{ Gdk.Key.F12, Key.F12 },
{ Gdk.Key.L3, Key.F13 },
{ Gdk.Key.F14, Key.F14 },
{ Gdk.Key.L5, Key.F15 },
{ Gdk.Key.F16, Key.F16 },
{ Gdk.Key.F17, Key.F17 },
{ Gdk.Key.L8, Key.F18 },
{ Gdk.Key.L9, Key.F19 },
{ Gdk.Key.L10, Key.F20 },
{ Gdk.Key.R1, Key.F21 },
{ Gdk.Key.R2, Key.F22 },
{ Gdk.Key.F23, Key.F23 },
{ Gdk.Key.R4, Key.F24 },
//{ Gdk.Key.?, Key.NumLock }
//{ Gdk.Key.?, Key.Scroll }
//{ Gdk.Key.?, Key.LeftShift }
//{ Gdk.Key.?, Key.RightShift }
//{ Gdk.Key.?, Key.LeftCtrl }
//{ Gdk.Key.?, Key.RightCtrl }
//{ Gdk.Key.?, Key.LeftAlt }
//{ Gdk.Key.?, Key.RightAlt }
//{ Gdk.Key.?, Key.BrowserBack }
//{ Gdk.Key.?, Key.BrowserForward }
//{ Gdk.Key.?, Key.BrowserRefresh }
//{ Gdk.Key.?, Key.BrowserStop }
//{ Gdk.Key.?, Key.BrowserSearch }
//{ Gdk.Key.?, Key.BrowserFavorites }
//{ Gdk.Key.?, Key.BrowserHome }
//{ Gdk.Key.?, Key.VolumeMute }
//{ Gdk.Key.?, Key.VolumeDown }
//{ Gdk.Key.?, Key.VolumeUp }
//{ Gdk.Key.?, Key.MediaNextTrack }
//{ Gdk.Key.?, Key.MediaPreviousTrack }
//{ Gdk.Key.?, Key.MediaStop }
//{ Gdk.Key.?, Key.MediaPlayPause }
//{ Gdk.Key.?, Key.LaunchMail }
//{ Gdk.Key.?, Key.SelectMedia }
//{ Gdk.Key.?, Key.LaunchApplication1 }
//{ Gdk.Key.?, Key.LaunchApplication2 }
//{ Gdk.Key.?, Key.OemSemicolon }
//{ Gdk.Key.?, Key.OemPlus }
//{ Gdk.Key.?, Key.OemComma }
//{ Gdk.Key.?, Key.OemMinus }
//{ Gdk.Key.?, Key.OemPeriod }
//{ Gdk.Key.?, Key.Oem2 }
//{ Gdk.Key.?, Key.OemTilde }
//{ Gdk.Key.?, Key.AbntC1 }
//{ Gdk.Key.?, Key.AbntC2 }
//{ Gdk.Key.?, Key.Oem4 }
//{ Gdk.Key.?, Key.OemPipe }
//{ Gdk.Key.?, Key.OemCloseBrackets }
//{ Gdk.Key.?, Key.Oem7 }
//{ Gdk.Key.?, Key.Oem8 }
//{ Gdk.Key.?, Key.Oem102 }
//{ Gdk.Key.?, Key.ImeProcessed }
//{ Gdk.Key.?, Key.System }
//{ Gdk.Key.?, Key.OemAttn }
//{ Gdk.Key.?, Key.OemFinish }
//{ Gdk.Key.?, Key.DbeHiragana }
//{ Gdk.Key.?, Key.OemAuto }
//{ Gdk.Key.?, Key.DbeDbcsChar }
//{ Gdk.Key.?, Key.OemBackTab }
//{ Gdk.Key.?, Key.Attn }
//{ Gdk.Key.?, Key.DbeEnterWordRegisterMode }
//{ Gdk.Key.?, Key.DbeEnterImeConfigureMode }
//{ Gdk.Key.?, Key.EraseEof }
//{ Gdk.Key.?, Key.Play }
//{ Gdk.Key.?, Key.Zoom }
//{ Gdk.Key.?, Key.NoName }
//{ Gdk.Key.?, Key.DbeEnterDialogConversionMode }
//{ Gdk.Key.?, Key.OemClear }
//{ Gdk.Key.?, Key.DeadCharProcessed }
};
private GtkKeyboardDevice()
{
}
public static GtkKeyboardDevice Instance { get; } = new GtkKeyboardDevice();
public static new GtkKeyboardDevice Instance
public static Key ConvertKey(Gdk.Key key)
{
get { return instance; }
}
public override ModifierKeys Modifiers
{
get
{
// TODO: Implement.
return ModifierKeys.None;
}
}
public static Perspex.Input.Key ConvertKey(Gdk.Key key)
{
// TODO: Don't use reflection for this! My eyes!!!
if (key == Gdk.Key.BackSpace)
{
return Perspex.Input.Key.Back;
}
else
{
var s = Enum.GetName(typeof(Gdk.Key), key);
Perspex.Input.Key result;
if (Enum.TryParse(s, true, out result))
{
return result;
}
else
{
return Perspex.Input.Key.None;
}
}
Key result;
return KeyDic.TryGetValue(key, out result) ? result : Key.None;
}
}
}

24
src/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs

@ -1,35 +1,29 @@
// -----------------------------------------------------------------------
// <copyright file="GtkMouseDevice.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Perspex.Input;
namespace Perspex.Gtk
{
using Perspex.Input;
public class GtkMouseDevice : MouseDevice
{
private static GtkMouseDevice instance;
private static readonly GtkMouseDevice s_instance;
private Point clientPosition;
private Point _clientPosition;
static GtkMouseDevice()
{
instance = new GtkMouseDevice();
s_instance = new GtkMouseDevice();
}
private GtkMouseDevice()
{
}
public static new GtkMouseDevice Instance
{
get { return instance; }
}
public static new GtkMouseDevice Instance => s_instance;
internal void SetClientPosition(Point p)
{
this.clientPosition = p;
_clientPosition = p;
}
}
}

30
src/Gtk/Perspex.Gtk/Perspex.Gtk.csproj

@ -30,20 +30,10 @@
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<Package>gtk-sharp-2.0</Package>
</Reference>
<Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<Package>gtk-sharp-2.0</Package>
</Reference>
<Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<Package>gtk-sharp-2.0</Package>
</Reference>
<Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
<Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
<Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
<Reference Include="System.Reactive.Interfaces">
<HintPath>..\..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll</HintPath>
</Reference>
@ -53,12 +43,15 @@
<Reference Include="System.Reactive.Linq">
<HintPath>..\..\..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll</HintPath>
</Reference>
<Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<Package>glib-sharp-2.0</Package>
<Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\..\..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AssetLoader.cs" />
<Compile Include="ClipboardImpl.cs" />
<Compile Include="SystemDialogImpl.cs" />
<Compile Include="CursorFactory.cs" />
<Compile Include="GtkExtensions.cs" />
<Compile Include="PopupImpl.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@ -70,11 +63,11 @@
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\..\Perspex.Animation\Perspex.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Project>{D211E587-D8BC-45B9-95A4-F297C8FA5200}</Project>
<Name>Perspex.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Application\Perspex.Application.csproj">
<Project>{799a7bb5-3c2c-48b6-85a7-406a12c420da}</Project>
<Project>{799A7BB5-3C2C-48B6-85A7-406A12C420DA}</Project>
<Name>Perspex.Application</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Base\Perspex.Base.csproj">
@ -110,4 +103,5 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="..\..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
</Project>

20
src/Gtk/Perspex.Gtk/PopupImpl.cs

@ -1,25 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Gtk;
using Perspex.Platform;
namespace Perspex.Gtk
{
using System;
using Perspex.Platform;
using global::Gtk;
public class PopupImpl : WindowImpl, IPopupImpl
{
public PopupImpl()
: base(WindowType.Popup)
{
{
}
public void SetPosition(Point p)
{
this.Move((int)p.X, (int)p.Y);
Move((int)p.X, (int)p.Y);
}
}
}

7
src/Gtk/Perspex.Gtk/Properties/AssemblyInfo.cs

@ -1,8 +1,5 @@
// -----------------------------------------------------------------------
// <copyright file="AssemblyInfo.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Reflection;
using System.Runtime.CompilerServices;

57
src/Gtk/Perspex.Gtk/SystemDialogImpl.cs

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Perspex.Controls;
using Perspex.Controls.Platform;
using Perspex.Platform;
namespace Perspex.Gtk
{
using global::Gtk;
class SystemDialogImpl : ISystemDialogImpl
{
public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
{
var tcs = new TaskCompletionSource<string[]>();
var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImpl) parent),
dialog is OpenFileDialog
? FileChooserAction.Open
: FileChooserAction.Save,
"Cancel", ResponseType.Cancel,
"Open", ResponseType.Accept)
{
SelectMultiple = (dialog as OpenFileDialog)?.AllowMultiple ?? false,
};
foreach (var filter in dialog.Filters)
{
var ffilter = new FileFilter()
{
Name = filter.Name + " (" + string.Join(";", filter.Extensions.Select(e => "*." + e)) + ")"
};
foreach (var ext in filter.Extensions)
ffilter.AddPattern("*." + ext);
dlg.AddFilter(ffilter);
}
dlg.SetFilename(dialog.InitialFileName);
dlg.Modal = true;
dlg.Response += (_, args) =>
{
if (args.ResponseId == ResponseType.Accept)
tcs.TrySetResult(dlg.Filenames);
dlg.Hide();
dlg.Dispose();
};
dlg.Close += delegate
{
tcs.TrySetResult(null);
dlg.Dispose();
};
dlg.Show();
return tcs.Task;
}
}
}

153
src/Gtk/Perspex.Gtk/WindowImpl.cs

@ -1,38 +1,37 @@
// -----------------------------------------------------------------------
// <copyright file="WindowImpl.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Disposables;
using Gdk;
using Perspex.Controls;
using Perspex.Input.Raw;
using Perspex.Platform;
using Perspex.Input;
using Action = System.Action;
namespace Perspex.Gtk
{
using System;
using System.Threading.Tasks;
using Perspex.Controls;
using Perspex.Input.Raw;
using Perspex.Platform;
using Gtk = global::Gtk;
using System.Reactive.Disposables;
public class WindowImpl : Gtk.Window, IWindowImpl
{
private TopLevel owner;
private TopLevel _owner;
private IPlatformHandle windowHandle;
private IPlatformHandle _windowHandle;
private Size clientSize;
private Size _clientSize;
private Gtk.IMContext imContext;
private Gtk.IMContext _imContext;
private uint lastKeyEventTimestamp;
private uint _lastKeyEventTimestamp;
private static readonly Gdk.Cursor DefaultCursor = new Gdk.Cursor(CursorType.LeftPtr);
public WindowImpl()
: base(Gtk.WindowType.Toplevel)
{
this.DefaultSize = new Gdk.Size(640, 480);
DefaultSize = new Gdk.Size(900, 480);
Init();
}
@ -44,25 +43,38 @@ namespace Perspex.Gtk
private void Init()
{
this.Events = Gdk.EventMask.PointerMotionMask |
Gdk.EventMask.ButtonPressMask |
Gdk.EventMask.ButtonReleaseMask;
this.windowHandle = new PlatformHandle(this.Handle, "GtkWindow");
this.imContext = new Gtk.IMMulticontext();
this.imContext.Commit += ImContext_Commit;
Events = EventMask.PointerMotionMask |
EventMask.ButtonPressMask |
EventMask.ButtonReleaseMask;
_windowHandle = new PlatformHandle(Handle, "GtkWindow");
_imContext = new Gtk.IMMulticontext();
_imContext.Commit += ImContext_Commit;
}
protected override void OnRealized ()
{
base.OnRealized ();
_imContext.ClientWindow = this.GdkWindow;
}
public Size ClientSize
{
get;
set;
}
IPlatformHandle ITopLevelImpl.Handle
public Size MaxClientSize
{
get { return this.windowHandle; }
get
{
// TODO: This should take into account things such as taskbar and window border
// thickness etc.
return new Size(Screen.Width, Screen.Height);
}
}
IPlatformHandle ITopLevelImpl.Handle => _windowHandle;
public Action Activated { get; set; }
public Action Closed { get; set; }
@ -82,73 +94,90 @@ namespace Perspex.Gtk
public void Invalidate(Rect rect)
{
#pragma warning disable CS0612 // Type or member is obsolete
this.Draw(new Gdk.Rectangle { X = (int)rect.X, Y = (int)rect.Y, Width = (int)rect.Width, Height = (int)rect.Height });
#pragma warning restore CS0612 // Type or member is obsolete
base.GdkWindow.InvalidateRect (new Rectangle ((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height), true);
}
public Point PointToScreen(Point point)
{
int x, y;
this.GdkWindow.GetDeskrelativeOrigin(out x, out y);
GdkWindow.GetDeskrelativeOrigin(out x, out y);
return new Point(point.X + x, point.Y + y);
}
public void SetOwner(TopLevel owner)
{
this.owner = owner;
_owner = owner;
}
public void SetTitle(string title)
{
this.Title = title;
Title = title;
}
public void SetCursor(IPlatformHandle cursor)
{
GdkWindow.Cursor = cursor != null ? new Gdk.Cursor(cursor.Handle) : DefaultCursor;
}
public IDisposable ShowDialog()
{
this.Modal = true;
this.Show();
Modal = true;
Show();
return Disposable.Empty;
}
void ITopLevelImpl.Activate()
{
this.Activate();
Activate();
}
protected override bool OnButtonPressEvent(Gdk.EventButton evnt)
private static ModifierKeys GetModifierKeys(ModifierType state)
{
var rv = ModifierKeys.None;
if (state.HasFlag(ModifierType.ControlMask))
rv |= ModifierKeys.Control;
if (state.HasFlag(ModifierType.ShiftMask))
rv |= ModifierKeys.Shift;
if (state.HasFlag(ModifierType.Mod1Mask))
rv |= ModifierKeys.Control;
return rv;
}
protected override bool OnButtonPressEvent(EventButton evnt)
{
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
this.owner,
_owner,
RawMouseEventType.LeftButtonDown,
new Point(evnt.X, evnt.Y));
this.Input(e);
new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
Input(e);
return true;
}
protected override bool OnButtonReleaseEvent(Gdk.EventButton evnt)
protected override bool OnButtonReleaseEvent(EventButton evnt)
{
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
this.owner,
_owner,
RawMouseEventType.LeftButtonUp,
new Point(evnt.X, evnt.Y));
this.Input(e);
new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
Input(e);
return true;
}
protected override bool OnConfigureEvent(Gdk.EventConfigure evnt)
protected override bool OnConfigureEvent(EventConfigure evnt)
{
var newSize = new Size(evnt.Width, evnt.Height);
if (newSize != this.clientSize)
if (newSize != _clientSize)
{
this.Resized(newSize);
Resized(newSize);
}
return true;
@ -156,44 +185,44 @@ namespace Perspex.Gtk
protected override void OnDestroyed()
{
this.Closed();
Closed();
}
private bool ProcessKeyEvent(Gdk.EventKey evnt)
private bool ProcessKeyEvent(EventKey evnt)
{
this.lastKeyEventTimestamp = evnt.Time;
if (this.imContext.FilterKeypress(evnt))
_lastKeyEventTimestamp = evnt.Time;
if (_imContext.FilterKeypress(evnt))
return true;
var e = new RawKeyEventArgs(
GtkKeyboardDevice.Instance,
evnt.Time,
evnt.Type == EventType.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
GtkKeyboardDevice.ConvertKey(evnt.Key));
this.Input(e);
GtkKeyboardDevice.ConvertKey(evnt.Key), GetModifierKeys(evnt.State));
Input(e);
return true;
}
protected override bool OnKeyPressEvent(Gdk.EventKey evnt) => ProcessKeyEvent(evnt);
protected override bool OnKeyPressEvent(EventKey evnt) => ProcessKeyEvent(evnt);
protected override bool OnKeyReleaseEvent(EventKey evnt) => ProcessKeyEvent(evnt);
private void ImContext_Commit(object o, Gtk.CommitArgs args)
{
this.Input(new RawTextInputEventArgs(GtkKeyboardDevice.Instance, this.lastKeyEventTimestamp, args.Str));
Input(new RawTextInputEventArgs(GtkKeyboardDevice.Instance, _lastKeyEventTimestamp, args.Str));
}
protected override bool OnExposeEvent(Gdk.EventExpose evnt)
protected override bool OnExposeEvent(EventExpose evnt)
{
this.Paint(evnt.Area.ToPerspex(), this.GetHandle(evnt.Window));
Paint(evnt.Area.ToPerspex(), GetHandle(evnt.Window));
return true;
}
protected override void OnFocusActivated()
{
this.Activated();
Activated();
}
protected override bool OnMotionNotifyEvent(Gdk.EventMotion evnt)
protected override bool OnMotionNotifyEvent(EventMotion evnt)
{
var position = new Point(evnt.X, evnt.Y);
@ -202,10 +231,10 @@ namespace Perspex.Gtk
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
this.owner,
_owner,
RawMouseEventType.Move,
position);
this.Input(e);
position, GetModifierKeys(evnt.State));
Input(e);
return true;
}

31
src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs

@ -1,44 +1,41 @@
// -----------------------------------------------------------------------
// <copyright file="PerspexObjectAssembler.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using OmniXaml;
using OmniXaml.ObjectAssembler;
using Perspex.Markup.Xaml.Templates;
namespace Perspex.Markup.Xaml.Context
{
using System;
using OmniXaml;
using OmniXaml.ObjectAssembler;
using Templates;
public class PerspexObjectAssembler : IObjectAssembler
{
private readonly TemplateHostingObjectAssembler objectAssembler;
private readonly TemplateHostingObjectAssembler _objectAssembler;
public PerspexObjectAssembler(IWiringContext wiringContext, ObjectAssemblerSettings objectAssemblerSettings = null)
{
var mapping = new DeferredLoaderMapping();
mapping.Map<XamlDataTemplate>(template => template.Content, new TemplateLoader());
var assembler = new ObjectAssembler(wiringContext, new TopDownMemberValueContext(), objectAssemblerSettings);
this.objectAssembler = new TemplateHostingObjectAssembler(assembler, mapping);
var assembler = new ObjectAssembler(wiringContext, new TopDownValueContext(), objectAssemblerSettings);
_objectAssembler = new TemplateHostingObjectAssembler(assembler, mapping);
}
public object Result => this.objectAssembler.Result;
public object Result => _objectAssembler.Result;
public EventHandler<XamlSetValueEventArgs> XamlSetValueHandler { get; set; }
public IWiringContext WiringContext => this.objectAssembler.WiringContext;
public IWiringContext WiringContext => _objectAssembler.WiringContext;
public void Process(XamlInstruction node)
{
this.objectAssembler.Process(node);
_objectAssembler.Process(node);
}
public void OverrideInstance(object instance)
{
this.objectAssembler.OverrideInstance(instance);
_objectAssembler.OverrideInstance(instance);
}
}
}

37
src/Markup/Perspex.Markup.Xaml/Context/PerspexParserFactory.cs

@ -1,19 +1,16 @@
// -----------------------------------------------------------------------
// <copyright file="PerspexParserFactory.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using OmniXaml;
using OmniXaml.ObjectAssembler;
using OmniXaml.Parsers.ProtoParser;
using OmniXaml.Parsers.XamlInstructions;
namespace Perspex.Markup.Xaml.Context
{
using OmniXaml;
using OmniXaml.ObjectAssembler;
using OmniXaml.Parsers.ProtoParser;
using OmniXaml.Parsers.XamlInstructions;
public class PerspexParserFactory : IXamlParserFactory
{
private readonly IWiringContext wiringContext;
private readonly IWiringContext _wiringContext;
public PerspexParserFactory()
: this(new TypeFactory())
@ -22,22 +19,22 @@ namespace Perspex.Markup.Xaml.Context
public PerspexParserFactory(ITypeFactory typeFactory)
{
this.wiringContext = new PerspexWiringContext(typeFactory);
_wiringContext = new PerspexWiringContext(typeFactory);
}
public IXamlParser CreateForReadingFree()
{
var objectAssemblerForUndefinedRoot = this.GetObjectAssemblerForUndefinedRoot();
var objectAssemblerForUndefinedRoot = GetObjectAssemblerForUndefinedRoot();
return this.CreateParser(objectAssemblerForUndefinedRoot);
return CreateParser(objectAssemblerForUndefinedRoot);
}
private IXamlParser CreateParser(IObjectAssembler objectAssemblerForUndefinedRoot)
{
var xamlInstructionParser = new OrderAwareXamlInstructionParser(new XamlInstructionParser(this.wiringContext));
var xamlInstructionParser = new OrderAwareXamlInstructionParser(new XamlInstructionParser(_wiringContext));
var phaseParserKit = new PhaseParserKit(
new XamlProtoInstructionParser(this.wiringContext),
new XamlProtoInstructionParser(_wiringContext),
xamlInstructionParser,
objectAssemblerForUndefinedRoot);
@ -46,19 +43,19 @@ namespace Perspex.Markup.Xaml.Context
private IObjectAssembler GetObjectAssemblerForUndefinedRoot()
{
return new ObjectAssembler(this.wiringContext, new TopDownMemberValueContext());
return new ObjectAssembler(_wiringContext, new TopDownValueContext());
}
public IXamlParser CreateForReadingSpecificInstance(object rootInstance)
{
var objectAssemblerForUndefinedRoot = this.GetObjectAssemblerForSpecificRoot(rootInstance);
var objectAssemblerForUndefinedRoot = GetObjectAssemblerForSpecificRoot(rootInstance);
return this.CreateParser(objectAssemblerForUndefinedRoot);
return CreateParser(objectAssemblerForUndefinedRoot);
}
private IObjectAssembler GetObjectAssemblerForSpecificRoot(object rootInstance)
{
return new PerspexObjectAssembler(this.wiringContext, new ObjectAssemblerSettings { RootInstance = rootInstance });
return new PerspexObjectAssembler(_wiringContext, new ObjectAssemblerSettings { RootInstance = rootInstance });
}
}
}

29
src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeRepository.cs

@ -1,35 +1,32 @@
// -----------------------------------------------------------------------
// <copyright file="PerspexTypeRepository.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Glass;
using OmniXaml;
using OmniXaml.Typing;
using Perspex.Markup.Xaml.DataBinding;
namespace Perspex.Markup.Xaml.Context
{
using System;
using DataBinding;
using Glass;
using OmniXaml;
using OmniXaml.Typing;
public class PerspexTypeRepository : XamlTypeRepository
{
private readonly ITypeFactory typeFactory;
private readonly IPerspexPropertyBinder propertyBinder;
private readonly ITypeFactory _typeFactory;
private readonly IPerspexPropertyBinder _propertyBinder;
public PerspexTypeRepository(IXamlNamespaceRegistry xamlNamespaceRegistry,
ITypeFactory typeFactory,
ITypeFeatureProvider featureProvider,
IPerspexPropertyBinder propertyBinder) : base(xamlNamespaceRegistry, typeFactory, featureProvider)
{
this.typeFactory = typeFactory;
this.propertyBinder = propertyBinder;
_typeFactory = typeFactory;
_propertyBinder = propertyBinder;
}
public override XamlType GetXamlType(Type type)
{
Guard.ThrowIfNull(type, nameof(type));
return new PerspexXamlType(type, this, this.typeFactory, this.FeatureProvider, this.propertyBinder);
return new PerspexXamlType(type, this, _typeFactory, FeatureProvider, _propertyBinder);
}
}
}

134
src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs

@ -1,31 +1,33 @@
// -----------------------------------------------------------------------
// <copyright file="PerspexWiringContext.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using Glass;
using OmniXaml;
using OmniXaml.Builder;
using OmniXaml.TypeConversion;
using OmniXaml.Typing;
using Perspex.Controls;
using Perspex.Markup.Xaml.Templates;
using Perspex.Markup.Xaml.Converters;
using Perspex.Markup.Xaml.DataBinding;
using Perspex.Markup.Xaml.MarkupExtensions;
using Perspex.Media;
using Perspex.Media.Imaging;
using Perspex.Metadata;
using Perspex.Platform;
using Perspex.Styling;
using Splat;
namespace Perspex.Markup.Xaml.Context
{
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
using Controls;
using Converters;
using DataBinding;
using Glass;
using MarkupExtensions;
using Media;
using Media.Imaging;
using OmniXaml;
using OmniXaml.Builder;
using OmniXaml.TypeConversion;
using OmniXaml.Typing;
using Templates;
public class PerspexWiringContext : IWiringContext
{
private readonly WiringContext context;
private const string PerspexNs = "https://github.com/grokys/Perspex";
private readonly WiringContext _context;
private const string PerspexNs = "https://github.com/perspex";
public PerspexWiringContext(ITypeFactory typeFactory)
{
@ -35,44 +37,34 @@ namespace Perspex.Markup.Xaml.Context
var perspexPropertyBinder = new PerspexPropertyBinder(featureProvider.ConverterProvider);
var xamlTypeRepository = new PerspexTypeRepository(xamlNamespaceRegistry, typeFactory, featureProvider, perspexPropertyBinder);
var typeContext = new TypeContext(xamlTypeRepository, xamlNamespaceRegistry, typeFactory);
this.context = new WiringContext(typeContext, featureProvider);
_context = new WiringContext(typeContext, featureProvider);
}
private static XamlNamespaceRegistry CreateXamlNamespaceRegistry()
{
var xamlNamespaceRegistry = new XamlNamespaceRegistry();
var rootType = typeof(Control);
var bindingType = typeof(BindingExtension);
var templateType = typeof(XamlDataTemplate);
var definitionForRoot = XamlNamespace
.Map(PerspexNs)
.With(
new[]
{
Route.Assembly(rootType.GetTypeInfo().Assembly).WithNamespaces(
new[]
{
rootType.Namespace
}),
Route.Assembly(bindingType.GetTypeInfo().Assembly).WithNamespaces(
new[]
{
bindingType.Namespace,
}),
Route.Assembly(templateType.GetTypeInfo().Assembly).WithNamespaces(
new[]
{
templateType.Namespace,
})
});
foreach (var ns in new List<XamlNamespace> { definitionForRoot })
var forcedAssemblies = new[]
{
xamlNamespaceRegistry.AddNamespace(ns);
typeof (Control),
typeof(Style)
}.Select(t => t.GetTypeInfo().Assembly);
foreach (var nsa in
forcedAssemblies
.Concat(Locator.Current.GetService<IPclPlatformWrapper>().GetLoadedAssemblies())
.Distinct()
.SelectMany(asm
=> asm.GetCustomAttributes<XmlnsDefinitionAttribute>().Select(attr => new {asm, attr}))
.GroupBy(entry => entry.attr.XmlNamespace))
{
var def = XamlNamespace.Map(nsa.Key)
.With(nsa.GroupBy(x => x.asm).Select(
a => Route.Assembly(a.Key)
.WithNamespaces(a.Select(entry => entry.attr.ClrNamespace).ToList())
));
xamlNamespaceRegistry.AddNamespace(def);
}
xamlNamespaceRegistry.RegisterPrefix(new PrefixRegistration(string.Empty, PerspexNs));
return xamlNamespaceRegistry;
@ -83,10 +75,18 @@ namespace Perspex.Markup.Xaml.Context
var typeConverterProvider = new TypeConverterProvider();
var converters = new[]
{
new TypeConverterRegistration(typeof (Bitmap), new BitmapConverter()),
new TypeConverterRegistration(typeof (GridLength), new GridLengthTypeConverter()),
new TypeConverterRegistration(typeof (Brush), new BrushConverter()),
new TypeConverterRegistration(typeof (Thickness), new ThicknessConverter()),
new TypeConverterRegistration(typeof(Bitmap), new BitmapTypeConverter()),
new TypeConverterRegistration(typeof(Brush), new BrushTypeConverter()),
new TypeConverterRegistration(typeof(Color), new ColorTypeConverter()),
new TypeConverterRegistration(typeof(Classes), new ClassesTypeConverter()),
new TypeConverterRegistration(typeof(ColumnDefinitions), new ColumnDefinitionsTypeConverter()),
new TypeConverterRegistration(typeof(GridLength), new GridLengthTypeConverter()),
new TypeConverterRegistration(typeof(Point), new PointTypeConverter()),
new TypeConverterRegistration(typeof(PerspexProperty), new PerspexPropertyTypeConverter()),
new TypeConverterRegistration(typeof(RelativePoint), new RelativePointTypeConverter()),
new TypeConverterRegistration(typeof(RowDefinitions), new RowDefinitionsTypeConverter()),
new TypeConverterRegistration(typeof(Thickness), new ThicknessTypeConverter()),
new TypeConverterRegistration(typeof(Selector), new SelectorTypeConverter()),
};
typeConverterProvider.AddAll(converters);
@ -98,13 +98,15 @@ namespace Perspex.Markup.Xaml.Context
var contentPropertyProvider = new ContentPropertyProvider();
var contentProperties = new Collection<ContentPropertyDefinition>
{
new ContentPropertyDefinition(typeof (ContentControl), "Content"),
new ContentPropertyDefinition(typeof (Decorator), "Child"),
new ContentPropertyDefinition(typeof (ItemsControl), "Items"),
new ContentPropertyDefinition(typeof (Panel), "Children"),
new ContentPropertyDefinition(typeof (TextBlock), "Text"),
new ContentPropertyDefinition(typeof (TextBox), "Text"),
new ContentPropertyDefinition(typeof (XamlDataTemplate), "Content"),
new ContentPropertyDefinition(typeof(ContentControl), "Content"),
new ContentPropertyDefinition(typeof(Decorator), "Child"),
new ContentPropertyDefinition(typeof(ItemsControl), "Items"),
new ContentPropertyDefinition(typeof(GradientBrush), "GradientStops"),
new ContentPropertyDefinition(typeof(Panel), "Children"),
new ContentPropertyDefinition(typeof(Style), "Setters"),
new ContentPropertyDefinition(typeof(TextBlock), "Text"),
new ContentPropertyDefinition(typeof(TextBox), "Text"),
new ContentPropertyDefinition(typeof(XamlDataTemplate), "Content"),
};
contentPropertyProvider.AddAll(contentProperties);
@ -112,8 +114,8 @@ namespace Perspex.Markup.Xaml.Context
return contentPropertyProvider;
}
public ITypeContext TypeContext => this.context.TypeContext;
public ITypeContext TypeContext => _context.TypeContext;
public ITypeFeatureProvider FeatureProvider => this.context.FeatureProvider;
public ITypeFeatureProvider FeatureProvider => _context.FeatureProvider;
}
}

21
src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMember.cs

@ -1,18 +1,15 @@
// -----------------------------------------------------------------------
// <copyright file="PerspexXamlMember.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Perspex.Markup.Xaml.DataBinding;
using OmniXaml;
using OmniXaml.Typing;
namespace Perspex.Markup.Xaml.Context
{
using DataBinding;
using OmniXaml;
using OmniXaml.Typing;
public class PerspexXamlMember : XamlMember
{
private readonly IPerspexPropertyBinder propertyBinder;
private readonly IPerspexPropertyBinder _propertyBinder;
public PerspexXamlMember(string name,
XamlType owner,
@ -21,12 +18,12 @@ namespace Perspex.Markup.Xaml.Context
IPerspexPropertyBinder propertyBinder)
: base(name, owner, xamlTypeRepository, featureProvider)
{
this.propertyBinder = propertyBinder;
_propertyBinder = propertyBinder;
}
protected override IXamlMemberValuePlugin LookupXamlMemberValueConnector()
{
return new PerspexXamlMemberValuePlugin(this, this.propertyBinder);
return new PerspexXamlMemberValuePlugin(this, _propertyBinder);
}
public override string ToString()

80
src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMemberValuePlugin.cs

@ -1,72 +1,66 @@
// -----------------------------------------------------------------------
// <copyright file="PerspexXamlMemberValuePlugin.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Linq;
using Glass;
using OmniXaml.ObjectAssembler;
using OmniXaml.Typing;
using Perspex.Controls;
using Perspex.Markup.Xaml.DataBinding;
using Perspex.Styling;
namespace Perspex.Markup.Xaml.Context
{
using System;
using System.Reactive.Linq;
using Controls;
using DataBinding;
using Glass;
using OmniXaml.Typing;
public class PerspexXamlMemberValuePlugin : MemberValuePlugin
{
private readonly XamlMember xamlMember;
private readonly IPerspexPropertyBinder propertyBinder;
private readonly XamlMember _xamlMember;
private readonly IPerspexPropertyBinder _propertyBinder;
public PerspexXamlMemberValuePlugin(XamlMember xamlMember, IPerspexPropertyBinder propertyBinder) : base(xamlMember)
{
this.xamlMember = xamlMember;
this.propertyBinder = propertyBinder;
_xamlMember = xamlMember;
_propertyBinder = propertyBinder;
}
public override void SetValue(object instance, object value)
{
if (this.ValueRequiresSpecialHandling(value))
{
this.HandleSpecialValue(instance, value);
}
else
if (value is XamlBindingDefinition)
{
base.SetValue(instance, value);
HandleXamlBindingDefinition((XamlBindingDefinition)value);
}
}
private void HandleSpecialValue(object instance, object value)
{
var definition = value as XamlBindingDefinition;
if (definition != null)
else if (IsPerspexProperty)
{
this.HandleXamlBindingDefinition(definition);
HandlePerspexProperty(instance, value);
}
else if (this.IsPerspexProperty)
else if (instance is Setter && _xamlMember.Name == "Value")
{
this.HandlePerspexProperty(instance, value);
var setter = (Setter)instance;
var targetType = setter.Property.PropertyType;
var valuePipeline = new ValuePipeline(_xamlMember.TypeRepository, null);
var xamlType = _xamlMember.TypeRepository.GetXamlType(targetType);
base.SetValue(instance, valuePipeline.ConvertValueIfNecessary(value, xamlType));
}
else
{
throw new InvalidOperationException($"Cannot handle the value {value} for member {this} and the instance {instance}");
base.SetValue(instance, value);
}
}
private void HandlePerspexProperty(object instance, object value)
{
var pp = this.PerspexProperty;
var po = (PerspexObject) instance;
var pp = PerspexProperty;
var po = (PerspexObject)instance;
po.SetValue(pp, value);
}
private void HandleXamlBindingDefinition(XamlBindingDefinition xamlBindingDefinition)
{
PerspexObject subjectObject = xamlBindingDefinition.Target;
this.propertyBinder.Create(xamlBindingDefinition);
_propertyBinder.Create(xamlBindingDefinition);
var observableForDataContext = subjectObject.GetObservable(Control.DataContextProperty);
observableForDataContext.Where(o => o != null).Subscribe(_ => this.BindToDataContextWhenItsSet(xamlBindingDefinition));
observableForDataContext.Where(o => o != null).Subscribe(_ => BindToDataContextWhenItsSet(xamlBindingDefinition));
}
private void BindToDataContextWhenItsSet(XamlBindingDefinition definition)
@ -74,8 +68,8 @@ namespace Perspex.Markup.Xaml.Context
var target = definition.Target;
var dataContext = target.DataContext;
var binding = this.propertyBinder.GetBinding(target, definition.TargetProperty);
binding.Bind(dataContext);
var binding = _propertyBinder.GetBinding(target, definition.TargetProperty);
binding.BindToDataContext(dataContext);
}
// ReSharper disable once MemberCanBePrivate.Global
@ -83,8 +77,8 @@ namespace Perspex.Markup.Xaml.Context
{
get
{
var underlyingType = this.xamlMember.DeclaringType.UnderlyingType;
var name = this.xamlMember.Name + "Property";
var underlyingType = _xamlMember.DeclaringType.UnderlyingType;
var name = _xamlMember.Name + "Property";
var value = ReflectionExtensions.GetValueOfStaticField(underlyingType, name);
return value as PerspexProperty;
@ -93,14 +87,14 @@ namespace Perspex.Markup.Xaml.Context
private bool ValueRequiresSpecialHandling(object value)
{
return value is XamlBindingDefinition || this.IsPerspexProperty;
return value is XamlBindingDefinition || IsPerspexProperty;
}
private bool IsPerspexProperty => this.PerspexProperty != null;
private bool IsPerspexProperty => PerspexProperty != null;
public override string ToString()
{
return $"{{Perspex Value Connector for member {this.xamlMember}}}";
return $"{{Perspex Value Connector for member {_xamlMember}}}";
}
}
}

25
src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs

@ -1,19 +1,16 @@
// -----------------------------------------------------------------------
// <copyright file="PerspexXamlType.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using OmniXaml;
using OmniXaml.Typing;
using Perspex.Markup.Xaml.DataBinding;
namespace Perspex.Markup.Xaml.Context
{
using System;
using DataBinding;
using OmniXaml;
using OmniXaml.Typing;
public class PerspexXamlType : XamlType
{
private readonly IPerspexPropertyBinder propertyBinder;
private readonly IPerspexPropertyBinder _propertyBinder;
public PerspexXamlType(Type type,
IXamlTypeRepository typeRepository,
@ -21,14 +18,14 @@ namespace Perspex.Markup.Xaml.Context
ITypeFeatureProvider featureProvider,
IPerspexPropertyBinder propertyBinder) : base(type, typeRepository, typeFactory, featureProvider)
{
this.propertyBinder = propertyBinder;
_propertyBinder = propertyBinder;
}
protected IPerspexPropertyBinder PropertyBinder => this.propertyBinder;
protected IPerspexPropertyBinder PropertyBinder => _propertyBinder;
protected override XamlMember LookupMember(string name)
{
return new PerspexXamlMember(name, this, this.TypeRepository, this.FeatureProvider, this.propertyBinder);
return new PerspexXamlMember(name, this, TypeRepository, FeatureProvider, _propertyBinder);
}
public override string ToString()

37
src/Markup/Perspex.Markup.Xaml/Converters/BitmapConverter.cs

@ -1,37 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="BitmapConverter.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Markup.Xaml.Converters
{
using System;
using System.Globalization;
using Media.Imaging;
using OmniXaml.TypeConversion;
public class BitmapConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return true;
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return true;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
var path = (string)value;
return new Bitmap(path);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
return new Bitmap(10, 10);
}
}
}

33
src/Markup/Perspex.Markup.Xaml/Converters/BitmapTypeConverter.cs

@ -0,0 +1,33 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Media.Imaging;
namespace Perspex.Markup.Xaml.Converters
{
public class BitmapTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return new Bitmap((string)value);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

89
src/Markup/Perspex.Markup.Xaml/Converters/BrushConverter.cs

@ -1,89 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="BrushConverter.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Markup.Xaml.Converters
{
using System;
using System.Globalization;
using System.Text;
using Media;
using Media.Imaging;
using OmniXaml.TypeConversion;
using Platform;
public class BrushConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return true;
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return true;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
var colorString = (string)value;
var color = DecodeColor(colorString);
return new SolidColorBrush(color);
}
private static Color DecodeColor(string colorString)
{
if (colorString[0] == '#')
{
var restOfValue = colorString.Remove(0, 1);
if (restOfValue.Length == 8)
{
var a = Convert.ToByte(restOfValue.Substring(0, 2), 16);
var r = Convert.ToByte(restOfValue.Substring(2, 2), 16);
var g = Convert.ToByte(restOfValue.Substring(6, 2), 16);
var b = Convert.ToByte(restOfValue.Substring(8, 2), 16);
return Color.FromArgb(a, r, g, b);
}
if (restOfValue.Length == 6)
{
var r = Convert.ToByte(restOfValue.Substring(0, 2), 16);
var g = Convert.ToByte(restOfValue.Substring(2, 2), 16);
var b = Convert.ToByte(restOfValue.Substring(4, 2), 16);
return Color.FromRgb(r, g, b);
}
throw new InvalidOperationException("The color code format cannot be parsed");
}
else
{
return DecodeFromNamedColor(colorString);
}
throw new InvalidOperationException($"The color cannot be decoded from the string \"{colorString}\"");
}
private static Color DecodeFromNamedColor(string colorString)
{
if (colorString == "Crimson")
{
return DecodeColor("#DC143C");
}
if (colorString == "Coral")
{
return DecodeColor("#FF7F50");
}
throw new NotImplementedException();
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

33
src/Markup/Perspex.Markup.Xaml/Converters/BrushTypeConverter.cs

@ -0,0 +1,33 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Media;
namespace Perspex.Markup.Xaml.Converters
{
public class BrushTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return Brush.Parse((string)value);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

33
src/Markup/Perspex.Markup.Xaml/Converters/ClassesTypeConverter.cs

@ -0,0 +1,33 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Styling;
namespace Perspex.Markup.Xaml.Converters
{
public class ClassesTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return new Classes(((string)value).Split(' '));
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

33
src/Markup/Perspex.Markup.Xaml/Converters/ColorTypeConverter.cs

@ -0,0 +1,33 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Media;
namespace Perspex.Markup.Xaml.Converters
{
public class ColorTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return Color.Parse((string)value);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

33
src/Markup/Perspex.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs

@ -0,0 +1,33 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Controls;
namespace Perspex.Markup.Xaml.Converters
{
public class ColumnDefinitionsTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return new ColumnDefinitions((string)value);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

48
src/Markup/Perspex.Markup.Xaml/Converters/GridLengthTypeConverter.cs

@ -1,51 +1,33 @@
// -----------------------------------------------------------------------
// <copyright file="GridLengthTypeConverter.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Controls;
namespace Perspex.Markup.Xaml.Converters
{
using System;
using System.Globalization;
using Controls;
using OmniXaml.TypeConversion;
public class GridLengthTypeConverter : ITypeConverter
{
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
var str = value as string;
if (str != null)
{
if (string.Equals(str, "Auto"))
{
return new GridLength(0, GridUnitType.Auto);
}
}
return new GridLength(1, GridUnitType.Star);
return sourceType == typeof(string);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
if ((string) value == "Auto")
{
return new GridLength(0, GridUnitType.Auto);
}
return new GridLength(1, GridUnitType.Star);
return false;
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return true;
return GridLength.Parse((string)value, culture);
}
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
return true;
throw new NotImplementedException();
}
}
}

72
src/Markup/Perspex.Markup.Xaml/Converters/PerspexPropertyTypeConverter.cs

@ -0,0 +1,72 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using System.Linq;
using OmniXaml;
using OmniXaml.TypeConversion;
using Perspex.Styling;
namespace Perspex.Markup.Xaml.Converters
{
public class PerspexPropertyTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
var s = (string)value;
var lastDot = s.LastIndexOf('.');
if (lastDot == -1)
{
throw new NotSupportedException("PerspexProperties must currently be fully qualified.");
}
var typeName = s.Substring(0, lastDot);
var propertyName = s.Substring(lastDot + 1);
var type = context.TypeRepository.GetByQualifiedName(typeName)?.UnderlyingType;
var styleType = context.TypeRepository.GetXamlType(typeof(Style));
// ATTN: SuperJMN
//var style = ((XamlTypeConverterContext)context).TopDownValueContext.GetLastInstance(styleType);
if (type == null)
{
throw new XamlParseException($"Could not find type '{typeName}'.");
}
// First look for non-attached property on the type and then look for an attached property.
var property = PerspexObject.GetRegisteredProperties(type)
.FirstOrDefault(x => x.Name == propertyName);
if (property == null)
{
property = PerspexObject.GetAttachedProperties(type)
.FirstOrDefault(x => x.Name == propertyName);
}
if (property == null)
{
throw new XamlParseException(
$"Could not find PerspexProperty '{typeName}'.{propertyName}.");
}
return property;
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

32
src/Markup/Perspex.Markup.Xaml/Converters/PointTypeConverter.cs

@ -0,0 +1,32 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
namespace Perspex.Markup.Xaml.Converters
{
public class PointTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return Point.Parse((string)value, culture);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

32
src/Markup/Perspex.Markup.Xaml/Converters/RelativePointTypeConverter.cs

@ -0,0 +1,32 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
namespace Perspex.Markup.Xaml.Converters
{
public class RelativePointTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return RelativePoint.Parse((string)value, culture);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

33
src/Markup/Perspex.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs

@ -0,0 +1,33 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Controls;
namespace Perspex.Markup.Xaml.Converters
{
public class RowDefinitionsTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return new RowDefinitions((string)value);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

34
src/Markup/Perspex.Markup.Xaml/Converters/SelectorTypeConverter.cs

@ -0,0 +1,34 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Markup.Xaml.Parsers;
namespace Perspex.Markup.Xaml.Converters
{
public class SelectorTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
var parser = new SelectorParser((t, ns) => context.TypeRepository.GetByPrefix(ns ?? "", t).UnderlyingType);
return parser.Parse((string)value);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

81
src/Markup/Perspex.Markup.Xaml/Converters/ThicknessConverter.cs

@ -1,81 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="ThicknessConverter.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Markup.Xaml.Converters
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using OmniXaml.TypeConversion;
public class ThicknessConverter : ITypeConverter
{
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
var s = value as string;
if (s != null)
{
return ConvertFromString(s);
}
return null;
}
private static Thickness ConvertFromString(string s)
{
var parts = s.Split(',')
.Take(4)
.Select(part => part.Trim());
if (parts.Count() == 1)
{
var uniformLength = double.Parse(parts.First());
return new Thickness(uniformLength);
}
double left = 0, top = 0, right = 0, bottom = 0;
IList<Action<double>> setValue = new List<Action<double>>
{
val => left = val,
val => top = val,
val => right = val,
val => bottom = val,
};
var i = 0;
foreach (var part in parts)
{
var v = double.Parse(part);
setValue[i](v);
i++;
}
return new Thickness(left, top, right, bottom);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new System.NotImplementedException();
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
throw new NotImplementedException();
}
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return false;
}
}
}

32
src/Markup/Perspex.Markup.Xaml/Converters/ThicknessTypeConverter.cs

@ -0,0 +1,32 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Globalization;
using OmniXaml.TypeConversion;
namespace Perspex.Markup.Xaml.Converters
{
public class ThicknessTypeConverter : ITypeConverter
{
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType)
{
return false;
}
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value)
{
return Thickness.Parse((string)value, culture);
}
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType)
{
throw new NotImplementedException();
}
}
}

98
src/Markup/Perspex.Markup.Xaml/DataBinding/ChangeTracking/ObservablePropertyBranch.cs

@ -1,56 +1,58 @@
// -----------------------------------------------------------------------
// <copyright file="ObservablePropertyBranch.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Reflection;
using Glass;
namespace Perspex.Markup.Xaml.DataBinding.ChangeTracking
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System.Reflection;
using Glass;
public class ObservablePropertyBranch
{
private readonly object root;
private readonly PropertyPath propertyPath;
private PropertyMountPoint mountPoint;
private readonly object _instance;
private readonly PropertyPath _propertyPath;
private readonly PropertyMountPoint _mountPoint;
public ObservablePropertyBranch(object root, PropertyPath propertyPath)
public ObservablePropertyBranch(object instance, PropertyPath propertyPath)
{
Guard.ThrowIfNull(root, nameof(root));
Guard.ThrowIfNull(instance, nameof(instance));
Guard.ThrowIfNull(propertyPath, nameof(propertyPath));
this.root = root;
this.propertyPath = propertyPath;
this.mountPoint = new PropertyMountPoint(root, propertyPath);
var subscriptions = this.GetInpcNodes();
this.Changed = this.CreateObservableFromNodes(subscriptions);
_instance = instance;
_propertyPath = propertyPath;
_mountPoint = new PropertyMountPoint(instance, propertyPath);
var properties = GetPropertiesThatRaiseNotifications();
Values = CreateUnifiedObservableFromNodes(properties);
}
public IObservable<object> Values { get; private set; }
private IObservable<object> CreateUnifiedObservableFromNodes(IEnumerable<PropertyDefinition> subscriptions)
{
return subscriptions.Select(GetObservableFromProperty).Merge();
}
private IObservable<object> CreateObservableFromNodes(IEnumerable<InpcNode> subscriptions)
private IObservable<object> GetObservableFromProperty(PropertyDefinition subscription)
{
return subscriptions.Select(
subscription => Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
ev => subscription.Parent.PropertyChanged += ev,
handler => subscription.Parent.PropertyChanged -= handler)
.Do(_ => this.mountPoint = new PropertyMountPoint(this.root, this.propertyPath))
.Where(pattern => pattern.EventArgs.PropertyName == subscription.PropertyName))
.Merge();
return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
parentOnPropertyChanged => subscription.Parent.PropertyChanged += parentOnPropertyChanged,
parentOnPropertyChanged => subscription.Parent.PropertyChanged -= parentOnPropertyChanged)
.Where(pattern => pattern.EventArgs.PropertyName == subscription.PropertyName)
.Select(pattern => _mountPoint.Value);
}
private IEnumerable<InpcNode> GetInpcNodes()
private IEnumerable<PropertyDefinition> GetPropertiesThatRaiseNotifications()
{
return this.GetSubscriptionsRecursive(this.root, this.propertyPath, 0);
return GetSubscriptionsRecursive(_instance, _propertyPath, 0);
}
private IEnumerable<InpcNode> GetSubscriptionsRecursive(object current, PropertyPath propertyPath, int i)
private IEnumerable<PropertyDefinition> GetSubscriptionsRecursive(object current, PropertyPath propertyPath, int i)
{
var subscriptions = new List<InpcNode>();
var subscriptions = new List<PropertyDefinition>();
var inpc = current as INotifyPropertyChanged;
if (inpc == null)
@ -59,42 +61,44 @@ namespace Perspex.Markup.Xaml.DataBinding.ChangeTracking
}
var nextPropertyName = propertyPath.Chunks[i];
subscriptions.Add(new InpcNode(inpc, nextPropertyName));
subscriptions.Add(new PropertyDefinition(inpc, nextPropertyName));
if (i < this.propertyPath.Chunks.Length)
if (i < _propertyPath.Chunks.Length)
{
var currentObjectTypeInfo = current.GetType().GetTypeInfo();
var nextProperty = currentObjectTypeInfo.GetDeclaredProperty(nextPropertyName);
var nextInstance = nextProperty.GetValue(current);
subscriptions.AddRange(this.GetSubscriptionsRecursive(nextInstance, propertyPath, i + 1));
if (i < _propertyPath.Chunks.Length - 1)
{
subscriptions.AddRange(GetSubscriptionsRecursive(nextInstance, propertyPath, i + 1));
}
}
return subscriptions;
}
public IObservable<object> Changed { get; }
public object Value
{
get
{
return this.mountPoint.Value;
return _mountPoint.Value;
}
set
{
this.mountPoint.Value = value;
_mountPoint.Value = value;
}
}
public Type Type => this.mountPoint.ProperyType;
public Type Type => _mountPoint.ProperyType;
private class InpcNode
private class PropertyDefinition
{
public InpcNode(INotifyPropertyChanged parent, string propertyName)
public PropertyDefinition(INotifyPropertyChanged parent, string propertyName)
{
this.Parent = parent;
this.PropertyName = propertyName;
Parent = parent;
PropertyName = propertyName;
}
public INotifyPropertyChanged Parent { get; }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save