Browse Source

Merge branch 'master' of https://github.com/Perspex/Perspex

pull/327/head
Steven Kirk 11 years ago
parent
commit
d0b3252161
  1. 894
      Perspex.sln
  2. 1
      nuget/build-appveyor.ps1
  3. 12
      nuget/build-version.ps1
  4. 27
      nuget/template/Perspex.Android.nuspec
  5. 822
      samples/TestApplication/Program.cs
  6. 153
      samples/TestApplication/TestApplication-Mono.csproj
  7. 14
      samples/TestApplication/TestApplication.csproj
  8. 11
      samples/TestApplicationShared/App.cs
  9. 0
      samples/TestApplicationShared/GalleryStyle.cs
  10. 0
      samples/TestApplicationShared/Item.cs
  11. 826
      samples/TestApplicationShared/MainWindow.cs
  12. 0
      samples/TestApplicationShared/Node.cs
  13. 29
      samples/TestApplicationShared/TestApplicationShared.projitems
  14. 13
      samples/TestApplicationShared/TestApplicationShared.shproj
  15. 0
      samples/TestApplicationShared/github_icon.png
  16. 0
      samples/TestApplicationShared/html.htm
  17. 0
      samples/TestApplicationShared/pattern.jpg
  18. 54
      src/Android/Perspex.Android/AndroidPlatform.cs
  19. 84
      src/Android/Perspex.Android/AndroidThreadingInterface.cs
  20. 12
      src/Android/Perspex.Android/CursorFactory.cs
  21. 157
      src/Android/Perspex.Android/Perspex.Android.csproj
  22. 59
      src/Android/Perspex.Android/Platform/AndroidTopLevelRenderer.cs
  23. 47
      src/Android/Perspex.Android/Platform/ClipboardImpl.cs
  24. 217
      src/Android/Perspex.Android/Platform/Input/AndroidKeyboardDevice.cs
  25. 12
      src/Android/Perspex.Android/Platform/Input/AndroidMouseDevice.cs
  26. 37
      src/Android/Perspex.Android/Platform/SkiaPlatform/MainWindowImpl.cs
  27. 154
      src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs
  28. 145
      src/Android/Perspex.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
  29. 136
      src/Android/Perspex.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
  30. 12
      src/Android/Perspex.Android/Platform/Specific/IAndroidActivity.cs
  31. 16
      src/Android/Perspex.Android/Platform/Specific/IAndroidView.cs
  32. 60
      src/Android/Perspex.Android/Platform/Specific/PerspexActivity.cs
  33. 30
      src/Android/Perspex.Android/Properties/AssemblyInfo.cs
  34. 50
      src/Android/Perspex.Android/Resources/AboutResources.txt
  35. 60
      src/Android/Perspex.Android/Resources/Resource.Designer.cs
  36. 6
      src/Android/Perspex.Android/Resources/Values/Strings.xml
  37. 16
      src/Android/Perspex.Android/SystemDialogImpl.cs
  38. 9
      src/Android/Perspex.Android/packages.config
  39. 19
      src/Android/Perspex.AndroidTestApplication/Assets/AboutAssets.txt
  40. 44
      src/Android/Perspex.AndroidTestApplication/MainActivity.cs
  41. 204
      src/Android/Perspex.AndroidTestApplication/Perspex.AndroidTestApplication.csproj
  42. 6
      src/Android/Perspex.AndroidTestApplication/Properties/AndroidManifest.xml
  43. 30
      src/Android/Perspex.AndroidTestApplication/Properties/AssemblyInfo.cs
  44. 50
      src/Android/Perspex.AndroidTestApplication/Resources/AboutResources.txt
  45. 86
      src/Android/Perspex.AndroidTestApplication/Resources/Resource.Designer.cs
  46. BIN
      src/Android/Perspex.AndroidTestApplication/Resources/drawable/Icon.png
  47. 6
      src/Android/Perspex.AndroidTestApplication/Resources/values/Strings.xml
  48. 12
      src/Android/Perspex.AndroidTestApplication/packages.config
  49. 2
      src/Gtk/Perspex.Gtk/GtkPlatform.cs
  50. 12
      src/Perspex.Application/Application.cs
  51. 19
      src/Perspex.Controls/Platform/PlatformManager.cs
  52. 4
      src/Perspex.Input/Platform/IPlatformSettings.cs
  53. 16
      src/Shared/PlatformSupport/AssetLoader.cs
  54. 5
      src/Shared/PlatformSupport/SharedPlatform.cs
  55. 2
      src/Skia/Perspex.Skia.Android.TestApp/Perspex.Skia.Android.TestApp.csproj
  56. 122
      src/Skia/Perspex.Skia.Android.TestApp/Perspex.Skia.Android.TestApp.csproj.bak
  57. 2
      src/Skia/Perspex.Skia.Android/Perspex.Skia.Android.csproj
  58. 16
      src/Skia/Perspex.Skia.Android/SkiaView.cs
  59. 74
      src/Skia/Perspex.Skia.iOS.TestApp/AppDelegate.cs
  60. 5
      src/Skia/Perspex.Skia.iOS.TestApp/Entitlements.plist
  61. 4
      src/Skia/Perspex.Skia.iOS.TestApp/GettingStarted.Xamarin
  62. 42
      src/Skia/Perspex.Skia.iOS.TestApp/Info.plist
  63. 15
      src/Skia/Perspex.Skia.iOS.TestApp/Main.cs
  64. 80
      src/Skia/Perspex.Skia.iOS.TestApp/MainView.cs
  65. 147
      src/Skia/Perspex.Skia.iOS.TestApp/Perspex.Skia.iOS.TestApp.csproj
  66. 36
      src/Skia/Perspex.Skia.iOS.TestApp/Properties/AssemblyInfo.cs
  67. 43
      src/Skia/Perspex.Skia.iOS.TestApp/Resources/LaunchScreen.xib
  68. 94
      src/Skia/Perspex.Skia.iOS/Perspex.Skia.iOS.csproj
  69. 36
      src/Skia/Perspex.Skia.iOS/Properties/AssemblyInfo.cs
  70. 19
      src/Skia/Perspex.Skia.iOS/iOSMethodTable.cs
  71. 2
      src/Skia/Perspex.Skia/MethodTable.cs
  72. 1
      src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs
  73. 2
      src/Windows/Perspex.Win32/Win32Platform.cs
  74. 1
      tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj

894
Perspex.sln

File diff suppressed because it is too large

1
nuget/build-appveyor.ps1

@ -26,6 +26,7 @@ if ([string]::IsNullOrWhiteSpace($pullreq))
nuget.exe push Perspex.$version.nupkg $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package
nuget.exe push Perspex.Desktop.$version.nupkg $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package
nuget.exe push Perspex.Skia.Desktop.$version.nupkg $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package
nuget.exe push Perspex.Android.$version.nupkg $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package
}
}

12
nuget/build-version.ps1

@ -3,6 +3,7 @@ $ErrorActionPreference = "Stop"
rm -Force -Recurse .\Perspex -ErrorAction SilentlyContinue
rm -Force -Recurse .\Perspex.Desktop -ErrorAction SilentlyContinue
rm -Force -Recurse .\Perspex.Skia.Desktop -ErrorAction SilentlyContinue
rm -Force -Recurse .\Perspex.Android -ErrorAction SilentlyContinue
rm -Force -Recurse *.nupkg -ErrorAction SilentlyContinue
Copy-Item template Perspex -Recurse
@ -12,10 +13,12 @@ sv build "Perspex.Desktop\lib\net45"
sv skia_root "Perspex.Skia.Desktop"
sv skia_lib "Perspex.Skia.Desktop\lib\net45"
sv skia_native "Perspex.Skia.Desktop\build\net45\native"
sv android "Perspex.Android\lib\MonoAndroid10"
mkdir $lib -ErrorAction SilentlyContinue
mkdir $build -ErrorAction SilentlyContinue
mkdir $skia_lib
mkdir $android
Copy-Item ..\src\Perspex.Animation\bin\Release\Perspex.Animation.dll $lib
@ -59,13 +62,20 @@ Copy-Item ..\src\Skia\native\Linux $skia_native -recurse
Copy-Item ..\src\Skia\Perspex.Skia.Desktop\bin\Release\Perspex.Skia.Desktop.dll $skia_lib
Copy-Item ..\src\Android\Perspex.Android\bin\Release\Perspex.Android.dll $android
Copy-Item ..\src\Skia\Perspex.Skia.Android\bin\Release\Perspex.Skia.Android.dll $android
(gc Perspex\Perspex.nuspec).replace('#VERSION#', $args[0]) | sc Perspex\Perspex.nuspec
(gc Perspex\Perspex.Desktop.nuspec).replace('#VERSION#', $args[0]) | sc Perspex.Desktop\Perspex.Desktop.nuspec
(gc Perspex\Perspex.Skia.Desktop.nuspec).replace('#VERSION#', $args[0]) | sc Perspex.Skia.Desktop\Perspex.Skia.Desktop.nuspec
(gc Perspex\Perspex.Android.nuspec).replace('#VERSION#', $args[0]) | sc Perspex.Android\Perspex.Android.nuspec
nuget.exe pack Perspex\Perspex.nuspec
nuget.exe pack Perspex.Desktop\Perspex.Desktop.nuspec
nuget.exe pack Perspex.Skia.Desktop\Perspex.Skia.Desktop.nuspec
nuget.exe pack Perspex.Android\Perspex.Android.nuspec
rm -Force -Recurse .\Perspex
rm -Force -Recurse .\Perspex.Desktop
rm -Force -Recurse .\Perspex.Skia.Desktop
rm -Force -Recurse .\Perspex.Skia.Desktop
rm -Force -Recurse .\Perspex.Android

27
nuget/template/Perspex.Android.nuspec

@ -0,0 +1,27 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>Perspex.Android</id>
<version>#VERSION#</version>
<authors>Perspex Team</authors>
<owners>stevenk</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>https://github.com/Perspex/Perspex/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>The Perspex UI framework</description>
<releaseNotes></releaseNotes>
<copyright>Copyright 2015</copyright>
<tags>Perspex</tags>
<dependencies>
<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" />
<dependency id="Perspex" version="#VERSION#" />
</dependencies>
</metadata>
</package>

822
samples/TestApplication/Program.cs

@ -26,828 +26,16 @@ namespace TestApplication
{
internal class Program
{
private static readonly PerspexList<Node> s_treeData = new PerspexList<Node>
{
new Node
{
Name = "Root 1",
Children = new PerspexList<Node>
{
new Node
{
Name = "Child 1",
},
new Node
{
Name = "Child 2",
Children = new PerspexList<Node>
{
new Node
{
Name = "Grandchild 1",
},
new Node
{
Name = "Grandmaster Flash",
},
}
},
new Node
{
Name = "Child 3",
},
}
},
new Node
{
Name = "Root 2",
},
};
private static readonly PerspexList<Item> s_listBoxData = new PerspexList<Item>
{
new Item { Name = "Item 1", Value = "Item 1 Value" },
new Item { Name = "Item 2", Value = "Item 2 Value" },
new Item { Name = "Item 3", Value = "Item 3 Value" },
new Item { Name = "Item 4", Value = "Item 4 Value" },
new Item { Name = "Item 5", Value = "Item 5 Value" },
new Item { Name = "Item 6", Value = "Item 6 Value" },
new Item { Name = "Item 7", Value = "Item 7 Value" },
new Item { Name = "Item 8", Value = "Item 8 Value" },
};
private static void Main(string[] args)
{
// The version of ReactiveUI currently included is for WPF and so expects a WPF
// dispatcher. This makes sure it's initialized.
System.Windows.Threading.Dispatcher foo = System.Windows.Threading.Dispatcher.CurrentDispatcher;
new App
{
DataTemplates = new DataTemplates
{
new FuncTreeDataTemplate<Node>(
x => new TextBlock { Text = x.Name },
x => x.Children,
x => true),
},
};
TabControl container;
Window window = new Window
{
Title = "Perspex Test Application",
Width = 900,
Height = 480,
Content = new Grid
{
ColumnDefinitions = new ColumnDefinitions
{
new ColumnDefinition(1, GridUnitType.Star),
new ColumnDefinition(1, GridUnitType.Star),
},
RowDefinitions = new RowDefinitions
{
new RowDefinition(GridLength.Auto),
new RowDefinition(1, GridUnitType.Star),
new RowDefinition(GridLength.Auto),
},
Children = new Controls
{
(container = new TabControl
{
Padding = new Thickness(5),
Items = new[]
{
ButtonsTab(),
TextTab(),
HtmlTab(),
ImagesTab(),
ListsTab(),
LayoutTab(),
AnimationsTab(),
},
Transition = new CrossFade(TimeSpan.FromSeconds(0.25)),
[Grid.RowProperty] = 1,
[Grid.ColumnSpanProperty] = 2,
})
}
},
};
container.Classes.Add(":container");
DevTools.Attach(window);
window.Show();
Application.Current.Run(window);
}
private static TabItem ButtonsTab()
{
var result = new TabItem
{
Header = "Button",
Content = new ScrollViewer()
{
CanScrollHorizontally = false,
Content = new StackPanel
{
Margin = new Thickness(10),
Orientation = Orientation.Vertical,
Gap = 4,
Children = new Controls
{
new TextBlock
{
Text = "Button",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A button control",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new Button
{
Width = 150,
Content = "Button"
},
new Button
{
Width = 150,
Content = "Disabled",
IsEnabled = false,
},
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "ToggleButton",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A toggle button control",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new ToggleButton
{
Width = 150,
IsChecked = true,
Content = "On"
},
new ToggleButton
{
Width = 150,
IsChecked = false,
Content = "Off"
},
}
}
},
};
return result;
}
private static TabItem HtmlTab()
{
return new TabItem
{
Header = "Text",
Content = new ScrollViewer()
{
CanScrollHorizontally = false,
Content = new StackPanel()
{
Margin = new Thickness(10),
Orientation = Orientation.Vertical,
Gap = 4,
Children = new Controls
{
new TextBlock
{
Text = "TextBlock",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A control for displaying text.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new TextBlock
{
Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
FontSize = 11
},
new TextBlock
{
Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
FontSize = 11,
FontWeight = FontWeight.Medium
},
new TextBlock
{
Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
FontSize = 11,
FontWeight = FontWeight.Bold
},
new TextBlock
{
Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
FontSize = 11,
FontStyle = FontStyle.Italic,
},
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "HtmlLabel",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A label capable of displaying HTML content",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new HtmlLabel
{
Background = SolidColorBrush.Parse("#CCCCCC"),
Padding = new Thickness(5),
Text = @"<p><strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href=""#"">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p>
<h2>Header Level 2</h2>
<ol>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ol>
<blockquote><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.</p></blockquote>
<h3>Header Level 3</h3>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ul>"
}
}
}
}
};
}
private static TabItem TextTab()
{
return new TabItem
{
Header = "Input",
Content = new ScrollViewer()
{
Content = new StackPanel
{
Margin = new Thickness(10),
Orientation = Orientation.Vertical,
Gap = 4,
Children = new Controls
{
new TextBlock
{
Text = "TextBox",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A text box control",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new TextBox { Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", Width = 200},
new TextBox { Width = 200, Watermark="Watermark"},
new TextBox { Width = 200, Watermark="Floating Watermark", UseFloatingWatermark = true },
new TextBox { AcceptsReturn = true, TextWrapping = TextWrapping.Wrap, Width = 200, Height = 150, Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." },
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "CheckBox",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A check box control",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new CheckBox { IsChecked = true, Margin = new Thickness(0, 0, 0, 5), Content = "Checked" },
new CheckBox { IsChecked = false, Content = "Unchecked" },
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "RadioButton",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A radio button control",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new RadioButton { IsChecked = true, Content = "Option 1" },
new RadioButton { IsChecked = false, Content = "Option 2" },
new RadioButton { IsChecked = false, Content = "Option 3" },
}
}
}
};
}
private static TabItem ListsTab()
{
return new TabItem
{
Header = "Lists",
Content = new ScrollViewer()
{
CanScrollHorizontally = false,
Content = new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Left,
Orientation = Orientation.Vertical,
VerticalAlignment = VerticalAlignment.Top,
Gap = 4,
Margin = new Thickness(10),
DataTemplates = new DataTemplates
{
new FuncDataTemplate<Item>(x =>
new StackPanel
{
Gap = 4,
Orientation = Orientation.Horizontal,
Children = new Controls
{
new Image { Width = 50, Height = 50, Source = new Bitmap("github_icon.png") },
new TextBlock { Text = x.Name, FontSize = 18 }
}
})
},
Children = new Controls
{
new TextBlock
{
Text = "ListBox",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A list box control.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new ListBox
{
BorderThickness = 2,
Items = s_listBoxData,
Height = 300,
Width = 300,
},
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "TreeView",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A tree view control.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new TreeView
{
Name = "treeView",
Items = s_treeData,
Height = 300,
BorderThickness = 2,
Width = 300,
}
}
},
}
};
}
private static TabItem ImagesTab()
{
var imageCarousel = new Carousel
{
Width = 400,
Height = 400,
Transition = new PageSlide(TimeSpan.FromSeconds(0.25)),
Items = new[]
{
new Image { Source = new Bitmap("github_icon.png"), Width = 400, Height = 400 },
new Image { Source = new Bitmap("pattern.jpg"), Width = 400, Height = 400 },
}
};
var next = new Button
{
VerticalAlignment = VerticalAlignment.Center,
Padding = new Thickness(20),
Content = new Perspex.Controls.Shapes.Path
{
Data = StreamGeometry.Parse("M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z"),
Fill = Brushes.Black
}
};
var prev = new Button
{
VerticalAlignment = VerticalAlignment.Center,
Padding = new Thickness(20),
Content = new Perspex.Controls.Shapes.Path
{
Data = StreamGeometry.Parse("M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z"),
Fill = Brushes.Black
}
};
prev.Click += (s, e) =>
{
if (imageCarousel.SelectedIndex == 0)
imageCarousel.SelectedIndex = 1;
else
imageCarousel.SelectedIndex--;
};
next.Click += (s, e) =>
{
if (imageCarousel.SelectedIndex == 1)
imageCarousel.SelectedIndex = 0;
else
imageCarousel.SelectedIndex++;
};
return new TabItem
{
Header = "Images",
Content = new ScrollViewer
{
Content = new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Left,
Orientation = Orientation.Vertical,
VerticalAlignment = VerticalAlignment.Top,
Gap = 4,
Margin = new Thickness(10),
Children = new Controls
{
new TextBlock
{
Text = "Carousel",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "An items control that displays its items as pages that fill the controls.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new StackPanel
{
Name = "carouselVisual",
Orientation = Orientation.Horizontal,
Gap = 4,
Children = new Controls
{
prev,
imageCarousel,
next
}
}
}
}
}
};
}
private static TabItem LayoutTab()
{
return new TabItem
{
Header = "Layout",
Content = new ScrollViewer
{
Content = new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Left,
Orientation = Orientation.Vertical,
VerticalAlignment = VerticalAlignment.Top,
Gap = 4,
Margin = new Thickness(10),
Children = new Controls
{
new TextBlock
{
Text = "Grid",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "Lays out child controls according to a grid.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new Grid
{
Width = 600,
ColumnDefinitions = new ColumnDefinitions
{
new ColumnDefinition(1, GridUnitType.Star),
new ColumnDefinition(1, GridUnitType.Star),
},
RowDefinitions = new RowDefinitions
{
new RowDefinition(1, GridUnitType.Auto),
new RowDefinition(1, GridUnitType.Auto)
},
Children = new Controls
{
new Rectangle
{
Fill = SolidColorBrush.Parse("#FF5722"),
[Grid.ColumnSpanProperty] = 2,
Height = 200,
Margin = new Thickness(2.5)
},
new Rectangle
{
Fill = SolidColorBrush.Parse("#FF5722"),
[Grid.RowProperty] = 1,
Height = 100,
Margin = new Thickness(2.5)
},
new Rectangle
{
Fill = SolidColorBrush.Parse("#FF5722"),
[Grid.RowProperty] = 1,
[Grid.ColumnProperty] = 1,
Height = 100,
Margin = new Thickness(2.5)
},
},
},
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "StackPanel",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A panel which lays out its children horizontally or vertically.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new StackPanel
{
Orientation = Orientation.Vertical,
Gap = 4,
Width = 300,
Children = new Controls
{
new Rectangle
{
Fill = SolidColorBrush.Parse("#FFC107"),
Height = 50,
},
new Rectangle
{
Fill = SolidColorBrush.Parse("#FFC107"),
Height = 50,
},
new Rectangle
{
Fill = SolidColorBrush.Parse("#FFC107"),
Height = 50,
},
}
},
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "Canvas",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A panel which lays out its children by explicit coordinates.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new Canvas
{
Background = Brushes.Yellow,
Width = 300,
Height = 400,
Children = new Controls
{
new Rectangle
{
Fill = Brushes.Blue,
Width = 63,
Height = 41,
[Canvas.LeftProperty] = 40,
[Canvas.TopProperty] = 31,
},
new Ellipse
{
Fill = Brushes.Green,
Width = 58,
Height = 58,
[Canvas.LeftProperty] = 130,
[Canvas.TopProperty] = 79,
},
}
},
}
}
}
};
}
private static TabItem AnimationsTab()
{
Border border1;
Border border2;
RotateTransform rotate;
Button button1;
var result = new TabItem
{
Header = "Animations",
Content = new StackPanel
{
Orientation = Orientation.Vertical,
Gap = 4,
Margin = new Thickness(10),
Children = new Controls
{
new TextBlock
{
Text = "Animations",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A few animations showcased below",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
(button1 = new Button
{
Content = "Animate",
Width = 120,
[Grid.ColumnProperty] = 1,
[Grid.RowProperty] = 1,
}),
new Canvas
{
ClipToBounds = false,
Children = new Controls
{
(border1 = new Border
{
Width = 100,
Height = 100,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Background = Brushes.Crimson,
RenderTransform = new RotateTransform(),
Child = new TextBox
{
Background = Brushes.White,
Text = "Hello!",
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
},
[Canvas.LeftProperty] = 100,
[Canvas.TopProperty] = 100,
}),
(border2 = new Border
{
Width = 100,
Height = 100,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Background = Brushes.Coral,
Child = new Image
{
Source = new Bitmap("github_icon.png"),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
},
RenderTransform = (rotate = new RotateTransform
{
PropertyTransitions = new PropertyTransitions
{
RotateTransform.AngleProperty.Transition(500),
}
}),
PropertyTransitions = new PropertyTransitions
{
Layoutable.WidthProperty.Transition(300),
Layoutable.HeightProperty.Transition(1000),
},
[Canvas.LeftProperty] = 400,
[Canvas.TopProperty] = 100,
}),
}
}
},
},
};
button1.Click += (s, e) =>
{
if (border2.Width == 100)
{
border2.Width = border2.Height = 400;
rotate.Angle = 180;
}
else
{
border2.Width = border2.Height = 100;
rotate.Angle = 0;
}
};
var start = Animate.Stopwatch.Elapsed;
var degrees = Animate.Timer
.Select(x =>
{
var elapsed = (x - start).TotalSeconds;
var cycles = elapsed / 4;
var progress = cycles % 1;
return 360.0 * progress;
});
border1.RenderTransform.Bind(
RotateTransform.AngleProperty,
degrees,
BindingPriority.Animation);
return result;
new App();
MainWindow.RootNamespace = "TestApplication";
var wnd = MainWindow.Create();
DevTools.Attach(wnd);
Application.Current.Run(wnd);
}
}
}

153
samples/TestApplication/TestApplication-Mono.csproj

@ -1,153 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B6FDF644-8EE5-4A6B-8ECC-C2C2E4DAF116}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TestApplication</RootNamespace>
<AssemblyName>TestApplication</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>caf18def</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug-Mono\</OutputPath>
<BaseIntermediateOutputPath>obj\Debug-Mono</BaseIntermediateOutputPath>
<DefineConstants>TRACE;DEBUG;PERSPEX_CAIRO;PERSPEX_GTK</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release-Mono\</OutputPath>
<BaseIntermediateOutputPath>obj\Release-Mono</BaseIntermediateOutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Reactive.Windows.Threading">
<HintPath>..\packages\Rx-Xaml.2.2.5\lib\net45\System.Reactive.Windows.Threading.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
<Reference Include="ReactiveUI">
<HintPath>..\packages\reactiveui-core.6.4.0.1\lib\Net45\ReactiveUI.dll</HintPath>
</Reference>
<Reference Include="Splat">
<HintPath>..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.Core">
<HintPath>..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.Interfaces">
<HintPath>..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.Linq">
<HintPath>..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.PlatformServices">
<HintPath>..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="App.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Cairo\Perspex.Cairo\Perspex.Cairo.csproj">
<Project>{FB05AC90-89BA-4F2F-A924-F37875FB547C}</Project>
<Name>Perspex.Cairo</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Animation\Perspex.Animation.csproj">
<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>
<Name>Perspex.Application</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Base\Perspex.Base.csproj">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Perspex.Base</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Controls\Perspex.Controls.csproj">
<Project>{D2221C82-4A25-4583-9B43-D791E3F6820C}</Project>
<Name>Perspex.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Diagnostics\Perspex.Diagnostics.csproj">
<Project>{7062AE20-5DCC-4442-9645-8195BDECE63E}</Project>
<Name>Perspex.Diagnostics</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Input\Perspex.Input.csproj">
<Project>{62024B2D-53EB-4638-B26B-85EEAA54866E}</Project>
<Name>Perspex.Input</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Interactivity\Perspex.Interactivity.csproj">
<Project>{6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}</Project>
<Name>Perspex.Interactivity</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>
<ProjectReference Include="..\Perspex.Styling\Perspex.Styling.csproj">
<Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Themes.Default\Perspex.Themes.Default.csproj">
<Project>{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}</Project>
<Name>Perspex.Themes.Default</Name>
</ProjectReference>
<ProjectReference Include="..\Gtk\Perspex.Gtk\Perspex.Gtk.csproj">
<Project>{54F237D5-A70A-4752-9656-0C70B1A7B047}</Project>
<Name>Perspex.Gtk</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="github_icon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\SharpDX.2.6.3\build\SharpDX.targets" Condition="Exists('..\packages\SharpDX.2.6.3\build\SharpDX.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\SharpDX.2.6.3\build\SharpDX.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\SharpDX.2.6.3\build\SharpDX.targets'))" />
</Target>
<!-- 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>
<Target Name="AfterBuild">
</Target>
-->
</Project>

14
samples/TestApplication/TestApplication.csproj

@ -68,10 +68,6 @@
</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>
@ -149,15 +145,7 @@
<Name>Perspex.Win32</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="github_icon.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<EmbeddedResource Include="html.htm" />
<Content Include="pattern.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="..\TestApplicationShared\TestApplicationShared.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\src\Shared\perspex.platform.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

11
samples/TestApplication/App.cs → samples/TestApplicationShared/App.cs

@ -3,6 +3,8 @@
using System;
using Perspex;
using Perspex.Controls;
using Perspex.Controls.Templates;
using Perspex.Themes.Default;
namespace TestApplication
@ -15,6 +17,15 @@ namespace TestApplication
InitializeSubsystems((int)Environment.OSVersion.Platform);
Styles = new DefaultTheme();
Styles.Add(new SampleTabStyle());
DataTemplates = new DataTemplates
{
new FuncTreeDataTemplate<Node>(
x => new TextBlock {Text = x.Name},
x => x.Children,
x => true),
};
}
}
}

0
samples/TestApplication/GalleryStyle.cs → samples/TestApplicationShared/GalleryStyle.cs

0
samples/TestApplication/Item.cs → samples/TestApplicationShared/Item.cs

826
samples/TestApplicationShared/MainWindow.cs

@ -0,0 +1,826 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reactive.Linq;
using System.Text;
using Perspex;
using Perspex.Animation;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Controls.Html;
using Perspex.Controls.Primitives;
using Perspex.Controls.Shapes;
using Perspex.Controls.Templates;
using Perspex.Diagnostics;
using Perspex.Layout;
using Perspex.Media;
using Perspex.Media.Imaging;
using Perspex.Platform;
using TestApplication;
namespace TestApplication
{
class MainWindow
{
private static readonly PerspexList<Node> s_treeData = new PerspexList<Node>
{
new Node
{
Name = "Root 1",
Children = new PerspexList<Node>
{
new Node
{
Name = "Child 1",
},
new Node
{
Name = "Child 2",
Children = new PerspexList<Node>
{
new Node
{
Name = "Grandchild 1",
},
new Node
{
Name = "Grandmaster Flash",
},
}
},
new Node
{
Name = "Child 3",
},
}
},
new Node
{
Name = "Root 2",
},
};
private static readonly PerspexList<Item> s_listBoxData = new PerspexList<Item>
{
new Item { Name = "Item 1", Value = "Item 1 Value" },
new Item { Name = "Item 2", Value = "Item 2 Value" },
new Item { Name = "Item 3", Value = "Item 3 Value" },
new Item { Name = "Item 4", Value = "Item 4 Value" },
new Item { Name = "Item 5", Value = "Item 5 Value" },
new Item { Name = "Item 6", Value = "Item 6 Value" },
new Item { Name = "Item 7", Value = "Item 7 Value" },
new Item { Name = "Item 8", Value = "Item 8 Value" },
};
public static Window Create()
{
TabControl container;
Window window = new Window
{
Title = "Perspex Test Application",
//Width = 900,
//Height = 480,
Content = (container = new TabControl
{
Padding = new Thickness(5),
Items = new[]
{
ButtonsTab(),
TextTab(),
HtmlTab(),
ImagesTab(),
ListsTab(),
LayoutTab(),
AnimationsTab(),
},
Transition = new CrossFade(TimeSpan.FromSeconds(0.25)),
[Grid.RowProperty] = 1,
[Grid.ColumnSpanProperty] = 2,
})
};
container.Classes.Add(":container");
window.Show();
return window;
}
private static TabItem ButtonsTab()
{
var result = new TabItem
{
Header = "Button",
Content = new ScrollViewer()
{
CanScrollHorizontally = false,
Content = new StackPanel
{
Margin = new Thickness(10),
Orientation = Orientation.Vertical,
Gap = 4,
Children = new Controls
{
new TextBlock
{
Text = "Button",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A button control",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new Button
{
Width = 150,
Content = "Button"
},
new Button
{
Width = 150,
Content = "Disabled",
IsEnabled = false,
},
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "ToggleButton",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A toggle button control",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new ToggleButton
{
Width = 150,
IsChecked = true,
Content = "On"
},
new ToggleButton
{
Width = 150,
IsChecked = false,
Content = "Off"
},
}
}
},
};
return result;
}
private static TabItem HtmlTab()
{
return new TabItem
{
Header = "Text",
Content = new ScrollViewer()
{
CanScrollHorizontally = false,
Content = new StackPanel()
{
Margin = new Thickness(10),
Orientation = Orientation.Vertical,
Gap = 4,
Children = new Controls
{
new TextBlock
{
Text = "TextBlock",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A control for displaying text.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new TextBlock
{
Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
FontSize = 11
},
new TextBlock
{
Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
FontSize = 11,
FontWeight = FontWeight.Medium
},
new TextBlock
{
Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
FontSize = 11,
FontWeight = FontWeight.Bold
},
new TextBlock
{
Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.",
FontSize = 11,
FontStyle = FontStyle.Italic,
},
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "HtmlLabel",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A label capable of displaying HTML content",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new HtmlLabel
{
Background = SolidColorBrush.Parse("#CCCCCC"),
Padding = new Thickness(5),
Text = @"<p><strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href=""#"">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p>
<h2>Header Level 2</h2>
<ol>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ol>
<blockquote><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.</p></blockquote>
<h3>Header Level 3</h3>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ul>"
}
}
}
}
};
}
private static TabItem TextTab()
{
return new TabItem
{
Header = "Input",
Content = new ScrollViewer()
{
Content = new StackPanel
{
Margin = new Thickness(10),
Orientation = Orientation.Vertical,
Gap = 4,
Children = new Controls
{
new TextBlock
{
Text = "TextBox",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A text box control",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new TextBox { Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", Width = 200},
new TextBox { Width = 200, Watermark="Watermark"},
new TextBox { Width = 200, Watermark="Floating Watermark", UseFloatingWatermark = true },
new TextBox { AcceptsReturn = true, TextWrapping = TextWrapping.Wrap, Width = 200, Height = 150, Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." },
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "CheckBox",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A check box control",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new CheckBox { IsChecked = true, Margin = new Thickness(0, 0, 0, 5), Content = "Checked" },
new CheckBox { IsChecked = false, Content = "Unchecked" },
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "RadioButton",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A radio button control",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new RadioButton { IsChecked = true, Content = "Option 1" },
new RadioButton { IsChecked = false, Content = "Option 2" },
new RadioButton { IsChecked = false, Content = "Option 3" },
}
}
}
};
}
public static string RootNamespace;
static Stream GetImage(string path)
{
return PerspexLocator.Current.GetService<IAssetLoader>().Open(new Uri("res:///" + RootNamespace + "." + path));
}
private static TabItem ListsTab()
{
return new TabItem
{
Header = "Lists",
Content = new ScrollViewer()
{
CanScrollHorizontally = false,
Content = new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Left,
Orientation = Orientation.Vertical,
VerticalAlignment = VerticalAlignment.Top,
Gap = 4,
Margin = new Thickness(10),
DataTemplates = new DataTemplates
{
new FuncDataTemplate<Item>(x =>
new StackPanel
{
Gap = 4,
Orientation = Orientation.Horizontal,
Children = new Controls
{
new Image { Width = 50, Height = 50, Source = new Bitmap(GetImage("github_icon.png")) },
new TextBlock { Text = x.Name, FontSize = 18 }
}
})
},
Children = new Controls
{
new TextBlock
{
Text = "ListBox",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A list box control.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new ListBox
{
BorderThickness = 2,
Items = s_listBoxData,
Height = 300,
Width = 300,
},
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "TreeView",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A tree view control.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new TreeView
{
Name = "treeView",
Items = s_treeData,
Height = 300,
BorderThickness = 2,
Width = 300,
}
}
},
}
};
}
private static TabItem ImagesTab()
{
var imageCarousel = new Carousel
{
Width = 400,
Height = 400,
Transition = new PageSlide(TimeSpan.FromSeconds(0.25)),
Items = new[]
{
new Image { Source = new Bitmap(GetImage("github_icon.png")), Width = 400, Height = 400 },
new Image { Source = new Bitmap(GetImage("pattern.jpg")), Width = 400, Height = 400 },
}
};
var next = new Button
{
VerticalAlignment = VerticalAlignment.Center,
Padding = new Thickness(20),
Content = new Perspex.Controls.Shapes.Path
{
Data = StreamGeometry.Parse("M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z"),
Fill = Brushes.Black
}
};
var prev = new Button
{
VerticalAlignment = VerticalAlignment.Center,
Padding = new Thickness(20),
Content = new Perspex.Controls.Shapes.Path
{
Data = StreamGeometry.Parse("M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z"),
Fill = Brushes.Black
}
};
prev.Click += (s, e) =>
{
if (imageCarousel.SelectedIndex == 0)
imageCarousel.SelectedIndex = 1;
else
imageCarousel.SelectedIndex--;
};
next.Click += (s, e) =>
{
if (imageCarousel.SelectedIndex == 1)
imageCarousel.SelectedIndex = 0;
else
imageCarousel.SelectedIndex++;
};
return new TabItem
{
Header = "Images",
Content = new ScrollViewer
{
Content = new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Left,
Orientation = Orientation.Vertical,
VerticalAlignment = VerticalAlignment.Top,
Gap = 4,
Margin = new Thickness(10),
Children = new Controls
{
new TextBlock
{
Text = "Carousel",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "An items control that displays its items as pages that fill the controls.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new StackPanel
{
Name = "carouselVisual",
Orientation = Orientation.Horizontal,
Gap = 4,
Children = new Controls
{
prev,
imageCarousel,
next
}
}
}
}
}
};
}
private static TabItem LayoutTab()
{
return new TabItem
{
Header = "Layout",
Content = new ScrollViewer
{
Content = new StackPanel
{
HorizontalAlignment = HorizontalAlignment.Left,
Orientation = Orientation.Vertical,
VerticalAlignment = VerticalAlignment.Top,
Gap = 4,
Margin = new Thickness(10),
Children = new Controls
{
new TextBlock
{
Text = "Grid",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "Lays out child controls according to a grid.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new Grid
{
Width = 600,
ColumnDefinitions = new ColumnDefinitions
{
new ColumnDefinition(1, GridUnitType.Star),
new ColumnDefinition(1, GridUnitType.Star),
},
RowDefinitions = new RowDefinitions
{
new RowDefinition(1, GridUnitType.Auto),
new RowDefinition(1, GridUnitType.Auto)
},
Children = new Controls
{
new Rectangle
{
Fill = SolidColorBrush.Parse("#FF5722"),
[Grid.ColumnSpanProperty] = 2,
Height = 200,
Margin = new Thickness(2.5)
},
new Rectangle
{
Fill = SolidColorBrush.Parse("#FF5722"),
[Grid.RowProperty] = 1,
Height = 100,
Margin = new Thickness(2.5)
},
new Rectangle
{
Fill = SolidColorBrush.Parse("#FF5722"),
[Grid.RowProperty] = 1,
[Grid.ColumnProperty] = 1,
Height = 100,
Margin = new Thickness(2.5)
},
},
},
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "StackPanel",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A panel which lays out its children horizontally or vertically.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new StackPanel
{
Orientation = Orientation.Vertical,
Gap = 4,
Width = 300,
Children = new Controls
{
new Rectangle
{
Fill = SolidColorBrush.Parse("#FFC107"),
Height = 50,
},
new Rectangle
{
Fill = SolidColorBrush.Parse("#FFC107"),
Height = 50,
},
new Rectangle
{
Fill = SolidColorBrush.Parse("#FFC107"),
Height = 50,
},
}
},
new TextBlock
{
Margin = new Thickness(0, 40, 0, 0),
Text = "Canvas",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A panel which lays out its children by explicit coordinates.",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
new Canvas
{
Background = Brushes.Yellow,
Width = 300,
Height = 400,
Children = new Controls
{
new Rectangle
{
Fill = Brushes.Blue,
Width = 63,
Height = 41,
[Canvas.LeftProperty] = 40,
[Canvas.TopProperty] = 31,
},
new Ellipse
{
Fill = Brushes.Green,
Width = 58,
Height = 58,
[Canvas.LeftProperty] = 130,
[Canvas.TopProperty] = 79,
},
}
},
}
}
}
};
}
private static TabItem AnimationsTab()
{
Border border1;
Border border2;
RotateTransform rotate;
Button button1;
var result = new TabItem
{
Header = "Animations",
Content = new StackPanel
{
Orientation = Orientation.Vertical,
Gap = 4,
Margin = new Thickness(10),
Children = new Controls
{
new TextBlock
{
Text = "Animations",
FontWeight = FontWeight.Medium,
FontSize = 20,
Foreground = SolidColorBrush.Parse("#212121"),
},
new TextBlock
{
Text = "A few animations showcased below",
FontSize = 13,
Foreground = SolidColorBrush.Parse("#727272"),
Margin = new Thickness(0, 0, 0, 10)
},
(button1 = new Button
{
Content = "Animate",
Width = 120,
[Grid.ColumnProperty] = 1,
[Grid.RowProperty] = 1,
}),
new Canvas
{
ClipToBounds = false,
Children = new Controls
{
(border1 = new Border
{
Width = 100,
Height = 100,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Background = Brushes.Crimson,
RenderTransform = new RotateTransform(),
Child = new TextBox
{
Background = Brushes.White,
Text = "Hello!",
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
},
[Canvas.LeftProperty] = 100,
[Canvas.TopProperty] = 100,
}),
(border2 = new Border
{
Width = 100,
Height = 100,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Background = Brushes.Coral,
Child = new Image
{
Source = new Bitmap(GetImage("github_icon.png")),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
},
RenderTransform = (rotate = new RotateTransform
{
PropertyTransitions = new PropertyTransitions
{
RotateTransform.AngleProperty.Transition(500),
}
}),
PropertyTransitions = new PropertyTransitions
{
Layoutable.WidthProperty.Transition(300),
Layoutable.HeightProperty.Transition(1000),
},
[Canvas.LeftProperty] = 400,
[Canvas.TopProperty] = 100,
}),
}
}
},
},
};
button1.Click += (s, e) =>
{
if (border2.Width == 100)
{
border2.Width = border2.Height = 400;
rotate.Angle = 180;
}
else
{
border2.Width = border2.Height = 100;
rotate.Angle = 0;
}
};
var start = Animate.Stopwatch.Elapsed;
var degrees = Animate.Timer
.Select(x =>
{
var elapsed = (x - start).TotalSeconds;
var cycles = elapsed / 4;
var progress = cycles % 1;
return 360.0 * progress;
});
border1.RenderTransform.Bind(
RotateTransform.AngleProperty,
degrees,
BindingPriority.Animation);
return result;
}
}
}

0
samples/TestApplication/Node.cs → samples/TestApplicationShared/Node.cs

29
samples/TestApplicationShared/TestApplicationShared.projitems

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>78345174-5b52-4a14-b9fd-d5f2428137f0</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>TestApplication</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)App.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GalleryStyle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Item.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MainWindow.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Node.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)html.htm" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)github_icon.png">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)pattern.jpg">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
</Project>

13
samples/TestApplicationShared/TestApplicationShared.shproj

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>78345174-5b52-4a14-b9fd-d5f2428137f0</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="TestApplicationShared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

0
samples/TestApplication/github_icon.png → samples/TestApplicationShared/github_icon.png

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

0
samples/TestApplication/html.htm → samples/TestApplicationShared/html.htm

0
samples/TestApplication/pattern.jpg → samples/TestApplicationShared/pattern.jpg

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

54
src/Android/Perspex.Android/AndroidPlatform.cs

@ -0,0 +1,54 @@
using Perspex.Android.CanvasRendering;
using Perspex.Android.Platform;
using Perspex.Android.Platform.Input;
using Perspex.Android.Platform.Specific;
using Perspex.Controls.Platform;
using Perspex.Input;
using Perspex.Input.Platform;
using Perspex.Platform;
using Perspex.Shared.PlatformSupport;
using Perspex.Skia;
using System;
using System.Collections.Generic;
namespace Perspex.Android
{
public class AndroidPlatform : IPlatformSettings
{
public static readonly AndroidPlatform Instance = new AndroidPlatform();
public Size DoubleClickSize => new Size(4, 4);
public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(200);
public double RenderScalingFactor => _scalingFactor;
public double LayoutScalingFactor => _scalingFactor;
private readonly double _scalingFactor = 1;
AndroidPlatform()
{
PerspexLocator.CurrentMutable
.Bind<IClipboard>().ToTransient<ClipboardImpl>()
.Bind<IStandardCursorFactory>().ToTransient<CursorFactory>()
.Bind<IKeyboardDevice>().ToSingleton<AndroidKeyboardDevice>()
.Bind<IMouseDevice>().ToSingleton<AndroidMouseDevice>()
.Bind<IPlatformSettings>().ToConstant(this)
.Bind<IPlatformThreadingInterface>().ToConstant(new AndroidThreadingInterface())
.Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
.Bind<ITopLevelRenderer>().ToTransient<AndroidTopLevelRenderer>();
SkiaPlatform.Initialize();
Application.SuppressPlatformInitialization();
PerspexLocator.CurrentMutable.Bind<IWindowImpl>().ToSingleton<Platform.SkiaPlatform.MainWindowImpl>();
_scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity;
//we have custom Assetloader so no need to overwrite it
}
public void Init(Type applicationType)
{
SharedPlatform.Register(applicationType.Assembly);
}
}
}

84
src/Android/Perspex.Android/AndroidThreadingInterface.cs

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Disposables;
using System.Text;
using System.Threading;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Perspex.Platform;
namespace Perspex.Android
{
class AndroidThreadingInterface : IPlatformThreadingInterface
{
private Handler _handler;
public AndroidThreadingInterface()
{
_handler = new Handler(global::Android.App.Application.Context.MainLooper);
}
public void RunLoop(CancellationToken cancellationToken)
{
return;
}
public IDisposable StartTimer(TimeSpan interval, Action tick)
{
if (interval.TotalMilliseconds < 10)
interval = TimeSpan.FromMilliseconds(10);
object l = new object();
var stopped = false;
Timer timer = null;
var scheduled = false;
timer = new Timer(_ =>
{
lock (l)
{
if (stopped)
{
timer.Dispose();
return;
}
if (scheduled)
return;
scheduled = true;
EnsureInvokeOnMainThread(() =>
{
tick();
lock (l)
{
scheduled = false;
}
});
}
}, null, TimeSpan.Zero, interval);
return Disposable.Create(() =>
{
lock (l)
{
stopped = true;
timer.Dispose();
}
});
}
private void EnsureInvokeOnMainThread(Action action) => _handler.Post(action);
public void Signal()
{
EnsureInvokeOnMainThread(() => Signaled?.Invoke());
}
public bool CurrentThreadIsLoopThread => Looper.MainLooper.Thread.Equals(Java.Lang.Thread.CurrentThread());
public event Action Signaled;
}
}

12
src/Android/Perspex.Android/CursorFactory.cs

@ -0,0 +1,12 @@
using System;
using Perspex.Input;
using Perspex.Platform;
namespace Perspex.Android
{
internal class CursorFactory : IStandardCursorFactory
{
public IPlatformHandle GetCursor(StandardCursorType cursorType)
=> new PlatformHandle(IntPtr.Zero, "ZeroCursor");
}
}

157
src/Android/Perspex.Android/Perspex.Android.csproj

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{7B92AF71-6287-4693-9DCB-BD5B6E927E23}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Perspex.Android</RootNamespace>
<AssemblyName>Perspex.Android</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v4.4</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Collections" />
<Reference Include="System.Core" />
<Reference Include="System.IO" />
<Reference Include="System.Reflection" />
<Reference Include="System.ObjectModel" />
<Reference Include="System.Threading.Tasks" />
<Reference Include="System.Reactive.Core, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\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">
<HintPath>..\..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\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">
<HintPath>..\..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\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">
<HintPath>..\..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AndroidPlatform.cs" />
<Compile Include="AndroidThreadingInterface.cs" />
<Compile Include="Platform\ClipboardImpl.cs" />
<Compile Include="CursorFactory.cs" />
<Compile Include="Platform\Input\AndroidKeyboardDevice.cs" />
<Compile Include="Platform\Input\AndroidMouseDevice.cs" />
<Compile Include="Platform\SkiaPlatform\MainWindowImpl.cs" />
<Compile Include="Platform\SkiaPlatform\WindowImpl.cs" />
<Compile Include="Platform\Specific\IAndroidView.cs" />
<Compile Include="Platform\Specific\IAndroidActivity.cs" />
<Compile Include="Platform\Specific\PerspexActivity.cs" />
<Compile Include="Platform\Specific\Helpers\AndroidTouchEventsHelper.cs" />
<Compile Include="Platform\Specific\Helpers\AndroidKeyboardEventsHelper.cs" />
<Compile Include="Platform\AndroidTopLevelRenderer.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SystemDialogImpl.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Resources\AboutResources.txt" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\Values\Strings.xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Markup\Perspex.Markup.Xaml\Perspex.Markup.Xaml.csproj">
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
<Name>Perspex.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Animation\Perspex.Animation.csproj">
<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>
<Name>Perspex.Application</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Base\Perspex.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Perspex.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Controls\Perspex.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Perspex.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Diagnostics\Perspex.Diagnostics.csproj">
<Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
<Name>Perspex.Diagnostics</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Input\Perspex.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Perspex.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Interactivity\Perspex.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Perspex.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Layout\Perspex.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Perspex.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.ReactiveUI\Perspex.ReactiveUI.csproj">
<Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
<Name>Perspex.ReactiveUI</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.SceneGraph\Perspex.SceneGraph.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Perspex.SceneGraph</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Styling\Perspex.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\..\Skia\Perspex.Skia.Android\Perspex.Skia.Android.csproj">
<Project>{bd43f7c0-396b-4aa1-bad9-dfde54d51298}</Project>
<Name>Perspex.Skia.Android</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="..\..\Shared\PlatformSupport\PlatformSupport.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- 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>
<Target Name="AfterBuild">
</Target>
-->
</Project>

59
src/Android/Perspex.Android/Platform/AndroidTopLevelRenderer.cs

@ -0,0 +1,59 @@
using Perspex.Controls;
using Perspex.Controls.Platform;
using Perspex.Platform;
using Perspex.Rendering;
using Perspex.Threading;
using System;
using System.Collections.Generic;
namespace Perspex.Android.CanvasRendering
{
internal class AndroidTopLevelRenderer : ITopLevelRenderer
{
public void Attach(TopLevel topLevel)
{
var resources = new List<IDisposable>();
var initialClientSize = topLevel.PlatformImpl.ClientSize;
var queueManager = ((IRenderRoot)topLevel).RenderQueueManager;
if (queueManager == null)
return;
var viewport = PlatformManager.CreateRenderTarget(topLevel.PlatformImpl);
resources.Add(viewport);
//resources.Add(queueManager.RenderNeeded.Subscribe(_
// =>
// Dispatcher.UIThread.InvokeAsync(() => topLevel.PlatformImpl.Invalidate(new Rect(topLevel.ClientSize)))));
Action pendingInvalidation = null;
resources.Add(queueManager.RenderNeeded.Subscribe(_ =>
{
if (pendingInvalidation == null)
{
pendingInvalidation = () =>
{
topLevel.PlatformImpl.Invalidate(new Rect(topLevel.ClientSize));
pendingInvalidation = null;
};
Dispatcher.UIThread.InvokeAsync(pendingInvalidation);
}
}
));
topLevel.PlatformImpl.Paint = rect =>
{
viewport.Render(topLevel);
queueManager.RenderFinished();
};
topLevel.Closed += delegate
{
foreach (var disposable in resources)
disposable.Dispose();
resources.Clear();
};
}
}
}

47
src/Android/Perspex.Android/Platform/ClipboardImpl.cs

@ -0,0 +1,47 @@
using Android.Content;
using Android.Runtime;
using Android.Views;
using Perspex.Input.Platform;
using Perspex.Platform;
using System.Threading.Tasks;
namespace Perspex.Android.Platform
{
internal class ClipboardImpl : IClipboard
{
private Context context = (PerspexLocator.Current.GetService<IWindowImpl>() as View).Context;
private ClipboardManager ClipboardManager
{
get
{
return this.context.GetSystemService(Context.ClipboardService).JavaCast<ClipboardManager>();
}
}
public Task<string> GetTextAsync()
{
if (ClipboardManager.HasPrimaryClip)
{
return Task.FromResult<string>(ClipboardManager.PrimaryClip.GetItemAt(0).Text);
}
return Task.FromResult<string>(null);
}
public Task SetTextAsync(string text)
{
ClipData clip = ClipData.NewPlainText("text", text);
ClipboardManager.PrimaryClip = clip;
return Task.FromResult<object>(null);
}
public Task ClearAsync()
{
ClipboardManager.PrimaryClip = null;
return Task.FromResult<object>(null);
}
}
}

217
src/Android/Perspex.Android/Platform/Input/AndroidKeyboardDevice.cs

@ -0,0 +1,217 @@
using System;
using Perspex.Input;
//using Android.InputMethodServices;
using System.Collections.Generic;
using Android.Views;
namespace Perspex.Android.Platform.Input
{
public class AndroidKeyboardDevice : KeyboardDevice, IKeyboardDevice {
private static readonly Dictionary<Keycode, Key> KeyDic = new Dictionary<Keycode, Key>
{
// { Keycode.Cancel?, Key.Cancel },
{ Keycode.Del, Key.Back },
{ Keycode.Tab, Key.Tab },
// { Keycode.Linefeed?, Key.LineFeed },
{ Keycode.Clear, Key.Clear },
{ Keycode.Enter, Key.Return },
{ Keycode.MediaPause, Key.Pause },
//{ Keycode.?, Key.CapsLock }
//{ Keycode.?, Key.HangulMode }
//{ Keycode.?, Key.JunjaMode }
//{ Keycode.?, Key.FinalMode }
//{ Keycode.?, Key.KanjiMode }
{ Keycode.Escape, Key.Escape },
//{ Keycode.?, Key.ImeConvert }
//{ Keycode.?, Key.ImeNonConvert }
//{ Keycode.?, Key.ImeAccept }
//{ Keycode.?, Key.ImeModeChange }
{ Keycode.Space, Key.Space },
{ Keycode.PageUp, Key.Prior },
{ Keycode.PageDown, Key.PageDown },
// { Keycode.end?, Key.End },
{ Keycode.Home, Key.Home },
{ Keycode.DpadLeft, Key.Left },
{ Keycode.DpadUp, Key.Up },
{ Keycode.DpadRight, Key.Right },
{ Keycode.DpadDown, Key.Down },
// { Keycode.ButtonSelect?, Key.Select },
// { Keycode.print?, Key.Print },
//{ Keycode.execute?, Key.Execute },
// { Keycode.snap, Key.Snapshot }
{ Keycode.Insert, Key.Insert },
{ Keycode.ForwardDel, Key.Delete },
//{ Keycode.help, Key.Help },
//{ Keycode.?, Key.D0 }
//{ Keycode.?, Key.D1 }
//{ Keycode.?, Key.D2 }
//{ Keycode.?, Key.D3 }
//{ Keycode.?, Key.D4 }
//{ Keycode.?, Key.D5 }
//{ Keycode.?, Key.D6 }
//{ Keycode.?, Key.D7 }
//{ Keycode.?, Key.D8 }
//{ Keycode.?, Key.D9 }
{ Keycode.A, Key.A },
{ Keycode.B, Key.B },
{ Keycode.C, Key.C },
{ Keycode.D, Key.D },
{ Keycode.E, Key.E },
{ Keycode.F, Key.F },
{ Keycode.G, Key.G },
{ Keycode.H, Key.H },
{ Keycode.I, Key.I },
{ Keycode.J, Key.J },
{ Keycode.K, Key.K },
{ Keycode.L, Key.L },
{ Keycode.M, Key.M },
{ Keycode.N, Key.N },
{ Keycode.O, Key.O },
{ Keycode.P, Key.P },
{ Keycode.Q, Key.Q },
{ Keycode.R, Key.R },
{ Keycode.S, Key.S },
{ Keycode.T, Key.T },
{ Keycode.U, Key.U },
{ Keycode.V, Key.V },
{ Keycode.W, Key.W },
{ Keycode.X, Key.X },
{ Keycode.Y, Key.Y },
{ Keycode.Z, Key.Z },
//{ Keycode.a, Key.A },
//{ Keycode.b, Key.B },
//{ Keycode.c, Key.C },
//{ Keycode.d, Key.D },
//{ Keycode.e, Key.E },
//{ Keycode.f, Key.F },
//{ Keycode.g, Key.G },
//{ Keycode.h, Key.H },
//{ Keycode.i, Key.I },
//{ Keycode.j, Key.J },
//{ Keycode.k, Key.K },
//{ Keycode.l, Key.L },
//{ Keycode.m, Key.M },
//{ Keycode.n, Key.N },
//{ Keycode.o, Key.O },
//{ Keycode.p, Key.P },
//{ Keycode.q, Key.Q },
//{ Keycode.r, Key.R },
//{ Keycode.s, Key.S },
//{ Keycode.t, Key.T },
//{ Keycode.u, Key.U },
//{ Keycode.v, Key.V },
//{ Keycode.w, Key.W },
//{ Keycode.x, Key.X },
//{ Keycode.y, Key.Y },
//{ Keycode.z, Key.Z },
//{ Keycode.?, Key.LWin }
//{ Keycode.?, Key.RWin }
//{ Keycode.?, Key.Apps }
//{ Keycode.?, Key.Sleep }
//{ Keycode.?, Key.NumPad0 }
//{ Keycode.?, Key.NumPad1 }
//{ Keycode.?, Key.NumPad2 }
//{ Keycode.?, Key.NumPad3 }
//{ Keycode.?, Key.NumPad4 }
//{ Keycode.?, Key.NumPad5 }
//{ Keycode.?, Key.NumPad6 }
//{ Keycode.?, Key.NumPad7 }
//{ Keycode.?, Key.NumPad8 }
//{ Keycode.?, Key.NumPad9 }
{ Keycode.NumpadMultiply, Key.Multiply },
{ Keycode.NumpadAdd, Key.Add },
{ Keycode.NumpadComma, Key.Separator },
{ Keycode.NumpadSubtract, Key.Subtract },
//{ Keycode.numpaddecimal?, Key.Decimal }
{ Keycode.NumpadDivide, Key.Divide },
{ Keycode.F1, Key.F1 },
{ Keycode.F2, Key.F2 },
{ Keycode.F3, Key.F3 },
{ Keycode.F4, Key.F4 },
{ Keycode.F5, Key.F5 },
{ Keycode.F6, Key.F6 },
{ Keycode.F7, Key.F7 },
{ Keycode.F8, Key.F8 },
{ Keycode.F9, Key.F9 },
{ Keycode.F10, Key.F10 },
{ Keycode.F11, Key.F11 },
{ Keycode.F12, Key.F12 },
//{ Keycode.f13, Key.F13 },
//{ Keycode.F14, Key.F14 },
//{ Keycode.L5, Key.F15 },
//{ Keycode.F16, Key.F16 },
//{ Keycode.F17, Key.F17 },
//{ Keycode.L8, Key.F18 },
//{ Keycode.L9, Key.F19 },
//{ Keycode.L10, Key.F20 },
//{ Keycode.R1, Key.F21 },
//{ Keycode.R2, Key.F22 },
//{ Keycode.F23, Key.F23 },
//{ Keycode.R4, Key.F24 },
// { Keycode.numpad, Key.NumLock }
{ Keycode.ScrollLock, Key.Scroll },
{ Keycode.ShiftLeft, Key.LeftShift },
//{ Keycode.?, Key.RightShift }
//{ Keycode.?, Key.LeftCtrl }
//{ Keycode.?, Key.RightCtrl }
//{ Keycode.?, Key.LeftAlt }
//{ Keycode.?, Key.RightAlt }
//{ Keycode.?, Key.BrowserBack }
//{ Keycode.?, Key.BrowserForward }
//{ Keycode.?, Key.BrowserRefresh }
//{ Keycode.?, Key.BrowserStop }
//{ Keycode.?, Key.BrowserSearch }
//{ Keycode.?, Key.BrowserFavorites }
//{ Keycode.?, Key.BrowserHome }
//{ Keycode.?, Key.VolumeMute }
//{ Keycode.?, Key.VolumeDown }
//{ Keycode.?, Key.VolumeUp }
//{ Keycode.?, Key.MediaNextTrack }
//{ Keycode.?, Key.MediaPreviousTrack }
//{ Keycode.?, Key.MediaStop }
//{ Keycode.?, Key.MediaPlayPause }
//{ Keycode.?, Key.LaunchMail }
//{ Keycode.?, Key.SelectMedia }
//{ Keycode.?, Key.LaunchApplication1 }
//{ Keycode.?, Key.LaunchApplication2 }
//{ Keycode.?, Key.OemSemicolon }
//{ Keycode.?, Key.OemPlus }
//{ Keycode.?, Key.OemComma }
//{ Keycode.?, Key.OemMinus }
//{ Keycode.?, Key.OemPeriod }
//{ Keycode.?, Key.Oem2 }
//{ Keycode.?, Key.OemTilde }
//{ Keycode.?, Key.AbntC1 }
//{ Keycode.?, Key.AbntC2 }
//{ Keycode.?, Key.Oem4 }
//{ Keycode.?, Key.OemPipe }
//{ Keycode.?, Key.OemCloseBrackets }
//{ Keycode.?, Key.Oem7 }
//{ Keycode.?, Key.Oem8 }
//{ Keycode.?, Key.Oem102 }
//{ Keycode.?, Key.ImeProcessed }
//{ Keycode.?, Key.System }
//{ Keycode.?, Key.OemAttn }
//{ Keycode.?, Key.OemFinish }
//{ Keycode.?, Key.DbeHiragana }
//{ Keycode.?, Key.OemAuto }
//{ Keycode.?, Key.DbeDbcsChar }
//{ Keycode.?, Key.OemBackTab }
//{ Keycode.?, Key.Attn }
//{ Keycode.?, Key.DbeEnterWordRegisterMode }
//{ Keycode.?, Key.DbeEnterImeConfigureMode }
//{ Keycode.?, Key.EraseEof }
//{ Keycode.?, Key.Play }
//{ Keycode.?, Key.Zoom }
//{ Keycode.?, Key.NoName }
//{ Keycode.?, Key.DbeEnterDialogConversionMode }
//{ Keycode.?, Key.OemClear }
//{ Keycode.?, Key.DeadCharProcessed }
};
internal static Key ConvertKey(Keycode key) {
Key result;
return KeyDic.TryGetValue(key, out result) ? result : Key.None;
}
}
}

12
src/Android/Perspex.Android/Platform/Input/AndroidMouseDevice.cs

@ -0,0 +1,12 @@
using Perspex.Input;
namespace Perspex.Android.Platform.Input
{
public class AndroidMouseDevice : MouseDevice
{
public AndroidMouseDevice()
{
}
}
}

37
src/Android/Perspex.Android/Platform/SkiaPlatform/MainWindowImpl.cs

@ -0,0 +1,37 @@
using Android.Views;
using Perspex.Android.Platform.Specific;
using Perspex.Input;
using Perspex.Platform;
namespace Perspex.Android.Platform.SkiaPlatform
{
public class MainWindowImpl :
WindowImpl
, IWindowImpl
{
public MainWindowImpl()
{
}
protected override void Init()
{
base.Init();
HandleEvents = true;
_keyboardHelper.ActivateAutoShowKeybord();
}
void ITopLevelImpl.Show()
{
(Parent as ViewGroup)?.RemoveAllViews();
PerspexLocator.Current.GetService<IAndroidActivity>().ContentView = this;
//this.Visibility = ViewStates.Visible;
}
void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot)
{
base.SetInputRoot(inputRoot);
_keyboardHelper.UpdateKeyboardState(inputRoot);
}
}
}

154
src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs

@ -0,0 +1,154 @@
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.Views;
using Perspex.Android.Platform.Specific;
using Perspex.Android.Platform.Specific.Helpers;
using Perspex.Input;
using Perspex.Input.Raw;
using Perspex.Platform;
using Perspex.Skia.Android;
using System;
namespace Perspex.Android.Platform.SkiaPlatform
{
public class WindowImpl : SkiaView, IAndroidView, IWindowImpl, ISurfaceHolderCallback
{
protected AndroidKeyboardEventsHelper<WindowImpl> _keyboardHelper;
private AndroidTouchEventsHelper<WindowImpl> _touchHelper;
public WindowImpl(Context context) : base((Activity)context)
{
_keyboardHelper = new AndroidKeyboardEventsHelper<WindowImpl>(this);
_touchHelper = new AndroidTouchEventsHelper<WindowImpl>(this, () => InputRoot, p => GetPerspexPointFromEvent(p));
MaxClientSize = new Size(Resources.DisplayMetrics.WidthPixels, Resources.DisplayMetrics.HeightPixels);
ClientSize = MaxClientSize;
Init();
}
public WindowImpl() : this(PerspexLocator.Current.GetService<IAndroidActivity>().Activity)
{
}
void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{
var newSize = new Size(width, height);
if (newSize != ClientSize)
{
MaxClientSize = newSize;
ClientSize = newSize;
Resized?.Invoke(ClientSize);
}
base.SurfaceChanged(holder, format, width, height);
}
protected virtual void Init()
{
}
private bool _handleEvents;
public bool HandleEvents
{
get { return _handleEvents; }
set
{
_handleEvents = value;
_keyboardHelper.HandleEvents = _handleEvents;
}
}
public virtual Point GetPerspexPointFromEvent(MotionEvent e) => new Point(e.GetX(), e.GetY());
public IInputRoot InputRoot { get; private set; }
public Size ClientSize { get; set; }
public Action Closed { get; set; }
public Action Deactivated { get; set; }
public Action<RawInputEventArgs> Input { get; set; }
public Size MaxClientSize { get; private set; }
public Action<Rect> Paint { get; set; }
public Action<Size> Resized { get; set; }
public View View => this;
Action ITopLevelImpl.Activated { get; set; }
IPlatformHandle ITopLevelImpl.Handle => this;
public void Activate()
{
}
public void Hide()
{
this.Visibility = ViewStates.Invisible;
}
public void Invalidate(Rect rect)
{
if (Holder?.Surface?.IsValid == true) base.Invalidate();
}
public Point PointToScreen(Point point)
{
return point;
}
public void SetCursor(IPlatformHandle cursor)
{
//still not implemented
}
public void SetInputRoot(IInputRoot inputRoot)
{
InputRoot = inputRoot;
}
public void SetTitle(string title)
{
}
public void Show()
{
this.Visibility = ViewStates.Visible;
}
public IDisposable ShowDialog()
{
throw new NotImplementedException();
}
public override bool DispatchTouchEvent(MotionEvent e)
{
bool callBase;
bool? result = _touchHelper.DispatchTouchEvent(e, out callBase);
bool baseResult = callBase ? base.DispatchTouchEvent(e) : false;
return result != null ? result.Value : baseResult;
}
public override bool DispatchKeyEvent(KeyEvent e)
{
bool callBase;
bool? res = _keyboardHelper.DispatchKeyEvent(e, out callBase);
bool baseResult = callBase ? base.DispatchKeyEvent(e) : false;
return res != null ? res.Value : baseResult;
}
protected override void Draw()
{
Paint?.Invoke(new Rect(new Point(0, 0), ClientSize));
}
}
}

145
src/Android/Perspex.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs

@ -0,0 +1,145 @@
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Views.InputMethods;
using Perspex.Android.Platform.Input;
using Perspex.Controls;
using Perspex.Input;
using Perspex.Input.Raw;
using Perspex.Platform;
using System;
using System.ComponentModel;
namespace Perspex.Android.Platform.Specific.Helpers
{
public class AndroidKeyboardEventsHelper<TView> : IDisposable where TView : View, IWindowImpl, IAndroidView
{
private TView _view;
private IInputElement _lastFocusedElement;
public bool HandleEvents { get; set; }
public AndroidKeyboardEventsHelper(TView view)
{
this._view = view;
HandleEvents = true;
}
public bool? DispatchKeyEvent(KeyEvent e, out bool callBase)
{
if (!HandleEvents)
{
callBase = true;
return null;
}
return DispatchKeyEventInternal(e, out callBase);
}
private bool? DispatchKeyEventInternal(KeyEvent e, out bool callBase)
{
if (e.Action == KeyEventActions.Multiple)
{
callBase = true;
return null;
}
var rawKeyEvent = new RawKeyEventArgs(
AndroidKeyboardDevice.Instance,
Convert.ToUInt32(e.EventTime),
e.Action == KeyEventActions.Down ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
AndroidKeyboardDevice.ConvertKey(e.KeyCode), GetModifierKeys(e));
_view.Input(rawKeyEvent);
if (e.Action == KeyEventActions.Down && e.UnicodeChar >= 32)
{
var rawTextEvent = new RawTextInputEventArgs(
AndroidKeyboardDevice.Instance,
Convert.ToUInt32(e.EventTime),
Convert.ToChar(e.UnicodeChar).ToString()
);
_view.Input(rawTextEvent);
}
if (e.Action == KeyEventActions.Up)
{
//nothing to do here more call base no need of more events
callBase = true;
return null;
}
callBase = false;
return false;
}
private static InputModifiers GetModifierKeys(KeyEvent e)
{
var rv = InputModifiers.None;
if (e.IsCtrlPressed) rv |= InputModifiers.Control;
if (e.IsShiftPressed) rv |= InputModifiers.Shift;
return rv;
}
private bool NeedsKeyboard(IInputElement element)
{
//may be some other elements
return element is TextBox;
}
private void TryShowHideKeyboard(IInputElement element, bool value)
{
var input = _view.Context.GetSystemService(Context.InputMethodService).JavaCast<InputMethodManager>();
if (value)
{
//show keyboard
//may be in the future different keyboards support e.g. normal, only digits etc.
//Android.Text.InputTypes
input.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.ImplicitOnly);
}
else
{
//hide keyboard
input.HideSoftInputFromWindow(_view.WindowToken, HideSoftInputFlags.None);
}
}
public void UpdateKeyboardState(IInputElement element)
{
var focusedElement = element;
bool oldValue = NeedsKeyboard(_lastFocusedElement);
bool newValue = NeedsKeyboard(focusedElement);
if (newValue != oldValue || newValue)
{
TryShowHideKeyboard(focusedElement, newValue);
}
_lastFocusedElement = element;
}
public void ActivateAutoShowKeybord()
{
var kbDevice = (KeyboardDevice.Instance as INotifyPropertyChanged);
//just in case we've called more than once the method
kbDevice.PropertyChanged -= KeyboardDevice_PropertyChanged;
kbDevice.PropertyChanged += KeyboardDevice_PropertyChanged;
}
private void KeyboardDevice_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(KeyboardDevice.FocusedElement))
{
UpdateKeyboardState(KeyboardDevice.Instance.FocusedElement);
}
}
public void Dispose()
{
HandleEvents = false;
}
}
}

136
src/Android/Perspex.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs

@ -0,0 +1,136 @@
using Android.Graphics;
using Android.Views;
using Perspex.Input;
using Perspex.Input.Raw;
using Perspex.Media;
using Perspex.Platform;
using System;
namespace Perspex.Android.Platform.Specific.Helpers
{
public class AndroidTouchEventsHelper<TView> : IDisposable where TView : View, IWindowImpl, IAndroidView
{
private TView _view;
public bool HandleEvents { get; set; }
public AndroidTouchEventsHelper(TView view, Func<IInputRoot> getInputRoot, Func<MotionEvent, Point> getPointfunc)
{
this._view = view;
HandleEvents = true;
_getPointFunc = getPointfunc;
_getInputRoot = getInputRoot;
}
private DateTime _lastTouchMoveEventTime = DateTime.Now;
private Point? _lastTouchMovePoint;
private Func<MotionEvent, Point> _getPointFunc;
private Func<IInputRoot> _getInputRoot;
private Point _point;
public bool? DispatchTouchEvent(MotionEvent e, out bool callBase)
{
if (!HandleEvents)
{
callBase = true;
return null;
}
RawMouseEventType? mouseEventType = null;
var eventTime = DateTime.Now;
//Basic touch support
switch (e.Action)
{
case MotionEventActions.Move:
//may be bot flood the evnt system with too many event especially on not so powerfull mobile devices
if ((eventTime - _lastTouchMoveEventTime).TotalMilliseconds > 10)
{
mouseEventType = RawMouseEventType.Move;
}
break;
case MotionEventActions.Down:
mouseEventType = RawMouseEventType.LeftButtonDown;
break;
case MotionEventActions.Up:
mouseEventType = RawMouseEventType.LeftButtonUp;
break;
}
if (mouseEventType != null)
{
//if point is in view otherwise it's possible perspex not to find the proper window to dispatch the event
_point = _getPointFunc(e);
double x = _view.GetX();
double y = _view.GetY();
double r = x + _view.Width;
double b = y + _view.Height;
if (x <= _point.X && r >= _point.X && y <= _point.Y && b >= _point.Y)
{
var inputRoot = _getInputRoot();
var mouseDevice = MouseDevice.Instance;
//in order the controls to work in a predictable way
//we need to generate mouse move before first mouse down event
//as this is the way buttons are working every time
//otherwise there is a problem sometimes
if (mouseEventType == RawMouseEventType.LeftButtonDown)
{
var me = new RawMouseEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
RawMouseEventType.Move, _point, InputModifiers.None);
_view.Input(me);
}
var mouseEvent = new RawMouseEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
mouseEventType.Value, _point, InputModifiers.LeftMouseButton);
_view.Input(mouseEvent);
if (e.Action == MotionEventActions.Move && mouseDevice.Captured == null)
{
if (_lastTouchMovePoint != null)
{
//raise mouse scroll event so the scrollers
//are moving with the cursor
double vectorX = _point.X - _lastTouchMovePoint.Value.X;
double vectorY = _point.Y - _lastTouchMovePoint.Value.Y;
//based on test correction of 0.02 is working perfect
double correction = 0.02;
var ps = AndroidPlatform.Instance.LayoutScalingFactor;
var mouseWheelEvent = new RawMouseWheelEventArgs(
mouseDevice,
(uint)eventTime.Ticks,
inputRoot,
_point,
new Vector(vectorX * correction / ps, vectorY * correction / ps), InputModifiers.LeftMouseButton);
_view.Input(mouseWheelEvent);
}
_lastTouchMovePoint = _point;
_lastTouchMoveEventTime = eventTime;
}
else if (e.Action == MotionEventActions.Down)
{
_lastTouchMovePoint = _point;
}
else
{
_lastTouchMovePoint = null;
}
}
}
callBase = true;
//if return false events for move and up are not received!!!
return e.Action != MotionEventActions.Up;
}
private Paint _paint;
public void Dispose()
{
HandleEvents = false;
}
}
}

12
src/Android/Perspex.Android/Platform/Specific/IAndroidActivity.cs

@ -0,0 +1,12 @@
using Android.App;
using Android.Views;
namespace Perspex.Android.Platform.Specific
{
public interface IAndroidActivity
{
Activity Activity { get; }
IAndroidView ContentView { get; set; }
}
}

16
src/Android/Perspex.Android/Platform/Specific/IAndroidView.cs

@ -0,0 +1,16 @@
using Android.Graphics;
using Android.Views;
using System;
using System.Collections.Generic;
namespace Perspex.Android.Platform.Specific
{
public interface IAndroidView
{
View View { get; }
}
}

60
src/Android/Perspex.Android/Platform/Specific/PerspexActivity.cs

@ -0,0 +1,60 @@
using System;
using Android.App;
using Android.OS;
using Android.Views;
using Android.Widget;
namespace Perspex.Android.Platform.Specific
{
public class PerspexActivity : Activity, IAndroidActivity
{
private IAndroidView _contentView;
public PerspexActivity(Type applicationType)
{
AndroidPlatform.Instance.Init(applicationType);
}
public Activity Activity => this;
public IAndroidView ContentView
{
get
{
return this._contentView;
}
set
{
this._contentView = value;
var fl = new FrameLayout(this);
fl.AddView(this._contentView.View);
//this.SetContentView(value.View);
this.SetContentView(fl);
}
}
protected override void OnCreate(Bundle savedInstanceState)
{
PerspexLocator.CurrentMutable.Bind<IAndroidActivity>().ToConstant(this);
RequestWindowFeature(WindowFeatures.NoTitle);
base.OnCreate(savedInstanceState);
}
public override void SetContentView(View view)
{
base.SetContentView(view);
TakeKeyEvents(true);
}
public override bool DispatchKeyEvent(KeyEvent e)
{
if (_contentView != null)
{
_contentView.View.DispatchKeyEvent(e);
}
return base.DispatchKeyEvent(e);
}
}
}

30
src/Android/Perspex.Android/Properties/AssemblyInfo.cs

@ -0,0 +1,30 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Perspex.Android")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Perspex.Android")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

50
src/Android/Perspex.Android/Resources/AboutResources.txt

@ -0,0 +1,50 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable-hdpi/
icon.png
drawable-ldpi/
icon.png
drawable-mdpi/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called
"Resource" that contains the tokens for each one of the resources included. For example,
for the above Resources layout, this is what the Resource class would expose:
public class Resource {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

60
src/Android/Perspex.Android/Resources/Resource.Designer.cs

@ -0,0 +1,60 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: global::Android.Runtime.ResourceDesignerAttribute("Perspex.Android.Resource", IsApplication=false)]
namespace Perspex.Android
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
public partial class Resource
{
static Resource()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
public partial class Attribute
{
static Attribute()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Attribute()
{
}
}
public partial class String
{
// aapt resource value: 0x7f020001
public static int ApplicationName = 2130837505;
// aapt resource value: 0x7f020000
public static int Hello = 2130837504;
static String()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private String()
{
}
}
}
}
#pragma warning restore 1591

6
src/Android/Perspex.Android/Resources/Values/Strings.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="Hello">Hello World, Click Me!</string>
<string name="ApplicationName">$projectname$</string>
</resources>

16
src/Android/Perspex.Android/SystemDialogImpl.cs

@ -0,0 +1,16 @@
using System;
using System.Threading.Tasks;
using Perspex.Controls;
using Perspex.Controls.Platform;
using Perspex.Platform;
namespace Perspex.Android
{
internal class SystemDialogImpl : ISystemDialogImpl
{
public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
{
throw new NotImplementedException();
}
}
}

9
src/Android/Perspex.Android/packages.config

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Rx-Core" version="2.2.5" targetFramework="monoandroid51" />
<package id="Rx-Interfaces" version="2.2.5" targetFramework="monoandroid51" />
<package id="Rx-Linq" version="2.2.5" targetFramework="monoandroid51" />
<package id="Rx-Main" version="2.2.5" targetFramework="monoandroid51" />
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="monoandroid51" />
</packages>

19
src/Android/Perspex.AndroidTestApplication/Assets/AboutAssets.txt

@ -0,0 +1,19 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories) and given a Build Action of "AndroidAsset".
These files will be deployed with you package and will be accessible using Android's
AssetManager, like this:
public class ReadAsset : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
InputStream input = Assets.Open ("my_asset.txt");
}
}
Additionally, some Android functions will automatically load asset files:
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");

44
src/Android/Perspex.AndroidTestApplication/MainActivity.cs

@ -0,0 +1,44 @@
using Android.App;
using Android.Content.PM;
using Android.OS;
using Perspex.Android;
using Perspex.Android.Platform.Specific;
using Perspex.Android.Platform.Specific.Helpers;
using Perspex.Controls.Platform;
using Perspex.Platform;
using TestApplication;
namespace Perspex.AndroidTestApplication
{
[Activity(Label = "Main",
MainLauncher = true,
Icon = "@drawable/icon",
LaunchMode = LaunchMode.SingleInstance/*,
ScreenOrientation = ScreenOrientation.Landscape*/)]
public class MainBaseActivity : PerspexActivity
{
public MainBaseActivity() : base(typeof (App))
{
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
App app;
if (Perspex.Application.Current != null)
app = (App)Perspex.Application.Current;
else
app = new App();
MainWindow.RootNamespace = "Perspex.AndroidTestApplication";
var window = MainWindow.Create();
window.Show();
app.Run(window);
}
}
}

204
src/Android/Perspex.AndroidTestApplication/Perspex.AndroidTestApplication.csproj

@ -0,0 +1,204 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{FF69B927-C545-49AE-8E16-3D14D621AA12}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Perspex.AndroidTestApplication</RootNamespace>
<AssemblyName>Perspex Test Application</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidApplication>true</AndroidApplication>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v4.4</TargetFrameworkVersion>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
<AndroidLinkSkip />
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidStoreUncompressedFileExtensions />
<MandroidI18n />
<Debugger>Xamarin</Debugger>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<DevInstrumentationEnabled>True</DevInstrumentationEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
<AndroidLinkSkip />
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidStoreUncompressedFileExtensions />
<MandroidI18n />
<Debugger>Xamarin</Debugger>
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<EnableProguard>False</EnableProguard>
<DevInstrumentationEnabled>False</DevInstrumentationEnabled>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="mscorlib" />
<Reference Include="Serilog, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Serilog.1.5.9\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Serilog.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\monoandroid\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Sprache, Version=2.0.0.47, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Sprache.2.0.0.47\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid1+MonoTouch1\Sprache.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Collections" />
<Reference Include="System.Core" />
<Reference Include="System.IO" />
<Reference Include="System.Linq.Expressions" />
<Reference Include="System.ObjectModel" />
<Reference Include="System.Reactive.Core, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\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">
<HintPath>..\..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\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">
<HintPath>..\..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\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">
<HintPath>..\..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\Strings.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\Icon.png" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\AndroidManifest.xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Android\Perspex.Android\Perspex.Android.csproj">
<Project>{7b92af71-6287-4693-9dcb-bd5b6e927e23}</Project>
<Name>Perspex.Android</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Markup\Perspex.Markup.Xaml\Perspex.Markup.Xaml.csproj">
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
<Name>Perspex.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Perspex.Animation\Perspex.Animation.csproj">
<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>
<Name>Perspex.Application</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Perspex.Base\Perspex.Base.csproj">
<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>
<Name>Perspex.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Perspex.Diagnostics\Perspex.Diagnostics.csproj">
<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>
<Name>Perspex.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Perspex.Interactivity\Perspex.Interactivity.csproj">
<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>
<Name>Perspex.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Perspex.ReactiveUI\Perspex.ReactiveUI.csproj">
<Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
<Name>Perspex.ReactiveUI</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Perspex.SceneGraph\Perspex.SceneGraph.csproj">
<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>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Perspex.Themes.Default\Perspex.Themes.Default.csproj">
<Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
<Name>Perspex.Themes.Default</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.HtmlRenderer\Perspex.HtmlRenderer.csproj">
<Project>{5fb2b005-0a7f-4dad-add4-3ed01444e63d}</Project>
<Name>Perspex.HtmlRenderer</Name>
</ProjectReference>
<ProjectReference Include="..\..\Skia\Perspex.Skia.Android\Perspex.Skia.Android.csproj">
<Project>{bd43f7c0-396b-4aa1-bad9-dfde54d51298}</Project>
<Name>Perspex.Skia.Android</Name>
</ProjectReference>
</ItemGroup>
<Import Project="..\..\..\samples\TestApplicationShared\TestApplicationShared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- 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>
<Target Name="AfterBuild">
</Target>
-->
</Project>

6
src/Android/Perspex.AndroidTestApplication/Properties/AndroidManifest.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="Perspex.AndroidTestApplication" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-sdk />
<application android:label="Perspex.AndroidTestApplication" android:icon="@drawable/Icon" android:hardwareAccelerated="true"></application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

30
src/Android/Perspex.AndroidTestApplication/Properties/AssemblyInfo.cs

@ -0,0 +1,30 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Perspex.AndroidTestApplication")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Perspex.AndroidTestApplication")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

50
src/Android/Perspex.AndroidTestApplication/Resources/AboutResources.txt

@ -0,0 +1,50 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable-hdpi/
icon.png
drawable-ldpi/
icon.png
drawable-mdpi/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called
"Resource" that contains the tokens for each one of the resources included. For example,
for the above Resources layout, this is what the Resource class would expose:
public class Resource {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

86
src/Android/Perspex.AndroidTestApplication/Resources/Resource.Designer.cs

@ -0,0 +1,86 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: global::Android.Runtime.ResourceDesignerAttribute("Perspex.AndroidTestApplication.Resource", IsApplication=true)]
namespace Perspex.AndroidTestApplication
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
public partial class Resource
{
static Resource()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
public static void UpdateIdValues()
{
global::Perspex.Android.Resource.String.ApplicationName = global::Perspex.AndroidTestApplication.Resource.String.ApplicationName;
global::Perspex.Android.Resource.String.Hello = global::Perspex.AndroidTestApplication.Resource.String.Hello;
global::Splat.Resource.String.library_name = global::Perspex.AndroidTestApplication.Resource.String.library_name;
}
public partial class Attribute
{
static Attribute()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Attribute()
{
}
}
public partial class Drawable
{
// aapt resource value: 0x7f020000
public const int Icon = 2130837504;
static Drawable()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private Drawable()
{
}
}
public partial class String
{
// aapt resource value: 0x7f030002
public const int ApplicationName = 2130903042;
// aapt resource value: 0x7f030001
public const int Hello = 2130903041;
// aapt resource value: 0x7f030000
public const int library_name = 2130903040;
static String()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
}
private String()
{
}
}
}
}
#pragma warning restore 1591

BIN
src/Android/Perspex.AndroidTestApplication/Resources/drawable/Icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

6
src/Android/Perspex.AndroidTestApplication/Resources/values/Strings.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="Hello">Hello World, Click Me!</string>
<string name="ApplicationName">Perspex.AndroidTestApplication</string>
</resources>

12
src/Android/Perspex.AndroidTestApplication/packages.config

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Rx-Core" version="2.2.5" targetFramework="monoandroid51" />
<package id="Rx-Interfaces" version="2.2.5" targetFramework="monoandroid51" />
<package id="Rx-Linq" version="2.2.5" targetFramework="monoandroid51" />
<package id="Rx-Main" version="2.2.5" targetFramework="monoandroid51" />
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="monoandroid51" />
<package id="Serilog" version="1.5.9" targetFramework="monoandroid51" />
<package id="Splat" version="1.6.2" targetFramework="monoandroid51" />
<package id="Sprache" version="2.0.0.47" targetFramework="monoandroid51" />
</packages>

2
src/Gtk/Perspex.Gtk/GtkPlatform.cs

@ -27,6 +27,8 @@ namespace Perspex.Gtk
public Size DoubleClickSize => new Size(4, 4);
public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(Gtk.Settings.Default.DoubleClickTime);
public double RenderScalingFactor { get; } = 1;
public double LayoutScalingFactor { get; } = 1;
public static void Initialize()
{

12
src/Perspex.Application/Application.cs

@ -34,6 +34,8 @@ namespace Perspex
/// </remarks>
public class Application : IGlobalDataTemplates, IGlobalStyles
{
static bool _suppressPlatformInitialization;
/// <summary>
/// The application-global data templates.
/// </summary>
@ -60,6 +62,11 @@ namespace Perspex
Current = this;
}
public static void SuppressPlatformInitialization()
{
_suppressPlatformInitialization = true;
}
/// <summary>
/// Gets the current instance of the <see cref="Application"/> class.
/// </summary>
@ -169,8 +176,7 @@ namespace Perspex
.Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>()
.Bind<IStyler>().ToConstant(_styler)
.Bind<ILayoutManager>().ToTransient<LayoutManager>()
.Bind<IRenderQueueManager>().ToTransient<RenderQueueManager>()
.Bind<PlatformSettings>().ToConstant(new PlatformSettings());
.Bind<IRenderQueueManager>().ToTransient<RenderQueueManager>();
}
/// <summary>
@ -179,6 +185,8 @@ namespace Perspex
/// <param name="platformID">The value of Environment.OSVersion.Platform.</param>
protected void InitializeSubsystems(int platformID)
{
if(_suppressPlatformInitialization)
return;
if (platformID == 4 || platformID == 6)
{
InitializeSubsystem("Perspex.Cairo");

19
src/Perspex.Controls/Platform/PlatformManager.cs

@ -13,10 +13,9 @@ namespace Perspex.Controls.Platform
{
public static partial class PlatformManager
{
static PlatformSettings DefaultSettings = new PlatformSettings();
static PlatformSettings GetSettings()
=> PerspexLocator.Current.GetService<PlatformSettings>() ?? DefaultSettings;
static IPlatformSettings GetSettings()
=> PerspexLocator.Current.GetService<IPlatformSettings>();
public static IRenderTarget CreateRenderTarget(ITopLevelImpl window)
{
@ -46,7 +45,7 @@ namespace Perspex.Controls.Platform
{
var cs = _window.ClientSize;
var ctx = _target.CreateDrawingContext();
var factor = GetSettings().RenderScalingFactor;
var factor = GetSettings()?.RenderScalingFactor ?? 1;
if (factor != 1)
{
ctx.PushPostTransform(Matrix.CreateScale(factor, factor));
@ -63,7 +62,7 @@ namespace Perspex.Controls.Platform
private readonly IPopupImpl _popup;
public ITopLevelImpl TopLevel => _tl;
double ScalingFactor => GetSettings().LayoutScalingFactor;
double ScalingFactor => GetSettings()?.LayoutScalingFactor ?? 1;
public WindowDecorator(ITopLevelImpl tl)
{
@ -90,9 +89,7 @@ namespace Perspex.Controls.Platform
{
var mouseEvent = obj as RawMouseEventArgs;
if (mouseEvent != null)
{
mouseEvent.Position /= GetSettings().LayoutScalingFactor;
}
mouseEvent.Position /= ScalingFactor;
//TODO: Transform event coordinates
Input?.Invoke(obj);
}
@ -176,10 +173,4 @@ namespace Perspex.Controls.Platform
return new WindowDecorator(PerspexLocator.Current.GetService<IPopupImpl>());
}
}
public class PlatformSettings
{
public double RenderScalingFactor { get; set; } = 1;
public double LayoutScalingFactor { get; set; } = 1;
}
}

4
src/Perspex.Input/Platform/IPlatformSettings.cs

@ -10,5 +10,9 @@ namespace Perspex.Platform
Size DoubleClickSize { get; }
TimeSpan DoubleClickTime { get; }
double RenderScalingFactor { get; }
double LayoutScalingFactor { get; }
}
}

16
src/Shared/PlatformSupport/AssetLoader.cs

@ -18,6 +18,13 @@ namespace Perspex.Shared.PlatformSupport
private static readonly Dictionary<string, Assembly> AssemblyNameCache
= new Dictionary<string, Assembly>();
private Assembly _defaultAssembly;
public AssetLoader(Assembly assembly = null)
{
_defaultAssembly = assembly;
}
static Assembly GetAssembly(string name)
{
Assembly rv;
@ -36,7 +43,7 @@ namespace Perspex.Shared.PlatformSupport
public bool Exists(Uri uri)
{
var parts = uri.AbsolutePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
var asm = parts.Length == 1 ? Assembly.GetEntryAssembly() : GetAssembly(parts[0]);
var asm = parts.Length == 1 ? (_defaultAssembly ?? Assembly.GetEntryAssembly()) : GetAssembly(parts[0]);
var typeName = parts[parts.Length == 1 ? 0 : 1];
var rv = asm.GetManifestResourceStream(typeName);
return rv != null;
@ -53,11 +60,16 @@ namespace Perspex.Shared.PlatformSupport
public Stream Open(Uri uri)
{
var parts = uri.AbsolutePath.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
var asm = parts.Length == 1 ? Assembly.GetEntryAssembly() : GetAssembly(parts[0]);
var asm = parts.Length == 1 ? (_defaultAssembly ?? Assembly.GetEntryAssembly()) : GetAssembly(parts[0]);
var typeName = parts[parts.Length == 1 ? 0 : 1];
var rv = asm.GetManifestResourceStream(typeName);
if (rv == null)
{
#if DEBUG
var names = asm.GetManifestResourceNames().ToList();
#endif
throw new FileNotFoundException($"The resource {uri} could not be found.");
}
return rv;
}
}

5
src/Shared/PlatformSupport/SharedPlatform.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Perspex.Platform;
@ -7,11 +8,11 @@ namespace Perspex.Shared.PlatformSupport
{
static class SharedPlatform
{
public static void Register()
public static void Register(Assembly assembly = null)
{
PerspexLocator.CurrentMutable
.Bind<IPclPlatformWrapper>().ToSingleton<PclPlatformWrapper>()
.Bind<IAssetLoader>().ToSingleton<AssetLoader>();
.Bind<IAssetLoader>().ToConstant(new AssetLoader(assembly));
}
}
}

2
src/Skia/Perspex.Skia.Android.TestApp/Perspex.Skia.Android.TestApp.csproj

@ -16,7 +16,7 @@
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v5.1</TargetFrameworkVersion>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

122
src/Skia/Perspex.Skia.Android.TestApp/Perspex.Skia.Android.TestApp.csproj.bak

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Perspex.Skia.Android.TestApp</RootNamespace>
<AssemblyName>Perspex.Skia.Android.TestApp</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidApplication>true</AndroidApplication>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
<AndroidLinkSkip />
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<AndroidSupportedAbis>armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidStoreUncompressedFileExtensions />
<MandroidI18n />
<Debugger>Xamarin</Debugger>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<DevInstrumentationEnabled>True</DevInstrumentationEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Collections" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainActivity.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\AndroidManifest.xml" />
<AndroidResource Include="Resources\layout\Main.axml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Perspex.Animation\Perspex.Animation.csproj">
<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.Controls\Perspex.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Perspex.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Input\Perspex.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Perspex.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Interactivity\Perspex.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Perspex.Interactivity</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>
<ProjectReference Include="..\..\Perspex.Styling\Perspex.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Skia.Android\Perspex.Skia.Android.csproj">
<Project>{bd43f7c0-396b-4aa1-bad9-dfde54d51298}</Project>
<Name>Perspex.Skia.Android</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\Icon.png" />
<AndroidResource Include="Resources\values\Strings.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- 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>
<Target Name="AfterBuild">
</Target>
-->
</Project>

2
src/Skia/Perspex.Skia.Android/Perspex.Skia.Android.csproj

@ -15,7 +15,7 @@
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v5.1</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>

16
src/Skia/Perspex.Skia.Android/SkiaView.cs

@ -20,12 +20,15 @@ namespace Perspex.Skia.Android
{
private readonly Activity _context;
bool _invalidateQueued;
object _lock = new object();
readonly object _lock = new object();
private readonly Handler _handler;
public SkiaView(Activity context) : base(context)
{
_context = context;
SkiaPlatform.Initialize();
Holder.AddCallback(this);
_handler = new Handler(context.MainLooper);
}
public override void Invalidate()
@ -34,13 +37,20 @@ namespace Perspex.Skia.Android
{
if(_invalidateQueued)
return;
_context.RunOnUiThread(() =>
_handler.Post(() =>
{
lock (_lock)
{
_invalidateQueued = false;
}
Draw();
try
{
Draw();
}
catch (Exception e)
{
Log.WriteLine(LogPriority.Error, "Perspex", e.ToString());
}
});
}
}

74
src/Skia/Perspex.Skia.iOS.TestApp/AppDelegate.cs

@ -0,0 +1,74 @@
using Foundation;
using UIKit;
namespace Perspex.Skia.iOS.TestApp
{
// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to application events from iOS.
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
// class-level declarations
public override UIWindow Window
{
get;
set;
}
class Controller : UIViewController
{
public override void LoadView()
{
View = new MainView();
}
}
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// create a new window instance based on the screen size
Window = new UIWindow(UIScreen.MainScreen.Bounds);
// If you have defined a root view controller, set it here:
Window.RootViewController = new Controller();
// make the window visible
Window.MakeKeyAndVisible();
return true;
}
public override void OnResignActivation(UIApplication application)
{
// Invoked when the application is about to move from active to inactive state.
// This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message)
// or when the user quits the application and it begins the transition to the background state.
// Games should use this method to pause the game.
}
public override void DidEnterBackground(UIApplication application)
{
// Use this method to release shared resources, save user data, invalidate timers and store the application state.
// If your application supports background exection this method is called instead of WillTerminate when the user quits.
}
public override void WillEnterForeground(UIApplication application)
{
// Called as part of the transiton from background to active state.
// Here you can undo many of the changes made on entering the background.
}
public override void OnActivated(UIApplication application)
{
// Restart any tasks that were paused (or not yet started) while the application was inactive.
// If the application was previously in the background, optionally refresh the user interface.
}
public override void WillTerminate(UIApplication application)
{
// Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground.
}
}
}

5
src/Skia/Perspex.Skia.iOS.TestApp/Entitlements.plist

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>

4
src/Skia/Perspex.Skia.iOS.TestApp/GettingStarted.Xamarin

@ -0,0 +1,4 @@
<GettingStarted>
<LocalContent>GS\iOS\CS\iOSApp\GettingStarted.html</LocalContent>
<EmbeddedNavigation>false</EmbeddedNavigation>
</GettingStarted>

42
src/Skia/Perspex.Skia.iOS.TestApp/Info.plist

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDisplayName</key>
<string>Perspex.Skia.iOS.TestApp</string>
<key>CFBundleIdentifier</key>
<string>com.companyname.Perspex.Skia.iOS.TestApp</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>MinimumOSVersion</key>
<string>6.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

15
src/Skia/Perspex.Skia.iOS.TestApp/Main.cs

@ -0,0 +1,15 @@
using UIKit;
namespace Perspex.Skia.iOS.TestApp
{
public class Application
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, "AppDelegate");
}
}
}

80
src/Skia/Perspex.Skia.iOS.TestApp/MainView.cs

@ -0,0 +1,80 @@
using System;
using System.Drawing;
using CoreAnimation;
using CoreGraphics;
using Foundation;
using Perspex.Media;
using Perspex.Platform;
using UIKit;
namespace Perspex.Skia.iOS.TestApp
{
[Register("MainView")]
public class MainView : UIView
{
CAEAGLLayer _layer = new CAEAGLLayer();
private IRenderTarget _target;
public MainView()
{
Initialize();
}
public MainView(RectangleF bounds) : base(bounds)
{
Initialize();
}
void Initialize()
{
AutoresizingMask = UIViewAutoresizing.All;
Layer.AddSublayer(_layer);
SkiaPlatform.Initialize();
_target = PerspexLocator.Current.GetService<IPlatformRenderInterface>()
.CreateRenderer(new PlatformHandle(_layer.DangerousRetain().Handle, "Layer"));
}
double _radians = 0;
public override void TouchesMoved(NSSet touches, UIEvent evt)
{
foreach (var touch in touches)
{
var loc = ((UITouch) touch).LocationInView(this);
_radians = (loc.X + loc.Y)/100;
}
SetNeedsDisplay();
base.TouchesMoved(touches, evt);
}
public override void Draw(CGRect rect)
{
_layer.Bounds = new CGRect(0, 0, Bounds.Width, Bounds.Height);
var scale = UIScreen.MainScreen.Scale;
int width = (int) (Bounds.Width*scale), height = (int) (Bounds.Height*scale);
using (var ctx = _target.CreateDrawingContext())
{
ctx.FillRectangle(Brushes.Green, new Rect(0, 0, width, height));
var rc = new Rect(0, 0, width/3, height/3);
using (ctx.PushPostTransform(
Perspex.Matrix.CreateTranslation(-width/6, -width/6)*
Perspex.Matrix.CreateRotation(_radians)*
Perspex.Matrix.CreateTranslation(width/2, height/2)))
{
ctx.FillRectangle(new LinearGradientBrush()
{
GradientStops =
{
new GradientStop() {Color = Colors.Blue},
new GradientStop(Colors.Red, 1)
}
}, rc, 5);
}
}
}
}
}

147
src/Skia/Perspex.Skia.iOS.TestApp/Perspex.Skia.iOS.TestApp.csproj

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
<ProjectGuid>{DA49C5F3-BE95-461C-B999-072128CCF59E}</ProjectGuid>
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Exe</OutputType>
<RootNamespace>Perspex.Skia.iOS.TestApp</RootNamespace>
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
<AssemblyName>PerspexSkiaiOSTestApp</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchArch>i386</MtouchArch>
<MtouchLink>None</MtouchLink>
<MtouchDebug>true</MtouchDebug>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhoneSimulator\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<MtouchLink>None</MtouchLink>
<MtouchArch>i386</MtouchArch>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhone\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchArch>ARMv7, ARM64</MtouchArch>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchDebug>true</MtouchDebug>
<CodesignProvision>
</CodesignProvision>
<CodesignResourceRules />
<CodesignExtraArgs />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhone\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<MtouchArch>ARMv7, ARM64</MtouchArch>
<ConsolePause>false</ConsolePause>
<CodesignKey>iPhone Developer</CodesignKey>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Ad-Hoc|iPhone' ">
<DebugType>none</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\iPhone\Ad-Hoc</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>
<MtouchArch>ARMv7, ARM64</MtouchArch>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<BuildIpa>True</BuildIpa>
<CodesignProvision>Automatic:AdHoc</CodesignProvision>
<CodesignKey>iPhone Distribution</CodesignKey>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|iPhone' ">
<DebugType>none</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\iPhone\AppStore</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>
<MtouchArch>ARMv7, ARM64</MtouchArch>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<CodesignProvision>Automatic:AppStore</CodesignProvision>
<CodesignKey>iPhone Distribution</CodesignKey>
</PropertyGroup>
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="AppDelegate.cs" />
<None Include="GettingStarted.Xamarin" />
<None Include="Info.plist" />
<Compile Include="MainView.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<InterfaceDefinition Include="Resources\LaunchScreen.xib" />
<Content Include="Entitlements.plist" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Perspex.Animation\Perspex.Animation.csproj">
<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>
<Name>Perspex.Application</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Base\Perspex.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Perspex.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Controls\Perspex.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Perspex.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Input\Perspex.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Perspex.Input</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>
<ProjectReference Include="..\..\Perspex.Styling\Perspex.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Skia.iOS\Perspex.Skia.iOS.csproj">
<Project>{47be08a7-5985-410b-9ffc-2264b8ea595f}</Project>
<Name>Perspex.Skia.iOS</Name>
<IsAppExtension>false</IsAppExtension>
<IsWatchApp>false</IsWatchApp>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
</Project>

36
src/Skia/Perspex.Skia.iOS.TestApp/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Perspex.Skia.iOS.TestApp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Perspex.Skia.iOS.TestApp")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("da49c5f3-be95-461c-b999-072128ccf59e")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

43
src/Skia/Perspex.Skia.iOS.TestApp/Resources/LaunchScreen.xib

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207" />
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1" />
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" />
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder" />
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480" />
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" />
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 " textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines"
minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21" />
<fontDescription key="fontDescription" type="system" pointSize="17" />
<color key="textColor" cocoaTouchSystemColor="darkTextColor" />
<nil key="highlightedColor" />
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Perspex.Skia.iOS.TestApp" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines"
minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43" />
<fontDescription key="fontDescription" type="boldSystem" pointSize="36" />
<color key="textColor" cocoaTouchSystemColor="darkTextColor" />
<nil key="highlightedColor" />
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite" />
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC" />
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk" />
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l" />
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0" />
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9" />
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g" />
</constraints>
<nil key="simulatedStatusBarMetrics" />
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics" />
<point key="canvasLocation" x="548" y="455" />
</view>
</objects>
</document>

94
src/Skia/Perspex.Skia.iOS/Perspex.Skia.iOS.csproj

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{47BE08A7-5985-410B-9FFC-2264B8EA595F}</ProjectGuid>
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<RootNamespace>Perspex.Skia.iOS</RootNamespace>
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
<AssemblyName>Perspex.Skia.iOS</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhone\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchDebug>true</MtouchDebug>
<CodesignKey>iPhone Developer</CodesignKey>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhone\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<CodesignKey>iPhone Developer</CodesignKey>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="iOSMethodTable.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\native\iOS\libperspesk_standalone.a">
<Link>libperspesk_standalone.a</Link>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Perspex.Animation\Perspex.Animation.csproj">
<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>
<Name>Perspex.Application</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Base\Perspex.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Perspex.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Controls\Perspex.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Perspex.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Input\Perspex.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Perspex.Input</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>
<ProjectReference Include="..\..\Perspex.Styling\Perspex.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\..\Perspex.Themes.Default\Perspex.Themes.Default.csproj">
<Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
<Name>Perspex.Themes.Default</Name>
</ProjectReference>
</ItemGroup>
<Import Project="..\Perspex.Skia\Perspex.Skia.projitems" Label="Shared" />
<Import Project="..\..\Shared\RenderHelpers\RenderHelpers.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
</Project>

36
src/Skia/Perspex.Skia.iOS/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Perspex.Skia.iOS")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Perspex.Skia.iOS")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("05514696-af27-48e3-8d23-864420b0fe2d")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

19
src/Skia/Perspex.Skia.iOS/iOSMethodTable.cs

@ -0,0 +1,19 @@
using System;
using System.Runtime.InteropServices;
using ObjCRuntime;
[assembly: LinkWith("Perspex.Skia.iOS.libperspesk_standalone.a", ForceLoad = true, SmartLink = true, IsCxx = true, Frameworks = "ImageIO MobileCoreServices CoreText")]
namespace Perspex.Skia
{
class MethodTableImpl : MethodTable
{
[DllImport("__Internal")]
static extern IntPtr GetPerspexMethodTable();
public MethodTableImpl() : base(GetPerspexMethodTable())
{
}
}
}

2
src/Skia/Perspex.Skia/MethodTable.cs

@ -7,7 +7,7 @@ using Perspex.Media;
namespace Perspex.Skia
{
internal unsafe abstract class MethodTable
unsafe abstract class MethodTable
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr _CreateWindowRenderTarget(IntPtr nativeHandle);

1
src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs

@ -177,6 +177,7 @@ namespace Perspex.Designer.AppHost
private void DoInit(string targetExe, StringBuilder logger)
{
MessageBox.Show("WAT");
_appDir = Path.GetFullPath(Path.GetDirectoryName(targetExe));
Directory.SetCurrentDirectory(_appDir);
Action<string> log = s =>

2
src/Windows/Perspex.Win32/Win32Platform.cs

@ -39,6 +39,8 @@ namespace Perspex.Win32
UnmanagedMethods.GetSystemMetrics(UnmanagedMethods.SystemMetric.SM_CYDOUBLECLK));
public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(UnmanagedMethods.GetDoubleClickTime());
public double RenderScalingFactor { get; } = 1;
public double LayoutScalingFactor { get; } = 1;
private static void InitializeInternal()
{

1
tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj

@ -44,7 +44,6 @@
<Reference Include="Magick.NET.Core">
<HintPath>..\..\packages\Magick.NET-Q16-AnyCPU.7.0.0.0018\lib\net40-client\Magick.NET.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>

Loading…
Cancel
Save