From 5be41985c32c1270b41aa531e8b2a96ddf6792cb Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 11 May 2016 23:36:54 +0200 Subject: [PATCH] Renamed Perspex -> Avalonia --- .gitmodules | 16 +- Avalonia.sln | 1888 +++++++++++++++++ ...ln.DotSettings => Avalonia.sln.DotSettings | 0 ...nchsolution => Avalonia.v2.ncrunchsolution | Bin Perspex.sln | 1888 ----------------- appveyor.yml | 6 +- docs/README.md | 4 +- docs/docfx.json | 44 +- docs/guidelines/build.md | 22 +- docs/guidelines/contributing.md | 6 +- docs/guidelines/toc.yml | 2 +- .../{perspex-video.png => avalonia-video.png} | Bin docs/index.md | 14 +- docs/intro.md | 28 +- docs/spec/architecture.md | 46 +- docs/spec/defining-properties.md | 34 +- docs/spec/logging.md | 12 +- docs/spec/styles.md | 8 +- docs/spec/toc.yml | 4 +- docs/spec/working-with-properties.md | 8 +- docs/template/partials/footer.tmpl.partial | 4 +- docs/tutorial/from-wpf.md | 40 +- docs/tutorial/gettingstarted.md | 8 +- nuget/.gitignore | 2 +- nuget/build-appveyor.ps1 | 2 +- nuget/build-version.ps1 | 94 +- nuget/include.ps1 | 2 +- nuget/template/Avalonia.Android.nuspec | 27 + nuget/template/Avalonia.Desktop.nuspec | 30 + nuget/template/Avalonia.Skia.Desktop.nuspec | 20 + nuget/template/Avalonia.iOS.nuspec | 27 + nuget/template/Avalonia.nuspec | 26 + nuget/template/Perspex.Android.nuspec | 27 - nuget/template/Perspex.Desktop.nuspec | 30 - nuget/template/Perspex.Skia.Desktop.nuspec | 20 - nuget/template/Perspex.iOS.nuspec | 27 - nuget/template/Perspex.nuspec | 26 - readme.md | 24 +- samples/BindingTest/App.xaml | 6 +- samples/BindingTest/App.xaml.cs | 12 +- samples/BindingTest/BindingTest.csproj | 70 +- samples/BindingTest/MainWindow.xaml | 2 +- samples/BindingTest/MainWindow.xaml.cs | 8 +- .../BindingTest/Properties/AssemblyInfo.cs | 2 +- samples/BindingTest/TestItemView.xaml | 2 +- samples/BindingTest/TestItemView.xaml.cs | 6 +- .../ViewModels/MainWindowViewModel.cs | 2 +- samples/BindingTest/ViewModels/TestItem.cs | 2 +- .../ControlCatalog.Desktop.csproj | 50 +- samples/ControlCatalog.Desktop/Program.cs | 6 +- .../Properties/AssemblyInfo.cs | 2 +- samples/ControlCatalog.iOS/AppDelegate.cs | 4 +- .../ControlCatalog.iOS.csproj | 62 +- samples/ControlCatalog.iOS/Main.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- .../Resources/LaunchScreen.xib | 2 +- samples/ControlCatalog/App.xaml | 6 +- samples/ControlCatalog/App.xaml.cs | 2 +- samples/ControlCatalog/ControlCatalog.csproj | 58 +- samples/ControlCatalog/MainWindow.xaml | 4 +- samples/ControlCatalog/MainWindow.xaml.cs | 8 +- samples/ControlCatalog/Pages/BorderPage.xaml | 2 +- .../ControlCatalog/Pages/BorderPage.xaml.cs | 6 +- samples/ControlCatalog/Pages/ButtonPage.xaml | 2 +- .../ControlCatalog/Pages/ButtonPage.xaml.cs | 6 +- samples/ControlCatalog/Pages/CanvasPage.xaml | 2 +- .../ControlCatalog/Pages/CanvasPage.xaml.cs | 6 +- .../ControlCatalog/Pages/CarouselPage.xaml | 2 +- .../ControlCatalog/Pages/CarouselPage.xaml.cs | 10 +- .../ControlCatalog/Pages/CheckBoxPage.xaml | 2 +- .../ControlCatalog/Pages/CheckBoxPage.xaml.cs | 6 +- .../ControlCatalog/Pages/DropDownPage.xaml | 2 +- .../ControlCatalog/Pages/DropDownPage.xaml.cs | 6 +- .../ControlCatalog/Pages/ExpanderPage.xaml | 2 +- .../ControlCatalog/Pages/ExpanderPage.xaml.cs | 6 +- samples/ControlCatalog/Pages/ImagePage.xaml | 2 +- .../ControlCatalog/Pages/ImagePage.xaml.cs | 6 +- .../Pages/LayoutTransformControlPage.xaml | 2 +- .../Pages/LayoutTransformControlPage.xaml.cs | 6 +- samples/ControlCatalog/Pages/MenuPage.xaml | 2 +- samples/ControlCatalog/Pages/MenuPage.xaml.cs | 6 +- .../ControlCatalog/Pages/RadioButtonPage.xaml | 2 +- .../Pages/RadioButtonPage.xaml.cs | 6 +- samples/ControlCatalog/Pages/SliderPage.xaml | 2 +- .../ControlCatalog/Pages/SliderPage.xaml.cs | 6 +- samples/ControlCatalog/Pages/TextBoxPage.xaml | 2 +- .../ControlCatalog/Pages/TextBoxPage.xaml.cs | 6 +- samples/ControlCatalog/Pages/ToolTipPage.xaml | 2 +- .../ControlCatalog/Pages/ToolTipPage.xaml.cs | 6 +- samples/ControlCatalog/Program.cs | 4 +- .../ControlCatalog/Properties/AssemblyInfo.cs | 2 +- samples/ControlCatalog/SideBar.xaml | 2 +- samples/TestApplication/Program.cs | 30 +- .../Properties/AssemblyInfo.cs | 2 +- .../TestApplication/TestApplication.csproj | 80 +- samples/TestApplicationShared/App.cs | 28 +- samples/TestApplicationShared/GalleryStyle.cs | 16 +- samples/TestApplicationShared/Item.cs | 2 +- samples/TestApplicationShared/MainWindow.cs | 52 +- samples/TestApplicationShared/Node.cs | 6 +- .../TestApplicationShared.projitems | 2 +- .../TestApplicationShared.shproj | 2 +- samples/TestApplicationShared/html.htm | 6 +- samples/XamlTestApplication/App.cs | 4 +- samples/XamlTestApplication/Program.cs | 6 +- .../Properties/AssemblyInfo.cs | 2 +- .../XamlTestApplication.csproj | 76 +- .../Properties/AssemblyInfo.cs | 2 +- .../XamlTestApplicationPcl/TestScrollable.cs | 10 +- .../ViewModels/EditorViewModel.cs | 2 +- .../ViewModels/MainWindowViewModel.cs | 4 +- .../ViewModels/TestItem.cs | 2 +- .../ViewModels/TestNode.cs | 2 +- .../Views/MainWindow.cs | 12 +- .../Views/MainWindow.xaml | 6 +- samples/XamlTestApplicationPcl/XamlTestApp.cs | 4 +- .../XamlTestApplicationPcl/XamlTestApp.xaml | 8 +- .../XamlTestApplicationPcl.csproj | 62 +- scripts/avalonia-rename.ps1 | 18 +- .../Avalonia.Android/AndroidPlatform.cs | 70 + .../AndroidThreadingInterface.cs | 84 + .../Avalonia.Android/Avalonia.Android.csproj | 153 ++ src/Android/Avalonia.Android/CursorFactory.cs | 12 + .../Platform/AndroidTopLevelRenderer.cs | 59 + .../Platform/ClipboardImpl.cs | 47 + .../Platform/Input/AndroidKeyboardDevice.cs | 217 ++ .../Platform/Input/AndroidMouseDevice.cs | 12 + .../Platform/SkiaPlatform/MainWindowImpl.cs | 44 + .../Platform/SkiaPlatform/WindowImpl.cs | 184 ++ .../Platform/Specific/AvaloniaActivity.cs | 60 + .../Helpers/AndroidKeyboardEventsHelper.cs | 145 ++ .../Helpers/AndroidTouchEventsHelper.cs | 136 ++ .../Platform/Specific/IAndroidActivity.cs | 12 + .../Platform/Specific/IAndroidView.cs | 16 + .../Properties/AssemblyInfo.cs | 30 + .../Resources/AboutResources.txt | 0 .../Resources/Resource.Designer.cs | 60 + .../Resources/Values/Strings.xml | 0 .../Avalonia.Android/SystemDialogImpl.cs | 21 + .../packages.config | 0 .../Assets/AboutAssets.txt | 0 .../Avalonia.AndroidTestApplication.csproj | 200 ++ .../MainActivity.cs | 44 + .../Properties/AndroidManifest.xml | 6 + .../Properties/AssemblyInfo.cs | 30 + .../Resources/AboutResources.txt | 0 .../Resources/Resource.Designer.cs | 86 + .../Resources/drawable/Icon.png | Bin .../Resources/values/Strings.xml | 6 + .../packages.config | 0 .../Perspex.Android/AndroidPlatform.cs | 70 - .../AndroidThreadingInterface.cs | 84 - src/Android/Perspex.Android/CursorFactory.cs | 12 - .../Perspex.Android/Perspex.Android.csproj | 153 -- .../Platform/AndroidTopLevelRenderer.cs | 59 - .../Perspex.Android/Platform/ClipboardImpl.cs | 47 - .../Platform/Input/AndroidKeyboardDevice.cs | 217 -- .../Platform/Input/AndroidMouseDevice.cs | 12 - .../Platform/SkiaPlatform/MainWindowImpl.cs | 44 - .../Platform/SkiaPlatform/WindowImpl.cs | 184 -- .../Helpers/AndroidKeyboardEventsHelper.cs | 145 -- .../Helpers/AndroidTouchEventsHelper.cs | 136 -- .../Platform/Specific/IAndroidActivity.cs | 12 - .../Platform/Specific/IAndroidView.cs | 16 - .../Platform/Specific/PerspexActivity.cs | 60 - .../Properties/AssemblyInfo.cs | 30 - .../Resources/Resource.Designer.cs | 60 - .../Perspex.Android/SystemDialogImpl.cs | 21 - .../MainActivity.cs | 44 - .../Perspex.AndroidTestApplication.csproj | 200 -- .../Properties/AndroidManifest.xml | 6 - .../Properties/AssemblyInfo.cs | 30 - .../Resources/Resource.Designer.cs | 86 - .../Resources/values/Strings.xml | 6 - src/Avalonia.Animation/Animatable.cs | 56 + src/Avalonia.Animation/Animate.cs | 134 ++ src/Avalonia.Animation/Animation.cs | 55 + src/Avalonia.Animation/AnimationExtensions.cs | 45 + src/Avalonia.Animation/Animation`1.cs | 56 + .../Avalonia.Animation.csproj | 88 + src/Avalonia.Animation/IEasing.cs | 23 + src/Avalonia.Animation/IEasing`1.cs | 24 + src/Avalonia.Animation/LinearDoubleEasing.cs | 41 + src/Avalonia.Animation/LinearEasing.cs | 35 + .../Properties/AssemblyInfo.cs | 6 + src/Avalonia.Animation/PropertyTransition.cs | 50 + src/Avalonia.Animation/PropertyTransitions.cs | 21 + .../packages.config | 0 src/Avalonia.Base/AttachedProperty.cs | 45 + src/Avalonia.Base/Avalonia.Base.csproj | 154 ++ src/Avalonia.Base/AvaloniaDisposable.cs | 41 + .../AvaloniaInternalException.cs | 22 + src/Avalonia.Base/AvaloniaLocator.cs | 115 + src/Avalonia.Base/AvaloniaObject.cs | 821 +++++++ src/Avalonia.Base/AvaloniaObjectExtensions.cs | 297 +++ src/Avalonia.Base/AvaloniaProperty.cs | 554 +++++ .../AvaloniaPropertyChangedEventArgs.cs | 74 + src/Avalonia.Base/AvaloniaPropertyRegistry.cs | 281 +++ src/Avalonia.Base/AvaloniaProperty`1.cs | 44 + .../Collections/AvaloniaDictionary.cs | 219 ++ src/Avalonia.Base/Collections/AvaloniaList.cs | 500 +++++ .../Collections/AvaloniaListExtensions.cs | 247 +++ .../Collections/IAvaloniaList.cs | 52 + .../Collections/IAvaloniaReadOnlyList.cs | 17 + src/Avalonia.Base/Contract.cs | 37 + .../Data/AssignBindingAttribute.cs | 20 + src/Avalonia.Base/Data/BindingError.cs | 59 + src/Avalonia.Base/Data/BindingMode.cs | 36 + src/Avalonia.Base/Data/BindingOperations.cs | 71 + src/Avalonia.Base/Data/BindingPriority.cs | 47 + src/Avalonia.Base/Data/IBinding.cs | 30 + src/Avalonia.Base/Data/IndexerDescriptor.cs | 115 + src/Avalonia.Base/Data/InstancedBinding.cs | 109 + src/Avalonia.Base/Data/ValidationMethods.cs | 13 + src/Avalonia.Base/Data/ValidationStatus.cs | 30 + .../Diagnostics/AvaloniaObjectExtensions.cs | 46 + .../Diagnostics/AvaloniaPropertyValue.cs | 53 + .../Diagnostics/IAvaloniaObjectDebug.cs | 22 + .../INotifyCollectionChangedDebug.cs | 25 + src/Avalonia.Base/DirectProperty.cs | 123 ++ src/Avalonia.Base/DirectPropertyMetadata`1.cs | 52 + src/Avalonia.Base/IAvaloniaObject.cs | 93 + src/Avalonia.Base/IDescription.cs | 19 + src/Avalonia.Base/IDirectPropertyAccessor.cs | 31 + src/Avalonia.Base/IDirectPropertyMetadata.cs | 16 + src/Avalonia.Base/IPriorityValueOwner.cs | 28 + src/Avalonia.Base/IStyledPropertyAccessor.cs | 31 + src/Avalonia.Base/IStyledPropertyMetadata.cs | 23 + src/Avalonia.Base/ISupportInitialize.cs | 22 + src/Avalonia.Base/Logging/ILogSink.cs | 26 + src/Avalonia.Base/Logging/LogArea.cs | 36 + src/Avalonia.Base/Logging/LogEventLevel.cs | 41 + src/Avalonia.Base/Logging/Logger.cs | 139 ++ .../Metadata/ContentAttribute.cs | 15 + .../Metadata/DependsOnAttribute.cs | 30 + .../Metadata/XmlnsDefinitionAttribute.cs | 35 + src/Avalonia.Base/Platform/IAssetLoader.cs | 47 + .../Platform/IPclPlatformWrapper.cs | 17 + src/Avalonia.Base/Platform/IPlatformHandle.cs | 23 + .../Platform/IPlatformThreadingInterface.cs | 34 + src/Avalonia.Base/Platform/PlatformHandle.cs | 36 + src/Avalonia.Base/PriorityBindingEntry.cs | 121 ++ src/Avalonia.Base/PriorityLevel.cs | 200 ++ src/Avalonia.Base/PriorityValue.cs | 279 +++ src/Avalonia.Base/Properties/AssemblyInfo.cs | 9 + src/Avalonia.Base/PropertyMetadata.cs | 52 + .../Reactive/AnonymousSubject`1.cs | 16 + .../Reactive/AnonymousSubject`2.cs | 49 + .../Reactive/AvaloniaObservable.cs | 42 + src/Avalonia.Base/Reactive/ObservableEx.cs | 41 + .../Reactive/WeakPropertyChangedObservable.cs | 85 + .../Settings.StyleCop | 0 src/Avalonia.Base/StyledProperty.cs | 52 + src/Avalonia.Base/StyledPropertyBase.cs | 175 ++ src/Avalonia.Base/StyledPropertyMetadata`1.cs | 79 + .../Threading/AvaloniaScheduler.cs | 38 + .../AvaloniaSynchronizationContext.cs | 51 + src/Avalonia.Base/Threading/Dispatcher.cs | 87 + .../Threading/DispatcherPriority.cs | 67 + .../Threading/DispatcherTimer.cs | 224 ++ src/Avalonia.Base/Threading/JobRunner.cs | 131 ++ .../Threading/SingleThreadDispatcher.cs | 60 + .../Utilities/IWeakSubscriber.cs | 21 + src/Avalonia.Base/Utilities/MathUtilities.cs | 39 + src/Avalonia.Base/Utilities/TypeUtilities.cs | 212 ++ .../Utilities/WeakSubscriptionManager.cs | 196 ++ src/Avalonia.Base/Utilities/WeakTimer.cs | 55 + .../app.config | 0 .../packages.config | 0 src/Avalonia.Controls/Application.cs | 235 ++ .../Avalonia.Controls.csproj | 261 +++ src/Avalonia.Controls/Border.cs | 143 ++ src/Avalonia.Controls/Button.cs | 349 +++ src/Avalonia.Controls/Canvas.cs | 233 ++ src/Avalonia.Controls/Carousel.cs | 100 + src/Avalonia.Controls/CheckBox.cs | 14 + src/Avalonia.Controls/Classes.cs | 253 +++ src/Avalonia.Controls/ColumnDefinition.cs | 91 + src/Avalonia.Controls/ColumnDefinitions.cs | 33 + src/Avalonia.Controls/ContentControl.cs | 87 + src/Avalonia.Controls/ContextMenu.cs | 137 ++ src/Avalonia.Controls/Control.cs | 806 +++++++ src/Avalonia.Controls/ControlExtensions.cs | 105 + .../ControlValidationStatus.cs | 27 + src/Avalonia.Controls/Controls.cs | 32 + src/Avalonia.Controls/Decorator.cs | 101 + src/Avalonia.Controls/DefinitionBase.cs | 26 + src/Avalonia.Controls/Design.cs | 57 + src/Avalonia.Controls/DockPanel.cs | 176 ++ src/Avalonia.Controls/DropDown.cs | 184 ++ src/Avalonia.Controls/DropDownItem.cs | 12 + src/Avalonia.Controls/Expander.cs | 89 + .../Generators/IItemContainerGenerator.cs | 93 + .../Generators/ITreeItemContainerGenerator.cs | 18 + .../Generators/ItemContainer.cs | 45 + .../Generators/ItemContainerEventArgs.cs | 51 + .../Generators/ItemContainerGenerator.cs | 210 ++ .../Generators/ItemContainerGenerator`1.cs | 65 + .../Generators/TreeContainerIndex.cs | 106 + .../Generators/TreeItemContainerGenerator.cs | 132 ++ src/Avalonia.Controls/Grid.cs | 941 ++++++++ src/Avalonia.Controls/GridLength.cs | 216 ++ src/Avalonia.Controls/GridSplitter.cs | 160 ++ src/Avalonia.Controls/HotkeyManager.cs | 117 + .../IApplicationLifecycle.cs | 24 + src/Avalonia.Controls/IContentControl.cs | 29 + src/Avalonia.Controls/IControl.cs | 49 + src/Avalonia.Controls/IGlobalDataTemplates.cs | 18 + src/Avalonia.Controls/IHeadered.cs | 16 + src/Avalonia.Controls/INameScope.cs | 43 + src/Avalonia.Controls/IPanel.cs | 16 + src/Avalonia.Controls/IPseudoClasses.cs | 25 + src/Avalonia.Controls/ISelectable.cs | 24 + src/Avalonia.Controls/ISetLogicalParent.cs | 22 + src/Avalonia.Controls/Image.cs | 103 + src/Avalonia.Controls/ItemsControl.cs | 370 ++++ .../LayoutTransformControl.cs | 389 ++++ src/Avalonia.Controls/ListBox.cs | 76 + src/Avalonia.Controls/ListBoxItem.cs | 37 + src/Avalonia.Controls/Menu.cs | 243 +++ src/Avalonia.Controls/MenuItem.cs | 490 +++++ .../MenuItemAccessKeyHandler.cs | 104 + .../Mixins/ContentControlMixin.cs | 154 ++ .../Mixins/SelectableMixin.cs | 79 + src/Avalonia.Controls/NameScope.cs | 109 + src/Avalonia.Controls/NameScopeEventArgs.cs | 19 + src/Avalonia.Controls/NameScopeExtensions.cs | 68 + src/Avalonia.Controls/Panel.cs | 142 ++ src/Avalonia.Controls/PlacementMode.cs | 28 + src/Avalonia.Controls/Platform/IPopupImpl.cs | 13 + .../Platform/ISystemDialogImpl.cs | 24 + .../Platform/ITopLevelImpl.cs | 128 ++ .../Platform/ITopLevelRenderer.cs | 54 + src/Avalonia.Controls/Platform/IWindowImpl.cs | 43 + .../Platform/IWindowingPlatform.cs | 15 + .../Platform/PlatformManager.cs | 51 + .../Presenters/CarouselPresenter.cs | 227 ++ .../Presenters/ContentPresenter.cs | 347 +++ .../Presenters/IContentPresenter.cs | 24 + .../Presenters/IContentPresenterHost.cs | 27 + .../Presenters/IItemsPresenter.cs | 10 + .../Presenters/IItemsPresenterHost.cs | 27 + .../Presenters/IPresenter.cs | 22 + .../Presenters/ItemsPresenter.cs | 148 ++ .../Presenters/ItemsPresenterBase.cs | 217 ++ .../Presenters/ScrollContentPresenter.cs | 273 +++ .../Presenters/TextPresenter.cs | 250 +++ .../Primitives/AccessText.cs | 179 ++ .../Primitives/AdornerDecorator.cs | 33 + .../Primitives/AdornerLayer.cs | 133 ++ .../Primitives/HeaderedContentControl.cs | 26 + .../Primitives/HeaderedItemsControl.cs | 58 + .../Primitives/HeaderedSelectingControl.cs | 56 + .../Primitives/IScrollable.cs | 54 + src/Avalonia.Controls/Primitives/Popup.cs | 340 +++ src/Avalonia.Controls/Primitives/PopupRoot.cs | 142 ++ src/Avalonia.Controls/Primitives/RangeBase.cs | 152 ++ src/Avalonia.Controls/Primitives/ScrollBar.cs | 108 + .../Primitives/ScrollBarVisibility.cs | 12 + .../Primitives/SelectingItemsControl.cs | 873 ++++++++ src/Avalonia.Controls/Primitives/TabStrip.cs | 54 + .../Primitives/TabStripItem.cs | 12 + .../Primitives/TemplateAppliedEventArgs.cs | 28 + .../Primitives/TemplatedControl.cs | 355 ++++ src/Avalonia.Controls/Primitives/Thumb.cs | 106 + .../Primitives/ToggleButton.cs | 43 + src/Avalonia.Controls/Primitives/Track.cs | 180 ++ src/Avalonia.Controls/ProgressBar.cs | 49 + .../Properties/AssemblyInfo.cs | 17 + src/Avalonia.Controls/RadioButton.cs | 44 + .../RequestBringIntoViewEventArgs.cs | 15 + src/Avalonia.Controls/RowDefinition.cs | 91 + src/Avalonia.Controls/RowDefinitions.cs | 33 + src/Avalonia.Controls/ScrollViewer.cs | 404 ++++ .../SelectionChangedEventArgs.cs | 38 + src/Avalonia.Controls/SelectionMode.cs | 34 + src/Avalonia.Controls/Separator.cs | 19 + src/Avalonia.Controls/Shapes/Ellipse.cs | 26 + src/Avalonia.Controls/Shapes/Line.cs | 39 + src/Avalonia.Controls/Shapes/Path.cs | 27 + src/Avalonia.Controls/Shapes/Polygon.cs | 30 + src/Avalonia.Controls/Shapes/Polyline.cs | 31 + src/Avalonia.Controls/Shapes/Rectangle.cs | 26 + src/Avalonia.Controls/Shapes/Shape.cs | 263 +++ src/Avalonia.Controls/Slider.cs | 147 ++ src/Avalonia.Controls/StackPanel.cs | 232 ++ src/Avalonia.Controls/SystemDialog.cs | 55 + src/Avalonia.Controls/TabControl.cs | 150 ++ src/Avalonia.Controls/TabItem.cs | 38 + .../Templates/DataTemplateExtensions.cs | 90 + .../Templates/DataTemplates.cs | 21 + .../Templates/FuncControlTemplate.cs | 24 + .../Templates/FuncControlTemplate`2.cs | 25 + .../Templates/FuncDataTemplate.cs | 79 + .../Templates/FuncDataTemplate`1.cs | 60 + .../Templates/FuncMemberSelector.cs | 35 + .../Templates/FuncTemplate`1.cs | 38 + .../Templates/FuncTemplate`2.cs | 41 + .../Templates/FuncTreeDataTemplate.cs | 81 + .../Templates/FuncTreeDataTemplate`1.cs | 79 + .../Templates/IControlTemplate.cs | 15 + .../Templates/IDataTemplate.cs | 20 + .../Templates/IMemberSelector.cs | 18 + .../Templates/ITemplate`1.cs | 20 + .../Templates/ITemplate`2.cs | 22 + .../Templates/ITreeDataTemplate.cs | 23 + .../Templates/TemplateExtensions.cs | 42 + src/Avalonia.Controls/TextBlock.cs | 408 ++++ src/Avalonia.Controls/TextBox.cs | 649 ++++++ src/Avalonia.Controls/TextWrapping.cs | 21 + src/Avalonia.Controls/ToolTip.cs | 160 ++ src/Avalonia.Controls/TopLevel.cs | 409 ++++ src/Avalonia.Controls/TreeView.cs | 268 +++ src/Avalonia.Controls/TreeViewItem.cs | 127 ++ src/Avalonia.Controls/UserControl.cs | 47 + src/Avalonia.Controls/Utils/AncestorFinder.cs | 77 + .../Utils/IEnumerableUtils.cs | 78 + src/Avalonia.Controls/Utils/StringUtils.cs | 263 +++ src/Avalonia.Controls/Utils/UndoRedoHelper.cs | 98 + src/Avalonia.Controls/Window.cs | 340 +++ src/Avalonia.Controls/WindowEdge.cs | 17 + src/Avalonia.Controls/WindowState.cs | 26 + src/Avalonia.Controls/WrapPanel.cs | 253 +++ .../app.config | 0 .../packages.config | 0 .../Avalonia.DesignerSupport.csproj | 123 ++ src/Avalonia.DesignerSupport/DesignerApi.cs | 56 + .../DesignerAssist.cs | 108 + .../Properties/AssemblyInfo.cs | 8 + .../app.config | 0 .../packages.config | 0 .../Avalonia.Diagnostics.csproj | 152 ++ src/Avalonia.Diagnostics/Debug.cs | 75 + src/Avalonia.Diagnostics/DevTools.xaml | 20 + src/Avalonia.Diagnostics/DevTools.xaml.cs | 121 ++ src/Avalonia.Diagnostics/LogManager.cs | 53 + .../Properties/AssemblyInfo.cs | 6 + src/Avalonia.Diagnostics/ViewLocator.cs | 32 + .../ViewModels/ControlDetailsViewModel.cs | 36 + .../ViewModels/DevToolsViewModel.cs | 83 + .../ViewModels/LogicalTreeNode.cs | 25 + .../ViewModels/PropertyDetails.cs | 59 + .../ViewModels/TreeNode.cs | 81 + .../ViewModels/TreePageViewModel.cs | 102 + .../ViewModels/VisualTreeNode.cs | 40 + .../Views/ControlDetailsView.cs | 83 + .../Views/GridRepeater.cs | 68 + .../Views/TreePage.xaml.cs | 70 + .../Views/TreePageView.xaml | 24 + .../app.config | 0 .../packages.config | 0 .../Adapters/AvaloniaAdapter.cs | 129 ++ .../Adapters/BrushAdapter.cs | 47 + .../Adapters/ContextMenuAdapter.cs | 51 + .../Adapters/ControlAdapter.cs | 108 + .../Adapters/FontAdapter.cs | 106 + .../Adapters/FontFamilyAdapter.cs | 29 + .../Adapters/GraphicsAdapter.cs | 295 +++ .../Adapters/GraphicsPathAdapter.cs | 67 + .../Adapters/ImageAdapter.cs | 52 + .../Adapters/PenAdapter.cs | 79 + .../Avalonia.HtmlRenderer.csproj | 199 ++ .../Avalonia.HtmlRenderer.csproj.DotSettings} | 0 .../Compat/Attributes.cs | 28 + .../Compat/ThreadPool.cs | 22 + src/Avalonia.HtmlRenderer/HtmlContainer.cs | 471 ++++ src/Avalonia.HtmlRenderer/HtmlControl.cs | 615 ++++++ src/Avalonia.HtmlRenderer/HtmlLabel.cs | 112 + .../HtmlRendererRoutedEventArgs.cs | 14 + .../Properties/AssemblyInfo.cs | 33 + src/Avalonia.HtmlRenderer/PropertyHelper.cs | 24 + src/Avalonia.HtmlRenderer/Utilities/Util.cs | 123 ++ .../external | 0 .../packages.config | 0 src/Avalonia.Input/AccessKeyHandler.cs | 224 ++ src/Avalonia.Input/Avalonia.Input.csproj | 145 ++ src/Avalonia.Input/Cursors.cs | 77 + src/Avalonia.Input/FocusManager.cs | 198 ++ .../FocusNavigationDirection.cs | 51 + src/Avalonia.Input/Gestures.cs | 59 + src/Avalonia.Input/GotFocusEventArgs.cs | 23 + src/Avalonia.Input/IAccessKeyHandler.cs | 38 + src/Avalonia.Input/ICloseable.cs | 12 + src/Avalonia.Input/IFocusManager.cs | 42 + src/Avalonia.Input/IFocusScope.cs | 9 + src/Avalonia.Input/IInputDevice.cs | 9 + src/Avalonia.Input/IInputElement.cs | 122 ++ src/Avalonia.Input/IInputManager.cs | 38 + src/Avalonia.Input/IInputRoot.cs | 31 + src/Avalonia.Input/IKeyboardDevice.cs | 38 + .../IKeyboardNavigationHandler.cs | 31 + src/Avalonia.Input/IMainMenu.cs | 28 + src/Avalonia.Input/IMouseDevice.cs | 16 + src/Avalonia.Input/INavigableContainer.cs | 19 + src/Avalonia.Input/IPointerDevice.cs | 18 + src/Avalonia.Input/InputElement.cs | 523 +++++ src/Avalonia.Input/InputExtensions.cs | 95 + src/Avalonia.Input/InputManager.cs | 42 + src/Avalonia.Input/Key.cs | 1021 +++++++++ src/Avalonia.Input/KeyBinding.cs | 49 + src/Avalonia.Input/KeyEventArgs.cs | 17 + src/Avalonia.Input/KeyGesture.cs | 116 + src/Avalonia.Input/KeyboardDevice.cs | 145 ++ src/Avalonia.Input/KeyboardNavigation.cs | 109 + .../KeyboardNavigationHandler.cs | 130 ++ src/Avalonia.Input/KeyboardNavigationMode.cs | 43 + src/Avalonia.Input/MouseDevice.cs | 329 +++ .../Navigation/DirectionalNavigation.cs | 232 ++ .../Navigation/FocusExtensions.cs | 25 + .../Navigation/TabNavigation.cs | 240 +++ src/Avalonia.Input/NavigationMethod.cs | 32 + src/Avalonia.Input/Platform/IClipboard.cs | 20 + .../Platform/IStandardCursorFactory.cs | 17 + src/Avalonia.Input/PointerEventArgs.cs | 71 + src/Avalonia.Input/PointerWheelEventArgs.cs | 10 + src/Avalonia.Input/Properties/AssemblyInfo.cs | 8 + src/Avalonia.Input/Raw/RawInputEventArgs.cs | 52 + src/Avalonia.Input/Raw/RawKeyEventArgs.cs | 32 + src/Avalonia.Input/Raw/RawMouseEventArgs.cs | 74 + .../Raw/RawMouseWheelEventArgs.cs | 24 + src/Avalonia.Input/Raw/RawSizeEventArgs.cs | 22 + .../Raw/RawTextInputEventArgs.cs | 15 + src/Avalonia.Input/TextInputEventArgs.cs | 19 + src/Avalonia.Input/VectorEventArgs.cs | 13 + .../app.config | 0 .../packages.config | 0 .../Avalonia.Interactivity.csproj | 99 + .../EventSubscription.cs | 16 + src/Avalonia.Interactivity/IInteractive.cs | 69 + src/Avalonia.Interactivity/Interactive.cs | 201 ++ .../InteractiveExtensions.cs | 38 + .../Properties/AssemblyInfo.cs | 6 + src/Avalonia.Interactivity/RoutedEvent.cs | 158 ++ src/Avalonia.Interactivity/RoutedEventArgs.cs | 33 + .../app.config | 0 .../packages.config | 0 src/Avalonia.Layout/Avalonia.Layout.csproj | 95 + src/Avalonia.Layout/ILayoutManager.cs | 45 + src/Avalonia.Layout/ILayoutRoot.cs | 26 + src/Avalonia.Layout/ILayoutable.cs | 116 + src/Avalonia.Layout/LayoutHelper.cs | 33 + src/Avalonia.Layout/LayoutManager.cs | 161 ++ src/Avalonia.Layout/Layoutable.cs | 676 ++++++ .../Properties/AssemblyInfo.cs | 6 + .../app.config | 0 .../packages.config | 0 .../Avalonia.Logging.Serilog.csproj | 65 + .../Properties/AssemblyInfo.cs | 30 + src/Avalonia.Logging.Serilog/SerilogLogger.cs | 44 + .../packages.config | 0 .../Avalonia.ReactiveUI.csproj | 114 + .../Properties/AssemblyInfo.cs | 33 + src/Avalonia.ReactiveUI/Registrations.cs | 23 + .../packages.config | 0 .../src | 0 .../Animation/CrossFade.cs | 118 ++ .../Animation/IPageTransition.cs | 31 + .../Animation/PageSlide.cs | 120 ++ .../Avalonia.SceneGraph.csproj | 179 ++ src/Avalonia.SceneGraph/INamed.cs | 16 + src/Avalonia.SceneGraph/Matrix.cs | 299 +++ src/Avalonia.SceneGraph/Media/AlignmentX.cs | 26 + src/Avalonia.SceneGraph/Media/AlignmentY.cs | 26 + src/Avalonia.SceneGraph/Media/ArcSegment.cs | 103 + .../Media/BezierSegment .cs | 65 + src/Avalonia.SceneGraph/Media/Brush.cs | 58 + .../Media/BrushMappingMode.cs | 17 + src/Avalonia.SceneGraph/Media/Brushes.cs | 864 ++++++++ src/Avalonia.SceneGraph/Media/Color.cs | 146 ++ src/Avalonia.SceneGraph/Media/Colors.cs | 716 +++++++ src/Avalonia.SceneGraph/Media/DashStyle.cs | 76 + .../Media/DrawingContext.cs | 225 ++ .../Media/EllipseGeometry.cs | 58 + src/Avalonia.SceneGraph/Media/FillRule.cs | 8 + src/Avalonia.SceneGraph/Media/FontStyle.cs | 26 + src/Avalonia.SceneGraph/Media/FontWeight.cs | 95 + .../Media/FormattedText.cs | 215 ++ .../Media/FormattedTextLine.cs | 32 + src/Avalonia.SceneGraph/Media/Geometry.cs | 70 + .../Media/GradientBrush.cs | 35 + .../Media/GradientSpreadMethod.cs | 18 + src/Avalonia.SceneGraph/Media/GradientStop.cs | 39 + src/Avalonia.SceneGraph/Media/IBrush.cs | 16 + .../Media/IDrawingContext.cs | 86 + .../Media/ISolidColorBrush.cs | 16 + src/Avalonia.SceneGraph/Media/ImageBush.cs | 44 + .../Media/Imaging/Bitmap.cs | 69 + .../Media/Imaging/IBitmap.cs | 34 + .../Media/Imaging/RenderTargetBitmap.cs | 52 + src/Avalonia.SceneGraph/Media/LineGeometry.cs | 44 + src/Avalonia.SceneGraph/Media/LineSegment.cs | 31 + .../Media/LinearGradientBrush.cs | 45 + .../Media/MatrixTransform.cs | 51 + .../Media/MediaExtensions.cs | 56 + .../Media/Mutable/SolidColorBrush.cs | 35 + src/Avalonia.SceneGraph/Media/PathFigure.cs | 102 + src/Avalonia.SceneGraph/Media/PathGeometry.cs | 123 ++ .../Media/PathGeometryCollections.cs | 15 + .../Media/PathMarkupParser.cs | 350 +++ src/Avalonia.SceneGraph/Media/PathSegment.cs | 10 + src/Avalonia.SceneGraph/Media/Pen.cs | 95 + src/Avalonia.SceneGraph/Media/PenLineCap.cs | 16 + src/Avalonia.SceneGraph/Media/PenLineJoin.cs | 15 + .../Media/PolylineGeometry.cs | 50 + .../Media/QuadraticBezierSegment .cs | 46 + .../Media/RadialGradientBrush.cs | 63 + .../Media/RectangleGeometry.cs | 40 + .../Media/RotateTransform.cs | 51 + .../Media/ScaleTransform.cs | 69 + .../Media/SolidColorBrush.cs | 50 + .../Media/StreamGeometry.cs | 65 + .../Media/StreamGeometryContext.cs | 113 + src/Avalonia.SceneGraph/Media/Stretch.cs | 35 + .../Media/SweepDirection.cs | 21 + .../Media/TextAlignment.cs | 26 + .../Media/TextHitTestResult.cs | 26 + src/Avalonia.SceneGraph/Media/TileBrush.cs | 133 ++ src/Avalonia.SceneGraph/Media/Transform.cs | 32 + .../Media/TransformGroup.cs | 57 + .../Media/TranslateTransform.cs | 69 + src/Avalonia.SceneGraph/Media/VisualBrush.cs | 44 + .../Platform/IBitmapImpl.cs | 27 + .../Platform/IFormattedTextImpl.cs | 66 + .../Platform/IGeometryImpl.cs | 28 + .../Platform/IPlatformRenderInterface.cs | 67 + .../Platform/IPlatformSettings.cs | 14 + .../Platform/IRenderTarget.cs | 22 + .../Platform/IRenderTargetBitmapImpl.cs | 15 + .../Platform/IStreamGeometryContextImpl.cs | 62 + .../Platform/IStreamGeometryImpl.cs | 25 + src/Avalonia.SceneGraph/Point.cs | 270 +++ .../Properties/AssemblyInfo.cs | 10 + src/Avalonia.SceneGraph/Rect.cs | 460 ++++ src/Avalonia.SceneGraph/RelativePoint.cs | 193 ++ src/Avalonia.SceneGraph/RelativeRect.cs | 210 ++ .../Rendering/IRenderQueueManager.cs | 31 + .../Rendering/IRenderRoot.cs | 32 + .../Rendering/RenderQueueManager.cs | 51 + .../Rendering/RendererMixin.cs | 178 ++ src/Avalonia.SceneGraph/Size.cs | 253 +++ src/Avalonia.SceneGraph/Thickness.cs | 237 +++ src/Avalonia.SceneGraph/Vector.cs | 134 ++ src/Avalonia.SceneGraph/Visual.cs | 496 +++++ src/Avalonia.SceneGraph/VisualExtensions.cs | 72 + .../VisualTree/BoundsTracker.cs | 64 + .../VisualTree/IHostedVisualTreeRoot.cs | 19 + src/Avalonia.SceneGraph/VisualTree/IVisual.cs | 116 + .../VisualTree/IVisualTreeHost.cs | 19 + .../VisualTree/TransformedBounds.cs | 39 + .../VisualTree/VisualExtensions.cs | 196 ++ .../VisualTreeAttachmentEventArgs.cs | 31 + .../app.config | 0 .../packages.config | 0 src/Avalonia.Styling/Avalonia.Styling.csproj | 112 + src/Avalonia.Styling/LogicalTree/ILogical.cs | 49 + .../LogicalTree/LogicalExtensions.cs | 81 + .../LogicalTreeAttachmentEventArgs.cs | 31 + .../Properties/AssemblyInfo.cs | 10 + .../Styling/ActivatedObservable.cs | 77 + .../Styling/ActivatedSubject.cs | 111 + .../Styling/ActivatedValue.cs | 72 + src/Avalonia.Styling/Styling/ChildSelector.cs | 56 + .../Styling/DescendentSelector.cs | 80 + src/Avalonia.Styling/Styling/IGlobalStyles.cs | 12 + src/Avalonia.Styling/Styling/ISetter.cs | 21 + src/Avalonia.Styling/Styling/IStyle.cs | 29 + src/Avalonia.Styling/Styling/IStyleHost.cs | 22 + src/Avalonia.Styling/Styling/IStyleRoot.cs | 12 + src/Avalonia.Styling/Styling/IStyleable.cs | 34 + src/Avalonia.Styling/Styling/IStyler.cs | 12 + .../Styling/ITemplatedControl.cs | 11 + .../Styling/PropertyEqualsSelector.cs | 91 + src/Avalonia.Styling/Styling/Selector.cs | 86 + src/Avalonia.Styling/Styling/SelectorMatch.cs | 55 + src/Avalonia.Styling/Styling/Selectors.cs | 154 ++ src/Avalonia.Styling/Styling/Setter.cs | 149 ++ src/Avalonia.Styling/Styling/Style.cs | 179 ++ .../Styling/StyleActivator.cs | 56 + .../Styling/StyleExtensions.cs | 39 + src/Avalonia.Styling/Styling/Styler.cs | 35 + src/Avalonia.Styling/Styling/Styles.cs | 51 + .../Styling/TemplateSelector.cs | 54 + .../Styling/TypeNameAndClassSelector.cs | 207 ++ .../Styling/packages.config | 0 .../app.config | 0 .../Accents/BaseLight.xaml | 29 + .../Avalonia.Themes.Default.csproj | 216 ++ src/Avalonia.Themes.Default/Button.xaml | 33 + src/Avalonia.Themes.Default/Carousel.xaml | 17 + src/Avalonia.Themes.Default/CheckBox.xaml | 44 + .../ContentControl.xaml | 12 + src/Avalonia.Themes.Default/ContextMenu.xaml | 20 + src/Avalonia.Themes.Default/DefaultTheme.xaml | 35 + .../DefaultTheme.xaml.cs | 22 + src/Avalonia.Themes.Default/DropDown.xaml | 52 + src/Avalonia.Themes.Default/DropDownItem.xaml | 25 + src/Avalonia.Themes.Default/Expander.xaml | 123 ++ src/Avalonia.Themes.Default/FocusAdorner.xaml | 9 + src/Avalonia.Themes.Default/GridSplitter.xaml | 51 + src/Avalonia.Themes.Default/ItemsControl.xaml | 10 + .../LayoutTransformControl.xaml | 12 + src/Avalonia.Themes.Default/ListBox.xaml | 20 + src/Avalonia.Themes.Default/ListBoxItem.xaml | 20 + src/Avalonia.Themes.Default/Menu.xaml | 15 + src/Avalonia.Themes.Default/MenuItem.xaml | 133 ++ src/Avalonia.Themes.Default/PopupRoot.xaml | 11 + src/Avalonia.Themes.Default/ProgressBar.xaml | 23 + .../Properties/AssemblyInfo.cs | 6 + src/Avalonia.Themes.Default/RadioButton.xaml | 43 + src/Avalonia.Themes.Default/ScrollBar.xaml | 35 + src/Avalonia.Themes.Default/ScrollViewer.xaml | 29 + src/Avalonia.Themes.Default/Separator.xaml | 25 + src/Avalonia.Themes.Default/Slider.xaml | 66 + src/Avalonia.Themes.Default/TabControl.xaml | 50 + src/Avalonia.Themes.Default/TabStrip.xaml | 20 + src/Avalonia.Themes.Default/TabStripItem.xaml | 19 + src/Avalonia.Themes.Default/TextBox.xaml | 60 + src/Avalonia.Themes.Default/ToggleButton.xaml | 37 + src/Avalonia.Themes.Default/ToolTip.xaml | 16 + src/Avalonia.Themes.Default/TreeView.xaml | 20 + src/Avalonia.Themes.Default/TreeViewItem.xaml | 68 + src/Avalonia.Themes.Default/Window.xaml | 14 + .../app.config | 0 .../packages.config | 0 src/Gtk/Avalonia.Cairo/Avalonia.Cairo.csproj | 121 ++ src/Gtk/Avalonia.Cairo/CairoExtensions.cs | 64 + src/Gtk/Avalonia.Cairo/CairoPlatform.cs | 93 + src/Gtk/Avalonia.Cairo/Media/BrushImpl.cs | 17 + .../Avalonia.Cairo/Media/DrawingContext.cs | 344 +++ .../Avalonia.Cairo/Media/FormattedTextImpl.cs | 153 ++ .../Avalonia.Cairo/Media/ImageBrushImpl.cs | 14 + .../Media/Imaging/BitmapImpl.cs | 33 + .../Media/Imaging/RenderTargetBitmapImpl.cs | 47 + .../Media/LinearGradientBrushImpl.cs | 22 + .../Media/RadialGradientBrushImpl.cs | 25 + .../Media/SolidColorBrushImpl.cs | 22 + .../Media/StreamGeometryContextImpl.cs | 103 + .../Media/StreamGeometryImpl.cs | 71 + src/Gtk/Avalonia.Cairo/Media/TileBrushes.cs | 55 + .../Avalonia.Cairo/Media/VisualBrushImpl.cs | 14 + .../Avalonia.Cairo/Properties/AssemblyInfo.cs | 39 + src/Gtk/Avalonia.Cairo/RenderTarget.cs | 55 + .../app.config | 0 .../packages.config | 0 src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj | 100 + src/Gtk/Avalonia.Gtk/ClipboardImpl.cs | 42 + src/Gtk/Avalonia.Gtk/CursorFactory.cs | 85 + src/Gtk/Avalonia.Gtk/GtkExtensions.cs | 15 + src/Gtk/Avalonia.Gtk/GtkPlatform.cs | 115 + .../Avalonia.Gtk/Input/GtkKeyboardDevice.cs | 225 ++ src/Gtk/Avalonia.Gtk/Input/GtkMouseDevice.cs | 29 + src/Gtk/Avalonia.Gtk/MyClass.cs | 12 + src/Gtk/Avalonia.Gtk/PopupImpl.cs | 16 + .../Avalonia.Gtk/Properties/AssemblyInfo.cs | 21 + src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs | 88 + src/Gtk/Avalonia.Gtk/WindowImpl.cs | 387 ++++ .../packages.config | 0 src/Gtk/Perspex.Cairo/CairoExtensions.cs | 64 - src/Gtk/Perspex.Cairo/CairoPlatform.cs | 93 - src/Gtk/Perspex.Cairo/Media/BrushImpl.cs | 17 - src/Gtk/Perspex.Cairo/Media/DrawingContext.cs | 344 --- .../Perspex.Cairo/Media/FormattedTextImpl.cs | 153 -- src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs | 14 - .../Perspex.Cairo/Media/Imaging/BitmapImpl.cs | 33 - .../Media/Imaging/RenderTargetBitmapImpl.cs | 47 - .../Media/LinearGradientBrushImpl.cs | 22 - .../Media/RadialGradientBrushImpl.cs | 25 - .../Media/SolidColorBrushImpl.cs | 22 - .../Media/StreamGeometryContextImpl.cs | 103 - .../Perspex.Cairo/Media/StreamGeometryImpl.cs | 71 - src/Gtk/Perspex.Cairo/Media/TileBrushes.cs | 55 - .../Perspex.Cairo/Media/VisualBrushImpl.cs | 14 - src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj | 121 -- .../Perspex.Cairo/Properties/AssemblyInfo.cs | 39 - src/Gtk/Perspex.Cairo/RenderTarget.cs | 55 - src/Gtk/Perspex.Gtk/ClipboardImpl.cs | 42 - src/Gtk/Perspex.Gtk/CursorFactory.cs | 85 - src/Gtk/Perspex.Gtk/GtkExtensions.cs | 15 - src/Gtk/Perspex.Gtk/GtkPlatform.cs | 115 - .../Perspex.Gtk/Input/GtkKeyboardDevice.cs | 225 -- src/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs | 29 - src/Gtk/Perspex.Gtk/MyClass.cs | 12 - src/Gtk/Perspex.Gtk/Perspex.Gtk.csproj | 100 - src/Gtk/Perspex.Gtk/PopupImpl.cs | 16 - .../Perspex.Gtk/Properties/AssemblyInfo.cs | 21 - src/Gtk/Perspex.Gtk/SystemDialogImpl.cs | 88 - src/Gtk/Perspex.Gtk/WindowImpl.cs | 387 ---- .../Avalonia.Markup.Xaml.csproj | 349 +++ .../AvaloniaXamlLoader.cs | 237 +++ .../Context/AvaloniaAttachableXamlMember.cs | 33 + .../AvaloniaContentPropertyProvider.cs | 58 + .../Context/AvaloniaLifeCycleListener.cs | 31 + .../Context/AvaloniaMemberValuePlugin.cs | 25 + .../Context/AvaloniaNamespaceRegistry.cs | 172 ++ .../Context/AvaloniaObjectAssembler.cs | 78 + .../Context/AvaloniaParserFactory.cs | 41 + .../Context/AvaloniaRuntimeTypeSource.cs | 91 + .../Context/AvaloniaTypeFeatureProvider.cs | 177 ++ .../Context/AvaloniaTypeRepository.cs | 28 + .../Context/AvaloniaWiringContext.cs | 126 ++ .../Context/AvaloniaXamlMember.cs | 31 + .../Context/AvaloniaXamlType.cs | 61 + .../Context/NameScopeWrapper.cs | 30 + .../Context/PropertyAccessor.cs | 167 ++ .../Converters/AvaloniaListTypeConverter.cs | 52 + .../AvaloniaPropertyTypeConverter.cs | 96 + .../Converters/BitmapTypeConverter.cs | 52 + .../Converters/BrushTypeConverter.cs | 33 + .../Converters/ClassesTypeConverter.cs | 34 + .../Converters/ColorTypeConverter.cs | 33 + .../ColumnDefinitionsTypeConverter.cs | 33 + .../Converters/CursorTypeConverter.cs | 36 + .../Converters/GeometryTypeConverter.cs | 30 + .../Converters/GridLengthTypeConverter.cs | 33 + .../Converters/KeyGestureConverter.cs | 30 + .../Converters/MemberSelectorTypeConverter.cs | 36 + .../Converters/PointTypeConverter.cs | 32 + .../Converters/PointsListTypeConverter.cs | 40 + .../Converters/RelativePointTypeConverter.cs | 32 + .../Converters/RelativeRectTypeConverter.cs | 32 + .../Converters/RowDefinitionsTypeConverter.cs | 33 + .../Converters/SelectorTypeConverter.cs | 34 + .../Converters/SizeTypeConverter.cs | 32 + .../Converters/ThicknessTypeConverter.cs | 32 + .../Converters/TimeSpanTypeConverter.cs | 41 + .../Converters/UriTypeConverter.cs | 32 + .../Avalonia.Markup.Xaml/Data/Binding.cs | 266 +++ .../Data/DelayedBinding.cs | 95 + .../Avalonia.Markup.Xaml/Data/MultiBinding.cs | 114 + .../Data/RelativeSource.cs | 25 + .../Data/SourceBindingEndpoint.cs | 27 + .../Data/StyleResourceBinding.cs | 69 + .../Data/TargetBindingEndpoint.cs | 18 + .../MarkupExtensions/BindingExtension.cs | 46 + .../RelativeSourceExtension.cs | 30 + .../MarkupExtensions/StaticExtension.cs | 86 + .../StyleResourceExtension.cs | 27 + .../TemplateBindingExtension.cs | 41 + .../MarkupExtensions/TypeExtension.cs | 49 + .../OmniXAML | 0 .../Parsers/SelectorGrammar.cs | 210 ++ .../Parsers/SelectorParser.cs | 118 ++ .../Properties/AssemblyInfo.cs | 14 + .../Styling/StyleInclude.cs | 71 + .../Templates/ControlTemplate.cs | 21 + .../Templates/DataTemplate.cs | 38 + .../Templates/FocusAdornerTemplate.cs | 19 + .../Templates/ItemsPanelTemplate.cs | 22 + .../Templates/MemberSelector.cs | 20 + .../Templates/Template.cs | 10 + .../Templates/TemplateContent.cs | 37 + .../Templates/TemplateLoader.cs | 16 + .../Templates/TreeDataTemplate.cs | 62 + .../app.config | 0 .../glass | 0 .../packages.config | 0 .../Avalonia.Markup/Avalonia.Markup.csproj | 135 ++ src/Markup/Avalonia.Markup/BoolConverters.cs | 19 + src/Markup/Avalonia.Markup/ControlLocator.cs | 63 + .../Data/CommonPropertyNames.cs | 10 + .../Avalonia.Markup/Data/ExpressionNode.cs | 125 ++ .../Data/ExpressionNodeBuilder.cs | 29 + .../Data/ExpressionObserver.cs | 301 +++ .../Data/ExpressionParseException.cs | 31 + .../Avalonia.Markup/Data/ExpressionSubject.cs | 193 ++ .../Avalonia.Markup/Data/IndexerNode.cs | 277 +++ .../Avalonia.Markup/Data/LogicalNotNode.cs | 55 + .../Data/Parsers/ArgumentListParser.cs | 68 + .../Data/Parsers/ExpressionParser.cs | 166 ++ .../Data/Parsers/IdentifierParser.cs | 52 + .../Avalonia.Markup/Data/Parsers/Reader.cs | 44 + .../Plugins/AvaloniaPropertyAccessorPlugin.cs | 118 ++ .../ExceptionValidationCheckerPlugin.cs | 74 + .../Data/Plugins/IPropertyAccessor.cs | 39 + .../Data/Plugins/IPropertyAccessorPlugin.cs | 37 + .../Data/Plugins/IValidationCheckerPlugin.cs | 36 + .../Plugins/IndeiValidationCheckerPlugin.cs | 96 + .../Plugins/InpcPropertyAccessorPlugin.cs | 144 ++ .../Data/Plugins/PropertyError.cs | 39 + .../Data/Plugins/ValidationCheckerBase.cs | 34 + .../Data/PropertyAccessorNode.cs | 132 ++ .../Avalonia.Markup/DefaultValueConverter.cs | 95 + .../FuncMultiValueConverter.cs | 45 + .../Avalonia.Markup/FuncValueConverter.cs | 48 + .../Avalonia.Markup/IMultiValueConverter.cs | 30 + src/Markup/Avalonia.Markup/IValueConverter.cs | 44 + .../Properties/AssemblyInfo.cs | 10 + .../Avalonia.Markup/StringConverters.cs | 27 + .../packages.config | 0 .../Context/NameScopeWrapper.cs | 30 - .../Context/PerspexAttachableXamlMember.cs | 33 - .../Context/PerspexContentPropertyProvider.cs | 58 - .../Context/PerspexLifeCycleListener.cs | 31 - .../Context/PerspexMemberValuePlugin.cs | 25 - .../Context/PerspexNamespaceRegistry.cs | 172 -- .../Context/PerspexObjectAssembler.cs | 78 - .../Context/PerspexParserFactory.cs | 41 - .../Context/PerspexRuntimeTypeSource.cs | 91 - .../Context/PerspexTypeFeatureProvider.cs | 177 -- .../Context/PerspexTypeRepository.cs | 28 - .../Context/PerspexWiringContext.cs | 126 -- .../Context/PerspexXamlMember.cs | 31 - .../Context/PerspexXamlType.cs | 61 - .../Context/PropertyAccessor.cs | 167 -- .../Converters/BitmapTypeConverter.cs | 52 - .../Converters/BrushTypeConverter.cs | 33 - .../Converters/ClassesTypeConverter.cs | 34 - .../Converters/ColorTypeConverter.cs | 33 - .../ColumnDefinitionsTypeConverter.cs | 33 - .../Converters/CursorTypeConverter.cs | 36 - .../Converters/GeometryTypeConverter.cs | 30 - .../Converters/GridLengthTypeConverter.cs | 33 - .../Converters/KeyGestureConverter.cs | 30 - .../Converters/MemberSelectorTypeConverter.cs | 36 - .../Converters/PerspexListTypeConverter.cs | 52 - .../PerspexPropertyTypeConverter.cs | 96 - .../Converters/PointTypeConverter.cs | 32 - .../Converters/PointsListTypeConverter.cs | 40 - .../Converters/RelativePointTypeConverter.cs | 32 - .../Converters/RelativeRectTypeConverter.cs | 32 - .../Converters/RowDefinitionsTypeConverter.cs | 33 - .../Converters/SelectorTypeConverter.cs | 34 - .../Converters/SizeTypeConverter.cs | 32 - .../Converters/ThicknessTypeConverter.cs | 32 - .../Converters/TimeSpanTypeConverter.cs | 41 - .../Converters/UriTypeConverter.cs | 32 - .../Perspex.Markup.Xaml/Data/Binding.cs | 266 --- .../Data/DelayedBinding.cs | 95 - .../Perspex.Markup.Xaml/Data/MultiBinding.cs | 114 - .../Data/RelativeSource.cs | 25 - .../Data/SourceBindingEndpoint.cs | 27 - .../Data/StyleResourceBinding.cs | 69 - .../Data/TargetBindingEndpoint.cs | 18 - .../MarkupExtensions/BindingExtension.cs | 46 - .../RelativeSourceExtension.cs | 30 - .../MarkupExtensions/StaticExtension.cs | 86 - .../StyleResourceExtension.cs | 27 - .../TemplateBindingExtension.cs | 41 - .../MarkupExtensions/TypeExtension.cs | 49 - .../Parsers/SelectorGrammar.cs | 210 -- .../Parsers/SelectorParser.cs | 118 -- .../Perspex.Markup.Xaml.csproj | 349 --- .../Perspex.Markup.Xaml/PerspexXamlLoader.cs | 237 --- .../Properties/AssemblyInfo.cs | 14 - .../Styling/StyleInclude.cs | 71 - .../Templates/ControlTemplate.cs | 21 - .../Templates/DataTemplate.cs | 38 - .../Templates/FocusAdornerTemplate.cs | 19 - .../Templates/ItemsPanelTemplate.cs | 22 - .../Templates/MemberSelector.cs | 20 - .../Perspex.Markup.Xaml/Templates/Template.cs | 10 - .../Templates/TemplateContent.cs | 37 - .../Templates/TemplateLoader.cs | 16 - .../Templates/TreeDataTemplate.cs | 62 - src/Markup/Perspex.Markup/BoolConverters.cs | 19 - src/Markup/Perspex.Markup/ControlLocator.cs | 63 - .../Data/CommonPropertyNames.cs | 10 - .../Perspex.Markup/Data/ExpressionNode.cs | 125 -- .../Data/ExpressionNodeBuilder.cs | 29 - .../Perspex.Markup/Data/ExpressionObserver.cs | 301 --- .../Data/ExpressionParseException.cs | 31 - .../Perspex.Markup/Data/ExpressionSubject.cs | 193 -- src/Markup/Perspex.Markup/Data/IndexerNode.cs | 277 --- .../Perspex.Markup/Data/LogicalNotNode.cs | 55 - .../Data/Parsers/ArgumentListParser.cs | 68 - .../Data/Parsers/ExpressionParser.cs | 166 -- .../Data/Parsers/IdentifierParser.cs | 52 - .../Perspex.Markup/Data/Parsers/Reader.cs | 44 - .../ExceptionValidationCheckerPlugin.cs | 74 - .../Data/Plugins/IPropertyAccessor.cs | 39 - .../Data/Plugins/IPropertyAccessorPlugin.cs | 37 - .../Data/Plugins/IValidationCheckerPlugin.cs | 36 - .../Plugins/IndeiValidationCheckerPlugin.cs | 96 - .../Plugins/InpcPropertyAccessorPlugin.cs | 144 -- .../Plugins/PerspexPropertyAccessorPlugin.cs | 118 -- .../Data/Plugins/PropertyError.cs | 39 - .../Data/Plugins/ValidationCheckerBase.cs | 34 - .../Data/PropertyAccessorNode.cs | 132 -- .../Perspex.Markup/DefaultValueConverter.cs | 95 - .../Perspex.Markup/FuncMultiValueConverter.cs | 45 - .../Perspex.Markup/FuncValueConverter.cs | 48 - .../Perspex.Markup/IMultiValueConverter.cs | 30 - src/Markup/Perspex.Markup/IValueConverter.cs | 44 - .../Perspex.Markup/Perspex.Markup.csproj | 135 -- .../Perspex.Markup/Properties/AssemblyInfo.cs | 10 - src/Markup/Perspex.Markup/StringConverters.cs | 27 - src/Perspex.Animation/Animatable.cs | 56 - src/Perspex.Animation/Animate.cs | 134 -- src/Perspex.Animation/Animation.cs | 55 - src/Perspex.Animation/AnimationExtensions.cs | 45 - src/Perspex.Animation/Animation`1.cs | 56 - src/Perspex.Animation/IEasing.cs | 23 - src/Perspex.Animation/IEasing`1.cs | 24 - src/Perspex.Animation/LinearDoubleEasing.cs | 41 - src/Perspex.Animation/LinearEasing.cs | 35 - .../Perspex.Animation.csproj | 88 - .../Properties/AssemblyInfo.cs | 6 - src/Perspex.Animation/PropertyTransition.cs | 50 - src/Perspex.Animation/PropertyTransitions.cs | 21 - src/Perspex.Base/AttachedProperty.cs | 45 - src/Perspex.Base/Collections/IPerspexList.cs | 52 - .../Collections/IPerspexReadOnlyList.cs | 17 - .../Collections/PerspexDictionary.cs | 219 -- src/Perspex.Base/Collections/PerspexList.cs | 500 ----- .../Collections/PerspexListExtensions.cs | 247 --- src/Perspex.Base/Contract.cs | 37 - .../Data/AssignBindingAttribute.cs | 20 - src/Perspex.Base/Data/BindingError.cs | 59 - src/Perspex.Base/Data/BindingMode.cs | 36 - src/Perspex.Base/Data/BindingOperations.cs | 71 - src/Perspex.Base/Data/BindingPriority.cs | 47 - src/Perspex.Base/Data/IBinding.cs | 30 - src/Perspex.Base/Data/IndexerDescriptor.cs | 115 - src/Perspex.Base/Data/InstancedBinding.cs | 109 - src/Perspex.Base/Data/ValidationMethods.cs | 13 - src/Perspex.Base/Data/ValidationStatus.cs | 30 - .../INotifyCollectionChangedDebug.cs | 25 - .../Diagnostics/IPerspexObjectDebug.cs | 22 - .../Diagnostics/PerspexObjectExtensions.cs | 46 - .../Diagnostics/PerspexPropertyValue.cs | 53 - src/Perspex.Base/DirectProperty.cs | 123 -- src/Perspex.Base/DirectPropertyMetadata`1.cs | 52 - src/Perspex.Base/IDescription.cs | 19 - src/Perspex.Base/IDirectPropertyAccessor.cs | 31 - src/Perspex.Base/IDirectPropertyMetadata.cs | 16 - src/Perspex.Base/IPerspexObject.cs | 93 - src/Perspex.Base/IPriorityValueOwner.cs | 28 - src/Perspex.Base/IStyledPropertyAccessor.cs | 31 - src/Perspex.Base/IStyledPropertyMetadata.cs | 23 - src/Perspex.Base/ISupportInitialize.cs | 22 - src/Perspex.Base/Logging/ILogSink.cs | 26 - src/Perspex.Base/Logging/LogArea.cs | 36 - src/Perspex.Base/Logging/LogEventLevel.cs | 41 - src/Perspex.Base/Logging/Logger.cs | 139 -- src/Perspex.Base/Metadata/ContentAttribute.cs | 15 - .../Metadata/DependsOnAttribute.cs | 30 - .../Metadata/XmlnsDefinitionAttribute.cs | 35 - src/Perspex.Base/Perspex.Base.csproj | 154 -- src/Perspex.Base/PerspexDisposable.cs | 41 - src/Perspex.Base/PerspexInternalException.cs | 22 - src/Perspex.Base/PerspexLocator.cs | 115 - src/Perspex.Base/PerspexObject.cs | 821 ------- src/Perspex.Base/PerspexObjectExtensions.cs | 297 --- src/Perspex.Base/PerspexProperty.cs | 554 ----- .../PerspexPropertyChangedEventArgs.cs | 74 - src/Perspex.Base/PerspexPropertyRegistry.cs | 281 --- src/Perspex.Base/PerspexProperty`1.cs | 44 - src/Perspex.Base/Platform/IAssetLoader.cs | 47 - .../Platform/IPclPlatformWrapper.cs | 17 - src/Perspex.Base/Platform/IPlatformHandle.cs | 23 - .../Platform/IPlatformThreadingInterface.cs | 34 - src/Perspex.Base/Platform/PlatformHandle.cs | 36 - src/Perspex.Base/PriorityBindingEntry.cs | 121 -- src/Perspex.Base/PriorityLevel.cs | 200 -- src/Perspex.Base/PriorityValue.cs | 279 --- src/Perspex.Base/Properties/AssemblyInfo.cs | 9 - src/Perspex.Base/PropertyMetadata.cs | 52 - .../Reactive/AnonymousSubject`1.cs | 16 - .../Reactive/AnonymousSubject`2.cs | 49 - src/Perspex.Base/Reactive/ObservableEx.cs | 41 - .../Reactive/PerspexObservable.cs | 42 - .../Reactive/WeakPropertyChangedObservable.cs | 85 - src/Perspex.Base/StyledProperty.cs | 52 - src/Perspex.Base/StyledPropertyBase.cs | 175 -- src/Perspex.Base/StyledPropertyMetadata`1.cs | 79 - src/Perspex.Base/Threading/Dispatcher.cs | 87 - .../Threading/DispatcherPriority.cs | 67 - src/Perspex.Base/Threading/DispatcherTimer.cs | 224 -- src/Perspex.Base/Threading/JobRunner.cs | 131 -- .../Threading/PerspexScheduler.cs | 38 - .../PerspexSynchronizationContext.cs | 51 - .../Threading/SingleThreadDispatcher.cs | 60 - src/Perspex.Base/Utilities/IWeakSubscriber.cs | 21 - src/Perspex.Base/Utilities/MathUtilities.cs | 39 - src/Perspex.Base/Utilities/TypeUtilities.cs | 212 -- .../Utilities/WeakSubscriptionManager.cs | 196 -- src/Perspex.Base/Utilities/WeakTimer.cs | 55 - src/Perspex.Controls/Application.cs | 235 -- src/Perspex.Controls/Border.cs | 143 -- src/Perspex.Controls/Button.cs | 349 --- src/Perspex.Controls/Canvas.cs | 233 -- src/Perspex.Controls/Carousel.cs | 100 - src/Perspex.Controls/CheckBox.cs | 14 - src/Perspex.Controls/Classes.cs | 253 --- src/Perspex.Controls/ColumnDefinition.cs | 91 - src/Perspex.Controls/ColumnDefinitions.cs | 33 - src/Perspex.Controls/ContentControl.cs | 87 - src/Perspex.Controls/ContextMenu.cs | 137 -- src/Perspex.Controls/Control.cs | 806 ------- src/Perspex.Controls/ControlExtensions.cs | 105 - .../ControlValidationStatus.cs | 27 - src/Perspex.Controls/Controls.cs | 32 - src/Perspex.Controls/Decorator.cs | 101 - src/Perspex.Controls/DefinitionBase.cs | 26 - src/Perspex.Controls/Design.cs | 57 - src/Perspex.Controls/DockPanel.cs | 176 -- src/Perspex.Controls/DropDown.cs | 184 -- src/Perspex.Controls/DropDownItem.cs | 12 - src/Perspex.Controls/Expander.cs | 89 - .../Generators/IItemContainerGenerator.cs | 93 - .../Generators/ITreeItemContainerGenerator.cs | 18 - .../Generators/ItemContainer.cs | 45 - .../Generators/ItemContainerEventArgs.cs | 51 - .../Generators/ItemContainerGenerator.cs | 210 -- .../Generators/ItemContainerGenerator`1.cs | 65 - .../Generators/TreeContainerIndex.cs | 106 - .../Generators/TreeItemContainerGenerator.cs | 132 -- src/Perspex.Controls/Grid.cs | 941 -------- src/Perspex.Controls/GridLength.cs | 216 -- src/Perspex.Controls/GridSplitter.cs | 160 -- src/Perspex.Controls/HotkeyManager.cs | 117 - src/Perspex.Controls/IApplicationLifecycle.cs | 24 - src/Perspex.Controls/IContentControl.cs | 29 - src/Perspex.Controls/IControl.cs | 49 - src/Perspex.Controls/IGlobalDataTemplates.cs | 18 - src/Perspex.Controls/IHeadered.cs | 16 - src/Perspex.Controls/INameScope.cs | 43 - src/Perspex.Controls/IPanel.cs | 16 - src/Perspex.Controls/IPseudoClasses.cs | 25 - src/Perspex.Controls/ISelectable.cs | 24 - src/Perspex.Controls/ISetLogicalParent.cs | 22 - src/Perspex.Controls/Image.cs | 103 - src/Perspex.Controls/ItemsControl.cs | 370 ---- .../LayoutTransformControl.cs | 389 ---- src/Perspex.Controls/ListBox.cs | 76 - src/Perspex.Controls/ListBoxItem.cs | 37 - src/Perspex.Controls/Menu.cs | 243 --- src/Perspex.Controls/MenuItem.cs | 490 ----- .../MenuItemAccessKeyHandler.cs | 104 - .../Mixins/ContentControlMixin.cs | 154 -- .../Mixins/SelectableMixin.cs | 79 - src/Perspex.Controls/NameScope.cs | 109 - src/Perspex.Controls/NameScopeEventArgs.cs | 19 - src/Perspex.Controls/NameScopeExtensions.cs | 68 - src/Perspex.Controls/Panel.cs | 142 -- src/Perspex.Controls/Perspex.Controls.csproj | 261 --- src/Perspex.Controls/PlacementMode.cs | 28 - src/Perspex.Controls/Platform/IPopupImpl.cs | 13 - .../Platform/ISystemDialogImpl.cs | 24 - .../Platform/ITopLevelImpl.cs | 128 -- .../Platform/ITopLevelRenderer.cs | 54 - src/Perspex.Controls/Platform/IWindowImpl.cs | 43 - .../Platform/IWindowingPlatform.cs | 15 - .../Platform/PlatformManager.cs | 51 - .../Presenters/CarouselPresenter.cs | 227 -- .../Presenters/ContentPresenter.cs | 347 --- .../Presenters/IContentPresenter.cs | 24 - .../Presenters/IContentPresenterHost.cs | 27 - .../Presenters/IItemsPresenter.cs | 10 - .../Presenters/IItemsPresenterHost.cs | 27 - src/Perspex.Controls/Presenters/IPresenter.cs | 22 - .../Presenters/ItemsPresenter.cs | 148 -- .../Presenters/ItemsPresenterBase.cs | 217 -- .../Presenters/ScrollContentPresenter.cs | 273 --- .../Presenters/TextPresenter.cs | 250 --- src/Perspex.Controls/Primitives/AccessText.cs | 179 -- .../Primitives/AdornerDecorator.cs | 33 - .../Primitives/AdornerLayer.cs | 133 -- .../Primitives/HeaderedContentControl.cs | 26 - .../Primitives/HeaderedItemsControl.cs | 58 - .../Primitives/HeaderedSelectingControl.cs | 56 - .../Primitives/IScrollable.cs | 54 - src/Perspex.Controls/Primitives/Popup.cs | 340 --- src/Perspex.Controls/Primitives/PopupRoot.cs | 142 -- src/Perspex.Controls/Primitives/RangeBase.cs | 152 -- src/Perspex.Controls/Primitives/ScrollBar.cs | 108 - .../Primitives/ScrollBarVisibility.cs | 12 - .../Primitives/SelectingItemsControl.cs | 873 -------- src/Perspex.Controls/Primitives/TabStrip.cs | 54 - .../Primitives/TabStripItem.cs | 12 - .../Primitives/TemplateAppliedEventArgs.cs | 28 - .../Primitives/TemplatedControl.cs | 355 ---- src/Perspex.Controls/Primitives/Thumb.cs | 106 - .../Primitives/ToggleButton.cs | 43 - src/Perspex.Controls/Primitives/Track.cs | 180 -- src/Perspex.Controls/ProgressBar.cs | 49 - .../Properties/AssemblyInfo.cs | 17 - src/Perspex.Controls/RadioButton.cs | 44 - .../RequestBringIntoViewEventArgs.cs | 15 - src/Perspex.Controls/RowDefinition.cs | 91 - src/Perspex.Controls/RowDefinitions.cs | 33 - src/Perspex.Controls/ScrollViewer.cs | 404 ---- .../SelectionChangedEventArgs.cs | 38 - src/Perspex.Controls/SelectionMode.cs | 34 - src/Perspex.Controls/Separator.cs | 19 - src/Perspex.Controls/Shapes/Ellipse.cs | 26 - src/Perspex.Controls/Shapes/Line.cs | 39 - src/Perspex.Controls/Shapes/Path.cs | 27 - src/Perspex.Controls/Shapes/Polygon.cs | 30 - src/Perspex.Controls/Shapes/Polyline.cs | 31 - src/Perspex.Controls/Shapes/Rectangle.cs | 26 - src/Perspex.Controls/Shapes/Shape.cs | 263 --- src/Perspex.Controls/Slider.cs | 147 -- src/Perspex.Controls/StackPanel.cs | 232 -- src/Perspex.Controls/SystemDialog.cs | 55 - src/Perspex.Controls/TabControl.cs | 150 -- src/Perspex.Controls/TabItem.cs | 38 - .../Templates/DataTemplateExtensions.cs | 90 - .../Templates/DataTemplates.cs | 21 - .../Templates/FuncControlTemplate.cs | 24 - .../Templates/FuncControlTemplate`2.cs | 25 - .../Templates/FuncDataTemplate.cs | 79 - .../Templates/FuncDataTemplate`1.cs | 60 - .../Templates/FuncMemberSelector.cs | 35 - .../Templates/FuncTemplate`1.cs | 38 - .../Templates/FuncTemplate`2.cs | 41 - .../Templates/FuncTreeDataTemplate.cs | 81 - .../Templates/FuncTreeDataTemplate`1.cs | 79 - .../Templates/IControlTemplate.cs | 15 - .../Templates/IDataTemplate.cs | 20 - .../Templates/IMemberSelector.cs | 18 - src/Perspex.Controls/Templates/ITemplate`1.cs | 20 - src/Perspex.Controls/Templates/ITemplate`2.cs | 22 - .../Templates/ITreeDataTemplate.cs | 23 - .../Templates/TemplateExtensions.cs | 42 - src/Perspex.Controls/TextBlock.cs | 408 ---- src/Perspex.Controls/TextBox.cs | 649 ------ src/Perspex.Controls/TextWrapping.cs | 21 - src/Perspex.Controls/ToolTip.cs | 160 -- src/Perspex.Controls/TopLevel.cs | 409 ---- src/Perspex.Controls/TreeView.cs | 268 --- src/Perspex.Controls/TreeViewItem.cs | 127 -- src/Perspex.Controls/UserControl.cs | 47 - src/Perspex.Controls/Utils/AncestorFinder.cs | 77 - .../Utils/IEnumerableUtils.cs | 78 - src/Perspex.Controls/Utils/StringUtils.cs | 263 --- src/Perspex.Controls/Utils/UndoRedoHelper.cs | 98 - src/Perspex.Controls/Window.cs | 340 --- src/Perspex.Controls/WindowEdge.cs | 17 - src/Perspex.Controls/WindowState.cs | 26 - src/Perspex.Controls/WrapPanel.cs | 253 --- src/Perspex.DesignerSupport/DesignerApi.cs | 56 - src/Perspex.DesignerSupport/DesignerAssist.cs | 108 - .../Perspex.DesignerSupport.csproj | 123 -- .../Properties/AssemblyInfo.cs | 8 - src/Perspex.Diagnostics/Debug.cs | 75 - src/Perspex.Diagnostics/DevTools.xaml | 20 - src/Perspex.Diagnostics/DevTools.xaml.cs | 121 -- src/Perspex.Diagnostics/LogManager.cs | 53 - .../Perspex.Diagnostics.csproj | 152 -- .../Properties/AssemblyInfo.cs | 6 - src/Perspex.Diagnostics/ViewLocator.cs | 32 - .../ViewModels/ControlDetailsViewModel.cs | 36 - .../ViewModels/DevToolsViewModel.cs | 83 - .../ViewModels/LogicalTreeNode.cs | 25 - .../ViewModels/PropertyDetails.cs | 59 - .../ViewModels/TreeNode.cs | 81 - .../ViewModels/TreePageViewModel.cs | 102 - .../ViewModels/VisualTreeNode.cs | 40 - .../Views/ControlDetailsView.cs | 83 - src/Perspex.Diagnostics/Views/GridRepeater.cs | 68 - .../Views/TreePage.xaml.cs | 70 - .../Views/TreePageView.xaml | 24 - .../Adapters/BrushAdapter.cs | 47 - .../Adapters/ContextMenuAdapter.cs | 51 - .../Adapters/ControlAdapter.cs | 108 - .../Adapters/FontAdapter.cs | 106 - .../Adapters/FontFamilyAdapter.cs | 29 - .../Adapters/GraphicsAdapter.cs | 295 --- .../Adapters/GraphicsPathAdapter.cs | 67 - .../Adapters/ImageAdapter.cs | 52 - .../Adapters/PenAdapter.cs | 79 - .../Adapters/PerspexAdapter.cs | 129 -- src/Perspex.HtmlRenderer/Compat/Attributes.cs | 28 - src/Perspex.HtmlRenderer/Compat/ThreadPool.cs | 22 - src/Perspex.HtmlRenderer/HtmlContainer.cs | 471 ---- src/Perspex.HtmlRenderer/HtmlControl.cs | 615 ------ src/Perspex.HtmlRenderer/HtmlLabel.cs | 112 - .../HtmlRendererRoutedEventArgs.cs | 14 - .../Perspex.HtmlRenderer.csproj | 199 -- .../Properties/AssemblyInfo.cs | 33 - src/Perspex.HtmlRenderer/PropertyHelper.cs | 24 - src/Perspex.HtmlRenderer/Utilities/Util.cs | 123 -- src/Perspex.Input/AccessKeyHandler.cs | 224 -- src/Perspex.Input/Cursors.cs | 77 - src/Perspex.Input/FocusManager.cs | 198 -- src/Perspex.Input/FocusNavigationDirection.cs | 51 - src/Perspex.Input/Gestures.cs | 59 - src/Perspex.Input/GotFocusEventArgs.cs | 23 - src/Perspex.Input/IAccessKeyHandler.cs | 38 - src/Perspex.Input/ICloseable.cs | 12 - src/Perspex.Input/IFocusManager.cs | 42 - src/Perspex.Input/IFocusScope.cs | 9 - src/Perspex.Input/IInputDevice.cs | 9 - src/Perspex.Input/IInputElement.cs | 122 -- src/Perspex.Input/IInputManager.cs | 38 - src/Perspex.Input/IInputRoot.cs | 31 - src/Perspex.Input/IKeyboardDevice.cs | 38 - .../IKeyboardNavigationHandler.cs | 31 - src/Perspex.Input/IMainMenu.cs | 28 - src/Perspex.Input/IMouseDevice.cs | 16 - src/Perspex.Input/INavigableContainer.cs | 19 - src/Perspex.Input/IPointerDevice.cs | 18 - src/Perspex.Input/InputElement.cs | 523 ----- src/Perspex.Input/InputExtensions.cs | 95 - src/Perspex.Input/InputManager.cs | 42 - src/Perspex.Input/Key.cs | 1021 --------- src/Perspex.Input/KeyBinding.cs | 49 - src/Perspex.Input/KeyEventArgs.cs | 17 - src/Perspex.Input/KeyGesture.cs | 116 - src/Perspex.Input/KeyboardDevice.cs | 145 -- src/Perspex.Input/KeyboardNavigation.cs | 109 - .../KeyboardNavigationHandler.cs | 130 -- src/Perspex.Input/KeyboardNavigationMode.cs | 43 - src/Perspex.Input/MouseDevice.cs | 329 --- .../Navigation/DirectionalNavigation.cs | 232 -- .../Navigation/FocusExtensions.cs | 25 - src/Perspex.Input/Navigation/TabNavigation.cs | 240 --- src/Perspex.Input/NavigationMethod.cs | 32 - src/Perspex.Input/Perspex.Input.csproj | 145 -- src/Perspex.Input/Platform/IClipboard.cs | 20 - .../Platform/IStandardCursorFactory.cs | 17 - src/Perspex.Input/PointerEventArgs.cs | 71 - src/Perspex.Input/PointerWheelEventArgs.cs | 10 - src/Perspex.Input/Properties/AssemblyInfo.cs | 8 - src/Perspex.Input/Raw/RawInputEventArgs.cs | 52 - src/Perspex.Input/Raw/RawKeyEventArgs.cs | 32 - src/Perspex.Input/Raw/RawMouseEventArgs.cs | 74 - .../Raw/RawMouseWheelEventArgs.cs | 24 - src/Perspex.Input/Raw/RawSizeEventArgs.cs | 22 - .../Raw/RawTextInputEventArgs.cs | 15 - src/Perspex.Input/TextInputEventArgs.cs | 19 - src/Perspex.Input/VectorEventArgs.cs | 13 - .../EventSubscription.cs | 16 - src/Perspex.Interactivity/IInteractive.cs | 69 - src/Perspex.Interactivity/Interactive.cs | 201 -- .../InteractiveExtensions.cs | 38 - .../Perspex.Interactivity.csproj | 99 - .../Properties/AssemblyInfo.cs | 6 - src/Perspex.Interactivity/RoutedEvent.cs | 158 -- src/Perspex.Interactivity/RoutedEventArgs.cs | 33 - src/Perspex.Layout/ILayoutManager.cs | 45 - src/Perspex.Layout/ILayoutRoot.cs | 26 - src/Perspex.Layout/ILayoutable.cs | 116 - src/Perspex.Layout/LayoutHelper.cs | 33 - src/Perspex.Layout/LayoutManager.cs | 161 -- src/Perspex.Layout/Layoutable.cs | 676 ------ src/Perspex.Layout/Perspex.Layout.csproj | 95 - src/Perspex.Layout/Properties/AssemblyInfo.cs | 6 - .../Perspex.Logging.Serilog.csproj | 65 - .../Properties/AssemblyInfo.cs | 30 - src/Perspex.Logging.Serilog/SerilogLogger.cs | 44 - .../Perspex.ReactiveUI.csproj | 114 - .../Properties/AssemblyInfo.cs | 33 - src/Perspex.ReactiveUI/Registrations.cs | 23 - src/Perspex.SceneGraph/Animation/CrossFade.cs | 118 -- .../Animation/IPageTransition.cs | 31 - src/Perspex.SceneGraph/Animation/PageSlide.cs | 120 -- src/Perspex.SceneGraph/INamed.cs | 16 - src/Perspex.SceneGraph/Matrix.cs | 299 --- src/Perspex.SceneGraph/Media/AlignmentX.cs | 26 - src/Perspex.SceneGraph/Media/AlignmentY.cs | 26 - src/Perspex.SceneGraph/Media/ArcSegment.cs | 103 - .../Media/BezierSegment .cs | 65 - src/Perspex.SceneGraph/Media/Brush.cs | 58 - .../Media/BrushMappingMode.cs | 17 - src/Perspex.SceneGraph/Media/Brushes.cs | 864 -------- src/Perspex.SceneGraph/Media/Color.cs | 146 -- src/Perspex.SceneGraph/Media/Colors.cs | 716 ------- src/Perspex.SceneGraph/Media/DashStyle.cs | 76 - .../Media/DrawingContext.cs | 225 -- .../Media/EllipseGeometry.cs | 58 - src/Perspex.SceneGraph/Media/FillRule.cs | 8 - src/Perspex.SceneGraph/Media/FontStyle.cs | 26 - src/Perspex.SceneGraph/Media/FontWeight.cs | 95 - src/Perspex.SceneGraph/Media/FormattedText.cs | 215 -- .../Media/FormattedTextLine.cs | 32 - src/Perspex.SceneGraph/Media/Geometry.cs | 70 - src/Perspex.SceneGraph/Media/GradientBrush.cs | 35 - .../Media/GradientSpreadMethod.cs | 18 - src/Perspex.SceneGraph/Media/GradientStop.cs | 39 - src/Perspex.SceneGraph/Media/IBrush.cs | 16 - .../Media/IDrawingContext.cs | 86 - .../Media/ISolidColorBrush.cs | 16 - src/Perspex.SceneGraph/Media/ImageBush.cs | 44 - .../Media/Imaging/Bitmap.cs | 69 - .../Media/Imaging/IBitmap.cs | 34 - .../Media/Imaging/RenderTargetBitmap.cs | 52 - src/Perspex.SceneGraph/Media/LineGeometry.cs | 44 - src/Perspex.SceneGraph/Media/LineSegment.cs | 31 - .../Media/LinearGradientBrush.cs | 45 - .../Media/MatrixTransform.cs | 51 - .../Media/MediaExtensions.cs | 56 - .../Media/Mutable/SolidColorBrush.cs | 35 - src/Perspex.SceneGraph/Media/PathFigure.cs | 102 - src/Perspex.SceneGraph/Media/PathGeometry.cs | 123 -- .../Media/PathGeometryCollections.cs | 15 - .../Media/PathMarkupParser.cs | 350 --- src/Perspex.SceneGraph/Media/PathSegment.cs | 10 - src/Perspex.SceneGraph/Media/Pen.cs | 95 - src/Perspex.SceneGraph/Media/PenLineCap.cs | 16 - src/Perspex.SceneGraph/Media/PenLineJoin.cs | 15 - .../Media/PolylineGeometry.cs | 50 - .../Media/QuadraticBezierSegment .cs | 46 - .../Media/RadialGradientBrush.cs | 63 - .../Media/RectangleGeometry.cs | 40 - .../Media/RotateTransform.cs | 51 - .../Media/ScaleTransform.cs | 69 - .../Media/SolidColorBrush.cs | 50 - .../Media/StreamGeometry.cs | 65 - .../Media/StreamGeometryContext.cs | 113 - src/Perspex.SceneGraph/Media/Stretch.cs | 35 - .../Media/SweepDirection.cs | 21 - src/Perspex.SceneGraph/Media/TextAlignment.cs | 26 - .../Media/TextHitTestResult.cs | 26 - src/Perspex.SceneGraph/Media/TileBrush.cs | 133 -- src/Perspex.SceneGraph/Media/Transform.cs | 32 - .../Media/TransformGroup.cs | 57 - .../Media/TranslateTransform.cs | 69 - src/Perspex.SceneGraph/Media/VisualBrush.cs | 44 - .../Perspex.SceneGraph.csproj | 179 -- .../Platform/IBitmapImpl.cs | 27 - .../Platform/IFormattedTextImpl.cs | 66 - .../Platform/IGeometryImpl.cs | 28 - .../Platform/IPlatformRenderInterface.cs | 67 - .../Platform/IPlatformSettings.cs | 14 - .../Platform/IRenderTarget.cs | 22 - .../Platform/IRenderTargetBitmapImpl.cs | 15 - .../Platform/IStreamGeometryContextImpl.cs | 62 - .../Platform/IStreamGeometryImpl.cs | 25 - src/Perspex.SceneGraph/Point.cs | 270 --- .../Properties/AssemblyInfo.cs | 10 - src/Perspex.SceneGraph/Rect.cs | 460 ---- src/Perspex.SceneGraph/RelativePoint.cs | 193 -- src/Perspex.SceneGraph/RelativeRect.cs | 210 -- .../Rendering/IRenderQueueManager.cs | 31 - .../Rendering/IRenderRoot.cs | 32 - .../Rendering/RenderQueueManager.cs | 51 - .../Rendering/RendererMixin.cs | 178 -- src/Perspex.SceneGraph/Size.cs | 253 --- src/Perspex.SceneGraph/Thickness.cs | 237 --- src/Perspex.SceneGraph/Vector.cs | 134 -- src/Perspex.SceneGraph/Visual.cs | 496 ----- src/Perspex.SceneGraph/VisualExtensions.cs | 72 - .../VisualTree/BoundsTracker.cs | 64 - .../VisualTree/IHostedVisualTreeRoot.cs | 19 - src/Perspex.SceneGraph/VisualTree/IVisual.cs | 116 - .../VisualTree/IVisualTreeHost.cs | 19 - .../VisualTree/TransformedBounds.cs | 39 - .../VisualTree/VisualExtensions.cs | 196 -- .../VisualTreeAttachmentEventArgs.cs | 31 - src/Perspex.Styling/LogicalTree/ILogical.cs | 49 - .../LogicalTree/LogicalExtensions.cs | 81 - .../LogicalTreeAttachmentEventArgs.cs | 31 - src/Perspex.Styling/Perspex.Styling.csproj | 112 - .../Properties/AssemblyInfo.cs | 10 - .../Styling/ActivatedObservable.cs | 77 - .../Styling/ActivatedSubject.cs | 111 - src/Perspex.Styling/Styling/ActivatedValue.cs | 72 - src/Perspex.Styling/Styling/ChildSelector.cs | 56 - .../Styling/DescendentSelector.cs | 80 - src/Perspex.Styling/Styling/IGlobalStyles.cs | 12 - src/Perspex.Styling/Styling/ISetter.cs | 21 - src/Perspex.Styling/Styling/IStyle.cs | 29 - src/Perspex.Styling/Styling/IStyleHost.cs | 22 - src/Perspex.Styling/Styling/IStyleRoot.cs | 12 - src/Perspex.Styling/Styling/IStyleable.cs | 34 - src/Perspex.Styling/Styling/IStyler.cs | 12 - .../Styling/ITemplatedControl.cs | 11 - .../Styling/PropertyEqualsSelector.cs | 91 - src/Perspex.Styling/Styling/Selector.cs | 86 - src/Perspex.Styling/Styling/SelectorMatch.cs | 55 - src/Perspex.Styling/Styling/Selectors.cs | 154 -- src/Perspex.Styling/Styling/Setter.cs | 149 -- src/Perspex.Styling/Styling/Style.cs | 179 -- src/Perspex.Styling/Styling/StyleActivator.cs | 56 - .../Styling/StyleExtensions.cs | 39 - src/Perspex.Styling/Styling/Styler.cs | 35 - src/Perspex.Styling/Styling/Styles.cs | 51 - .../Styling/TemplateSelector.cs | 54 - .../Styling/TypeNameAndClassSelector.cs | 207 -- .../Accents/BaseLight.xaml | 29 - src/Perspex.Themes.Default/Button.xaml | 33 - src/Perspex.Themes.Default/Carousel.xaml | 17 - src/Perspex.Themes.Default/CheckBox.xaml | 44 - .../ContentControl.xaml | 12 - src/Perspex.Themes.Default/ContextMenu.xaml | 20 - src/Perspex.Themes.Default/DefaultTheme.xaml | 35 - .../DefaultTheme.xaml.cs | 22 - src/Perspex.Themes.Default/DropDown.xaml | 52 - src/Perspex.Themes.Default/DropDownItem.xaml | 25 - src/Perspex.Themes.Default/Expander.xaml | 123 -- src/Perspex.Themes.Default/FocusAdorner.xaml | 9 - src/Perspex.Themes.Default/GridSplitter.xaml | 51 - src/Perspex.Themes.Default/ItemsControl.xaml | 10 - .../LayoutTransformControl.xaml | 12 - src/Perspex.Themes.Default/ListBox.xaml | 20 - src/Perspex.Themes.Default/ListBoxItem.xaml | 20 - src/Perspex.Themes.Default/Menu.xaml | 15 - src/Perspex.Themes.Default/MenuItem.xaml | 133 -- .../Perspex.Themes.Default.csproj | 216 -- src/Perspex.Themes.Default/PopupRoot.xaml | 11 - src/Perspex.Themes.Default/ProgressBar.xaml | 23 - .../Properties/AssemblyInfo.cs | 6 - src/Perspex.Themes.Default/RadioButton.xaml | 43 - src/Perspex.Themes.Default/ScrollBar.xaml | 35 - src/Perspex.Themes.Default/ScrollViewer.xaml | 29 - src/Perspex.Themes.Default/Separator.xaml | 25 - src/Perspex.Themes.Default/Slider.xaml | 66 - src/Perspex.Themes.Default/TabControl.xaml | 50 - src/Perspex.Themes.Default/TabStrip.xaml | 20 - src/Perspex.Themes.Default/TabStripItem.xaml | 19 - src/Perspex.Themes.Default/TextBox.xaml | 60 - src/Perspex.Themes.Default/ToggleButton.xaml | 37 - src/Perspex.Themes.Default/ToolTip.xaml | 16 - src/Perspex.Themes.Default/TreeView.xaml | 20 - src/Perspex.Themes.Default/TreeViewItem.xaml | 68 - src/Perspex.Themes.Default/Window.xaml | 14 - src/Shared/PlatformSupport/AssetLoader.cs | 10 +- .../PlatformSupport/PclPlatformWrapper.cs | Bin 1954 -> 952 bytes .../PlatformSupport/PlatformSupport.projitems | 4 +- src/Shared/PlatformSupport/SharedPlatform.cs | 8 +- src/Shared/RenderHelpers/ArcToHelper.cs | 12 +- src/Shared/RenderHelpers/QuadBezierHelper.cs | 4 +- .../RenderHelpers/RenderHelpers.projitems | 4 +- src/Shared/RenderHelpers/RenderHelpers.shproj | 2 +- .../RenderHelpers/TileBrushImplHelper.cs | 12 +- src/Shared/SharedAssemblyInfo.cs | Bin 1364 -> 665 bytes src/Shared/avalonia.platform.targets | 20 + src/Shared/perspex.platform.targets | 20 - .../Avalonia.Skia.Android.TestApp.csproj | 122 ++ .../MainActivity.cs | 71 + .../Properties/AndroidManifest.xml | 5 + .../Properties/AssemblyInfo.cs | 30 + .../Resources/Resource.Designer.cs | 112 + .../Resources/drawable/Icon.png | Bin .../Resources/layout/Main.axml | 0 .../Resources/values/Strings.xml | 5 + .../AndroidRenderTarget.cs | 24 + .../Avalonia.Skia.Android.csproj | 106 + .../Resources/Resource.Designer.cs | 0 .../Avalonia.Skia.Android/SkiaRenderView.cs | 39 + src/Skia/Avalonia.Skia.Android/SkiaView.cs | 88 + .../packages.config | 0 .../Avalonia.Skia.Desktop.csproj | 133 ++ .../Properties/AssemblyInfo.cs | 36 + .../packages.config | 0 .../Avalonia.Skia.iOS.TestApp/AppDelegate.cs | 74 + .../Avalonia.Skia.iOS.TestApp.csproj | 143 ++ .../Entitlements.plist | 0 .../GettingStarted.Xamarin | 0 src/Skia/Avalonia.Skia.iOS.TestApp/Info.plist | 42 + src/Skia/Avalonia.Skia.iOS.TestApp/Main.cs | 15 + .../Avalonia.Skia.iOS.TestApp/MainView.cs | 77 + .../Properties/AssemblyInfo.cs | 36 + .../Resources/LaunchScreen.xib | 43 + .../Avalonia.Skia.iOS.csproj | 96 + .../Properties/AssemblyInfo.cs | 36 + src/Skia/Avalonia.Skia.iOS/SkiaView.cs | 64 + .../packages.config | 0 .../Avalonia.Skia/Avalonia.Skia.projitems | 26 + src/Skia/Avalonia.Skia/Avalonia.Skia.shproj | 13 + src/Skia/Avalonia.Skia/BitmapImpl.cs | 84 + src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 306 +++ src/Skia/Avalonia.Skia/FormattedTextImpl.cs | 333 +++ .../Avalonia.Skia/PlatformRenderInterface.cs | 70 + src/Skia/Avalonia.Skia/RenderTarget.cs | 187 ++ src/Skia/Avalonia.Skia/SkiaPlatform.cs | 41 + src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs | 74 + src/Skia/Avalonia.Skia/StreamGeometryImpl.cs | 143 ++ src/Skia/Avalonia.Skia/TypefaceCache.cs | 48 + .../Avalonia.Skia/WindowDrawingContextImpl.cs | 21 + src/Skia/Avalonia.Skia/readme.md | 39 + .../MainActivity.cs | 71 - .../Perspex.Skia.Android.TestApp.csproj | 122 -- .../Properties/AndroidManifest.xml | 5 - .../Properties/AssemblyInfo.cs | 30 - .../Resources/Resource.Designer.cs | 112 - .../Resources/values/Strings.xml | 5 - .../AndroidRenderTarget.cs | 24 - .../Perspex.Skia.Android.csproj | 106 - .../Perspex.Skia.Android/SkiaRenderView.cs | 39 - src/Skia/Perspex.Skia.Android/SkiaView.cs | 88 - .../Perspex.Skia.Desktop.csproj | 133 -- .../Properties/AssemblyInfo.cs | 36 - .../Perspex.Skia.iOS.TestApp/AppDelegate.cs | 74 - src/Skia/Perspex.Skia.iOS.TestApp/Info.plist | 42 - src/Skia/Perspex.Skia.iOS.TestApp/Main.cs | 15 - src/Skia/Perspex.Skia.iOS.TestApp/MainView.cs | 77 - .../Perspex.Skia.iOS.TestApp.csproj | 143 -- .../Properties/AssemblyInfo.cs | 36 - .../Resources/LaunchScreen.xib | 43 - .../Perspex.Skia.iOS/Perspex.Skia.iOS.csproj | 96 - .../Properties/AssemblyInfo.cs | 36 - src/Skia/Perspex.Skia.iOS/SkiaView.cs | 64 - src/Skia/Perspex.Skia/BitmapImpl.cs | 84 - src/Skia/Perspex.Skia/DrawingContextImpl.cs | 306 --- src/Skia/Perspex.Skia/FormattedTextImpl.cs | 333 --- src/Skia/Perspex.Skia/Perspex.Skia.projitems | 26 - src/Skia/Perspex.Skia/Perspex.Skia.shproj | 13 - .../Perspex.Skia/PlatformRenderInterface.cs | 70 - src/Skia/Perspex.Skia/RenderTarget.cs | 187 -- src/Skia/Perspex.Skia/SkiaPlatform.cs | 41 - src/Skia/Perspex.Skia/SkiaSharpExtensions.cs | 74 - src/Skia/Perspex.Skia/StreamGeometryImpl.cs | 143 -- src/Skia/Perspex.Skia/TypefaceCache.cs | 48 - .../Perspex.Skia/WindowDrawingContextImpl.cs | 21 - src/Skia/Perspex.Skia/readme.md | 39 - .../App.config | 0 src/Windows/Avalonia.Designer/App.xaml | 8 + src/Windows/Avalonia.Designer/App.xaml.cs | 28 + .../AppHost/AvaloniaAppHost.cs | 297 +++ .../AppHost/HostedAppModel.cs | 100 + .../Avalonia.Designer/AppHost/WindowHost.cs | 143 ++ .../Avalonia.Designer.csproj | 137 ++ .../Avalonia.Designer/AvaloniaDesigner.xaml | 17 + .../AvaloniaDesigner.xaml.cs | 131 ++ .../Avalonia.Designer/Comm/CommChannel.cs | 137 ++ .../Avalonia.Designer/Comm/InitMessage.cs | 18 + .../Avalonia.Designer/Comm/ProcessHost.cs | 171 ++ .../Avalonia.Designer/Comm/StateMessage.cs | 19 + .../Avalonia.Designer/Comm/UpdateMetadata.cs | 20 + .../Comm/UpdateXamlMessage.cs | 19 + .../Comm/WindowCreatedMessage.cs | 19 + src/Windows/Avalonia.Designer/DemoWindow.xaml | 23 + .../Avalonia.Designer/DemoWindow.xaml.cs | 34 + .../InProcDesigner/InProcDesignerView.xaml | 34 + .../InProcDesigner/InProcDesignerView.xaml.cs | 98 + .../Metadata/AvaloniaDesignerMetadata.cs | 51 + src/Windows/Avalonia.Designer/Program.cs | 67 + .../Properties/AssemblyInfo.cs | 36 + .../README.txt | 0 src/Windows/Avalonia.Designer/Settings.cs | 19 + src/Windows/Avalonia.Designer/WinApi.cs | 33 + .../avalonia.designer.snk} | Bin .../packages.config | 0 .../Avalonia.Direct2D1.csproj | 138 ++ .../Avalonia.Direct2D1/Direct2D1Platform.cs | 90 + src/Windows/Avalonia.Direct2D1/Disposable.cs | 36 + .../Media/AvaloniaTextRenderer.cs | 101 + .../Avalonia.Direct2D1/Media/BrushImpl.cs | 20 + .../Avalonia.Direct2D1/Media/BrushWrapper.cs | 18 + .../Media/DrawingContext.cs | 328 +++ .../Media/FormattedTextImpl.cs | 129 ++ .../Avalonia.Direct2D1/Media/GeometryImpl.cs | 88 + .../Media/Imaging/BitmapImpl.cs | 131 ++ .../Media/Imaging/RenderTargetBitmapImpl.cs | 45 + .../Media/LinearGradientBrushImpl.cs | 50 + .../Media/RadialGradientBrushImpl.cs | 56 + .../Media/SolidColorBrushImpl.cs | 23 + .../Media/StreamGeometryContextImpl.cs | 83 + .../Media/StreamGeometryImpl.cs | 66 + .../Avalonia.Direct2D1/Media/TileBrushImpl.cs | 78 + .../Avalonia.Direct2D1/PrimitiveExtensions.cs | 195 ++ .../Properties/AssemblyInfo.cs | 6 + .../Avalonia.Direct2D1/RenderTarget.cs | 141 ++ .../app.config | 0 .../packages.config | 0 .../Avalonia.Win32/Avalonia.Win32.csproj | 127 ++ src/Windows/Avalonia.Win32/ClipboardImpl.cs | 84 + src/Windows/Avalonia.Win32/CursorFactory.cs | 70 + .../Embedding/EmbeddedWindowImpl.cs | 31 + .../Avalonia.Win32/Input/KeyInterop.cs | 381 ++++ .../Input/WindowsKeyboardDevice.cs | 95 + .../Input/WindowsMouseDevice.cs | 35 + .../Interop/UnmanagedMethods.cs | 1155 ++++++++++ .../Avalonia.Win32/PlatformConstants.cs | 11 + src/Windows/Avalonia.Win32/PopupImpl.cs | 53 + .../Avalonia.Win32/Properties/AssemblyInfo.cs | 6 + .../Settings.StyleCop | 0 .../Avalonia.Win32/SystemDialogImpl.cs | 195 ++ src/Windows/Avalonia.Win32/Win32Platform.cs | 189 ++ src/Windows/Avalonia.Win32/WindowImpl.cs | 672 ++++++ .../app.config | 0 .../packages.config | 0 src/Windows/Perspex.Designer/App.xaml | 8 - src/Windows/Perspex.Designer/App.xaml.cs | 28 - .../AppHost/HostedAppModel.cs | 100 - .../AppHost/PerspexAppHost.cs | 297 --- .../Perspex.Designer/AppHost/WindowHost.cs | 143 -- .../Perspex.Designer/Comm/CommChannel.cs | 137 -- .../Perspex.Designer/Comm/InitMessage.cs | 18 - .../Perspex.Designer/Comm/ProcessHost.cs | 171 -- .../Perspex.Designer/Comm/StateMessage.cs | 19 - .../Perspex.Designer/Comm/UpdateMetadata.cs | 20 - .../Comm/UpdateXamlMessage.cs | 19 - .../Comm/WindowCreatedMessage.cs | 19 - src/Windows/Perspex.Designer/DemoWindow.xaml | 23 - .../Perspex.Designer/DemoWindow.xaml.cs | 34 - .../InProcDesigner/InProcDesignerView.xaml | 34 - .../InProcDesigner/InProcDesignerView.xaml.cs | 98 - .../Metadata/PerspexDesignerMetadata.cs | 51 - .../Perspex.Designer/Perspex.Designer.csproj | 137 -- .../Perspex.Designer/PerspexDesigner.xaml | 17 - .../Perspex.Designer/PerspexDesigner.xaml.cs | 131 -- src/Windows/Perspex.Designer/Program.cs | 67 - .../Properties/AssemblyInfo.cs | 36 - src/Windows/Perspex.Designer/Settings.cs | 19 - src/Windows/Perspex.Designer/WinApi.cs | 33 - .../Perspex.Direct2D1/Direct2D1Platform.cs | 90 - src/Windows/Perspex.Direct2D1/Disposable.cs | 36 - .../Perspex.Direct2D1/Media/BrushImpl.cs | 20 - .../Perspex.Direct2D1/Media/BrushWrapper.cs | 18 - .../Perspex.Direct2D1/Media/DrawingContext.cs | 328 --- .../Media/FormattedTextImpl.cs | 129 -- .../Perspex.Direct2D1/Media/GeometryImpl.cs | 88 - .../Media/Imaging/BitmapImpl.cs | 131 -- .../Media/Imaging/RenderTargetBitmapImpl.cs | 45 - .../Media/LinearGradientBrushImpl.cs | 50 - .../Media/PerspexTextRenderer.cs | 101 - .../Media/RadialGradientBrushImpl.cs | 56 - .../Media/SolidColorBrushImpl.cs | 23 - .../Media/StreamGeometryContextImpl.cs | 83 - .../Media/StreamGeometryImpl.cs | 66 - .../Perspex.Direct2D1/Media/TileBrushImpl.cs | 78 - .../Perspex.Direct2D1.csproj | 138 -- .../Perspex.Direct2D1/PrimitiveExtensions.cs | 195 -- .../Properties/AssemblyInfo.cs | 6 - src/Windows/Perspex.Direct2D1/RenderTarget.cs | 141 -- src/Windows/Perspex.Win32/ClipboardImpl.cs | 84 - src/Windows/Perspex.Win32/CursorFactory.cs | 70 - .../Embedding/EmbeddedWindowImpl.cs | 31 - src/Windows/Perspex.Win32/Input/KeyInterop.cs | 381 ---- .../Input/WindowsKeyboardDevice.cs | 95 - .../Perspex.Win32/Input/WindowsMouseDevice.cs | 35 - .../Perspex.Win32/Interop/UnmanagedMethods.cs | 1155 ---------- .../Perspex.Win32/Perspex.Win32.csproj | 127 -- .../Perspex.Win32/PlatformConstants.cs | 11 - src/Windows/Perspex.Win32/PopupImpl.cs | 53 - .../Perspex.Win32/Properties/AssemblyInfo.cs | 6 - src/Windows/Perspex.Win32/SystemDialogImpl.cs | 195 -- src/Windows/Perspex.Win32/Win32Platform.cs | 189 -- src/Windows/Perspex.Win32/WindowImpl.cs | 672 ------ src/iOS/Avalonia.iOS/Avalonia.iOS.csproj | 99 + src/iOS/Avalonia.iOS/AvaloniaView.cs | 234 ++ src/iOS/Avalonia.iOS/Clipboard.cs | 26 + src/iOS/Avalonia.iOS/CursorFactory.cs | 11 + src/iOS/Avalonia.iOS/Extensions.cs | 15 + src/iOS/Avalonia.iOS/PlatformSettings.cs | 16 + .../PlatformThreadingInterface.cs | 104 + .../Avalonia.iOS/Properties/AssemblyInfo.cs | 36 + .../Specific/KeyboardEventsHelper.cs | 147 ++ src/iOS/Avalonia.iOS/WindowingPlatformImpl.cs | 33 + src/iOS/Avalonia.iOS/iOSPlatform.cs | 74 + .../AppDelegate.cs | 44 + .../Avalonia.iOSTestApplication.csproj | 197 ++ .../Entitlements.plist | 0 .../GettingStarted.Xamarin | 0 .../Avalonia.iOSTestApplication/Info.plist | 38 + src/iOS/Avalonia.iOSTestApplication/Main.cs | 20 + .../Properties/AssemblyInfo.cs | 36 + .../Resources/Default-568h@2x.png | Bin .../packages.config | 0 src/iOS/Perspex.iOS/Clipboard.cs | 26 - src/iOS/Perspex.iOS/CursorFactory.cs | 11 - src/iOS/Perspex.iOS/Extensions.cs | 15 - src/iOS/Perspex.iOS/Perspex.iOS.csproj | 99 - src/iOS/Perspex.iOS/PerspexView.cs | 234 -- src/iOS/Perspex.iOS/PlatformSettings.cs | 16 - .../Perspex.iOS/PlatformThreadingInterface.cs | 104 - .../Perspex.iOS/Properties/AssemblyInfo.cs | 36 - .../Specific/KeyboardEventsHelper.cs | 147 -- src/iOS/Perspex.iOS/WindowingPlatformImpl.cs | 33 - src/iOS/Perspex.iOS/iOSPlatform.cs | 74 - .../Perspex.iOSTestApplication/AppDelegate.cs | 44 - src/iOS/Perspex.iOSTestApplication/Info.plist | 38 - src/iOS/Perspex.iOSTestApplication/Main.cs | 20 - .../Perspex.iOSTestApplication.csproj | 197 -- .../Properties/AssemblyInfo.cs | 36 - .../AttachedPropertyTests.cs | 25 + .../Avalonia.Base.UnitTests.csproj | 165 ++ .../AvaloniaObjectTests_Binding.cs | 351 +++ .../AvaloniaObjectTests_Direct.cs | 517 +++++ .../AvaloniaObjectTests_GetObservable.cs | 82 + .../AvaloniaObjectTests_GetSubject.cs | 49 + .../AvaloniaObjectTests_GetValue.cs | 83 + .../AvaloniaObjectTests_Inheritance.cs | 101 + .../AvaloniaObjectTests_Metadata.cs | 68 + .../AvaloniaObjectTests_SetValue.cs | 207 ++ .../AvaloniaObjectTests_Validation.cs | 144 ++ .../AvaloniaPropertyRegistryTests.cs | 193 ++ .../AvaloniaPropertyTests.cs | 159 ++ .../Collections/AvaloniaDictionaryTests.cs | 151 ++ .../Collections/AvaloniaListTests.cs | 202 ++ .../Collections/CollectionChangedTracker.cs | 33 + .../Collections/PropertyChangedTracker.cs | 30 + .../DirectPropertyTests.cs | 91 + .../PriorityValueTests.cs | 306 +++ .../Properties/AssemblyInfo.cs | 10 + .../StyledPropertyTests.cs | 44 + .../WeakSubscriptionManagerTests.cs | 70 + .../app.config | 0 .../packages.config | 0 .../App.config | 0 .../Avalonia.Benchmarks.csproj | 126 ++ tests/Avalonia.Benchmarks/Program.cs | 28 + .../Properties/AssemblyInfo.cs | 36 + .../Styling/ApplyStyling.cs | 68 + .../packages.config | 0 .../Avalonia.Controls.UnitTests.csproj | 232 ++ .../BorderTests.cs | 24 + .../CarouselTests.cs | 108 + .../ClassesTests.cs | 153 ++ .../ContentControlTests.cs | 274 +++ .../ControlTests.cs | 268 +++ .../ControlTests_NameScope.cs | 74 + .../DecoratorTests.cs | 123 ++ .../DockPanelTests.cs | 62 + .../DropDownTests.cs | 45 + .../EnumerableExtensions.cs | 20 + .../Generators/ItemContainerGeneratorTests.cs | 97 + .../ItemContainerGeneratorTypedTests.cs | 28 + .../GridLengthTests.cs | 107 + .../GridSplitterTests.cs | 116 + .../Avalonia.Controls.UnitTests/GridTests.cs | 68 + .../HeaderedItemsControlTests .cs | 79 + .../Avalonia.Controls.UnitTests/ImageTests.cs | 65 + .../ItemsControlTests.cs | 462 ++++ .../LayoutTransformControlTests.cs | 245 +++ .../ListBoxTests.cs | 164 ++ .../ListBoxTests_Single.cs | 240 +++ .../Mixins/SelectableMixinTests.cs | 73 + .../NameScopeTests.cs | 55 + .../Avalonia.Controls.UnitTests/PanelTests.cs | 121 ++ .../Presenters/CarouselPresenterTests.cs | 208 ++ .../Presenters/ContentPresenterTests.cs | 160 ++ .../Presenters/ItemsPresenterTests.cs | 339 +++ .../Presenters/ScrollContentPresenterTests.cs | 281 +++ ...ScrollContentPresenterTests_IScrollable.cs | 234 ++ .../Primitives/PopupTests.cs | 286 +++ .../Primitives/RangeBaseTests.cs | 94 + .../Primitives/ScrollBarTests.cs | 142 ++ .../Primitives/SelectingItemsControlTests.cs | 698 ++++++ .../SelectingItemsControlTests_AutoSelect.cs | 104 + .../SelectingItemsControlTests_Multiple.cs | 590 ++++++ .../Primitives/TabStripTests.cs | 170 ++ .../Primitives/TemplatedControlTests.cs | 421 ++++ .../Primitives/TrackTests.cs | 144 ++ .../Properties/AssemblyInfo.cs | 10 + .../ScrollViewerTests.cs | 88 + .../StackPanelTests.cs | 150 ++ .../TabControlTests.cs | 335 +++ .../Templates/TemplateExtensionsTests.cs | 40 + .../TestTemplatedControl.cs | 24 + .../TextBlockTests.cs | 19 + .../TextBoxTests.cs | 19 + .../TopLevelTests.cs | 314 +++ .../TreeViewTests.cs | 438 ++++ .../UserControlTests.cs | 57 + .../Utils/AncestorFinderTests.cs | 41 + .../Utils/HotKeyManagerTests.cs | 72 + .../WindowTests.cs | 43 + .../WindowingPlatformMock.cs | 30 + .../WrapPanelTests.cs | 96 + .../app.config | 0 .../packages.config | 0 .../Avalonia.Direct2D1.UnitTests.csproj | 127 ++ .../Controls/Shapes/PathTests.cs | 72 + .../Media/GeometryTests.cs | 39 + .../Properties/AssemblyInfo.cs | 10 + .../RectComparer.cs | 24 + .../app.config | 0 .../packages.config | 0 .../Avalonia.Input.UnitTests.csproj | 129 ++ .../InputElement_Focus.cs | 49 + .../InputElement_HitTesting.cs | 129 ++ .../KeyGestureParseTests.cs | 28 + .../KeyboardNavigationTests_Arrows.cs | 821 +++++++ .../KeyboardNavigationTests_Tab.cs | 1071 ++++++++++ .../Properties/AssemblyInfo.cs | 10 + .../app.config | 0 .../packages.config | 0 .../Avalonia.Interactivity.UnitTests.csproj | 120 ++ .../GestureTests.cs | 82 + .../InteractiveTests.cs | 409 ++++ .../Properties/AssemblyInfo.cs | 6 + .../packages.config | 0 .../Avalonia.Layout.UnitTests/ArrangeTests.cs | 123 ++ .../Avalonia.Layout.UnitTests.csproj | 194 ++ .../FullLayoutTests.cs | 162 ++ .../LayoutManagerTests.cs | 45 + .../Avalonia.Layout.UnitTests/MeasureTests.cs | 87 + .../Properties/AssemblyInfo.cs | 6 + .../TestLayoutRoot.cs | 24 + .../app.config | 0 .../packages.config | 0 .../Avalonia.LeakTests.csproj | 170 ++ tests/Avalonia.LeakTests/ControlTests.cs | 317 +++ .../Properties/AssemblyInfo.cs | 36 + .../Readme.txt | 0 .../app.config | 0 .../packages.config | 0 .../Avalonia.Markup.UnitTests.csproj | 169 ++ .../ControlLocatorTests.cs | 153 ++ .../Data/ExceptionValidatorTests.cs | 99 + .../Data/ExpressionNodeBuilderTests.cs | 167 ++ .../Data/ExpressionNodeBuilderTests_Errors.cs | 74 + ...xpressionObserverTests_AttachedProperty.cs | 147 ++ ...xpressionObserverTests_AvaloniaProperty.cs | 73 + .../Data/ExpressionObserverTests_Indexer.cs | 249 +++ .../Data/ExpressionObserverTests_Lifetime.cs | 101 + .../Data/ExpressionObserverTests_Negation.cs | 92 + .../ExpressionObserverTests_Observable.cs | 69 + .../Data/ExpressionObserverTests_Property.cs | 418 ++++ .../Data/ExpressionObserverTests_SetValue.cs | 81 + .../Data/ExpressionObserverTests_Task.cs | 88 + .../Data/ExpressionSubjectTests.cs | 197 ++ .../Data/IndeiValidatorTests.cs | 120 ++ .../DefaultValueConverterTests.cs | 142 ++ .../Properties/AssemblyInfo.cs | 36 + .../UnitTestSynchronizationContext.cs | 68 + .../app.config | 0 .../packages.config | 0 .../Avalonia.Markup.Xaml.UnitTests.csproj | 222 ++ .../AvaloniaPropertyConverterTest.cs | 109 + .../Data/BindingTests.cs | 341 +++ .../Data/BindingTests_ElementName.cs | 157 ++ .../Data/BindingTests_Source.cs | 39 + .../Data/BindingTests_TemplatedParent.cs | 70 + .../Data/BindingTests_Validation.cs | 111 + .../Data/MultiBindingTests.cs | 80 + .../Parsers/SelectorGrammarTests.cs | 227 ++ .../Properties/AssemblyInfo.cs | 10 + .../SampleAvaloniaObject.cs | 28 + .../StyleTests.cs | 104 + .../Templates/DataTemplateTests.cs | 32 + .../TestViewModel.cs | 44 + .../TypeProviderMock.cs | 38 + .../Xaml/BasicTests.cs | 54 + .../Xaml/BindingTests.cs | 149 ++ .../Xaml/ControlBindingTests.cs | 71 + .../Xaml/DataTemplateTests.cs | 84 + .../Xaml/InitializationOrderTracker.cs | 26 + .../Xaml/NonControl.cs | 28 + .../Xaml/Style1.xaml | 8 + .../Xaml/Style2.xaml | 9 + .../Xaml/StyleTests.cs | 228 ++ .../Xaml/TreeDataTemplateTests.cs | 29 + .../app.config | 0 .../packages.config | 0 .../Avalonia.Cairo.RenderTests.csproj | 164 ++ .../Avalonia.Direct2D1.RenderTests.csproj | 167 ++ .../Avalonia.Skia.RenderTests.csproj | 143 ++ .../Controls/BorderTests.cs | 433 ++++ .../Controls/ImageTests.cs | 120 ++ .../Media/ImageBrushTests.cs | 372 ++++ .../Media/LinearGradientBrushTests.cs | 89 + .../Media/VisualBrushTests.cs | 429 ++++ .../Properties/AssemblyInfo.cs | 10 + .../Shapes/EllipseTests.cs | 43 + .../Avalonia.RenderTests/Shapes/LineTests.cs | 84 + .../Avalonia.RenderTests/Shapes/PathTests.cs | 161 ++ .../Shapes/PolygonTests.cs | 80 + .../Shapes/PolylineTests.cs | 87 + .../Shapes/RectangleTests.cs | 103 + tests/Avalonia.RenderTests/TestBase.cs | 89 + .../app.config | 0 ...ackages.Avalonia.Cairo.RenderTests.config} | 0 ...ges.Avalonia.Direct2D1.RenderTests.config} | 0 ...packages.Avalonia.Skia.RenderTests.config} | 0 .../Avalonia.SceneGraph.UnitTests.csproj | 171 ++ .../Media/BrushTests.cs | 74 + .../Media/ColorTests.cs | 74 + .../Properties/AssemblyInfo.cs | 10 + .../RelativePointTests.cs | 27 + .../RelativeRectComparer.cs | 25 + .../RelativeRectTests.cs | 29 + .../RenderTests_Culling.cs | 183 ++ .../Avalonia.SceneGraph.UnitTests/TestRoot.cs | 32 + .../TestVisual.cs | 65 + .../ThicknessTests.cs | 43 + .../VisualTests.cs | 102 + .../VisualTree/BoundsTrackerTests.cs | 52 + .../app.config | 0 .../packages.config | 0 .../ActivatedObservableTests.cs | 70 + .../ActivatedSubjectTests.cs | 86 + .../ActivatedValueTests.cs | 61 + .../Avalonia.Styling.UnitTests.csproj | 194 ++ .../Properties/AssemblyInfo.cs | 10 + .../ResourceTests.cs | 78 + .../SelectorTests_Child.cs | 165 ++ .../SelectorTests_Class.cs | 124 ++ .../SelectorTests_Descendent.cs | 196 ++ .../SelectorTests_Multiple.cs | 115 + .../SelectorTests_Name.cs | 59 + .../SelectorTests_OfType.cs | 46 + .../SelectorTests_PropertyEquals.cs | 38 + .../SelectorTests_Template.cs | 157 ++ .../Avalonia.Styling.UnitTests/SetterTests.cs | 29 + .../StyleActivatorTests.cs | 169 ++ .../Avalonia.Styling.UnitTests/StyleTests.cs | 187 ++ .../TestControlBase.cs | 75 + .../TestObservable.cs | 20 + .../TestObserver.cs | 62 + .../TestSelectors.cs | 20 + .../Avalonia.Styling.UnitTests/TestSubject.cs | 54 + .../TestTemplatedControl.cs | 75 + .../app.config | 0 .../packages.config | 0 .../Avalonia.UnitTests.csproj | 133 ++ .../MockWindowingPlatform.cs | 30 + tests/Avalonia.UnitTests/NotifyingBase.cs | 43 + .../Properties/AssemblyInfo.cs | 36 + tests/Avalonia.UnitTests/TestLogSink.cs | 38 + tests/Avalonia.UnitTests/TestRoot.cs | 65 + tests/Avalonia.UnitTests/TestServices.cs | 151 ++ tests/Avalonia.UnitTests/TestTemplatedRoot.cs | 67 + .../Avalonia.UnitTests/UnitTestApplication.cs | 57 + .../app.config | 0 .../packages.config | 0 .../AttachedPropertyTests.cs | 25 - .../Collections/CollectionChangedTracker.cs | 33 - .../Collections/PerspexDictionaryTests.cs | 151 -- .../Collections/PerspexListTests.cs | 202 -- .../Collections/PropertyChangedTracker.cs | 30 - .../DirectPropertyTests.cs | 91 - .../Perspex.Base.UnitTests.csproj | 165 -- .../PerspexObjectTests_Binding.cs | 351 --- .../PerspexObjectTests_Direct.cs | 517 ----- .../PerspexObjectTests_GetObservable.cs | 82 - .../PerspexObjectTests_GetSubject.cs | 49 - .../PerspexObjectTests_GetValue.cs | 83 - .../PerspexObjectTests_Inheritance.cs | 101 - .../PerspexObjectTests_Metadata.cs | 68 - .../PerspexObjectTests_SetValue.cs | 207 -- .../PerspexObjectTests_Validation.cs | 144 -- .../PerspexPropertyRegistryTests.cs | 193 -- .../PerspexPropertyTests.cs | 159 -- .../PriorityValueTests.cs | 306 --- .../Properties/AssemblyInfo.cs | 10 - .../StyledPropertyTests.cs | 44 - .../WeakSubscriptionManagerTests.cs | 70 - .../Perspex.Benchmarks.csproj | 126 -- tests/Perspex.Benchmarks/Program.cs | 28 - .../Properties/AssemblyInfo.cs | 36 - .../Styling/ApplyStyling.cs | 68 - .../Perspex.Controls.UnitTests/BorderTests.cs | 24 - .../CarouselTests.cs | 108 - .../ClassesTests.cs | 153 -- .../ContentControlTests.cs | 274 --- .../ControlTests.cs | 268 --- .../ControlTests_NameScope.cs | 74 - .../DecoratorTests.cs | 123 -- .../DockPanelTests.cs | 62 - .../DropDownTests.cs | 45 - .../EnumerableExtensions.cs | 20 - .../Generators/ItemContainerGeneratorTests.cs | 97 - .../ItemContainerGeneratorTypedTests.cs | 28 - .../GridLengthTests.cs | 107 - .../GridSplitterTests.cs | 116 - tests/Perspex.Controls.UnitTests/GridTests.cs | 68 - .../HeaderedItemsControlTests .cs | 79 - .../Perspex.Controls.UnitTests/ImageTests.cs | 65 - .../ItemsControlTests.cs | 462 ---- .../LayoutTransformControlTests.cs | 245 --- .../ListBoxTests.cs | 164 -- .../ListBoxTests_Single.cs | 240 --- .../Mixins/SelectableMixinTests.cs | 73 - .../NameScopeTests.cs | 55 - .../Perspex.Controls.UnitTests/PanelTests.cs | 121 -- .../Perspex.Controls.UnitTests.csproj | 232 -- .../Presenters/CarouselPresenterTests.cs | 208 -- .../Presenters/ContentPresenterTests.cs | 160 -- .../Presenters/ItemsPresenterTests.cs | 339 --- .../Presenters/ScrollContentPresenterTests.cs | 281 --- ...ScrollContentPresenterTests_IScrollable.cs | 234 -- .../Primitives/PopupTests.cs | 286 --- .../Primitives/RangeBaseTests.cs | 94 - .../Primitives/ScrollBarTests.cs | 142 -- .../Primitives/SelectingItemsControlTests.cs | 698 ------ .../SelectingItemsControlTests_AutoSelect.cs | 104 - .../SelectingItemsControlTests_Multiple.cs | 590 ------ .../Primitives/TabStripTests.cs | 170 -- .../Primitives/TemplatedControlTests.cs | 421 ---- .../Primitives/TrackTests.cs | 144 -- .../Properties/AssemblyInfo.cs | 10 - .../ScrollViewerTests.cs | 88 - .../StackPanelTests.cs | 150 -- .../TabControlTests.cs | 335 --- .../Templates/TemplateExtensionsTests.cs | 40 - .../TestTemplatedControl.cs | 24 - .../TextBlockTests.cs | 19 - .../TextBoxTests.cs | 19 - .../TopLevelTests.cs | 314 --- .../TreeViewTests.cs | 438 ---- .../UserControlTests.cs | 57 - .../Utils/AncestorFinderTests.cs | 41 - .../Utils/HotKeyManagerTests.cs | 72 - .../Perspex.Controls.UnitTests/WindowTests.cs | 43 - .../WindowingPlatformMock.cs | 30 - .../WrapPanelTests.cs | 96 - .../Controls/Shapes/PathTests.cs | 72 - .../Media/GeometryTests.cs | 39 - .../Perspex.Direct2D1.UnitTests.csproj | 127 -- .../Properties/AssemblyInfo.cs | 10 - .../RectComparer.cs | 24 - .../InputElement_Focus.cs | 49 - .../InputElement_HitTesting.cs | 129 -- .../KeyGestureParseTests.cs | 28 - .../KeyboardNavigationTests_Arrows.cs | 821 ------- .../KeyboardNavigationTests_Tab.cs | 1071 ---------- .../Perspex.Input.UnitTests.csproj | 129 -- .../Properties/AssemblyInfo.cs | 10 - .../GestureTests.cs | 82 - .../InteractiveTests.cs | 409 ---- .../Perspex.Interactivity.UnitTests.csproj | 120 -- .../Properties/AssemblyInfo.cs | 6 - .../Perspex.Layout.UnitTests/ArrangeTests.cs | 123 -- .../FullLayoutTests.cs | 162 -- .../LayoutManagerTests.cs | 45 - .../Perspex.Layout.UnitTests/MeasureTests.cs | 87 - .../Perspex.Layout.UnitTests.csproj | 194 -- .../Properties/AssemblyInfo.cs | 6 - .../TestLayoutRoot.cs | 24 - tests/Perspex.LeakTests/ControlTests.cs | 317 --- .../Perspex.LeakTests.csproj | 170 -- .../Properties/AssemblyInfo.cs | 36 - .../ControlLocatorTests.cs | 153 -- .../Data/ExceptionValidatorTests.cs | 99 - .../Data/ExpressionNodeBuilderTests.cs | 167 -- .../Data/ExpressionNodeBuilderTests_Errors.cs | 74 - ...xpressionObserverTests_AttachedProperty.cs | 147 -- .../Data/ExpressionObserverTests_Indexer.cs | 249 --- .../Data/ExpressionObserverTests_Lifetime.cs | 101 - .../Data/ExpressionObserverTests_Negation.cs | 92 - .../ExpressionObserverTests_Observable.cs | 69 - ...ExpressionObserverTests_PerspexProperty.cs | 73 - .../Data/ExpressionObserverTests_Property.cs | 418 ---- .../Data/ExpressionObserverTests_SetValue.cs | 81 - .../Data/ExpressionObserverTests_Task.cs | 88 - .../Data/ExpressionSubjectTests.cs | 197 -- .../Data/IndeiValidatorTests.cs | 120 -- .../DefaultValueConverterTests.cs | 142 -- .../Perspex.Markup.UnitTests.csproj | 169 -- .../Properties/AssemblyInfo.cs | 36 - .../UnitTestSynchronizationContext.cs | 68 - .../PerspexPropertyConverterTest.cs | 109 - .../Data/BindingTests.cs | 341 --- .../Data/BindingTests_ElementName.cs | 157 -- .../Data/BindingTests_Source.cs | 39 - .../Data/BindingTests_TemplatedParent.cs | 70 - .../Data/BindingTests_Validation.cs | 111 - .../Data/MultiBindingTests.cs | 80 - .../Parsers/SelectorGrammarTests.cs | 227 -- .../Perspex.Markup.Xaml.UnitTests.csproj | 222 -- .../Properties/AssemblyInfo.cs | 10 - .../SamplePerspexObject.cs | 28 - .../StyleTests.cs | 104 - .../Templates/DataTemplateTests.cs | 32 - .../TestViewModel.cs | 44 - .../TypeProviderMock.cs | 38 - .../Xaml/BasicTests.cs | 54 - .../Xaml/BindingTests.cs | 149 -- .../Xaml/ControlBindingTests.cs | 71 - .../Xaml/DataTemplateTests.cs | 84 - .../Xaml/InitializationOrderTracker.cs | 26 - .../Xaml/NonControl.cs | 28 - .../Xaml/Style1.xaml | 8 - .../Xaml/Style2.xaml | 9 - .../Xaml/StyleTests.cs | 228 -- .../Xaml/TreeDataTemplateTests.cs | 29 - .../Controls/BorderTests.cs | Bin 25732 -> 0 bytes .../Controls/ImageTests.cs | Bin 6586 -> 0 bytes .../Media/ImageBrushTests.cs | 372 ---- .../Media/LinearGradientBrushTests.cs | 89 - .../Media/VisualBrushTests.cs | 429 ---- .../Perspex.Cairo.RenderTests.csproj | 164 -- .../Perspex.Direct2D1.RenderTests.csproj | 167 -- .../Perspex.Skia.RenderTests.csproj | 143 -- .../Properties/AssemblyInfo.cs | Bin 742 -> 0 bytes .../Shapes/EllipseTests.cs | Bin 2186 -> 0 bytes tests/Perspex.RenderTests/Shapes/LineTests.cs | 84 - tests/Perspex.RenderTests/Shapes/PathTests.cs | 161 -- .../Shapes/PolygonTests.cs | 80 - .../Shapes/PolylineTests.cs | 87 - .../Shapes/RectangleTests.cs | Bin 5474 -> 0 bytes tests/Perspex.RenderTests/TestBase.cs | Bin 5286 -> 0 bytes .../Media/BrushTests.cs | 74 - .../Media/ColorTests.cs | 74 - .../Perspex.SceneGraph.UnitTests.csproj | 171 -- .../Properties/AssemblyInfo.cs | 10 - .../RelativePointTests.cs | 27 - .../RelativeRectComparer.cs | 25 - .../RelativeRectTests.cs | 29 - .../RenderTests_Culling.cs | 183 -- .../Perspex.SceneGraph.UnitTests/TestRoot.cs | 32 - .../TestVisual.cs | 65 - .../ThicknessTests.cs | 43 - .../VisualTests.cs | 102 - .../VisualTree/BoundsTrackerTests.cs | 52 - .../ActivatedObservableTests.cs | 70 - .../ActivatedSubjectTests.cs | 86 - .../ActivatedValueTests.cs | 61 - .../Perspex.Styling.UnitTests.csproj | 194 -- .../Properties/AssemblyInfo.cs | 10 - .../ResourceTests.cs | 78 - .../SelectorTests_Child.cs | 165 -- .../SelectorTests_Class.cs | 124 -- .../SelectorTests_Descendent.cs | 196 -- .../SelectorTests_Multiple.cs | 115 - .../SelectorTests_Name.cs | 59 - .../SelectorTests_OfType.cs | 46 - .../SelectorTests_PropertyEquals.cs | 38 - .../SelectorTests_Template.cs | 157 -- .../Perspex.Styling.UnitTests/SetterTests.cs | 29 - .../StyleActivatorTests.cs | 169 -- tests/Perspex.Styling.UnitTests/StyleTests.cs | 187 -- .../TestControlBase.cs | 75 - .../TestObservable.cs | 20 - .../Perspex.Styling.UnitTests/TestObserver.cs | 62 - .../TestSelectors.cs | 20 - .../Perspex.Styling.UnitTests/TestSubject.cs | 54 - .../TestTemplatedControl.cs | 75 - .../MockWindowingPlatform.cs | 30 - tests/Perspex.UnitTests/NotifyingBase.cs | 43 - .../Perspex.UnitTests.csproj | 133 -- .../Properties/AssemblyInfo.cs | 36 - tests/Perspex.UnitTests/TestLogSink.cs | 38 - tests/Perspex.UnitTests/TestRoot.cs | 65 - tests/Perspex.UnitTests/TestServices.cs | 151 -- tests/Perspex.UnitTests/TestTemplatedRoot.cs | 67 - .../Perspex.UnitTests/UnitTestApplication.cs | 57 - 2213 files changed, 102561 insertions(+), 101763 deletions(-) create mode 100644 Avalonia.sln rename Perspex.sln.DotSettings => Avalonia.sln.DotSettings (100%) rename Perspex.v2.ncrunchsolution => Avalonia.v2.ncrunchsolution (100%) delete mode 100644 Perspex.sln rename docs/images/{perspex-video.png => avalonia-video.png} (100%) create mode 100644 nuget/template/Avalonia.Android.nuspec create mode 100644 nuget/template/Avalonia.Desktop.nuspec create mode 100644 nuget/template/Avalonia.Skia.Desktop.nuspec create mode 100644 nuget/template/Avalonia.iOS.nuspec create mode 100644 nuget/template/Avalonia.nuspec delete mode 100644 nuget/template/Perspex.Android.nuspec delete mode 100644 nuget/template/Perspex.Desktop.nuspec delete mode 100644 nuget/template/Perspex.Skia.Desktop.nuspec delete mode 100644 nuget/template/Perspex.iOS.nuspec delete mode 100644 nuget/template/Perspex.nuspec create mode 100644 src/Android/Avalonia.Android/AndroidPlatform.cs create mode 100644 src/Android/Avalonia.Android/AndroidThreadingInterface.cs create mode 100644 src/Android/Avalonia.Android/Avalonia.Android.csproj create mode 100644 src/Android/Avalonia.Android/CursorFactory.cs create mode 100644 src/Android/Avalonia.Android/Platform/AndroidTopLevelRenderer.cs create mode 100644 src/Android/Avalonia.Android/Platform/ClipboardImpl.cs create mode 100644 src/Android/Avalonia.Android/Platform/Input/AndroidKeyboardDevice.cs create mode 100644 src/Android/Avalonia.Android/Platform/Input/AndroidMouseDevice.cs create mode 100644 src/Android/Avalonia.Android/Platform/SkiaPlatform/MainWindowImpl.cs create mode 100644 src/Android/Avalonia.Android/Platform/SkiaPlatform/WindowImpl.cs create mode 100644 src/Android/Avalonia.Android/Platform/Specific/AvaloniaActivity.cs create mode 100644 src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs create mode 100644 src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs create mode 100644 src/Android/Avalonia.Android/Platform/Specific/IAndroidActivity.cs create mode 100644 src/Android/Avalonia.Android/Platform/Specific/IAndroidView.cs create mode 100644 src/Android/Avalonia.Android/Properties/AssemblyInfo.cs rename src/Android/{Perspex.Android => Avalonia.Android}/Resources/AboutResources.txt (100%) create mode 100644 src/Android/Avalonia.Android/Resources/Resource.Designer.cs rename src/Android/{Perspex.Android => Avalonia.Android}/Resources/Values/Strings.xml (100%) create mode 100644 src/Android/Avalonia.Android/SystemDialogImpl.cs rename src/Android/{Perspex.Android => Avalonia.Android}/packages.config (100%) rename src/Android/{Perspex.AndroidTestApplication => Avalonia.AndroidTestApplication}/Assets/AboutAssets.txt (100%) create mode 100644 src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj create mode 100644 src/Android/Avalonia.AndroidTestApplication/MainActivity.cs create mode 100644 src/Android/Avalonia.AndroidTestApplication/Properties/AndroidManifest.xml create mode 100644 src/Android/Avalonia.AndroidTestApplication/Properties/AssemblyInfo.cs rename src/Android/{Perspex.AndroidTestApplication => Avalonia.AndroidTestApplication}/Resources/AboutResources.txt (100%) create mode 100644 src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs rename src/Android/{Perspex.AndroidTestApplication => Avalonia.AndroidTestApplication}/Resources/drawable/Icon.png (100%) create mode 100644 src/Android/Avalonia.AndroidTestApplication/Resources/values/Strings.xml rename src/Android/{Perspex.AndroidTestApplication => Avalonia.AndroidTestApplication}/packages.config (100%) delete mode 100644 src/Android/Perspex.Android/AndroidPlatform.cs delete mode 100644 src/Android/Perspex.Android/AndroidThreadingInterface.cs delete mode 100644 src/Android/Perspex.Android/CursorFactory.cs delete mode 100644 src/Android/Perspex.Android/Perspex.Android.csproj delete mode 100644 src/Android/Perspex.Android/Platform/AndroidTopLevelRenderer.cs delete mode 100644 src/Android/Perspex.Android/Platform/ClipboardImpl.cs delete mode 100644 src/Android/Perspex.Android/Platform/Input/AndroidKeyboardDevice.cs delete mode 100644 src/Android/Perspex.Android/Platform/Input/AndroidMouseDevice.cs delete mode 100644 src/Android/Perspex.Android/Platform/SkiaPlatform/MainWindowImpl.cs delete mode 100644 src/Android/Perspex.Android/Platform/SkiaPlatform/WindowImpl.cs delete mode 100644 src/Android/Perspex.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs delete mode 100644 src/Android/Perspex.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs delete mode 100644 src/Android/Perspex.Android/Platform/Specific/IAndroidActivity.cs delete mode 100644 src/Android/Perspex.Android/Platform/Specific/IAndroidView.cs delete mode 100644 src/Android/Perspex.Android/Platform/Specific/PerspexActivity.cs delete mode 100644 src/Android/Perspex.Android/Properties/AssemblyInfo.cs delete mode 100644 src/Android/Perspex.Android/Resources/Resource.Designer.cs delete mode 100644 src/Android/Perspex.Android/SystemDialogImpl.cs delete mode 100644 src/Android/Perspex.AndroidTestApplication/MainActivity.cs delete mode 100644 src/Android/Perspex.AndroidTestApplication/Perspex.AndroidTestApplication.csproj delete mode 100644 src/Android/Perspex.AndroidTestApplication/Properties/AndroidManifest.xml delete mode 100644 src/Android/Perspex.AndroidTestApplication/Properties/AssemblyInfo.cs delete mode 100644 src/Android/Perspex.AndroidTestApplication/Resources/Resource.Designer.cs delete mode 100644 src/Android/Perspex.AndroidTestApplication/Resources/values/Strings.xml create mode 100644 src/Avalonia.Animation/Animatable.cs create mode 100644 src/Avalonia.Animation/Animate.cs create mode 100644 src/Avalonia.Animation/Animation.cs create mode 100644 src/Avalonia.Animation/AnimationExtensions.cs create mode 100644 src/Avalonia.Animation/Animation`1.cs create mode 100644 src/Avalonia.Animation/Avalonia.Animation.csproj create mode 100644 src/Avalonia.Animation/IEasing.cs create mode 100644 src/Avalonia.Animation/IEasing`1.cs create mode 100644 src/Avalonia.Animation/LinearDoubleEasing.cs create mode 100644 src/Avalonia.Animation/LinearEasing.cs create mode 100644 src/Avalonia.Animation/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.Animation/PropertyTransition.cs create mode 100644 src/Avalonia.Animation/PropertyTransitions.cs rename src/{Perspex.Animation => Avalonia.Animation}/packages.config (100%) create mode 100644 src/Avalonia.Base/AttachedProperty.cs create mode 100644 src/Avalonia.Base/Avalonia.Base.csproj create mode 100644 src/Avalonia.Base/AvaloniaDisposable.cs create mode 100644 src/Avalonia.Base/AvaloniaInternalException.cs create mode 100644 src/Avalonia.Base/AvaloniaLocator.cs create mode 100644 src/Avalonia.Base/AvaloniaObject.cs create mode 100644 src/Avalonia.Base/AvaloniaObjectExtensions.cs create mode 100644 src/Avalonia.Base/AvaloniaProperty.cs create mode 100644 src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs create mode 100644 src/Avalonia.Base/AvaloniaPropertyRegistry.cs create mode 100644 src/Avalonia.Base/AvaloniaProperty`1.cs create mode 100644 src/Avalonia.Base/Collections/AvaloniaDictionary.cs create mode 100644 src/Avalonia.Base/Collections/AvaloniaList.cs create mode 100644 src/Avalonia.Base/Collections/AvaloniaListExtensions.cs create mode 100644 src/Avalonia.Base/Collections/IAvaloniaList.cs create mode 100644 src/Avalonia.Base/Collections/IAvaloniaReadOnlyList.cs create mode 100644 src/Avalonia.Base/Contract.cs create mode 100644 src/Avalonia.Base/Data/AssignBindingAttribute.cs create mode 100644 src/Avalonia.Base/Data/BindingError.cs create mode 100644 src/Avalonia.Base/Data/BindingMode.cs create mode 100644 src/Avalonia.Base/Data/BindingOperations.cs create mode 100644 src/Avalonia.Base/Data/BindingPriority.cs create mode 100644 src/Avalonia.Base/Data/IBinding.cs create mode 100644 src/Avalonia.Base/Data/IndexerDescriptor.cs create mode 100644 src/Avalonia.Base/Data/InstancedBinding.cs create mode 100644 src/Avalonia.Base/Data/ValidationMethods.cs create mode 100644 src/Avalonia.Base/Data/ValidationStatus.cs create mode 100644 src/Avalonia.Base/Diagnostics/AvaloniaObjectExtensions.cs create mode 100644 src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs create mode 100644 src/Avalonia.Base/Diagnostics/IAvaloniaObjectDebug.cs create mode 100644 src/Avalonia.Base/Diagnostics/INotifyCollectionChangedDebug.cs create mode 100644 src/Avalonia.Base/DirectProperty.cs create mode 100644 src/Avalonia.Base/DirectPropertyMetadata`1.cs create mode 100644 src/Avalonia.Base/IAvaloniaObject.cs create mode 100644 src/Avalonia.Base/IDescription.cs create mode 100644 src/Avalonia.Base/IDirectPropertyAccessor.cs create mode 100644 src/Avalonia.Base/IDirectPropertyMetadata.cs create mode 100644 src/Avalonia.Base/IPriorityValueOwner.cs create mode 100644 src/Avalonia.Base/IStyledPropertyAccessor.cs create mode 100644 src/Avalonia.Base/IStyledPropertyMetadata.cs create mode 100644 src/Avalonia.Base/ISupportInitialize.cs create mode 100644 src/Avalonia.Base/Logging/ILogSink.cs create mode 100644 src/Avalonia.Base/Logging/LogArea.cs create mode 100644 src/Avalonia.Base/Logging/LogEventLevel.cs create mode 100644 src/Avalonia.Base/Logging/Logger.cs create mode 100644 src/Avalonia.Base/Metadata/ContentAttribute.cs create mode 100644 src/Avalonia.Base/Metadata/DependsOnAttribute.cs create mode 100644 src/Avalonia.Base/Metadata/XmlnsDefinitionAttribute.cs create mode 100644 src/Avalonia.Base/Platform/IAssetLoader.cs create mode 100644 src/Avalonia.Base/Platform/IPclPlatformWrapper.cs create mode 100644 src/Avalonia.Base/Platform/IPlatformHandle.cs create mode 100644 src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs create mode 100644 src/Avalonia.Base/Platform/PlatformHandle.cs create mode 100644 src/Avalonia.Base/PriorityBindingEntry.cs create mode 100644 src/Avalonia.Base/PriorityLevel.cs create mode 100644 src/Avalonia.Base/PriorityValue.cs create mode 100644 src/Avalonia.Base/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.Base/PropertyMetadata.cs create mode 100644 src/Avalonia.Base/Reactive/AnonymousSubject`1.cs create mode 100644 src/Avalonia.Base/Reactive/AnonymousSubject`2.cs create mode 100644 src/Avalonia.Base/Reactive/AvaloniaObservable.cs create mode 100644 src/Avalonia.Base/Reactive/ObservableEx.cs create mode 100644 src/Avalonia.Base/Reactive/WeakPropertyChangedObservable.cs rename src/{Perspex.Base => Avalonia.Base}/Settings.StyleCop (100%) create mode 100644 src/Avalonia.Base/StyledProperty.cs create mode 100644 src/Avalonia.Base/StyledPropertyBase.cs create mode 100644 src/Avalonia.Base/StyledPropertyMetadata`1.cs create mode 100644 src/Avalonia.Base/Threading/AvaloniaScheduler.cs create mode 100644 src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs create mode 100644 src/Avalonia.Base/Threading/Dispatcher.cs create mode 100644 src/Avalonia.Base/Threading/DispatcherPriority.cs create mode 100644 src/Avalonia.Base/Threading/DispatcherTimer.cs create mode 100644 src/Avalonia.Base/Threading/JobRunner.cs create mode 100644 src/Avalonia.Base/Threading/SingleThreadDispatcher.cs create mode 100644 src/Avalonia.Base/Utilities/IWeakSubscriber.cs create mode 100644 src/Avalonia.Base/Utilities/MathUtilities.cs create mode 100644 src/Avalonia.Base/Utilities/TypeUtilities.cs create mode 100644 src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs create mode 100644 src/Avalonia.Base/Utilities/WeakTimer.cs rename src/{Perspex.Base => Avalonia.Base}/app.config (100%) rename src/{Perspex.Base => Avalonia.Base}/packages.config (100%) create mode 100644 src/Avalonia.Controls/Application.cs create mode 100644 src/Avalonia.Controls/Avalonia.Controls.csproj create mode 100644 src/Avalonia.Controls/Border.cs create mode 100644 src/Avalonia.Controls/Button.cs create mode 100644 src/Avalonia.Controls/Canvas.cs create mode 100644 src/Avalonia.Controls/Carousel.cs create mode 100644 src/Avalonia.Controls/CheckBox.cs create mode 100644 src/Avalonia.Controls/Classes.cs create mode 100644 src/Avalonia.Controls/ColumnDefinition.cs create mode 100644 src/Avalonia.Controls/ColumnDefinitions.cs create mode 100644 src/Avalonia.Controls/ContentControl.cs create mode 100644 src/Avalonia.Controls/ContextMenu.cs create mode 100644 src/Avalonia.Controls/Control.cs create mode 100644 src/Avalonia.Controls/ControlExtensions.cs create mode 100644 src/Avalonia.Controls/ControlValidationStatus.cs create mode 100644 src/Avalonia.Controls/Controls.cs create mode 100644 src/Avalonia.Controls/Decorator.cs create mode 100644 src/Avalonia.Controls/DefinitionBase.cs create mode 100644 src/Avalonia.Controls/Design.cs create mode 100644 src/Avalonia.Controls/DockPanel.cs create mode 100644 src/Avalonia.Controls/DropDown.cs create mode 100644 src/Avalonia.Controls/DropDownItem.cs create mode 100644 src/Avalonia.Controls/Expander.cs create mode 100644 src/Avalonia.Controls/Generators/IItemContainerGenerator.cs create mode 100644 src/Avalonia.Controls/Generators/ITreeItemContainerGenerator.cs create mode 100644 src/Avalonia.Controls/Generators/ItemContainer.cs create mode 100644 src/Avalonia.Controls/Generators/ItemContainerEventArgs.cs create mode 100644 src/Avalonia.Controls/Generators/ItemContainerGenerator.cs create mode 100644 src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs create mode 100644 src/Avalonia.Controls/Generators/TreeContainerIndex.cs create mode 100644 src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs create mode 100644 src/Avalonia.Controls/Grid.cs create mode 100644 src/Avalonia.Controls/GridLength.cs create mode 100644 src/Avalonia.Controls/GridSplitter.cs create mode 100644 src/Avalonia.Controls/HotkeyManager.cs create mode 100644 src/Avalonia.Controls/IApplicationLifecycle.cs create mode 100644 src/Avalonia.Controls/IContentControl.cs create mode 100644 src/Avalonia.Controls/IControl.cs create mode 100644 src/Avalonia.Controls/IGlobalDataTemplates.cs create mode 100644 src/Avalonia.Controls/IHeadered.cs create mode 100644 src/Avalonia.Controls/INameScope.cs create mode 100644 src/Avalonia.Controls/IPanel.cs create mode 100644 src/Avalonia.Controls/IPseudoClasses.cs create mode 100644 src/Avalonia.Controls/ISelectable.cs create mode 100644 src/Avalonia.Controls/ISetLogicalParent.cs create mode 100644 src/Avalonia.Controls/Image.cs create mode 100644 src/Avalonia.Controls/ItemsControl.cs create mode 100644 src/Avalonia.Controls/LayoutTransformControl.cs create mode 100644 src/Avalonia.Controls/ListBox.cs create mode 100644 src/Avalonia.Controls/ListBoxItem.cs create mode 100644 src/Avalonia.Controls/Menu.cs create mode 100644 src/Avalonia.Controls/MenuItem.cs create mode 100644 src/Avalonia.Controls/MenuItemAccessKeyHandler.cs create mode 100644 src/Avalonia.Controls/Mixins/ContentControlMixin.cs create mode 100644 src/Avalonia.Controls/Mixins/SelectableMixin.cs create mode 100644 src/Avalonia.Controls/NameScope.cs create mode 100644 src/Avalonia.Controls/NameScopeEventArgs.cs create mode 100644 src/Avalonia.Controls/NameScopeExtensions.cs create mode 100644 src/Avalonia.Controls/Panel.cs create mode 100644 src/Avalonia.Controls/PlacementMode.cs create mode 100644 src/Avalonia.Controls/Platform/IPopupImpl.cs create mode 100644 src/Avalonia.Controls/Platform/ISystemDialogImpl.cs create mode 100644 src/Avalonia.Controls/Platform/ITopLevelImpl.cs create mode 100644 src/Avalonia.Controls/Platform/ITopLevelRenderer.cs create mode 100644 src/Avalonia.Controls/Platform/IWindowImpl.cs create mode 100644 src/Avalonia.Controls/Platform/IWindowingPlatform.cs create mode 100644 src/Avalonia.Controls/Platform/PlatformManager.cs create mode 100644 src/Avalonia.Controls/Presenters/CarouselPresenter.cs create mode 100644 src/Avalonia.Controls/Presenters/ContentPresenter.cs create mode 100644 src/Avalonia.Controls/Presenters/IContentPresenter.cs create mode 100644 src/Avalonia.Controls/Presenters/IContentPresenterHost.cs create mode 100644 src/Avalonia.Controls/Presenters/IItemsPresenter.cs create mode 100644 src/Avalonia.Controls/Presenters/IItemsPresenterHost.cs create mode 100644 src/Avalonia.Controls/Presenters/IPresenter.cs create mode 100644 src/Avalonia.Controls/Presenters/ItemsPresenter.cs create mode 100644 src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs create mode 100644 src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs create mode 100644 src/Avalonia.Controls/Presenters/TextPresenter.cs create mode 100644 src/Avalonia.Controls/Primitives/AccessText.cs create mode 100644 src/Avalonia.Controls/Primitives/AdornerDecorator.cs create mode 100644 src/Avalonia.Controls/Primitives/AdornerLayer.cs create mode 100644 src/Avalonia.Controls/Primitives/HeaderedContentControl.cs create mode 100644 src/Avalonia.Controls/Primitives/HeaderedItemsControl.cs create mode 100644 src/Avalonia.Controls/Primitives/HeaderedSelectingControl.cs create mode 100644 src/Avalonia.Controls/Primitives/IScrollable.cs create mode 100644 src/Avalonia.Controls/Primitives/Popup.cs create mode 100644 src/Avalonia.Controls/Primitives/PopupRoot.cs create mode 100644 src/Avalonia.Controls/Primitives/RangeBase.cs create mode 100644 src/Avalonia.Controls/Primitives/ScrollBar.cs create mode 100644 src/Avalonia.Controls/Primitives/ScrollBarVisibility.cs create mode 100644 src/Avalonia.Controls/Primitives/SelectingItemsControl.cs create mode 100644 src/Avalonia.Controls/Primitives/TabStrip.cs create mode 100644 src/Avalonia.Controls/Primitives/TabStripItem.cs create mode 100644 src/Avalonia.Controls/Primitives/TemplateAppliedEventArgs.cs create mode 100644 src/Avalonia.Controls/Primitives/TemplatedControl.cs create mode 100644 src/Avalonia.Controls/Primitives/Thumb.cs create mode 100644 src/Avalonia.Controls/Primitives/ToggleButton.cs create mode 100644 src/Avalonia.Controls/Primitives/Track.cs create mode 100644 src/Avalonia.Controls/ProgressBar.cs create mode 100644 src/Avalonia.Controls/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.Controls/RadioButton.cs create mode 100644 src/Avalonia.Controls/RequestBringIntoViewEventArgs.cs create mode 100644 src/Avalonia.Controls/RowDefinition.cs create mode 100644 src/Avalonia.Controls/RowDefinitions.cs create mode 100644 src/Avalonia.Controls/ScrollViewer.cs create mode 100644 src/Avalonia.Controls/SelectionChangedEventArgs.cs create mode 100644 src/Avalonia.Controls/SelectionMode.cs create mode 100644 src/Avalonia.Controls/Separator.cs create mode 100644 src/Avalonia.Controls/Shapes/Ellipse.cs create mode 100644 src/Avalonia.Controls/Shapes/Line.cs create mode 100644 src/Avalonia.Controls/Shapes/Path.cs create mode 100644 src/Avalonia.Controls/Shapes/Polygon.cs create mode 100644 src/Avalonia.Controls/Shapes/Polyline.cs create mode 100644 src/Avalonia.Controls/Shapes/Rectangle.cs create mode 100644 src/Avalonia.Controls/Shapes/Shape.cs create mode 100644 src/Avalonia.Controls/Slider.cs create mode 100644 src/Avalonia.Controls/StackPanel.cs create mode 100644 src/Avalonia.Controls/SystemDialog.cs create mode 100644 src/Avalonia.Controls/TabControl.cs create mode 100644 src/Avalonia.Controls/TabItem.cs create mode 100644 src/Avalonia.Controls/Templates/DataTemplateExtensions.cs create mode 100644 src/Avalonia.Controls/Templates/DataTemplates.cs create mode 100644 src/Avalonia.Controls/Templates/FuncControlTemplate.cs create mode 100644 src/Avalonia.Controls/Templates/FuncControlTemplate`2.cs create mode 100644 src/Avalonia.Controls/Templates/FuncDataTemplate.cs create mode 100644 src/Avalonia.Controls/Templates/FuncDataTemplate`1.cs create mode 100644 src/Avalonia.Controls/Templates/FuncMemberSelector.cs create mode 100644 src/Avalonia.Controls/Templates/FuncTemplate`1.cs create mode 100644 src/Avalonia.Controls/Templates/FuncTemplate`2.cs create mode 100644 src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs create mode 100644 src/Avalonia.Controls/Templates/FuncTreeDataTemplate`1.cs create mode 100644 src/Avalonia.Controls/Templates/IControlTemplate.cs create mode 100644 src/Avalonia.Controls/Templates/IDataTemplate.cs create mode 100644 src/Avalonia.Controls/Templates/IMemberSelector.cs create mode 100644 src/Avalonia.Controls/Templates/ITemplate`1.cs create mode 100644 src/Avalonia.Controls/Templates/ITemplate`2.cs create mode 100644 src/Avalonia.Controls/Templates/ITreeDataTemplate.cs create mode 100644 src/Avalonia.Controls/Templates/TemplateExtensions.cs create mode 100644 src/Avalonia.Controls/TextBlock.cs create mode 100644 src/Avalonia.Controls/TextBox.cs create mode 100644 src/Avalonia.Controls/TextWrapping.cs create mode 100644 src/Avalonia.Controls/ToolTip.cs create mode 100644 src/Avalonia.Controls/TopLevel.cs create mode 100644 src/Avalonia.Controls/TreeView.cs create mode 100644 src/Avalonia.Controls/TreeViewItem.cs create mode 100644 src/Avalonia.Controls/UserControl.cs create mode 100644 src/Avalonia.Controls/Utils/AncestorFinder.cs create mode 100644 src/Avalonia.Controls/Utils/IEnumerableUtils.cs create mode 100644 src/Avalonia.Controls/Utils/StringUtils.cs create mode 100644 src/Avalonia.Controls/Utils/UndoRedoHelper.cs create mode 100644 src/Avalonia.Controls/Window.cs create mode 100644 src/Avalonia.Controls/WindowEdge.cs create mode 100644 src/Avalonia.Controls/WindowState.cs create mode 100644 src/Avalonia.Controls/WrapPanel.cs rename src/{Perspex.Controls => Avalonia.Controls}/app.config (100%) rename src/{Perspex.Controls => Avalonia.Controls}/packages.config (100%) create mode 100644 src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj create mode 100644 src/Avalonia.DesignerSupport/DesignerApi.cs create mode 100644 src/Avalonia.DesignerSupport/DesignerAssist.cs create mode 100644 src/Avalonia.DesignerSupport/Properties/AssemblyInfo.cs rename src/{Perspex.DesignerSupport => Avalonia.DesignerSupport}/app.config (100%) rename src/{Perspex.DesignerSupport => Avalonia.DesignerSupport}/packages.config (100%) create mode 100644 src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj create mode 100644 src/Avalonia.Diagnostics/Debug.cs create mode 100644 src/Avalonia.Diagnostics/DevTools.xaml create mode 100644 src/Avalonia.Diagnostics/DevTools.xaml.cs create mode 100644 src/Avalonia.Diagnostics/LogManager.cs create mode 100644 src/Avalonia.Diagnostics/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.Diagnostics/ViewLocator.cs create mode 100644 src/Avalonia.Diagnostics/ViewModels/ControlDetailsViewModel.cs create mode 100644 src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs create mode 100644 src/Avalonia.Diagnostics/ViewModels/LogicalTreeNode.cs create mode 100644 src/Avalonia.Diagnostics/ViewModels/PropertyDetails.cs create mode 100644 src/Avalonia.Diagnostics/ViewModels/TreeNode.cs create mode 100644 src/Avalonia.Diagnostics/ViewModels/TreePageViewModel.cs create mode 100644 src/Avalonia.Diagnostics/ViewModels/VisualTreeNode.cs create mode 100644 src/Avalonia.Diagnostics/Views/ControlDetailsView.cs create mode 100644 src/Avalonia.Diagnostics/Views/GridRepeater.cs create mode 100644 src/Avalonia.Diagnostics/Views/TreePage.xaml.cs create mode 100644 src/Avalonia.Diagnostics/Views/TreePageView.xaml rename src/{Perspex.Diagnostics => Avalonia.Diagnostics}/app.config (100%) rename src/{Perspex.Diagnostics => Avalonia.Diagnostics}/packages.config (100%) create mode 100644 src/Avalonia.HtmlRenderer/Adapters/AvaloniaAdapter.cs create mode 100644 src/Avalonia.HtmlRenderer/Adapters/BrushAdapter.cs create mode 100644 src/Avalonia.HtmlRenderer/Adapters/ContextMenuAdapter.cs create mode 100644 src/Avalonia.HtmlRenderer/Adapters/ControlAdapter.cs create mode 100644 src/Avalonia.HtmlRenderer/Adapters/FontAdapter.cs create mode 100644 src/Avalonia.HtmlRenderer/Adapters/FontFamilyAdapter.cs create mode 100644 src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs create mode 100644 src/Avalonia.HtmlRenderer/Adapters/GraphicsPathAdapter.cs create mode 100644 src/Avalonia.HtmlRenderer/Adapters/ImageAdapter.cs create mode 100644 src/Avalonia.HtmlRenderer/Adapters/PenAdapter.cs create mode 100644 src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj rename src/{Perspex.HtmlRenderer/Perspex.HtmlRenderer.csproj.DotSettings => Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj.DotSettings} (100%) create mode 100644 src/Avalonia.HtmlRenderer/Compat/Attributes.cs create mode 100644 src/Avalonia.HtmlRenderer/Compat/ThreadPool.cs create mode 100644 src/Avalonia.HtmlRenderer/HtmlContainer.cs create mode 100644 src/Avalonia.HtmlRenderer/HtmlControl.cs create mode 100644 src/Avalonia.HtmlRenderer/HtmlLabel.cs create mode 100644 src/Avalonia.HtmlRenderer/HtmlRendererRoutedEventArgs.cs create mode 100644 src/Avalonia.HtmlRenderer/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.HtmlRenderer/PropertyHelper.cs create mode 100644 src/Avalonia.HtmlRenderer/Utilities/Util.cs rename src/{Perspex.HtmlRenderer => Avalonia.HtmlRenderer}/external (100%) rename src/{Perspex.HtmlRenderer => Avalonia.HtmlRenderer}/packages.config (100%) create mode 100644 src/Avalonia.Input/AccessKeyHandler.cs create mode 100644 src/Avalonia.Input/Avalonia.Input.csproj create mode 100644 src/Avalonia.Input/Cursors.cs create mode 100644 src/Avalonia.Input/FocusManager.cs create mode 100644 src/Avalonia.Input/FocusNavigationDirection.cs create mode 100644 src/Avalonia.Input/Gestures.cs create mode 100644 src/Avalonia.Input/GotFocusEventArgs.cs create mode 100644 src/Avalonia.Input/IAccessKeyHandler.cs create mode 100644 src/Avalonia.Input/ICloseable.cs create mode 100644 src/Avalonia.Input/IFocusManager.cs create mode 100644 src/Avalonia.Input/IFocusScope.cs create mode 100644 src/Avalonia.Input/IInputDevice.cs create mode 100644 src/Avalonia.Input/IInputElement.cs create mode 100644 src/Avalonia.Input/IInputManager.cs create mode 100644 src/Avalonia.Input/IInputRoot.cs create mode 100644 src/Avalonia.Input/IKeyboardDevice.cs create mode 100644 src/Avalonia.Input/IKeyboardNavigationHandler.cs create mode 100644 src/Avalonia.Input/IMainMenu.cs create mode 100644 src/Avalonia.Input/IMouseDevice.cs create mode 100644 src/Avalonia.Input/INavigableContainer.cs create mode 100644 src/Avalonia.Input/IPointerDevice.cs create mode 100644 src/Avalonia.Input/InputElement.cs create mode 100644 src/Avalonia.Input/InputExtensions.cs create mode 100644 src/Avalonia.Input/InputManager.cs create mode 100644 src/Avalonia.Input/Key.cs create mode 100644 src/Avalonia.Input/KeyBinding.cs create mode 100644 src/Avalonia.Input/KeyEventArgs.cs create mode 100644 src/Avalonia.Input/KeyGesture.cs create mode 100644 src/Avalonia.Input/KeyboardDevice.cs create mode 100644 src/Avalonia.Input/KeyboardNavigation.cs create mode 100644 src/Avalonia.Input/KeyboardNavigationHandler.cs create mode 100644 src/Avalonia.Input/KeyboardNavigationMode.cs create mode 100644 src/Avalonia.Input/MouseDevice.cs create mode 100644 src/Avalonia.Input/Navigation/DirectionalNavigation.cs create mode 100644 src/Avalonia.Input/Navigation/FocusExtensions.cs create mode 100644 src/Avalonia.Input/Navigation/TabNavigation.cs create mode 100644 src/Avalonia.Input/NavigationMethod.cs create mode 100644 src/Avalonia.Input/Platform/IClipboard.cs create mode 100644 src/Avalonia.Input/Platform/IStandardCursorFactory.cs create mode 100644 src/Avalonia.Input/PointerEventArgs.cs create mode 100644 src/Avalonia.Input/PointerWheelEventArgs.cs create mode 100644 src/Avalonia.Input/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.Input/Raw/RawInputEventArgs.cs create mode 100644 src/Avalonia.Input/Raw/RawKeyEventArgs.cs create mode 100644 src/Avalonia.Input/Raw/RawMouseEventArgs.cs create mode 100644 src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs create mode 100644 src/Avalonia.Input/Raw/RawSizeEventArgs.cs create mode 100644 src/Avalonia.Input/Raw/RawTextInputEventArgs.cs create mode 100644 src/Avalonia.Input/TextInputEventArgs.cs create mode 100644 src/Avalonia.Input/VectorEventArgs.cs rename src/{Perspex.Input => Avalonia.Input}/app.config (100%) rename src/{Perspex.Input => Avalonia.Input}/packages.config (100%) create mode 100644 src/Avalonia.Interactivity/Avalonia.Interactivity.csproj create mode 100644 src/Avalonia.Interactivity/EventSubscription.cs create mode 100644 src/Avalonia.Interactivity/IInteractive.cs create mode 100644 src/Avalonia.Interactivity/Interactive.cs create mode 100644 src/Avalonia.Interactivity/InteractiveExtensions.cs create mode 100644 src/Avalonia.Interactivity/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.Interactivity/RoutedEvent.cs create mode 100644 src/Avalonia.Interactivity/RoutedEventArgs.cs rename src/{Perspex.Interactivity => Avalonia.Interactivity}/app.config (100%) rename src/{Perspex.Interactivity => Avalonia.Interactivity}/packages.config (100%) create mode 100644 src/Avalonia.Layout/Avalonia.Layout.csproj create mode 100644 src/Avalonia.Layout/ILayoutManager.cs create mode 100644 src/Avalonia.Layout/ILayoutRoot.cs create mode 100644 src/Avalonia.Layout/ILayoutable.cs create mode 100644 src/Avalonia.Layout/LayoutHelper.cs create mode 100644 src/Avalonia.Layout/LayoutManager.cs create mode 100644 src/Avalonia.Layout/Layoutable.cs create mode 100644 src/Avalonia.Layout/Properties/AssemblyInfo.cs rename src/{Perspex.Layout => Avalonia.Layout}/app.config (100%) rename src/{Perspex.Layout => Avalonia.Layout}/packages.config (100%) create mode 100644 src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj create mode 100644 src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.Logging.Serilog/SerilogLogger.cs rename src/{Perspex.Logging.Serilog => Avalonia.Logging.Serilog}/packages.config (100%) create mode 100644 src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj create mode 100644 src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.ReactiveUI/Registrations.cs rename src/{Perspex.ReactiveUI => Avalonia.ReactiveUI}/packages.config (100%) rename src/{Perspex.ReactiveUI => Avalonia.ReactiveUI}/src (100%) create mode 100644 src/Avalonia.SceneGraph/Animation/CrossFade.cs create mode 100644 src/Avalonia.SceneGraph/Animation/IPageTransition.cs create mode 100644 src/Avalonia.SceneGraph/Animation/PageSlide.cs create mode 100644 src/Avalonia.SceneGraph/Avalonia.SceneGraph.csproj create mode 100644 src/Avalonia.SceneGraph/INamed.cs create mode 100644 src/Avalonia.SceneGraph/Matrix.cs create mode 100644 src/Avalonia.SceneGraph/Media/AlignmentX.cs create mode 100644 src/Avalonia.SceneGraph/Media/AlignmentY.cs create mode 100644 src/Avalonia.SceneGraph/Media/ArcSegment.cs create mode 100644 src/Avalonia.SceneGraph/Media/BezierSegment .cs create mode 100644 src/Avalonia.SceneGraph/Media/Brush.cs create mode 100644 src/Avalonia.SceneGraph/Media/BrushMappingMode.cs create mode 100644 src/Avalonia.SceneGraph/Media/Brushes.cs create mode 100644 src/Avalonia.SceneGraph/Media/Color.cs create mode 100644 src/Avalonia.SceneGraph/Media/Colors.cs create mode 100644 src/Avalonia.SceneGraph/Media/DashStyle.cs create mode 100644 src/Avalonia.SceneGraph/Media/DrawingContext.cs create mode 100644 src/Avalonia.SceneGraph/Media/EllipseGeometry.cs create mode 100644 src/Avalonia.SceneGraph/Media/FillRule.cs create mode 100644 src/Avalonia.SceneGraph/Media/FontStyle.cs create mode 100644 src/Avalonia.SceneGraph/Media/FontWeight.cs create mode 100644 src/Avalonia.SceneGraph/Media/FormattedText.cs create mode 100644 src/Avalonia.SceneGraph/Media/FormattedTextLine.cs create mode 100644 src/Avalonia.SceneGraph/Media/Geometry.cs create mode 100644 src/Avalonia.SceneGraph/Media/GradientBrush.cs create mode 100644 src/Avalonia.SceneGraph/Media/GradientSpreadMethod.cs create mode 100644 src/Avalonia.SceneGraph/Media/GradientStop.cs create mode 100644 src/Avalonia.SceneGraph/Media/IBrush.cs create mode 100644 src/Avalonia.SceneGraph/Media/IDrawingContext.cs create mode 100644 src/Avalonia.SceneGraph/Media/ISolidColorBrush.cs create mode 100644 src/Avalonia.SceneGraph/Media/ImageBush.cs create mode 100644 src/Avalonia.SceneGraph/Media/Imaging/Bitmap.cs create mode 100644 src/Avalonia.SceneGraph/Media/Imaging/IBitmap.cs create mode 100644 src/Avalonia.SceneGraph/Media/Imaging/RenderTargetBitmap.cs create mode 100644 src/Avalonia.SceneGraph/Media/LineGeometry.cs create mode 100644 src/Avalonia.SceneGraph/Media/LineSegment.cs create mode 100644 src/Avalonia.SceneGraph/Media/LinearGradientBrush.cs create mode 100644 src/Avalonia.SceneGraph/Media/MatrixTransform.cs create mode 100644 src/Avalonia.SceneGraph/Media/MediaExtensions.cs create mode 100644 src/Avalonia.SceneGraph/Media/Mutable/SolidColorBrush.cs create mode 100644 src/Avalonia.SceneGraph/Media/PathFigure.cs create mode 100644 src/Avalonia.SceneGraph/Media/PathGeometry.cs create mode 100644 src/Avalonia.SceneGraph/Media/PathGeometryCollections.cs create mode 100644 src/Avalonia.SceneGraph/Media/PathMarkupParser.cs create mode 100644 src/Avalonia.SceneGraph/Media/PathSegment.cs create mode 100644 src/Avalonia.SceneGraph/Media/Pen.cs create mode 100644 src/Avalonia.SceneGraph/Media/PenLineCap.cs create mode 100644 src/Avalonia.SceneGraph/Media/PenLineJoin.cs create mode 100644 src/Avalonia.SceneGraph/Media/PolylineGeometry.cs create mode 100644 src/Avalonia.SceneGraph/Media/QuadraticBezierSegment .cs create mode 100644 src/Avalonia.SceneGraph/Media/RadialGradientBrush.cs create mode 100644 src/Avalonia.SceneGraph/Media/RectangleGeometry.cs create mode 100644 src/Avalonia.SceneGraph/Media/RotateTransform.cs create mode 100644 src/Avalonia.SceneGraph/Media/ScaleTransform.cs create mode 100644 src/Avalonia.SceneGraph/Media/SolidColorBrush.cs create mode 100644 src/Avalonia.SceneGraph/Media/StreamGeometry.cs create mode 100644 src/Avalonia.SceneGraph/Media/StreamGeometryContext.cs create mode 100644 src/Avalonia.SceneGraph/Media/Stretch.cs create mode 100644 src/Avalonia.SceneGraph/Media/SweepDirection.cs create mode 100644 src/Avalonia.SceneGraph/Media/TextAlignment.cs create mode 100644 src/Avalonia.SceneGraph/Media/TextHitTestResult.cs create mode 100644 src/Avalonia.SceneGraph/Media/TileBrush.cs create mode 100644 src/Avalonia.SceneGraph/Media/Transform.cs create mode 100644 src/Avalonia.SceneGraph/Media/TransformGroup.cs create mode 100644 src/Avalonia.SceneGraph/Media/TranslateTransform.cs create mode 100644 src/Avalonia.SceneGraph/Media/VisualBrush.cs create mode 100644 src/Avalonia.SceneGraph/Platform/IBitmapImpl.cs create mode 100644 src/Avalonia.SceneGraph/Platform/IFormattedTextImpl.cs create mode 100644 src/Avalonia.SceneGraph/Platform/IGeometryImpl.cs create mode 100644 src/Avalonia.SceneGraph/Platform/IPlatformRenderInterface.cs create mode 100644 src/Avalonia.SceneGraph/Platform/IPlatformSettings.cs create mode 100644 src/Avalonia.SceneGraph/Platform/IRenderTarget.cs create mode 100644 src/Avalonia.SceneGraph/Platform/IRenderTargetBitmapImpl.cs create mode 100644 src/Avalonia.SceneGraph/Platform/IStreamGeometryContextImpl.cs create mode 100644 src/Avalonia.SceneGraph/Platform/IStreamGeometryImpl.cs create mode 100644 src/Avalonia.SceneGraph/Point.cs create mode 100644 src/Avalonia.SceneGraph/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.SceneGraph/Rect.cs create mode 100644 src/Avalonia.SceneGraph/RelativePoint.cs create mode 100644 src/Avalonia.SceneGraph/RelativeRect.cs create mode 100644 src/Avalonia.SceneGraph/Rendering/IRenderQueueManager.cs create mode 100644 src/Avalonia.SceneGraph/Rendering/IRenderRoot.cs create mode 100644 src/Avalonia.SceneGraph/Rendering/RenderQueueManager.cs create mode 100644 src/Avalonia.SceneGraph/Rendering/RendererMixin.cs create mode 100644 src/Avalonia.SceneGraph/Size.cs create mode 100644 src/Avalonia.SceneGraph/Thickness.cs create mode 100644 src/Avalonia.SceneGraph/Vector.cs create mode 100644 src/Avalonia.SceneGraph/Visual.cs create mode 100644 src/Avalonia.SceneGraph/VisualExtensions.cs create mode 100644 src/Avalonia.SceneGraph/VisualTree/BoundsTracker.cs create mode 100644 src/Avalonia.SceneGraph/VisualTree/IHostedVisualTreeRoot.cs create mode 100644 src/Avalonia.SceneGraph/VisualTree/IVisual.cs create mode 100644 src/Avalonia.SceneGraph/VisualTree/IVisualTreeHost.cs create mode 100644 src/Avalonia.SceneGraph/VisualTree/TransformedBounds.cs create mode 100644 src/Avalonia.SceneGraph/VisualTree/VisualExtensions.cs create mode 100644 src/Avalonia.SceneGraph/VisualTreeAttachmentEventArgs.cs rename src/{Perspex.SceneGraph => Avalonia.SceneGraph}/app.config (100%) rename src/{Perspex.SceneGraph => Avalonia.SceneGraph}/packages.config (100%) create mode 100644 src/Avalonia.Styling/Avalonia.Styling.csproj create mode 100644 src/Avalonia.Styling/LogicalTree/ILogical.cs create mode 100644 src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs create mode 100644 src/Avalonia.Styling/LogicalTree/LogicalTreeAttachmentEventArgs.cs create mode 100644 src/Avalonia.Styling/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.Styling/Styling/ActivatedObservable.cs create mode 100644 src/Avalonia.Styling/Styling/ActivatedSubject.cs create mode 100644 src/Avalonia.Styling/Styling/ActivatedValue.cs create mode 100644 src/Avalonia.Styling/Styling/ChildSelector.cs create mode 100644 src/Avalonia.Styling/Styling/DescendentSelector.cs create mode 100644 src/Avalonia.Styling/Styling/IGlobalStyles.cs create mode 100644 src/Avalonia.Styling/Styling/ISetter.cs create mode 100644 src/Avalonia.Styling/Styling/IStyle.cs create mode 100644 src/Avalonia.Styling/Styling/IStyleHost.cs create mode 100644 src/Avalonia.Styling/Styling/IStyleRoot.cs create mode 100644 src/Avalonia.Styling/Styling/IStyleable.cs create mode 100644 src/Avalonia.Styling/Styling/IStyler.cs create mode 100644 src/Avalonia.Styling/Styling/ITemplatedControl.cs create mode 100644 src/Avalonia.Styling/Styling/PropertyEqualsSelector.cs create mode 100644 src/Avalonia.Styling/Styling/Selector.cs create mode 100644 src/Avalonia.Styling/Styling/SelectorMatch.cs create mode 100644 src/Avalonia.Styling/Styling/Selectors.cs create mode 100644 src/Avalonia.Styling/Styling/Setter.cs create mode 100644 src/Avalonia.Styling/Styling/Style.cs create mode 100644 src/Avalonia.Styling/Styling/StyleActivator.cs create mode 100644 src/Avalonia.Styling/Styling/StyleExtensions.cs create mode 100644 src/Avalonia.Styling/Styling/Styler.cs create mode 100644 src/Avalonia.Styling/Styling/Styles.cs create mode 100644 src/Avalonia.Styling/Styling/TemplateSelector.cs create mode 100644 src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs rename src/{Perspex.Styling => Avalonia.Styling}/Styling/packages.config (100%) rename src/{Perspex.Styling => Avalonia.Styling}/app.config (100%) create mode 100644 src/Avalonia.Themes.Default/Accents/BaseLight.xaml create mode 100644 src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj create mode 100644 src/Avalonia.Themes.Default/Button.xaml create mode 100644 src/Avalonia.Themes.Default/Carousel.xaml create mode 100644 src/Avalonia.Themes.Default/CheckBox.xaml create mode 100644 src/Avalonia.Themes.Default/ContentControl.xaml create mode 100644 src/Avalonia.Themes.Default/ContextMenu.xaml create mode 100644 src/Avalonia.Themes.Default/DefaultTheme.xaml create mode 100644 src/Avalonia.Themes.Default/DefaultTheme.xaml.cs create mode 100644 src/Avalonia.Themes.Default/DropDown.xaml create mode 100644 src/Avalonia.Themes.Default/DropDownItem.xaml create mode 100644 src/Avalonia.Themes.Default/Expander.xaml create mode 100644 src/Avalonia.Themes.Default/FocusAdorner.xaml create mode 100644 src/Avalonia.Themes.Default/GridSplitter.xaml create mode 100644 src/Avalonia.Themes.Default/ItemsControl.xaml create mode 100644 src/Avalonia.Themes.Default/LayoutTransformControl.xaml create mode 100644 src/Avalonia.Themes.Default/ListBox.xaml create mode 100644 src/Avalonia.Themes.Default/ListBoxItem.xaml create mode 100644 src/Avalonia.Themes.Default/Menu.xaml create mode 100644 src/Avalonia.Themes.Default/MenuItem.xaml create mode 100644 src/Avalonia.Themes.Default/PopupRoot.xaml create mode 100644 src/Avalonia.Themes.Default/ProgressBar.xaml create mode 100644 src/Avalonia.Themes.Default/Properties/AssemblyInfo.cs create mode 100644 src/Avalonia.Themes.Default/RadioButton.xaml create mode 100644 src/Avalonia.Themes.Default/ScrollBar.xaml create mode 100644 src/Avalonia.Themes.Default/ScrollViewer.xaml create mode 100644 src/Avalonia.Themes.Default/Separator.xaml create mode 100644 src/Avalonia.Themes.Default/Slider.xaml create mode 100644 src/Avalonia.Themes.Default/TabControl.xaml create mode 100644 src/Avalonia.Themes.Default/TabStrip.xaml create mode 100644 src/Avalonia.Themes.Default/TabStripItem.xaml create mode 100644 src/Avalonia.Themes.Default/TextBox.xaml create mode 100644 src/Avalonia.Themes.Default/ToggleButton.xaml create mode 100644 src/Avalonia.Themes.Default/ToolTip.xaml create mode 100644 src/Avalonia.Themes.Default/TreeView.xaml create mode 100644 src/Avalonia.Themes.Default/TreeViewItem.xaml create mode 100644 src/Avalonia.Themes.Default/Window.xaml rename src/{Perspex.Themes.Default => Avalonia.Themes.Default}/app.config (100%) rename src/{Perspex.Themes.Default => Avalonia.Themes.Default}/packages.config (100%) create mode 100644 src/Gtk/Avalonia.Cairo/Avalonia.Cairo.csproj create mode 100644 src/Gtk/Avalonia.Cairo/CairoExtensions.cs create mode 100644 src/Gtk/Avalonia.Cairo/CairoPlatform.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/BrushImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/FormattedTextImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/ImageBrushImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/Imaging/BitmapImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/LinearGradientBrushImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/RadialGradientBrushImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/SolidColorBrushImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/StreamGeometryContextImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/StreamGeometryImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/TileBrushes.cs create mode 100644 src/Gtk/Avalonia.Cairo/Media/VisualBrushImpl.cs create mode 100644 src/Gtk/Avalonia.Cairo/Properties/AssemblyInfo.cs create mode 100644 src/Gtk/Avalonia.Cairo/RenderTarget.cs rename src/Gtk/{Perspex.Cairo => Avalonia.Cairo}/app.config (100%) rename src/Gtk/{Perspex.Cairo => Avalonia.Cairo}/packages.config (100%) create mode 100644 src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj create mode 100644 src/Gtk/Avalonia.Gtk/ClipboardImpl.cs create mode 100644 src/Gtk/Avalonia.Gtk/CursorFactory.cs create mode 100644 src/Gtk/Avalonia.Gtk/GtkExtensions.cs create mode 100644 src/Gtk/Avalonia.Gtk/GtkPlatform.cs create mode 100644 src/Gtk/Avalonia.Gtk/Input/GtkKeyboardDevice.cs create mode 100644 src/Gtk/Avalonia.Gtk/Input/GtkMouseDevice.cs create mode 100644 src/Gtk/Avalonia.Gtk/MyClass.cs create mode 100644 src/Gtk/Avalonia.Gtk/PopupImpl.cs create mode 100644 src/Gtk/Avalonia.Gtk/Properties/AssemblyInfo.cs create mode 100644 src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs create mode 100644 src/Gtk/Avalonia.Gtk/WindowImpl.cs rename src/Gtk/{Perspex.Gtk => Avalonia.Gtk}/packages.config (100%) delete mode 100644 src/Gtk/Perspex.Cairo/CairoExtensions.cs delete mode 100644 src/Gtk/Perspex.Cairo/CairoPlatform.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/BrushImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/DrawingContext.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/FormattedTextImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/Imaging/BitmapImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/LinearGradientBrushImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/RadialGradientBrushImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/SolidColorBrushImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/TileBrushes.cs delete mode 100644 src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs delete mode 100644 src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj delete mode 100644 src/Gtk/Perspex.Cairo/Properties/AssemblyInfo.cs delete mode 100644 src/Gtk/Perspex.Cairo/RenderTarget.cs delete mode 100644 src/Gtk/Perspex.Gtk/ClipboardImpl.cs delete mode 100644 src/Gtk/Perspex.Gtk/CursorFactory.cs delete mode 100644 src/Gtk/Perspex.Gtk/GtkExtensions.cs delete mode 100644 src/Gtk/Perspex.Gtk/GtkPlatform.cs delete mode 100644 src/Gtk/Perspex.Gtk/Input/GtkKeyboardDevice.cs delete mode 100644 src/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs delete mode 100644 src/Gtk/Perspex.Gtk/MyClass.cs delete mode 100644 src/Gtk/Perspex.Gtk/Perspex.Gtk.csproj delete mode 100644 src/Gtk/Perspex.Gtk/PopupImpl.cs delete mode 100644 src/Gtk/Perspex.Gtk/Properties/AssemblyInfo.cs delete mode 100644 src/Gtk/Perspex.Gtk/SystemDialogImpl.cs delete mode 100644 src/Gtk/Perspex.Gtk/WindowImpl.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj create mode 100644 src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaAttachableXamlMember.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaContentPropertyProvider.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaLifeCycleListener.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaMemberValuePlugin.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaNamespaceRegistry.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaObjectAssembler.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaParserFactory.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaRuntimeTypeSource.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeFeatureProvider.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeRepository.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaWiringContext.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaXamlMember.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaXamlType.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/NameScopeWrapper.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Context/PropertyAccessor.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaListTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/BrushTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/ClassesTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/ColorTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/CursorTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/GeometryTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/GridLengthTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/KeyGestureConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/PointTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/PointsListTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/RelativePointTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/RelativeRectTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/SizeTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/ThicknessTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/TimeSpanTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Converters/UriTypeConverter.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Data/DelayedBinding.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Data/RelativeSource.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Data/SourceBindingEndpoint.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Data/TargetBindingEndpoint.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticExtension.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs rename src/Markup/{Perspex.Markup.Xaml => Avalonia.Markup.Xaml}/OmniXAML (100%) create mode 100644 src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorGrammar.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/ControlTemplate.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/FocusAdornerTemplate.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs create mode 100644 src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs rename src/Markup/{Perspex.Markup.Xaml => Avalonia.Markup.Xaml}/app.config (100%) rename src/Markup/{Perspex.Markup.Xaml => Avalonia.Markup.Xaml}/glass (100%) rename src/Markup/{Perspex.Markup.Xaml => Avalonia.Markup.Xaml}/packages.config (100%) create mode 100644 src/Markup/Avalonia.Markup/Avalonia.Markup.csproj create mode 100644 src/Markup/Avalonia.Markup/BoolConverters.cs create mode 100644 src/Markup/Avalonia.Markup/ControlLocator.cs create mode 100644 src/Markup/Avalonia.Markup/Data/CommonPropertyNames.cs create mode 100644 src/Markup/Avalonia.Markup/Data/ExpressionNode.cs create mode 100644 src/Markup/Avalonia.Markup/Data/ExpressionNodeBuilder.cs create mode 100644 src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs create mode 100644 src/Markup/Avalonia.Markup/Data/ExpressionParseException.cs create mode 100644 src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs create mode 100644 src/Markup/Avalonia.Markup/Data/IndexerNode.cs create mode 100644 src/Markup/Avalonia.Markup/Data/LogicalNotNode.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Parsers/ArgumentListParser.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Parsers/ExpressionParser.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Parsers/IdentifierParser.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Parsers/Reader.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Plugins/ExceptionValidationCheckerPlugin.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessor.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessorPlugin.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Plugins/IValidationCheckerPlugin.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Plugins/IndeiValidationCheckerPlugin.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Plugins/PropertyError.cs create mode 100644 src/Markup/Avalonia.Markup/Data/Plugins/ValidationCheckerBase.cs create mode 100644 src/Markup/Avalonia.Markup/Data/PropertyAccessorNode.cs create mode 100644 src/Markup/Avalonia.Markup/DefaultValueConverter.cs create mode 100644 src/Markup/Avalonia.Markup/FuncMultiValueConverter.cs create mode 100644 src/Markup/Avalonia.Markup/FuncValueConverter.cs create mode 100644 src/Markup/Avalonia.Markup/IMultiValueConverter.cs create mode 100644 src/Markup/Avalonia.Markup/IValueConverter.cs create mode 100644 src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs create mode 100644 src/Markup/Avalonia.Markup/StringConverters.cs rename src/Markup/{Perspex.Markup => Avalonia.Markup}/packages.config (100%) delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/NameScopeWrapper.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexAttachableXamlMember.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexContentPropertyProvider.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexLifeCycleListener.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexMemberValuePlugin.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexNamespaceRegistry.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexParserFactory.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexRuntimeTypeSource.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeFeatureProvider.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeRepository.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMember.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Context/PropertyAccessor.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/BitmapTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/BrushTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/ClassesTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/ColorTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/GeometryTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/GridLengthTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/KeyGestureConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/PerspexListTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/PerspexPropertyTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/PointTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/PointsListTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/RelativePointTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/RelativeRectTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/SelectorTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/SizeTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/ThicknessTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/TimeSpanTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Converters/UriTypeConverter.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Data/Binding.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Data/DelayedBinding.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Data/MultiBinding.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Data/RelativeSource.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Data/SourceBindingEndpoint.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Data/StyleResourceBinding.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Data/TargetBindingEndpoint.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StaticExtension.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TypeExtension.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Parsers/SelectorGrammar.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Parsers/SelectorParser.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj delete mode 100644 src/Markup/Perspex.Markup.Xaml/PerspexXamlLoader.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Properties/AssemblyInfo.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Styling/StyleInclude.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Templates/ControlTemplate.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Templates/DataTemplate.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Templates/FocusAdornerTemplate.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Templates/ItemsPanelTemplate.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Templates/MemberSelector.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Templates/Template.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Templates/TemplateContent.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Templates/TemplateLoader.cs delete mode 100644 src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs delete mode 100644 src/Markup/Perspex.Markup/BoolConverters.cs delete mode 100644 src/Markup/Perspex.Markup/ControlLocator.cs delete mode 100644 src/Markup/Perspex.Markup/Data/CommonPropertyNames.cs delete mode 100644 src/Markup/Perspex.Markup/Data/ExpressionNode.cs delete mode 100644 src/Markup/Perspex.Markup/Data/ExpressionNodeBuilder.cs delete mode 100644 src/Markup/Perspex.Markup/Data/ExpressionObserver.cs delete mode 100644 src/Markup/Perspex.Markup/Data/ExpressionParseException.cs delete mode 100644 src/Markup/Perspex.Markup/Data/ExpressionSubject.cs delete mode 100644 src/Markup/Perspex.Markup/Data/IndexerNode.cs delete mode 100644 src/Markup/Perspex.Markup/Data/LogicalNotNode.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Parsers/ArgumentListParser.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Parsers/ExpressionParser.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Parsers/IdentifierParser.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Parsers/Reader.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Plugins/ExceptionValidationCheckerPlugin.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Plugins/IPropertyAccessor.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Plugins/IPropertyAccessorPlugin.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Plugins/IValidationCheckerPlugin.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Plugins/IndeiValidationCheckerPlugin.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Plugins/PerspexPropertyAccessorPlugin.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Plugins/PropertyError.cs delete mode 100644 src/Markup/Perspex.Markup/Data/Plugins/ValidationCheckerBase.cs delete mode 100644 src/Markup/Perspex.Markup/Data/PropertyAccessorNode.cs delete mode 100644 src/Markup/Perspex.Markup/DefaultValueConverter.cs delete mode 100644 src/Markup/Perspex.Markup/FuncMultiValueConverter.cs delete mode 100644 src/Markup/Perspex.Markup/FuncValueConverter.cs delete mode 100644 src/Markup/Perspex.Markup/IMultiValueConverter.cs delete mode 100644 src/Markup/Perspex.Markup/IValueConverter.cs delete mode 100644 src/Markup/Perspex.Markup/Perspex.Markup.csproj delete mode 100644 src/Markup/Perspex.Markup/Properties/AssemblyInfo.cs delete mode 100644 src/Markup/Perspex.Markup/StringConverters.cs delete mode 100644 src/Perspex.Animation/Animatable.cs delete mode 100644 src/Perspex.Animation/Animate.cs delete mode 100644 src/Perspex.Animation/Animation.cs delete mode 100644 src/Perspex.Animation/AnimationExtensions.cs delete mode 100644 src/Perspex.Animation/Animation`1.cs delete mode 100644 src/Perspex.Animation/IEasing.cs delete mode 100644 src/Perspex.Animation/IEasing`1.cs delete mode 100644 src/Perspex.Animation/LinearDoubleEasing.cs delete mode 100644 src/Perspex.Animation/LinearEasing.cs delete mode 100644 src/Perspex.Animation/Perspex.Animation.csproj delete mode 100644 src/Perspex.Animation/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Animation/PropertyTransition.cs delete mode 100644 src/Perspex.Animation/PropertyTransitions.cs delete mode 100644 src/Perspex.Base/AttachedProperty.cs delete mode 100644 src/Perspex.Base/Collections/IPerspexList.cs delete mode 100644 src/Perspex.Base/Collections/IPerspexReadOnlyList.cs delete mode 100644 src/Perspex.Base/Collections/PerspexDictionary.cs delete mode 100644 src/Perspex.Base/Collections/PerspexList.cs delete mode 100644 src/Perspex.Base/Collections/PerspexListExtensions.cs delete mode 100644 src/Perspex.Base/Contract.cs delete mode 100644 src/Perspex.Base/Data/AssignBindingAttribute.cs delete mode 100644 src/Perspex.Base/Data/BindingError.cs delete mode 100644 src/Perspex.Base/Data/BindingMode.cs delete mode 100644 src/Perspex.Base/Data/BindingOperations.cs delete mode 100644 src/Perspex.Base/Data/BindingPriority.cs delete mode 100644 src/Perspex.Base/Data/IBinding.cs delete mode 100644 src/Perspex.Base/Data/IndexerDescriptor.cs delete mode 100644 src/Perspex.Base/Data/InstancedBinding.cs delete mode 100644 src/Perspex.Base/Data/ValidationMethods.cs delete mode 100644 src/Perspex.Base/Data/ValidationStatus.cs delete mode 100644 src/Perspex.Base/Diagnostics/INotifyCollectionChangedDebug.cs delete mode 100644 src/Perspex.Base/Diagnostics/IPerspexObjectDebug.cs delete mode 100644 src/Perspex.Base/Diagnostics/PerspexObjectExtensions.cs delete mode 100644 src/Perspex.Base/Diagnostics/PerspexPropertyValue.cs delete mode 100644 src/Perspex.Base/DirectProperty.cs delete mode 100644 src/Perspex.Base/DirectPropertyMetadata`1.cs delete mode 100644 src/Perspex.Base/IDescription.cs delete mode 100644 src/Perspex.Base/IDirectPropertyAccessor.cs delete mode 100644 src/Perspex.Base/IDirectPropertyMetadata.cs delete mode 100644 src/Perspex.Base/IPerspexObject.cs delete mode 100644 src/Perspex.Base/IPriorityValueOwner.cs delete mode 100644 src/Perspex.Base/IStyledPropertyAccessor.cs delete mode 100644 src/Perspex.Base/IStyledPropertyMetadata.cs delete mode 100644 src/Perspex.Base/ISupportInitialize.cs delete mode 100644 src/Perspex.Base/Logging/ILogSink.cs delete mode 100644 src/Perspex.Base/Logging/LogArea.cs delete mode 100644 src/Perspex.Base/Logging/LogEventLevel.cs delete mode 100644 src/Perspex.Base/Logging/Logger.cs delete mode 100644 src/Perspex.Base/Metadata/ContentAttribute.cs delete mode 100644 src/Perspex.Base/Metadata/DependsOnAttribute.cs delete mode 100644 src/Perspex.Base/Metadata/XmlnsDefinitionAttribute.cs delete mode 100644 src/Perspex.Base/Perspex.Base.csproj delete mode 100644 src/Perspex.Base/PerspexDisposable.cs delete mode 100644 src/Perspex.Base/PerspexInternalException.cs delete mode 100644 src/Perspex.Base/PerspexLocator.cs delete mode 100644 src/Perspex.Base/PerspexObject.cs delete mode 100644 src/Perspex.Base/PerspexObjectExtensions.cs delete mode 100644 src/Perspex.Base/PerspexProperty.cs delete mode 100644 src/Perspex.Base/PerspexPropertyChangedEventArgs.cs delete mode 100644 src/Perspex.Base/PerspexPropertyRegistry.cs delete mode 100644 src/Perspex.Base/PerspexProperty`1.cs delete mode 100644 src/Perspex.Base/Platform/IAssetLoader.cs delete mode 100644 src/Perspex.Base/Platform/IPclPlatformWrapper.cs delete mode 100644 src/Perspex.Base/Platform/IPlatformHandle.cs delete mode 100644 src/Perspex.Base/Platform/IPlatformThreadingInterface.cs delete mode 100644 src/Perspex.Base/Platform/PlatformHandle.cs delete mode 100644 src/Perspex.Base/PriorityBindingEntry.cs delete mode 100644 src/Perspex.Base/PriorityLevel.cs delete mode 100644 src/Perspex.Base/PriorityValue.cs delete mode 100644 src/Perspex.Base/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Base/PropertyMetadata.cs delete mode 100644 src/Perspex.Base/Reactive/AnonymousSubject`1.cs delete mode 100644 src/Perspex.Base/Reactive/AnonymousSubject`2.cs delete mode 100644 src/Perspex.Base/Reactive/ObservableEx.cs delete mode 100644 src/Perspex.Base/Reactive/PerspexObservable.cs delete mode 100644 src/Perspex.Base/Reactive/WeakPropertyChangedObservable.cs delete mode 100644 src/Perspex.Base/StyledProperty.cs delete mode 100644 src/Perspex.Base/StyledPropertyBase.cs delete mode 100644 src/Perspex.Base/StyledPropertyMetadata`1.cs delete mode 100644 src/Perspex.Base/Threading/Dispatcher.cs delete mode 100644 src/Perspex.Base/Threading/DispatcherPriority.cs delete mode 100644 src/Perspex.Base/Threading/DispatcherTimer.cs delete mode 100644 src/Perspex.Base/Threading/JobRunner.cs delete mode 100644 src/Perspex.Base/Threading/PerspexScheduler.cs delete mode 100644 src/Perspex.Base/Threading/PerspexSynchronizationContext.cs delete mode 100644 src/Perspex.Base/Threading/SingleThreadDispatcher.cs delete mode 100644 src/Perspex.Base/Utilities/IWeakSubscriber.cs delete mode 100644 src/Perspex.Base/Utilities/MathUtilities.cs delete mode 100644 src/Perspex.Base/Utilities/TypeUtilities.cs delete mode 100644 src/Perspex.Base/Utilities/WeakSubscriptionManager.cs delete mode 100644 src/Perspex.Base/Utilities/WeakTimer.cs delete mode 100644 src/Perspex.Controls/Application.cs delete mode 100644 src/Perspex.Controls/Border.cs delete mode 100644 src/Perspex.Controls/Button.cs delete mode 100644 src/Perspex.Controls/Canvas.cs delete mode 100644 src/Perspex.Controls/Carousel.cs delete mode 100644 src/Perspex.Controls/CheckBox.cs delete mode 100644 src/Perspex.Controls/Classes.cs delete mode 100644 src/Perspex.Controls/ColumnDefinition.cs delete mode 100644 src/Perspex.Controls/ColumnDefinitions.cs delete mode 100644 src/Perspex.Controls/ContentControl.cs delete mode 100644 src/Perspex.Controls/ContextMenu.cs delete mode 100644 src/Perspex.Controls/Control.cs delete mode 100644 src/Perspex.Controls/ControlExtensions.cs delete mode 100644 src/Perspex.Controls/ControlValidationStatus.cs delete mode 100644 src/Perspex.Controls/Controls.cs delete mode 100644 src/Perspex.Controls/Decorator.cs delete mode 100644 src/Perspex.Controls/DefinitionBase.cs delete mode 100644 src/Perspex.Controls/Design.cs delete mode 100644 src/Perspex.Controls/DockPanel.cs delete mode 100644 src/Perspex.Controls/DropDown.cs delete mode 100644 src/Perspex.Controls/DropDownItem.cs delete mode 100644 src/Perspex.Controls/Expander.cs delete mode 100644 src/Perspex.Controls/Generators/IItemContainerGenerator.cs delete mode 100644 src/Perspex.Controls/Generators/ITreeItemContainerGenerator.cs delete mode 100644 src/Perspex.Controls/Generators/ItemContainer.cs delete mode 100644 src/Perspex.Controls/Generators/ItemContainerEventArgs.cs delete mode 100644 src/Perspex.Controls/Generators/ItemContainerGenerator.cs delete mode 100644 src/Perspex.Controls/Generators/ItemContainerGenerator`1.cs delete mode 100644 src/Perspex.Controls/Generators/TreeContainerIndex.cs delete mode 100644 src/Perspex.Controls/Generators/TreeItemContainerGenerator.cs delete mode 100644 src/Perspex.Controls/Grid.cs delete mode 100644 src/Perspex.Controls/GridLength.cs delete mode 100644 src/Perspex.Controls/GridSplitter.cs delete mode 100644 src/Perspex.Controls/HotkeyManager.cs delete mode 100644 src/Perspex.Controls/IApplicationLifecycle.cs delete mode 100644 src/Perspex.Controls/IContentControl.cs delete mode 100644 src/Perspex.Controls/IControl.cs delete mode 100644 src/Perspex.Controls/IGlobalDataTemplates.cs delete mode 100644 src/Perspex.Controls/IHeadered.cs delete mode 100644 src/Perspex.Controls/INameScope.cs delete mode 100644 src/Perspex.Controls/IPanel.cs delete mode 100644 src/Perspex.Controls/IPseudoClasses.cs delete mode 100644 src/Perspex.Controls/ISelectable.cs delete mode 100644 src/Perspex.Controls/ISetLogicalParent.cs delete mode 100644 src/Perspex.Controls/Image.cs delete mode 100644 src/Perspex.Controls/ItemsControl.cs delete mode 100644 src/Perspex.Controls/LayoutTransformControl.cs delete mode 100644 src/Perspex.Controls/ListBox.cs delete mode 100644 src/Perspex.Controls/ListBoxItem.cs delete mode 100644 src/Perspex.Controls/Menu.cs delete mode 100644 src/Perspex.Controls/MenuItem.cs delete mode 100644 src/Perspex.Controls/MenuItemAccessKeyHandler.cs delete mode 100644 src/Perspex.Controls/Mixins/ContentControlMixin.cs delete mode 100644 src/Perspex.Controls/Mixins/SelectableMixin.cs delete mode 100644 src/Perspex.Controls/NameScope.cs delete mode 100644 src/Perspex.Controls/NameScopeEventArgs.cs delete mode 100644 src/Perspex.Controls/NameScopeExtensions.cs delete mode 100644 src/Perspex.Controls/Panel.cs delete mode 100644 src/Perspex.Controls/Perspex.Controls.csproj delete mode 100644 src/Perspex.Controls/PlacementMode.cs delete mode 100644 src/Perspex.Controls/Platform/IPopupImpl.cs delete mode 100644 src/Perspex.Controls/Platform/ISystemDialogImpl.cs delete mode 100644 src/Perspex.Controls/Platform/ITopLevelImpl.cs delete mode 100644 src/Perspex.Controls/Platform/ITopLevelRenderer.cs delete mode 100644 src/Perspex.Controls/Platform/IWindowImpl.cs delete mode 100644 src/Perspex.Controls/Platform/IWindowingPlatform.cs delete mode 100644 src/Perspex.Controls/Platform/PlatformManager.cs delete mode 100644 src/Perspex.Controls/Presenters/CarouselPresenter.cs delete mode 100644 src/Perspex.Controls/Presenters/ContentPresenter.cs delete mode 100644 src/Perspex.Controls/Presenters/IContentPresenter.cs delete mode 100644 src/Perspex.Controls/Presenters/IContentPresenterHost.cs delete mode 100644 src/Perspex.Controls/Presenters/IItemsPresenter.cs delete mode 100644 src/Perspex.Controls/Presenters/IItemsPresenterHost.cs delete mode 100644 src/Perspex.Controls/Presenters/IPresenter.cs delete mode 100644 src/Perspex.Controls/Presenters/ItemsPresenter.cs delete mode 100644 src/Perspex.Controls/Presenters/ItemsPresenterBase.cs delete mode 100644 src/Perspex.Controls/Presenters/ScrollContentPresenter.cs delete mode 100644 src/Perspex.Controls/Presenters/TextPresenter.cs delete mode 100644 src/Perspex.Controls/Primitives/AccessText.cs delete mode 100644 src/Perspex.Controls/Primitives/AdornerDecorator.cs delete mode 100644 src/Perspex.Controls/Primitives/AdornerLayer.cs delete mode 100644 src/Perspex.Controls/Primitives/HeaderedContentControl.cs delete mode 100644 src/Perspex.Controls/Primitives/HeaderedItemsControl.cs delete mode 100644 src/Perspex.Controls/Primitives/HeaderedSelectingControl.cs delete mode 100644 src/Perspex.Controls/Primitives/IScrollable.cs delete mode 100644 src/Perspex.Controls/Primitives/Popup.cs delete mode 100644 src/Perspex.Controls/Primitives/PopupRoot.cs delete mode 100644 src/Perspex.Controls/Primitives/RangeBase.cs delete mode 100644 src/Perspex.Controls/Primitives/ScrollBar.cs delete mode 100644 src/Perspex.Controls/Primitives/ScrollBarVisibility.cs delete mode 100644 src/Perspex.Controls/Primitives/SelectingItemsControl.cs delete mode 100644 src/Perspex.Controls/Primitives/TabStrip.cs delete mode 100644 src/Perspex.Controls/Primitives/TabStripItem.cs delete mode 100644 src/Perspex.Controls/Primitives/TemplateAppliedEventArgs.cs delete mode 100644 src/Perspex.Controls/Primitives/TemplatedControl.cs delete mode 100644 src/Perspex.Controls/Primitives/Thumb.cs delete mode 100644 src/Perspex.Controls/Primitives/ToggleButton.cs delete mode 100644 src/Perspex.Controls/Primitives/Track.cs delete mode 100644 src/Perspex.Controls/ProgressBar.cs delete mode 100644 src/Perspex.Controls/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Controls/RadioButton.cs delete mode 100644 src/Perspex.Controls/RequestBringIntoViewEventArgs.cs delete mode 100644 src/Perspex.Controls/RowDefinition.cs delete mode 100644 src/Perspex.Controls/RowDefinitions.cs delete mode 100644 src/Perspex.Controls/ScrollViewer.cs delete mode 100644 src/Perspex.Controls/SelectionChangedEventArgs.cs delete mode 100644 src/Perspex.Controls/SelectionMode.cs delete mode 100644 src/Perspex.Controls/Separator.cs delete mode 100644 src/Perspex.Controls/Shapes/Ellipse.cs delete mode 100644 src/Perspex.Controls/Shapes/Line.cs delete mode 100644 src/Perspex.Controls/Shapes/Path.cs delete mode 100644 src/Perspex.Controls/Shapes/Polygon.cs delete mode 100644 src/Perspex.Controls/Shapes/Polyline.cs delete mode 100644 src/Perspex.Controls/Shapes/Rectangle.cs delete mode 100644 src/Perspex.Controls/Shapes/Shape.cs delete mode 100644 src/Perspex.Controls/Slider.cs delete mode 100644 src/Perspex.Controls/StackPanel.cs delete mode 100644 src/Perspex.Controls/SystemDialog.cs delete mode 100644 src/Perspex.Controls/TabControl.cs delete mode 100644 src/Perspex.Controls/TabItem.cs delete mode 100644 src/Perspex.Controls/Templates/DataTemplateExtensions.cs delete mode 100644 src/Perspex.Controls/Templates/DataTemplates.cs delete mode 100644 src/Perspex.Controls/Templates/FuncControlTemplate.cs delete mode 100644 src/Perspex.Controls/Templates/FuncControlTemplate`2.cs delete mode 100644 src/Perspex.Controls/Templates/FuncDataTemplate.cs delete mode 100644 src/Perspex.Controls/Templates/FuncDataTemplate`1.cs delete mode 100644 src/Perspex.Controls/Templates/FuncMemberSelector.cs delete mode 100644 src/Perspex.Controls/Templates/FuncTemplate`1.cs delete mode 100644 src/Perspex.Controls/Templates/FuncTemplate`2.cs delete mode 100644 src/Perspex.Controls/Templates/FuncTreeDataTemplate.cs delete mode 100644 src/Perspex.Controls/Templates/FuncTreeDataTemplate`1.cs delete mode 100644 src/Perspex.Controls/Templates/IControlTemplate.cs delete mode 100644 src/Perspex.Controls/Templates/IDataTemplate.cs delete mode 100644 src/Perspex.Controls/Templates/IMemberSelector.cs delete mode 100644 src/Perspex.Controls/Templates/ITemplate`1.cs delete mode 100644 src/Perspex.Controls/Templates/ITemplate`2.cs delete mode 100644 src/Perspex.Controls/Templates/ITreeDataTemplate.cs delete mode 100644 src/Perspex.Controls/Templates/TemplateExtensions.cs delete mode 100644 src/Perspex.Controls/TextBlock.cs delete mode 100644 src/Perspex.Controls/TextBox.cs delete mode 100644 src/Perspex.Controls/TextWrapping.cs delete mode 100644 src/Perspex.Controls/ToolTip.cs delete mode 100644 src/Perspex.Controls/TopLevel.cs delete mode 100644 src/Perspex.Controls/TreeView.cs delete mode 100644 src/Perspex.Controls/TreeViewItem.cs delete mode 100644 src/Perspex.Controls/UserControl.cs delete mode 100644 src/Perspex.Controls/Utils/AncestorFinder.cs delete mode 100644 src/Perspex.Controls/Utils/IEnumerableUtils.cs delete mode 100644 src/Perspex.Controls/Utils/StringUtils.cs delete mode 100644 src/Perspex.Controls/Utils/UndoRedoHelper.cs delete mode 100644 src/Perspex.Controls/Window.cs delete mode 100644 src/Perspex.Controls/WindowEdge.cs delete mode 100644 src/Perspex.Controls/WindowState.cs delete mode 100644 src/Perspex.Controls/WrapPanel.cs delete mode 100644 src/Perspex.DesignerSupport/DesignerApi.cs delete mode 100644 src/Perspex.DesignerSupport/DesignerAssist.cs delete mode 100644 src/Perspex.DesignerSupport/Perspex.DesignerSupport.csproj delete mode 100644 src/Perspex.DesignerSupport/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Diagnostics/Debug.cs delete mode 100644 src/Perspex.Diagnostics/DevTools.xaml delete mode 100644 src/Perspex.Diagnostics/DevTools.xaml.cs delete mode 100644 src/Perspex.Diagnostics/LogManager.cs delete mode 100644 src/Perspex.Diagnostics/Perspex.Diagnostics.csproj delete mode 100644 src/Perspex.Diagnostics/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Diagnostics/ViewLocator.cs delete mode 100644 src/Perspex.Diagnostics/ViewModels/ControlDetailsViewModel.cs delete mode 100644 src/Perspex.Diagnostics/ViewModels/DevToolsViewModel.cs delete mode 100644 src/Perspex.Diagnostics/ViewModels/LogicalTreeNode.cs delete mode 100644 src/Perspex.Diagnostics/ViewModels/PropertyDetails.cs delete mode 100644 src/Perspex.Diagnostics/ViewModels/TreeNode.cs delete mode 100644 src/Perspex.Diagnostics/ViewModels/TreePageViewModel.cs delete mode 100644 src/Perspex.Diagnostics/ViewModels/VisualTreeNode.cs delete mode 100644 src/Perspex.Diagnostics/Views/ControlDetailsView.cs delete mode 100644 src/Perspex.Diagnostics/Views/GridRepeater.cs delete mode 100644 src/Perspex.Diagnostics/Views/TreePage.xaml.cs delete mode 100644 src/Perspex.Diagnostics/Views/TreePageView.xaml delete mode 100644 src/Perspex.HtmlRenderer/Adapters/BrushAdapter.cs delete mode 100644 src/Perspex.HtmlRenderer/Adapters/ContextMenuAdapter.cs delete mode 100644 src/Perspex.HtmlRenderer/Adapters/ControlAdapter.cs delete mode 100644 src/Perspex.HtmlRenderer/Adapters/FontAdapter.cs delete mode 100644 src/Perspex.HtmlRenderer/Adapters/FontFamilyAdapter.cs delete mode 100644 src/Perspex.HtmlRenderer/Adapters/GraphicsAdapter.cs delete mode 100644 src/Perspex.HtmlRenderer/Adapters/GraphicsPathAdapter.cs delete mode 100644 src/Perspex.HtmlRenderer/Adapters/ImageAdapter.cs delete mode 100644 src/Perspex.HtmlRenderer/Adapters/PenAdapter.cs delete mode 100644 src/Perspex.HtmlRenderer/Adapters/PerspexAdapter.cs delete mode 100644 src/Perspex.HtmlRenderer/Compat/Attributes.cs delete mode 100644 src/Perspex.HtmlRenderer/Compat/ThreadPool.cs delete mode 100644 src/Perspex.HtmlRenderer/HtmlContainer.cs delete mode 100644 src/Perspex.HtmlRenderer/HtmlControl.cs delete mode 100644 src/Perspex.HtmlRenderer/HtmlLabel.cs delete mode 100644 src/Perspex.HtmlRenderer/HtmlRendererRoutedEventArgs.cs delete mode 100644 src/Perspex.HtmlRenderer/Perspex.HtmlRenderer.csproj delete mode 100644 src/Perspex.HtmlRenderer/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.HtmlRenderer/PropertyHelper.cs delete mode 100644 src/Perspex.HtmlRenderer/Utilities/Util.cs delete mode 100644 src/Perspex.Input/AccessKeyHandler.cs delete mode 100644 src/Perspex.Input/Cursors.cs delete mode 100644 src/Perspex.Input/FocusManager.cs delete mode 100644 src/Perspex.Input/FocusNavigationDirection.cs delete mode 100644 src/Perspex.Input/Gestures.cs delete mode 100644 src/Perspex.Input/GotFocusEventArgs.cs delete mode 100644 src/Perspex.Input/IAccessKeyHandler.cs delete mode 100644 src/Perspex.Input/ICloseable.cs delete mode 100644 src/Perspex.Input/IFocusManager.cs delete mode 100644 src/Perspex.Input/IFocusScope.cs delete mode 100644 src/Perspex.Input/IInputDevice.cs delete mode 100644 src/Perspex.Input/IInputElement.cs delete mode 100644 src/Perspex.Input/IInputManager.cs delete mode 100644 src/Perspex.Input/IInputRoot.cs delete mode 100644 src/Perspex.Input/IKeyboardDevice.cs delete mode 100644 src/Perspex.Input/IKeyboardNavigationHandler.cs delete mode 100644 src/Perspex.Input/IMainMenu.cs delete mode 100644 src/Perspex.Input/IMouseDevice.cs delete mode 100644 src/Perspex.Input/INavigableContainer.cs delete mode 100644 src/Perspex.Input/IPointerDevice.cs delete mode 100644 src/Perspex.Input/InputElement.cs delete mode 100644 src/Perspex.Input/InputExtensions.cs delete mode 100644 src/Perspex.Input/InputManager.cs delete mode 100644 src/Perspex.Input/Key.cs delete mode 100644 src/Perspex.Input/KeyBinding.cs delete mode 100644 src/Perspex.Input/KeyEventArgs.cs delete mode 100644 src/Perspex.Input/KeyGesture.cs delete mode 100644 src/Perspex.Input/KeyboardDevice.cs delete mode 100644 src/Perspex.Input/KeyboardNavigation.cs delete mode 100644 src/Perspex.Input/KeyboardNavigationHandler.cs delete mode 100644 src/Perspex.Input/KeyboardNavigationMode.cs delete mode 100644 src/Perspex.Input/MouseDevice.cs delete mode 100644 src/Perspex.Input/Navigation/DirectionalNavigation.cs delete mode 100644 src/Perspex.Input/Navigation/FocusExtensions.cs delete mode 100644 src/Perspex.Input/Navigation/TabNavigation.cs delete mode 100644 src/Perspex.Input/NavigationMethod.cs delete mode 100644 src/Perspex.Input/Perspex.Input.csproj delete mode 100644 src/Perspex.Input/Platform/IClipboard.cs delete mode 100644 src/Perspex.Input/Platform/IStandardCursorFactory.cs delete mode 100644 src/Perspex.Input/PointerEventArgs.cs delete mode 100644 src/Perspex.Input/PointerWheelEventArgs.cs delete mode 100644 src/Perspex.Input/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Input/Raw/RawInputEventArgs.cs delete mode 100644 src/Perspex.Input/Raw/RawKeyEventArgs.cs delete mode 100644 src/Perspex.Input/Raw/RawMouseEventArgs.cs delete mode 100644 src/Perspex.Input/Raw/RawMouseWheelEventArgs.cs delete mode 100644 src/Perspex.Input/Raw/RawSizeEventArgs.cs delete mode 100644 src/Perspex.Input/Raw/RawTextInputEventArgs.cs delete mode 100644 src/Perspex.Input/TextInputEventArgs.cs delete mode 100644 src/Perspex.Input/VectorEventArgs.cs delete mode 100644 src/Perspex.Interactivity/EventSubscription.cs delete mode 100644 src/Perspex.Interactivity/IInteractive.cs delete mode 100644 src/Perspex.Interactivity/Interactive.cs delete mode 100644 src/Perspex.Interactivity/InteractiveExtensions.cs delete mode 100644 src/Perspex.Interactivity/Perspex.Interactivity.csproj delete mode 100644 src/Perspex.Interactivity/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Interactivity/RoutedEvent.cs delete mode 100644 src/Perspex.Interactivity/RoutedEventArgs.cs delete mode 100644 src/Perspex.Layout/ILayoutManager.cs delete mode 100644 src/Perspex.Layout/ILayoutRoot.cs delete mode 100644 src/Perspex.Layout/ILayoutable.cs delete mode 100644 src/Perspex.Layout/LayoutHelper.cs delete mode 100644 src/Perspex.Layout/LayoutManager.cs delete mode 100644 src/Perspex.Layout/Layoutable.cs delete mode 100644 src/Perspex.Layout/Perspex.Layout.csproj delete mode 100644 src/Perspex.Layout/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Logging.Serilog/Perspex.Logging.Serilog.csproj delete mode 100644 src/Perspex.Logging.Serilog/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Logging.Serilog/SerilogLogger.cs delete mode 100644 src/Perspex.ReactiveUI/Perspex.ReactiveUI.csproj delete mode 100644 src/Perspex.ReactiveUI/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.ReactiveUI/Registrations.cs delete mode 100644 src/Perspex.SceneGraph/Animation/CrossFade.cs delete mode 100644 src/Perspex.SceneGraph/Animation/IPageTransition.cs delete mode 100644 src/Perspex.SceneGraph/Animation/PageSlide.cs delete mode 100644 src/Perspex.SceneGraph/INamed.cs delete mode 100644 src/Perspex.SceneGraph/Matrix.cs delete mode 100644 src/Perspex.SceneGraph/Media/AlignmentX.cs delete mode 100644 src/Perspex.SceneGraph/Media/AlignmentY.cs delete mode 100644 src/Perspex.SceneGraph/Media/ArcSegment.cs delete mode 100644 src/Perspex.SceneGraph/Media/BezierSegment .cs delete mode 100644 src/Perspex.SceneGraph/Media/Brush.cs delete mode 100644 src/Perspex.SceneGraph/Media/BrushMappingMode.cs delete mode 100644 src/Perspex.SceneGraph/Media/Brushes.cs delete mode 100644 src/Perspex.SceneGraph/Media/Color.cs delete mode 100644 src/Perspex.SceneGraph/Media/Colors.cs delete mode 100644 src/Perspex.SceneGraph/Media/DashStyle.cs delete mode 100644 src/Perspex.SceneGraph/Media/DrawingContext.cs delete mode 100644 src/Perspex.SceneGraph/Media/EllipseGeometry.cs delete mode 100644 src/Perspex.SceneGraph/Media/FillRule.cs delete mode 100644 src/Perspex.SceneGraph/Media/FontStyle.cs delete mode 100644 src/Perspex.SceneGraph/Media/FontWeight.cs delete mode 100644 src/Perspex.SceneGraph/Media/FormattedText.cs delete mode 100644 src/Perspex.SceneGraph/Media/FormattedTextLine.cs delete mode 100644 src/Perspex.SceneGraph/Media/Geometry.cs delete mode 100644 src/Perspex.SceneGraph/Media/GradientBrush.cs delete mode 100644 src/Perspex.SceneGraph/Media/GradientSpreadMethod.cs delete mode 100644 src/Perspex.SceneGraph/Media/GradientStop.cs delete mode 100644 src/Perspex.SceneGraph/Media/IBrush.cs delete mode 100644 src/Perspex.SceneGraph/Media/IDrawingContext.cs delete mode 100644 src/Perspex.SceneGraph/Media/ISolidColorBrush.cs delete mode 100644 src/Perspex.SceneGraph/Media/ImageBush.cs delete mode 100644 src/Perspex.SceneGraph/Media/Imaging/Bitmap.cs delete mode 100644 src/Perspex.SceneGraph/Media/Imaging/IBitmap.cs delete mode 100644 src/Perspex.SceneGraph/Media/Imaging/RenderTargetBitmap.cs delete mode 100644 src/Perspex.SceneGraph/Media/LineGeometry.cs delete mode 100644 src/Perspex.SceneGraph/Media/LineSegment.cs delete mode 100644 src/Perspex.SceneGraph/Media/LinearGradientBrush.cs delete mode 100644 src/Perspex.SceneGraph/Media/MatrixTransform.cs delete mode 100644 src/Perspex.SceneGraph/Media/MediaExtensions.cs delete mode 100644 src/Perspex.SceneGraph/Media/Mutable/SolidColorBrush.cs delete mode 100644 src/Perspex.SceneGraph/Media/PathFigure.cs delete mode 100644 src/Perspex.SceneGraph/Media/PathGeometry.cs delete mode 100644 src/Perspex.SceneGraph/Media/PathGeometryCollections.cs delete mode 100644 src/Perspex.SceneGraph/Media/PathMarkupParser.cs delete mode 100644 src/Perspex.SceneGraph/Media/PathSegment.cs delete mode 100644 src/Perspex.SceneGraph/Media/Pen.cs delete mode 100644 src/Perspex.SceneGraph/Media/PenLineCap.cs delete mode 100644 src/Perspex.SceneGraph/Media/PenLineJoin.cs delete mode 100644 src/Perspex.SceneGraph/Media/PolylineGeometry.cs delete mode 100644 src/Perspex.SceneGraph/Media/QuadraticBezierSegment .cs delete mode 100644 src/Perspex.SceneGraph/Media/RadialGradientBrush.cs delete mode 100644 src/Perspex.SceneGraph/Media/RectangleGeometry.cs delete mode 100644 src/Perspex.SceneGraph/Media/RotateTransform.cs delete mode 100644 src/Perspex.SceneGraph/Media/ScaleTransform.cs delete mode 100644 src/Perspex.SceneGraph/Media/SolidColorBrush.cs delete mode 100644 src/Perspex.SceneGraph/Media/StreamGeometry.cs delete mode 100644 src/Perspex.SceneGraph/Media/StreamGeometryContext.cs delete mode 100644 src/Perspex.SceneGraph/Media/Stretch.cs delete mode 100644 src/Perspex.SceneGraph/Media/SweepDirection.cs delete mode 100644 src/Perspex.SceneGraph/Media/TextAlignment.cs delete mode 100644 src/Perspex.SceneGraph/Media/TextHitTestResult.cs delete mode 100644 src/Perspex.SceneGraph/Media/TileBrush.cs delete mode 100644 src/Perspex.SceneGraph/Media/Transform.cs delete mode 100644 src/Perspex.SceneGraph/Media/TransformGroup.cs delete mode 100644 src/Perspex.SceneGraph/Media/TranslateTransform.cs delete mode 100644 src/Perspex.SceneGraph/Media/VisualBrush.cs delete mode 100644 src/Perspex.SceneGraph/Perspex.SceneGraph.csproj delete mode 100644 src/Perspex.SceneGraph/Platform/IBitmapImpl.cs delete mode 100644 src/Perspex.SceneGraph/Platform/IFormattedTextImpl.cs delete mode 100644 src/Perspex.SceneGraph/Platform/IGeometryImpl.cs delete mode 100644 src/Perspex.SceneGraph/Platform/IPlatformRenderInterface.cs delete mode 100644 src/Perspex.SceneGraph/Platform/IPlatformSettings.cs delete mode 100644 src/Perspex.SceneGraph/Platform/IRenderTarget.cs delete mode 100644 src/Perspex.SceneGraph/Platform/IRenderTargetBitmapImpl.cs delete mode 100644 src/Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs delete mode 100644 src/Perspex.SceneGraph/Platform/IStreamGeometryImpl.cs delete mode 100644 src/Perspex.SceneGraph/Point.cs delete mode 100644 src/Perspex.SceneGraph/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.SceneGraph/Rect.cs delete mode 100644 src/Perspex.SceneGraph/RelativePoint.cs delete mode 100644 src/Perspex.SceneGraph/RelativeRect.cs delete mode 100644 src/Perspex.SceneGraph/Rendering/IRenderQueueManager.cs delete mode 100644 src/Perspex.SceneGraph/Rendering/IRenderRoot.cs delete mode 100644 src/Perspex.SceneGraph/Rendering/RenderQueueManager.cs delete mode 100644 src/Perspex.SceneGraph/Rendering/RendererMixin.cs delete mode 100644 src/Perspex.SceneGraph/Size.cs delete mode 100644 src/Perspex.SceneGraph/Thickness.cs delete mode 100644 src/Perspex.SceneGraph/Vector.cs delete mode 100644 src/Perspex.SceneGraph/Visual.cs delete mode 100644 src/Perspex.SceneGraph/VisualExtensions.cs delete mode 100644 src/Perspex.SceneGraph/VisualTree/BoundsTracker.cs delete mode 100644 src/Perspex.SceneGraph/VisualTree/IHostedVisualTreeRoot.cs delete mode 100644 src/Perspex.SceneGraph/VisualTree/IVisual.cs delete mode 100644 src/Perspex.SceneGraph/VisualTree/IVisualTreeHost.cs delete mode 100644 src/Perspex.SceneGraph/VisualTree/TransformedBounds.cs delete mode 100644 src/Perspex.SceneGraph/VisualTree/VisualExtensions.cs delete mode 100644 src/Perspex.SceneGraph/VisualTreeAttachmentEventArgs.cs delete mode 100644 src/Perspex.Styling/LogicalTree/ILogical.cs delete mode 100644 src/Perspex.Styling/LogicalTree/LogicalExtensions.cs delete mode 100644 src/Perspex.Styling/LogicalTree/LogicalTreeAttachmentEventArgs.cs delete mode 100644 src/Perspex.Styling/Perspex.Styling.csproj delete mode 100644 src/Perspex.Styling/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Styling/Styling/ActivatedObservable.cs delete mode 100644 src/Perspex.Styling/Styling/ActivatedSubject.cs delete mode 100644 src/Perspex.Styling/Styling/ActivatedValue.cs delete mode 100644 src/Perspex.Styling/Styling/ChildSelector.cs delete mode 100644 src/Perspex.Styling/Styling/DescendentSelector.cs delete mode 100644 src/Perspex.Styling/Styling/IGlobalStyles.cs delete mode 100644 src/Perspex.Styling/Styling/ISetter.cs delete mode 100644 src/Perspex.Styling/Styling/IStyle.cs delete mode 100644 src/Perspex.Styling/Styling/IStyleHost.cs delete mode 100644 src/Perspex.Styling/Styling/IStyleRoot.cs delete mode 100644 src/Perspex.Styling/Styling/IStyleable.cs delete mode 100644 src/Perspex.Styling/Styling/IStyler.cs delete mode 100644 src/Perspex.Styling/Styling/ITemplatedControl.cs delete mode 100644 src/Perspex.Styling/Styling/PropertyEqualsSelector.cs delete mode 100644 src/Perspex.Styling/Styling/Selector.cs delete mode 100644 src/Perspex.Styling/Styling/SelectorMatch.cs delete mode 100644 src/Perspex.Styling/Styling/Selectors.cs delete mode 100644 src/Perspex.Styling/Styling/Setter.cs delete mode 100644 src/Perspex.Styling/Styling/Style.cs delete mode 100644 src/Perspex.Styling/Styling/StyleActivator.cs delete mode 100644 src/Perspex.Styling/Styling/StyleExtensions.cs delete mode 100644 src/Perspex.Styling/Styling/Styler.cs delete mode 100644 src/Perspex.Styling/Styling/Styles.cs delete mode 100644 src/Perspex.Styling/Styling/TemplateSelector.cs delete mode 100644 src/Perspex.Styling/Styling/TypeNameAndClassSelector.cs delete mode 100644 src/Perspex.Themes.Default/Accents/BaseLight.xaml delete mode 100644 src/Perspex.Themes.Default/Button.xaml delete mode 100644 src/Perspex.Themes.Default/Carousel.xaml delete mode 100644 src/Perspex.Themes.Default/CheckBox.xaml delete mode 100644 src/Perspex.Themes.Default/ContentControl.xaml delete mode 100644 src/Perspex.Themes.Default/ContextMenu.xaml delete mode 100644 src/Perspex.Themes.Default/DefaultTheme.xaml delete mode 100644 src/Perspex.Themes.Default/DefaultTheme.xaml.cs delete mode 100644 src/Perspex.Themes.Default/DropDown.xaml delete mode 100644 src/Perspex.Themes.Default/DropDownItem.xaml delete mode 100644 src/Perspex.Themes.Default/Expander.xaml delete mode 100644 src/Perspex.Themes.Default/FocusAdorner.xaml delete mode 100644 src/Perspex.Themes.Default/GridSplitter.xaml delete mode 100644 src/Perspex.Themes.Default/ItemsControl.xaml delete mode 100644 src/Perspex.Themes.Default/LayoutTransformControl.xaml delete mode 100644 src/Perspex.Themes.Default/ListBox.xaml delete mode 100644 src/Perspex.Themes.Default/ListBoxItem.xaml delete mode 100644 src/Perspex.Themes.Default/Menu.xaml delete mode 100644 src/Perspex.Themes.Default/MenuItem.xaml delete mode 100644 src/Perspex.Themes.Default/Perspex.Themes.Default.csproj delete mode 100644 src/Perspex.Themes.Default/PopupRoot.xaml delete mode 100644 src/Perspex.Themes.Default/ProgressBar.xaml delete mode 100644 src/Perspex.Themes.Default/Properties/AssemblyInfo.cs delete mode 100644 src/Perspex.Themes.Default/RadioButton.xaml delete mode 100644 src/Perspex.Themes.Default/ScrollBar.xaml delete mode 100644 src/Perspex.Themes.Default/ScrollViewer.xaml delete mode 100644 src/Perspex.Themes.Default/Separator.xaml delete mode 100644 src/Perspex.Themes.Default/Slider.xaml delete mode 100644 src/Perspex.Themes.Default/TabControl.xaml delete mode 100644 src/Perspex.Themes.Default/TabStrip.xaml delete mode 100644 src/Perspex.Themes.Default/TabStripItem.xaml delete mode 100644 src/Perspex.Themes.Default/TextBox.xaml delete mode 100644 src/Perspex.Themes.Default/ToggleButton.xaml delete mode 100644 src/Perspex.Themes.Default/ToolTip.xaml delete mode 100644 src/Perspex.Themes.Default/TreeView.xaml delete mode 100644 src/Perspex.Themes.Default/TreeViewItem.xaml delete mode 100644 src/Perspex.Themes.Default/Window.xaml create mode 100644 src/Shared/avalonia.platform.targets delete mode 100644 src/Shared/perspex.platform.targets create mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Avalonia.Skia.Android.TestApp.csproj create mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/MainActivity.cs create mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Properties/AndroidManifest.xml create mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Properties/AssemblyInfo.cs create mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Resources/Resource.Designer.cs rename src/Skia/{Perspex.Skia.Android.TestApp => Avalonia.Skia.Android.TestApp}/Resources/drawable/Icon.png (100%) rename src/Skia/{Perspex.Skia.Android.TestApp => Avalonia.Skia.Android.TestApp}/Resources/layout/Main.axml (100%) create mode 100644 src/Skia/Avalonia.Skia.Android.TestApp/Resources/values/Strings.xml create mode 100644 src/Skia/Avalonia.Skia.Android/AndroidRenderTarget.cs create mode 100644 src/Skia/Avalonia.Skia.Android/Avalonia.Skia.Android.csproj rename src/Skia/{Perspex.Skia.Android => Avalonia.Skia.Android}/Resources/Resource.Designer.cs (100%) create mode 100644 src/Skia/Avalonia.Skia.Android/SkiaRenderView.cs create mode 100644 src/Skia/Avalonia.Skia.Android/SkiaView.cs rename src/Skia/{Perspex.Skia.Android => Avalonia.Skia.Android}/packages.config (100%) create mode 100644 src/Skia/Avalonia.Skia.Desktop/Avalonia.Skia.Desktop.csproj create mode 100644 src/Skia/Avalonia.Skia.Desktop/Properties/AssemblyInfo.cs rename src/Skia/{Perspex.Skia.Desktop => Avalonia.Skia.Desktop}/packages.config (100%) create mode 100644 src/Skia/Avalonia.Skia.iOS.TestApp/AppDelegate.cs create mode 100644 src/Skia/Avalonia.Skia.iOS.TestApp/Avalonia.Skia.iOS.TestApp.csproj rename src/Skia/{Perspex.Skia.iOS.TestApp => Avalonia.Skia.iOS.TestApp}/Entitlements.plist (100%) rename src/Skia/{Perspex.Skia.iOS.TestApp => Avalonia.Skia.iOS.TestApp}/GettingStarted.Xamarin (100%) create mode 100644 src/Skia/Avalonia.Skia.iOS.TestApp/Info.plist create mode 100644 src/Skia/Avalonia.Skia.iOS.TestApp/Main.cs create mode 100644 src/Skia/Avalonia.Skia.iOS.TestApp/MainView.cs create mode 100644 src/Skia/Avalonia.Skia.iOS.TestApp/Properties/AssemblyInfo.cs create mode 100644 src/Skia/Avalonia.Skia.iOS.TestApp/Resources/LaunchScreen.xib create mode 100644 src/Skia/Avalonia.Skia.iOS/Avalonia.Skia.iOS.csproj create mode 100644 src/Skia/Avalonia.Skia.iOS/Properties/AssemblyInfo.cs create mode 100644 src/Skia/Avalonia.Skia.iOS/SkiaView.cs rename src/Skia/{Perspex.Skia.iOS => Avalonia.Skia.iOS}/packages.config (100%) create mode 100644 src/Skia/Avalonia.Skia/Avalonia.Skia.projitems create mode 100644 src/Skia/Avalonia.Skia/Avalonia.Skia.shproj create mode 100644 src/Skia/Avalonia.Skia/BitmapImpl.cs create mode 100644 src/Skia/Avalonia.Skia/DrawingContextImpl.cs create mode 100644 src/Skia/Avalonia.Skia/FormattedTextImpl.cs create mode 100644 src/Skia/Avalonia.Skia/PlatformRenderInterface.cs create mode 100644 src/Skia/Avalonia.Skia/RenderTarget.cs create mode 100644 src/Skia/Avalonia.Skia/SkiaPlatform.cs create mode 100644 src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs create mode 100644 src/Skia/Avalonia.Skia/StreamGeometryImpl.cs create mode 100644 src/Skia/Avalonia.Skia/TypefaceCache.cs create mode 100644 src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs create mode 100644 src/Skia/Avalonia.Skia/readme.md delete mode 100644 src/Skia/Perspex.Skia.Android.TestApp/MainActivity.cs delete mode 100644 src/Skia/Perspex.Skia.Android.TestApp/Perspex.Skia.Android.TestApp.csproj delete mode 100644 src/Skia/Perspex.Skia.Android.TestApp/Properties/AndroidManifest.xml delete mode 100644 src/Skia/Perspex.Skia.Android.TestApp/Properties/AssemblyInfo.cs delete mode 100644 src/Skia/Perspex.Skia.Android.TestApp/Resources/Resource.Designer.cs delete mode 100644 src/Skia/Perspex.Skia.Android.TestApp/Resources/values/Strings.xml delete mode 100644 src/Skia/Perspex.Skia.Android/AndroidRenderTarget.cs delete mode 100644 src/Skia/Perspex.Skia.Android/Perspex.Skia.Android.csproj delete mode 100644 src/Skia/Perspex.Skia.Android/SkiaRenderView.cs delete mode 100644 src/Skia/Perspex.Skia.Android/SkiaView.cs delete mode 100644 src/Skia/Perspex.Skia.Desktop/Perspex.Skia.Desktop.csproj delete mode 100644 src/Skia/Perspex.Skia.Desktop/Properties/AssemblyInfo.cs delete mode 100644 src/Skia/Perspex.Skia.iOS.TestApp/AppDelegate.cs delete mode 100644 src/Skia/Perspex.Skia.iOS.TestApp/Info.plist delete mode 100644 src/Skia/Perspex.Skia.iOS.TestApp/Main.cs delete mode 100644 src/Skia/Perspex.Skia.iOS.TestApp/MainView.cs delete mode 100644 src/Skia/Perspex.Skia.iOS.TestApp/Perspex.Skia.iOS.TestApp.csproj delete mode 100644 src/Skia/Perspex.Skia.iOS.TestApp/Properties/AssemblyInfo.cs delete mode 100644 src/Skia/Perspex.Skia.iOS.TestApp/Resources/LaunchScreen.xib delete mode 100644 src/Skia/Perspex.Skia.iOS/Perspex.Skia.iOS.csproj delete mode 100644 src/Skia/Perspex.Skia.iOS/Properties/AssemblyInfo.cs delete mode 100644 src/Skia/Perspex.Skia.iOS/SkiaView.cs delete mode 100644 src/Skia/Perspex.Skia/BitmapImpl.cs delete mode 100644 src/Skia/Perspex.Skia/DrawingContextImpl.cs delete mode 100644 src/Skia/Perspex.Skia/FormattedTextImpl.cs delete mode 100644 src/Skia/Perspex.Skia/Perspex.Skia.projitems delete mode 100644 src/Skia/Perspex.Skia/Perspex.Skia.shproj delete mode 100644 src/Skia/Perspex.Skia/PlatformRenderInterface.cs delete mode 100644 src/Skia/Perspex.Skia/RenderTarget.cs delete mode 100644 src/Skia/Perspex.Skia/SkiaPlatform.cs delete mode 100644 src/Skia/Perspex.Skia/SkiaSharpExtensions.cs delete mode 100644 src/Skia/Perspex.Skia/StreamGeometryImpl.cs delete mode 100644 src/Skia/Perspex.Skia/TypefaceCache.cs delete mode 100644 src/Skia/Perspex.Skia/WindowDrawingContextImpl.cs delete mode 100644 src/Skia/Perspex.Skia/readme.md rename src/Windows/{Perspex.Designer => Avalonia.Designer}/App.config (100%) create mode 100644 src/Windows/Avalonia.Designer/App.xaml create mode 100644 src/Windows/Avalonia.Designer/App.xaml.cs create mode 100644 src/Windows/Avalonia.Designer/AppHost/AvaloniaAppHost.cs create mode 100644 src/Windows/Avalonia.Designer/AppHost/HostedAppModel.cs create mode 100644 src/Windows/Avalonia.Designer/AppHost/WindowHost.cs create mode 100644 src/Windows/Avalonia.Designer/Avalonia.Designer.csproj create mode 100644 src/Windows/Avalonia.Designer/AvaloniaDesigner.xaml create mode 100644 src/Windows/Avalonia.Designer/AvaloniaDesigner.xaml.cs create mode 100644 src/Windows/Avalonia.Designer/Comm/CommChannel.cs create mode 100644 src/Windows/Avalonia.Designer/Comm/InitMessage.cs create mode 100644 src/Windows/Avalonia.Designer/Comm/ProcessHost.cs create mode 100644 src/Windows/Avalonia.Designer/Comm/StateMessage.cs create mode 100644 src/Windows/Avalonia.Designer/Comm/UpdateMetadata.cs create mode 100644 src/Windows/Avalonia.Designer/Comm/UpdateXamlMessage.cs create mode 100644 src/Windows/Avalonia.Designer/Comm/WindowCreatedMessage.cs create mode 100644 src/Windows/Avalonia.Designer/DemoWindow.xaml create mode 100644 src/Windows/Avalonia.Designer/DemoWindow.xaml.cs create mode 100644 src/Windows/Avalonia.Designer/InProcDesigner/InProcDesignerView.xaml create mode 100644 src/Windows/Avalonia.Designer/InProcDesigner/InProcDesignerView.xaml.cs create mode 100644 src/Windows/Avalonia.Designer/Metadata/AvaloniaDesignerMetadata.cs create mode 100644 src/Windows/Avalonia.Designer/Program.cs create mode 100644 src/Windows/Avalonia.Designer/Properties/AssemblyInfo.cs rename src/Windows/{Perspex.Designer => Avalonia.Designer}/README.txt (100%) create mode 100644 src/Windows/Avalonia.Designer/Settings.cs create mode 100644 src/Windows/Avalonia.Designer/WinApi.cs rename src/Windows/{Perspex.Designer/perspex.designer.snk => Avalonia.Designer/avalonia.designer.snk} (100%) rename src/Windows/{Perspex.Designer => Avalonia.Designer}/packages.config (100%) create mode 100644 src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj create mode 100644 src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Disposable.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/AvaloniaTextRenderer.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/BrushWrapper.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/FormattedTextImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/TileBrushImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs create mode 100644 src/Windows/Avalonia.Direct2D1/RenderTarget.cs rename src/Windows/{Perspex.Direct2D1 => Avalonia.Direct2D1}/app.config (100%) rename src/Windows/{Perspex.Direct2D1 => Avalonia.Direct2D1}/packages.config (100%) create mode 100644 src/Windows/Avalonia.Win32/Avalonia.Win32.csproj create mode 100644 src/Windows/Avalonia.Win32/ClipboardImpl.cs create mode 100644 src/Windows/Avalonia.Win32/CursorFactory.cs create mode 100644 src/Windows/Avalonia.Win32/Embedding/EmbeddedWindowImpl.cs create mode 100644 src/Windows/Avalonia.Win32/Input/KeyInterop.cs create mode 100644 src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs create mode 100644 src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs create mode 100644 src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs create mode 100644 src/Windows/Avalonia.Win32/PlatformConstants.cs create mode 100644 src/Windows/Avalonia.Win32/PopupImpl.cs create mode 100644 src/Windows/Avalonia.Win32/Properties/AssemblyInfo.cs rename src/Windows/{Perspex.Win32 => Avalonia.Win32}/Settings.StyleCop (100%) create mode 100644 src/Windows/Avalonia.Win32/SystemDialogImpl.cs create mode 100644 src/Windows/Avalonia.Win32/Win32Platform.cs create mode 100644 src/Windows/Avalonia.Win32/WindowImpl.cs rename src/Windows/{Perspex.Win32 => Avalonia.Win32}/app.config (100%) rename src/Windows/{Perspex.Win32 => Avalonia.Win32}/packages.config (100%) delete mode 100644 src/Windows/Perspex.Designer/App.xaml delete mode 100644 src/Windows/Perspex.Designer/App.xaml.cs delete mode 100644 src/Windows/Perspex.Designer/AppHost/HostedAppModel.cs delete mode 100644 src/Windows/Perspex.Designer/AppHost/PerspexAppHost.cs delete mode 100644 src/Windows/Perspex.Designer/AppHost/WindowHost.cs delete mode 100644 src/Windows/Perspex.Designer/Comm/CommChannel.cs delete mode 100644 src/Windows/Perspex.Designer/Comm/InitMessage.cs delete mode 100644 src/Windows/Perspex.Designer/Comm/ProcessHost.cs delete mode 100644 src/Windows/Perspex.Designer/Comm/StateMessage.cs delete mode 100644 src/Windows/Perspex.Designer/Comm/UpdateMetadata.cs delete mode 100644 src/Windows/Perspex.Designer/Comm/UpdateXamlMessage.cs delete mode 100644 src/Windows/Perspex.Designer/Comm/WindowCreatedMessage.cs delete mode 100644 src/Windows/Perspex.Designer/DemoWindow.xaml delete mode 100644 src/Windows/Perspex.Designer/DemoWindow.xaml.cs delete mode 100644 src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml delete mode 100644 src/Windows/Perspex.Designer/InProcDesigner/InProcDesignerView.xaml.cs delete mode 100644 src/Windows/Perspex.Designer/Metadata/PerspexDesignerMetadata.cs delete mode 100644 src/Windows/Perspex.Designer/Perspex.Designer.csproj delete mode 100644 src/Windows/Perspex.Designer/PerspexDesigner.xaml delete mode 100644 src/Windows/Perspex.Designer/PerspexDesigner.xaml.cs delete mode 100644 src/Windows/Perspex.Designer/Program.cs delete mode 100644 src/Windows/Perspex.Designer/Properties/AssemblyInfo.cs delete mode 100644 src/Windows/Perspex.Designer/Settings.cs delete mode 100644 src/Windows/Perspex.Designer/WinApi.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Direct2D1Platform.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Disposable.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/BrushImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/BrushWrapper.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/DrawingContext.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/FormattedTextImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/GeometryImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/Imaging/BitmapImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/LinearGradientBrushImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/PerspexTextRenderer.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/RadialGradientBrushImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/SolidColorBrushImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/StreamGeometryImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Media/TileBrushImpl.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj delete mode 100644 src/Windows/Perspex.Direct2D1/PrimitiveExtensions.cs delete mode 100644 src/Windows/Perspex.Direct2D1/Properties/AssemblyInfo.cs delete mode 100644 src/Windows/Perspex.Direct2D1/RenderTarget.cs delete mode 100644 src/Windows/Perspex.Win32/ClipboardImpl.cs delete mode 100644 src/Windows/Perspex.Win32/CursorFactory.cs delete mode 100644 src/Windows/Perspex.Win32/Embedding/EmbeddedWindowImpl.cs delete mode 100644 src/Windows/Perspex.Win32/Input/KeyInterop.cs delete mode 100644 src/Windows/Perspex.Win32/Input/WindowsKeyboardDevice.cs delete mode 100644 src/Windows/Perspex.Win32/Input/WindowsMouseDevice.cs delete mode 100644 src/Windows/Perspex.Win32/Interop/UnmanagedMethods.cs delete mode 100644 src/Windows/Perspex.Win32/Perspex.Win32.csproj delete mode 100644 src/Windows/Perspex.Win32/PlatformConstants.cs delete mode 100644 src/Windows/Perspex.Win32/PopupImpl.cs delete mode 100644 src/Windows/Perspex.Win32/Properties/AssemblyInfo.cs delete mode 100644 src/Windows/Perspex.Win32/SystemDialogImpl.cs delete mode 100644 src/Windows/Perspex.Win32/Win32Platform.cs delete mode 100644 src/Windows/Perspex.Win32/WindowImpl.cs create mode 100644 src/iOS/Avalonia.iOS/Avalonia.iOS.csproj create mode 100644 src/iOS/Avalonia.iOS/AvaloniaView.cs create mode 100644 src/iOS/Avalonia.iOS/Clipboard.cs create mode 100644 src/iOS/Avalonia.iOS/CursorFactory.cs create mode 100644 src/iOS/Avalonia.iOS/Extensions.cs create mode 100644 src/iOS/Avalonia.iOS/PlatformSettings.cs create mode 100644 src/iOS/Avalonia.iOS/PlatformThreadingInterface.cs create mode 100644 src/iOS/Avalonia.iOS/Properties/AssemblyInfo.cs create mode 100644 src/iOS/Avalonia.iOS/Specific/KeyboardEventsHelper.cs create mode 100644 src/iOS/Avalonia.iOS/WindowingPlatformImpl.cs create mode 100644 src/iOS/Avalonia.iOS/iOSPlatform.cs create mode 100644 src/iOS/Avalonia.iOSTestApplication/AppDelegate.cs create mode 100644 src/iOS/Avalonia.iOSTestApplication/Avalonia.iOSTestApplication.csproj rename src/iOS/{Perspex.iOSTestApplication => Avalonia.iOSTestApplication}/Entitlements.plist (100%) rename src/iOS/{Perspex.iOSTestApplication => Avalonia.iOSTestApplication}/GettingStarted.Xamarin (100%) create mode 100644 src/iOS/Avalonia.iOSTestApplication/Info.plist create mode 100644 src/iOS/Avalonia.iOSTestApplication/Main.cs create mode 100644 src/iOS/Avalonia.iOSTestApplication/Properties/AssemblyInfo.cs rename src/iOS/{Perspex.iOSTestApplication => Avalonia.iOSTestApplication}/Resources/Default-568h@2x.png (100%) rename src/iOS/{Perspex.iOSTestApplication => Avalonia.iOSTestApplication}/packages.config (100%) delete mode 100644 src/iOS/Perspex.iOS/Clipboard.cs delete mode 100644 src/iOS/Perspex.iOS/CursorFactory.cs delete mode 100644 src/iOS/Perspex.iOS/Extensions.cs delete mode 100644 src/iOS/Perspex.iOS/Perspex.iOS.csproj delete mode 100644 src/iOS/Perspex.iOS/PerspexView.cs delete mode 100644 src/iOS/Perspex.iOS/PlatformSettings.cs delete mode 100644 src/iOS/Perspex.iOS/PlatformThreadingInterface.cs delete mode 100644 src/iOS/Perspex.iOS/Properties/AssemblyInfo.cs delete mode 100644 src/iOS/Perspex.iOS/Specific/KeyboardEventsHelper.cs delete mode 100644 src/iOS/Perspex.iOS/WindowingPlatformImpl.cs delete mode 100644 src/iOS/Perspex.iOS/iOSPlatform.cs delete mode 100644 src/iOS/Perspex.iOSTestApplication/AppDelegate.cs delete mode 100644 src/iOS/Perspex.iOSTestApplication/Info.plist delete mode 100644 src/iOS/Perspex.iOSTestApplication/Main.cs delete mode 100644 src/iOS/Perspex.iOSTestApplication/Perspex.iOSTestApplication.csproj delete mode 100644 src/iOS/Perspex.iOSTestApplication/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.Base.UnitTests/AttachedPropertyTests.cs create mode 100644 tests/Avalonia.Base.UnitTests/Avalonia.Base.UnitTests.csproj create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_GetObservable.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_GetSubject.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_GetValue.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Metadata.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Validation.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs create mode 100644 tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs create mode 100644 tests/Avalonia.Base.UnitTests/Collections/AvaloniaDictionaryTests.cs create mode 100644 tests/Avalonia.Base.UnitTests/Collections/AvaloniaListTests.cs create mode 100644 tests/Avalonia.Base.UnitTests/Collections/CollectionChangedTracker.cs create mode 100644 tests/Avalonia.Base.UnitTests/Collections/PropertyChangedTracker.cs create mode 100644 tests/Avalonia.Base.UnitTests/DirectPropertyTests.cs create mode 100644 tests/Avalonia.Base.UnitTests/PriorityValueTests.cs create mode 100644 tests/Avalonia.Base.UnitTests/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.Base.UnitTests/StyledPropertyTests.cs create mode 100644 tests/Avalonia.Base.UnitTests/WeakSubscriptionManagerTests.cs rename tests/{Perspex.Base.UnitTests => Avalonia.Base.UnitTests}/app.config (100%) rename tests/{Perspex.Base.UnitTests => Avalonia.Base.UnitTests}/packages.config (100%) rename tests/{Perspex.Benchmarks => Avalonia.Benchmarks}/App.config (100%) create mode 100644 tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj create mode 100644 tests/Avalonia.Benchmarks/Program.cs create mode 100644 tests/Avalonia.Benchmarks/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.Benchmarks/Styling/ApplyStyling.cs rename tests/{Perspex.Benchmarks => Avalonia.Benchmarks}/packages.config (100%) create mode 100644 tests/Avalonia.Controls.UnitTests/Avalonia.Controls.UnitTests.csproj create mode 100644 tests/Avalonia.Controls.UnitTests/BorderTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/CarouselTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/ClassesTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/ContentControlTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/ControlTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/ControlTests_NameScope.cs create mode 100644 tests/Avalonia.Controls.UnitTests/DecoratorTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/DockPanelTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/DropDownTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/EnumerableExtensions.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTypedTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/GridLengthTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/GridSplitterTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/GridTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/HeaderedItemsControlTests .cs create mode 100644 tests/Avalonia.Controls.UnitTests/ImageTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/LayoutTransformControlTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/ListBoxTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Mixins/SelectableMixinTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/NameScopeTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/PanelTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Presenters/CarouselPresenterTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Presenters/ItemsPresenterTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Presenters/ScrollContentPresenterTests_IScrollable.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Primitives/ScrollBarTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Primitives/TrackTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.Controls.UnitTests/ScrollViewerTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/StackPanelTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/TabControlTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Templates/TemplateExtensionsTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/TestTemplatedControl.cs create mode 100644 tests/Avalonia.Controls.UnitTests/TextBlockTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/TextBoxTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/TopLevelTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/TreeViewTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/UserControlTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Utils/AncestorFinderTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/WindowTests.cs create mode 100644 tests/Avalonia.Controls.UnitTests/WindowingPlatformMock.cs create mode 100644 tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs rename tests/{Perspex.Controls.UnitTests => Avalonia.Controls.UnitTests}/app.config (100%) rename tests/{Perspex.Controls.UnitTests => Avalonia.Controls.UnitTests}/packages.config (100%) create mode 100644 tests/Avalonia.Direct2D1.UnitTests/Avalonia.Direct2D1.UnitTests.csproj create mode 100644 tests/Avalonia.Direct2D1.UnitTests/Controls/Shapes/PathTests.cs create mode 100644 tests/Avalonia.Direct2D1.UnitTests/Media/GeometryTests.cs create mode 100644 tests/Avalonia.Direct2D1.UnitTests/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.Direct2D1.UnitTests/RectComparer.cs rename tests/{Perspex.Direct2D1.UnitTests => Avalonia.Direct2D1.UnitTests}/app.config (100%) rename tests/{Perspex.Direct2D1.UnitTests => Avalonia.Direct2D1.UnitTests}/packages.config (100%) create mode 100644 tests/Avalonia.Input.UnitTests/Avalonia.Input.UnitTests.csproj create mode 100644 tests/Avalonia.Input.UnitTests/InputElement_Focus.cs create mode 100644 tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs create mode 100644 tests/Avalonia.Input.UnitTests/KeyGestureParseTests.cs create mode 100644 tests/Avalonia.Input.UnitTests/KeyboardNavigationTests_Arrows.cs create mode 100644 tests/Avalonia.Input.UnitTests/KeyboardNavigationTests_Tab.cs create mode 100644 tests/Avalonia.Input.UnitTests/Properties/AssemblyInfo.cs rename tests/{Perspex.Input.UnitTests => Avalonia.Input.UnitTests}/app.config (100%) rename tests/{Perspex.Input.UnitTests => Avalonia.Input.UnitTests}/packages.config (100%) create mode 100644 tests/Avalonia.Interactivity.UnitTests/Avalonia.Interactivity.UnitTests.csproj create mode 100644 tests/Avalonia.Interactivity.UnitTests/GestureTests.cs create mode 100644 tests/Avalonia.Interactivity.UnitTests/InteractiveTests.cs create mode 100644 tests/Avalonia.Interactivity.UnitTests/Properties/AssemblyInfo.cs rename tests/{Perspex.Interactivity.UnitTests => Avalonia.Interactivity.UnitTests}/packages.config (100%) create mode 100644 tests/Avalonia.Layout.UnitTests/ArrangeTests.cs create mode 100644 tests/Avalonia.Layout.UnitTests/Avalonia.Layout.UnitTests.csproj create mode 100644 tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs create mode 100644 tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs create mode 100644 tests/Avalonia.Layout.UnitTests/MeasureTests.cs create mode 100644 tests/Avalonia.Layout.UnitTests/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.Layout.UnitTests/TestLayoutRoot.cs rename tests/{Perspex.Layout.UnitTests => Avalonia.Layout.UnitTests}/app.config (100%) rename tests/{Perspex.Layout.UnitTests => Avalonia.Layout.UnitTests}/packages.config (100%) create mode 100644 tests/Avalonia.LeakTests/Avalonia.LeakTests.csproj create mode 100644 tests/Avalonia.LeakTests/ControlTests.cs create mode 100644 tests/Avalonia.LeakTests/Properties/AssemblyInfo.cs rename tests/{Perspex.LeakTests => Avalonia.LeakTests}/Readme.txt (100%) rename tests/{Perspex.LeakTests => Avalonia.LeakTests}/app.config (100%) rename tests/{Perspex.LeakTests => Avalonia.LeakTests}/packages.config (100%) create mode 100644 tests/Avalonia.Markup.UnitTests/Avalonia.Markup.UnitTests.csproj create mode 100644 tests/Avalonia.Markup.UnitTests/ControlLocatorTests.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExceptionValidatorTests.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionNodeBuilderTests.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionNodeBuilderTests_Errors.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_AttachedProperty.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_AvaloniaProperty.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Indexer.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Lifetime.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Negation.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Observable.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Property.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_SetValue.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Task.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/ExpressionSubjectTests.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Data/IndeiValidatorTests.cs create mode 100644 tests/Avalonia.Markup.UnitTests/DefaultValueConverterTests.cs create mode 100644 tests/Avalonia.Markup.UnitTests/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.Markup.UnitTests/UnitTestSynchronizationContext.cs rename tests/{Perspex.Markup.UnitTests => Avalonia.Markup.UnitTests}/app.config (100%) rename tests/{Perspex.Markup.UnitTests => Avalonia.Markup.UnitTests}/packages.config (100%) create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Avalonia.Markup.Xaml.UnitTests.csproj create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Converters/AvaloniaPropertyConverterTest.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Source.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Validation.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Parsers/SelectorGrammarTests.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/SampleAvaloniaObject.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/StyleTests.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Templates/DataTemplateTests.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/TestViewModel.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/TypeProviderMock.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlBindingTests.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/InitializationOrderTracker.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/NonControl.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/Style1.xaml create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/Style2.xaml create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs rename tests/{Perspex.Markup.Xaml.UnitTests => Avalonia.Markup.Xaml.UnitTests}/app.config (100%) rename tests/{Perspex.Markup.Xaml.UnitTests => Avalonia.Markup.Xaml.UnitTests}/packages.config (100%) create mode 100644 tests/Avalonia.RenderTests/Avalonia.Cairo.RenderTests.csproj create mode 100644 tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.csproj create mode 100644 tests/Avalonia.RenderTests/Avalonia.Skia.RenderTests.csproj create mode 100644 tests/Avalonia.RenderTests/Controls/BorderTests.cs create mode 100644 tests/Avalonia.RenderTests/Controls/ImageTests.cs create mode 100644 tests/Avalonia.RenderTests/Media/ImageBrushTests.cs create mode 100644 tests/Avalonia.RenderTests/Media/LinearGradientBrushTests.cs create mode 100644 tests/Avalonia.RenderTests/Media/VisualBrushTests.cs create mode 100644 tests/Avalonia.RenderTests/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.RenderTests/Shapes/EllipseTests.cs create mode 100644 tests/Avalonia.RenderTests/Shapes/LineTests.cs create mode 100644 tests/Avalonia.RenderTests/Shapes/PathTests.cs create mode 100644 tests/Avalonia.RenderTests/Shapes/PolygonTests.cs create mode 100644 tests/Avalonia.RenderTests/Shapes/PolylineTests.cs create mode 100644 tests/Avalonia.RenderTests/Shapes/RectangleTests.cs create mode 100644 tests/Avalonia.RenderTests/TestBase.cs rename tests/{Perspex.RenderTests => Avalonia.RenderTests}/app.config (100%) rename tests/{Perspex.RenderTests/packages.Perspex.Cairo.RenderTests.config => Avalonia.RenderTests/packages.Avalonia.Cairo.RenderTests.config} (100%) rename tests/{Perspex.RenderTests/packages.Perspex.Direct2D1.RenderTests.config => Avalonia.RenderTests/packages.Avalonia.Direct2D1.RenderTests.config} (100%) rename tests/{Perspex.RenderTests/packages.Perspex.Skia.RenderTests.config => Avalonia.RenderTests/packages.Avalonia.Skia.RenderTests.config} (100%) create mode 100644 tests/Avalonia.SceneGraph.UnitTests/Avalonia.SceneGraph.UnitTests.csproj create mode 100644 tests/Avalonia.SceneGraph.UnitTests/Media/BrushTests.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/Media/ColorTests.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/RelativePointTests.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/RelativeRectComparer.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/RelativeRectTests.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/RenderTests_Culling.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/TestRoot.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/TestVisual.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/ThicknessTests.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/VisualTests.cs create mode 100644 tests/Avalonia.SceneGraph.UnitTests/VisualTree/BoundsTrackerTests.cs rename tests/{Perspex.SceneGraph.UnitTests => Avalonia.SceneGraph.UnitTests}/app.config (100%) rename tests/{Perspex.SceneGraph.UnitTests => Avalonia.SceneGraph.UnitTests}/packages.config (100%) create mode 100644 tests/Avalonia.Styling.UnitTests/ActivatedObservableTests.cs create mode 100644 tests/Avalonia.Styling.UnitTests/ActivatedSubjectTests.cs create mode 100644 tests/Avalonia.Styling.UnitTests/ActivatedValueTests.cs create mode 100644 tests/Avalonia.Styling.UnitTests/Avalonia.Styling.UnitTests.csproj create mode 100644 tests/Avalonia.Styling.UnitTests/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.Styling.UnitTests/ResourceTests.cs create mode 100644 tests/Avalonia.Styling.UnitTests/SelectorTests_Child.cs create mode 100644 tests/Avalonia.Styling.UnitTests/SelectorTests_Class.cs create mode 100644 tests/Avalonia.Styling.UnitTests/SelectorTests_Descendent.cs create mode 100644 tests/Avalonia.Styling.UnitTests/SelectorTests_Multiple.cs create mode 100644 tests/Avalonia.Styling.UnitTests/SelectorTests_Name.cs create mode 100644 tests/Avalonia.Styling.UnitTests/SelectorTests_OfType.cs create mode 100644 tests/Avalonia.Styling.UnitTests/SelectorTests_PropertyEquals.cs create mode 100644 tests/Avalonia.Styling.UnitTests/SelectorTests_Template.cs create mode 100644 tests/Avalonia.Styling.UnitTests/SetterTests.cs create mode 100644 tests/Avalonia.Styling.UnitTests/StyleActivatorTests.cs create mode 100644 tests/Avalonia.Styling.UnitTests/StyleTests.cs create mode 100644 tests/Avalonia.Styling.UnitTests/TestControlBase.cs create mode 100644 tests/Avalonia.Styling.UnitTests/TestObservable.cs create mode 100644 tests/Avalonia.Styling.UnitTests/TestObserver.cs create mode 100644 tests/Avalonia.Styling.UnitTests/TestSelectors.cs create mode 100644 tests/Avalonia.Styling.UnitTests/TestSubject.cs create mode 100644 tests/Avalonia.Styling.UnitTests/TestTemplatedControl.cs rename tests/{Perspex.Styling.UnitTests => Avalonia.Styling.UnitTests}/app.config (100%) rename tests/{Perspex.Styling.UnitTests => Avalonia.Styling.UnitTests}/packages.config (100%) create mode 100644 tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj create mode 100644 tests/Avalonia.UnitTests/MockWindowingPlatform.cs create mode 100644 tests/Avalonia.UnitTests/NotifyingBase.cs create mode 100644 tests/Avalonia.UnitTests/Properties/AssemblyInfo.cs create mode 100644 tests/Avalonia.UnitTests/TestLogSink.cs create mode 100644 tests/Avalonia.UnitTests/TestRoot.cs create mode 100644 tests/Avalonia.UnitTests/TestServices.cs create mode 100644 tests/Avalonia.UnitTests/TestTemplatedRoot.cs create mode 100644 tests/Avalonia.UnitTests/UnitTestApplication.cs rename tests/{Perspex.UnitTests => Avalonia.UnitTests}/app.config (100%) rename tests/{Perspex.UnitTests => Avalonia.UnitTests}/packages.config (100%) delete mode 100644 tests/Perspex.Base.UnitTests/AttachedPropertyTests.cs delete mode 100644 tests/Perspex.Base.UnitTests/Collections/CollectionChangedTracker.cs delete mode 100644 tests/Perspex.Base.UnitTests/Collections/PerspexDictionaryTests.cs delete mode 100644 tests/Perspex.Base.UnitTests/Collections/PerspexListTests.cs delete mode 100644 tests/Perspex.Base.UnitTests/Collections/PropertyChangedTracker.cs delete mode 100644 tests/Perspex.Base.UnitTests/DirectPropertyTests.cs delete mode 100644 tests/Perspex.Base.UnitTests/Perspex.Base.UnitTests.csproj delete mode 100644 tests/Perspex.Base.UnitTests/PerspexObjectTests_Binding.cs delete mode 100644 tests/Perspex.Base.UnitTests/PerspexObjectTests_Direct.cs delete mode 100644 tests/Perspex.Base.UnitTests/PerspexObjectTests_GetObservable.cs delete mode 100644 tests/Perspex.Base.UnitTests/PerspexObjectTests_GetSubject.cs delete mode 100644 tests/Perspex.Base.UnitTests/PerspexObjectTests_GetValue.cs delete mode 100644 tests/Perspex.Base.UnitTests/PerspexObjectTests_Inheritance.cs delete mode 100644 tests/Perspex.Base.UnitTests/PerspexObjectTests_Metadata.cs delete mode 100644 tests/Perspex.Base.UnitTests/PerspexObjectTests_SetValue.cs delete mode 100644 tests/Perspex.Base.UnitTests/PerspexObjectTests_Validation.cs delete mode 100644 tests/Perspex.Base.UnitTests/PerspexPropertyRegistryTests.cs delete mode 100644 tests/Perspex.Base.UnitTests/PerspexPropertyTests.cs delete mode 100644 tests/Perspex.Base.UnitTests/PriorityValueTests.cs delete mode 100644 tests/Perspex.Base.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Base.UnitTests/StyledPropertyTests.cs delete mode 100644 tests/Perspex.Base.UnitTests/WeakSubscriptionManagerTests.cs delete mode 100644 tests/Perspex.Benchmarks/Perspex.Benchmarks.csproj delete mode 100644 tests/Perspex.Benchmarks/Program.cs delete mode 100644 tests/Perspex.Benchmarks/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Benchmarks/Styling/ApplyStyling.cs delete mode 100644 tests/Perspex.Controls.UnitTests/BorderTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/CarouselTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/ClassesTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/ContentControlTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/ControlTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/ControlTests_NameScope.cs delete mode 100644 tests/Perspex.Controls.UnitTests/DecoratorTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/DockPanelTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/DropDownTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/EnumerableExtensions.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Generators/ItemContainerGeneratorTypedTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/GridLengthTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/GridSplitterTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/GridTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/HeaderedItemsControlTests .cs delete mode 100644 tests/Perspex.Controls.UnitTests/ImageTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/ItemsControlTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/LayoutTransformControlTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/ListBoxTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/ListBoxTests_Single.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Mixins/SelectableMixinTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/NameScopeTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/PanelTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj delete mode 100644 tests/Perspex.Controls.UnitTests/Presenters/CarouselPresenterTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Presenters/ContentPresenterTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Presenters/ItemsPresenterTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Presenters/ScrollContentPresenterTests_IScrollable.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Primitives/PopupTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Primitives/RangeBaseTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Primitives/ScrollBarTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_AutoSelect.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests_Multiple.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Primitives/TabStripTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Primitives/TemplatedControlTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Primitives/TrackTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Controls.UnitTests/ScrollViewerTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/StackPanelTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/TabControlTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Templates/TemplateExtensionsTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/TestTemplatedControl.cs delete mode 100644 tests/Perspex.Controls.UnitTests/TextBlockTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/TextBoxTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/TopLevelTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/TreeViewTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/UserControlTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Utils/AncestorFinderTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/Utils/HotKeyManagerTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/WindowTests.cs delete mode 100644 tests/Perspex.Controls.UnitTests/WindowingPlatformMock.cs delete mode 100644 tests/Perspex.Controls.UnitTests/WrapPanelTests.cs delete mode 100644 tests/Perspex.Direct2D1.UnitTests/Controls/Shapes/PathTests.cs delete mode 100644 tests/Perspex.Direct2D1.UnitTests/Media/GeometryTests.cs delete mode 100644 tests/Perspex.Direct2D1.UnitTests/Perspex.Direct2D1.UnitTests.csproj delete mode 100644 tests/Perspex.Direct2D1.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Direct2D1.UnitTests/RectComparer.cs delete mode 100644 tests/Perspex.Input.UnitTests/InputElement_Focus.cs delete mode 100644 tests/Perspex.Input.UnitTests/InputElement_HitTesting.cs delete mode 100644 tests/Perspex.Input.UnitTests/KeyGestureParseTests.cs delete mode 100644 tests/Perspex.Input.UnitTests/KeyboardNavigationTests_Arrows.cs delete mode 100644 tests/Perspex.Input.UnitTests/KeyboardNavigationTests_Tab.cs delete mode 100644 tests/Perspex.Input.UnitTests/Perspex.Input.UnitTests.csproj delete mode 100644 tests/Perspex.Input.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Interactivity.UnitTests/GestureTests.cs delete mode 100644 tests/Perspex.Interactivity.UnitTests/InteractiveTests.cs delete mode 100644 tests/Perspex.Interactivity.UnitTests/Perspex.Interactivity.UnitTests.csproj delete mode 100644 tests/Perspex.Interactivity.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Layout.UnitTests/ArrangeTests.cs delete mode 100644 tests/Perspex.Layout.UnitTests/FullLayoutTests.cs delete mode 100644 tests/Perspex.Layout.UnitTests/LayoutManagerTests.cs delete mode 100644 tests/Perspex.Layout.UnitTests/MeasureTests.cs delete mode 100644 tests/Perspex.Layout.UnitTests/Perspex.Layout.UnitTests.csproj delete mode 100644 tests/Perspex.Layout.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Layout.UnitTests/TestLayoutRoot.cs delete mode 100644 tests/Perspex.LeakTests/ControlTests.cs delete mode 100644 tests/Perspex.LeakTests/Perspex.LeakTests.csproj delete mode 100644 tests/Perspex.LeakTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Markup.UnitTests/ControlLocatorTests.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExceptionValidatorTests.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionNodeBuilderTests.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionNodeBuilderTests_Errors.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_AttachedProperty.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_Indexer.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_Lifetime.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_Negation.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_Observable.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_PerspexProperty.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_Property.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_SetValue.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_Task.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/ExpressionSubjectTests.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Data/IndeiValidatorTests.cs delete mode 100644 tests/Perspex.Markup.UnitTests/DefaultValueConverterTests.cs delete mode 100644 tests/Perspex.Markup.UnitTests/Perspex.Markup.UnitTests.csproj delete mode 100644 tests/Perspex.Markup.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Markup.UnitTests/UnitTestSynchronizationContext.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Converters/PerspexPropertyConverterTest.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_ElementName.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_Source.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Data/BindingTests_Validation.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Parsers/SelectorGrammarTests.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/SamplePerspexObject.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/StyleTests.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Templates/DataTemplateTests.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/TestViewModel.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/TypeProviderMock.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Xaml/BasicTests.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Xaml/BindingTests.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Xaml/ControlBindingTests.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Xaml/InitializationOrderTracker.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Xaml/NonControl.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Xaml/Style1.xaml delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Xaml/Style2.xaml delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Xaml/StyleTests.cs delete mode 100644 tests/Perspex.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs delete mode 100644 tests/Perspex.RenderTests/Controls/BorderTests.cs delete mode 100644 tests/Perspex.RenderTests/Controls/ImageTests.cs delete mode 100644 tests/Perspex.RenderTests/Media/ImageBrushTests.cs delete mode 100644 tests/Perspex.RenderTests/Media/LinearGradientBrushTests.cs delete mode 100644 tests/Perspex.RenderTests/Media/VisualBrushTests.cs delete mode 100644 tests/Perspex.RenderTests/Perspex.Cairo.RenderTests.csproj delete mode 100644 tests/Perspex.RenderTests/Perspex.Direct2D1.RenderTests.csproj delete mode 100644 tests/Perspex.RenderTests/Perspex.Skia.RenderTests.csproj delete mode 100644 tests/Perspex.RenderTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.RenderTests/Shapes/EllipseTests.cs delete mode 100644 tests/Perspex.RenderTests/Shapes/LineTests.cs delete mode 100644 tests/Perspex.RenderTests/Shapes/PathTests.cs delete mode 100644 tests/Perspex.RenderTests/Shapes/PolygonTests.cs delete mode 100644 tests/Perspex.RenderTests/Shapes/PolylineTests.cs delete mode 100644 tests/Perspex.RenderTests/Shapes/RectangleTests.cs delete mode 100644 tests/Perspex.RenderTests/TestBase.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/Media/BrushTests.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/Media/ColorTests.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/Perspex.SceneGraph.UnitTests.csproj delete mode 100644 tests/Perspex.SceneGraph.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/RelativePointTests.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/RelativeRectComparer.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/RelativeRectTests.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/RenderTests_Culling.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/TestRoot.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/TestVisual.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/ThicknessTests.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/VisualTests.cs delete mode 100644 tests/Perspex.SceneGraph.UnitTests/VisualTree/BoundsTrackerTests.cs delete mode 100644 tests/Perspex.Styling.UnitTests/ActivatedObservableTests.cs delete mode 100644 tests/Perspex.Styling.UnitTests/ActivatedSubjectTests.cs delete mode 100644 tests/Perspex.Styling.UnitTests/ActivatedValueTests.cs delete mode 100644 tests/Perspex.Styling.UnitTests/Perspex.Styling.UnitTests.csproj delete mode 100644 tests/Perspex.Styling.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.Styling.UnitTests/ResourceTests.cs delete mode 100644 tests/Perspex.Styling.UnitTests/SelectorTests_Child.cs delete mode 100644 tests/Perspex.Styling.UnitTests/SelectorTests_Class.cs delete mode 100644 tests/Perspex.Styling.UnitTests/SelectorTests_Descendent.cs delete mode 100644 tests/Perspex.Styling.UnitTests/SelectorTests_Multiple.cs delete mode 100644 tests/Perspex.Styling.UnitTests/SelectorTests_Name.cs delete mode 100644 tests/Perspex.Styling.UnitTests/SelectorTests_OfType.cs delete mode 100644 tests/Perspex.Styling.UnitTests/SelectorTests_PropertyEquals.cs delete mode 100644 tests/Perspex.Styling.UnitTests/SelectorTests_Template.cs delete mode 100644 tests/Perspex.Styling.UnitTests/SetterTests.cs delete mode 100644 tests/Perspex.Styling.UnitTests/StyleActivatorTests.cs delete mode 100644 tests/Perspex.Styling.UnitTests/StyleTests.cs delete mode 100644 tests/Perspex.Styling.UnitTests/TestControlBase.cs delete mode 100644 tests/Perspex.Styling.UnitTests/TestObservable.cs delete mode 100644 tests/Perspex.Styling.UnitTests/TestObserver.cs delete mode 100644 tests/Perspex.Styling.UnitTests/TestSelectors.cs delete mode 100644 tests/Perspex.Styling.UnitTests/TestSubject.cs delete mode 100644 tests/Perspex.Styling.UnitTests/TestTemplatedControl.cs delete mode 100644 tests/Perspex.UnitTests/MockWindowingPlatform.cs delete mode 100644 tests/Perspex.UnitTests/NotifyingBase.cs delete mode 100644 tests/Perspex.UnitTests/Perspex.UnitTests.csproj delete mode 100644 tests/Perspex.UnitTests/Properties/AssemblyInfo.cs delete mode 100644 tests/Perspex.UnitTests/TestLogSink.cs delete mode 100644 tests/Perspex.UnitTests/TestRoot.cs delete mode 100644 tests/Perspex.UnitTests/TestServices.cs delete mode 100644 tests/Perspex.UnitTests/TestTemplatedRoot.cs delete mode 100644 tests/Perspex.UnitTests/UnitTestApplication.cs diff --git a/.gitmodules b/.gitmodules index daef52a069..71dae69105 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,13 +1,13 @@ -[submodule "src/Perspex.ReactiveUI/src"] - path = src/Perspex.ReactiveUI/src +[submodule "src/Avalonia.ReactiveUI/src"] + path = src/Avalonia.ReactiveUI/src url = https://github.com/reactiveui/ReactiveUI.git -[submodule "src/Perspex.HtmlRenderer/external"] - path = src/Perspex.HtmlRenderer/external +[submodule "src/Avalonia.HtmlRenderer/external"] + path = src/Avalonia.HtmlRenderer/external url = https://github.com/Perspex/HTML-Renderer.git branch = perspex-pcl -[submodule "src/Markup/Perspex.Markup.Xaml/OmniXAML"] - path = src/Markup/Perspex.Markup.Xaml/OmniXAML +[submodule "src/Markup/Avalonia.Markup.Xaml/OmniXAML"] + path = src/Markup/Avalonia.Markup.Xaml/OmniXAML url = https://github.com/Perspex/OmniXAML.git -[submodule "src/Markup/Perspex.Markup.Xaml/glass"] - path = src/Markup/Perspex.Markup.Xaml/glass +[submodule "src/Markup/Avalonia.Markup.Xaml/glass"] + path = src/Markup/Avalonia.Markup.Xaml/glass url = https://github.com/SuperJMN/glass diff --git a/Avalonia.sln b/Avalonia.sln new file mode 100644 index 0000000000..3b885312df --- /dev/null +++ b/Avalonia.sln @@ -0,0 +1,1888 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.SceneGraph", "src\Avalonia.SceneGraph\Avalonia.SceneGraph.csproj", "{EB582467-6ABB-43A1-B052-E981BA910E3A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Layout", "src\Avalonia.Layout\Avalonia.Layout.csproj", "{42472427-4774-4C81-8AFF-9F27B8E31721}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Windows", "Windows", "{B39A8919-9F95-48FE-AD7B-76E08B509888}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32", "src\Windows\Avalonia.Win32\Avalonia.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Direct2D1", "src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Designer", "src\Windows\Avalonia.Designer\Avalonia.Designer.csproj", "{EC42600F-049B-43FF-AED1-8314D61B2749}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Input", "src\Avalonia.Input\Avalonia.Input.csproj", "{62024B2D-53EB-4638-B26B-85EEAA54866E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Interactivity", "src\Avalonia.Interactivity\Avalonia.Interactivity.csproj", "{6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Controls", "src\Avalonia.Controls\Avalonia.Controls.csproj", "{D2221C82-4A25-4583-9B43-D791E3F6820C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Styling", "src\Avalonia.Styling\Avalonia.Styling.csproj", "{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Themes.Default", "src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Diagnostics", "src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj", "{7062AE20-5DCC-4442-9645-8195BDECE63E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Animation", "src\Avalonia.Animation\Avalonia.Animation.csproj", "{D211E587-D8BC-45B9-95A4-F297C8FA5200}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Styling.UnitTests", "tests\Avalonia.Styling.UnitTests\Avalonia.Styling.UnitTests.csproj", "{47ECDF59-DEF8-4C53-87B1-2098A3429059}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Controls.UnitTests", "tests\Avalonia.Controls.UnitTests\Avalonia.Controls.UnitTests.csproj", "{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.SceneGraph.UnitTests", "tests\Avalonia.SceneGraph.UnitTests\Avalonia.SceneGraph.UnitTests.csproj", "{76716382-3159-460E-BDA6-C5715CF606D7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Base.UnitTests", "tests\Avalonia.Base.UnitTests\Avalonia.Base.UnitTests.csproj", "{2905FF23-53FB-45E6-AA49-6AF47A172056}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Layout.UnitTests", "tests\Avalonia.Layout.UnitTests\Avalonia.Layout.UnitTests.csproj", "{DB070A10-BF39-4752-8456-86E9D5928478}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Interactivity.UnitTests", "tests\Avalonia.Interactivity.UnitTests\Avalonia.Interactivity.UnitTests.csproj", "{08478EF5-44E8-42E9-92D6-15E00EC038D8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Direct2D1.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Direct2D1.RenderTests.csproj", "{DABFD304-D6A4-4752-8123-C2CCF7AC7831}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Input.UnitTests", "tests\Avalonia.Input.UnitTests\Avalonia.Input.UnitTests.csproj", "{AC18926A-E784-40FE-B09D-BB0FE2B599F0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Direct2D1.UnitTests", "tests\Avalonia.Direct2D1.UnitTests\Avalonia.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Cairo.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Cairo.RenderTests.csproj", "{E106CF37-4066-4615-B684-172A6D30B058}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Markup.Xaml.UnitTests", "tests\Avalonia.Markup.Xaml.UnitTests\Avalonia.Markup.Xaml.UnitTests.csproj", "{99135EAB-653D-47E4-A378-C96E1278CA44}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Markup", "Markup", "{8B6A8209-894F-4BA1-B880-965FD453982C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Markup.Xaml", "src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj", "{3E53A01A-B331-47F3-B828-4A5717E77A24}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{9B9E3891-2366-4253-A952-D08BCEB71098}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication", "samples\TestApplication\TestApplication.csproj", "{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}" + ProjectSection(ProjectDependencies) = postProject + {3E908F67-5543-4879-A1DC-08EACE79B3CD} = {3E908F67-5543-4879-A1DC-08EACE79B3CD} + {FB05AC90-89BA-4F2F-A924-F37875FB547C} = {FB05AC90-89BA-4F2F-A924-F37875FB547C} + {811A76CF-1CF6-440F-963B-BBE31BD72A82} = {811A76CF-1CF6-440F-963B-BBE31BD72A82} + {54F237D5-A70A-4752-9656-0C70B1A7B047} = {54F237D5-A70A-4752-9656-0C70B1A7B047} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplication", "samples\XamlTestApplication\XamlTestApplication.csproj", "{78CAFE33-DBEB-4132-8A28-81CFE8A4933C}" + ProjectSection(ProjectDependencies) = postProject + {3E908F67-5543-4879-A1DC-08EACE79B3CD} = {3E908F67-5543-4879-A1DC-08EACE79B3CD} + {FB05AC90-89BA-4F2F-A924-F37875FB547C} = {FB05AC90-89BA-4F2F-A924-F37875FB547C} + {811A76CF-1CF6-440F-963B-BBE31BD72A82} = {811A76CF-1CF6-440F-963B-BBE31BD72A82} + {54F237D5-A70A-4752-9656-0C70B1A7B047} = {54F237D5-A70A-4752-9656-0C70B1A7B047} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DEF5-D50F-4975-8B72-124C9EB54066}" + ProjectSection(SolutionItems) = preProject + src\Shared\SharedAssemblyInfo.cs = src\Shared\SharedAssemblyInfo.cs + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gtk", "Gtk", "{B9894058-278A-46B5-B6ED-AD613FCC03B3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Gtk", "src\Gtk\Avalonia.Gtk\Avalonia.Gtk.csproj", "{54F237D5-A70A-4752-9656-0C70B1A7B047}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Cairo", "src\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj", "{FB05AC90-89BA-4F2F-A924-F37875FB547C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.ReactiveUI", "src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.HtmlRenderer", "src\Avalonia.HtmlRenderer\Avalonia.HtmlRenderer.csproj", "{5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlatformSupport", "src\Shared\PlatformSupport\PlatformSupport.shproj", "{E4D9629C-F168-4224-3F51-A5E482FFBC42}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Markup", "src\Markup\Avalonia.Markup\Avalonia.Markup.csproj", "{6417E941-21BC-467B-A771-0DE389353CE6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Markup.UnitTests", "tests\Avalonia.Markup.UnitTests\Avalonia.Markup.UnitTests.csproj", "{8EF392D5-1416-45AA-9956-7CBBC3229E8A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BindingTest", "samples\BindingTest\BindingTest.csproj", "{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}" + ProjectSection(ProjectDependencies) = postProject + {B61B66A3-B82D-4875-8001-89D3394FE0C9} = {B61B66A3-B82D-4875-8001-89D3394FE0C9} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplicationPcl", "samples\XamlTestApplicationPcl\XamlTestApplicationPcl.csproj", "{EA113F1A-D8D7-4142-9948-353270E7EBAE}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "src\Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Skia", "Skia", "{3743B0F2-CC41-4F14-A8C8-267F579BF91E}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Avalonia.Skia", "src\Skia\Avalonia.Skia\Avalonia.Skia.shproj", "{2F59F3D0-748D-4652-B01E-E0D954756308}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Desktop", "src\Skia\Avalonia.Skia.Desktop\Avalonia.Skia.Desktop.csproj", "{925DD807-B651-475F-9F7C-CBEB974CE43D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Android", "src\Skia\Avalonia.Skia.Android\Avalonia.Skia.Android.csproj", "{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Android.TestApp", "src\Skia\Avalonia.Skia.Android.TestApp\Avalonia.Skia.Android.TestApp.csproj", "{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.iOS.TestApp", "src\Skia\Avalonia.Skia.iOS.TestApp\Avalonia.Skia.iOS.TestApp.csproj", "{DA49C5F3-BE95-461C-B999-072128CCF59E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.iOS", "src\Skia\Avalonia.Skia.iOS\Avalonia.Skia.iOS.csproj", "{47BE08A7-5985-410B-9FFC-2264B8EA595F}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "TestApplicationShared", "samples\TestApplicationShared\TestApplicationShared.shproj", "{78345174-5B52-4A14-B9FD-D5F2428137F0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Android", "src\Android\Avalonia.Android\Avalonia.Android.csproj", "{7B92AF71-6287-4693-9DCB-BD5B6E927E23}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.AndroidTestApplication", "src\Android\Avalonia.AndroidTestApplication\Avalonia.AndroidTestApplication.csproj", "{FF69B927-C545-49AE-8E16-3D14D621AA12}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "iOS", "iOS", "{0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.iOS", "src\iOS\Avalonia.iOS\Avalonia.iOS.csproj", "{4488AD85-1495-4809-9AA4-DDFE0A48527E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.iOSTestApplication", "src\iOS\Avalonia.iOSTestApplication\Avalonia.iOSTestApplication.csproj", "{8C923867-8A8F-4F6B-8B80-47D9E8436166}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.LeakTests", "tests\Avalonia.LeakTests\Avalonia.LeakTests.csproj", "{E1AA3DBF-9056-4530-9376-18119A7A3FFE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.UnitTests", "tests\Avalonia.UnitTests\Avalonia.UnitTests.csproj", "{88060192-33D5-4932-B0F9-8BD2763E857D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Benchmarks", "tests\Avalonia.Benchmarks\Avalonia.Benchmarks.csproj", "{410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Logging.Serilog", "src\Avalonia.Logging.Serilog\Avalonia.Logging.Serilog.csproj", "{B61B66A3-B82D-4875-8001-89D3394FE0C9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.DesignerSupport", "src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj", "{799A7BB5-3C2C-48B6-85A7-406A12C420DA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog", "samples\ControlCatalog\ControlCatalog.csproj", "{D0A739B9-3C68-4BA6-A328-41606954B6BD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Desktop", "samples\ControlCatalog.Desktop\ControlCatalog.Desktop.csproj", "{2B888490-D14A-4BCA-AB4B-48676FA93C9B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{57E0455D-D565-44BB-B069-EE1AA20F8337}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.RenderTests", "tests\Avalonia.RenderTests\Avalonia.Skia.RenderTests.csproj", "{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}" +EndProject +Global + GlobalSection(SharedMSBuildProjectFiles) = preSolution + src\Shared\RenderHelpers\RenderHelpers.projitems*{fb05ac90-89ba-4f2f-a924-f37875fb547c}*SharedItemsImports = 4 + src\Shared\PlatformSupport\PlatformSupport.projitems*{4488ad85-1495-4809-9aa4-ddfe0a48527e}*SharedItemsImports = 4 + src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4 + src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13 + src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{2f59f3d0-748d-4652-b01e-e0d954756308}*SharedItemsImports = 13 + src\Shared\PlatformSupport\PlatformSupport.projitems*{db070a10-bf39-4752-8456-86e9d5928478}*SharedItemsImports = 4 + src\Shared\RenderHelpers\RenderHelpers.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4 + src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4 + samples\TestApplicationShared\TestApplicationShared.projitems*{78345174-5b52-4a14-b9fd-d5f2428137f0}*SharedItemsImports = 13 + src\Shared\PlatformSupport\PlatformSupport.projitems*{54f237d5-a70a-4752-9656-0c70b1a7b047}*SharedItemsImports = 4 + samples\TestApplicationShared\TestApplicationShared.projitems*{ff69b927-c545-49ae-8e16-3d14d621aa12}*SharedItemsImports = 4 + src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 + src\Shared\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4 + src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*SharedItemsImports = 4 + src\Shared\RenderHelpers\RenderHelpers.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4 + src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4 + samples\TestApplicationShared\TestApplicationShared.projitems*{8c923867-8a8f-4f6b-8b80-47d9e8436166}*SharedItemsImports = 4 + samples\TestApplicationShared\TestApplicationShared.projitems*{e3a1060b-50d0-44e8-88b6-f44ef2e5bd72}*SharedItemsImports = 4 + src\Shared\RenderHelpers\RenderHelpers.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4 + src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4 + src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4 + src\Shared\PlatformSupport\PlatformSupport.projitems*{e1aa3dbf-9056-4530-9376-18119a7a3ffe}*SharedItemsImports = 4 + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Ad-Hoc|Any CPU = Ad-Hoc|Any CPU + Ad-Hoc|iPhone = Ad-Hoc|iPhone + Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator + Ad-Hoc|x86 = Ad-Hoc|x86 + AppStore|Any CPU = AppStore|Any CPU + AppStore|iPhone = AppStore|iPhone + AppStore|iPhoneSimulator = AppStore|iPhoneSimulator + AppStore|x86 = AppStore|x86 + Debug|Any CPU = Debug|Any CPU + Debug|iPhone = Debug|iPhone + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|Any CPU.Build.0 = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhone.Build.0 = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|x86.ActiveCfg = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|x86.Build.0 = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhone.Build.0 = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|x86.ActiveCfg = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|x86.Build.0 = Debug|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|Any CPU.Build.0 = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhone.ActiveCfg = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhone.Build.0 = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|x86.ActiveCfg = Release|Any CPU + {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|x86.Build.0 = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|Any CPU.Build.0 = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhone.Build.0 = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|x86.ActiveCfg = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|x86.Build.0 = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhone.Build.0 = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|x86.ActiveCfg = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|x86.Build.0 = Debug|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|Any CPU.Build.0 = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhone.ActiveCfg = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhone.Build.0 = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|x86.ActiveCfg = Release|Any CPU + {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|x86.Build.0 = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|Any CPU.Build.0 = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhone.Build.0 = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|x86.ActiveCfg = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|x86.Build.0 = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhone.Build.0 = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|x86.ActiveCfg = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|x86.Build.0 = Debug|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|Any CPU.Build.0 = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhone.ActiveCfg = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhone.Build.0 = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|x86.ActiveCfg = Release|Any CPU + {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|x86.Build.0 = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|Any CPU.Build.0 = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhone.Build.0 = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|x86.ActiveCfg = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|x86.Build.0 = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.Build.0 = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhone.Build.0 = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|x86.ActiveCfg = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|x86.Build.0 = Debug|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.ActiveCfg = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.Build.0 = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhone.ActiveCfg = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhone.Build.0 = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|x86.ActiveCfg = Release|Any CPU + {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|x86.Build.0 = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|Any CPU.Build.0 = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhone.Build.0 = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|x86.ActiveCfg = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|x86.Build.0 = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhone.Build.0 = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|x86.ActiveCfg = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|x86.Build.0 = Debug|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.Build.0 = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhone.ActiveCfg = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhone.Build.0 = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|x86.ActiveCfg = Release|Any CPU + {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|x86.Build.0 = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|Any CPU.Build.0 = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhone.Build.0 = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|x86.ActiveCfg = Debug|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhone.Build.0 = Debug|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|x86.ActiveCfg = Debug|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|Any CPU.Build.0 = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhone.ActiveCfg = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhone.Build.0 = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|x86.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|Any CPU.Build.0 = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhone.Build.0 = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|x86.ActiveCfg = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|x86.Build.0 = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhone.Build.0 = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|x86.ActiveCfg = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|x86.Build.0 = Debug|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|Any CPU.Build.0 = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhone.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhone.Build.0 = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|x86.ActiveCfg = Release|Any CPU + {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|x86.Build.0 = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|Any CPU.Build.0 = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhone.Build.0 = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|x86.ActiveCfg = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|x86.Build.0 = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhone.Build.0 = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|x86.ActiveCfg = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|x86.Build.0 = Debug|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|Any CPU.Build.0 = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhone.ActiveCfg = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhone.Build.0 = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|x86.ActiveCfg = Release|Any CPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|x86.Build.0 = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|Any CPU.Build.0 = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhone.Build.0 = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|x86.ActiveCfg = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|x86.Build.0 = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhone.Build.0 = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|x86.ActiveCfg = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|x86.Build.0 = Debug|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.Build.0 = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhone.ActiveCfg = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhone.Build.0 = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|x86.ActiveCfg = Release|Any CPU + {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|x86.Build.0 = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|Any CPU.Build.0 = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhone.Build.0 = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|x86.ActiveCfg = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|x86.Build.0 = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhone.Build.0 = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|x86.ActiveCfg = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|x86.Build.0 = Debug|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|Any CPU.Build.0 = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhone.ActiveCfg = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhone.Build.0 = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|x86.ActiveCfg = Release|Any CPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|x86.Build.0 = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|Any CPU.Build.0 = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhone.Build.0 = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|x86.ActiveCfg = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|x86.Build.0 = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhone.Build.0 = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|x86.ActiveCfg = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|x86.Build.0 = Debug|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.Build.0 = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhone.ActiveCfg = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhone.Build.0 = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|x86.ActiveCfg = Release|Any CPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|x86.Build.0 = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|Any CPU.Build.0 = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhone.Build.0 = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|x86.ActiveCfg = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|x86.Build.0 = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhone.Build.0 = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|x86.ActiveCfg = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|x86.Build.0 = Debug|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|Any CPU.Build.0 = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhone.ActiveCfg = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhone.Build.0 = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|x86.ActiveCfg = Release|Any CPU + {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|x86.Build.0 = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|Any CPU.Build.0 = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhone.Build.0 = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|x86.ActiveCfg = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|x86.Build.0 = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhone.Build.0 = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|x86.ActiveCfg = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|x86.Build.0 = Debug|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|Any CPU.Build.0 = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhone.ActiveCfg = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhone.Build.0 = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|x86.ActiveCfg = Release|Any CPU + {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|x86.Build.0 = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|Any CPU.Build.0 = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhone.Build.0 = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|x86.ActiveCfg = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|x86.Build.0 = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhone.Build.0 = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|x86.ActiveCfg = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|x86.Build.0 = Debug|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|Any CPU.Build.0 = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhone.ActiveCfg = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhone.Build.0 = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|x86.ActiveCfg = Release|Any CPU + {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|x86.Build.0 = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|Any CPU.Build.0 = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhone.Build.0 = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|x86.ActiveCfg = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|x86.Build.0 = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhone.Build.0 = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|x86.ActiveCfg = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|x86.Build.0 = Debug|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.Build.0 = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhone.ActiveCfg = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhone.Build.0 = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|x86.ActiveCfg = Release|Any CPU + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|x86.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|Any CPU.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhone.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|x86.ActiveCfg = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|x86.Build.0 = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhone.Build.0 = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|x86.ActiveCfg = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|x86.Build.0 = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhone.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhone.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Release|x86.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Release|x86.Build.0 = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|Any CPU.Build.0 = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhone.Build.0 = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|x86.ActiveCfg = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|x86.Build.0 = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhone.Build.0 = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|x86.ActiveCfg = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|x86.Build.0 = Debug|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.Build.0 = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhone.ActiveCfg = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhone.Build.0 = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|x86.ActiveCfg = Release|Any CPU + {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|x86.Build.0 = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|Any CPU.Build.0 = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhone.Build.0 = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|x86.ActiveCfg = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|x86.Build.0 = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhone.Build.0 = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|x86.ActiveCfg = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|x86.Build.0 = Debug|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Release|Any CPU.Build.0 = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhone.ActiveCfg = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhone.Build.0 = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Release|x86.ActiveCfg = Release|Any CPU + {DB070A10-BF39-4752-8456-86E9D5928478}.Release|x86.Build.0 = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|Any CPU.Build.0 = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhone.Build.0 = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|x86.ActiveCfg = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|x86.Build.0 = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhone.Build.0 = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|x86.ActiveCfg = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|x86.Build.0 = Debug|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|Any CPU.Build.0 = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhone.ActiveCfg = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhone.Build.0 = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|x86.ActiveCfg = Release|Any CPU + {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|x86.Build.0 = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|Any CPU.Build.0 = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhone.Build.0 = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|x86.ActiveCfg = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|x86.Build.0 = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhone.Build.0 = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|x86.ActiveCfg = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|x86.Build.0 = Debug|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.Build.0 = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhone.ActiveCfg = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhone.Build.0 = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|x86.ActiveCfg = Release|Any CPU + {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|x86.Build.0 = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|Any CPU.Build.0 = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhone.Build.0 = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|x86.ActiveCfg = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|x86.Build.0 = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhone.Build.0 = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|x86.ActiveCfg = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|x86.Build.0 = Debug|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|Any CPU.Build.0 = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhone.ActiveCfg = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhone.Build.0 = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|x86.ActiveCfg = Release|Any CPU + {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|x86.Build.0 = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|Any CPU.Build.0 = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhone.Build.0 = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|x86.ActiveCfg = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|x86.Build.0 = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhone.Build.0 = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|x86.ActiveCfg = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|x86.Build.0 = Debug|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.Build.0 = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhone.ActiveCfg = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhone.Build.0 = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|x86.ActiveCfg = Release|Any CPU + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|x86.Build.0 = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|Any CPU.Build.0 = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhone.Build.0 = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|x86.ActiveCfg = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|x86.Build.0 = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhone.Build.0 = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Debug|x86.ActiveCfg = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Debug|x86.Build.0 = Debug|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Release|Any CPU.Build.0 = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhone.ActiveCfg = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhone.Build.0 = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Release|x86.ActiveCfg = Release|Any CPU + {E106CF37-4066-4615-B684-172A6D30B058}.Release|x86.Build.0 = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|Any CPU.Build.0 = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhone.Build.0 = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|x86.ActiveCfg = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|x86.Build.0 = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhone.Build.0 = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|x86.ActiveCfg = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|x86.Build.0 = Debug|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.Build.0 = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhone.ActiveCfg = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhone.Build.0 = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|x86.ActiveCfg = Release|Any CPU + {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|x86.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|Any CPU.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhone.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|x86.ActiveCfg = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|x86.Build.0 = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhone.Build.0 = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|x86.ActiveCfg = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|x86.Build.0 = Debug|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhone.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhone.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|x86.ActiveCfg = Release|Any CPU + {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|x86.Build.0 = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|Any CPU.Build.0 = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|iPhone.Build.0 = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|x86.ActiveCfg = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|x86.Build.0 = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|iPhone.Build.0 = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|x86.ActiveCfg = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|x86.Build.0 = Debug|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|Any CPU.Build.0 = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|iPhone.ActiveCfg = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|iPhone.Build.0 = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|x86.ActiveCfg = Release|Any CPU + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|x86.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|Any CPU.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|iPhone.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|x86.ActiveCfg = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|x86.Build.0 = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|iPhone.Build.0 = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|x86.ActiveCfg = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|x86.Build.0 = Debug|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|Any CPU.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|iPhone.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|iPhone.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|x86.ActiveCfg = Release|Any CPU + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|x86.Build.0 = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|Any CPU.Build.0 = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhone.Build.0 = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|x86.ActiveCfg = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|x86.Build.0 = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhone.Build.0 = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|x86.ActiveCfg = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|x86.Build.0 = Debug|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|Any CPU.Build.0 = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhone.ActiveCfg = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhone.Build.0 = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|x86.ActiveCfg = Release|Any CPU + {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|x86.Build.0 = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|Any CPU.Build.0 = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhone.Build.0 = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|x86.ActiveCfg = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|x86.Build.0 = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhone.Build.0 = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|x86.ActiveCfg = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|x86.Build.0 = Debug|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|Any CPU.Build.0 = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhone.ActiveCfg = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhone.Build.0 = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|x86.ActiveCfg = Release|Any CPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|x86.Build.0 = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|Any CPU.Build.0 = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhone.Build.0 = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|x86.ActiveCfg = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|x86.Build.0 = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhone.Build.0 = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|x86.ActiveCfg = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|x86.Build.0 = Debug|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.Build.0 = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhone.ActiveCfg = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhone.Build.0 = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|x86.ActiveCfg = Release|Any CPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|x86.Build.0 = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|Any CPU.Build.0 = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|iPhone.Build.0 = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|x86.ActiveCfg = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|x86.Build.0 = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|iPhone.Build.0 = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|x86.ActiveCfg = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|x86.Build.0 = Debug|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|Any CPU.Build.0 = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|iPhone.ActiveCfg = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|iPhone.Build.0 = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|x86.ActiveCfg = Release|Any CPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|x86.Build.0 = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|Any CPU.Build.0 = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhone.Build.0 = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|x86.ActiveCfg = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|x86.Build.0 = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhone.Build.0 = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|x86.ActiveCfg = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|x86.Build.0 = Debug|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Release|Any CPU.Build.0 = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhone.ActiveCfg = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhone.Build.0 = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Release|x86.ActiveCfg = Release|Any CPU + {6417E941-21BC-467B-A771-0DE389353CE6}.Release|x86.Build.0 = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|Any CPU.Build.0 = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhone.Build.0 = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|x86.ActiveCfg = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|x86.Build.0 = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhone.Build.0 = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|x86.ActiveCfg = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|x86.Build.0 = Debug|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|Any CPU.Build.0 = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhone.ActiveCfg = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhone.Build.0 = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|x86.ActiveCfg = Release|Any CPU + {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|x86.Build.0 = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|Any CPU.Build.0 = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhone.Build.0 = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|x86.ActiveCfg = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|x86.Build.0 = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhone.Build.0 = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|x86.ActiveCfg = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|x86.Build.0 = Debug|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|Any CPU.Build.0 = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhone.ActiveCfg = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhone.Build.0 = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|x86.ActiveCfg = Release|Any CPU + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|x86.Build.0 = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|Any CPU.Build.0 = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|iPhone.Build.0 = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|x86.ActiveCfg = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|x86.Build.0 = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|iPhone.Build.0 = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|x86.ActiveCfg = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|x86.Build.0 = Debug|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|Any CPU.Build.0 = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|iPhone.ActiveCfg = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|iPhone.Build.0 = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|x86.ActiveCfg = Release|Any CPU + {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|x86.Build.0 = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|x86.ActiveCfg = Release|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|x86.Build.0 = Release|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|Any CPU.Build.0 = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|iPhone.Build.0 = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|x86.ActiveCfg = Release|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|x86.Build.0 = Release|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|Any CPU.ActiveCfg = Debug|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|Any CPU.Build.0 = Debug|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|iPhone.ActiveCfg = Debug|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|iPhone.Build.0 = Debug|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|x86.ActiveCfg = Debug|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|x86.Build.0 = Debug|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|Any CPU.ActiveCfg = Release|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|Any CPU.Build.0 = Release|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|iPhone.ActiveCfg = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|iPhone.Build.0 = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|x86.ActiveCfg = Release|x86 + {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|x86.Build.0 = Release|x86 + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|Any CPU.Build.0 = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|iPhone.Build.0 = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|x86.ActiveCfg = Debug|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|x86.Build.0 = Debug|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|x86.ActiveCfg = Debug|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|x86.Build.0 = Debug|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|Any CPU.Build.0 = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|iPhone.ActiveCfg = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|x86.ActiveCfg = Release|Any CPU + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|x86.Build.0 = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.Deploy.0 = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.ActiveCfg = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.Build.0 = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.Deploy.0 = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.ActiveCfg = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.Build.0 = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.Deploy.0 = Debug|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.Build.0 = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.Deploy.0 = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|iPhone.ActiveCfg = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.ActiveCfg = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.Build.0 = Release|Any CPU + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.Deploy.0 = Release|Any CPU + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhone.ActiveCfg = AppStore|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhone.Build.0 = AppStore|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|x86.ActiveCfg = AppStore|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|Any CPU.ActiveCfg = Debug|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhone.ActiveCfg = Debug|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhone.Build.0 = Debug|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|x86.ActiveCfg = Debug|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|Any CPU.ActiveCfg = Release|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhone.ActiveCfg = Release|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhone.Build.0 = Release|iPhone + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|x86.ActiveCfg = Release|iPhoneSimulator + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|x86.ActiveCfg = AppStore|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|x86.Build.0 = AppStore|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|Any CPU.Build.0 = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|iPhone.Build.0 = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|x86.ActiveCfg = AppStore|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|x86.Build.0 = AppStore|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|iPhone.Build.0 = Debug|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|x86.ActiveCfg = Debug|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|x86.Build.0 = Debug|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|Any CPU.Build.0 = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhone.ActiveCfg = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhone.Build.0 = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|x86.ActiveCfg = Release|Any CPU + {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|x86.Build.0 = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|x86.ActiveCfg = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|x86.Build.0 = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|x86.ActiveCfg = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|x86.Build.0 = Debug|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.Build.0 = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|iPhone.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|x86.ActiveCfg = Release|Any CPU + {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|x86.Build.0 = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|x86.ActiveCfg = Debug|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|x86.ActiveCfg = Debug|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.Build.0 = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.Deploy.0 = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|iPhone.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|x86.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|x86.ActiveCfg = AppStore|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|x86.Build.0 = AppStore|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|Any CPU.Build.0 = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhone.Build.0 = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|x86.ActiveCfg = AppStore|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|x86.Build.0 = AppStore|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhone.Build.0 = Debug|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|x86.ActiveCfg = Debug|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|x86.Build.0 = Debug|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|Any CPU.Build.0 = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhone.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhone.Build.0 = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|x86.ActiveCfg = Release|Any CPU + {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|x86.Build.0 = Release|Any CPU + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhone.ActiveCfg = AppStore|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhone.Build.0 = AppStore|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|x86.ActiveCfg = AppStore|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|Any CPU.ActiveCfg = Debug|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhone.ActiveCfg = Debug|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhone.Build.0 = Debug|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|x86.ActiveCfg = Debug|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|Any CPU.ActiveCfg = Release|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhone.ActiveCfg = Release|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhone.Build.0 = Release|iPhone + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|x86.ActiveCfg = Release|iPhoneSimulator + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|Any CPU.Build.0 = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhone.Build.0 = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|x86.ActiveCfg = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|x86.Build.0 = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhone.Build.0 = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|x86.ActiveCfg = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|x86.Build.0 = Debug|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|Any CPU.Build.0 = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhone.ActiveCfg = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhone.Build.0 = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|x86.ActiveCfg = Release|Any CPU + {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|x86.Build.0 = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|Any CPU.Build.0 = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhone.Build.0 = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|x86.ActiveCfg = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|x86.Build.0 = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhone.Build.0 = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|x86.ActiveCfg = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|x86.Build.0 = Debug|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|Any CPU.Build.0 = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhone.ActiveCfg = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhone.Build.0 = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|x86.ActiveCfg = Release|Any CPU + {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|x86.Build.0 = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|Any CPU.Build.0 = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhone.Build.0 = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|x86.ActiveCfg = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|x86.Build.0 = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhone.Build.0 = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|x86.ActiveCfg = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|x86.Build.0 = Debug|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|Any CPU.Build.0 = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhone.ActiveCfg = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhone.Build.0 = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|x86.ActiveCfg = Release|Any CPU + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|x86.Build.0 = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|Any CPU.Build.0 = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|iPhone.Build.0 = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|x86.ActiveCfg = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|x86.Build.0 = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|iPhone.Build.0 = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|x86.ActiveCfg = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|x86.Build.0 = Debug|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|Any CPU.Build.0 = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|iPhone.ActiveCfg = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|iPhone.Build.0 = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|x86.ActiveCfg = Release|Any CPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|x86.Build.0 = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|Any CPU.Build.0 = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhone.Build.0 = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|x86.ActiveCfg = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|x86.Build.0 = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhone.Build.0 = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|x86.ActiveCfg = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|x86.Build.0 = Debug|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|Any CPU.Build.0 = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhone.ActiveCfg = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhone.Build.0 = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|x86.ActiveCfg = Release|Any CPU + {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|x86.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|x86.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|Any CPU.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhone.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|x86.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|x86.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhone.Build.0 = Debug|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|x86.ActiveCfg = Debug|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|x86.Build.0 = Debug|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|Any CPU.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhone.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhone.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|x86.ActiveCfg = Release|Any CPU + {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|x86.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|x86.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|Any CPU.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhone.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|x86.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|x86.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhone.Build.0 = Debug|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|x86.ActiveCfg = Debug|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|x86.Build.0 = Debug|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|Any CPU.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhone.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhone.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|x86.ActiveCfg = Release|Any CPU + {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|x86.Build.0 = Release|Any CPU + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhone.ActiveCfg = AppStore|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhone.Build.0 = AppStore|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator + {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator + {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|x86.ActiveCfg = AppStore|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|Any CPU.ActiveCfg = Debug|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhone.ActiveCfg = Debug|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhone.Build.0 = Debug|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|x86.ActiveCfg = Debug|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|Any CPU.ActiveCfg = Release|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|iPhone.ActiveCfg = Release|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|iPhone.Build.0 = Release|iPhone + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|x86.ActiveCfg = Release|iPhone + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|x86.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|Any CPU.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|iPhone.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|x86.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|x86.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhone.Build.0 = Debug|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|x86.ActiveCfg = Debug|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|x86.Build.0 = Debug|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Any CPU.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhone.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhone.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|x86.ActiveCfg = Release|Any CPU + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {811A76CF-1CF6-440F-963B-BBE31BD72A82} = {B39A8919-9F95-48FE-AD7B-76E08B509888} + {3E908F67-5543-4879-A1DC-08EACE79B3CD} = {B39A8919-9F95-48FE-AD7B-76E08B509888} + {EC42600F-049B-43FF-AED1-8314D61B2749} = {B39A8919-9F95-48FE-AD7B-76E08B509888} + {47ECDF59-DEF8-4C53-87B1-2098A3429059} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {5CCB5571-7C30-4E7D-967D-0E2158EBD91F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {76716382-3159-460E-BDA6-C5715CF606D7} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {2905FF23-53FB-45E6-AA49-6AF47A172056} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {DB070A10-BF39-4752-8456-86E9D5928478} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {08478EF5-44E8-42E9-92D6-15E00EC038D8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {AC18926A-E784-40FE-B09D-BB0FE2B599F0} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {E106CF37-4066-4615-B684-172A6D30B058} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C} + {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {78CAFE33-DBEB-4132-8A28-81CFE8A4933C} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {54F237D5-A70A-4752-9656-0C70B1A7B047} = {B9894058-278A-46B5-B6ED-AD613FCC03B3} + {FB05AC90-89BA-4F2F-A924-F37875FB547C} = {B9894058-278A-46B5-B6ED-AD613FCC03B3} + {E4D9629C-F168-4224-3F51-A5E482FFBC42} = {A689DEF5-D50F-4975-8B72-124C9EB54066} + {6417E941-21BC-467B-A771-0DE389353CE6} = {8B6A8209-894F-4BA1-B880-965FD453982C} + {8EF392D5-1416-45AA-9956-7CBBC3229E8A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {EA113F1A-D8D7-4142-9948-353270E7EBAE} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {3C4C0CB4-0C0F-4450-A37B-148C84FF905F} = {A689DEF5-D50F-4975-8B72-124C9EB54066} + {2F59F3D0-748D-4652-B01E-E0D954756308} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} + {925DD807-B651-475F-9F7C-CBEB974CE43D} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} + {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} + {F92E55A5-ED73-4CCB-AB4B-0541B6757F31} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} + {DA49C5F3-BE95-461C-B999-072128CCF59E} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} + {47BE08A7-5985-410B-9FFC-2264B8EA595F} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} + {78345174-5B52-4A14-B9FD-D5F2428137F0} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F} + {FF69B927-C545-49AE-8E16-3D14D621AA12} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F} + {4488AD85-1495-4809-9AA4-DDFE0A48527E} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1} + {8C923867-8A8F-4F6B-8B80-47D9E8436166} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1} + {E1AA3DBF-9056-4530-9376-18119A7A3FFE} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {88060192-33D5-4932-B0F9-8BD2763E857D} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + {D0A739B9-3C68-4BA6-A328-41606954B6BD} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {2B888490-D14A-4BCA-AB4B-48676FA93C9B} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {57E0455D-D565-44BB-B069-EE1AA20F8337} = {9B9E3891-2366-4253-A952-D08BCEB71098} + {D35A9F3D-8BB0-496E-BF72-444038A7DEBB} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} + EndGlobalSection +EndGlobal diff --git a/Perspex.sln.DotSettings b/Avalonia.sln.DotSettings similarity index 100% rename from Perspex.sln.DotSettings rename to Avalonia.sln.DotSettings diff --git a/Perspex.v2.ncrunchsolution b/Avalonia.v2.ncrunchsolution similarity index 100% rename from Perspex.v2.ncrunchsolution rename to Avalonia.v2.ncrunchsolution diff --git a/Perspex.sln b/Perspex.sln deleted file mode 100644 index c081e1ed22..0000000000 --- a/Perspex.sln +++ /dev/null @@ -1,1888 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Base", "src\Perspex.Base\Perspex.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.SceneGraph", "src\Perspex.SceneGraph\Perspex.SceneGraph.csproj", "{EB582467-6ABB-43A1-B052-E981BA910E3A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Layout", "src\Perspex.Layout\Perspex.Layout.csproj", "{42472427-4774-4C81-8AFF-9F27B8E31721}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Windows", "Windows", "{B39A8919-9F95-48FE-AD7B-76E08B509888}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Win32", "src\Windows\Perspex.Win32\Perspex.Win32.csproj", "{811A76CF-1CF6-440F-963B-BBE31BD72A82}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Direct2D1", "src\Windows\Perspex.Direct2D1\Perspex.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Designer", "src\Windows\Perspex.Designer\Perspex.Designer.csproj", "{EC42600F-049B-43FF-AED1-8314D61B2749}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Input", "src\Perspex.Input\Perspex.Input.csproj", "{62024B2D-53EB-4638-B26B-85EEAA54866E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Interactivity", "src\Perspex.Interactivity\Perspex.Interactivity.csproj", "{6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Controls", "src\Perspex.Controls\Perspex.Controls.csproj", "{D2221C82-4A25-4583-9B43-D791E3F6820C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Styling", "src\Perspex.Styling\Perspex.Styling.csproj", "{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Themes.Default", "src\Perspex.Themes.Default\Perspex.Themes.Default.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Diagnostics", "src\Perspex.Diagnostics\Perspex.Diagnostics.csproj", "{7062AE20-5DCC-4442-9645-8195BDECE63E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Animation", "src\Perspex.Animation\Perspex.Animation.csproj", "{D211E587-D8BC-45B9-95A4-F297C8FA5200}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Styling.UnitTests", "tests\Perspex.Styling.UnitTests\Perspex.Styling.UnitTests.csproj", "{47ECDF59-DEF8-4C53-87B1-2098A3429059}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Controls.UnitTests", "tests\Perspex.Controls.UnitTests\Perspex.Controls.UnitTests.csproj", "{5CCB5571-7C30-4E7D-967D-0E2158EBD91F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.SceneGraph.UnitTests", "tests\Perspex.SceneGraph.UnitTests\Perspex.SceneGraph.UnitTests.csproj", "{76716382-3159-460E-BDA6-C5715CF606D7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Base.UnitTests", "tests\Perspex.Base.UnitTests\Perspex.Base.UnitTests.csproj", "{2905FF23-53FB-45E6-AA49-6AF47A172056}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Layout.UnitTests", "tests\Perspex.Layout.UnitTests\Perspex.Layout.UnitTests.csproj", "{DB070A10-BF39-4752-8456-86E9D5928478}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Interactivity.UnitTests", "tests\Perspex.Interactivity.UnitTests\Perspex.Interactivity.UnitTests.csproj", "{08478EF5-44E8-42E9-92D6-15E00EC038D8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Direct2D1.RenderTests", "tests\Perspex.RenderTests\Perspex.Direct2D1.RenderTests.csproj", "{DABFD304-D6A4-4752-8123-C2CCF7AC7831}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Input.UnitTests", "tests\Perspex.Input.UnitTests\Perspex.Input.UnitTests.csproj", "{AC18926A-E784-40FE-B09D-BB0FE2B599F0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Direct2D1.UnitTests", "tests\Perspex.Direct2D1.UnitTests\Perspex.Direct2D1.UnitTests.csproj", "{EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Cairo.RenderTests", "tests\Perspex.RenderTests\Perspex.Cairo.RenderTests.csproj", "{E106CF37-4066-4615-B684-172A6D30B058}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Markup.Xaml.UnitTests", "tests\Perspex.Markup.Xaml.UnitTests\Perspex.Markup.Xaml.UnitTests.csproj", "{99135EAB-653D-47E4-A378-C96E1278CA44}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Markup", "Markup", "{8B6A8209-894F-4BA1-B880-965FD453982C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Markup.Xaml", "src\Markup\Perspex.Markup.Xaml\Perspex.Markup.Xaml.csproj", "{3E53A01A-B331-47F3-B828-4A5717E77A24}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{9B9E3891-2366-4253-A952-D08BCEB71098}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication", "samples\TestApplication\TestApplication.csproj", "{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}" - ProjectSection(ProjectDependencies) = postProject - {3E908F67-5543-4879-A1DC-08EACE79B3CD} = {3E908F67-5543-4879-A1DC-08EACE79B3CD} - {FB05AC90-89BA-4F2F-A924-F37875FB547C} = {FB05AC90-89BA-4F2F-A924-F37875FB547C} - {811A76CF-1CF6-440F-963B-BBE31BD72A82} = {811A76CF-1CF6-440F-963B-BBE31BD72A82} - {54F237D5-A70A-4752-9656-0C70B1A7B047} = {54F237D5-A70A-4752-9656-0C70B1A7B047} - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplication", "samples\XamlTestApplication\XamlTestApplication.csproj", "{78CAFE33-DBEB-4132-8A28-81CFE8A4933C}" - ProjectSection(ProjectDependencies) = postProject - {3E908F67-5543-4879-A1DC-08EACE79B3CD} = {3E908F67-5543-4879-A1DC-08EACE79B3CD} - {FB05AC90-89BA-4F2F-A924-F37875FB547C} = {FB05AC90-89BA-4F2F-A924-F37875FB547C} - {811A76CF-1CF6-440F-963B-BBE31BD72A82} = {811A76CF-1CF6-440F-963B-BBE31BD72A82} - {54F237D5-A70A-4752-9656-0C70B1A7B047} = {54F237D5-A70A-4752-9656-0C70B1A7B047} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A689DEF5-D50F-4975-8B72-124C9EB54066}" - ProjectSection(SolutionItems) = preProject - src\Shared\SharedAssemblyInfo.cs = src\Shared\SharedAssemblyInfo.cs - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gtk", "Gtk", "{B9894058-278A-46B5-B6ED-AD613FCC03B3}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Gtk", "src\Gtk\Perspex.Gtk\Perspex.Gtk.csproj", "{54F237D5-A70A-4752-9656-0C70B1A7B047}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Cairo", "src\Gtk\Perspex.Cairo\Perspex.Cairo.csproj", "{FB05AC90-89BA-4F2F-A924-F37875FB547C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.ReactiveUI", "src\Perspex.ReactiveUI\Perspex.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.HtmlRenderer", "src\Perspex.HtmlRenderer\Perspex.HtmlRenderer.csproj", "{5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlatformSupport", "src\Shared\PlatformSupport\PlatformSupport.shproj", "{E4D9629C-F168-4224-3F51-A5E482FFBC42}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Markup", "src\Markup\Perspex.Markup\Perspex.Markup.csproj", "{6417E941-21BC-467B-A771-0DE389353CE6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Markup.UnitTests", "tests\Perspex.Markup.UnitTests\Perspex.Markup.UnitTests.csproj", "{8EF392D5-1416-45AA-9956-7CBBC3229E8A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BindingTest", "samples\BindingTest\BindingTest.csproj", "{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}" - ProjectSection(ProjectDependencies) = postProject - {B61B66A3-B82D-4875-8001-89D3394FE0C9} = {B61B66A3-B82D-4875-8001-89D3394FE0C9} - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlTestApplicationPcl", "samples\XamlTestApplicationPcl\XamlTestApplicationPcl.csproj", "{EA113F1A-D8D7-4142-9948-353270E7EBAE}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "src\Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Skia", "Skia", "{3743B0F2-CC41-4F14-A8C8-267F579BF91E}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Perspex.Skia", "src\Skia\Perspex.Skia\Perspex.Skia.shproj", "{2F59F3D0-748D-4652-B01E-E0D954756308}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.Desktop", "src\Skia\Perspex.Skia.Desktop\Perspex.Skia.Desktop.csproj", "{925DD807-B651-475F-9F7C-CBEB974CE43D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.Android", "src\Skia\Perspex.Skia.Android\Perspex.Skia.Android.csproj", "{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.Android.TestApp", "src\Skia\Perspex.Skia.Android.TestApp\Perspex.Skia.Android.TestApp.csproj", "{F92E55A5-ED73-4CCB-AB4B-0541B6757F31}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.iOS.TestApp", "src\Skia\Perspex.Skia.iOS.TestApp\Perspex.Skia.iOS.TestApp.csproj", "{DA49C5F3-BE95-461C-B999-072128CCF59E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.iOS", "src\Skia\Perspex.Skia.iOS\Perspex.Skia.iOS.csproj", "{47BE08A7-5985-410B-9FFC-2264B8EA595F}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "TestApplicationShared", "samples\TestApplicationShared\TestApplicationShared.shproj", "{78345174-5B52-4A14-B9FD-D5F2428137F0}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Android", "src\Android\Perspex.Android\Perspex.Android.csproj", "{7B92AF71-6287-4693-9DCB-BD5B6E927E23}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.AndroidTestApplication", "src\Android\Perspex.AndroidTestApplication\Perspex.AndroidTestApplication.csproj", "{FF69B927-C545-49AE-8E16-3D14D621AA12}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "iOS", "iOS", "{0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.iOS", "src\iOS\Perspex.iOS\Perspex.iOS.csproj", "{4488AD85-1495-4809-9AA4-DDFE0A48527E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.iOSTestApplication", "src\iOS\Perspex.iOSTestApplication\Perspex.iOSTestApplication.csproj", "{8C923867-8A8F-4F6B-8B80-47D9E8436166}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.LeakTests", "tests\Perspex.LeakTests\Perspex.LeakTests.csproj", "{E1AA3DBF-9056-4530-9376-18119A7A3FFE}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.UnitTests", "tests\Perspex.UnitTests\Perspex.UnitTests.csproj", "{88060192-33D5-4932-B0F9-8BD2763E857D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Benchmarks", "tests\Perspex.Benchmarks\Perspex.Benchmarks.csproj", "{410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Logging.Serilog", "src\Perspex.Logging.Serilog\Perspex.Logging.Serilog.csproj", "{B61B66A3-B82D-4875-8001-89D3394FE0C9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.DesignerSupport", "src\Perspex.DesignerSupport\Perspex.DesignerSupport.csproj", "{799A7BB5-3C2C-48B6-85A7-406A12C420DA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog", "samples\ControlCatalog\ControlCatalog.csproj", "{D0A739B9-3C68-4BA6-A328-41606954B6BD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Desktop", "samples\ControlCatalog.Desktop\ControlCatalog.Desktop.csproj", "{2B888490-D14A-4BCA-AB4B-48676FA93C9B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{57E0455D-D565-44BB-B069-EE1AA20F8337}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Skia.RenderTests", "tests\Perspex.RenderTests\Perspex.Skia.RenderTests.csproj", "{D35A9F3D-8BB0-496E-BF72-444038A7DEBB}" -EndProject -Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - src\Shared\RenderHelpers\RenderHelpers.projitems*{fb05ac90-89ba-4f2f-a924-f37875fb547c}*SharedItemsImports = 4 - src\Shared\PlatformSupport\PlatformSupport.projitems*{4488ad85-1495-4809-9aa4-ddfe0a48527e}*SharedItemsImports = 4 - src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4 - src\Shared\PlatformSupport\PlatformSupport.projitems*{e4d9629c-f168-4224-3f51-a5e482ffbc42}*SharedItemsImports = 13 - src\Skia\Perspex.Skia\Perspex.Skia.projitems*{2f59f3d0-748d-4652-b01e-e0d954756308}*SharedItemsImports = 13 - src\Shared\PlatformSupport\PlatformSupport.projitems*{db070a10-bf39-4752-8456-86e9d5928478}*SharedItemsImports = 4 - src\Shared\RenderHelpers\RenderHelpers.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4 - src\Skia\Perspex.Skia\Perspex.Skia.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4 - samples\TestApplicationShared\TestApplicationShared.projitems*{78345174-5b52-4a14-b9fd-d5f2428137f0}*SharedItemsImports = 13 - src\Shared\PlatformSupport\PlatformSupport.projitems*{54f237d5-a70a-4752-9656-0c70b1a7b047}*SharedItemsImports = 4 - samples\TestApplicationShared\TestApplicationShared.projitems*{ff69b927-c545-49ae-8e16-3d14d621aa12}*SharedItemsImports = 4 - src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 - src\Shared\PlatformSupport\PlatformSupport.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4 - src\Shared\PlatformSupport\PlatformSupport.projitems*{88060192-33d5-4932-b0f9-8bd2763e857d}*SharedItemsImports = 4 - src\Shared\RenderHelpers\RenderHelpers.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4 - src\Skia\Perspex.Skia\Perspex.Skia.projitems*{47be08a7-5985-410b-9ffc-2264b8ea595f}*SharedItemsImports = 4 - samples\TestApplicationShared\TestApplicationShared.projitems*{8c923867-8a8f-4f6b-8b80-47d9e8436166}*SharedItemsImports = 4 - samples\TestApplicationShared\TestApplicationShared.projitems*{e3a1060b-50d0-44e8-88b6-f44ef2e5bd72}*SharedItemsImports = 4 - src\Shared\RenderHelpers\RenderHelpers.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4 - src\Skia\Perspex.Skia\Perspex.Skia.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4 - src\Shared\RenderHelpers\RenderHelpers.projitems*{3e908f67-5543-4879-a1dc-08eace79b3cd}*SharedItemsImports = 4 - src\Shared\PlatformSupport\PlatformSupport.projitems*{e1aa3dbf-9056-4530-9376-18119a7a3ffe}*SharedItemsImports = 4 - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Ad-Hoc|Any CPU = Ad-Hoc|Any CPU - Ad-Hoc|iPhone = Ad-Hoc|iPhone - Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator - Ad-Hoc|x86 = Ad-Hoc|x86 - AppStore|Any CPU = AppStore|Any CPU - AppStore|iPhone = AppStore|iPhone - AppStore|iPhoneSimulator = AppStore|iPhoneSimulator - AppStore|x86 = AppStore|x86 - Debug|Any CPU = Debug|Any CPU - Debug|iPhone = Debug|iPhone - Debug|iPhoneSimulator = Debug|iPhoneSimulator - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|iPhone = Release|iPhone - Release|iPhoneSimulator = Release|iPhoneSimulator - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|Any CPU.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhone.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|x86.ActiveCfg = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|x86.Build.0 = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhone.Build.0 = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|x86.ActiveCfg = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|x86.Build.0 = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|Any CPU.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhone.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhone.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|x86.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|x86.Build.0 = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|Any CPU.Build.0 = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhone.Build.0 = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|x86.ActiveCfg = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.AppStore|x86.Build.0 = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhone.Build.0 = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|x86.ActiveCfg = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Debug|x86.Build.0 = Debug|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|Any CPU.Build.0 = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhone.ActiveCfg = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhone.Build.0 = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|x86.ActiveCfg = Release|Any CPU - {EB582467-6ABB-43A1-B052-E981BA910E3A}.Release|x86.Build.0 = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|Any CPU.Build.0 = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhone.Build.0 = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|x86.ActiveCfg = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.AppStore|x86.Build.0 = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|Any CPU.Build.0 = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhone.Build.0 = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|x86.ActiveCfg = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Debug|x86.Build.0 = Debug|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|Any CPU.ActiveCfg = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|Any CPU.Build.0 = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhone.ActiveCfg = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhone.Build.0 = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|x86.ActiveCfg = Release|Any CPU - {42472427-4774-4C81-8AFF-9F27B8E31721}.Release|x86.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|Any CPU.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhone.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|x86.ActiveCfg = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|x86.Build.0 = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.Build.0 = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhone.Build.0 = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|x86.ActiveCfg = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|x86.Build.0 = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhone.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhone.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|x86.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|x86.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|Any CPU.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhone.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|x86.ActiveCfg = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|x86.Build.0 = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhone.Build.0 = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|x86.ActiveCfg = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|x86.Build.0 = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhone.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhone.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|x86.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|x86.Build.0 = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|Any CPU.Build.0 = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhone.Build.0 = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.AppStore|x86.ActiveCfg = Debug|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhone.Build.0 = Debug|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Debug|x86.ActiveCfg = Debug|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|Any CPU.Build.0 = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhone.ActiveCfg = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhone.Build.0 = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {EC42600F-049B-43FF-AED1-8314D61B2749}.Release|x86.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|Any CPU.Build.0 = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhone.Build.0 = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|x86.ActiveCfg = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.AppStore|x86.Build.0 = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhone.Build.0 = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|x86.ActiveCfg = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Debug|x86.Build.0 = Debug|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|Any CPU.Build.0 = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhone.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhone.Build.0 = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|x86.ActiveCfg = Release|Any CPU - {62024B2D-53EB-4638-B26B-85EEAA54866E}.Release|x86.Build.0 = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|Any CPU.Build.0 = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhone.Build.0 = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|x86.ActiveCfg = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.AppStore|x86.Build.0 = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhone.Build.0 = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|x86.ActiveCfg = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Debug|x86.Build.0 = Debug|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|Any CPU.Build.0 = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhone.ActiveCfg = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhone.Build.0 = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|x86.ActiveCfg = Release|Any CPU - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}.Release|x86.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|Any CPU.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhone.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|x86.ActiveCfg = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|x86.Build.0 = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhone.Build.0 = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|x86.ActiveCfg = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|x86.Build.0 = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhone.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhone.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|x86.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|x86.Build.0 = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|Any CPU.Build.0 = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhone.Build.0 = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|x86.ActiveCfg = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.AppStore|x86.Build.0 = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhone.Build.0 = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|x86.ActiveCfg = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Debug|x86.Build.0 = Debug|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|Any CPU.Build.0 = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhone.ActiveCfg = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhone.Build.0 = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|x86.ActiveCfg = Release|Any CPU - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}.Release|x86.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|Any CPU.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhone.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|x86.ActiveCfg = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|x86.Build.0 = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhone.Build.0 = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|x86.ActiveCfg = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|x86.Build.0 = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhone.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhone.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|x86.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|x86.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|Any CPU.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhone.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|x86.ActiveCfg = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|x86.Build.0 = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhone.Build.0 = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|x86.ActiveCfg = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|x86.Build.0 = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|Any CPU.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhone.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhone.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|x86.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|x86.Build.0 = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|Any CPU.Build.0 = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhone.Build.0 = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|x86.ActiveCfg = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.AppStore|x86.Build.0 = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhone.Build.0 = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|x86.ActiveCfg = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Debug|x86.Build.0 = Debug|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|Any CPU.Build.0 = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhone.ActiveCfg = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhone.Build.0 = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|x86.ActiveCfg = Release|Any CPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200}.Release|x86.Build.0 = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|Any CPU.Build.0 = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhone.Build.0 = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|x86.ActiveCfg = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.AppStore|x86.Build.0 = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhone.Build.0 = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|x86.ActiveCfg = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Debug|x86.Build.0 = Debug|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|Any CPU.ActiveCfg = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|Any CPU.Build.0 = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhone.ActiveCfg = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhone.Build.0 = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|x86.ActiveCfg = Release|Any CPU - {47ECDF59-DEF8-4C53-87B1-2098A3429059}.Release|x86.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|Any CPU.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhone.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|x86.ActiveCfg = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|x86.Build.0 = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhone.Build.0 = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|x86.ActiveCfg = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|x86.Build.0 = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhone.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhone.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|x86.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|x86.Build.0 = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|Any CPU.Build.0 = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhone.Build.0 = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|x86.ActiveCfg = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.AppStore|x86.Build.0 = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhone.Build.0 = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|x86.ActiveCfg = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|x86.Build.0 = Debug|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.Build.0 = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhone.ActiveCfg = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhone.Build.0 = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Release|x86.ActiveCfg = Release|Any CPU - {76716382-3159-460E-BDA6-C5715CF606D7}.Release|x86.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|Any CPU.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhone.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|x86.ActiveCfg = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|x86.Build.0 = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhone.Build.0 = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|x86.ActiveCfg = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|x86.Build.0 = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhone.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhone.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|x86.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|x86.Build.0 = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|Any CPU.Build.0 = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhone.Build.0 = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|x86.ActiveCfg = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.AppStore|x86.Build.0 = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhone.Build.0 = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|x86.ActiveCfg = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Debug|x86.Build.0 = Debug|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Release|Any CPU.Build.0 = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhone.ActiveCfg = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhone.Build.0 = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Release|x86.ActiveCfg = Release|Any CPU - {DB070A10-BF39-4752-8456-86E9D5928478}.Release|x86.Build.0 = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|Any CPU.Build.0 = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhone.Build.0 = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|x86.ActiveCfg = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.AppStore|x86.Build.0 = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhone.Build.0 = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|x86.ActiveCfg = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Debug|x86.Build.0 = Debug|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|Any CPU.Build.0 = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhone.ActiveCfg = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhone.Build.0 = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|x86.ActiveCfg = Release|Any CPU - {08478EF5-44E8-42E9-92D6-15E00EC038D8}.Release|x86.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|Any CPU.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhone.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|x86.ActiveCfg = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|x86.Build.0 = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhone.Build.0 = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|x86.ActiveCfg = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|x86.Build.0 = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhone.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhone.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|x86.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|x86.Build.0 = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|Any CPU.Build.0 = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhone.Build.0 = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|x86.ActiveCfg = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.AppStore|x86.Build.0 = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhone.Build.0 = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|x86.ActiveCfg = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Debug|x86.Build.0 = Debug|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|Any CPU.Build.0 = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhone.ActiveCfg = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhone.Build.0 = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|x86.ActiveCfg = Release|Any CPU - {AC18926A-E784-40FE-B09D-BB0FE2B599F0}.Release|x86.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|Any CPU.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhone.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|x86.ActiveCfg = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|x86.Build.0 = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhone.Build.0 = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|x86.ActiveCfg = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|x86.Build.0 = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhone.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhone.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|x86.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|x86.Build.0 = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|Any CPU.Build.0 = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhone.Build.0 = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|x86.ActiveCfg = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.AppStore|x86.Build.0 = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhone.Build.0 = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Debug|x86.ActiveCfg = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Debug|x86.Build.0 = Debug|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Release|Any CPU.Build.0 = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhone.ActiveCfg = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhone.Build.0 = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Release|x86.ActiveCfg = Release|Any CPU - {E106CF37-4066-4615-B684-172A6D30B058}.Release|x86.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|Any CPU.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhone.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|x86.ActiveCfg = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|x86.Build.0 = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.Build.0 = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhone.Build.0 = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|x86.ActiveCfg = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|x86.Build.0 = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhone.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhone.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|x86.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|x86.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|Any CPU.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhone.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|x86.ActiveCfg = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|x86.Build.0 = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhone.Build.0 = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|x86.ActiveCfg = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|x86.Build.0 = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhone.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhone.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|x86.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|x86.Build.0 = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|Any CPU.Build.0 = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|iPhone.Build.0 = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|x86.ActiveCfg = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.AppStore|x86.Build.0 = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|iPhone.Build.0 = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|x86.ActiveCfg = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Debug|x86.Build.0 = Debug|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|Any CPU.Build.0 = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|iPhone.ActiveCfg = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|iPhone.Build.0 = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|x86.ActiveCfg = Release|Any CPU - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72}.Release|x86.Build.0 = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|Any CPU.Build.0 = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|iPhone.Build.0 = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|x86.ActiveCfg = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.AppStore|x86.Build.0 = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|iPhone.Build.0 = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|x86.ActiveCfg = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Debug|x86.Build.0 = Debug|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|Any CPU.Build.0 = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|iPhone.ActiveCfg = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|iPhone.Build.0 = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|x86.ActiveCfg = Release|Any CPU - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C}.Release|x86.Build.0 = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|Any CPU.Build.0 = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhone.Build.0 = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|x86.ActiveCfg = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.AppStore|x86.Build.0 = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|Any CPU.Build.0 = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhone.Build.0 = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|x86.ActiveCfg = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Debug|x86.Build.0 = Debug|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|Any CPU.ActiveCfg = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|Any CPU.Build.0 = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhone.ActiveCfg = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhone.Build.0 = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|x86.ActiveCfg = Release|Any CPU - {54F237D5-A70A-4752-9656-0C70B1A7B047}.Release|x86.Build.0 = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|Any CPU.Build.0 = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhone.Build.0 = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|x86.ActiveCfg = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.AppStore|x86.Build.0 = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhone.Build.0 = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|x86.ActiveCfg = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Debug|x86.Build.0 = Debug|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|Any CPU.Build.0 = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhone.ActiveCfg = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhone.Build.0 = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|x86.ActiveCfg = Release|Any CPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C}.Release|x86.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|Any CPU.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhone.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|x86.ActiveCfg = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|x86.Build.0 = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhone.Build.0 = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|x86.ActiveCfg = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|x86.Build.0 = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhone.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhone.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|x86.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|x86.Build.0 = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|Any CPU.Build.0 = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|iPhone.Build.0 = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|x86.ActiveCfg = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.AppStore|x86.Build.0 = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|iPhone.Build.0 = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|x86.ActiveCfg = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Debug|x86.Build.0 = Debug|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|Any CPU.Build.0 = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|iPhone.ActiveCfg = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|iPhone.Build.0 = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|x86.ActiveCfg = Release|Any CPU - {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}.Release|x86.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|Any CPU.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhone.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|x86.ActiveCfg = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|x86.Build.0 = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhone.Build.0 = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|x86.ActiveCfg = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|x86.Build.0 = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|Any CPU.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhone.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhone.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|x86.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|x86.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|Any CPU.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhone.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|x86.ActiveCfg = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|x86.Build.0 = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhone.Build.0 = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|x86.ActiveCfg = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|x86.Build.0 = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|Any CPU.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhone.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhone.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|x86.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|x86.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|Any CPU.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhone.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|x86.ActiveCfg = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|x86.Build.0 = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|Any CPU.Build.0 = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhone.Build.0 = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|x86.ActiveCfg = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|x86.Build.0 = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|Any CPU.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|Any CPU.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhone.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhone.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|x86.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|x86.Build.0 = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|Any CPU.Build.0 = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|iPhone.Build.0 = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|x86.ActiveCfg = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.AppStore|x86.Build.0 = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|iPhone.Build.0 = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|x86.ActiveCfg = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Debug|x86.Build.0 = Debug|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|Any CPU.Build.0 = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|iPhone.ActiveCfg = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|iPhone.Build.0 = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|x86.ActiveCfg = Release|Any CPU - {EA113F1A-D8D7-4142-9948-353270E7EBAE}.Release|x86.Build.0 = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|x86.ActiveCfg = Release|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Ad-Hoc|x86.Build.0 = Release|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|Any CPU.Build.0 = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|iPhone.Build.0 = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|x86.ActiveCfg = Release|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.AppStore|x86.Build.0 = Release|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|Any CPU.ActiveCfg = Debug|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|Any CPU.Build.0 = Debug|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|iPhone.ActiveCfg = Debug|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|iPhone.Build.0 = Debug|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|x86.ActiveCfg = Debug|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Debug|x86.Build.0 = Debug|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|Any CPU.ActiveCfg = Release|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|Any CPU.Build.0 = Release|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|iPhone.ActiveCfg = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|iPhone.Build.0 = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|x86.ActiveCfg = Release|x86 - {925DD807-B651-475F-9F7C-CBEB974CE43D}.Release|x86.Build.0 = Release|x86 - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|Any CPU.Build.0 = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|iPhone.Build.0 = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|x86.ActiveCfg = Debug|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.AppStore|x86.Build.0 = Debug|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|x86.ActiveCfg = Debug|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Debug|x86.Build.0 = Debug|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|Any CPU.Build.0 = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|iPhone.ActiveCfg = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|x86.ActiveCfg = Release|Any CPU - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|x86.Build.0 = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Ad-Hoc|x86.Deploy.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.Build.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.AppStore|x86.Deploy.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.ActiveCfg = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.Build.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Debug|x86.Deploy.0 = Debug|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.Build.0 = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|Any CPU.Deploy.0 = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|iPhone.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.ActiveCfg = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.Build.0 = Release|Any CPU - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31}.Release|x86.Deploy.0 = Release|Any CPU - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhone.ActiveCfg = AppStore|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhone.Build.0 = AppStore|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|x86.ActiveCfg = AppStore|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|Any CPU.ActiveCfg = Debug|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhone.ActiveCfg = Debug|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhone.Build.0 = Debug|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|x86.ActiveCfg = Debug|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|Any CPU.ActiveCfg = Release|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhone.ActiveCfg = Release|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhone.Build.0 = Release|iPhone - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator - {DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|x86.ActiveCfg = Release|iPhoneSimulator - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|x86.ActiveCfg = AppStore|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|x86.Build.0 = AppStore|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|Any CPU.Build.0 = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|iPhone.Build.0 = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|x86.ActiveCfg = AppStore|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.AppStore|x86.Build.0 = AppStore|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|iPhone.Build.0 = Debug|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|x86.ActiveCfg = Debug|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Debug|x86.Build.0 = Debug|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|Any CPU.Build.0 = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhone.ActiveCfg = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhone.Build.0 = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|x86.ActiveCfg = Release|Any CPU - {47BE08A7-5985-410B-9FFC-2264B8EA595F}.Release|x86.Build.0 = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|x86.ActiveCfg = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|x86.Build.0 = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|x86.ActiveCfg = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|x86.Build.0 = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.Build.0 = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|iPhone.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|x86.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|x86.Build.0 = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.AppStore|x86.ActiveCfg = Debug|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Debug|x86.ActiveCfg = Debug|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.Build.0 = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|Any CPU.Deploy.0 = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|iPhone.ActiveCfg = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FF69B927-C545-49AE-8E16-3D14D621AA12}.Release|x86.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|x86.ActiveCfg = AppStore|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|x86.Build.0 = AppStore|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|Any CPU.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhone.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|x86.ActiveCfg = AppStore|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|x86.Build.0 = AppStore|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhone.Build.0 = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|x86.ActiveCfg = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|x86.Build.0 = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|Any CPU.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhone.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhone.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|x86.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|x86.Build.0 = Release|Any CPU - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhone.ActiveCfg = AppStore|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhone.Build.0 = AppStore|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.AppStore|x86.ActiveCfg = AppStore|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|Any CPU.ActiveCfg = Debug|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhone.ActiveCfg = Debug|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhone.Build.0 = Debug|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Debug|x86.ActiveCfg = Debug|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|Any CPU.ActiveCfg = Release|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhone.ActiveCfg = Release|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhone.Build.0 = Release|iPhone - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator - {8C923867-8A8F-4F6B-8B80-47D9E8436166}.Release|x86.ActiveCfg = Release|iPhoneSimulator - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|Any CPU.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhone.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|x86.ActiveCfg = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|x86.Build.0 = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhone.Build.0 = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|x86.ActiveCfg = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|x86.Build.0 = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|Any CPU.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhone.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhone.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|x86.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|x86.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|Any CPU.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhone.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|x86.ActiveCfg = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|x86.Build.0 = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhone.Build.0 = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|x86.ActiveCfg = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|x86.Build.0 = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|Any CPU.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhone.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhone.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|x86.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|x86.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|Any CPU.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhone.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|x86.ActiveCfg = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|x86.Build.0 = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhone.Build.0 = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|x86.ActiveCfg = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|x86.Build.0 = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|Any CPU.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhone.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhone.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|x86.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|x86.Build.0 = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|Any CPU.Build.0 = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|iPhone.Build.0 = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|x86.ActiveCfg = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.AppStore|x86.Build.0 = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|iPhone.Build.0 = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|x86.ActiveCfg = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Debug|x86.Build.0 = Debug|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|Any CPU.Build.0 = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|iPhone.ActiveCfg = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|iPhone.Build.0 = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|x86.ActiveCfg = Release|Any CPU - {B61B66A3-B82D-4875-8001-89D3394FE0C9}.Release|x86.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|Any CPU.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhone.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|x86.ActiveCfg = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|x86.Build.0 = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhone.Build.0 = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|x86.ActiveCfg = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|x86.Build.0 = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|Any CPU.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhone.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhone.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|x86.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|x86.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|x86.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|Any CPU.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhone.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|x86.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|x86.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhone.Build.0 = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|x86.ActiveCfg = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|x86.Build.0 = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|Any CPU.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhone.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhone.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|x86.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|x86.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|x86.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|Any CPU.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhone.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|x86.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|x86.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhone.Build.0 = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|x86.ActiveCfg = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|x86.Build.0 = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|Any CPU.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhone.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhone.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|x86.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|x86.Build.0 = Release|Any CPU - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhone.ActiveCfg = AppStore|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhone.Build.0 = AppStore|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator - {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator - {57E0455D-D565-44BB-B069-EE1AA20F8337}.AppStore|x86.ActiveCfg = AppStore|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|Any CPU.ActiveCfg = Debug|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhone.ActiveCfg = Debug|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhone.Build.0 = Debug|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Debug|x86.ActiveCfg = Debug|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|Any CPU.ActiveCfg = Release|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|iPhone.ActiveCfg = Release|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|iPhone.Build.0 = Release|iPhone - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator - {57E0455D-D565-44BB-B069-EE1AA20F8337}.Release|x86.ActiveCfg = Release|iPhone - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Ad-Hoc|x86.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|Any CPU.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|iPhone.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|x86.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.AppStore|x86.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhone.Build.0 = Debug|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|x86.ActiveCfg = Debug|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Debug|x86.Build.0 = Debug|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|Any CPU.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhone.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhone.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|x86.ActiveCfg = Release|Any CPU - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {811A76CF-1CF6-440F-963B-BBE31BD72A82} = {B39A8919-9F95-48FE-AD7B-76E08B509888} - {3E908F67-5543-4879-A1DC-08EACE79B3CD} = {B39A8919-9F95-48FE-AD7B-76E08B509888} - {EC42600F-049B-43FF-AED1-8314D61B2749} = {B39A8919-9F95-48FE-AD7B-76E08B509888} - {47ECDF59-DEF8-4C53-87B1-2098A3429059} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {76716382-3159-460E-BDA6-C5715CF606D7} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {2905FF23-53FB-45E6-AA49-6AF47A172056} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {DB070A10-BF39-4752-8456-86E9D5928478} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {08478EF5-44E8-42E9-92D6-15E00EC038D8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {AC18926A-E784-40FE-B09D-BB0FE2B599F0} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {E106CF37-4066-4615-B684-172A6D30B058} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {99135EAB-653D-47E4-A378-C96E1278CA44} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {3E53A01A-B331-47F3-B828-4A5717E77A24} = {8B6A8209-894F-4BA1-B880-965FD453982C} - {E3A1060B-50D0-44E8-88B6-F44EF2E5BD72} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {78CAFE33-DBEB-4132-8A28-81CFE8A4933C} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {54F237D5-A70A-4752-9656-0C70B1A7B047} = {B9894058-278A-46B5-B6ED-AD613FCC03B3} - {FB05AC90-89BA-4F2F-A924-F37875FB547C} = {B9894058-278A-46B5-B6ED-AD613FCC03B3} - {E4D9629C-F168-4224-3F51-A5E482FFBC42} = {A689DEF5-D50F-4975-8B72-124C9EB54066} - {6417E941-21BC-467B-A771-0DE389353CE6} = {8B6A8209-894F-4BA1-B880-965FD453982C} - {8EF392D5-1416-45AA-9956-7CBBC3229E8A} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {EA113F1A-D8D7-4142-9948-353270E7EBAE} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {3C4C0CB4-0C0F-4450-A37B-148C84FF905F} = {A689DEF5-D50F-4975-8B72-124C9EB54066} - {2F59F3D0-748D-4652-B01E-E0D954756308} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} - {925DD807-B651-475F-9F7C-CBEB974CE43D} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} - {BD43F7C0-396B-4AA1-BAD9-DFDE54D51298} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} - {F92E55A5-ED73-4CCB-AB4B-0541B6757F31} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} - {DA49C5F3-BE95-461C-B999-072128CCF59E} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} - {47BE08A7-5985-410B-9FFC-2264B8EA595F} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} - {78345174-5B52-4A14-B9FD-D5F2428137F0} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F} - {FF69B927-C545-49AE-8E16-3D14D621AA12} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F} - {4488AD85-1495-4809-9AA4-DDFE0A48527E} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1} - {8C923867-8A8F-4F6B-8B80-47D9E8436166} = {0CB0B92E-6CFF-4240-80A5-CCAFE75D91E1} - {E1AA3DBF-9056-4530-9376-18119A7A3FFE} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {88060192-33D5-4932-B0F9-8BD2763E857D} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {D0A739B9-3C68-4BA6-A328-41606954B6BD} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {2B888490-D14A-4BCA-AB4B-48676FA93C9B} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {57E0455D-D565-44BB-B069-EE1AA20F8337} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {D35A9F3D-8BB0-496E-BF72-444038A7DEBB} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - EndGlobalSection -EndGlobal diff --git a/appveyor.yml b/appveyor.yml index 2cb5bf6484..5b7be0823d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ version: 1.0.{build} os: Visual Studio 2015 before_build: - git submodule update --init -- nuget restore Perspex.sln +- nuget restore Avalonia.sln environment: myget_key: @@ -20,12 +20,12 @@ configuration: - Release after_test: -- .\packages\JetBrains.dotMemoryUnit.2.1.20150828.125449\tools\dotMemoryUnit.exe -targetExecutable="%xunit20%\xunit.console.x86.exe" -returnTargetExitCode --"tests\Perspex.LeakTests\bin\Release\Perspex.LeakTests.dll" +- .\packages\JetBrains.dotMemoryUnit.2.1.20150828.125449\tools\dotMemoryUnit.exe -targetExecutable="%xunit20%\xunit.console.x86.exe" -returnTargetExitCode --"tests\Avalonia.LeakTests\bin\Release\Avalonia.LeakTests.dll" - ps: nuget\build-appveyor.ps1 artifacts: - path: nuget\*.nupkg build: - project: Perspex.sln + project: Avalonia.sln verbosity: minimal diff --git a/docs/README.md b/docs/README.md index 44ed3528af..c65b576bfa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ -# Perspex Documentation +# Avalonia Documentation -* [API Reference](http://perspex.github.io/) +* [API Reference](http://avalonia.github.io/) ## Building diff --git a/docs/docfx.json b/docs/docfx.json index 4e908b97da..2b86d31d57 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -4,27 +4,27 @@ "src": [ { "files": [ - "/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj", - "/src/Gtk/Perspex.Gtk/Perspex.Gtk.csproj", - "/src/Markup/Perspex.Markup/Perspex.Markup.csproj", - "/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj", - "/src/Perspex.Animation/Perspex.Animation.csproj", - "/src/Perspex.Application/Perspex.Application.csproj", - "/src/Perspex.Base/Perspex.Base.csproj", - "/src/Perspex.Controls/Perspex.Controls.csproj", - "/src/Perspex.Diagnostics/Perspex.Diagnostics.csproj", - "/src/Perspex.HtmlRenderer/Perspex.HtmlRenderer.csproj", - "/src/Perspex.Input/Perspex.Input.csproj", - "/src/Perspex.Interactivity/Perspex.Interactivity.csproj", - "/src/Perspex.Layout/Perspex.Layout.csproj", - "/src/Perspex.ReactiveUI/Perspex.ReactiveUI.csproj", - "/src/Perspex.SceneGraph/Perspex.SceneGraph.csproj", - "/src/Perspex.Styling/Perspex.Styling.csproj", - "/src/Perspex.Themes.Default/Perspex.Themes.Default.csproj", - "/src/Skia/Perspex.Skia.Desktop/Perspex.Skia.Desktop.csproj", - "/src/Windows/Perspex.Designer/Perspex.Designer.csproj", - "/src/Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj", - "/src/Windows/Perspex.Win32/Perspex.Win32.csproj", + "/src/Gtk/Avalonia.Cairo/Avalonia.Cairo.csproj", + "/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj", + "/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj", + "/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj", + "/src/Avalonia.Animation/Avalonia.Animation.csproj", + "/src/Avalonia.Application/Avalonia.Application.csproj", + "/src/Avalonia.Base/Avalonia.Base.csproj", + "/src/Avalonia.Controls/Avalonia.Controls.csproj", + "/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj", + "/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj", + "/src/Avalonia.Input/Avalonia.Input.csproj", + "/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj", + "/src/Avalonia.Layout/Avalonia.Layout.csproj", + "/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj", + "/src/Avalonia.SceneGraph/Avalonia.SceneGraph.csproj", + "/src/Avalonia.Styling/Avalonia.Styling.csproj", + "/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj", + "/src/Skia/Avalonia.Skia.Desktop/Avalonia.Skia.Desktop.csproj", + "/src/Windows/Avalonia.Designer/Avalonia.Designer.csproj", + "/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj", + "/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj", ], "exclude": [ "**/bin/**", "**/obj/**" ], "cwd": ".." @@ -47,7 +47,7 @@ ], "overwrite": "apidoc/*.md", "globalMetadata": { - "_appTitle": "Perspex Website" + "_appTitle": "Avalonia Website" }, "dest": "_site", "template": [ "default", "template"] diff --git a/docs/guidelines/build.md b/docs/guidelines/build.md index 935341c0d5..f865224ee2 100644 --- a/docs/guidelines/build.md +++ b/docs/guidelines/build.md @@ -1,21 +1,21 @@ -# Building Perspex +# Building Avalonia ## Windows -Perspex requires Visual Studio 2015 to build on Windows. +Avalonia requires Visual Studio 2015 to build on Windows. ### Install GTK Sharp To compile the full project under windows, you must have [gtk-sharp](http://www.mono-project.com/download/#download-win) installed. However, if you're not interested in building the cross-platform bits you can simply unload these projects from Visual Studio: - - Perspex.Cairo - - Perspex.Cairo.RenderTests - - Perspex.Gtk + - Avalonia.Cairo + - Avalonia.Cairo.RenderTests + - Avalonia.Gtk -### Clone the Perspex repository +### Clone the Avalonia repository - git clone https://github.com/Perspex/Perspex.git + git clone https://github.com/AvaloniaUI/Avalonia.git We currently need to build our own private version of ReactiveUI as it doesn't work on mono. This is linked as a submodule in the git repository, so run: @@ -40,9 +40,9 @@ Then install the needed packages: sudo apt-get install git mono-devel referenceassemblies-pcl monodevelop -### Clone the Perspex repository +### Clone the Avalonia repository - git clone https://github.com/Perspex/Perspex.git + git clone https://github.com/AvaloniaUI/Avalonia.git We currently need to build our own private version of ReactiveUI as it doesn't work on mono. This is linked as a submodule in the git repository, so run: @@ -53,11 +53,11 @@ The next step is to download the Skia native libraries. Run ```getnatives.sh``` ### Load the Project in MonoDevelop -Start MonoDevelop and open the `Perspex.sln` solution. Wait for MonoDevelop to install the +Start MonoDevelop and open the `Avalonia.sln` solution. Wait for MonoDevelop to install the project's NuGet packages. Set the TestApplication project as the startup project and click Run. There will be some compile errors in the tests, but ignore them for now. -You can track the Linux version's progress in the [Linux issue](https://github.com/Perspex/Perspex/issues/78). +You can track the Linux version's progress in the [Linux issue](https://github.com/AvaloniaUI/Avalonia/issues/78). diff --git a/docs/guidelines/contributing.md b/docs/guidelines/contributing.md index 6b10297a3a..771b8f49f2 100644 --- a/docs/guidelines/contributing.md +++ b/docs/guidelines/contributing.md @@ -2,7 +2,7 @@ ## Before You Start ## -Drop into our [gitter chat room](https://gitter.im/Perspex/Perspex) and let us know what you're thinking of doing. We might be able to give you guidance or let you know if someone else is already working on the feature. +Drop into our [gitter chat room](https://gitter.im/Avalonia/Avalonia) and let us know what you're thinking of doing. We might be able to give you guidance or let you know if someone else is already working on the feature. ## Style ## @@ -46,9 +46,9 @@ There are two types of tests currently in the codebase; unit tests and render te Unit tests should be contained in a class name that mirrors the class being tested with the suffix -Tests, e.g. - Perspex.Controls.UnitTests.Presenters.TextPresenterTests + Avalonia.Controls.UnitTests.Presenters.TextPresenterTests -Where Perspex.Controls.UnitTests is the name of the project. +Where Avalonia.Controls.UnitTests is the name of the project. Unit test methods should be named in a sentence style, separated by underscores, that describes in English what the test is testing, e.g. diff --git a/docs/guidelines/toc.yml b/docs/guidelines/toc.yml index a3ef7bb87d..25bfbbf6bf 100644 --- a/docs/guidelines/toc.yml +++ b/docs/guidelines/toc.yml @@ -1,4 +1,4 @@ -- name: Building Perspex +- name: Building Avalonia href: build.md - name: Contributing href: contributing.md \ No newline at end of file diff --git a/docs/images/perspex-video.png b/docs/images/avalonia-video.png similarity index 100% rename from docs/images/perspex-video.png rename to docs/images/avalonia-video.png diff --git a/docs/index.md b/docs/index.md index b4a1a27744..99424e3f75 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,30 +1,30 @@ -# The Perspex UI Framework +# The Avalonia UI Framework Cross platform .NET UI Framework with bindings and XAML ## Current status -We're pleased to announce that Perspex is now in alpha! +We're pleased to announce that Avalonia is now in alpha! What does alpha mean? Well, it means that it's now at a stage where you can have a play and hopefully create simple applications. There's now a Visual Studio Extension containing project and item templates that will help you get started, and there's an initial complement of controls. There's still a lot missing, and you will find bugs, and the API will change, but this represents the first time where we've made it somewhat easy to have a play and experiment with the framework. ## How do I try it out -The easiest way to try out Perspex is to install the [Visual Studio Extension](https://visualstudiogallery.msdn.microsoft.com/a4542e8a-b56c-4295-8df1-7e220178b873). +The easiest way to try out Avalonia is to install the [Visual Studio Extension](https://visualstudiogallery.msdn.microsoft.com/a4542e8a-b56c-4295-8df1-7e220178b873). -This will add a Perspex project template and a Window template to the standard Visual Studo "Add" dialog (yes, icons still to come :) ): +This will add a Avalonia project template and a Window template to the standard Visual Studo "Add" dialog (yes, icons still to come :) ): ![](images/add-dialogs.png) -Creating a Perspex Project will give you a simple project with a single XAML window. We even have a simple designer: +Creating a Avalonia Project will give you a simple project with a single XAML window. We even have a simple designer: ![](images/hello-world-xaml.png) -You can also find the project [on GitHub](https://github.com/Perspex/Perspex/) +You can also find the project [on GitHub](https://github.com/AvaloniaUI/Avalonia/) ## News -You can read news about Perspex on [Groky's blog](http://grokys.github.io/) +You can read news about Avalonia on [Groky's blog](http://grokys.github.io/) ## Cross Platform diff --git a/docs/intro.md b/docs/intro.md index 85a457a385..1303815736 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -1,4 +1,4 @@ -# Perspex # +# Avalonia # ...a next generation WPF? @@ -14,8 +14,8 @@ written for .NET 1 and barely updated to even bring it up-to-date with .NET 2 fe generics. So I began to think: what if we were to start anew with modern C# features such as *(gasp)* -Generics, Observables, async, etc etc. The result of that thought is Perspex -(https://github.com/grokys/Perspex). +Generics, Observables, async, etc etc. The result of that thought is Avalonia +(https://github.com/grokys/Avalonia). ##### DISCLAIMER This is really **early development pre-alpha-alpha** stuff. Everything is subject to @@ -27,9 +27,9 @@ So what can it do so far? Not a whole lot right now. Here's the demo application ![](screen.png) -## PerspexProperty ## +## AvaloniaProperty ## -PerspexProperty is the equivalent of WPF's DependencyProperty. +AvaloniaProperty is the equivalent of WPF's DependencyProperty. I'm not a big fan of DependencyProperty. My first thought was that I'd rather not have something like this at all and just use basic INPC but DPs give you two important features: Inheritance and @@ -58,8 +58,8 @@ Eww! All that just to declare a single property. There's **A LOT** of boilerplat generics and default parameters we can at least make it look a bit nicer: ```csharp -public static readonly PerspexProperty PropertyDeclaration = -PerspexProperty.Register("PropertyName", inherits: true); +public static readonly AvaloniaProperty PropertyDeclaration = +AvaloniaProperty.Register("PropertyName", inherits: true); public PropertyType PropertyName { @@ -70,7 +70,7 @@ public PropertyType PropertyName What can we see here? -- PerspexProperties are typed, so no more having to cast in the getter. +- AvaloniaProperties are typed, so no more having to cast in the getter. - We pass the property type and owner class as a generic type to `Register()` so we don't have to write `typeof()` twice. - We used default parameter values in `Register()` so that defaults don't have to be restated. @@ -79,13 +79,13 @@ write `typeof()` twice. ## Binding -Binding in Perspex uses Reactive Extensions' [IObservable](http://msdn.microsoft.com/library/dd990377.aspx). To bind an IObservable to a property, use the `Bind()` method: +Binding in Avalonia uses Reactive Extensions' [IObservable](http://msdn.microsoft.com/library/dd990377.aspx). To bind an IObservable to a property, use the `Bind()` method: ```csharp control.Bind(BorderProperty, someObject.SomeObservable()); ``` -Note that because PerspexProperty is typed, we can check that the observable is of the correct type. +Note that because AvaloniaProperty is typed, we can check that the observable is of the correct type. To get the value of a property as an observable, call `GetObservable()`: @@ -144,7 +144,7 @@ var control = new Control ## Visual and Logical trees -Perspex uses the same visual/logical tree separation that is used by WPF (and to some extent HTML +Avalonia uses the same visual/logical tree separation that is used by WPF (and to some extent HTML is moving in this direction with the Shadow DOM). The manner of accessing the two trees is slightly different however. Rather than using Visual/LogicalTreeHelper you can cast any control to an `IVisual` or `ILogical` to reveal the tree operations. There's also the VisualExtensions class which @@ -156,7 +156,7 @@ property, which is determined by... ## Styles -Styles in Perspex diverge from styles in WPF quite a lot, and move towards a more CSS-like system. +Styles in Avalonia diverge from styles in WPF quite a lot, and move towards a more CSS-like system. It's probably easiest to show in an example. Here is the default style for the CheckBox control: ```csharp @@ -215,11 +215,11 @@ different look-and-feel. ## XAML As you can see, all of the examples here are defined in code - but a XAML implementation is being -worked on. The current progress can be reviewed at [https://github.com/SuperJMN/Perspex](https://github.com/SuperJMN/Perspex). +worked on. The current progress can be reviewed at [https://github.com/SuperJMN/Avalonia](https://github.com/SuperJMN/Avalonia). ## That's all for now There's a lot more to see, and even more to do, so if you want to have a play you can get the code -here: [https://github.com/grokys/Perspex](https://github.com/grokys/Perspex) +here: [https://github.com/grokys/Avalonia](https://github.com/grokys/Avalonia) Feedback is always welcome! diff --git a/docs/spec/architecture.md b/docs/spec/architecture.md index 1e9e5a0321..8966308a24 100644 --- a/docs/spec/architecture.md +++ b/docs/spec/architecture.md @@ -1,6 +1,6 @@ -# Perspex Architecture +# Avalonia Architecture -At the highest level, perspex is split up into a "core" and two "subsystems". +At the highest level, avalonia is split up into a "core" and two "subsystems". * The core is a set of Portable Class Libraries that can run anywhere. * The Windowing subsystem is responsible for creating windows, handling input and scheduling timers. @@ -10,37 +10,37 @@ There are currently two Windowing and two Rendering subsystems: ## Windowing Subsystems -* Perspex.Win32 uses the Win32 API (this also works on 64-bit windows). -* Perspex.Gtk uses the GTK2 toolkit and can be run on both Windows and *nix. +* Avalonia.Win32 uses the Win32 API (this also works on 64-bit windows). +* Avalonia.Gtk uses the GTK2 toolkit and can be run on both Windows and *nix. ## Rendering Subsystems -* Perspex.Direct2D1 uses Microsoft's Direct2D1 API. -* Perspex.Cairo uses Cairo for rendering and Pango for text layout. +* Avalonia.Direct2D1 uses Microsoft's Direct2D1 API. +* Avalonia.Cairo uses Cairo for rendering and Pango for text layout. ## Core -The Perspex core is split up into several assemblies. Note that they're not separated like this +The Avalonia core is split up into several assemblies. Note that they're not separated like this because you will want to use them separately; they are separate to maintain separation of concerns and a layered architecture. It is fully possible that they will be ILMerged into a single assembly for distribution. The assemblies are as follows, from lowest to highest level: -### Perspex.Base +### Avalonia.Base -The main classes in this assembly are `PerspexObject` and `PerspexProperty`. +The main classes in this assembly are `AvaloniaObject` and `AvaloniaProperty`. -These are Perspex's versions of XAML's `DependencyObject` and `DependencyProperty`. It also -defines a `PerspexDispatcher` which is - surprise - our version of XAML's `Dispatcher`. +These are Avalonia's versions of XAML's `DependencyObject` and `DependencyProperty`. It also +defines a `AvaloniaDispatcher` which is - surprise - our version of XAML's `Dispatcher`. -### Perspex.Animation +### Avalonia.Animation The main class in the assembly is `Animatable`. -Allows PerspexProperties to be animated and provides various utilities related to animation. +Allows AvaloniaProperties to be animated and provides various utilities related to animation. -### Perspex.SceneGraph +### Avalonia.SceneGraph The main class in this assembly is `Visual` and its interface `IVisual`. @@ -48,26 +48,26 @@ Defines the "Visual" layer which is a 2D scene graph, with each node being a `IV Also defines primitives such as `Point`/`Rect`/`Matrix`, plus `Geometry`, `Bitmap`, `Brush` and whatever else you might need in order to draw to the screen. -### Perspex.Styling +### Avalonia.Styling The main interface in this assembly is `IStyleable`. Defines a CSS-like system for styling controls. -### Perspex.Layout +### Avalonia.Layout The main class in this assembly is `Layoutable`. Defines a XAML-like layout system using `Measure` and `Arrange`. Also defines `LayoutManager` which carries out the actual layout. -### Perspex.Interactivity +### Avalonia.Interactivity The main class in this assembly is `Interactive`. Defines a system of routed events similar to those found in XAML. -### Perspex.Input +### Avalonia.Input The main class in this assembly is `InputElement`. @@ -76,7 +76,7 @@ Handles input from various devices such as `MouseDevice` and `KeyboardDevice`, t `InputManager` in the form of "Raw" events which are then translated into routed events for the controls. -### Perspex.Controls +### Avalonia.Controls There are many important classes in this assembly, but the root of them is `Control`. @@ -84,18 +84,18 @@ Finally defines the actual controls. The `Control` class is analogous to WPF's ` whereas the `TemplatedControl` class is our version of WPF's `Control`. This is also where you'll find all of the basic controls you'd expect. -### Perspex.Themes.Default +### Avalonia.Themes.Default Defines a default theme using a set of styles and control templates. -### Perspex.Application +### Avalonia.Application The main class in this assembly is `Application`. This ties everything together, setting up the service locator, defining the default theme etc. -### Perspex.Diagnostics +### Avalonia.Diagnostics -Adds utilities for debugging perspex applications, such as `DevTools` which provides a Snoop/WPF +Adds utilities for debugging avalonia applications, such as `DevTools` which provides a Snoop/WPF Inspector/Browser DevTools window for inspecting the state of the application. diff --git a/docs/spec/defining-properties.md b/docs/spec/defining-properties.md index 898efc8cef..d9e925aa1c 100644 --- a/docs/spec/defining-properties.md +++ b/docs/spec/defining-properties.md @@ -1,7 +1,7 @@ # Defining Properties If you are creating a control, you will want to define properties on your -control. The process in Perspex is broadly similar to other XAML languages +control. The process in Avalonia is broadly similar to other XAML languages with a few differences - the main one being that Perpsex's equivalent of `DependencyProperty` is called `StyledProperty`. @@ -10,7 +10,7 @@ with a few differences - the main one being that Perpsex's equivalent of A styled property is analogous to a `DependencyProperty` in other XAML frameworks. -You register a styled property by calling `PerspexProperty.Register` and +You register a styled property by calling `AvaloniaProperty.Register` and storing the result in a `static readonly` field. You then create a standard C# property to access it. @@ -18,7 +18,7 @@ Here's how the `Border` control defines its `Background` property: ```c# public static readonly StyledProperty BackgroundProperty = - PerspexProperty.Register(nameof(Background)); + AvaloniaProperty.Register(nameof(Background)); public Brush Background { @@ -27,7 +27,7 @@ Here's how the `Border` control defines its `Background` property: } ``` -The `PerspexProperty.Register` method also accepts a number of other parameters: +The `AvaloniaProperty.Register` method also accepts a number of other parameters: - `defaultValue`: This gives the property a default value. Be sure to only pass value types and immutable types here as passing a reference type will cause the @@ -72,7 +72,7 @@ Here's how `Grid` defines its `Grid.Column` attached property: ```c# public static readonly AttachedProperty ColumnProperty = - PerspexProperty.RegisterAttached("Column"); + AvaloniaProperty.RegisterAttached("Column"); public static int GetColumn(Control element) { @@ -85,14 +85,14 @@ Here's how `Grid` defines its `Grid.Column` attached property: } ``` -## Readonly PerspexProperties +## Readonly AvaloniaProperties -To create a readonly property you use the `PerspexProperty.RegisterDirect` +To create a readonly property you use the `AvaloniaProperty.RegisterDirect` method. Here is how `Visual` registers the readonly `Bounds` property: ```c# public static readonly DirectProperty BoundsProperty = - PerspexProperty.RegisterDirect( + AvaloniaProperty.RegisterDirect( nameof(Bounds), o => o.Bounds); @@ -110,13 +110,13 @@ registering the property, a getter is passed which is used to access the property value through `GetValue` and then `SetAndRaise` is used to notify listeners to changes to the property. -## Direct PerspexProperties +## Direct AvaloniaProperties As its name suggests, `RegisterDirect` isn't just used for registering readonly properties. You can also pass a *setter* to `RegisterDirect` to expose a -standard C# property as a Perspex property. +standard C# property as a Avalonia property. -A `StyledProperty` which is registered using `PerspexProperty.Register` +A `StyledProperty` which is registered using `AvaloniaProperty.Register` maintains a prioritized list of values and bindings that allow styles to work. However, this is overkill for many properties, such as `ItemsControl.Items` - this will never be styled and the overhead involved with styled properties is @@ -126,12 +126,12 @@ Here is how `ItemsControl.Items` is registered: ```c# public static readonly DirectProperty ItemsProperty = - PerspexProperty.RegisterDirect( + AvaloniaProperty.RegisterDirect( nameof(Items), o => o.Items, (o, v) => o.Items = v); - private IEnumerable _items = new PerspexList(); + private IEnumerable _items = new AvaloniaList(); public IEnumerable Items { @@ -144,8 +144,8 @@ Here is how `ItemsControl.Items` is registered: Direct properties are a lightweight version of styled properties that support the following: -- PerspexObject.GetValue -- PerspexObject.SetValue for non-readonly properties +- AvaloniaObject.GetValue +- AvaloniaObject.SetValue for non-readonly properties - PropertyChanged - Binding (only with LocalValue priority) - GetObservable @@ -170,7 +170,7 @@ on the control, you must also add a field for the property: o => o.Items, (o, v) => o.Items = v); - private IEnumerable _items = new PerspexList(); + private IEnumerable _items = new AvaloniaList(); public IEnumerable Items { @@ -190,7 +190,7 @@ Pros: Cons: - Cannot inherit value from parent control -- Cannot take advantage of Perspex's styling system +- Cannot take advantage of Avalonia's styling system - Property value is a field and as such is allocated whether the property is set on the object or not diff --git a/docs/spec/logging.md b/docs/spec/logging.md index 91d35023e4..60b8689d84 100644 --- a/docs/spec/logging.md +++ b/docs/spec/logging.md @@ -1,7 +1,7 @@ -# Perspex Logging +# Avalonia Logging -Perspex uses [Serilog](https://github.com/serilog/serilog) for logging via -the Perspex.Logging.Serilog assembly. +Avalonia uses [Serilog](https://github.com/serilog/serilog) for logging via +the Avalonia.Logging.Serilog assembly. The following method should be present in your App.xaml.cs file: @@ -24,7 +24,7 @@ for more information on the options here. ## Areas -Each Perspex log message has an "Area" that can be used to filter the log to +Each Avalonia log message has an "Area" that can be used to filter the log to include only the type of events that you are interested in. These are currently: - Property @@ -47,8 +47,8 @@ SerilogLogger.Initialize(new LoggerConfiguration() ## Removing Serilog If you don't want a dependency on Serilog in your application, simply remove -the reference to Perspex.Logging.Serilog and the code that initializes it. If +the reference to Avalonia.Logging.Serilog and the code that initializes it. If you do however still want some kinda of logging, there are two steps: -- Implement `Perspex.Logging.ILogSink` +- Implement `Avalonia.Logging.ILogSink` - Assign your implementation to `Logger.Sink` diff --git a/docs/spec/styles.md b/docs/spec/styles.md index 053d91b1e0..6f203591d7 100644 --- a/docs/spec/styles.md +++ b/docs/spec/styles.md @@ -1,7 +1,7 @@ -# Styling in Perspex +# Styling in Avalonia -The main difference between Perspex and existing XAML toolkits such as WPF and -UWP is in styling. Styling in Perspex uses a CSS-like system that aims to be +The main difference between Avalonia and existing XAML toolkits such as WPF and +UWP is in styling. Styling in Avalonia uses a CSS-like system that aims to be more powerful and flexible than existing XAML styling systems. For convenience for the rest of this document we'll refer to existing XAML toolkit's styling as "WPF styling" as that's where it originated. @@ -50,7 +50,7 @@ As in CSS, controls can be given *style classes* which can be used in selectors: Each control can be given 0 or more style classes. This is different to WPF -where only a single style can be applied to a control: in Perspex any number +where only a single style can be applied to a control: in Avalonia any number of separate styles can be applied to a control. If more than one style affects a particular property, the style closest to the control will take precedence. diff --git a/docs/spec/toc.yml b/docs/spec/toc.yml index 3075a03619..f225084c4e 100644 --- a/docs/spec/toc.yml +++ b/docs/spec/toc.yml @@ -1,6 +1,6 @@ -- name: Perspex Architecture +- name: Avalonia Architecture href: architecture.md -- name: Styling in Perspex +- name: Styling in Avalonia href: styles.md - name: Defining Properties href: defining-properties.md diff --git a/docs/spec/working-with-properties.md b/docs/spec/working-with-properties.md index bde12b50f2..74dd60a9b2 100644 --- a/docs/spec/working-with-properties.md +++ b/docs/spec/working-with-properties.md @@ -1,6 +1,6 @@ # Working with Properties -Perspex controls expose their properties as standard CLR properties, so for +Avalonia controls expose their properties as standard CLR properties, so for reading and writing values there's no surprises: ```c# @@ -77,9 +77,9 @@ The `GetObservable` method returns an observable that tracks changes to a property on a single instance. However, if you're writing a control you may want to implement an `OnPropertyChanged` method. In WPF this is done by passing a static `PropertyChangedCallback` to the `DependencyProperty` registration -method, but in Perspex it's slightly different (and hopefully easier!) +method, but in Avalonia it's slightly different (and hopefully easier!) -The field which defines the property is derived from `PerspexProperty` and this +The field which defines the property is derived from `AvaloniaProperty` and this has a `Changed` observable which is fired every time the property changes on *any* object. In addition there is an `AddClassHandler` extension method which can automatically route the event to a method on your control. @@ -93,7 +93,7 @@ you'd do it like this: FooProperty.Changed.AddClassHandler(x => x.FooChanged); } - private void FooChanged(PerspexPropertyChangedEventArgs e) + private void FooChanged(AvaloniaPropertyChangedEventArgs e) { // The 'e' parameter describes what's changed. } diff --git a/docs/template/partials/footer.tmpl.partial b/docs/template/partials/footer.tmpl.partial index a94f934e92..c9b8ba35e3 100644 --- a/docs/template/partials/footer.tmpl.partial +++ b/docs/template/partials/footer.tmpl.partial @@ -1,4 +1,4 @@ -{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
@@ -7,7 +7,7 @@ Back to top - Copyright © 2016 The Perspex Project
Generated by DocFX
+ Copyright © 2016 The Avalonia Project
Generated by DocFX
diff --git a/docs/tutorial/from-wpf.md b/docs/tutorial/from-wpf.md index 0b4fd82646..f25de9cde4 100644 --- a/docs/tutorial/from-wpf.md +++ b/docs/tutorial/from-wpf.md @@ -1,11 +1,11 @@ -# Perspex for WPF Developers +# Avalonia for WPF Developers -Perspex is in general very similar to WPF, but you will find differences. Here +Avalonia is in general very similar to WPF, but you will find differences. Here are the most common: ## Styling -The most obvious difference from other XAML frameworks is that Perspex uses a +The most obvious difference from other XAML frameworks is that Avalonia uses a [CSS-like styling system](../spec/styles.md). Styles aren't stored in a `Resources` collection as in WPF, they are stored in a separate `Styles` collection: @@ -51,7 +51,7 @@ place the template for your items into the control's `DataTemplates`, e.g. -Data templates in Perspex can also target interfaces and derived classes (which +Data templates in Avalonia can also target interfaces and derived classes (which cannot be done in WPF) and so the order of `DataTemplate`s can be important: `DataTemplate`s within the same collection are evaluated in declaration order so you need to place them from most-specific to least-specific as you would in @@ -59,15 +59,15 @@ code. ## HierachicalDataTemplate -WPF's `HierarchicalDataTemplate` is called `TreeDataTemplate` in Perspex (as the +WPF's `HierarchicalDataTemplate` is called `TreeDataTemplate` in Avalonia (as the former is difficult to type!). The two are almost entirely equivalent except -that the `ItemTemplate` property is not present in Perspex. +that the `ItemTemplate` property is not present in Avalonia. ## UIElement, FrameworkElement and Control WPF's `UIElement` and `FrameworkElement` are non-templated control base classes, -which roughly equate to the Perspex `Control` class. WPF's `Control` class on -the other hand is a templated control - Perspex's equivalent of this is +which roughly equate to the Avalonia `Control` class. WPF's `Control` class on +the other hand is a templated control - Avalonia's equivalent of this is `TemplatedControl`. So to recap: @@ -78,15 +78,15 @@ So to recap: ## DependencyProperty -The Perspex equivalent of `DependencyProperty` is `StyledProperty`, however -Perspex [has a richer property system than WPF](../spec/defining-properties.md), -and includes `DirectProperty` for turning standard CLR properties into Perspex +The Avalonia equivalent of `DependencyProperty` is `StyledProperty`, however +Avalonia [has a richer property system than WPF](../spec/defining-properties.md), +and includes `DirectProperty` for turning standard CLR properties into Avalonia properties. The common base class of `StyledProperty` and `DirectProperty` -is `PerspexProperty`. +is `AvaloniaProperty`. # Resources -There is no `Resources` collection on controls in Perspex, however `Style`s +There is no `Resources` collection on controls in Avalonia, however `Style`s do have a `Resources` collection for style-related resources. These can be referred to using the `{StyleResource}` markup extension both inside and outside styles. @@ -102,13 +102,13 @@ reasons](http://www.codemag.com/article/1501091) for this, but briefly: ## Grid -Column and row definitions can be specified in Perspex using strings, avoiding +Column and row definitions can be specified in Avalonia using strings, avoiding the clunky syntax in WPF: A common use of `Grid` in WPF is to stack two controls on top of each other. -For this purpose in Perspex you can just use a `Panel` which is more lightweight +For this purpose in Avalonia you can just use a `Panel` which is more lightweight than `Grid`. We don't yet support `SharedSizeScope` in `Grid`. @@ -116,12 +116,12 @@ We don't yet support `SharedSizeScope` in `Grid`. ## ItemsControl In WPF, `ItemsControl` and derived classes such as `ListBox` have two separate -items properties: `Items` and `ItemsSource`. Perspex however just has a single +items properties: `Items` and `ItemsSource`. Avalonia however just has a single one: `Items`. ## Tunnelling Events -Perspex has tunnelling events (unlike UWP!) but they're not exposed via +Avalonia has tunnelling events (unlike UWP!) but they're not exposed via separate `Preview` CLR event handlers. To subscribe to a tunnelling event you must call `AddHandler` with `RoutingStrategies.Tunnel`: @@ -149,7 +149,7 @@ An example of registering a class handler in WPF might be: { } -The equivalent of this in Perspex would be: +The equivalent of this in Avalonia would be: static MyControl() { @@ -161,7 +161,7 @@ The equivalent of this in Perspex would be: } Notice that in WPF you have to add the class handler as a static method, whereas -in Perspex the class handler is not static: the notification is automatically +in Avalonia the class handler is not static: the notification is automatically directed to the correct instance. ## PropertyChangedCallback @@ -171,6 +171,6 @@ register a `DependencyProperty` you can supply a static `PropertyChangedCallback but if you want to listen to changes from elsewhere [things can get complicated and error-prone](http://stackoverflow.com/questions/23682232). -In Perspex, there is no `PropertyChangedCallback` at the time of registration, +In Avalonia, there is no `PropertyChangedCallback` at the time of registration, instead a class listener is [added to the control's static constructor in much the same way that event class listeners are added](../spec/working-with-properties.md#subscribing-to-a-property-on-any-object). diff --git a/docs/tutorial/gettingstarted.md b/docs/tutorial/gettingstarted.md index c26b064dde..046be79278 100644 --- a/docs/tutorial/gettingstarted.md +++ b/docs/tutorial/gettingstarted.md @@ -1,15 +1,15 @@ -# Getting Started +# Getting Started ## Windows ![](images/add-dialogs.png) -The easiest way to try out Perspex is to install the Visual Studio Extension. +The easiest way to try out Avalonia is to install the Visual Studio Extension. -This will add a Perspex project template and a Window template to the standard Visual Studo “Add” dialog (yes, icons still to come :) ): +This will add a Avalonia project template and a Window template to the standard Visual Studo “Add” dialog (yes, icons still to come :) ): ## OSX / Linux -It is a little more manual on non-Windows platforms, but using Xamarin Studio you can install the Perspex NuGet package. +It is a little more manual on non-Windows platforms, but using Xamarin Studio you can install the Avalonia NuGet package. ![](images/add-packages.png) diff --git a/nuget/.gitignore b/nuget/.gitignore index d1dab00f5b..32f9557fad 100644 --- a/nuget/.gitignore +++ b/nuget/.gitignore @@ -1,2 +1,2 @@ -Perspex +Avalonia *.nupkg \ No newline at end of file diff --git a/nuget/build-appveyor.ps1 b/nuget/build-appveyor.ps1 index cbe6980648..ce9d12f290 100644 --- a/nuget/build-appveyor.ps1 +++ b/nuget/build-appveyor.ps1 @@ -27,7 +27,7 @@ if ([string]::IsNullOrWhiteSpace($pullreq)) echo "Repo branch matched" foreach($pkg in $Packages) { - nuget.exe push "$($pkg).$($version).nupkg" $key -Source https://www.myget.org/F/perspex-nightly/api/v2/package + nuget.exe push "$($pkg).$($version).nupkg" $key -Source https://www.myget.org/F/avalonia-nightly/api/v2/package } } } diff --git a/nuget/build-version.ps1 b/nuget/build-version.ps1 index 480d532f7f..c59789ddb8 100644 --- a/nuget/build-version.ps1 +++ b/nuget/build-version.ps1 @@ -8,14 +8,14 @@ foreach($pkg in $Packages) } rm -Force -Recurse *.nupkg -ErrorAction SilentlyContinue -Copy-Item template Perspex -Recurse -sv lib "Perspex\lib\portable-windows8+net45" -sv build "Perspex.Desktop\lib\net45" +Copy-Item template Avalonia -Recurse +sv lib "Avalonia\lib\portable-windows8+net45" +sv build "Avalonia.Desktop\lib\net45" -sv skia_root "Perspex.Skia.Desktop" -sv skia_lib "Perspex.Skia.Desktop\lib\net45" -sv android "Perspex.Android\lib\MonoAndroid10" -sv ios "Perspex.iOS\lib\Xamarin.iOS10" +sv skia_root "Avalonia.Skia.Desktop" +sv skia_lib "Avalonia.Skia.Desktop\lib\net45" +sv android "Avalonia.Android\lib\MonoAndroid10" +sv ios "Avalonia.iOS\lib\Xamarin.iOS10" mkdir $lib -ErrorAction SilentlyContinue mkdir $build -ErrorAction SilentlyContinue @@ -24,53 +24,53 @@ mkdir $android mkdir $ios -Copy-Item ..\src\Perspex.Animation\bin\Release\Perspex.Animation.dll $lib -Copy-Item ..\src\Perspex.Animation\bin\Release\Perspex.Animation.xml $lib -Copy-Item ..\src\Perspex.Base\bin\Release\Perspex.Base.dll $lib -Copy-Item ..\src\Perspex.Base\bin\Release\Perspex.Base.xml $lib -Copy-Item ..\src\Perspex.Controls\bin\Release\Perspex.Controls.dll $lib -Copy-Item ..\src\Perspex.Controls\bin\Release\Perspex.Controls.xml $lib -Copy-Item ..\src\Perspex.DesignerSupport\bin\Release\Perspex.DesignerSupport.dll $lib -Copy-Item ..\src\Perspex.DesignerSupport\bin\Release\Perspex.DesignerSupport.xml $lib -Copy-Item ..\src\Perspex.Diagnostics\bin\Release\\Perspex.Diagnostics.dll $lib -Copy-Item ..\src\Perspex.Diagnostics\bin\Release\\Perspex.Diagnostics.xml $lib -Copy-Item ..\src\Perspex.Input\bin\Release\Perspex.Input.dll $lib -Copy-Item ..\src\Perspex.Input\bin\Release\Perspex.Input.xml $lib -Copy-Item ..\src\Perspex.Interactivity\bin\Release\Perspex.Interactivity.dll $lib -Copy-Item ..\src\Perspex.Interactivity\bin\Release\Perspex.Interactivity.xml $lib -Copy-Item ..\src\Perspex.Layout\bin\Release\Perspex.Layout.dll $lib -Copy-Item ..\src\Perspex.Layout\bin\Release\Perspex.Layout.xml $lib -Copy-Item ..\src\Perspex.Logging.Serilog\bin\Release\Perspex.Logging.Serilog.dll $lib -Copy-Item ..\src\Perspex.Logging.Serilog\bin\Release\Perspex.Logging.Serilog.xml $lib -Copy-Item ..\src\Perspex.SceneGraph\bin\Release\Perspex.SceneGraph.dll $lib -Copy-Item ..\src\Perspex.SceneGraph\bin\Release\Perspex.SceneGraph.xml $lib -Copy-Item ..\src\Perspex.Styling\bin\Release\Perspex.Styling.dll $lib -Copy-Item ..\src\Perspex.Styling\bin\Release\Perspex.Styling.xml $lib -Copy-Item ..\src\Perspex.Themes.Default\bin\Release\Perspex.Themes.Default.dll $lib -Copy-Item ..\src\Perspex.Themes.Default\bin\Release\Perspex.Themes.Default.xml $lib -Copy-Item ..\src\Markup\Perspex.Markup\bin\Release\Perspex.Markup.dll $lib -Copy-Item ..\src\Markup\Perspex.Markup\bin\Release\Perspex.Markup.xml $lib -Copy-Item ..\src\Markup\Perspex.Markup.Xaml\bin\Release\Perspex.Markup.Xaml.dll $lib -Copy-Item ..\src\Markup\Perspex.Markup.Xaml\bin\Release\Perspex.Markup.Xaml.xml $lib -Copy-Item ..\src\Perspex.HtmlRenderer\bin\Release\Perspex.HtmlRenderer.dll $lib -Copy-Item ..\src\Perspex.ReactiveUI\bin\Release\Perspex.ReactiveUI.dll $lib +Copy-Item ..\src\Avalonia.Animation\bin\Release\Avalonia.Animation.dll $lib +Copy-Item ..\src\Avalonia.Animation\bin\Release\Avalonia.Animation.xml $lib +Copy-Item ..\src\Avalonia.Base\bin\Release\Avalonia.Base.dll $lib +Copy-Item ..\src\Avalonia.Base\bin\Release\Avalonia.Base.xml $lib +Copy-Item ..\src\Avalonia.Controls\bin\Release\Avalonia.Controls.dll $lib +Copy-Item ..\src\Avalonia.Controls\bin\Release\Avalonia.Controls.xml $lib +Copy-Item ..\src\Avalonia.DesignerSupport\bin\Release\Avalonia.DesignerSupport.dll $lib +Copy-Item ..\src\Avalonia.DesignerSupport\bin\Release\Avalonia.DesignerSupport.xml $lib +Copy-Item ..\src\Avalonia.Diagnostics\bin\Release\\Avalonia.Diagnostics.dll $lib +Copy-Item ..\src\Avalonia.Diagnostics\bin\Release\\Avalonia.Diagnostics.xml $lib +Copy-Item ..\src\Avalonia.Input\bin\Release\Avalonia.Input.dll $lib +Copy-Item ..\src\Avalonia.Input\bin\Release\Avalonia.Input.xml $lib +Copy-Item ..\src\Avalonia.Interactivity\bin\Release\Avalonia.Interactivity.dll $lib +Copy-Item ..\src\Avalonia.Interactivity\bin\Release\Avalonia.Interactivity.xml $lib +Copy-Item ..\src\Avalonia.Layout\bin\Release\Avalonia.Layout.dll $lib +Copy-Item ..\src\Avalonia.Layout\bin\Release\Avalonia.Layout.xml $lib +Copy-Item ..\src\Avalonia.Logging.Serilog\bin\Release\Avalonia.Logging.Serilog.dll $lib +Copy-Item ..\src\Avalonia.Logging.Serilog\bin\Release\Avalonia.Logging.Serilog.xml $lib +Copy-Item ..\src\Avalonia.SceneGraph\bin\Release\Avalonia.SceneGraph.dll $lib +Copy-Item ..\src\Avalonia.SceneGraph\bin\Release\Avalonia.SceneGraph.xml $lib +Copy-Item ..\src\Avalonia.Styling\bin\Release\Avalonia.Styling.dll $lib +Copy-Item ..\src\Avalonia.Styling\bin\Release\Avalonia.Styling.xml $lib +Copy-Item ..\src\Avalonia.Themes.Default\bin\Release\Avalonia.Themes.Default.dll $lib +Copy-Item ..\src\Avalonia.Themes.Default\bin\Release\Avalonia.Themes.Default.xml $lib +Copy-Item ..\src\Markup\Avalonia.Markup\bin\Release\Avalonia.Markup.dll $lib +Copy-Item ..\src\Markup\Avalonia.Markup\bin\Release\Avalonia.Markup.xml $lib +Copy-Item ..\src\Markup\Avalonia.Markup.Xaml\bin\Release\Avalonia.Markup.Xaml.dll $lib +Copy-Item ..\src\Markup\Avalonia.Markup.Xaml\bin\Release\Avalonia.Markup.Xaml.xml $lib +Copy-Item ..\src\Avalonia.HtmlRenderer\bin\Release\Avalonia.HtmlRenderer.dll $lib +Copy-Item ..\src\Avalonia.ReactiveUI\bin\Release\Avalonia.ReactiveUI.dll $lib -Copy-Item ..\src\Windows\Perspex.Direct2D1\bin\Release\Perspex.Direct2D1.dll $build -Copy-Item ..\src\Windows\Perspex.Win32\bin\Release\Perspex.Win32.dll $build -Copy-Item ..\src\Gtk\Perspex.Gtk\bin\Release\Perspex.Gtk.dll $build -Copy-Item ..\src\Gtk\Perspex.Cairo\bin\Release\Perspex.Cairo.dll $build +Copy-Item ..\src\Windows\Avalonia.Direct2D1\bin\Release\Avalonia.Direct2D1.dll $build +Copy-Item ..\src\Windows\Avalonia.Win32\bin\Release\Avalonia.Win32.dll $build +Copy-Item ..\src\Gtk\Avalonia.Gtk\bin\Release\Avalonia.Gtk.dll $build +Copy-Item ..\src\Gtk\Avalonia.Cairo\bin\Release\Avalonia.Cairo.dll $build -Copy-Item ..\src\Skia\Perspex.Skia.Desktop\bin\x86\Release\Perspex.Skia.Desktop.dll $skia_lib +Copy-Item ..\src\Skia\Avalonia.Skia.Desktop\bin\x86\Release\Avalonia.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 +Copy-Item ..\src\Android\Avalonia.Android\bin\Release\Avalonia.Android.dll $android +Copy-Item ..\src\Skia\Avalonia.Skia.Android\bin\Release\Avalonia.Skia.Android.dll $android -Copy-Item ..\src\iOS\Perspex.iOS\bin\iPhone\Release\Perspex.iOS.dll $ios -Copy-Item ..\src\Skia\Perspex.Skia.iOS\bin\iPhone\Release\Perspex.Skia.iOS.dll $ios +Copy-Item ..\src\iOS\Avalonia.iOS\bin\iPhone\Release\Avalonia.iOS.dll $ios +Copy-Item ..\src\Skia\Avalonia.Skia.iOS\bin\iPhone\Release\Avalonia.Skia.iOS.dll $ios foreach($pkg in $Packages) { - (gc Perspex\$pkg.nuspec).replace('#VERSION#', $args[0]) | sc $pkg\$pkg.nuspec + (gc Avalonia\$pkg.nuspec).replace('#VERSION#', $args[0]) | sc $pkg\$pkg.nuspec } foreach($pkg in $Packages) diff --git a/nuget/include.ps1 b/nuget/include.ps1 index f1e6f5d523..bde8ebb731 100644 --- a/nuget/include.ps1 +++ b/nuget/include.ps1 @@ -1 +1 @@ -$Packages = @("Perspex", "Perspex.Desktop", "Perspex.Skia.Desktop", "Perspex.Android", "Perspex.iOS") \ No newline at end of file +$Packages = @("Avalonia", "Avalonia.Desktop", "Avalonia.Skia.Desktop", "Avalonia.Android", "Avalonia.iOS") \ No newline at end of file diff --git a/nuget/template/Avalonia.Android.nuspec b/nuget/template/Avalonia.Android.nuspec new file mode 100644 index 0000000000..81418e442a --- /dev/null +++ b/nuget/template/Avalonia.Android.nuspec @@ -0,0 +1,27 @@ + + + + Avalonia.Android + #VERSION# + Avalonia Team + stevenk + http://opensource.org/licenses/MIT + https://github.com/AvaloniaUI/Avalonia/ + false + The Avalonia UI framework + + Copyright 2015 + Avalonia + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuget/template/Avalonia.Desktop.nuspec b/nuget/template/Avalonia.Desktop.nuspec new file mode 100644 index 0000000000..b5311be8dd --- /dev/null +++ b/nuget/template/Avalonia.Desktop.nuspec @@ -0,0 +1,30 @@ + + + + Avalonia.Desktop + #VERSION# + Avalonia Team + stevenk + http://opensource.org/licenses/MIT + https://github.com/AvaloniaUI/Avalonia/ + false + The Avalonia UI framework + + Copyright 2015 + Avalonia + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuget/template/Avalonia.Skia.Desktop.nuspec b/nuget/template/Avalonia.Skia.Desktop.nuspec new file mode 100644 index 0000000000..8361fa4428 --- /dev/null +++ b/nuget/template/Avalonia.Skia.Desktop.nuspec @@ -0,0 +1,20 @@ + + + + Avalonia.Skia.Desktop + #VERSION# + Avalonia Team + stevenk + http://opensource.org/licenses/MIT + https://github.com/AvaloniaUI/Avalonia/ + false + The Avalonia UI framework + + Copyright 2015 + Avalonia + + + + + + \ No newline at end of file diff --git a/nuget/template/Avalonia.iOS.nuspec b/nuget/template/Avalonia.iOS.nuspec new file mode 100644 index 0000000000..4d572b591b --- /dev/null +++ b/nuget/template/Avalonia.iOS.nuspec @@ -0,0 +1,27 @@ + + + + Avalonia.iOS + #VERSION# + Avalonia Team + stevenk + http://opensource.org/licenses/MIT + https://github.com/AvaloniaUI/Avalonia/ + false + The Avalonia UI framework + + Copyright 2015 + Avalonia + + + + + + + + + + + + + \ No newline at end of file diff --git a/nuget/template/Avalonia.nuspec b/nuget/template/Avalonia.nuspec new file mode 100644 index 0000000000..32594ebea7 --- /dev/null +++ b/nuget/template/Avalonia.nuspec @@ -0,0 +1,26 @@ + + + + Avalonia + #VERSION# + Avalonia Team + stevenk + http://opensource.org/licenses/MIT + https://github.com/AvaloniaUI/Avalonia/ + false + The Avalonia UI framework + Initial alpha release. + Copyright 2015 + Avalonia + + + + + + + + + + + + \ No newline at end of file diff --git a/nuget/template/Perspex.Android.nuspec b/nuget/template/Perspex.Android.nuspec deleted file mode 100644 index 5ee0174a43..0000000000 --- a/nuget/template/Perspex.Android.nuspec +++ /dev/null @@ -1,27 +0,0 @@ - - - - Perspex.Android - #VERSION# - Perspex Team - stevenk - http://opensource.org/licenses/MIT - https://github.com/Perspex/Perspex/ - false - The Perspex UI framework - - Copyright 2015 - Perspex - - - - - - - - - - - - - \ No newline at end of file diff --git a/nuget/template/Perspex.Desktop.nuspec b/nuget/template/Perspex.Desktop.nuspec deleted file mode 100644 index a920cf8657..0000000000 --- a/nuget/template/Perspex.Desktop.nuspec +++ /dev/null @@ -1,30 +0,0 @@ - - - - Perspex.Desktop - #VERSION# - Perspex Team - stevenk - http://opensource.org/licenses/MIT - https://github.com/Perspex/Perspex/ - false - The Perspex UI framework - - Copyright 2015 - Perspex - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/nuget/template/Perspex.Skia.Desktop.nuspec b/nuget/template/Perspex.Skia.Desktop.nuspec deleted file mode 100644 index 59616049fa..0000000000 --- a/nuget/template/Perspex.Skia.Desktop.nuspec +++ /dev/null @@ -1,20 +0,0 @@ - - - - Perspex.Skia.Desktop - #VERSION# - Perspex Team - stevenk - http://opensource.org/licenses/MIT - https://github.com/Perspex/Perspex/ - false - The Perspex UI framework - - Copyright 2015 - Perspex - - - - - - \ No newline at end of file diff --git a/nuget/template/Perspex.iOS.nuspec b/nuget/template/Perspex.iOS.nuspec deleted file mode 100644 index f85d8be5c1..0000000000 --- a/nuget/template/Perspex.iOS.nuspec +++ /dev/null @@ -1,27 +0,0 @@ - - - - Perspex.iOS - #VERSION# - Perspex Team - stevenk - http://opensource.org/licenses/MIT - https://github.com/Perspex/Perspex/ - false - The Perspex UI framework - - Copyright 2015 - Perspex - - - - - - - - - - - - - \ No newline at end of file diff --git a/nuget/template/Perspex.nuspec b/nuget/template/Perspex.nuspec deleted file mode 100644 index 0339e1b2b8..0000000000 --- a/nuget/template/Perspex.nuspec +++ /dev/null @@ -1,26 +0,0 @@ - - - - Perspex - #VERSION# - Perspex Team - stevenk - http://opensource.org/licenses/MIT - https://github.com/Perspex/Perspex/ - false - The Perspex UI framework - Initial alpha release. - Copyright 2015 - Perspex - - - - - - - - - - - - \ No newline at end of file diff --git a/readme.md b/readme.md index f4cb42f927..090eb244b2 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ -# Perspex -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/Perspex/Perspex?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) +# Avalonia +[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/Avalonia/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) -[![Build status](https://ci.appveyor.com/api/projects/status/hubk3k0w9idyibfg/branch/master?svg=true)](https://ci.appveyor.com/project/Perspex/Perspex/branch/master) +[![Build status](https://ci.appveyor.com/api/projects/status/hubk3k0w9idyibfg/branch/master?svg=true)](https://ci.appveyor.com/project/Avalonia/Avalonia/branch/master) A multi-platform .NET UI framework. It can run on Windows, Linux, Mac OS X, iOS and Android. @@ -9,7 +9,7 @@ A multi-platform .NET UI framework. It can run on Windows, Linux, Mac OS X, iOS Desktop platforms: -![](docs/images/perspex-video.png) +![](docs/images/avalonia-video.png) Mobile platforms: @@ -17,21 +17,21 @@ Mobile platforms: ## NuGet -Perspex is delivered as a NuGet package. -You can find the packages here: ([stable(ish)](https://www.nuget.org/packages/Perspex/), [nightly](https://github.com/Perspex/Perspex/wiki/Using-nightly-build-feed)) +Avalonia is delivered as a NuGet package. +You can find the packages here: ([stable(ish)](https://www.nuget.org/packages/Avalonia/), [nightly](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed)) You can install the package like this: -`Install-Package Perspex -Pre` +`Install-Package Avalonia -Pre` ## Background -Perspex is a multi-platform windowing toolkit - somewhat like WPF - that is intended to be multi- +Avalonia is a multi-platform windowing toolkit - somewhat like WPF - that is intended to be multi- platform. It supports XAML, lookless controls and a flexible styling system, and runs on Windows using Direct2D and other operating systems using Gtk & Cairo. ## Current Status -Perspex is now in alpha. What does "alpha" mean? Well, it means that it's now at a stage where you +Avalonia is now in alpha. What does "alpha" mean? Well, it means that it's now at a stage where you can have a play and hopefully create simple applications. There's now a [Visual Studio Extension](https://visualstudiogallery.msdn.microsoft.com/a4542e8a-b56c-4295-8df1-7e220178b873) containing project and item templates that will help you get started, and @@ -42,13 +42,13 @@ framework. ## Documentation -As mentioned above, Perspex is still in alpha and as such there's not much documentation yet. You can +As mentioned above, Avalonia is still in alpha and as such there's not much documentation yet. You can take a look at the [getting started page](docs/tutorial/gettingstarted.md) for an overview of how to get started but probably the best thing to do for now is to already know a little bit -about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/Perspex/Perspex). +about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/Avalonia/Avalonia). There's also a high-level [architecture document](docs/spec/architecture.md) that is currently a little bit -out of date, and I've also started writing blog posts on Perspex at http://grokys.github.io/. +out of date, and I've also started writing blog posts on Avalonia at http://grokys.github.io/. Contributions are always welcome! diff --git a/samples/BindingTest/App.xaml b/samples/BindingTest/App.xaml index b416385619..d9630eef58 100644 --- a/samples/BindingTest/App.xaml +++ b/samples/BindingTest/App.xaml @@ -1,6 +1,6 @@ - + - - + + \ No newline at end of file diff --git a/samples/BindingTest/App.xaml.cs b/samples/BindingTest/App.xaml.cs index ef5f7ba4d9..26df631523 100644 --- a/samples/BindingTest/App.xaml.cs +++ b/samples/BindingTest/App.xaml.cs @@ -1,9 +1,9 @@ -using System; -using Perspex; -using Perspex.Controls; -using Perspex.Diagnostics; -using Perspex.Logging.Serilog; -using Perspex.Markup.Xaml; +using System; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Diagnostics; +using Avalonia.Logging.Serilog; +using Avalonia.Markup.Xaml; using Serilog; namespace BindingTest diff --git a/samples/BindingTest/BindingTest.csproj b/samples/BindingTest/BindingTest.csproj index ed4900a402..6001b70d31 100644 --- a/samples/BindingTest/BindingTest.csproj +++ b/samples/BindingTest/BindingTest.csproj @@ -1,4 +1,4 @@ - + @@ -100,73 +100,73 @@ - + {3e53a01a-b331-47f3-b828-4a5717e77a24} - Perspex.Markup.Xaml + Avalonia.Markup.Xaml - + {6417e941-21bc-467b-a771-0de389353ce6} - Perspex.Markup + Avalonia.Markup - + {d211e587-d8bc-45b9-95a4-f297c8fa5200} - Perspex.Animation + Avalonia.Animation - + {b09b78d8-9b26-48b0-9149-d64a2f120f3f} - Perspex.Base + Avalonia.Base - + {d2221c82-4a25-4583-9b43-d791e3f6820c} - Perspex.Controls + Avalonia.Controls - + {799a7bb5-3c2c-48b6-85a7-406a12c420da} - Perspex.DesignerSupport + Avalonia.DesignerSupport - + {7062ae20-5dcc-4442-9645-8195bdece63e} - Perspex.Diagnostics + Avalonia.Diagnostics - + {62024b2d-53eb-4638-b26b-85eeaa54866e} - Perspex.Input + Avalonia.Input - + {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} - Perspex.Interactivity + Avalonia.Interactivity - + {42472427-4774-4c81-8aff-9f27b8e31721} - Perspex.Layout + Avalonia.Layout - + {b61b66a3-b82d-4875-8001-89d3394fe0c9} - Perspex.Logging.Serilog + Avalonia.Logging.Serilog - + {6417b24e-49c2-4985-8db2-3ab9d898ec91} - Perspex.ReactiveUI + Avalonia.ReactiveUI - + {eb582467-6abb-43a1-b052-e981ba910e3a} - Perspex.SceneGraph + Avalonia.SceneGraph - + {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} - Perspex.Styling + Avalonia.Styling - + {3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f} - Perspex.Themes.Default + Avalonia.Themes.Default - + {3e908f67-5543-4879-a1dc-08eace79b3cd} - Perspex.Direct2D1 + Avalonia.Direct2D1 - + {811a76cf-1cf6-440f-963b-bbe31bd72a82} - Perspex.Win32 + Avalonia.Win32 diff --git a/samples/BindingTest/MainWindow.xaml b/samples/BindingTest/MainWindow.xaml index 9bd6a3e3a8..e8c32d7560 100644 --- a/samples/BindingTest/MainWindow.xaml +++ b/samples/BindingTest/MainWindow.xaml @@ -1,4 +1,4 @@ - diff --git a/samples/BindingTest/MainWindow.xaml.cs b/samples/BindingTest/MainWindow.xaml.cs index 00b46faecf..8b07c6b482 100644 --- a/samples/BindingTest/MainWindow.xaml.cs +++ b/samples/BindingTest/MainWindow.xaml.cs @@ -1,7 +1,7 @@ -using BindingTest.ViewModels; -using Perspex; -using Perspex.Controls; -using Perspex.Markup.Xaml; +using BindingTest.ViewModels; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; namespace BindingTest { diff --git a/samples/BindingTest/Properties/AssemblyInfo.cs b/samples/BindingTest/Properties/AssemblyInfo.cs index 648b1cb406..79166d5f29 100644 --- a/samples/BindingTest/Properties/AssemblyInfo.cs +++ b/samples/BindingTest/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/samples/BindingTest/TestItemView.xaml b/samples/BindingTest/TestItemView.xaml index 80b377a2ab..6594f2d93e 100644 --- a/samples/BindingTest/TestItemView.xaml +++ b/samples/BindingTest/TestItemView.xaml @@ -1,4 +1,4 @@ - + diff --git a/samples/BindingTest/TestItemView.xaml.cs b/samples/BindingTest/TestItemView.xaml.cs index f6e85a84e3..32f367ef68 100644 --- a/samples/BindingTest/TestItemView.xaml.cs +++ b/samples/BindingTest/TestItemView.xaml.cs @@ -1,5 +1,5 @@ -using Perspex.Controls; -using Perspex.Markup.Xaml; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; namespace BindingTest { @@ -12,7 +12,7 @@ namespace BindingTest private void InitializeComponent() { - PerspexXamlLoader.Load(this); + AvaloniaXamlLoader.Load(this); } } } diff --git a/samples/BindingTest/ViewModels/MainWindowViewModel.cs b/samples/BindingTest/ViewModels/MainWindowViewModel.cs index 114ddf5cbf..28c3684501 100644 --- a/samples/BindingTest/ViewModels/MainWindowViewModel.cs +++ b/samples/BindingTest/ViewModels/MainWindowViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.ObjectModel; using System.Linq; using ReactiveUI; diff --git a/samples/BindingTest/ViewModels/TestItem.cs b/samples/BindingTest/ViewModels/TestItem.cs index 22cd97637c..2326a92b7d 100644 --- a/samples/BindingTest/ViewModels/TestItem.cs +++ b/samples/BindingTest/ViewModels/TestItem.cs @@ -1,4 +1,4 @@ -using ReactiveUI; +using ReactiveUI; namespace BindingTest.ViewModels { diff --git a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj index 6cbf41ebbd..79f5f1d259 100644 --- a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj +++ b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj @@ -1,4 +1,4 @@ - + @@ -59,53 +59,53 @@ - + {FB05AC90-89BA-4F2F-A924-F37875FB547C} - Perspex.Cairo + Avalonia.Cairo - + {54F237D5-A70A-4752-9656-0C70B1A7B047} - Perspex.Gtk + Avalonia.Gtk - + {3E53A01A-B331-47F3-B828-4A5717E77A24} - Perspex.Markup.Xaml + Avalonia.Markup.Xaml - + {6417E941-21BC-467B-A771-0DE389353CE6} - Perspex.Markup + Avalonia.Markup - + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} - Perspex.Base + Avalonia.Base - + {D2221C82-4A25-4583-9B43-D791E3F6820C} - Perspex.Controls + Avalonia.Controls - + {B61B66A3-B82D-4875-8001-89D3394FE0C9} - Perspex.Logging.Serilog + Avalonia.Logging.Serilog - + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} - Perspex.Styling + Avalonia.Styling - + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F} - Perspex.Themes.Default + Avalonia.Themes.Default - + {925DD807-B651-475F-9F7C-CBEB974CE43D} - Perspex.Skia.Desktop + Avalonia.Skia.Desktop - + {3E908F67-5543-4879-A1DC-08EACE79B3CD} - Perspex.Direct2D1 + Avalonia.Direct2D1 - + {811A76CF-1CF6-440F-963B-BBE31BD72A82} - Perspex.Win32 + Avalonia.Win32 {d0a739b9-3c68-4ba6-a328-41606954b6bd} diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs index 3a6f466b9e..4257587b21 100644 --- a/samples/ControlCatalog.Desktop/Program.cs +++ b/samples/ControlCatalog.Desktop/Program.cs @@ -1,10 +1,10 @@ -using Perspex.Logging.Serilog; +using Avalonia.Logging.Serilog; using Serilog; using System; using System.Linq; -using Perspex; +using Avalonia; using System.Reflection; -using Perspex.Platform; +using Avalonia.Platform; namespace ControlCatalog { diff --git a/samples/ControlCatalog.Desktop/Properties/AssemblyInfo.cs b/samples/ControlCatalog.Desktop/Properties/AssemblyInfo.cs index 2377b91393..78460f60db 100644 --- a/samples/ControlCatalog.Desktop/Properties/AssemblyInfo.cs +++ b/samples/ControlCatalog.Desktop/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/samples/ControlCatalog.iOS/AppDelegate.cs b/samples/ControlCatalog.iOS/AppDelegate.cs index 68d53f9bf5..94c79cd60b 100644 --- a/samples/ControlCatalog.iOS/AppDelegate.cs +++ b/samples/ControlCatalog.iOS/AppDelegate.cs @@ -1,6 +1,6 @@ -using Foundation; +using Foundation; using UIKit; -using Perspex; +using Avalonia; namespace ControlCatalog { diff --git a/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj b/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj index d66671c9b9..d216c5ad82 100644 --- a/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj +++ b/samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj @@ -1,4 +1,4 @@ - + Debug @@ -115,67 +115,67 @@ - + {4488AD85-1495-4809-9AA4-DDFE0A48527E} - Perspex.iOS + Avalonia.iOS false false - + {3E53A01A-B331-47F3-B828-4A5717E77A24} - Perspex.Markup.Xaml + Avalonia.Markup.Xaml - + {6417E941-21BC-467B-A771-0DE389353CE6} - Perspex.Markup + Avalonia.Markup - + {D211E587-D8BC-45B9-95A4-F297C8FA5200} - Perspex.Animation + Avalonia.Animation - + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} - Perspex.Base + Avalonia.Base - + {D2221C82-4A25-4583-9B43-D791E3F6820C} - Perspex.Controls + Avalonia.Controls - + {7062AE20-5DCC-4442-9645-8195BDECE63E} - Perspex.Diagnostics + Avalonia.Diagnostics - + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D} - Perspex.HtmlRenderer + Avalonia.HtmlRenderer - + {62024B2D-53EB-4638-B26B-85EEAA54866E} - Perspex.Input + Avalonia.Input - + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B} - Perspex.Interactivity + Avalonia.Interactivity - + {42472427-4774-4C81-8AFF-9F27B8E31721} - Perspex.Layout + Avalonia.Layout - + {EB582467-6ABB-43A1-B052-E981BA910E3A} - Perspex.SceneGraph + Avalonia.SceneGraph - + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} - Perspex.Styling + Avalonia.Styling - + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F} - Perspex.Themes.Default + Avalonia.Themes.Default - + {47BE08A7-5985-410B-9FFC-2264B8EA595F} - Perspex.Skia.iOS + Avalonia.Skia.iOS false false diff --git a/samples/ControlCatalog.iOS/Main.cs b/samples/ControlCatalog.iOS/Main.cs index 64c6298fca..fe039ba69e 100644 --- a/samples/ControlCatalog.iOS/Main.cs +++ b/samples/ControlCatalog.iOS/Main.cs @@ -1,4 +1,4 @@ -using UIKit; +using UIKit; namespace ControlCatalog.iOS { diff --git a/samples/ControlCatalog.iOS/Properties/AssemblyInfo.cs b/samples/ControlCatalog.iOS/Properties/AssemblyInfo.cs index 88c6abb1dd..0a5a598651 100644 --- a/samples/ControlCatalog.iOS/Properties/AssemblyInfo.cs +++ b/samples/ControlCatalog.iOS/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/samples/ControlCatalog.iOS/Resources/LaunchScreen.xib b/samples/ControlCatalog.iOS/Resources/LaunchScreen.xib index e370a5ea74..be4abb2b43 100644 --- a/samples/ControlCatalog.iOS/Resources/LaunchScreen.xib +++ b/samples/ControlCatalog.iOS/Resources/LaunchScreen.xib @@ -1,4 +1,4 @@ - + diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml index d01ab6f126..43971dec4f 100644 --- a/samples/ControlCatalog/App.xaml +++ b/samples/ControlCatalog/App.xaml @@ -1,7 +1,7 @@ - + - - + + + + + + + + + \ No newline at end of file diff --git a/src/Perspex.Diagnostics/app.config b/src/Avalonia.Diagnostics/app.config similarity index 100% rename from src/Perspex.Diagnostics/app.config rename to src/Avalonia.Diagnostics/app.config diff --git a/src/Perspex.Diagnostics/packages.config b/src/Avalonia.Diagnostics/packages.config similarity index 100% rename from src/Perspex.Diagnostics/packages.config rename to src/Avalonia.Diagnostics/packages.config diff --git a/src/Avalonia.HtmlRenderer/Adapters/AvaloniaAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/AvaloniaAdapter.cs new file mode 100644 index 0000000000..12c040fab3 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Adapters/AvaloniaAdapter.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Input.Platform; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; +using TheArtOfDev.HtmlRenderer.Avalonia.Utilities; + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters +{ + class AvaloniaAdapter : RAdapter + { + public static AvaloniaAdapter Instance { get; } = new AvaloniaAdapter(); + + /// + /// List of valid predefined color names in lower-case + /// + private static readonly Dictionary ColorNameDic = new Dictionary(); + + + static AvaloniaAdapter() + { + foreach (var colorProp in typeof(Colors).GetRuntimeProperties() + .Where(p=>p.PropertyType == typeof(Color))) + { + ColorNameDic[colorProp.Name.ToLower()] = (Color)colorProp.GetValue(null); + } + } + + protected override RColor GetColorInt(string colorName) + { + Color c; + if(!ColorNameDic.TryGetValue(colorName.ToLower(), out c)) + return RColor.Empty; + return Util.Convert(c); + } + + protected override RPen CreatePen(RColor color) + { + return new PenAdapter(GetSolidColorBrush(color)); + } + + /// + /// Get solid color brush for the given color. + /// + private static IBrush GetSolidColorBrush(RColor color) + { + IBrush solidBrush; + if (color == RColor.White) + solidBrush = Brushes.White; + else if (color == RColor.Black) + solidBrush = Brushes.Black; + else if (color.A < 1) + solidBrush = Brushes.Transparent; + else + solidBrush = new SolidColorBrush(Util.Convert(color)); + return solidBrush; + } + + protected override RBrush CreateSolidBrush(RColor color) + { + return new BrushAdapter(GetSolidColorBrush(color)); + } + + protected override RBrush CreateLinearGradientBrush(RRect rect, RColor color1, RColor color2, double angle) + { + var startColor = angle <= 180 ? Util.Convert(color1) : Util.Convert(color2); + var endColor = angle <= 180 ? Util.Convert(color2) : Util.Convert(color1); + angle = angle <= 180 ? angle : angle - 180; + double x = angle < 135 ? Math.Max((angle - 45) / 90, 0) : 1; + double y = angle <= 45 ? Math.Max(0.5 - angle / 90, 0) : angle > 135 ? Math.Abs(1.5 - angle / 90) : 0; + return new BrushAdapter(new LinearGradientBrush + { + StartPoint = new RelativePoint(x, y, RelativeUnit.Relative), + EndPoint = new RelativePoint(1 - x, 1 - y, RelativeUnit.Relative), + GradientStops = + { + new GradientStop(startColor, 0), + new GradientStop(endColor, 1) + } + }); + + } + + protected override RImage ConvertImageInt(object image) + { + return image != null ? new ImageAdapter((Bitmap)image) : null; + } + + protected override RImage ImageFromStreamInt(Stream memoryStream) + { + //TODO: Implement bitmap loader + return null; + } + + protected override RFont CreateFontInt(string family, double size, RFontStyle style) + { + return new FontAdapter(family, size, style); + } + + protected override RFont CreateFontInt(RFontFamily family, double size, RFontStyle style) + { + return new FontAdapter(family.Name, size, style); + } + + protected override void SetToClipboardInt(string html, string plainText) + { + SetToClipboardInt(plainText); + } + + protected override void SetToClipboardInt(string text) + { + AvaloniaLocator.Current.GetService().SetTextAsync(text); + } + + protected override void SetToClipboardInt(RImage image) + { + //Do not crash, just ignore + //TODO: implement image clipboard support + } + } +} diff --git a/src/Avalonia.HtmlRenderer/Adapters/BrushAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/BrushAdapter.cs new file mode 100644 index 0000000000..8ea67274b1 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Adapters/BrushAdapter.cs @@ -0,0 +1,47 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using Avalonia.Media; +using TheArtOfDev.HtmlRenderer.Adapters; + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters +{ + /// + /// Adapter for Avalonia brushes. + /// + internal sealed class BrushAdapter : RBrush + { + /// + /// The actual Avalonia brush instance. + /// + private readonly IBrush _brush; + + /// + /// Init. + /// + public BrushAdapter(IBrush brush) + { + _brush = brush; + } + + /// + /// The actual Avalonia brush instance. + /// + public IBrush Brush + { + get { return _brush; } + } + + public override void Dispose() + { } + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Adapters/ContextMenuAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/ContextMenuAdapter.cs new file mode 100644 index 0000000000..380108c01a --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Adapters/ContextMenuAdapter.cs @@ -0,0 +1,51 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using System; +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters +{ + /// + /// Adapter for Avalonia context menu for core. + /// + internal sealed class NullContextMenuAdapter : RContextMenu + { + //TODO: actually implement context menu + + private int _itemCount; + public override int ItemsCount => _itemCount; + public override void AddDivider() + { + + } + + public override void AddItem(string text, bool enabled, EventHandler onClick) + { + _itemCount++; + } + + public override void RemoveLastDivider() + { + _itemCount++; + } + + public override void Show(RControl parent, RPoint location) + { + } + + public override void Dispose() + { + } + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Adapters/ControlAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/ControlAdapter.cs new file mode 100644 index 0000000000..523da3508e --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Adapters/ControlAdapter.cs @@ -0,0 +1,108 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using Avalonia.Controls; +using Avalonia.Controls.Html; +using Avalonia.Input; +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; +using TheArtOfDev.HtmlRenderer.Core.Utils; +using TheArtOfDev.HtmlRenderer.Avalonia.Utilities; +// ReSharper disable ConvertPropertyToExpressionBody + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters +{ + /// + /// Adapter for Avalonia Control for core. + /// + internal sealed class ControlAdapter : RControl + { + /// + /// the underline Avalonia control. + /// + private readonly Control _control; + + /// + /// Init. + /// + public ControlAdapter(Control control) + : base(AvaloniaAdapter.Instance) + { + ArgChecker.AssertArgNotNull(control, "control"); + + _control = control; + } + + /// + /// Get the underline Avalonia control + /// + public Control Control + { + get { return _control; } + } + + public override RPoint MouseLocation + { + get + { + return Util.Convert(MouseDevice.Instance.GetPosition(_control)); + } + } + + private bool _leftMouseButton; + public override bool LeftMouseButton => (_control as HtmlControl)?.LeftMouseButton ?? false; + + public override bool RightMouseButton + { + get + { + return false; + //TODO: Implement right mouse click + //return Mouse.RightButton == MouseButtonState.Pressed; + } + } + + public override void SetCursorDefault() + { + _control.Cursor = new Cursor(StandardCursorType.Arrow); + } + + public override void SetCursorHand() + { + _control.Cursor = new Cursor(StandardCursorType.Hand); + } + + public override void SetCursorIBeam() + { + _control.Cursor = new Cursor(StandardCursorType.Ibeam); + } + + public override void DoDragDropCopy(object dragDropData) + { + //TODO: Implement DragDropCopy + //DragDrop.DoDragDrop(_control, dragDropData, DragDropEffects.Copy); + } + + public override void MeasureString(string str, RFont font, double maxWidth, out int charFit, out double charFitWidth) + { + using (var g = new GraphicsAdapter()) + { + g.MeasureString(str, font, maxWidth, out charFit, out charFitWidth); + } + } + + public override void Invalidate() + { + _control.InvalidateVisual(); + } + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Adapters/FontAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/FontAdapter.cs new file mode 100644 index 0000000000..7e70967ac1 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Adapters/FontAdapter.cs @@ -0,0 +1,106 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using Avalonia.Media; +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters +{ + /// + /// Adapter for Avalonia Font. + /// + internal sealed class FontAdapter : RFont + { + public RFontStyle Style { get; } + + #region Fields and Consts + + + /// + /// the size of the font + /// + private readonly double _size; + + /// + /// the vertical offset of the font underline location from the top of the font. + /// + private readonly double _underlineOffset = -1; + + /// + /// Cached font height. + /// + private readonly double _height = -1; + + /// + /// Cached font whitespace width. + /// + private double _whitespaceWidth = -1; + + + #endregion + + + /// + /// Init. + /// + public FontAdapter(string fontFamily, double size, RFontStyle style) + { + Style = style; + Name = fontFamily; + _size = size; + //TODO: Somehow get proper line spacing and underlinePosition + var lineSpacing = 1; + var underlinePosition = 0; + + _height = 96d / 72d * _size * lineSpacing; + _underlineOffset = 96d / 72d * _size * (lineSpacing + underlinePosition); + + } + + public string Name { get; set; } + + + public override double Size + { + get { return _size; } + } + + public override double UnderlineOffset + { + get { return _underlineOffset; } + } + + public override double Height + { + get { return _height; } + } + + public override double LeftPadding + { + get { return _height / 6f; } + } + + public override double GetWhitespaceWidth(RGraphics graphics) + { + if (_whitespaceWidth < 0) + { + _whitespaceWidth = graphics.MeasureString(" ", this).Width; + } + return _whitespaceWidth; + } + + public FontStyle FontStyle => Style.HasFlag(RFontStyle.Italic) ? FontStyle.Italic : FontStyle.Normal; + + public FontWeight Weight => Style.HasFlag(RFontStyle.Bold) ? FontWeight.Bold : FontWeight.Normal; + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Adapters/FontFamilyAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/FontFamilyAdapter.cs new file mode 100644 index 0000000000..063d8386ba --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Adapters/FontFamilyAdapter.cs @@ -0,0 +1,29 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using TheArtOfDev.HtmlRenderer.Adapters; + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters +{ + /// + /// Adapter for Avalonia Font family object for core. + /// + internal sealed class FontFamilyAdapter : RFontFamily + { + public FontFamilyAdapter(string fontFamily) + { + Name = fontFamily; + } + + public override string Name { get; } + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs new file mode 100644 index 0000000000..c9dd2a786c --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs @@ -0,0 +1,295 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using System; +using System.Collections.Generic; +using System.Globalization; +using Avalonia; +using Avalonia.Media; +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; +using TheArtOfDev.HtmlRenderer.Core.Utils; +using TheArtOfDev.HtmlRenderer.Avalonia.Utilities; + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters +{ + /// + /// Adapter for Avalonia Graphics. + /// + internal sealed class GraphicsAdapter : RGraphics + { + #region Fields and Consts + + /// + /// The wrapped Avalonia graphics object + /// + private readonly DrawingContext _g; + + /// + /// if to release the graphics object on dispose + /// + private readonly bool _releaseGraphics; + + #endregion + + + private readonly Stack _clipStack = new Stack(); + + + /// + /// Init. + /// + /// the Avalonia graphics object to use + /// the initial clip of the graphics + /// optional: if to release the graphics object on dispose (default - false) + public GraphicsAdapter(DrawingContext g, RRect initialClip, bool releaseGraphics = false) + : base(AvaloniaAdapter.Instance, initialClip) + { + ArgChecker.AssertArgNotNull(g, "g"); + + _g = g; + _releaseGraphics = releaseGraphics; + } + + /// + /// Init. + /// + public GraphicsAdapter() + : base(AvaloniaAdapter.Instance, RRect.Empty) + { + _g = null; + _releaseGraphics = false; + } + + + + public override void PopClip() + { + _clipStack.Pop()?.Dispose(); + } + + public override void PushClip(RRect rect) + { + _clipStack.Push(_g.PushClip(Util.Convert(rect))); + //_clipStack.Push(rect); + //_g.PushClip(new RectangleGeometry(Utils.Convert(rect))); + } + + public override void PushClipExclude(RRect rect) + { + _clipStack.Push(null); + + //TODO: Implement exclude rect, see #128 + //var geometry = new CombinedGeometry(); + //geometry.Geometry1 = new RectangleGeometry(Utils.Convert(_clipStack.Peek())); + //geometry.Geometry2 = new RectangleGeometry(Utils.Convert(rect)); + //geometry.GeometryCombineMode = GeometryCombineMode.Exclude; + + //_clipStack.Push(_clipStack.Peek()); + //_g.PushClip(geometry); + } + + public override Object SetAntiAliasSmoothingMode() + { + return null; + } + + public override void ReturnPreviousSmoothingMode(Object prevMode) + { } + + public override RSize MeasureString(string str, RFont font) + { + var text = GetText(str, font); + var measure = text.Measure(); + return new RSize(measure.Width, measure.Height); + + } + + FormattedText GetText(string str, RFont font) + { + var f = ((FontAdapter)font); + return new FormattedText(str, f.Name, font.Size, f.FontStyle, TextAlignment.Left, f.Weight); + } + + public override void MeasureString(string str, RFont font, double maxWidth, out int charFit, out double charFitWidth) + { + var text = GetText(str, font); + var fullLength = text.Measure().Width; + if (fullLength < maxWidth) + { + charFitWidth = fullLength; + charFit = str.Length; + return; + } + + int lastLen = 0; + double lastMeasure = 0; + BinarySearch(len => + { + text = GetText(str.Substring(0, len), font); + var size = text.Measure().Width; + lastMeasure = size; + lastLen = len; + if (size <= maxWidth) + return -1; + return 1; + + }, 0, str.Length); + if (lastMeasure > maxWidth) + { + lastLen--; + lastMeasure = GetText(str.Substring(0, lastLen), font).Measure().Width; + } + charFit = lastLen; + charFitWidth = lastMeasure; + + } + + private static int BinarySearch(Func condition, int start, int end) + { + do + { + int ind = start + (end - start)/2; + int res = condition(ind); + if (res == 0) + return ind; + else if (res > 0) + { + if (start != ind) + start = ind; + else + start = ind + 1; + } + else + end = ind; + + } while (end > start); + return -1; + } + + public override void DrawString(string str, RFont font, RColor color, RPoint point, RSize size, bool rtl) + { + var text = GetText(str, font); + text.Constraint = Util.Convert(size); + _g.DrawText(new SolidColorBrush(Util.Convert(color)), Util.Convert(point), text); + } + + public override RBrush GetTextureBrush(RImage image, RRect dstRect, RPoint translateTransformLocation) + { + //TODO: Implement texture brush + return AvaloniaAdapter.Instance.GetSolidBrush(Util.Convert(Colors.Magenta)); + + //var brush = new ImageBrush(((ImageAdapter)image).Image); + //brush.Stretch = Stretch.None; + //brush.TileMode = TileMode.Tile; + //brush.Viewport = Utils.Convert(dstRect); + //brush.ViewportUnits = BrushMappingMode.Absolute; + //brush.Transform = new TranslateTransform(translateTransformLocation.X, translateTransformLocation.Y); + //brush.Freeze(); + //return new BrushAdapter(brush); + } + + public override RGraphicsPath GetGraphicsPath() + { + return new GraphicsPathAdapter(); + } + + public override void Dispose() + { + while (_clipStack.Count != 0) + PopClip(); + if (_releaseGraphics) + _g.Dispose(); + } + + + #region Delegate graphics methods + + public override void DrawLine(RPen pen, double x1, double y1, double x2, double y2) + { + x1 = (int)x1; + x2 = (int)x2; + y1 = (int)y1; + y2 = (int)y2; + + var adj = pen.Width; + if (Math.Abs(x1 - x2) < .1 && Math.Abs(adj % 2 - 1) < .1) + { + x1 += .5; + x2 += .5; + } + if (Math.Abs(y1 - y2) < .1 && Math.Abs(adj % 2 - 1) < .1) + { + y1 += .5; + y2 += .5; + } + + _g.DrawLine(((PenAdapter)pen).CreatePen(), new Point(x1, y1), new Point(x2, y2)); + } + + public override void DrawRectangle(RPen pen, double x, double y, double width, double height) + { + var adj = pen.Width; + if (Math.Abs(adj % 2 - 1) < .1) + { + x += .5; + y += .5; + } + _g.DrawRectangle(((PenAdapter) pen).CreatePen(), new Rect(x, y, width, height)); + } + + public override void DrawRectangle(RBrush brush, double x, double y, double width, double height) + { + _g.FillRectangle(((BrushAdapter) brush).Brush, new Rect(x, y, width, height)); + } + + public override void DrawImage(RImage image, RRect destRect, RRect srcRect) + { + _g.DrawImage(((ImageAdapter) image).Image, 1, Util.Convert(srcRect), Util.Convert(destRect)); + } + + public override void DrawImage(RImage image, RRect destRect) + { + _g.DrawImage(((ImageAdapter) image).Image, 1, new Rect(0, 0, image.Width, image.Height), + Util.Convert(destRect)); + } + + public override void DrawPath(RPen pen, RGraphicsPath path) + { + _g.DrawGeometry(null, ((PenAdapter)pen).CreatePen(), ((GraphicsPathAdapter)path).GetClosedGeometry()); + } + + public override void DrawPath(RBrush brush, RGraphicsPath path) + { + _g.DrawGeometry(((BrushAdapter)brush).Brush, null, ((GraphicsPathAdapter)path).GetClosedGeometry()); + } + + public override void DrawPolygon(RBrush brush, RPoint[] points) + { + if (points != null && points.Length > 0) + { + var g = new StreamGeometry(); + using (var context = g.Open()) + { + context.BeginFigure(Util.Convert(points[0]), true); + for (int i = 1; i < points.Length; i++) + context.LineTo(Util.Convert(points[i])); + context.EndFigure(false); + } + + _g.DrawGeometry(((BrushAdapter)brush).Brush, null, g); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Adapters/GraphicsPathAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/GraphicsPathAdapter.cs new file mode 100644 index 0000000000..f448c0ce09 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Adapters/GraphicsPathAdapter.cs @@ -0,0 +1,67 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using Avalonia; +using Avalonia.Media; +using TheArtOfDev.HtmlRenderer.Adapters; + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters +{ + /// + /// Adapter for Avalonia graphics path object for core. + /// + internal sealed class GraphicsPathAdapter : RGraphicsPath + { + /// + /// The actual Avalonia graphics geometry instance. + /// + private readonly StreamGeometry _geometry = new StreamGeometry(); + + /// + /// The context used in Avalonia geometry to render path + /// + private readonly StreamGeometryContext _geometryContext; + + public GraphicsPathAdapter() + { + _geometryContext = _geometry.Open(); + } + + public override void Start(double x, double y) + { + _geometryContext.BeginFigure(new Point(x, y), true); + } + + public override void LineTo(double x, double y) + { + _geometryContext.LineTo(new Point(x, y)); + } + + public override void ArcTo(double x, double y, double size, Corner corner) + { + _geometryContext.ArcTo(new Point(x, y), new Size(size, size), 0, false, SweepDirection.Clockwise); + } + + /// + /// Close the geometry to so no more path adding is allowed and return the instance so it can be rendered. + /// + public StreamGeometry GetClosedGeometry() + { + _geometryContext.EndFigure(true); + _geometryContext.Dispose(); + return _geometry; + } + + public override void Dispose() + { } + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Adapters/ImageAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/ImageAdapter.cs new file mode 100644 index 0000000000..3ee0b40771 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Adapters/ImageAdapter.cs @@ -0,0 +1,52 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using Avalonia.Media.Imaging; +using TheArtOfDev.HtmlRenderer.Adapters; + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters +{ + /// + /// Adapter for Avalonia Image object for core. + /// + internal sealed class ImageAdapter : RImage + { + /// + /// the underline Avalonia image. + /// + private readonly Bitmap _image; + + /// + /// Init. + /// + public ImageAdapter(Bitmap image) + { + _image = image; + } + + /// + /// the underline Avalonia image. + /// + public Bitmap Image => _image; + + public override double Width => _image.PixelWidth; + + public override double Height => _image.PixelHeight; + + public override void Dispose() + { + //TODO: Implement image disposal + /*if (_image.StreamSource != null) + _image.StreamSource.Dispose();*/ + } + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Adapters/PenAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/PenAdapter.cs new file mode 100644 index 0000000000..42025afc63 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Adapters/PenAdapter.cs @@ -0,0 +1,79 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using System.Collections.Generic; +using Avalonia.Media; +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters +{ + /// + /// Adapter for Avalonia pens objects for core. + /// + internal sealed class PenAdapter : RPen + { + /// + /// The actual Avalonia brush instance. + /// + private readonly IBrush _brush; + + /// + /// the width of the pen + /// + private double _width; + + private DashStyle _dashStyle; + + /// + /// the dash style of the pen + /// + //private DashStyle _dashStyle = DashStyles.Solid; + + /// + /// Init. + /// + public PenAdapter(IBrush brush) + { + _brush = brush; + } + + public override double Width + { + get { return _width; } + set { _width = value; } + } + + public override RDashStyle DashStyle + { + set { DashStyles.TryGetValue(value, out _dashStyle); } + } + + private static readonly Dictionary DashStyles = new Dictionary + { + {RDashStyle.Solid,null }, + {RDashStyle.Dash, global::Avalonia.Media.DashStyle.Dash }, + {RDashStyle.DashDot, global::Avalonia.Media.DashStyle.DashDot }, + {RDashStyle.DashDotDot, global::Avalonia.Media.DashStyle.DashDotDot }, + {RDashStyle.Dot, global::Avalonia.Media.DashStyle.Dot } + }; + + /// + /// Create the actual Avalonia pen instance. + /// + public Pen CreatePen() + { + var pen = new Pen(_brush, _width, _dashStyle); + return pen; + } + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj new file mode 100644 index 0000000000..827a8fa22a --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj @@ -0,0 +1,199 @@ + + + + + 10.0 + Debug + AnyCPU + {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D} + Library + Properties + Avalonia.HtmlRenderer + Avalonia.HtmlRenderer + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + + + true + full + false + bin\Debug\ + TRACE;DEBUG;PCL + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE;PCL + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {D211E587-D8BC-45B9-95A4-F297C8FA5200} + Avalonia.Animation + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + {D2221C82-4A25-4583-9B43-D791E3F6820C} + Avalonia.Controls + + + {62024B2D-53EB-4638-B26B-85EEAA54866E} + Avalonia.Input + + + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B} + Avalonia.Interactivity + + + {42472427-4774-4C81-8AFF-9F27B8E31721} + Avalonia.Layout + + + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Avalonia.SceneGraph + + + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} + Avalonia.Styling + + + + + + + + ..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll + + + ..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/src/Perspex.HtmlRenderer/Perspex.HtmlRenderer.csproj.DotSettings b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj.DotSettings similarity index 100% rename from src/Perspex.HtmlRenderer/Perspex.HtmlRenderer.csproj.DotSettings rename to src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj.DotSettings diff --git a/src/Avalonia.HtmlRenderer/Compat/Attributes.cs b/src/Avalonia.HtmlRenderer/Compat/Attributes.cs new file mode 100644 index 0000000000..311b2ae4e8 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Compat/Attributes.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +internal class CategoryAttribute : Attribute +{ + public CategoryAttribute(string s) + { + + } +} +internal class DescriptionAttribute : Attribute +{ + public DescriptionAttribute(string s) + { + + } +} + +internal class BrowsableAttribute : Attribute +{ + public BrowsableAttribute(bool b) + { + + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/Compat/ThreadPool.cs b/src/Avalonia.HtmlRenderer/Compat/ThreadPool.cs new file mode 100644 index 0000000000..9a664745a2 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Compat/ThreadPool.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TheArtOfDev.HtmlRenderer.Core.Handlers; + +namespace System.Threading +{ + class ThreadPool + { + public static void QueueUserWorkItem(Action cb, object state) + { + Task.Factory.StartNew(() => cb(state)); + } + + public static void QueueUserWorkItem(Action cb) + { + Task.Factory.StartNew(() => cb(null)); + } + } +} diff --git a/src/Avalonia.HtmlRenderer/HtmlContainer.cs b/src/Avalonia.HtmlRenderer/HtmlContainer.cs new file mode 100644 index 0000000000..c3345589ce --- /dev/null +++ b/src/Avalonia.HtmlRenderer/HtmlContainer.cs @@ -0,0 +1,471 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using System; +using System.Collections.Generic; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Html; +using Avalonia.Input; +using Avalonia.Media; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; +using TheArtOfDev.HtmlRenderer.Core; +using TheArtOfDev.HtmlRenderer.Core.Entities; +using TheArtOfDev.HtmlRenderer.Core.Parse; +using TheArtOfDev.HtmlRenderer.Core.Utils; +using TheArtOfDev.HtmlRenderer.Avalonia.Adapters; +using TheArtOfDev.HtmlRenderer.Avalonia.Utilities; + +namespace TheArtOfDev.HtmlRenderer.Avalonia +{ + /// + /// Low level handling of Html Renderer logic, this class is used by , + /// , and .
+ ///
+ /// + public sealed class HtmlContainer : IDisposable + { + #region Fields and Consts + + /// + /// The internal core html container + /// + private readonly HtmlContainerInt _htmlContainerInt; + + #endregion + + + /// + /// Init. + /// + public HtmlContainer() + { + _htmlContainerInt = new HtmlContainerInt(AvaloniaAdapter.Instance); + } + + /// + /// Raised when the set html document has been fully loaded.
+ /// Allows manipulation of the html dom, scroll position, etc. + ///
+ public event EventHandler LoadComplete + { + add { _htmlContainerInt.LoadComplete += value; } + remove { _htmlContainerInt.LoadComplete -= value; } + } + + /// + /// Raised when the user clicks on a link in the html.
+ /// Allows canceling the execution of the link. + ///
+ public event EventHandler LinkClicked + { + add { _htmlContainerInt.LinkClicked += value; } + remove { _htmlContainerInt.LinkClicked -= value; } + } + + /// + /// Raised when html renderer requires refresh of the control hosting (invalidation and re-layout). + /// + /// + /// There is no guarantee that the event will be raised on the main thread, it can be raised on thread-pool thread. + /// + public event EventHandler Refresh + { + add { _htmlContainerInt.Refresh += value; } + remove { _htmlContainerInt.Refresh -= value; } + } + + /// + /// Raised when Html Renderer request scroll to specific location.
+ /// This can occur on document anchor click. + ///
+ public event EventHandler ScrollChange + { + add { _htmlContainerInt.ScrollChange += value; } + remove { _htmlContainerInt.ScrollChange -= value; } + } + + /// + /// Raised when an error occurred during html rendering.
+ ///
+ /// + /// There is no guarantee that the event will be raised on the main thread, it can be raised on thread-pool thread. + /// + public event EventHandler RenderError + { + add { _htmlContainerInt.RenderError += value; } + remove { _htmlContainerInt.RenderError -= value; } + } + + /// + /// Raised when a stylesheet is about to be loaded by file path or URI by link element.
+ /// This event allows to provide the stylesheet manually or provide new source (file or Uri) to load from.
+ /// If no alternative data is provided the original source will be used.
+ ///
+ public event EventHandler StylesheetLoad + { + add { _htmlContainerInt.StylesheetLoad += value; } + remove { _htmlContainerInt.StylesheetLoad -= value; } + } + + /// + /// Raised when an image is about to be loaded by file path or URI.
+ /// This event allows to provide the image manually, if not handled the image will be loaded from file or download from URI. + ///
+ public event EventHandler ImageLoad + { + add { _htmlContainerInt.ImageLoad += value; } + remove { _htmlContainerInt.ImageLoad -= value; } + } + + /// + /// The internal core html container + /// + internal HtmlContainerInt HtmlContainerInt + { + get { return _htmlContainerInt; } + } + + /// + /// the parsed stylesheet data used for handling the html + /// + public CssData CssData + { + get { return _htmlContainerInt.CssData; } + } + + /// + /// Gets or sets a value indicating if image asynchronous loading should be avoided (default - false).
+ /// True - images are loaded synchronously during html parsing.
+ /// False - images are loaded asynchronously to html parsing when downloaded from URL or loaded from disk.
+ ///
+ /// + /// Asynchronously image loading allows to unblock html rendering while image is downloaded or loaded from disk using IO + /// ports to achieve better performance.
+ /// Asynchronously image loading should be avoided when the full html content must be available during render, like render to image. + ///
+ public bool AvoidAsyncImagesLoading + { + get { return _htmlContainerInt.AvoidAsyncImagesLoading; } + set { _htmlContainerInt.AvoidAsyncImagesLoading = value; } + } + + /// + /// Gets or sets a value indicating if image loading only when visible should be avoided (default - false).
+ /// True - images are loaded as soon as the html is parsed.
+ /// False - images that are not visible because of scroll location are not loaded until they are scrolled to. + ///
+ /// + /// Images late loading improve performance if the page contains image outside the visible scroll area, especially if there is large + /// amount of images, as all image loading is delayed (downloading and loading into memory).
+ /// Late image loading may effect the layout and actual size as image without set size will not have actual size until they are loaded + /// resulting in layout change during user scroll.
+ /// Early image loading may also effect the layout if image without known size above the current scroll location are loaded as they + /// will push the html elements down. + ///
+ public bool AvoidImagesLateLoading + { + get { return _htmlContainerInt.AvoidImagesLateLoading; } + set { _htmlContainerInt.AvoidImagesLateLoading = value; } + } + + /// + /// Is content selection is enabled for the rendered html (default - true).
+ /// If set to 'false' the rendered html will be static only with ability to click on links. + ///
+ public bool IsSelectionEnabled + { + get { return _htmlContainerInt.IsSelectionEnabled; } + set { _htmlContainerInt.IsSelectionEnabled = value; } + } + + /// + /// Is the build-in context menu enabled and will be shown on mouse right click (default - true) + /// + public bool IsContextMenuEnabled + { + get { return _htmlContainerInt.IsContextMenuEnabled; } + set { _htmlContainerInt.IsContextMenuEnabled = value; } + } + + /// + /// The scroll offset of the html.
+ /// This will adjust the rendered html by the given offset so the content will be "scrolled".
+ ///
+ /// + /// Element that is rendered at location (50,100) with offset of (0,200) will not be rendered as it + /// will be at -100 therefore outside the client Rect. + /// + public Point ScrollOffset + { + get { return Util.Convert(_htmlContainerInt.ScrollOffset); } + set { _htmlContainerInt.ScrollOffset = Util.Convert(value); } + } + + /// + /// The top-left most location of the rendered html.
+ /// This will offset the top-left corner of the rendered html. + ///
+ public Point Location + { + get { return Util.Convert(_htmlContainerInt.Location); } + set { _htmlContainerInt.Location = Util.Convert(value); } + } + + /// + /// The max width and height of the rendered html.
+ /// The max width will effect the html layout wrapping lines, resize images and tables where possible.
+ /// The max height does NOT effect layout, but will not render outside it (clip).
+ /// can be exceed the max size by layout restrictions (unwrappable line, set image size, etc.).
+ /// Set zero for unlimited (width\height separately).
+ ///
+ public Size MaxSize + { + get { return Util.Convert(_htmlContainerInt.MaxSize); } + set { _htmlContainerInt.MaxSize = Util.Convert(value); } + } + + /// + /// The actual size of the rendered html (after layout) + /// + public Size ActualSize + { + get { return Util.Convert(_htmlContainerInt.ActualSize); } + internal set { _htmlContainerInt.ActualSize = Util.Convert(value); } + } + + /// + /// Get the currently selected text segment in the html. + /// + public string SelectedText + { + get { return _htmlContainerInt.SelectedText; } + } + + /// + /// Copy the currently selected html segment with style. + /// + public string SelectedHtml + { + get { return _htmlContainerInt.SelectedHtml; } + } + + /// + /// Clear the current selection. + /// + public void ClearSelection() + { + HtmlContainerInt.ClearSelection(); + } + + /// + /// Init with optional document and stylesheet. + /// + /// the html to init with, init empty if not given + /// optional: the stylesheet to init with, init default if not given + public void SetHtml(string htmlSource, CssData baseCssData = null) + { + _htmlContainerInt.SetHtml(htmlSource, baseCssData); + } + + /// + /// Clear the content of the HTML container releasing any resources used to render previously existing content. + /// + public void Clear() + { + _htmlContainerInt.Clear(); + } + + /// + /// Get html from the current DOM tree with style if requested. + /// + /// Optional: controls the way styles are generated when html is generated (default: ) + /// generated html + public string GetHtml(HtmlGenerationStyle styleGen = HtmlGenerationStyle.Inline) + { + return _htmlContainerInt.GetHtml(styleGen); + } + + /// + /// Get attribute value of element at the given x,y location by given key.
+ /// If more than one element exist with the attribute at the location the inner most is returned. + ///
+ /// the location to find the attribute at + /// the attribute key to get value by + /// found attribute value or null if not found + public string GetAttributeAt(Point location, string attribute) + { + return _htmlContainerInt.GetAttributeAt(Util.Convert(location), attribute); + } + + /// + /// Get all the links in the HTML with the element Rect and href data. + /// + /// collection of all the links in the HTML + public List> GetLinks() + { + var linkElements = new List>(); + foreach (var link in HtmlContainerInt.GetLinks()) + { + linkElements.Add(new LinkElementData(link.Id, link.Href, Util.Convert(link.Rectangle))); + } + return linkElements; + } + + /// + /// Get css link href at the given x,y location. + /// + /// the location to find the link at + /// css link href if exists or null + public string GetLinkAt(Point location) + { + return _htmlContainerInt.GetLinkAt(Util.Convert(location)); + } + + /// + /// Get the Rect of html element as calculated by html layout.
+ /// Element if found by id (id attribute on the html element).
+ /// Note: to get the screen Rect you need to adjust by the hosting control.
+ ///
+ /// the id of the element to get its Rect + /// the Rect of the element or null if not found + public Rect? GetElementRectangle(string elementId) + { + var r = _htmlContainerInt.GetElementRectangle(elementId); + return r.HasValue ? Util.Convert(r.Value) : (Rect?)null; + } + + /// + /// Measures the bounds of box and children, recursively. + /// + public void PerformLayout() + { + using (var ig = new GraphicsAdapter()) + { + _htmlContainerInt.PerformLayout(ig); + } + } + + /// + /// Render the html using the given device. + /// + /// the device to use to render + /// the clip rectangle of the html container + public void PerformPaint(DrawingContext g, Rect clip) + { + ArgChecker.AssertArgNotNull(g, "g"); + + using (var ig = new GraphicsAdapter(g, Util.Convert(clip))) + { + _htmlContainerInt.PerformPaint(ig); + } + } + + /// + /// Handle mouse down to handle selection. + /// + /// the control hosting the html to invalidate + /// the mouse event args + public void HandleLeftMouseDown(Control parent, PointerEventArgs e) + { + ArgChecker.AssertArgNotNull(parent, "parent"); + ArgChecker.AssertArgNotNull(e, "e"); + + _htmlContainerInt.HandleMouseDown(new ControlAdapter(parent), Util.Convert(e.GetPosition(parent))); + } + + /// + /// Handle mouse up to handle selection and link click. + /// + /// the control hosting the html to invalidate + /// the mouse event args + public void HandleLeftMouseUp(Control parent, PointerEventArgs e) + { + ArgChecker.AssertArgNotNull(parent, "parent"); + ArgChecker.AssertArgNotNull(e, "e"); + + var mouseEvent = new RMouseEvent(true); + _htmlContainerInt.HandleMouseUp(new ControlAdapter(parent), Util.Convert(e.GetPosition(parent)), mouseEvent); + } + + /// + /// Handle mouse double click to select word under the mouse. + /// + /// the control hosting the html to set cursor and invalidate + /// mouse event args + public void HandleMouseDoubleClick(Control parent, PointerEventArgs e) + { + ArgChecker.AssertArgNotNull(parent, "parent"); + ArgChecker.AssertArgNotNull(e, "e"); + + _htmlContainerInt.HandleMouseDoubleClick(new ControlAdapter(parent), Util.Convert(e.GetPosition(parent))); + } + + /// + /// Handle mouse move to handle hover cursor and text selection. + /// + /// the control hosting the html to set cursor and invalidate + /// the mouse event args + public void HandleMouseMove(Control parent, Point mousePos) + { + ArgChecker.AssertArgNotNull(parent, "parent"); + + _htmlContainerInt.HandleMouseMove(new ControlAdapter(parent), Util.Convert(mousePos)); + } + + /// + /// Handle mouse leave to handle hover cursor. + /// + /// the control hosting the html to set cursor and invalidate + public void HandleMouseLeave(Control parent) + { + ArgChecker.AssertArgNotNull(parent, "parent"); + + _htmlContainerInt.HandleMouseLeave(new ControlAdapter(parent)); + } + + /// + /// Handle key down event for selection and copy. + /// + /// the control hosting the html to invalidate + /// the pressed key + public void HandleKeyDown(Control parent, KeyEventArgs e) + { + ArgChecker.AssertArgNotNull(parent, "parent"); + ArgChecker.AssertArgNotNull(e, "e"); + + _htmlContainerInt.HandleKeyDown(new ControlAdapter(parent), CreateKeyEevent(e)); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + _htmlContainerInt.Dispose(); + } + + + #region Private methods + + /// + /// Create HtmlRenderer key event from Avalonia key event. + /// + private static RKeyEvent CreateKeyEevent(KeyEventArgs e) + { + var control = (e.Modifiers & InputModifiers.Control) == InputModifiers.Control; + return new RKeyEvent(control, e.Key == Key.A, e.Key == Key.C); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/HtmlControl.cs b/src/Avalonia.HtmlRenderer/HtmlControl.cs new file mode 100644 index 0000000000..ca8dcec2e1 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/HtmlControl.cs @@ -0,0 +1,615 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using System; +using Avalonia.Controls.Primitives; +using Avalonia.HtmlRenderer; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Media; +using Avalonia.Threading; +using TheArtOfDev.HtmlRenderer.Core; +using TheArtOfDev.HtmlRenderer.Core.Entities; +using TheArtOfDev.HtmlRenderer.Avalonia; +using TheArtOfDev.HtmlRenderer.Avalonia.Adapters; + +namespace Avalonia.Controls.Html +{ + /// + /// Provides HTML rendering using the text property.
+ /// Avalonia control that will render html content in it's client rectangle.
+ /// The control will handle mouse and keyboard events on it to support html text selection, copy-paste and mouse clicks.
+ /// + /// The major differential to use HtmlPanel or HtmlLabel is size and scrollbars.
+ /// If the size of the control depends on the html content the HtmlLabel should be used.
+ /// If the size is set by some kind of layout then HtmlPanel is more suitable, also shows scrollbars if the html contents is larger than the control client rectangle.
+ ///
+ /// + ///

LinkClicked event:

+ /// Raised when the user clicks on a link in the html.
+ /// Allows canceling the execution of the link. + ///
+ /// + ///

StylesheetLoad event:

+ /// Raised when a stylesheet is about to be loaded by file path or URI by link element.
+ /// This event allows to provide the stylesheet manually or provide new source (file or uri) to load from.
+ /// If no alternative data is provided the original source will be used.
+ ///
+ /// + ///

ImageLoad event:

+ /// Raised when an image is about to be loaded by file path or URI.
+ /// This event allows to provide the image manually, if not handled the image will be loaded from file or download from URI. + ///
+ /// + ///

RenderError event:

+ /// Raised when an error occurred during html rendering.
+ ///
+ ///
+ + public class HtmlControl : Control + { + /// + /// Underline html container instance. + /// + protected readonly HtmlContainer _htmlContainer; + + /// + /// the base stylesheet data used in the control + /// + protected CssData _baseCssData; + + /// + /// The last position of the scrollbars to know if it has changed to update mouse + /// + protected Point _lastScrollOffset; + + public static readonly AvaloniaProperty AvoidImagesLateLoadingProperty = + PropertyHelper.Register("AvoidImagesLateLoading", false, OnAvaloniaProperty_valueChanged); + public static readonly AvaloniaProperty IsSelectionEnabledProperty = + PropertyHelper.Register("IsSelectionEnabled", true, OnAvaloniaProperty_valueChanged); + public static readonly AvaloniaProperty IsContextMenuEnabledProperty = + PropertyHelper.Register("IsContextMenuEnabled", true, OnAvaloniaProperty_valueChanged); + + public static readonly AvaloniaProperty BaseStylesheetProperty = + PropertyHelper.Register("BaseStylesheet", null, OnAvaloniaProperty_valueChanged); + + public static readonly AvaloniaProperty TextProperty = + PropertyHelper.Register("Text", null, OnAvaloniaProperty_valueChanged); + + public static readonly StyledProperty BackgroundProperty = + Border.BackgroundProperty.AddOwner(); + + public static readonly AvaloniaProperty BorderThicknessProperty = + AvaloniaProperty.Register("BorderThickness", new Thickness(0)); + + public static readonly AvaloniaProperty BorderBrushProperty = + AvaloniaProperty.Register("BorderBrush"); + + public static readonly AvaloniaProperty PaddingProperty = + AvaloniaProperty.Register("Padding", new Thickness(0)); + + public static readonly RoutedEvent LoadCompleteEvent = + RoutedEvent.Register("LoadComplete", RoutingStrategies.Bubble, typeof(HtmlControl)); + public static readonly RoutedEvent LinkClickedEvent = + RoutedEvent.Register>("LinkClicked", RoutingStrategies.Bubble, typeof(HtmlControl)); + public static readonly RoutedEvent RenderErrorEvent + = RoutedEvent.Register>("RenderError", RoutingStrategies.Bubble, typeof(HtmlControl)); + public static readonly RoutedEvent RefreshEvent + = RoutedEvent.Register>("Refresh", RoutingStrategies.Bubble, typeof(HtmlControl)); + public static readonly RoutedEvent StylesheetLoadEvent + = RoutedEvent.Register>("StylesheetLoad", RoutingStrategies.Bubble, typeof(HtmlControl)); + + public static readonly RoutedEvent ImageLoadEvent + = RoutedEvent.Register>("ImageLoad", RoutingStrategies.Bubble, + typeof (HtmlControl)); + + static HtmlControl() + { + FocusableProperty.OverrideDefaultValue(typeof(HtmlControl), true); + } + + /// + /// Creates a new HtmlPanel and sets a basic css for it's styling. + /// + protected HtmlControl() + { + _htmlContainer = new HtmlContainer(); + _htmlContainer.LoadComplete += (_, e) => OnLoadComplete(e); + _htmlContainer.LinkClicked += (_, e) => OnLinkClicked(e); + _htmlContainer.RenderError += (_, e) => OnRenderError(e); + _htmlContainer.Refresh += (_, e) => OnRefresh(e); + _htmlContainer.StylesheetLoad += (_, e) => OnStylesheetLoad(e); + _htmlContainer.ImageLoad += (_, e) => OnImageLoad(e); + } + + //Hack for adapter + internal bool LeftMouseButton { get; private set; } + + /// + /// Raised when the set html document has been fully loaded.
+ /// Allows manipulation of the html dom, scroll position, etc. + ///
+ public event EventHandler> LoadComplete + { + add { AddHandler(LoadCompleteEvent, value); } + remove { RemoveHandler(LoadCompleteEvent, value); } + } + + /// + /// Raised when the user clicks on a link in the html.
+ /// Allows canceling the execution of the link. + ///
+ public event EventHandler> LinkClicked + { + add { AddHandler(LinkClickedEvent, value); } + remove { RemoveHandler(LinkClickedEvent, value); } + } + + /// + /// Raised when an error occurred during html rendering.
+ ///
+ public event EventHandler> RenderError + { + add { AddHandler(RenderErrorEvent, value); } + remove { RemoveHandler(RenderErrorEvent, value); } + } + + /// + /// Raised when a stylesheet is about to be loaded by file path or URI by link element.
+ /// This event allows to provide the stylesheet manually or provide new source (file or uri) to load from.
+ /// If no alternative data is provided the original source will be used.
+ ///
+ public event EventHandler> StylesheetLoad + { + add { AddHandler(StylesheetLoadEvent, value); } + remove { RemoveHandler(StylesheetLoadEvent, value); } + } + + /// + /// Raised when an image is about to be loaded by file path or URI.
+ /// This event allows to provide the image manually, if not handled the image will be loaded from file or download from URI. + ///
+ public event EventHandler> ImageLoad + { + add { AddHandler(ImageLoadEvent, value); } + remove { RemoveHandler(ImageLoadEvent, value); } + } + + /// + /// Gets or sets a value indicating if image loading only when visible should be avoided (default - false).
+ /// True - images are loaded as soon as the html is parsed.
+ /// False - images that are not visible because of scroll location are not loaded until they are scrolled to. + ///
+ /// + /// Images late loading improve performance if the page contains image outside the visible scroll area, especially if there is large + /// amount of images, as all image loading is delayed (downloading and loading into memory).
+ /// Late image loading may effect the layout and actual size as image without set size will not have actual size until they are loaded + /// resulting in layout change during user scroll.
+ /// Early image loading may also effect the layout if image without known size above the current scroll location are loaded as they + /// will push the html elements down. + ///
+ [Category("Behavior")] + [Description("If image loading only when visible should be avoided")] + public bool AvoidImagesLateLoading + { + get { return (bool)GetValue(AvoidImagesLateLoadingProperty); } + set { SetValue(AvoidImagesLateLoadingProperty, value); } + } + + /// + /// Is content selection is enabled for the rendered html (default - true).
+ /// If set to 'false' the rendered html will be static only with ability to click on links. + ///
+ [Category("Behavior")] + [Description("Is content selection is enabled for the rendered html.")] + public bool IsSelectionEnabled + { + get { return (bool)GetValue(IsSelectionEnabledProperty); } + set { SetValue(IsSelectionEnabledProperty, value); } + } + + /// + /// Is the build-in context menu enabled and will be shown on mouse right click (default - true) + /// + [Category("Behavior")] + [Description("Is the build-in context menu enabled and will be shown on mouse right click.")] + public bool IsContextMenuEnabled + { + get { return (bool)GetValue(IsContextMenuEnabledProperty); } + set { SetValue(IsContextMenuEnabledProperty, value); } + } + + /// + /// Set base stylesheet to be used by html rendered in the panel. + /// + [Category("Appearance")] + [Description("Set base stylesheet to be used by html rendered in the control.")] + public string BaseStylesheet + { + get { return (string)GetValue(BaseStylesheetProperty); } + set { SetValue(BaseStylesheetProperty, value); } + } + + /// + /// Gets or sets the text of this panel + /// + [Description("Sets the html of this control.")] + public string Text + { + get { return (string)GetValue(TextProperty); } + set { SetValue(TextProperty, value); } + } + + public Thickness BorderThickness + { + get { return (Thickness) GetValue(BorderThicknessProperty); } + set { SetValue(BorderThicknessProperty, value); } + } + + public IBrush BorderBrush + { + get { return (IBrush)GetValue(BorderBrushProperty); } + set { SetValue(BorderThicknessProperty, value); } + } + + public Thickness Padding + { + get { return (Thickness)GetValue(PaddingProperty); } + set { SetValue(PaddingProperty, value); } + } + + public IBrush Background + { + get { return (IBrush) GetValue(BackgroundProperty); } + set { SetValue(BackgroundProperty, value);} + } + + /// + /// Get the currently selected text segment in the html. + /// + [Browsable(false)] + public virtual string SelectedText + { + get { return _htmlContainer.SelectedText; } + } + + /// + /// Copy the currently selected html segment with style. + /// + [Browsable(false)] + public virtual string SelectedHtml + { + get { return _htmlContainer.SelectedHtml; } + } + + /// + /// Get html from the current DOM tree with inline style. + /// + /// generated html + public virtual string GetHtml() + { + return _htmlContainer != null ? _htmlContainer.GetHtml() : null; + } + + /// + /// Get the rectangle of html element as calculated by html layout.
+ /// Element if found by id (id attribute on the html element).
+ /// Note: to get the screen rectangle you need to adjust by the hosting control.
+ ///
+ /// the id of the element to get its rectangle + /// the rectangle of the element or null if not found + public virtual Rect? GetElementRectangle(string elementId) + { + return _htmlContainer != null ? _htmlContainer.GetElementRectangle(elementId) : null; + } + + /// + /// Clear the current selection. + /// + public void ClearSelection() + { + if (_htmlContainer != null) + _htmlContainer.ClearSelection(); + } + + + + //HACK: We don't have support for RenderSize for now + private Size RenderSize => new Size(Bounds.Width, Bounds.Height); + + + public override void Render(DrawingContext context) + { + context.FillRectangle(Background, new Rect(RenderSize)); + + if (BorderThickness != new Thickness(0) && BorderBrush != null) + { + var brush = new SolidColorBrush(Colors.Black); + if (BorderThickness.Top > 0) + context.FillRectangle(brush, new Rect(0, 0, RenderSize.Width, BorderThickness.Top)); + if (BorderThickness.Bottom > 0) + context.FillRectangle(brush, new Rect(0, RenderSize.Height - BorderThickness.Bottom, RenderSize.Width, BorderThickness.Bottom)); + if (BorderThickness.Left > 0) + context.FillRectangle(brush, new Rect(0, 0, BorderThickness.Left, RenderSize.Height)); + if (BorderThickness.Right > 0) + context.FillRectangle(brush, new Rect(RenderSize.Width - BorderThickness.Right, 0, BorderThickness.Right, RenderSize.Height)); + } + + var htmlWidth = HtmlWidth(RenderSize); + var htmlHeight = HtmlHeight(RenderSize); + if (_htmlContainer != null && htmlWidth > 0 && htmlHeight > 0) + { + /* + //TODO: Revert antialiasing fixes + var windows = Window.GetWindow(this); + if (windows != null) + { + // adjust render location to round point so we won't get anti-alias smugness + var wPoint = TranslatePoint(new Point(0, 0), windows); + wPoint.Offset(-(int)wPoint.X, -(int)wPoint.Y); + var xTrans = wPoint.X < .5 ? -wPoint.X : 1 - wPoint.X; + var yTrans = wPoint.Y < .5 ? -wPoint.Y : 1 - wPoint.Y; + context.PushTransform(new TranslateTransform(xTrans, yTrans)); + }*/ + + using (context.PushClip(new Rect(Padding.Left + BorderThickness.Left, Padding.Top + BorderThickness.Top, + htmlWidth, (int) htmlHeight))) + { + _htmlContainer.Location = new Point(Padding.Left + BorderThickness.Left, + Padding.Top + BorderThickness.Top); + _htmlContainer.PerformPaint(context, + new Rect(Padding.Left + BorderThickness.Left, Padding.Top + BorderThickness.Top, htmlWidth, + htmlHeight)); + } + + if (!_lastScrollOffset.Equals(_htmlContainer.ScrollOffset)) + { + _lastScrollOffset = _htmlContainer.ScrollOffset; + InvokeMouseMove(); + } + } + } + + /// + /// Handle mouse move to handle hover cursor and text selection. + /// + protected override void OnPointerMoved(PointerEventArgs e) + { + base.OnPointerMoved(e); + if (_htmlContainer != null) + _htmlContainer.HandleMouseMove(this, e.GetPosition(this)); + } + /// + /// Handle mouse leave to handle cursor change. + /// + protected override void OnPointerLeave(PointerEventArgs e) + { + base.OnPointerLeave(e); + if (_htmlContainer != null) + _htmlContainer.HandleMouseLeave(this); + } + + /// + /// Handle mouse down to handle selection. + /// + protected override void OnPointerPressed(PointerPressedEventArgs e) + { + base.OnPointerPressed(e); + LeftMouseButton = true; + _htmlContainer?.HandleLeftMouseDown(this, e); + } + + + + /// + /// Handle mouse up to handle selection and link click. + /// + protected override void OnPointerReleased(PointerEventArgs e) + { + base.OnPointerReleased(e); + LeftMouseButton = false; + if (_htmlContainer != null) + _htmlContainer.HandleLeftMouseUp(this, e); + } + + //TODO: Implement double click + /* + /// + /// Handle mouse double click to select word under the mouse. + /// + protected override void OnMouseDoubleClick(MouseButtonEventArgs e) + { + base.OnMouseDoubleClick(e); + if (_htmlContainer != null) + _htmlContainer.HandleMouseDoubleClick(this, e); + } + */ + /// + /// Handle key down event for selection, copy and scrollbars handling. + /// + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if (_htmlContainer != null) + _htmlContainer.HandleKeyDown(this, e); + } + + void RaiseRouted(RoutedEvent ev, T arg) + { + var e =new HtmlRendererRoutedEventArgs + { + Event = arg, + Source = this, + RoutedEvent = ev, + Route = ev.RoutingStrategies + }; + RaiseEvent(e); + } + + /// + /// Propagate the LoadComplete event from root container. + /// + protected virtual void OnLoadComplete(EventArgs e) => RaiseRouted(LoadCompleteEvent, e); + + /// + /// Propagate the LinkClicked event from root container. + /// + protected virtual void OnLinkClicked(HtmlLinkClickedEventArgs e) => RaiseRouted(LinkClickedEvent, e); + + /// + /// Propagate the Render Error event from root container. + /// + protected virtual void OnRenderError(HtmlRenderErrorEventArgs e) => RaiseRouted(RenderErrorEvent, e); + + /// + /// Propagate the stylesheet load event from root container. + /// + protected virtual void OnStylesheetLoad(HtmlStylesheetLoadEventArgs e) => RaiseRouted(StylesheetLoadEvent, e); + + /// + /// Propagate the image load event from root container. + /// + protected virtual void OnImageLoad(HtmlImageLoadEventArgs e) => RaiseRouted(ImageLoadEvent, e); + + /// + /// Handle html renderer invalidate and re-layout as requested. + /// + protected virtual void OnRefresh(HtmlRefreshEventArgs e) + { + if (e.Layout) + InvalidateMeasure(); + InvalidateVisual(); + } + + /// + /// Get the width the HTML has to render in (not including vertical scroll iff it is visible) + /// + protected virtual double HtmlWidth(Size size) + { + return size.Width - Padding.Left - Padding.Right - BorderThickness.Left - BorderThickness.Right; + } + + /// + /// Get the width the HTML has to render in (not including vertical scroll iff it is visible) + /// + protected virtual double HtmlHeight(Size size) + { + return size.Height - Padding.Top - Padding.Bottom - BorderThickness.Top - BorderThickness.Bottom; + } + + /// + /// call mouse move to handle paint after scroll or html change affecting mouse cursor. + /// + protected virtual void InvokeMouseMove() + { + + _htmlContainer.HandleMouseMove(this, MouseDevice.Instance?.GetPosition(this) ?? default(Point)); + } + + /// + /// Handle when dependency property value changes to update the underline HtmlContainer with the new value. + /// + private static void OnAvaloniaProperty_valueChanged(AvaloniaObject AvaloniaObject, + AvaloniaPropertyChangedEventArgs e) + { + var control = AvaloniaObject as HtmlControl; + if (control != null) + { + var htmlContainer = control._htmlContainer; + if (e.Property == AvoidImagesLateLoadingProperty) + { + htmlContainer.AvoidImagesLateLoading = (bool) e.NewValue; + } + else if (e.Property == IsSelectionEnabledProperty) + { + htmlContainer.IsSelectionEnabled = (bool) e.NewValue; + } + else if (e.Property == IsContextMenuEnabledProperty) + { + htmlContainer.IsContextMenuEnabled = (bool) e.NewValue; + } + else if (e.Property == BaseStylesheetProperty) + { + var baseCssData = CssData.Parse(AvaloniaAdapter.Instance, (string) e.NewValue); + control._baseCssData = baseCssData; + htmlContainer.SetHtml(control.Text, baseCssData); + } + else if (e.Property == TextProperty) + { + htmlContainer.ScrollOffset = new Point(0, 0); + htmlContainer.SetHtml((string) e.NewValue, control._baseCssData); + control.InvalidateMeasure(); + control.InvalidateVisual(); + + if (control.VisualRoot != null) + { + control.InvokeMouseMove(); + } + } + } + } + + + //TODO: Implement CheckAccess calls + /* + private void OnLoadComplete(object sender, EventArgs e) + { + + if (CheckAccess()) + OnLoadComplete(e); + else + Dispatcher.UIThread.Invoke(new Action(OnLinkClicked), e); + + } + + private void OnLinkClicked(object sender, HtmlLinkClickedEventArgs e) + { + if (CheckAccess()) + OnLinkClicked(e); + else + Dispatcher.UIThread.Invoke(new Action(OnLinkClicked), e); + } + + private void OnRenderError(object sender, HtmlRenderErrorEventArgs e) + { + if (CheckAccess()) + OnRenderError(e); + else + Dispatcher.UIThread.Invoke(new Action(OnRenderError), e); + } + + private void OnStylesheetLoad(object sender, HtmlStylesheetLoadEventArgs e) + { + if (CheckAccess()) + OnStylesheetLoad(e); + else + Dispatcher.UIThread.Invoke(new Action(OnStylesheetLoad), e); + } + + private void OnImageLoad(object sender, HtmlImageLoadEventArgs e) + { + if (CheckAccess()) + OnImageLoad(e); + else + Dispatcher.UIThread.Invoke(new Action(OnImageLoad), e); + } + + private void OnRefresh(object sender, HtmlRefreshEventArgs e) + { + if (CheckAccess()) + OnRefresh(e); + else + Dispatcher.UIThread.Invoke(new Action(OnRefresh), e); + } + */ + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/HtmlLabel.cs b/src/Avalonia.HtmlRenderer/HtmlLabel.cs new file mode 100644 index 0000000000..547a3a10fa --- /dev/null +++ b/src/Avalonia.HtmlRenderer/HtmlLabel.cs @@ -0,0 +1,112 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using System; +using Avalonia.HtmlRenderer; +using Avalonia.Media; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; +using TheArtOfDev.HtmlRenderer.Core; +using TheArtOfDev.HtmlRenderer.Avalonia.Adapters; + +namespace Avalonia.Controls.Html +{ + /// + /// Provides HTML rendering using the text property.
+ /// WPF control that will render html content in it's client rectangle.
+ /// Using and client can control how the html content effects the + /// size of the label. Either case scrollbars are never shown and html content outside of client bounds will be clipped. + /// MaxWidth/MaxHeight and MinWidth/MinHeight with AutoSize can limit the max/min size of the control
+ /// The control will handle mouse and keyboard events on it to support html text selection, copy-paste and mouse clicks.
+ ///
+ /// + /// See for more info. + /// + public class HtmlLabel : HtmlControl + { + #region Dependency properties + + public static readonly AvaloniaProperty AutoSizeProperty = PropertyHelper.Register("AutoSize", true, OnAvaloniaProperty_valueChanged); + public static readonly AvaloniaProperty AutoSizeHeightOnlyProperty = PropertyHelper.Register("AutoSizeHeightOnly", false, OnAvaloniaProperty_valueChanged); + + #endregion + + + /// + /// Init. + /// + static HtmlLabel() + { + BackgroundProperty.OverrideDefaultValue(Brushes.Transparent); + } + + #region Private methods + + /// + /// Perform the layout of the html in the control. + /// + protected override Size MeasureOverride(Size constraint) + { + if (_htmlContainer != null) + { + using (var ig = new GraphicsAdapter()) + { + var horizontal = Padding.Left + Padding.Right + BorderThickness.Left + BorderThickness.Right; + var vertical = Padding.Top + Padding.Bottom + BorderThickness.Top + BorderThickness.Bottom; + + var size = new Size(Math.Min(MaxWidth, constraint.Width), Math.Min(MaxHeight, constraint.Height)); + var maxSize = new RSize(size.Width < Double.PositiveInfinity ? size.Width - horizontal : 0, size.Height < Double.PositiveInfinity ? size.Height - vertical : 0); + _htmlContainer.HtmlContainerInt.MaxSize = maxSize; + + _htmlContainer.HtmlContainerInt.PerformLayout(ig); + var newSize = _htmlContainer.ActualSize; + constraint = new Size(newSize.Width + horizontal, newSize.Height + vertical); + } + } + + if (double.IsPositiveInfinity(constraint.Width) || double.IsPositiveInfinity(constraint.Height)) + constraint = Size.Empty; + + return constraint; + } + + /// + /// Handle when dependency property value changes to update the underline HtmlContainer with the new value. + /// + private static void OnAvaloniaProperty_valueChanged(AvaloniaObject AvaloniaObject, AvaloniaPropertyChangedEventArgs e) + { + var control = AvaloniaObject as HtmlLabel; + if (control != null) + { + if (e.Property == AutoSizeProperty) + { + if ((bool)e.NewValue) + { + AvaloniaObject.SetValue(AutoSizeHeightOnlyProperty, false); + control.InvalidateMeasure(); + control.InvalidateVisual(); + } + } + else if (e.Property == AutoSizeHeightOnlyProperty) + { + if ((bool)e.NewValue) + { + AvaloniaObject.SetValue(AutoSizeProperty, false); + control.InvalidateMeasure(); + control.InvalidateVisual(); + } + } + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/HtmlRendererRoutedEventArgs.cs b/src/Avalonia.HtmlRenderer/HtmlRendererRoutedEventArgs.cs new file mode 100644 index 0000000000..3136624b7f --- /dev/null +++ b/src/Avalonia.HtmlRenderer/HtmlRendererRoutedEventArgs.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Interactivity; + +namespace Avalonia.Controls.Html +{ + public class HtmlRendererRoutedEventArgs : RoutedEventArgs + { + public T Event { get; set; } + } +} diff --git a/src/Avalonia.HtmlRenderer/Properties/AssemblyInfo.cs b/src/Avalonia.HtmlRenderer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..d77b5b900e --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Resources; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Avalonia.Metadata; + +// 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("Avalonia.HtmlRenderer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Avalonia.HtmlRenderer")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// 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")] + +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Html")] \ No newline at end of file diff --git a/src/Avalonia.HtmlRenderer/PropertyHelper.cs b/src/Avalonia.HtmlRenderer/PropertyHelper.cs new file mode 100644 index 0000000000..56257ed478 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/PropertyHelper.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.HtmlRenderer +{ + static class PropertyHelper + { + + public static AvaloniaProperty Register(string name, T def, Action changed) where TOwner : AvaloniaObject + { + var pp = AvaloniaProperty.Register(name, def); + Action cb = args => + { + changed(args.Sender, args); + }; + + pp.Changed.Subscribe(cb); + return pp; + } + } +} diff --git a/src/Avalonia.HtmlRenderer/Utilities/Util.cs b/src/Avalonia.HtmlRenderer/Utilities/Util.cs new file mode 100644 index 0000000000..3a19eaef92 --- /dev/null +++ b/src/Avalonia.HtmlRenderer/Utilities/Util.cs @@ -0,0 +1,123 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using Avalonia; +using Avalonia.Media; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; + +namespace TheArtOfDev.HtmlRenderer.Avalonia.Utilities +{ + /// + /// Utilities for converting WPF entities to HtmlRenderer core entities. + /// + internal static class Util + { + /// + /// Convert from WPF point to core point. + /// + public static RPoint Convert(Point p) + { + return new RPoint(p.X, p.Y); + } + + /// + /// Convert from WPF point to core point. + /// + public static Point[] Convert(RPoint[] points) + { + Point[] myPoints = new Point[points.Length]; + for (int i = 0; i < points.Length; i++) + myPoints[i] = Convert(points[i]); + return myPoints; + } + + /// + /// Convert from core point to WPF point. + /// + public static Point Convert(RPoint p) + { + return new Point(p.X, p.Y); + } + + /// + /// Convert from core point to WPF point. + /// + public static Point ConvertRound(RPoint p) + { + return new Point((int)p.X, (int)p.Y); + } + + /// + /// Convert from WPF size to core size. + /// + public static RSize Convert(Size s) + { + return new RSize(s.Width, s.Height); + } + + /// + /// Convert from core size to WPF size. + /// + public static Size Convert(RSize s) + { + return new Size(s.Width, s.Height); + } + + /// + /// Convert from core point to WPF point. + /// + public static Size ConvertRound(RSize s) + { + return new Size((int)s.Width, (int)s.Height); + } + + /// + /// Convert from WPF rectangle to core rectangle. + /// + public static RRect Convert(Rect r) + { + return new RRect(r.X, r.Y, r.Width, r.Height); + } + + /// + /// Convert from core rectangle to WPF rectangle. + /// + public static Rect Convert(RRect r) + { + return new Rect(r.X, r.Y, r.Width, r.Height); + } + + /// + /// Convert from core rectangle to WPF rectangle. + /// + public static Rect ConvertRound(RRect r) + { + return new Rect((int)r.X, (int)r.Y, (int)r.Width, (int)r.Height); + } + + /// + /// Convert from WPF color to core color. + /// + public static RColor Convert(Color c) + { + return RColor.FromArgb(c.A, c.R, c.G, c.B); + } + + /// + /// Convert from core color to WPF color. + /// + public static Color Convert(RColor c) + { + return Color.FromArgb(c.A, c.R, c.G, c.B); + } + } +} \ No newline at end of file diff --git a/src/Perspex.HtmlRenderer/external b/src/Avalonia.HtmlRenderer/external similarity index 100% rename from src/Perspex.HtmlRenderer/external rename to src/Avalonia.HtmlRenderer/external diff --git a/src/Perspex.HtmlRenderer/packages.config b/src/Avalonia.HtmlRenderer/packages.config similarity index 100% rename from src/Perspex.HtmlRenderer/packages.config rename to src/Avalonia.HtmlRenderer/packages.config diff --git a/src/Avalonia.Input/AccessKeyHandler.cs b/src/Avalonia.Input/AccessKeyHandler.cs new file mode 100644 index 0000000000..7acbc109fc --- /dev/null +++ b/src/Avalonia.Input/AccessKeyHandler.cs @@ -0,0 +1,224 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia.Interactivity; +using Avalonia.VisualTree; + +namespace Avalonia.Input +{ + /// + /// Handles access keys for a window. + /// + public class AccessKeyHandler : IAccessKeyHandler + { + /// + /// Defines the AccessKeyPressed attached event. + /// + public static readonly RoutedEvent AccessKeyPressedEvent = + RoutedEvent.Register( + "AccessKeyPressed", + RoutingStrategies.Bubble, + typeof(AccessKeyHandler)); + + /// + /// The registered access keys. + /// + private readonly List> _registered = new List>(); + + /// + /// The window to which the handler belongs. + /// + private IInputRoot _owner; + + /// + /// Whether access keys are currently being shown; + /// + private bool _showingAccessKeys; + + /// + /// Whether to ignore the Alt KeyUp event. + /// + private bool _ignoreAltUp; + + /// + /// Gets or sets the window's main menu. + /// + public IMainMenu MainMenu { get; set; } + + /// + /// Sets the owner of the access key handler. + /// + /// The owner. + /// + /// This method can only be called once, typically by the owner itself on creation. + /// + public void SetOwner(IInputRoot owner) + { + Contract.Requires(owner != null); + + if (_owner != null) + { + throw new InvalidOperationException("AccessKeyHandler owner has already been set."); + } + + _owner = owner; + + _owner.AddHandler(InputElement.KeyDownEvent, OnPreviewKeyDown, RoutingStrategies.Tunnel); + _owner.AddHandler(InputElement.KeyDownEvent, OnKeyDown, RoutingStrategies.Bubble); + _owner.AddHandler(InputElement.KeyUpEvent, OnPreviewKeyUp, RoutingStrategies.Tunnel); + _owner.AddHandler(InputElement.PointerPressedEvent, OnPreviewPointerPressed, RoutingStrategies.Tunnel); + } + + /// + /// Registers an input element to be associated with an access key. + /// + /// The access key. + /// The input element. + public void Register(char accessKey, IInputElement element) + { + var existing = _registered.FirstOrDefault(x => x.Item2 == element); + + if (existing != null) + { + _registered.Remove(existing); + } + + _registered.Add(Tuple.Create(accessKey.ToString().ToUpper(), element)); + } + + /// + /// Unregisters the access keys associated with the input element. + /// + /// The input element. + public void Unregister(IInputElement element) + { + foreach (var i in _registered.Where(x => x.Item2 == element).ToList()) + { + _registered.Remove(i); + } + } + + /// + /// Called when a key is pressed in the owner window. + /// + /// The event sender. + /// The event args. + protected virtual void OnPreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.LeftAlt) + { + if (MainMenu == null || !MainMenu.IsOpen) + { + // When Alt is pressed without a main menu, or with a closed main menu, show + // access key markers in the window (i.e. "_File"). + _owner.ShowAccessKeys = _showingAccessKeys = true; + } + else + { + // If the Alt key is pressed and the main menu is open, close the main menu. + CloseMenu(); + _ignoreAltUp = true; + } + + // We always handle the Alt key. + e.Handled = true; + } + } + + /// + /// Called when a key is pressed in the owner window. + /// + /// The event sender. + /// The event args. + protected virtual void OnKeyDown(object sender, KeyEventArgs e) + { + bool menuIsOpen = MainMenu?.IsOpen == true; + + if (e.Key == Key.Escape && menuIsOpen) + { + // When the Escape key is pressed with the main menu open, close it. + CloseMenu(); + e.Handled = true; + } + else if ((e.Modifiers & InputModifiers.Alt) != 0 || menuIsOpen) + { + // If any other key is pressed with the Alt key held down, or the main menu is open, + // find all controls who have registered that access key. + var text = e.Key.ToString().ToUpper(); + var matches = _registered + .Where(x => x.Item1 == text && x.Item2.IsEffectivelyVisible) + .Select(x => x.Item2); + + // If the menu is open, only match controls in the menu's visual tree. + if (menuIsOpen) + { + matches = matches.Where(x => MainMenu.IsVisualAncestorOf(x)); + } + + var match = matches.FirstOrDefault(); + + // If there was a match, raise the AccessKeyPressed event on it. + if (match != null) + { + match.RaiseEvent(new RoutedEventArgs(AccessKeyPressedEvent)); + e.Handled = true; + } + } + } + + /// + /// Handles the Alt/F10 keys being released in the window. + /// + /// The event sender. + /// The event args. + protected virtual void OnPreviewKeyUp(object sender, KeyEventArgs e) + { + switch (e.Key) + { + case Key.LeftAlt: + if (_ignoreAltUp) + { + _ignoreAltUp = false; + } + else if (_showingAccessKeys && MainMenu != null) + { + MainMenu.Open(); + e.Handled = true; + } + + break; + + case Key.F10: + _owner.ShowAccessKeys = _showingAccessKeys = true; + MainMenu.Open(); + e.Handled = true; + break; + } + } + + /// + /// Handles pointer presses in the window. + /// + /// The event sender. + /// The event args. + protected virtual void OnPreviewPointerPressed(object sender, PointerEventArgs e) + { + if (_showingAccessKeys) + { + _owner.ShowAccessKeys = false; + } + } + + /// + /// Closes the and performs other bookeeping. + /// + private void CloseMenu() + { + MainMenu.Close(); + _owner.ShowAccessKeys = _showingAccessKeys = false; + } + } +} diff --git a/src/Avalonia.Input/Avalonia.Input.csproj b/src/Avalonia.Input/Avalonia.Input.csproj new file mode 100644 index 0000000000..569e1bb2cc --- /dev/null +++ b/src/Avalonia.Input/Avalonia.Input.csproj @@ -0,0 +1,145 @@ + + + + + 11.0 + Debug + AnyCPU + {62024B2D-53EB-4638-B26B-85EEAA54866E} + Library + Properties + Avalonia.Input + Avalonia.Input + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Avalonia.Input.XML + CS1591 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Avalonia.Input.XML + CS1591 + + + + + {D211E587-D8BC-45B9-95A4-F297C8FA5200} + Avalonia.Animation + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B} + Avalonia.Interactivity + + + {42472427-4774-4C81-8AFF-9F27B8E31721} + Avalonia.Layout + + + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Avalonia.SceneGraph + + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll + + + ..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll + + + ..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll + + + ..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Input/Cursors.cs b/src/Avalonia.Input/Cursors.cs new file mode 100644 index 0000000000..e3860e58e5 --- /dev/null +++ b/src/Avalonia.Input/Cursors.cs @@ -0,0 +1,77 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Platform; + +namespace Avalonia.Input +{ + /* + ========================================================================================= + NOTE: Cursors are NOT disposable and are cached in platform implementation. + To support loading custom cursors some measures about that should be taken beforehand + ========================================================================================= + */ + + public enum StandardCursorType + { + Arrow, + Ibeam, + Wait, + Cross, + UpArrow, + SizeWestEast, + SizeNorthSouth, + SizeAll, + No, + Hand, + AppStarting, + Help, + TopSide, + BottomSize, + LeftSide, + RightSide, + TopLeftCorner, + TopRightCorner, + BottomLeftCorner, + BottomRightCorner + + // Not available in GTK directly, see http://www.pixelbeat.org/programming/x_cursors/ + // We might enable them later, preferably, by loading pixmax direclty from theme with fallback image + // SizeNorthWestSouthEast, + // SizeNorthEastSouthWest, + } + + public class Cursor + { + public static Cursor Default = new Cursor(StandardCursorType.Arrow); + + internal Cursor(IPlatformHandle platformCursor) + { + PlatformCursor = platformCursor; + } + + public Cursor(StandardCursorType cursorType) + : this(GetCursor(cursorType)) + { + } + + public IPlatformHandle PlatformCursor { get; } + + private static IPlatformHandle GetCursor(StandardCursorType type) + { + var platform = AvaloniaLocator.Current.GetService(); + + if (platform == null) + { + throw new Exception("Could not create Cursor: IStandardCursorFactory not registered."); + } + + return platform.GetCursor(type); + } + } +} diff --git a/src/Avalonia.Input/FocusManager.cs b/src/Avalonia.Input/FocusManager.cs new file mode 100644 index 0000000000..37026d16f5 --- /dev/null +++ b/src/Avalonia.Input/FocusManager.cs @@ -0,0 +1,198 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia.Interactivity; +using Avalonia.VisualTree; + +namespace Avalonia.Input +{ + /// + /// Manages focus for the application. + /// + public class FocusManager : IFocusManager + { + /// + /// The focus scopes in which the focus is currently defined. + /// + private readonly Dictionary _focusScopes = + new Dictionary(); + + /// + /// Initializes a new instance of the class. + /// + public FocusManager() + { + InputElement.PointerPressedEvent.AddClassHandler( + typeof(IInputElement), + new EventHandler(OnPreviewPointerPressed), + RoutingStrategies.Tunnel); + } + + /// + /// Gets the instance of the . + /// + public static IFocusManager Instance => AvaloniaLocator.Current.GetService(); + + /// + /// Gets the currently focused . + /// + public IInputElement Current => KeyboardDevice.Instance?.FocusedElement; + + /// + /// Gets the current focus scope. + /// + public IFocusScope Scope + { + get; + private set; + } + + /// + /// Focuses a control. + /// + /// The control to focus. + /// The method by which focus was changed. + /// Any input modifiers active at the time of focus. + public void Focus( + IInputElement control, + NavigationMethod method = NavigationMethod.Unspecified, + InputModifiers modifiers = InputModifiers.None) + { + if (control != null) + { + var scope = GetFocusScopeAncestors(control) + .FirstOrDefault(); + + if (scope != null) + { + Scope = scope; + SetFocusedElement(scope, control, method, modifiers); + } + } + else if (Current != null) + { + // If control is null, set focus to the topmost focus scope. + foreach (var scope in GetFocusScopeAncestors(Current).Reverse().ToList()) + { + IInputElement element; + + if (_focusScopes.TryGetValue(scope, out element)) + { + Focus(element, method); + return; + } + } + + // Couldn't find a focus scope, clear focus. + SetFocusedElement(Scope, null); + } + } + + /// + /// Sets the currently focused element in the specified scope. + /// + /// The focus scope. + /// The element to focus. May be null. + /// The method by which focus was changed. + /// Any input modifiers active at the time of focus. + /// + /// If the specified scope is the current then the keyboard focus + /// will change. + /// + public void SetFocusedElement( + IFocusScope scope, + IInputElement element, + NavigationMethod method = NavigationMethod.Unspecified, + InputModifiers modifiers = InputModifiers.None) + { + Contract.Requires(scope != null); + + _focusScopes[scope] = element; + + if (Scope == scope) + { + KeyboardDevice.Instance?.SetFocusedElement(element, method, modifiers); + } + } + + /// + /// Notifies the focus manager of a change in focus scope. + /// + /// The new focus scope. + public void SetFocusScope(IFocusScope scope) + { + Contract.Requires(scope != null); + + IInputElement e; + + if (!_focusScopes.TryGetValue(scope, out e)) + { + // TODO: Make this do something useful, i.e. select the first focusable + // control, select a control that the user has specified to have default + // focus etc. + e = scope as IInputElement; + _focusScopes.Add(scope, e); + } + + Scope = scope; + Focus(e); + } + + /// + /// Checks if the specified element can be focused. + /// + /// The element. + /// True if the element can be focused. + private static bool CanFocus(IInputElement e) => e.Focusable && e.IsEnabledCore && e.IsVisible; + + /// + /// Gets the focus scope ancestors of the specified control, traversing popups. + /// + /// The control. + /// The focus scopes. + private static IEnumerable GetFocusScopeAncestors(IInputElement control) + { + while (control != null) + { + var scope = control as IFocusScope; + + if (scope != null) + { + yield return scope; + } + + control = control.GetVisualParent() ?? + ((control as IHostedVisualTreeRoot)?.Host as IInputElement); + } + } + + /// + /// Global handler for pointer pressed events. + /// + /// The event sender. + /// The event args. + private void OnPreviewPointerPressed(object sender, RoutedEventArgs e) + { + if (sender == e.Source) + { + var ev = (PointerPressedEventArgs)e; + var element = (ev.Device?.Captured as IInputElement) ?? (e.Source as IInputElement); + + if (element == null || !CanFocus(element)) + { + element = element.GetSelfAndVisualAncestors() + .OfType() + .FirstOrDefault(CanFocus); + } + + if (element != null) + { + Focus(element, NavigationMethod.Pointer, ev.InputModifiers); + } + } + } + } +} diff --git a/src/Avalonia.Input/FocusNavigationDirection.cs b/src/Avalonia.Input/FocusNavigationDirection.cs new file mode 100644 index 0000000000..c8f670a13c --- /dev/null +++ b/src/Avalonia.Input/FocusNavigationDirection.cs @@ -0,0 +1,51 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Describes how focus should be moved. + /// + public enum FocusNavigationDirection + { + /// + /// Move the focus to the next control in the tab order. + /// + Next, + + /// + /// Move the focus to the previous control in the tab order. + /// + Previous, + + /// + /// Move the focus to the first control in the tab order. + /// + First, + + /// + /// Move the focus to the last control in the tab order. + /// + Last, + + /// + /// Move the focus to the left. + /// + Left, + + /// + /// Move the focus to the right. + /// + Right, + + /// + /// Move the focus up. + /// + Up, + + /// + /// Move the focus down. + /// + Down, + } +} diff --git a/src/Avalonia.Input/Gestures.cs b/src/Avalonia.Input/Gestures.cs new file mode 100644 index 0000000000..8a514ca685 --- /dev/null +++ b/src/Avalonia.Input/Gestures.cs @@ -0,0 +1,59 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Interactivity; + +namespace Avalonia.Input +{ + public static class Gestures + { + public static readonly RoutedEvent TappedEvent = RoutedEvent.Register( + "Tapped", + RoutingStrategies.Bubble, + typeof(Gestures)); + + public static readonly RoutedEvent DoubleTappedEvent = RoutedEvent.Register( + "DoubleTapped", + RoutingStrategies.Bubble, + typeof(Gestures)); + + private static WeakReference s_lastPress; + + static Gestures() + { + InputElement.PointerPressedEvent.RouteFinished.Subscribe(PointerPressed); + InputElement.PointerReleasedEvent.RouteFinished.Subscribe(PointerReleased); + } + + private static void PointerPressed(RoutedEventArgs ev) + { + if (ev.Route == RoutingStrategies.Bubble) + { + var e = (PointerPressedEventArgs)ev; + + if (e.ClickCount <= 1) + { + s_lastPress = new WeakReference(e.Source); + } + else if (s_lastPress?.IsAlive == true && e.ClickCount == 2 && s_lastPress.Target == e.Source) + { + e.Source.RaiseEvent(new RoutedEventArgs(DoubleTappedEvent)); + } + } + } + + private static void PointerReleased(RoutedEventArgs ev) + { + if (ev.Route == RoutingStrategies.Bubble) + { + var e = (PointerReleasedEventArgs)ev; + + if (s_lastPress?.IsAlive == true && s_lastPress.Target == e.Source) + { + ((IInteractive)s_lastPress.Target).RaiseEvent(new RoutedEventArgs(TappedEvent)); + } + } + } + } +} diff --git a/src/Avalonia.Input/GotFocusEventArgs.cs b/src/Avalonia.Input/GotFocusEventArgs.cs new file mode 100644 index 0000000000..01e978a55c --- /dev/null +++ b/src/Avalonia.Input/GotFocusEventArgs.cs @@ -0,0 +1,23 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Interactivity; + +namespace Avalonia.Input +{ + /// + /// Holds arguments for a . + /// + public class GotFocusEventArgs : RoutedEventArgs + { + /// + /// Gets or sets a value indicating how the change in focus occurred. + /// + public NavigationMethod NavigationMethod { get; set; } + + /// + /// Gets or sets any input modifiers active at the time of focus. + /// + public InputModifiers InputModifiers { get; set; } + } +} diff --git a/src/Avalonia.Input/IAccessKeyHandler.cs b/src/Avalonia.Input/IAccessKeyHandler.cs new file mode 100644 index 0000000000..4ad4ed4c8a --- /dev/null +++ b/src/Avalonia.Input/IAccessKeyHandler.cs @@ -0,0 +1,38 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Defines the interface for classes that handle access keys for a window. + /// + public interface IAccessKeyHandler + { + /// + /// Gets or sets the window's main menu. + /// + IMainMenu MainMenu { get; set; } + + /// + /// Sets the owner of the access key handler. + /// + /// The owner. + /// + /// This method can only be called once, typically by the owner itself on creation. + /// + void SetOwner(IInputRoot owner); + + /// + /// Registers an input element to be associated with an access key. + /// + /// The access key. + /// The input element. + void Register(char accessKey, IInputElement element); + + /// + /// Unregisters the access keys associated with the input element. + /// + /// The input element. + void Unregister(IInputElement element); + } +} diff --git a/src/Avalonia.Input/ICloseable.cs b/src/Avalonia.Input/ICloseable.cs new file mode 100644 index 0000000000..b25e29360a --- /dev/null +++ b/src/Avalonia.Input/ICloseable.cs @@ -0,0 +1,12 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Input +{ + public interface ICloseable + { + event EventHandler Closed; + } +} diff --git a/src/Avalonia.Input/IFocusManager.cs b/src/Avalonia.Input/IFocusManager.cs new file mode 100644 index 0000000000..29a22b86b2 --- /dev/null +++ b/src/Avalonia.Input/IFocusManager.cs @@ -0,0 +1,42 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Manages focus for the application. + /// + public interface IFocusManager + { + /// + /// Gets the currently focused . + /// + IInputElement Current { get; } + + /// + /// Gets the current focus scope. + /// + IFocusScope Scope { get; } + + /// + /// Focuses a control. + /// + /// The control to focus. + /// The method by which focus was changed. + /// Any input modifiers active at the time of focus. + void Focus( + IInputElement control, + NavigationMethod method = NavigationMethod.Unspecified, + InputModifiers modifiers = InputModifiers.None); + + /// + /// Notifies the focus manager of a change in focus scope. + /// + /// The new focus scope. + /// + /// This should not be called by client code. It is called by an + /// when it activates, e.g. when a Window is activated. + /// + void SetFocusScope(IFocusScope scope); + } +} diff --git a/src/Avalonia.Input/IFocusScope.cs b/src/Avalonia.Input/IFocusScope.cs new file mode 100644 index 0000000000..97b97e0157 --- /dev/null +++ b/src/Avalonia.Input/IFocusScope.cs @@ -0,0 +1,9 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + public interface IFocusScope + { + } +} diff --git a/src/Avalonia.Input/IInputDevice.cs b/src/Avalonia.Input/IInputDevice.cs new file mode 100644 index 0000000000..916f29376a --- /dev/null +++ b/src/Avalonia.Input/IInputDevice.cs @@ -0,0 +1,9 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + public interface IInputDevice + { + } +} diff --git a/src/Avalonia.Input/IInputElement.cs b/src/Avalonia.Input/IInputElement.cs new file mode 100644 index 0000000000..72f03d3ae5 --- /dev/null +++ b/src/Avalonia.Input/IInputElement.cs @@ -0,0 +1,122 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Diagnostics.Contracts; +using System; +using System.Collections.Generic; +using Avalonia.Interactivity; +using Avalonia.VisualTree; + +namespace Avalonia.Input +{ + /// + /// Defines input-related functionality for a control. + /// + public interface IInputElement : IInteractive, IVisual + { + /// + /// Occurs when the control receives focus. + /// + event EventHandler GotFocus; + + /// + /// Occurs when the control loses focus. + /// + event EventHandler LostFocus; + + /// + /// Occurs when a key is pressed while the control has focus. + /// + event EventHandler KeyDown; + + /// + /// Occurs when a key is released while the control has focus. + /// + event EventHandler KeyUp; + + /// + /// Occurs when a user typed some text while the control has focus. + /// + event EventHandler TextInput; + + /// + /// Occurs when the pointer enters the control. + /// + event EventHandler PointerEnter; + + /// + /// Occurs when the pointer leaves the control. + /// + event EventHandler PointerLeave; + + /// + /// Occurs when the pointer is pressed over the control. + /// + event EventHandler PointerPressed; + + /// + /// Occurs when the pointer moves over the control. + /// + event EventHandler PointerMoved; + + /// + /// Occurs when the pointer is released over the control. + /// + event EventHandler PointerReleased; + + /// + /// Occurs when the mouse wheen is scrolled over the control. + /// + event EventHandler PointerWheelChanged; + + /// + /// Gets or sets a value indicating whether the control can receive keyboard focus. + /// + bool Focusable { get; } + + /// + /// Gets or sets a value indicating whether the control is enabled for user interaction. + /// + bool IsEnabled { get; } + + /// + /// Gets or sets the associated mouse cursor. + /// + Cursor Cursor { get; } + + /// + /// Gets a value indicating whether the control is effectively enabled for user interaction. + /// + /// + /// The property is used to toggle the enabled state for individual + /// controls. The property takes into account the + /// value of this control and its parent controls. + /// + bool IsEnabledCore { get; } + + /// + /// Gets or sets a value indicating whether the control is focused. + /// + bool IsFocused { get; } + + /// + /// Gets or sets a value indicating whether the control is considered for hit testing. + /// + bool IsHitTestVisible { get; } + + /// + /// Gets or sets a value indicating whether the pointer is currently over the control. + /// + bool IsPointerOver { get; } + + /// + /// Focuses the control. + /// + void Focus(); + + /// + /// Gets the key bindings for the element. + /// + List KeyBindings { get; } + } +} diff --git a/src/Avalonia.Input/IInputManager.cs b/src/Avalonia.Input/IInputManager.cs new file mode 100644 index 0000000000..bc8ccbed5a --- /dev/null +++ b/src/Avalonia.Input/IInputManager.cs @@ -0,0 +1,38 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Input.Raw; + +namespace Avalonia.Input +{ + /// + /// Recieves input from the windowing subsystem and dispatches it to interested parties + /// for processing. + /// + public interface IInputManager + { + /// + /// Gets an observable that notifies on each input event recieved before + /// . + /// + IObservable PreProcess { get; } + + /// + /// Gets an observable that notifies on each input event recieved. + /// + IObservable Process { get; } + + /// + /// Gets an observable that notifies on each input event recieved after + /// . + /// + IObservable PostProcess { get; } + + /// + /// Processes a raw input event. + /// + /// The raw input event. + void ProcessInput(RawInputEventArgs e); + } +} diff --git a/src/Avalonia.Input/IInputRoot.cs b/src/Avalonia.Input/IInputRoot.cs new file mode 100644 index 0000000000..6c01bb9c0e --- /dev/null +++ b/src/Avalonia.Input/IInputRoot.cs @@ -0,0 +1,31 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Defines the interface for top-level input elements. + /// + public interface IInputRoot : IInputElement + { + /// + /// Gets or sets the access key handler. + /// + IAccessKeyHandler AccessKeyHandler { get; } + + /// + /// Gets or sets the keyboard navigation handler. + /// + IKeyboardNavigationHandler KeyboardNavigationHandler { get; } + + /// + /// Gets or sets the input element that the pointer is currently over. + /// + IInputElement PointerOverElement { get; set; } + + /// + /// Gets or sets a value indicating whether access keys are shown in the window. + /// + bool ShowAccessKeys { get; set; } + } +} diff --git a/src/Avalonia.Input/IKeyboardDevice.cs b/src/Avalonia.Input/IKeyboardDevice.cs new file mode 100644 index 0000000000..f27fec6907 --- /dev/null +++ b/src/Avalonia.Input/IKeyboardDevice.cs @@ -0,0 +1,38 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Input +{ + [Flags] + public enum InputModifiers + { + None = 0, + Alt = 1, + Control = 2, + Shift = 4, + Windows = 8, + LeftMouseButton = 16, + RightMouseButton = 32, + MiddleMouseButton = 64 + } + + [Flags] + public enum KeyStates + { + None = 0, + Down = 1, + Toggled = 2, + } + + public interface IKeyboardDevice : IInputDevice + { + IInputElement FocusedElement { get; } + + void SetFocusedElement( + IInputElement element, + NavigationMethod method, + InputModifiers modifiers); + } +} diff --git a/src/Avalonia.Input/IKeyboardNavigationHandler.cs b/src/Avalonia.Input/IKeyboardNavigationHandler.cs new file mode 100644 index 0000000000..14e2144da9 --- /dev/null +++ b/src/Avalonia.Input/IKeyboardNavigationHandler.cs @@ -0,0 +1,31 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Defines the interface for classes that handle keyboard navigation for a window. + /// + public interface IKeyboardNavigationHandler + { + /// + /// Sets the owner of the keyboard navigation handler. + /// + /// The owner. + /// + /// This method can only be called once, typically by the owner itself on creation. + /// + void SetOwner(IInputRoot owner); + + /// + /// Moves the focus in the specified direction. + /// + /// The current element. + /// The direction to move. + /// Any input modifiers active at the time of focus. + void Move( + IInputElement element, + FocusNavigationDirection direction, + InputModifiers modifiers = InputModifiers.None); + } +} \ No newline at end of file diff --git a/src/Avalonia.Input/IMainMenu.cs b/src/Avalonia.Input/IMainMenu.cs new file mode 100644 index 0000000000..39d19a0a76 --- /dev/null +++ b/src/Avalonia.Input/IMainMenu.cs @@ -0,0 +1,28 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.VisualTree; + +namespace Avalonia.Input +{ + /// + /// Defines the interface for a window's main menu. + /// + public interface IMainMenu : IVisual + { + /// + /// Gets a value indicating whether the menu is open. + /// + bool IsOpen { get; } + + /// + /// Closes the menu. + /// + void Close(); + + /// + /// Opens the menu in response to the Alt/F10 key. + /// + void Open(); + } +} diff --git a/src/Avalonia.Input/IMouseDevice.cs b/src/Avalonia.Input/IMouseDevice.cs new file mode 100644 index 0000000000..58e2222295 --- /dev/null +++ b/src/Avalonia.Input/IMouseDevice.cs @@ -0,0 +1,16 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Represents a mouse device. + /// + public interface IMouseDevice : IPointerDevice + { + /// + /// Gets the mouse position, in screen coordinates. + /// + Point Position { get; } + } +} diff --git a/src/Avalonia.Input/INavigableContainer.cs b/src/Avalonia.Input/INavigableContainer.cs new file mode 100644 index 0000000000..48f85819c0 --- /dev/null +++ b/src/Avalonia.Input/INavigableContainer.cs @@ -0,0 +1,19 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Defines a container in which the child controls can be navigated by keyboard. + /// + public interface INavigableContainer + { + /// + /// Gets the next control in the specified direction. + /// + /// The movement direction. + /// The control from which movement begins. + /// The control. + IInputElement GetControl(FocusNavigationDirection direction, IInputElement from); + } +} diff --git a/src/Avalonia.Input/IPointerDevice.cs b/src/Avalonia.Input/IPointerDevice.cs new file mode 100644 index 0000000000..4ffbd1c6e3 --- /dev/null +++ b/src/Avalonia.Input/IPointerDevice.cs @@ -0,0 +1,18 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Interactivity; +using Avalonia.VisualTree; + +namespace Avalonia.Input +{ + public interface IPointerDevice : IInputDevice + { + IInputElement Captured { get; } + + void Capture(IInputElement control); + + Point GetPosition(IVisual relativeTo); + } +} diff --git a/src/Avalonia.Input/InputElement.cs b/src/Avalonia.Input/InputElement.cs new file mode 100644 index 0000000000..652b58f0b5 --- /dev/null +++ b/src/Avalonia.Input/InputElement.cs @@ -0,0 +1,523 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia.Interactivity; +using Avalonia.Rendering; +using Avalonia.VisualTree; + +namespace Avalonia.Input +{ + /// + /// Implements input-related functionality for a control. + /// + public class InputElement : Interactive, IInputElement + { + /// + /// Defines the property. + /// + public static readonly StyledProperty FocusableProperty = + AvaloniaProperty.Register(nameof(Focusable)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty IsEnabledProperty = + AvaloniaProperty.Register(nameof(IsEnabled), true); + + /// + /// Defines the property. + /// + public static readonly StyledProperty IsEnabledCoreProperty = + AvaloniaProperty.Register("IsEnabledCore", true); + + /// + /// Gets or sets associated mouse cursor. + /// + public static readonly StyledProperty CursorProperty = + AvaloniaProperty.Register("Cursor", null, true); + + /// + /// Defines the property. + /// + public static readonly DirectProperty IsFocusedProperty = + AvaloniaProperty.RegisterDirect("IsFocused", o => o.IsFocused); + + /// + /// Defines the property. + /// + public static readonly StyledProperty IsHitTestVisibleProperty = + AvaloniaProperty.Register("IsHitTestVisible", true); + + /// + /// Defines the property. + /// + public static readonly DirectProperty IsPointerOverProperty = + AvaloniaProperty.RegisterDirect("IsPointerOver", o => o.IsPointerOver); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent GotFocusEvent = + RoutedEvent.Register("GotFocus", RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent LostFocusEvent = + RoutedEvent.Register("LostFocus", RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent KeyDownEvent = + RoutedEvent.Register( + "KeyDown", + RoutingStrategies.Tunnel | RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent KeyUpEvent = + RoutedEvent.Register( + "KeyUp", + RoutingStrategies.Tunnel | RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent TextInputEvent = + RoutedEvent.Register( + "TextInput", + RoutingStrategies.Tunnel | RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent PointerEnterEvent = + RoutedEvent.Register("PointerEnter", RoutingStrategies.Direct); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent PointerLeaveEvent = + RoutedEvent.Register("PointerLeave", RoutingStrategies.Direct); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent PointerMovedEvent = + RoutedEvent.Register( + "PointerMove", + RoutingStrategies.Tunnel | RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent PointerPressedEvent = + RoutedEvent.Register( + "PointerPressed", + RoutingStrategies.Tunnel | RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent PointerReleasedEvent = + RoutedEvent.Register( + "PointerReleased", + RoutingStrategies.Tunnel | RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent PointerWheelChangedEvent = + RoutedEvent.Register( + "PointerWheelChanged", + RoutingStrategies.Tunnel | RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent TappedEvent = Gestures.TappedEvent; + + /// + /// Defines the event. + /// + public static readonly RoutedEvent DoubleTappedEvent = Gestures.DoubleTappedEvent; + + private bool _isFocused; + private bool _isPointerOver; + + /// + /// Initializes static members of the class. + /// + static InputElement() + { + IsEnabledProperty.Changed.Subscribe(IsEnabledChanged); + + GotFocusEvent.AddClassHandler(x => x.OnGotFocus); + LostFocusEvent.AddClassHandler(x => x.OnLostFocus); + KeyDownEvent.AddClassHandler(x => x.OnKeyDown); + KeyUpEvent.AddClassHandler(x => x.OnKeyUp); + TextInputEvent.AddClassHandler(x => x.OnTextInput); + PointerEnterEvent.AddClassHandler(x => x.OnPointerEnter); + PointerLeaveEvent.AddClassHandler(x => x.OnPointerLeave); + PointerMovedEvent.AddClassHandler(x => x.OnPointerMoved); + PointerPressedEvent.AddClassHandler(x => x.OnPointerPressed); + PointerReleasedEvent.AddClassHandler(x => x.OnPointerReleased); + PointerWheelChangedEvent.AddClassHandler(x => x.OnPointerWheelChanged); + } + + /// + /// Occurs when the control receives focus. + /// + public event EventHandler GotFocus + { + add { AddHandler(GotFocusEvent, value); } + remove { RemoveHandler(GotFocusEvent, value); } + } + + /// + /// Occurs when the control loses focus. + /// + public event EventHandler LostFocus + { + add { AddHandler(LostFocusEvent, value); } + remove { RemoveHandler(LostFocusEvent, value); } + } + + /// + /// Occurs when a key is pressed while the control has focus. + /// + public event EventHandler KeyDown + { + add { AddHandler(KeyDownEvent, value); } + remove { RemoveHandler(KeyDownEvent, value); } + } + + /// + /// Occurs when a key is released while the control has focus. + /// + public event EventHandler KeyUp + { + add { AddHandler(KeyUpEvent, value); } + remove { RemoveHandler(KeyUpEvent, value); } + } + + /// + /// Occurs when a user typed some text while the control has focus. + /// + public event EventHandler TextInput + { + add { AddHandler(TextInputEvent, value); } + remove { RemoveHandler(TextInputEvent, value); } + } + + /// + /// Occurs when the pointer enters the control. + /// + public event EventHandler PointerEnter + { + add { AddHandler(PointerEnterEvent, value); } + remove { RemoveHandler(PointerEnterEvent, value); } + } + + /// + /// Occurs when the pointer leaves the control. + /// + public event EventHandler PointerLeave + { + add { AddHandler(PointerLeaveEvent, value); } + remove { RemoveHandler(PointerLeaveEvent, value); } + } + + /// + /// Occurs when the pointer moves over the control. + /// + public event EventHandler PointerMoved + { + add { AddHandler(PointerMovedEvent, value); } + remove { RemoveHandler(PointerMovedEvent, value); } + } + + /// + /// Occurs when the pointer is pressed over the control. + /// + public event EventHandler PointerPressed + { + add { AddHandler(PointerPressedEvent, value); } + remove { RemoveHandler(PointerPressedEvent, value); } + } + + /// + /// Occurs when the pointer is released over the control. + /// + public event EventHandler PointerReleased + { + add { AddHandler(PointerReleasedEvent, value); } + remove { RemoveHandler(PointerReleasedEvent, value); } + } + + /// + /// Occurs when the mouse wheen is scrolled over the control. + /// + public event EventHandler PointerWheelChanged + { + add { AddHandler(PointerWheelChangedEvent, value); } + remove { RemoveHandler(PointerWheelChangedEvent, value); } + } + + /// + /// Occurs when a tap gesture occurs on the control. + /// + public event EventHandler Tapped + { + add { AddHandler(TappedEvent, value); } + remove { RemoveHandler(TappedEvent, value); } + } + + /// + /// Occurs when a double-tap gesture occurs on the control. + /// + public event EventHandler DoubleTapped + { + add { AddHandler(DoubleTappedEvent, value); } + remove { RemoveHandler(DoubleTappedEvent, value); } + } + + /// + /// Gets or sets a value indicating whether the control can receive focus. + /// + public bool Focusable + { + get { return GetValue(FocusableProperty); } + set { SetValue(FocusableProperty, value); } + } + + /// + /// Gets or sets a value indicating whether the control is enabled for user interaction. + /// + public bool IsEnabled + { + get { return GetValue(IsEnabledProperty); } + set { SetValue(IsEnabledProperty, value); } + } + + /// + /// Gets or sets associated mouse cursor. + /// + public Cursor Cursor + { + get { return GetValue(CursorProperty); } + set { SetValue(CursorProperty, value); } + } + + /// + /// Gets or sets a value indicating whether the control is focused. + /// + public bool IsFocused + { + get { return _isFocused; } + private set { SetAndRaise(IsFocusedProperty, ref _isFocused, value); } + } + + /// + /// Gets or sets a value indicating whether the control is considered for hit testing. + /// + public bool IsHitTestVisible + { + get { return GetValue(IsHitTestVisibleProperty); } + set { SetValue(IsHitTestVisibleProperty, value); } + } + + /// + /// Gets or sets a value indicating whether the pointer is currently over the control. + /// + public bool IsPointerOver + { + get { return _isPointerOver; } + internal set { SetAndRaise(IsPointerOverProperty, ref _isPointerOver, value); } + } + + /// + /// Gets a value indicating whether the control is effectively enabled for user interaction. + /// + /// + /// The property is used to toggle the enabled state for individual + /// controls. The property takes into account the + /// value of this control and its parent controls. + /// + bool IInputElement.IsEnabledCore => IsEnabledCore; + + /// + /// Gets a value indicating whether the control is effectively enabled for user interaction. + /// + /// + /// The property is used to toggle the enabled state for individual + /// controls. The property takes into account the + /// value of this control and its parent controls. + /// + protected bool IsEnabledCore + { + get { return GetValue(IsEnabledCoreProperty); } + set { SetValue(IsEnabledCoreProperty, value); } + } + + public List KeyBindings { get; } = new List(); + + /// + /// Focuses the control. + /// + public void Focus() + { + FocusManager.Instance.Focus(this); + } + + /// + protected override void OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) + { + base.OnDetachedFromVisualTreeCore(e); + + if (IsFocused) + { + FocusManager.Instance.Focus(null); + } + } + + /// + protected override void OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTreeCore(e); + UpdateIsEnabledCore(); + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnGotFocus(GotFocusEventArgs e) + { + IsFocused = e.Source == this; + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnLostFocus(RoutedEventArgs e) + { + IsFocused = false; + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnKeyDown(KeyEventArgs e) + { + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnKeyUp(KeyEventArgs e) + { + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnTextInput(TextInputEventArgs e) + { + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnPointerEnter(PointerEventArgs e) + { + IsPointerOver = true; + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnPointerLeave(PointerEventArgs e) + { + IsPointerOver = false; + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnPointerMoved(PointerEventArgs e) + { + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnPointerPressed(PointerPressedEventArgs e) + { + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnPointerReleased(PointerEventArgs e) + { + } + + /// + /// Called before the event occurs. + /// + /// The event args. + protected virtual void OnPointerWheelChanged(PointerWheelEventArgs e) + { + } + + private static void IsEnabledChanged(AvaloniaPropertyChangedEventArgs e) + { + ((InputElement)e.Sender).UpdateIsEnabledCore(); + } + + /// + /// Updates the property value. + /// + private void UpdateIsEnabledCore() + { + UpdateIsEnabledCore(this.GetVisualParent()); + } + + /// + /// Updates the property based on the parent's + /// . + /// + /// The parent control. + private void UpdateIsEnabledCore(InputElement parent) + { + if (parent != null) + { + IsEnabledCore = IsEnabled && parent.IsEnabledCore; + } + else + { + IsEnabledCore = IsEnabled; + } + + foreach (var child in this.GetVisualChildren().OfType()) + { + child.UpdateIsEnabledCore(this); + } + } + } +} diff --git a/src/Avalonia.Input/InputExtensions.cs b/src/Avalonia.Input/InputExtensions.cs new file mode 100644 index 0000000000..fcf82287ec --- /dev/null +++ b/src/Avalonia.Input/InputExtensions.cs @@ -0,0 +1,95 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Avalonia.Input +{ + /// + /// Defines extensions for the interface. + /// + public static class InputExtensions + { + /// + /// Returns the active input elements at a point on an . + /// + /// The element to test. + /// The point on . + /// + /// The active input elements found at the point, ordered topmost first. + /// + public static IEnumerable GetInputElementsAt(this IInputElement element, Point p) + { + Contract.Requires(element != null); + + if (element.Bounds.Contains(p) && + element.IsVisible && + element.IsHitTestVisible && + element.IsEnabledCore) + { + p -= element.Bounds.Position; + + if (element.VisualChildren.Any()) + { + foreach (var child in ZSort(element.VisualChildren.OfType())) + { + foreach (var result in child.GetInputElementsAt(p)) + { + yield return result; + } + } + } + + yield return element; + } + } + + /// + /// Returns the topmost active input element at a point on an . + /// + /// The element to test. + /// The point on . + /// The topmost at the specified position. + public static IInputElement InputHitTest(this IInputElement element, Point p) + { + return element.GetInputElementsAt(p).FirstOrDefault(); + } + + private static IEnumerable ZSort(IEnumerable elements) + { + return elements + .Select((element, index) => new ZOrderElement + { + Element = element, + Index = index, + ZIndex = element.ZIndex, + }) + .OrderBy(x => x, null) + .Select(x => x.Element); + + } + + private class ZOrderElement : IComparable + { + public IInputElement Element { get; set; } + public int Index { get; set; } + public int ZIndex { get; set; } + + public int CompareTo(ZOrderElement other) + { + var z = other.ZIndex - ZIndex; + + if (z != 0) + { + return z; + } + else + { + return other.Index - Index; + } + } + } + } +} diff --git a/src/Avalonia.Input/InputManager.cs b/src/Avalonia.Input/InputManager.cs new file mode 100644 index 0000000000..7aa609e65c --- /dev/null +++ b/src/Avalonia.Input/InputManager.cs @@ -0,0 +1,42 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Subjects; +using Avalonia.Input.Raw; + +namespace Avalonia.Input +{ + /// + /// Recieves input from the windowing subsystem and dispatches it to interested parties + /// for processing. + /// + public class InputManager : IInputManager + { + private readonly Subject _preProcess = new Subject(); + private readonly Subject _process = new Subject(); + private readonly Subject _postProcess = new Subject(); + + /// + /// Gets the global instance of the input manager. + /// + public static IInputManager Instance => AvaloniaLocator.Current.GetService(); + + /// + public IObservable PreProcess => _preProcess; + + /// + public IObservable Process => _process; + + /// + public IObservable PostProcess => _postProcess; + + /// + public void ProcessInput(RawInputEventArgs e) + { + _preProcess.OnNext(e); + _process.OnNext(e); + _postProcess.OnNext(e); + } + } +} diff --git a/src/Avalonia.Input/Key.cs b/src/Avalonia.Input/Key.cs new file mode 100644 index 0000000000..3ea506d79e --- /dev/null +++ b/src/Avalonia.Input/Key.cs @@ -0,0 +1,1021 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Defines the keys available on a keyboard. + /// + public enum Key + { + /// + /// No key pressed. + /// + None = 0, + + /// + /// The Cancel key. + /// + Cancel = 1, + + /// + /// The Back key. + /// + Back = 2, + + /// + /// The Tab key. + /// + Tab = 3, + + /// + /// The Linefeed key. + /// + LineFeed = 4, + + /// + /// The Clear key. + /// + Clear = 5, + + /// + /// The Return key. + /// + Return = 6, + + /// + /// The Enter key. + /// + Enter = 6, + + /// + /// The Pause key. + /// + Pause = 7, + + /// + /// The Caps Lock key. + /// + CapsLock = 8, + + /// + /// The Caps Lock key. + /// + Capital = 8, + + /// + /// The IME Hangul mode key. + /// + HangulMode = 9, + + /// + /// The IME Kana mode key. + /// + KanaMode = 9, + + /// + /// The IME Janja mode key. + /// + JunjaMode = 10, + + /// + /// The IME Final mode key. + /// + FinalMode = 11, + + /// + /// The IME Kanji mode key. + /// + KanjiMode = 12, + + /// + /// The IME Hanja mode key. + /// + HanjaMode = 12, + + /// + /// The Escape key. + /// + Escape = 13, + + /// + /// The IME Convert key. + /// + ImeConvert = 14, + + /// + /// The IME NonConvert key. + /// + ImeNonConvert = 15, + + /// + /// The IME Accept key. + /// + ImeAccept = 16, + + /// + /// The IME Mode change key. + /// + ImeModeChange = 17, + + /// + /// The space bar. + /// + Space = 18, + + /// + /// The Page Up key. + /// + PageUp = 19, + + /// + /// The Page Up key. + /// + Prior = 19, + + /// + /// The Page Down key. + /// + PageDown = 20, + + /// + /// The Page Down key. + /// + Next = 20, + + /// + /// The End key. + /// + End = 21, + + /// + /// The Home key. + /// + Home = 22, + + /// + /// The Left arrow key. + /// + Left = 23, + + /// + /// The Up arrow key. + /// + Up = 24, + + /// + /// The Right arrow key. + /// + Right = 25, + + /// + /// The Down arrow key. + /// + Down = 26, + + /// + /// The Select key. + /// + Select = 27, + + /// + /// The Print key. + /// + Print = 28, + + /// + /// The Execute key. + /// + Execute = 29, + + /// + /// The Print Screen key. + /// + Snapshot = 30, + + /// + /// The Print Screen key. + /// + PrintScreen = 30, + + /// + /// The Insert key. + /// + Insert = 31, + + /// + /// The Delete key. + /// + Delete = 32, + + /// + /// The Help key. + /// + Help = 33, + + /// + /// The 0 key. + /// + D0 = 34, + + /// + /// The 1 key. + /// + D1 = 35, + + /// + /// The 2 key. + /// + D2 = 36, + + /// + /// The 3 key. + /// + D3 = 37, + + /// + /// The 4 key. + /// + D4 = 38, + + /// + /// The 5 key. + /// + D5 = 39, + + /// + /// The 6 key. + /// + D6 = 40, + + /// + /// The 7 key. + /// + D7 = 41, + + /// + /// The 8 key. + /// + D8 = 42, + + /// + /// The 9 key. + /// + D9 = 43, + + /// + /// The A key. + /// + A = 44, + + /// + /// The B key. + /// + B = 45, + + /// + /// The C key. + /// + C = 46, + + /// + /// The D key. + /// + D = 47, + + /// + /// The E key. + /// + E = 48, + + /// + /// The F key. + /// + F = 49, + + /// + /// The G key. + /// + G = 50, + + /// + /// The H key. + /// + H = 51, + + /// + /// The I key. + /// + I = 52, + + /// + /// The J key. + /// + J = 53, + + /// + /// The K key. + /// + K = 54, + + /// + /// The L key. + /// + L = 55, + + /// + /// The M key. + /// + M = 56, + + /// + /// The N key. + /// + N = 57, + + /// + /// The O key. + /// + O = 58, + + /// + /// The P key. + /// + P = 59, + + /// + /// The Q key. + /// + Q = 60, + + /// + /// The R key. + /// + R = 61, + + /// + /// The S key. + /// + S = 62, + + /// + /// The T key. + /// + T = 63, + + /// + /// The U key. + /// + U = 64, + + /// + /// The V key. + /// + V = 65, + + /// + /// The W key. + /// + W = 66, + + /// + /// The X key. + /// + X = 67, + + /// + /// The Y key. + /// + Y = 68, + + /// + /// The Z key. + /// + Z = 69, + + /// + /// The left Windows key. + /// + LWin = 70, + + /// + /// The right Windows key. + /// + RWin = 71, + + /// + /// The Application key. + /// + Apps = 72, + + /// + /// The Sleep key. + /// + Sleep = 73, + + /// + /// The 0 key on the numeric keypad. + /// + NumPad0 = 74, + + /// + /// The 1 key on the numeric keypad. + /// + NumPad1 = 75, + + /// + /// The 2 key on the numeric keypad. + /// + NumPad2 = 76, + + /// + /// The 3 key on the numeric keypad. + /// + NumPad3 = 77, + + /// + /// The 4 key on the numeric keypad. + /// + NumPad4 = 78, + + /// + /// The 5 key on the numeric keypad. + /// + NumPad5 = 79, + + /// + /// The 6 key on the numeric keypad. + /// + NumPad6 = 80, + + /// + /// The 7 key on the numeric keypad. + /// + NumPad7 = 81, + + /// + /// The 8 key on the numeric keypad. + /// + NumPad8 = 82, + + /// + /// The 9 key on the numeric keypad. + /// + NumPad9 = 83, + + /// + /// The Multiply key. + /// + Multiply = 84, + + /// + /// The Add key. + /// + Add = 85, + + /// + /// The Separator key. + /// + Separator = 86, + + /// + /// The Subtract key. + /// + Subtract = 87, + + /// + /// The Decimal key. + /// + Decimal = 88, + + /// + /// The Divide key. + /// + Divide = 89, + + /// + /// The F1 key. + /// + F1 = 90, + + /// + /// The F2 key. + /// + F2 = 91, + + /// + /// The F3 key. + /// + F3 = 92, + + /// + /// The F4 key. + /// + F4 = 93, + + /// + /// The F5 key. + /// + F5 = 94, + + /// + /// The F6 key. + /// + F6 = 95, + + /// + /// The F7 key. + /// + F7 = 96, + + /// + /// The F8 key. + /// + F8 = 97, + + /// + /// The F9 key. + /// + F9 = 98, + + /// + /// The F10 key. + /// + F10 = 99, + + /// + /// The F11 key. + /// + F11 = 100, + + /// + /// The F12 key. + /// + F12 = 101, + + /// + /// The F13 key. + /// + F13 = 102, + + /// + /// The F14 key. + /// + F14 = 103, + + /// + /// The F15 key. + /// + F15 = 104, + + /// + /// The F16 key. + /// + F16 = 105, + + /// + /// The F17 key. + /// + F17 = 106, + + /// + /// The F18 key. + /// + F18 = 107, + + /// + /// The F19 key. + /// + F19 = 108, + + /// + /// The F20 key. + /// + F20 = 109, + + /// + /// The F21 key. + /// + F21 = 110, + + /// + /// The F22 key. + /// + F22 = 111, + + /// + /// The F23 key. + /// + F23 = 112, + + /// + /// The F24 key. + /// + F24 = 113, + + /// + /// The Numlock key. + /// + NumLock = 114, + + /// + /// The Scroll key. + /// + Scroll = 115, + + /// + /// The left Shift key. + /// + LeftShift = 116, + + /// + /// The right Shift key. + /// + RightShift = 117, + + /// + /// The left Ctrl key. + /// + LeftCtrl = 118, + + /// + /// The right Ctrl key. + /// + RightCtrl = 119, + + /// + /// The left Alt key. + /// + LeftAlt = 120, + + /// + /// The right Alt key. + /// + RightAlt = 121, + + /// + /// The browser Back key. + /// + BrowserBack = 122, + + /// + /// The browser Forward key. + /// + BrowserForward = 123, + + /// + /// The browser Refresh key. + /// + BrowserRefresh = 124, + + /// + /// The browser Stop key. + /// + BrowserStop = 125, + + /// + /// The browser Search key. + /// + BrowserSearch = 126, + + /// + /// The browser Favorites key. + /// + BrowserFavorites = 127, + + /// + /// The browser Home key. + /// + BrowserHome = 128, + + /// + /// The Volume Mute key. + /// + VolumeMute = 129, + + /// + /// The Volume Down key. + /// + VolumeDown = 130, + + /// + /// The Volume Up key. + /// + VolumeUp = 131, + + /// + /// The media Next Track key. + /// + MediaNextTrack = 132, + + /// + /// The media Previous Track key. + /// + MediaPreviousTrack = 133, + + /// + /// The media Stop key. + /// + MediaStop = 134, + + /// + /// The media Play/Pause key. + /// + MediaPlayPause = 135, + + /// + /// The Launch Mail key. + /// + LaunchMail = 136, + + /// + /// The Select Media key. + /// + SelectMedia = 137, + + /// + /// The Launch Application 1 key. + /// + LaunchApplication1 = 138, + + /// + /// The Launch Application 2 key. + /// + LaunchApplication2 = 139, + + /// + /// The OEM Semicolon key. + /// + OemSemicolon = 140, + + /// + /// The OEM 1 key. + /// + Oem1 = 140, + + /// + /// The OEM Plus key. + /// + OemPlus = 141, + + /// + /// The OEM Comma key. + /// + OemComma = 142, + + /// + /// The OEM Minus key. + /// + OemMinus = 143, + + /// + /// The OEM Period key. + /// + OemPeriod = 144, + + /// + /// The OEM Question Mark key. + /// + OemQuestion = 145, + + /// + /// The OEM 2 key. + /// + Oem2 = 145, + + /// + /// The OEM Tilde key. + /// + OemTilde = 146, + + /// + /// The OEM 3 key. + /// + Oem3 = 146, + + /// + /// The ABNT_C1 (Brazilian) key. + /// + AbntC1 = 147, + + /// + /// The ABNT_C2 (Brazilian) key. + /// + AbntC2 = 148, + + /// + /// The OEM Open Brackets key. + /// + OemOpenBrackets = 149, + + /// + /// The OEM 4 key. + /// + Oem4 = 149, + + /// + /// The OEM Pipe key. + /// + OemPipe = 150, + + /// + /// The OEM 5 key. + /// + Oem5 = 150, + + /// + /// The OEM Close Brackets key. + /// + OemCloseBrackets = 151, + + /// + /// The OEM 6 key. + /// + Oem6 = 151, + + /// + /// The OEM Quotes key. + /// + OemQuotes = 152, + + /// + /// The OEM 7 key. + /// + Oem7 = 152, + + /// + /// The OEM 8 key. + /// + Oem8 = 153, + + /// + /// The OEM Backslash key. + /// + OemBackslash = 154, + + /// + /// The OEM 3 key. + /// + Oem102 = 154, + + /// + /// A special key masking the real key being processed by an IME. + /// + ImeProcessed = 155, + + /// + /// A special key masking the real key being processed as a system key. + /// + System = 156, + + /// + /// The OEM ATTN key. + /// + OemAttn = 157, + + /// + /// The DBE_ALPHANUMERIC key. + /// + DbeAlphanumeric = 157, + + /// + /// The OEM Finish key. + /// + OemFinish = 158, + + /// + /// The DBE_KATAKANA key. + /// + DbeKatakana = 158, + + /// + /// The DBE_HIRAGANA key. + /// + DbeHiragana = 159, + + /// + /// The OEM Copy key. + /// + OemCopy = 159, + + /// + /// The DBE_SBCSCHAR key. + /// + DbeSbcsChar = 160, + + /// + /// The OEM Auto key. + /// + OemAuto = 160, + + /// + /// The DBE_DBCSCHAR key. + /// + DbeDbcsChar = 161, + + /// + /// The OEM ENLW key. + /// + OemEnlw = 161, + + /// + /// The OEM BackTab key. + /// + OemBackTab = 162, + + /// + /// The DBE_ROMAN key. + /// + DbeRoman = 162, + + /// + /// The DBE_NOROMAN key. + /// + DbeNoRoman = 163, + + /// + /// The ATTN key. + /// + Attn = 163, + + /// + /// The CRSEL key. + /// + CrSel = 164, + + /// + /// The DBE_ENTERWORDREGISTERMODE key. + /// + DbeEnterWordRegisterMode = 164, + + /// + /// The EXSEL key. + /// + ExSel = 165, + + /// + /// The DBE_ENTERIMECONFIGMODE key. + /// + DbeEnterImeConfigureMode = 165, + + /// + /// The ERASE EOF Key. + /// + EraseEof = 166, + + /// + /// The DBE_FLUSHSTRING key. + /// + DbeFlushString = 166, + + /// + /// The Play key. + /// + Play = 167, + + /// + /// The DBE_CODEINPUT key. + /// + DbeCodeInput = 167, + + /// + /// The DBE_NOCODEINPUT key. + /// + DbeNoCodeInput = 168, + + /// + /// The Zoom key. + /// + Zoom = 168, + + /// + /// Reserved for future use. + /// + NoName = 169, + + /// + /// The DBE_DETERMINESTRING key. + /// + DbeDetermineString = 169, + + /// + /// The DBE_ENTERDLGCONVERSIONMODE key. + /// + DbeEnterDialogConversionMode = 170, + + /// + /// The PA1 key. + /// + Pa1 = 170, + + /// + /// The OEM Clear key. + /// + OemClear = 171, + + /// + /// The key is used with another key to create a single combined character. + /// + DeadCharProcessed = 172, + } +} diff --git a/src/Avalonia.Input/KeyBinding.cs b/src/Avalonia.Input/KeyBinding.cs new file mode 100644 index 0000000000..a14f87beb1 --- /dev/null +++ b/src/Avalonia.Input/KeyBinding.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace Avalonia.Input +{ + public class KeyBinding : AvaloniaObject + { + public static readonly StyledProperty CommandProperty = + AvaloniaProperty.Register("Command"); + + public ICommand Command + { + get { return GetValue(CommandProperty); } + set { SetValue(CommandProperty, value); } + } + + public static readonly StyledProperty CommandParameterProperty = + AvaloniaProperty.Register("CommandParameter"); + + public object CommandParameter + { + get { return GetValue(CommandParameterProperty); } + set { SetValue(CommandParameterProperty, value); } + } + + public static readonly StyledProperty GestureProperty = + AvaloniaProperty.Register("Gesture"); + + public KeyGesture Gesture + { + get { return GetValue(GestureProperty); } + set { SetValue(GestureProperty, value); } + } + + public void TryHandle(KeyEventArgs args) + { + if (Gesture?.Matches(args) == true) + { + args.Handled = true; + if (Command?.CanExecute(CommandParameter) == true) + Command.Execute(CommandParameter); + } + } + } +} diff --git a/src/Avalonia.Input/KeyEventArgs.cs b/src/Avalonia.Input/KeyEventArgs.cs new file mode 100644 index 0000000000..c44f2b2fca --- /dev/null +++ b/src/Avalonia.Input/KeyEventArgs.cs @@ -0,0 +1,17 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Interactivity; + +namespace Avalonia.Input +{ + public class KeyEventArgs : RoutedEventArgs + { + public IKeyboardDevice Device { get; set; } + + public Key Key { get; set; } + + public InputModifiers Modifiers { get; set; } + } +} diff --git a/src/Avalonia.Input/KeyGesture.cs b/src/Avalonia.Input/KeyGesture.cs new file mode 100644 index 0000000000..88d3c99839 --- /dev/null +++ b/src/Avalonia.Input/KeyGesture.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Input +{ + public sealed class KeyGesture : IEquatable + { + public bool Equals(KeyGesture other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Key == other.Key && Modifiers == other.Modifiers; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + return obj is KeyGesture && Equals((KeyGesture) obj); + } + + public override int GetHashCode() + { + unchecked + { + return ((int) Key*397) ^ (int) Modifiers; + } + } + + public static bool operator ==(KeyGesture left, KeyGesture right) + { + return Equals(left, right); + } + + public static bool operator !=(KeyGesture left, KeyGesture right) + { + return !Equals(left, right); + } + + public Key Key { get; set; } + + public InputModifiers Modifiers { get; set; } + + + static readonly Dictionary KeySynonims = new Dictionary + { + {"+", Key.OemPlus }, + {"-", Key.OemMinus}, + {".", Key.OemPeriod } + }; + + //TODO: Move that to external key parser + static Key ParseKey(string key) + { + Key rv; + if (KeySynonims.TryGetValue(key.ToLower(), out rv)) + return rv; + return (Key)Enum.Parse(typeof (Key), key, true); + } + + static InputModifiers ParseModifier(string modifier) + { + if (modifier.Equals("ctrl", StringComparison.OrdinalIgnoreCase)) + return InputModifiers.Control; + return (InputModifiers) Enum.Parse(typeof (InputModifiers), modifier, true); + } + + public static KeyGesture Parse(string gesture) + { + //string.Split can't be used here because "Ctrl++" is a perfectly valid key gesture + + var parts = new List(); + + var cstart = 0; + for (var c = 0; c <= gesture.Length; c++) + { + var ch = c == gesture.Length ? '\0' : gesture[c]; + if (c == gesture.Length || (ch == '+' && cstart != c)) + { + parts.Add(gesture.Substring(cstart, c - cstart)); + cstart = c + 1; + } + } + for (var c = 0; c < parts.Count; c++) + parts[c] = parts[c].Trim(); + + var rv = new KeyGesture(); + + for (var c = 0; c < parts.Count; c++) + { + if (c == parts.Count - 1) + rv.Key = ParseKey(parts[c]); + else + rv.Modifiers |= ParseModifier(parts[c]); + } + return rv; + } + + public override string ToString() + { + var parts = new List(); + foreach (var flag in Enum.GetValues(typeof (InputModifiers)).Cast()) + { + if (Modifiers.HasFlag(flag) && flag != InputModifiers.None) + parts.Add(flag.ToString()); + } + parts.Add(Key.ToString()); + return string.Join(" + ", parts); + } + + public bool Matches(KeyEventArgs keyEvent) => keyEvent.Key == Key && keyEvent.Modifiers == Modifiers; + } +} diff --git a/src/Avalonia.Input/KeyboardDevice.cs b/src/Avalonia.Input/KeyboardDevice.cs new file mode 100644 index 0000000000..51af01f69b --- /dev/null +++ b/src/Avalonia.Input/KeyboardDevice.cs @@ -0,0 +1,145 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.ComponentModel; +using System.Linq; +using System.Reactive.Linq; +using System.Runtime.CompilerServices; +using Avalonia.Input.Raw; +using Avalonia.Interactivity; +using Avalonia.VisualTree; + +namespace Avalonia.Input +{ + public class KeyboardDevice : IKeyboardDevice, INotifyPropertyChanged + { + private IInputElement _focusedElement; + + public KeyboardDevice() + { + InputManager.Process + .OfType() + .Where(e => e.Device == this && !e.Handled) + .Subscribe(ProcessRawEvent); + } + + public event PropertyChangedEventHandler PropertyChanged; + + public static IKeyboardDevice Instance => AvaloniaLocator.Current.GetService(); + + public IInputManager InputManager => AvaloniaLocator.Current.GetService(); + + public IFocusManager FocusManager => AvaloniaLocator.Current.GetService(); + + public IInputElement FocusedElement + { + get + { + return _focusedElement; + } + + private set + { + _focusedElement = value; + RaisePropertyChanged(); + } + } + + public void SetFocusedElement( + IInputElement element, + NavigationMethod method, + InputModifiers modifiers) + { + if (element != FocusedElement) + { + var interactive = FocusedElement as IInteractive; + + interactive?.RaiseEvent(new RoutedEventArgs + { + RoutedEvent = InputElement.LostFocusEvent, + }); + + FocusedElement = element; + interactive = element as IInteractive; + + interactive?.RaiseEvent(new GotFocusEventArgs + { + RoutedEvent = InputElement.GotFocusEvent, + NavigationMethod = method, + InputModifiers = modifiers, + }); + } + } + + protected void RaisePropertyChanged([CallerMemberName] string propertyName = "") + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + private void ProcessRawEvent(RawInputEventArgs e) + { + IInputElement element = FocusedElement; + + if (element != null) + { + var keyInput = e as RawKeyEventArgs; + + if (keyInput != null) + { + switch (keyInput.Type) + { + case RawKeyEventType.KeyDown: + case RawKeyEventType.KeyUp: + var routedEvent = keyInput.Type == RawKeyEventType.KeyDown + ? InputElement.KeyDownEvent + : InputElement.KeyUpEvent; + + KeyEventArgs ev = new KeyEventArgs + { + RoutedEvent = routedEvent, + Device = this, + Key = keyInput.Key, + Modifiers = keyInput.Modifiers, + Source = element, + }; + + IVisual currentHandler = element; + while (currentHandler != null && !ev.Handled && keyInput.Type == RawKeyEventType.KeyDown) + { + var bindings = (currentHandler as IInputElement)?.KeyBindings; + if(bindings!=null) + foreach (var binding in bindings) + { + if(ev.Handled) + break; + binding.TryHandle(ev); + } + currentHandler = currentHandler.VisualParent; + } + + element.RaiseEvent(ev); + e.Handled = ev.Handled; + break; + } + } + + var text = e as RawTextInputEventArgs; + + if (text != null) + { + var ev = new TextInputEventArgs() + { + Device = this, + Text = text.Text, + Source = element, + RoutedEvent = InputElement.TextInputEvent + }; + + element.RaiseEvent(ev); + e.Handled = ev.Handled; + } + } + } + } +} diff --git a/src/Avalonia.Input/KeyboardNavigation.cs b/src/Avalonia.Input/KeyboardNavigation.cs new file mode 100644 index 0000000000..cbd9a74f4c --- /dev/null +++ b/src/Avalonia.Input/KeyboardNavigation.cs @@ -0,0 +1,109 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Defines attached properties that control keyboard navigation behaviour for a container. + /// + public static class KeyboardNavigation + { + /// + /// Defines the DirectionalNavigation attached property. + /// + /// + /// The DirectionalNavigation attached property defines how pressing arrow keys causes + /// focus to be navigated between the children of the container. + /// + public static readonly AttachedProperty DirectionalNavigationProperty = + AvaloniaProperty.RegisterAttached( + "DirectionalNavigation", + typeof(KeyboardNavigation), + KeyboardNavigationMode.None); + + /// + /// Defines the TabNavigation attached property. + /// + /// + /// The TabNavigation attached property defines how pressing the Tab key causes focus to + /// be navigated between the children of the container. + /// + public static readonly AttachedProperty TabNavigationProperty = + AvaloniaProperty.RegisterAttached( + "TabNavigation", + typeof(KeyboardNavigation)); + + /// + /// Defines the TabOnceActiveElement attached property. + /// + /// + /// When focus enters a container which has its + /// attached property set to , this property + /// defines to which child the focus should move. + /// + public static readonly AttachedProperty TabOnceActiveElementProperty = + AvaloniaProperty.RegisterAttached( + "TabOnceActiveElement", + typeof(KeyboardNavigation)); + + /// + /// Gets the for a container. + /// + /// The container. + /// The for the container. + public static KeyboardNavigationMode GetDirectionalNavigation(InputElement element) + { + return element.GetValue(DirectionalNavigationProperty); + } + + /// + /// Sets the for a container. + /// + /// The container. + /// The for the container. + public static void SetDirectionalNavigation(InputElement element, KeyboardNavigationMode value) + { + element.SetValue(DirectionalNavigationProperty, value); + } + + /// + /// Gets the for a container. + /// + /// The container. + /// The for the container. + public static KeyboardNavigationMode GetTabNavigation(InputElement element) + { + return element.GetValue(TabNavigationProperty); + } + + /// + /// Sets the for a container. + /// + /// The container. + /// The for the container. + public static void SetTabNavigation(InputElement element, KeyboardNavigationMode value) + { + element.SetValue(TabNavigationProperty, value); + } + + /// + /// Gets the for a container. + /// + /// The container. + /// The active element for the container. + public static IInputElement GetTabOnceActiveElement(InputElement element) + { + return element.GetValue(TabOnceActiveElementProperty); + } + + /// + /// Sets the for a container. + /// + /// The container. + /// The active element for the container. + public static void SetTabOnceActiveElement(InputElement element, IInputElement value) + { + element.SetValue(TabOnceActiveElementProperty, value); + } + } +} diff --git a/src/Avalonia.Input/KeyboardNavigationHandler.cs b/src/Avalonia.Input/KeyboardNavigationHandler.cs new file mode 100644 index 0000000000..9991f7ec10 --- /dev/null +++ b/src/Avalonia.Input/KeyboardNavigationHandler.cs @@ -0,0 +1,130 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Input.Navigation; + +namespace Avalonia.Input +{ + /// + /// Handles keyboard navigation for a window. + /// + public class KeyboardNavigationHandler : IKeyboardNavigationHandler + { + /// + /// The window to which the handler belongs. + /// + private IInputRoot _owner; + + /// + /// Sets the owner of the keyboard navigation handler. + /// + /// The owner. + /// + /// This method can only be called once, typically by the owner itself on creation. + /// + public void SetOwner(IInputRoot owner) + { + Contract.Requires(owner != null); + + if (_owner != null) + { + throw new InvalidOperationException("AccessKeyHandler owner has already been set."); + } + + _owner = owner; + + _owner.AddHandler(InputElement.KeyDownEvent, OnKeyDown); + } + + /// + /// Gets the next control in the specified navigation direction. + /// + /// The element. + /// The navigation direction. + /// + /// The next element in the specified direction, or null if + /// was the last in therequested direction. + /// + public static IInputElement GetNext( + IInputElement element, + FocusNavigationDirection direction) + { + Contract.Requires(element != null); + + if (direction == FocusNavigationDirection.Next || direction == FocusNavigationDirection.Previous) + { + return TabNavigation.GetNextInTabOrder(element, direction); + } + else + { + return DirectionalNavigation.GetNext(element, direction); + } + } + + /// + /// Moves the focus in the specified direction. + /// + /// The current element. + /// The direction to move. + /// Any input modifiers active at the time of focus. + public void Move( + IInputElement element, + FocusNavigationDirection direction, + InputModifiers modifiers = InputModifiers.None) + { + Contract.Requires(element != null); + + var next = GetNext(element, direction); + + if (next != null) + { + var method = direction == FocusNavigationDirection.Next || + direction == FocusNavigationDirection.Previous ? + NavigationMethod.Tab : NavigationMethod.Directional; + FocusManager.Instance.Focus(next, method, modifiers); + } + } + + /// + /// Handles the Tab key being pressed in the window. + /// + /// The event sender. + /// The event args. + protected virtual void OnKeyDown(object sender, KeyEventArgs e) + { + var current = FocusManager.Instance.Current; + + if (current != null) + { + FocusNavigationDirection? direction = null; + + switch (e.Key) + { + case Key.Tab: + direction = (e.Modifiers & InputModifiers.Shift) == 0 ? + FocusNavigationDirection.Next : FocusNavigationDirection.Previous; + break; + case Key.Up: + direction = FocusNavigationDirection.Up; + break; + case Key.Down: + direction = FocusNavigationDirection.Down; + break; + case Key.Left: + direction = FocusNavigationDirection.Left; + break; + case Key.Right: + direction = FocusNavigationDirection.Right; + break; + } + + if (direction.HasValue) + { + Move(current, direction.Value, e.Modifiers); + e.Handled = true; + } + } + } + } +} diff --git a/src/Avalonia.Input/KeyboardNavigationMode.cs b/src/Avalonia.Input/KeyboardNavigationMode.cs new file mode 100644 index 0000000000..c6ad7ecbaf --- /dev/null +++ b/src/Avalonia.Input/KeyboardNavigationMode.cs @@ -0,0 +1,43 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Defines the mode of keyboard traversal within a container when the tab or arrow keys are + /// pressed. + /// + public enum KeyboardNavigationMode + { + /// + /// Items in the container will be cycled through, and focus will be moved to the + /// previous/next container after the first/last control in the container. + /// + Continue, + + /// + /// Items in the container will be cycled through, and moving past the first or last + /// control in the container will cause the last/first control to be focused. + /// + Cycle, + + /// + /// Items in the container will be cycled through and focus will stop moving when the edge + /// of the container is reached. + /// + Contained, + + /// + /// When focus is moved into the container, the control described by the + /// attached property on the + /// container will be focused. When focus moves away from this control, focus will move to + /// the previous/next container. + /// + Once, + + /// + /// The container's children will not be focused when using the tab key. + /// + None, + } +} \ No newline at end of file diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs new file mode 100644 index 0000000000..2c0cb8656c --- /dev/null +++ b/src/Avalonia.Input/MouseDevice.cs @@ -0,0 +1,329 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; +using Avalonia.Input.Raw; +using Avalonia.Interactivity; +using Avalonia.Platform; +using Avalonia.VisualTree; + +namespace Avalonia.Input +{ + /// + /// Represents a mouse device. + /// + public class MouseDevice : IMouseDevice + { + private int _clickCount; + private Rect _lastClickRect; + private uint _lastClickTime; + private readonly List _pointerOvers = new List(); + + /// + /// Intializes a new instance of . + /// + public MouseDevice() + { + InputManager.Process + .OfType() + .Where(e => e.Device == this && !e.Handled) + .Subscribe(ProcessRawEvent); + } + + /// + /// Gets the current mouse device instance. + /// + public static IMouseDevice Instance => AvaloniaLocator.Current.GetService(); + + /// + /// Gets the control that is currently capturing by the mouse, if any. + /// + /// + /// When an element captures the mouse, it recieves mouse input whether the cursor is + /// within the control's bounds or not. To set the mouse capture, call the + /// method. + /// + public IInputElement Captured + { + get; + protected set; + } + + /// + /// Gets the application's input manager. + /// + public IInputManager InputManager => AvaloniaLocator.Current.GetService(); + + /// + /// Gets the mouse position, in screen coordinates. + /// + public Point Position + { + get; + protected set; + } + + /// + /// Captures mouse input to the specified control. + /// + /// The control. + /// + /// When an element captures the mouse, it recieves mouse input whether the cursor is + /// within the control's bounds or not. The current mouse capture control is exposed + /// by the property. + /// + public virtual void Capture(IInputElement control) + { + Captured = control; + } + + /// + /// Gets the mouse position relative to a control. + /// + /// The control. + /// The mouse position in the control's coordinates. + public Point GetPosition(IVisual relativeTo) + { + Point p = default(Point); + IVisual v = relativeTo; + IVisual root = null; + + while (v != null) + { + p += v.Bounds.Position; + root = v; + v = v.VisualParent; + } + + return root.PointToClient(Position) - p; + } + + private void ProcessRawEvent(RawMouseEventArgs e) + { + var mouse = (IMouseDevice)e.Device; + + Position = e.Root.PointToScreen(e.Position); + + switch (e.Type) + { + case RawMouseEventType.LeaveWindow: + LeaveWindow(mouse, e.Root); + break; + case RawMouseEventType.LeftButtonDown: + case RawMouseEventType.RightButtonDown: + case RawMouseEventType.MiddleButtonDown: + e.Handled = MouseDown(mouse, e.Timestamp, e.Root, e.Position, + e.Type == RawMouseEventType.LeftButtonDown + ? MouseButton.Left + : e.Type == RawMouseEventType.RightButtonDown ? MouseButton.Right : MouseButton.Middle, + e.InputModifiers); + break; + case RawMouseEventType.LeftButtonUp: + case RawMouseEventType.RightButtonUp: + case RawMouseEventType.MiddleButtonUp: + e.Handled = MouseUp(mouse, e.Root, e.Position, + e.Type == RawMouseEventType.LeftButtonUp + ? MouseButton.Left + : e.Type == RawMouseEventType.RightButtonUp ? MouseButton.Right : MouseButton.Middle, + e.InputModifiers); + break; + case RawMouseEventType.Move: + e.Handled = MouseMove(mouse, e.Root, e.Position, e.InputModifiers); + break; + case RawMouseEventType.Wheel: + e.Handled = MouseWheel(mouse, e.Root, e.Position, ((RawMouseWheelEventArgs)e).Delta, e.InputModifiers); + break; + } + } + + private void LeaveWindow(IMouseDevice device, IInputRoot root) + { + ClearPointerOver(this, root); + } + + private bool MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p, MouseButton button, InputModifiers inputModifiers) + { + var hit = HitTest(root, p); + + if (hit != null) + { + IInteractive source = GetSource(hit); + + if (source != null) + { + var settings = AvaloniaLocator.Current.GetService(); + var doubleClickTime = settings.DoubleClickTime.TotalMilliseconds; + + if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime) + { + _clickCount = 0; + } + + ++_clickCount; + _lastClickTime = timestamp; + _lastClickRect = new Rect(p, new Size()) + .Inflate(new Thickness(settings.DoubleClickSize.Width / 2, settings.DoubleClickSize.Height / 2)); + + var e = new PointerPressedEventArgs + { + Device = this, + RoutedEvent = InputElement.PointerPressedEvent, + Source = source, + ClickCount = _clickCount, + MouseButton = button, + InputModifiers = inputModifiers + }; + + source.RaiseEvent(e); + return e.Handled; + } + } + + return false; + } + + private bool MouseMove(IMouseDevice device, IInputRoot root, Point p, InputModifiers inputModifiers) + { + IInputElement source; + + if (Captured == null) + { + source = SetPointerOver(this, root, p); + } + else + { + var elements = Captured.GetSelfAndVisualAncestors().OfType().ToList(); + SetPointerOver(this, root, elements); + source = Captured; + } + + var e = new PointerEventArgs + { + Device = this, + RoutedEvent = InputElement.PointerMovedEvent, + Source = source, + InputModifiers = inputModifiers + }; + + source.RaiseEvent(e); + return e.Handled; + } + + private bool MouseUp(IMouseDevice device, IInputRoot root, Point p, MouseButton button, InputModifiers inputModifiers) + { + var hit = HitTest(root, p); + + if (hit != null) + { + var source = GetSource(hit); + var e = new PointerReleasedEventArgs + { + Device = this, + RoutedEvent = InputElement.PointerReleasedEvent, + Source = source, + MouseButton = button, + InputModifiers = inputModifiers + }; + + source?.RaiseEvent(e); + return e.Handled; + } + + return false; + } + + private bool MouseWheel(IMouseDevice device, IInputRoot root, Point p, Vector delta, InputModifiers inputModifiers) + { + var hit = HitTest(root, p); + + if (hit != null) + { + var source = GetSource(hit); + var e = new PointerWheelEventArgs + { + Device = this, + RoutedEvent = InputElement.PointerWheelChangedEvent, + Source = source, + Delta = delta, + InputModifiers = inputModifiers + }; + + source?.RaiseEvent(e); + return e.Handled; + } + + return false; + } + + private IInteractive GetSource(IVisual hit) + { + return Captured ?? + (hit as IInteractive) ?? + hit.GetSelfAndVisualAncestors().OfType().FirstOrDefault(); + } + + private IInputElement HitTest(IInputElement root, Point p) + { + return Captured ?? root.InputHitTest(p); + } + + private void ClearPointerOver(IPointerDevice device, IInputRoot root) + { + foreach (var control in _pointerOvers.ToList()) + { + PointerEventArgs e = new PointerEventArgs + { + RoutedEvent = InputElement.PointerLeaveEvent, + Device = device, + Source = control, + }; + + _pointerOvers.Remove(control); + control.RaiseEvent(e); + } + + root.PointerOverElement = null; + } + + private IInputElement SetPointerOver(IPointerDevice device, IInputRoot root, Point p) + { + var elements = root.GetInputElementsAt(p).ToList(); + return SetPointerOver(device, root, elements); + } + + private IInputElement SetPointerOver(IPointerDevice device, IInputRoot root, IList elements) + { + foreach (var control in _pointerOvers.Except(elements).ToList()) + { + PointerEventArgs e = new PointerEventArgs + { + RoutedEvent = InputElement.PointerLeaveEvent, + Device = device, + Source = control, + }; + + _pointerOvers.Remove(control); + control.RaiseEvent(e); + } + + foreach (var control in elements.Except(_pointerOvers)) + { + PointerEventArgs e = new PointerEventArgs + { + RoutedEvent = InputElement.PointerEnterEvent, + Device = device, + Source = control, + }; + + _pointerOvers.Add(control); + control.RaiseEvent(e); + } + + root.PointerOverElement = elements.FirstOrDefault() ?? root; + return root.PointerOverElement; + } + } +} diff --git a/src/Avalonia.Input/Navigation/DirectionalNavigation.cs b/src/Avalonia.Input/Navigation/DirectionalNavigation.cs new file mode 100644 index 0000000000..4d6e706516 --- /dev/null +++ b/src/Avalonia.Input/Navigation/DirectionalNavigation.cs @@ -0,0 +1,232 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia.VisualTree; + +namespace Avalonia.Input.Navigation +{ + /// + /// The implementation for default directional navigation. + /// + public static class DirectionalNavigation + { + /// + /// Gets the next control in the specified navigation direction. + /// + /// The element. + /// The navigation direction. + /// + /// The next element in the specified direction, or null if + /// was the last in the requested direction. + /// + public static IInputElement GetNext( + IInputElement element, + FocusNavigationDirection direction) + { + Contract.Requires(element != null); + Contract.Requires( + direction != FocusNavigationDirection.Next && + direction != FocusNavigationDirection.Previous); + + var container = element.GetVisualParent(); + + if (container != null) + { + var isForward = IsForward(direction); + var mode = KeyboardNavigation.GetDirectionalNavigation((InputElement)container); + + switch (mode) + { + case KeyboardNavigationMode.Continue: + return GetNextInContainer(element, container, direction) ?? + GetFirstInNextContainer(element, direction); + case KeyboardNavigationMode.Cycle: + return GetNextInContainer(element, container, direction) ?? + GetFocusableDescendent(container, direction); + case KeyboardNavigationMode.Contained: + return GetNextInContainer(element, container, direction); + default: + return null; + } + } + else + { + return GetFocusableDescendents(element).FirstOrDefault(); + } + } + + /// + /// Returns a value indicting whether the specified direction is forward. + /// + /// The direction. + /// True if the direction is forward. + private static bool IsForward(FocusNavigationDirection direction) + { + return direction == FocusNavigationDirection.Next || + direction == FocusNavigationDirection.Last || + direction == FocusNavigationDirection.Right || + direction == FocusNavigationDirection.Down; + } + + /// + /// Gets the first or last focusable descendent of the specified element. + /// + /// The element. + /// The direction to search. + /// The element or null if not found.## + private static IInputElement GetFocusableDescendent(IInputElement container, FocusNavigationDirection direction) + { + return IsForward(direction) ? + GetFocusableDescendents(container).FirstOrDefault() : + GetFocusableDescendents(container).LastOrDefault(); + } + + /// + /// Gets the focusable descendents of the specified element. + /// + /// The element. + /// The element's focusable descendents. + private static IEnumerable GetFocusableDescendents(IInputElement element) + { + var mode = KeyboardNavigation.GetDirectionalNavigation((InputElement)element); + var children = element.GetVisualChildren().OfType(); + + foreach (var child in children) + { + if (child.CanFocus()) + { + yield return child; + } + + if (child.CanFocusDescendents()) + { + foreach (var descendent in GetFocusableDescendents(child)) + { + yield return descendent; + } + } + } + } + + /// + /// Gets the next item that should be focused in the specified container. + /// + /// The starting element/ + /// The container. + /// The direction. + /// The next element, or null if the element is the last. + private static IInputElement GetNextInContainer( + IInputElement element, + IInputElement container, + FocusNavigationDirection direction) + { + if (direction == FocusNavigationDirection.Down) + { + var descendent = GetFocusableDescendents(element).FirstOrDefault(); + + if (descendent != null) + { + return descendent; + } + } + + if (container != null) + { + var navigable = container as INavigableContainer; + + if (navigable != null) + { + while (element != null) + { + element = navigable.GetControl(direction, element); + + if (element != null && element.CanFocus()) + { + break; + } + } + } + else + { + // TODO: Do a spatial search here if the container doesn't implement + // INavigableContainer. + element = null; + } + + if (element != null && direction == FocusNavigationDirection.Up) + { + var descendent = GetFocusableDescendents(element).LastOrDefault(); + + if (descendent != null) + { + return descendent; + } + } + + return element; + } + + return null; + } + + /// + /// Gets the first item that should be focused in the next container. + /// + /// The container. + /// The direction of the search. + /// The first element, or null if there are no more elements. + private static IInputElement GetFirstInNextContainer( + IInputElement container, + FocusNavigationDirection direction) + { + var parent = container.GetVisualParent(); + var isForward = IsForward(direction); + IInputElement next = null; + + if (parent != null) + { + if (!isForward && parent.CanFocus()) + { + return parent; + } + + var siblings = parent.GetVisualChildren() + .OfType() + .Where(FocusExtensions.CanFocusDescendents); + var sibling = isForward ? + siblings.SkipWhile(x => x != container).Skip(1).FirstOrDefault() : + siblings.TakeWhile(x => x != container).LastOrDefault(); + + if (sibling != null) + { + if (sibling.CanFocus()) + { + next = sibling; + } + else + { + next = isForward ? + GetFocusableDescendents(sibling).FirstOrDefault() : + GetFocusableDescendents(sibling).LastOrDefault(); + } + } + + if (next == null) + { + next = GetFirstInNextContainer(parent, direction); + } + } + else + { + next = isForward ? + GetFocusableDescendents(container).FirstOrDefault() : + GetFocusableDescendents(container).LastOrDefault(); + } + + return next; + } + } +} diff --git a/src/Avalonia.Input/Navigation/FocusExtensions.cs b/src/Avalonia.Input/Navigation/FocusExtensions.cs new file mode 100644 index 0000000000..36fda1abb1 --- /dev/null +++ b/src/Avalonia.Input/Navigation/FocusExtensions.cs @@ -0,0 +1,25 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input.Navigation +{ + /// + /// Provides extension methods relating to control focus. + /// + internal static class FocusExtensions + { + /// + /// Checks if the specified element can be focused. + /// + /// The element. + /// True if the element can be focused. + public static bool CanFocus(this IInputElement e) => e.Focusable && e.IsEnabledCore && e.IsVisible; + + /// + /// Checks if descendents of the specified element can be focused. + /// + /// The element. + /// True if descendents of the element can be focused. + public static bool CanFocusDescendents(this IInputElement e) => e.IsEnabledCore && e.IsVisible; + } +} diff --git a/src/Avalonia.Input/Navigation/TabNavigation.cs b/src/Avalonia.Input/Navigation/TabNavigation.cs new file mode 100644 index 0000000000..90502cdbf9 --- /dev/null +++ b/src/Avalonia.Input/Navigation/TabNavigation.cs @@ -0,0 +1,240 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using Avalonia.VisualTree; + +namespace Avalonia.Input.Navigation +{ + /// + /// The implementation for default tab navigation. + /// + internal static class TabNavigation + { + /// + /// Gets the next control in the specified tab direction. + /// + /// The element. + /// The tab direction. Must be Next or Previous. + /// + /// The next element in the specified direction, or null if + /// was the last in the requested direction. + /// + public static IInputElement GetNextInTabOrder( + IInputElement element, + FocusNavigationDirection direction) + { + Contract.Requires(element != null); + Contract.Requires( + direction == FocusNavigationDirection.Next || + direction == FocusNavigationDirection.Previous); + + var container = element.GetVisualParent(); + + if (container != null) + { + var mode = KeyboardNavigation.GetTabNavigation((InputElement)container); + + switch (mode) + { + case KeyboardNavigationMode.Continue: + return GetNextInContainer(element, container, direction) ?? + GetFirstInNextContainer(element, direction); + case KeyboardNavigationMode.Cycle: + return GetNextInContainer(element, container, direction) ?? + GetFocusableDescendent(container, direction); + case KeyboardNavigationMode.Contained: + return GetNextInContainer(element, container, direction); + default: + return GetFirstInNextContainer(container, direction); + } + } + else + { + return GetFocusableDescendents(element).FirstOrDefault(); + } + } + + /// + /// Gets the first or last focusable descendent of the specified element. + /// + /// The element. + /// The direction to search. + /// The element or null if not found.## + private static IInputElement GetFocusableDescendent(IInputElement container, FocusNavigationDirection direction) + { + return direction == FocusNavigationDirection.Next ? + GetFocusableDescendents(container).FirstOrDefault() : + GetFocusableDescendents(container).LastOrDefault(); + } + + /// + /// Gets the focusable descendents of the specified element. + /// + /// The element. + /// The element's focusable descendents. + private static IEnumerable GetFocusableDescendents(IInputElement element) + { + var mode = KeyboardNavigation.GetTabNavigation((InputElement)element); + + if (mode == KeyboardNavigationMode.None) + { + yield break; + } + + var children = element.GetVisualChildren().OfType(); + + if (mode == KeyboardNavigationMode.Once) + { + var active = KeyboardNavigation.GetTabOnceActiveElement((InputElement)element); + + if (active != null) + { + yield return active; + yield break; + } + else + { + children = children.Take(1); + } + } + + foreach (var child in children) + { + if (child.CanFocus()) + { + yield return child; + } + + if (child.CanFocusDescendents()) + { + foreach (var descendent in GetFocusableDescendents(child)) + { + yield return descendent; + } + } + } + } + + /// + /// Gets the next item that should be focused in the specified container. + /// + /// The starting element/ + /// The container. + /// The direction. + /// The next element, or null if the element is the last. + private static IInputElement GetNextInContainer( + IInputElement element, + IInputElement container, + FocusNavigationDirection direction) + { + if (direction == FocusNavigationDirection.Next) + { + var descendent = GetFocusableDescendents(element).FirstOrDefault(); + + if (descendent != null) + { + return descendent; + } + } + + if (container != null) + { + var navigable = container as INavigableContainer; + + // TODO: Do a spatial search here if the container doesn't implement + // INavigableContainer. + if (navigable != null) + { + while (element != null) + { + element = navigable.GetControl(direction, element); + + if (element != null && element.CanFocus()) + { + break; + } + } + } + else + { + // TODO: Do a spatial search here if the container doesn't implement + // INavigableContainer. + element = null; + } + + if (element != null && direction == FocusNavigationDirection.Previous) + { + var descendent = GetFocusableDescendents(element).LastOrDefault(); + + if (descendent != null) + { + return descendent; + } + } + + return element; + } + + return null; + } + + /// + /// Gets the first item that should be focused in the next container. + /// + /// The container. + /// The direction of the search. + /// The first element, or null if there are no more elements. + private static IInputElement GetFirstInNextContainer( + IInputElement container, + FocusNavigationDirection direction) + { + var parent = container.GetVisualParent(); + IInputElement next = null; + + if (parent != null) + { + if (direction == FocusNavigationDirection.Previous && parent.CanFocus()) + { + return parent; + } + + var siblings = parent.GetVisualChildren() + .OfType() + .Where(FocusExtensions.CanFocusDescendents); + var sibling = direction == FocusNavigationDirection.Next ? + siblings.SkipWhile(x => x != container).Skip(1).FirstOrDefault() : + siblings.TakeWhile(x => x != container).LastOrDefault(); + + if (sibling != null) + { + if (sibling.CanFocus()) + { + next = sibling; + } + else + { + next = direction == FocusNavigationDirection.Next ? + GetFocusableDescendents(sibling).FirstOrDefault() : + GetFocusableDescendents(sibling).LastOrDefault(); + } + } + + if (next == null) + { + next = GetFirstInNextContainer(parent, direction); + } + } + else + { + next = direction == FocusNavigationDirection.Next ? + GetFocusableDescendents(container).FirstOrDefault() : + GetFocusableDescendents(container).LastOrDefault(); + } + + return next; + } + } +} diff --git a/src/Avalonia.Input/NavigationMethod.cs b/src/Avalonia.Input/NavigationMethod.cs new file mode 100644 index 0000000000..a8185da52a --- /dev/null +++ b/src/Avalonia.Input/NavigationMethod.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + /// + /// Defines the method by which a focus change occurred. + /// + public enum NavigationMethod + { + /// + /// The focus was changed by an unspecified method, e.g. calling + /// . + /// + Unspecified, + + /// + /// The focus was changed by the user tabbing between control. + /// + Tab, + + /// + /// The focus was changed by the user pressing a directional navigation key. + /// + Directional, + + /// + /// The focus was changed by a pointer click. + /// + Pointer, + } +} diff --git a/src/Avalonia.Input/Platform/IClipboard.cs b/src/Avalonia.Input/Platform/IClipboard.cs new file mode 100644 index 0000000000..2426af7f5a --- /dev/null +++ b/src/Avalonia.Input/Platform/IClipboard.cs @@ -0,0 +1,20 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Input.Platform +{ + public interface IClipboard + { + Task GetTextAsync(); + + Task SetTextAsync(string text); + + Task ClearAsync(); + } +} diff --git a/src/Avalonia.Input/Platform/IStandardCursorFactory.cs b/src/Avalonia.Input/Platform/IStandardCursorFactory.cs new file mode 100644 index 0000000000..7510c0681e --- /dev/null +++ b/src/Avalonia.Input/Platform/IStandardCursorFactory.cs @@ -0,0 +1,17 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Input; + +namespace Avalonia.Platform +{ + public interface IStandardCursorFactory + { + IPlatformHandle GetCursor(StandardCursorType cursorType); + } +} diff --git a/src/Avalonia.Input/PointerEventArgs.cs b/src/Avalonia.Input/PointerEventArgs.cs new file mode 100644 index 0000000000..c4964897dd --- /dev/null +++ b/src/Avalonia.Input/PointerEventArgs.cs @@ -0,0 +1,71 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Interactivity; +using Avalonia.VisualTree; + +namespace Avalonia.Input +{ + public class PointerEventArgs : RoutedEventArgs + { + public PointerEventArgs() + { + + } + + public PointerEventArgs(RoutedEvent routedEvent) + : base(routedEvent) + { + + } + + public IPointerDevice Device { get; set; } + + public InputModifiers InputModifiers { get; set; } + + public Point GetPosition(IVisual relativeTo) + { + return Device.GetPosition(relativeTo); + } + } + + public enum MouseButton + { + None, + Left, + Right, + Middle + } + + public class PointerPressedEventArgs : PointerEventArgs + { + public PointerPressedEventArgs() + : base(InputElement.PointerPressedEvent) + { + } + + public PointerPressedEventArgs(RoutedEvent routedEvent) + : base(routedEvent) + { + } + + public int ClickCount { get; set; } + public MouseButton MouseButton { get; set; } + } + + public class PointerReleasedEventArgs : PointerEventArgs + { + public PointerReleasedEventArgs() + : base(InputElement.PointerReleasedEvent) + { + } + + public PointerReleasedEventArgs(RoutedEvent routedEvent) + : base(routedEvent) + { + } + + public MouseButton MouseButton { get; set; } + } +} diff --git a/src/Avalonia.Input/PointerWheelEventArgs.cs b/src/Avalonia.Input/PointerWheelEventArgs.cs new file mode 100644 index 0000000000..401d1d847c --- /dev/null +++ b/src/Avalonia.Input/PointerWheelEventArgs.cs @@ -0,0 +1,10 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input +{ + public class PointerWheelEventArgs : PointerEventArgs + { + public Vector Delta { get; set; } + } +} diff --git a/src/Avalonia.Input/Properties/AssemblyInfo.cs b/src/Avalonia.Input/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..64b8e8f1a3 --- /dev/null +++ b/src/Avalonia.Input/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; +using Avalonia.Metadata; + +[assembly: AssemblyTitle("Avalonia.Input")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Input")] diff --git a/src/Avalonia.Input/Raw/RawInputEventArgs.cs b/src/Avalonia.Input/Raw/RawInputEventArgs.cs new file mode 100644 index 0000000000..041c361d30 --- /dev/null +++ b/src/Avalonia.Input/Raw/RawInputEventArgs.cs @@ -0,0 +1,52 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Input.Raw +{ + /// + /// A raw input event. + /// + /// + /// Raw input events are sent from the windowing subsystem to the + /// for processing: this gives an application the opportunity to pre-process the event. After + /// pre-processing they are consumed by the relevant and turned into + /// standard Avalonia events. + /// + public class RawInputEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The associated device. + /// The event timestamp. + public RawInputEventArgs(IInputDevice device, uint timestamp) + { + Contract.Requires(device != null); + + Device = device; + Timestamp = timestamp; + } + + /// + /// Gets the associated device. + /// + public IInputDevice Device { get; } + + /// + /// Gets or sets a value indicating whether the event was handled. + /// + /// + /// If an event is not marked handled after processing via the + /// , then it will be passed on to the underlying OS for + /// handling. + /// + public bool Handled { get; set; } + + /// + /// Gets the timestamp associated with the event. + /// + public uint Timestamp { get; private set; } + } +} diff --git a/src/Avalonia.Input/Raw/RawKeyEventArgs.cs b/src/Avalonia.Input/Raw/RawKeyEventArgs.cs new file mode 100644 index 0000000000..0c208b4596 --- /dev/null +++ b/src/Avalonia.Input/Raw/RawKeyEventArgs.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input.Raw +{ + public enum RawKeyEventType + { + KeyDown, + KeyUp + } + + public class RawKeyEventArgs : RawInputEventArgs + { + public RawKeyEventArgs( + IKeyboardDevice device, + uint timestamp, + RawKeyEventType type, + Key key, InputModifiers modifiers) + : base(device, timestamp) + { + Key = key; + Type = type; + Modifiers = modifiers; + } + + public Key Key { get; set; } + + public InputModifiers Modifiers { get; set; } + + public RawKeyEventType Type { get; set; } + } +} diff --git a/src/Avalonia.Input/Raw/RawMouseEventArgs.cs b/src/Avalonia.Input/Raw/RawMouseEventArgs.cs new file mode 100644 index 0000000000..914833624f --- /dev/null +++ b/src/Avalonia.Input/Raw/RawMouseEventArgs.cs @@ -0,0 +1,74 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Input.Raw +{ + public enum RawMouseEventType + { + LeaveWindow, + LeftButtonDown, + LeftButtonUp, + RightButtonDown, + RightButtonUp, + MiddleButtonDown, + MiddleButtonUp, + Move, + Wheel, + NonClientLeftButtonDown, + } + + /// + /// A raw mouse event. + /// + public class RawMouseEventArgs : RawInputEventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The associated device. + /// The event timestamp. + /// The root from which the event originates. + /// The type of the event. + /// The mouse position, in client DIPs. + /// The input modifiers. + public RawMouseEventArgs( + IInputDevice device, + uint timestamp, + IInputRoot root, + RawMouseEventType type, + Point position, + InputModifiers inputModifiers) + : base(device, timestamp) + { + Contract.Requires(device != null); + Contract.Requires(root != null); + + Root = root; + Position = position; + Type = type; + InputModifiers = inputModifiers; + } + + /// + /// Gets the root from which the event originates. + /// + public IInputRoot Root { get; } + + /// + /// Gets the mouse position, in client DIPs. + /// + public Point Position { get; set; } + + /// + /// Gets the type of the event. + /// + public RawMouseEventType Type { get; private set; } + + /// + /// Gets the input modifiers. + /// + public InputModifiers InputModifiers { get; private set; } + } +} diff --git a/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs b/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs new file mode 100644 index 0000000000..d0ea8e5b93 --- /dev/null +++ b/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs @@ -0,0 +1,24 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Layout; + +namespace Avalonia.Input.Raw +{ + public class RawMouseWheelEventArgs : RawMouseEventArgs + { + public RawMouseWheelEventArgs( + IInputDevice device, + uint timestamp, + IInputRoot root, + Point position, + Vector delta, InputModifiers inputModifiers) + : base(device, timestamp, root, RawMouseEventType.Wheel, position, inputModifiers) + { + Delta = delta; + } + + public Vector Delta { get; private set; } + } +} diff --git a/src/Avalonia.Input/Raw/RawSizeEventArgs.cs b/src/Avalonia.Input/Raw/RawSizeEventArgs.cs new file mode 100644 index 0000000000..0a3074a859 --- /dev/null +++ b/src/Avalonia.Input/Raw/RawSizeEventArgs.cs @@ -0,0 +1,22 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Input.Raw +{ + public class RawSizeEventArgs : EventArgs + { + public RawSizeEventArgs(Size size) + { + Size = size; + } + + public RawSizeEventArgs(double width, double height) + { + Size = new Size(width, height); + } + + public Size Size { get; private set; } + } +} diff --git a/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs b/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs new file mode 100644 index 0000000000..6e427c3751 --- /dev/null +++ b/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs @@ -0,0 +1,15 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Input.Raw +{ + public class RawTextInputEventArgs : RawInputEventArgs + { + public string Text { get; set; } + + public RawTextInputEventArgs(IKeyboardDevice device, uint timestamp, string text) : base(device, timestamp) + { + Text = text; + } + } +} diff --git a/src/Avalonia.Input/TextInputEventArgs.cs b/src/Avalonia.Input/TextInputEventArgs.cs new file mode 100644 index 0000000000..17df088bdd --- /dev/null +++ b/src/Avalonia.Input/TextInputEventArgs.cs @@ -0,0 +1,19 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Interactivity; + +namespace Avalonia.Input +{ + public class TextInputEventArgs : RoutedEventArgs + { + public IKeyboardDevice Device { get; set; } + + public string Text { get; set; } + } +} diff --git a/src/Avalonia.Input/VectorEventArgs.cs b/src/Avalonia.Input/VectorEventArgs.cs new file mode 100644 index 0000000000..11aa84e16b --- /dev/null +++ b/src/Avalonia.Input/VectorEventArgs.cs @@ -0,0 +1,13 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Interactivity; + +namespace Avalonia.Input +{ + public class VectorEventArgs : RoutedEventArgs + { + public Vector Vector { get; set; } + } +} diff --git a/src/Perspex.Input/app.config b/src/Avalonia.Input/app.config similarity index 100% rename from src/Perspex.Input/app.config rename to src/Avalonia.Input/app.config diff --git a/src/Perspex.Input/packages.config b/src/Avalonia.Input/packages.config similarity index 100% rename from src/Perspex.Input/packages.config rename to src/Avalonia.Input/packages.config diff --git a/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj b/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj new file mode 100644 index 0000000000..0463d7252a --- /dev/null +++ b/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj @@ -0,0 +1,99 @@ + + + + + 11.0 + Debug + AnyCPU + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B} + Library + Properties + Avalonia.Interactivity + Avalonia.Interactivity + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Avalonia.Interactivity.XML + CS1591 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Avalonia.Interactivity.XML + CS1591 + + + + + {D211E587-D8BC-45B9-95A4-F297C8FA5200} + Avalonia.Animation + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + {42472427-4774-4C81-8AFF-9F27B8E31721} + Avalonia.Layout + + + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Avalonia.SceneGraph + + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + ..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll + + + ..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll + + + ..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll + + + ..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Interactivity/EventSubscription.cs b/src/Avalonia.Interactivity/EventSubscription.cs new file mode 100644 index 0000000000..9f763edcd3 --- /dev/null +++ b/src/Avalonia.Interactivity/EventSubscription.cs @@ -0,0 +1,16 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Interactivity +{ + internal class EventSubscription + { + public Delegate Handler { get; set; } + + public RoutingStrategies Routes { get; set; } + + public bool AlsoIfHandled { get; set; } + } +} diff --git a/src/Avalonia.Interactivity/IInteractive.cs b/src/Avalonia.Interactivity/IInteractive.cs new file mode 100644 index 0000000000..dee8396f39 --- /dev/null +++ b/src/Avalonia.Interactivity/IInteractive.cs @@ -0,0 +1,69 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Interactivity +{ + /// + /// Interface for objects that raise routed events. + /// + public interface IInteractive + { + /// + /// Gets the interactive parent of the object for bubbling and tunnelling events. + /// + IInteractive InteractiveParent { get; } + + /// + /// Adds a handler for the specified routed event. + /// + /// The routed event. + /// The handler. + /// The routing strategies to listen to. + /// Whether handled events should also be listened for. + /// A disposable that terminates the event subscription. + IDisposable AddHandler( + RoutedEvent routedEvent, + Delegate handler, + RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble, + bool handledEventsToo = false); + + /// + /// Adds a handler for the specified routed event. + /// + /// The type of the event's args. + /// The routed event. + /// The handler. + /// The routing strategies to listen to. + /// Whether handled events should also be listened for. + /// A disposable that terminates the event subscription. + IDisposable AddHandler( + RoutedEvent routedEvent, + EventHandler handler, + RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble, + bool handledEventsToo = false) where TEventArgs : RoutedEventArgs; + + /// + /// Removes a handler for the specified routed event. + /// + /// The routed event. + /// The handler. + void RemoveHandler(RoutedEvent routedEvent, Delegate handler); + + /// + /// Removes a handler for the specified routed event. + /// + /// The type of the event's args. + /// The routed event. + /// The handler. + void RemoveHandler(RoutedEvent routedEvent, EventHandler handler) + where TEventArgs : RoutedEventArgs; + + /// + /// Raises a routed event. + /// + /// The event args. + void RaiseEvent(RoutedEventArgs e); + } +} diff --git a/src/Avalonia.Interactivity/Interactive.cs b/src/Avalonia.Interactivity/Interactive.cs new file mode 100644 index 0000000000..e38b348179 --- /dev/null +++ b/src/Avalonia.Interactivity/Interactive.cs @@ -0,0 +1,201 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using Avalonia.Layout; +using Avalonia.VisualTree; + +namespace Avalonia.Interactivity +{ + /// + /// Base class for objects that raise routed events. + /// + public class Interactive : Layoutable, IInteractive + { + private readonly Dictionary> _eventHandlers = + new Dictionary>(); + + /// + /// Gets the interactive parent of the object for bubbling and tunnelling events. + /// + IInteractive IInteractive.InteractiveParent => ((IVisual)this).VisualParent as IInteractive; + + /// + /// Adds a handler for the specified routed event. + /// + /// The routed event. + /// The handler. + /// The routing strategies to listen to. + /// Whether handled events should also be listened for. + /// A disposable that terminates the event subscription. + public IDisposable AddHandler( + RoutedEvent routedEvent, + Delegate handler, + RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble, + bool handledEventsToo = false) + { + Contract.Requires(routedEvent != null); + Contract.Requires(handler != null); + + List subscriptions; + + if (!_eventHandlers.TryGetValue(routedEvent, out subscriptions)) + { + subscriptions = new List(); + _eventHandlers.Add(routedEvent, subscriptions); + } + + var sub = new EventSubscription + { + Handler = handler, + Routes = routes, + AlsoIfHandled = handledEventsToo, + }; + + subscriptions.Add(sub); + + return Disposable.Create(() => subscriptions.Remove(sub)); + } + + /// + /// Adds a handler for the specified routed event. + /// + /// The type of the event's args. + /// The routed event. + /// The handler. + /// The routing strategies to listen to. + /// Whether handled events should also be listened for. + /// A disposable that terminates the event subscription. + public IDisposable AddHandler( + RoutedEvent routedEvent, + EventHandler handler, + RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble, + bool handledEventsToo = false) where TEventArgs : RoutedEventArgs + { + return AddHandler(routedEvent, (Delegate)handler, routes, handledEventsToo); + } + + /// + /// Removes a handler for the specified routed event. + /// + /// The routed event. + /// The handler. + public void RemoveHandler(RoutedEvent routedEvent, Delegate handler) + { + Contract.Requires(routedEvent != null); + Contract.Requires(handler != null); + + List subscriptions; + + if (_eventHandlers.TryGetValue(routedEvent, out subscriptions)) + { + subscriptions.RemoveAll(x => x.Handler == handler); + } + } + + /// + /// Removes a handler for the specified routed event. + /// + /// The type of the event's args. + /// The routed event. + /// The handler. + public void RemoveHandler(RoutedEvent routedEvent, EventHandler handler) + where TEventArgs : RoutedEventArgs + { + RemoveHandler(routedEvent, (Delegate)handler); + } + + /// + /// Raises a routed event. + /// + /// The event args. + public void RaiseEvent(RoutedEventArgs e) + { + Contract.Requires(e != null); + + e.Source = e.Source ?? this; + + if (e.RoutedEvent.RoutingStrategies == RoutingStrategies.Direct) + { + e.Route = RoutingStrategies.Direct; + RaiseEventImpl(e); + e.RoutedEvent.InvokeRouteFinished(e); + } + + if ((e.RoutedEvent.RoutingStrategies & RoutingStrategies.Tunnel) != 0) + { + TunnelEvent(e); + e.RoutedEvent.InvokeRouteFinished(e); + } + + if ((e.RoutedEvent.RoutingStrategies & RoutingStrategies.Bubble) != 0) + { + BubbleEvent(e); + e.RoutedEvent.InvokeRouteFinished(e); + } + } + + /// + /// Bubbles an event. + /// + /// The event args. + private void BubbleEvent(RoutedEventArgs e) + { + Contract.Requires(e != null); + + e.Route = RoutingStrategies.Bubble; + + foreach (var target in this.GetBubbleEventRoute()) + { + ((Interactive)target).RaiseEventImpl(e); + } + } + + /// + /// Tunnels an event. + /// + /// The event args. + private void TunnelEvent(RoutedEventArgs e) + { + Contract.Requires(e != null); + + e.Route = RoutingStrategies.Tunnel; + + foreach (var target in this.GetTunnelEventRoute()) + { + ((Interactive)target).RaiseEventImpl(e); + } + } + + /// + /// Carries out the actual invocation of an event on this object. + /// + /// The event args. + private void RaiseEventImpl(RoutedEventArgs e) + { + Contract.Requires(e != null); + + e.RoutedEvent.InvokeRaised(this, e); + + List subscriptions; + + if (_eventHandlers.TryGetValue(e.RoutedEvent, out subscriptions)) + { + foreach (var sub in subscriptions.ToList()) + { + bool correctRoute = (e.Route & sub.Routes) != 0; + bool notFinished = !e.Handled || sub.AlsoIfHandled; + + if (correctRoute && notFinished) + { + sub.Handler.DynamicInvoke(this, e); + } + } + } + } + } +} diff --git a/src/Avalonia.Interactivity/InteractiveExtensions.cs b/src/Avalonia.Interactivity/InteractiveExtensions.cs new file mode 100644 index 0000000000..2507fc6866 --- /dev/null +++ b/src/Avalonia.Interactivity/InteractiveExtensions.cs @@ -0,0 +1,38 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Collections.Generic; +using System.Linq; + +namespace Avalonia.Interactivity +{ + /// + /// Provides extension methods for the interface. + /// + public static class InteractiveExtensions + { + /// + /// Gets the route for bubbling events from the specified interactive. + /// + /// The interactive. + /// The event route. + public static IEnumerable GetBubbleEventRoute(this IInteractive interactive) + { + while (interactive != null) + { + yield return interactive; + interactive = interactive.InteractiveParent; + } + } + + /// + /// Gets the route for tunneling events from the specified interactive. + /// + /// The interactive. + /// The event route. + public static IEnumerable GetTunnelEventRoute(this IInteractive interactive) + { + return interactive.GetBubbleEventRoute().Reverse(); + } + } +} diff --git a/src/Avalonia.Interactivity/Properties/AssemblyInfo.cs b/src/Avalonia.Interactivity/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..27c8765239 --- /dev/null +++ b/src/Avalonia.Interactivity/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; + +[assembly: AssemblyTitle("Avalonia.Interactive")] diff --git a/src/Avalonia.Interactivity/RoutedEvent.cs b/src/Avalonia.Interactivity/RoutedEvent.cs new file mode 100644 index 0000000000..61bb567d54 --- /dev/null +++ b/src/Avalonia.Interactivity/RoutedEvent.cs @@ -0,0 +1,158 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Subjects; +using System.Reflection; +using System.Runtime.ExceptionServices; + +namespace Avalonia.Interactivity +{ + [Flags] + public enum RoutingStrategies + { + Direct = 0x01, + Tunnel = 0x02, + Bubble = 0x04, + } + + public class RoutedEvent + { + private Subject> _raised = new Subject>(); + private Subject _routeFinished = new Subject(); + + public RoutedEvent( + string name, + RoutingStrategies routingStrategies, + Type eventArgsType, + Type ownerType) + { + Contract.Requires(name != null); + Contract.Requires(eventArgsType != null); + Contract.Requires(ownerType != null); + Contract.Requires(typeof(RoutedEventArgs).GetTypeInfo().IsAssignableFrom(eventArgsType.GetTypeInfo())); + + EventArgsType = eventArgsType; + Name = name; + OwnerType = ownerType; + RoutingStrategies = routingStrategies; + } + + public Type EventArgsType + { + get; + private set; + } + + public string Name + { + get; + private set; + } + + public Type OwnerType + { + get; + private set; + } + + public RoutingStrategies RoutingStrategies + { + get; + private set; + } + + public IObservable> Raised => _raised; + public IObservable RouteFinished => _routeFinished; + + public static RoutedEvent Register( + string name, + RoutingStrategies routingStrategy) + where TEventArgs : RoutedEventArgs + { + Contract.Requires(name != null); + + return new RoutedEvent(name, routingStrategy, typeof(TOwner)); + } + + public static RoutedEvent Register( + string name, + RoutingStrategies routingStrategy, + Type ownerType) + where TEventArgs : RoutedEventArgs + { + Contract.Requires(name != null); + + return new RoutedEvent(name, routingStrategy, ownerType); + } + + public IDisposable AddClassHandler( + Type targetType, + EventHandler handler, + RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble, + bool handledEventsToo = false) + { + return Raised.Subscribe(args => + { + var sender = args.Item1; + var e = args.Item2; + + if (targetType.GetTypeInfo().IsAssignableFrom(sender.GetType().GetTypeInfo()) && + ((e.Route == RoutingStrategies.Direct) || (e.Route & routes) != 0) && + (!e.Handled || handledEventsToo)) + { + try + { + handler.DynamicInvoke(sender, e); + } + catch (TargetInvocationException ex) + { + // Unwrap the inner exception. + ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); + } + } + }); + } + + internal void InvokeRaised(object sender, RoutedEventArgs e) + { + _raised.OnNext(Tuple.Create(sender, e)); + } + + internal void InvokeRouteFinished(RoutedEventArgs e) + { + _routeFinished.OnNext(e); + } + } + + public class RoutedEvent : RoutedEvent + where TEventArgs : RoutedEventArgs + { + public RoutedEvent(string name, RoutingStrategies routingStrategies, Type ownerType) + : base(name, routingStrategies, typeof(TEventArgs), ownerType) + { + Contract.Requires(name != null); + Contract.Requires(ownerType != null); + } + + public IDisposable AddClassHandler( + Func> handler, + RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble, + bool handledEventsToo = false) + where TTarget : class, IInteractive + { + EventHandler adapter = (sender, e) => + { + var target = sender as TTarget; + var args = e as TEventArgs; + + if (target != null && args != null) + { + handler(target)(args); + } + }; + + return AddClassHandler(typeof(TTarget), adapter, routes, handledEventsToo); + } + } +} diff --git a/src/Avalonia.Interactivity/RoutedEventArgs.cs b/src/Avalonia.Interactivity/RoutedEventArgs.cs new file mode 100644 index 0000000000..05bbf7b6a3 --- /dev/null +++ b/src/Avalonia.Interactivity/RoutedEventArgs.cs @@ -0,0 +1,33 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Interactivity +{ + public class RoutedEventArgs : EventArgs + { + public RoutedEventArgs() + { + } + + public RoutedEventArgs(RoutedEvent routedEvent) + { + RoutedEvent = routedEvent; + } + + public RoutedEventArgs(RoutedEvent routedEvent, IInteractive source) + { + RoutedEvent = routedEvent; + Source = source; + } + + public bool Handled { get; set; } + + public RoutedEvent RoutedEvent { get; set; } + + public RoutingStrategies Route { get; set; } + + public IInteractive Source { get; set; } + } +} diff --git a/src/Perspex.Interactivity/app.config b/src/Avalonia.Interactivity/app.config similarity index 100% rename from src/Perspex.Interactivity/app.config rename to src/Avalonia.Interactivity/app.config diff --git a/src/Perspex.Interactivity/packages.config b/src/Avalonia.Interactivity/packages.config similarity index 100% rename from src/Perspex.Interactivity/packages.config rename to src/Avalonia.Interactivity/packages.config diff --git a/src/Avalonia.Layout/Avalonia.Layout.csproj b/src/Avalonia.Layout/Avalonia.Layout.csproj new file mode 100644 index 0000000000..6880351a67 --- /dev/null +++ b/src/Avalonia.Layout/Avalonia.Layout.csproj @@ -0,0 +1,95 @@ + + + + + 11.0 + Debug + AnyCPU + {42472427-4774-4C81-8AFF-9F27B8E31721} + Library + Properties + Avalonia + Avalonia.Layout + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Avalonia.Layout.XML + CS1591 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Avalonia.Layout.XML + CS1591 + + + + + {D211E587-D8BC-45B9-95A4-F297C8FA5200} + Avalonia.Animation + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Avalonia.SceneGraph + + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + ..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll + + + ..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll + + + ..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll + + + ..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Layout/ILayoutManager.cs b/src/Avalonia.Layout/ILayoutManager.cs new file mode 100644 index 0000000000..b41cfd9f91 --- /dev/null +++ b/src/Avalonia.Layout/ILayoutManager.cs @@ -0,0 +1,45 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive; + +namespace Avalonia.Layout +{ + /// + /// Manages measuring and arranging of controls. + /// + public interface ILayoutManager + { + /// + /// Notifies the layout manager that a control requires a measure. + /// + /// The control. + void InvalidateMeasure(ILayoutable control); + + /// + /// Notifies the layout manager that a control requires an arrange. + /// + /// The control. + void InvalidateArrange(ILayoutable control); + + /// + /// Executes a layout pass. + /// + /// + /// You should not usually need to call this method explictly, the layout manager will + /// schedule layout passes itself. + /// + void ExecuteLayoutPass(); + + /// + /// Executes the initial layout pass on a layout root. + /// + /// The control to lay out. + /// + /// You should not usually need to call this method explictly, the layout root will call + /// it to carry out the initial layout of the control. + /// + void ExecuteInitialLayoutPass(ILayoutRoot root); + } +} diff --git a/src/Avalonia.Layout/ILayoutRoot.cs b/src/Avalonia.Layout/ILayoutRoot.cs new file mode 100644 index 0000000000..25a6331b38 --- /dev/null +++ b/src/Avalonia.Layout/ILayoutRoot.cs @@ -0,0 +1,26 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Layout +{ + /// + /// Defines the root of a layoutable tree. + /// + public interface ILayoutRoot : ILayoutable + { + /// + /// The size available to lay out the controls. + /// + Size ClientSize { get; } + + /// + /// The maximum client size available. + /// + Size MaxClientSize { get; } + + /// + /// The scaling factor to use in layout. + /// + double LayoutScaling { get; } + } +} diff --git a/src/Avalonia.Layout/ILayoutable.cs b/src/Avalonia.Layout/ILayoutable.cs new file mode 100644 index 0000000000..d670889565 --- /dev/null +++ b/src/Avalonia.Layout/ILayoutable.cs @@ -0,0 +1,116 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.VisualTree; + +namespace Avalonia.Layout +{ + /// + /// Defines layout-related functionality for a control. + /// + public interface ILayoutable : IVisual + { + /// + /// Gets the size that this element computed during the measure pass of the layout process. + /// + Size DesiredSize { get; } + + /// + /// Gets the width of the element. + /// + double Width { get; } + + /// + /// Gets the height of the element. + /// + double Height { get; } + + /// + /// Gets the minimum width of the element. + /// + double MinWidth { get; } + + /// + /// Gets the maximum width of the element. + /// + double MaxWidth { get; } + + /// + /// Gets the minimum height of the element. + /// + double MinHeight { get; } + + /// + /// Gets the maximum height of the element. + /// + double MaxHeight { get; } + + /// + /// Gets the margin around the element. + /// + Thickness Margin { get; } + + /// + /// Gets the element's preferred horizontal alignment in its parent. + /// + HorizontalAlignment HorizontalAlignment { get; } + + /// + /// Gets the element's preferred vertical alignment in its parent. + /// + VerticalAlignment VerticalAlignment { get; } + + /// + /// Gets a value indicating whether the control's layout measure is valid. + /// + bool IsMeasureValid { get; } + + /// + /// Gets a value indicating whether the control's layouts arrange is valid. + /// + bool IsArrangeValid { get; } + + /// + /// Gets the available size passed in the previous layout pass, if any. + /// + Size? PreviousMeasure { get; } + + /// + /// Gets the layout rect passed in the previous layout pass, if any. + /// + Rect? PreviousArrange { get; } + + /// + /// Creates the visual children of the control, if necessary + /// + void ApplyTemplate(); + + /// + /// Carries out a measure of the control. + /// + /// The available size for the control. + void Measure(Size availableSize); + + /// + /// Arranges the control and its children. + /// + /// The control's new bounds. + void Arrange(Rect rect); + + /// + /// Invalidates the measurement of the control and queues a new layout pass. + /// + void InvalidateMeasure(); + + /// + /// Invalidates the arrangement of the control and queues a new layout pass. + /// + void InvalidateArrange(); + + /// + /// Called when a child control's desired size changes. + /// + /// The child control. + void ChildDesiredSizeChanged(ILayoutable control); + } +} diff --git a/src/Avalonia.Layout/LayoutHelper.cs b/src/Avalonia.Layout/LayoutHelper.cs new file mode 100644 index 0000000000..8c0a6a579b --- /dev/null +++ b/src/Avalonia.Layout/LayoutHelper.cs @@ -0,0 +1,33 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Layout +{ + /// + /// Provides helper methods needed for layout. + /// + public static class LayoutHelper + { + /// + /// Calculates a control's size based on its , + /// , , + /// , and + /// . + /// + /// The control. + /// The space available for the control. + /// The control's size. + public static Size ApplyLayoutConstraints(ILayoutable control, Size constraints) + { + double width = (control.Width > 0) ? control.Width : constraints.Width; + double height = (control.Height > 0) ? control.Height : constraints.Height; + width = Math.Min(width, control.MaxWidth); + width = Math.Max(width, control.MinWidth); + height = Math.Min(height, control.MaxHeight); + height = Math.Max(height, control.MinHeight); + return new Size(width, height); + } + } +} diff --git a/src/Avalonia.Layout/LayoutManager.cs b/src/Avalonia.Layout/LayoutManager.cs new file mode 100644 index 0000000000..42ed45b0bb --- /dev/null +++ b/src/Avalonia.Layout/LayoutManager.cs @@ -0,0 +1,161 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using Avalonia.Logging; +using Avalonia.Threading; + +namespace Avalonia.Layout +{ + /// + /// Manages measuring and arranging of controls. + /// + public class LayoutManager : ILayoutManager + { + private readonly Queue _toMeasure = new Queue(); + private readonly Queue _toArrange = new Queue(); + private bool _queued; + private bool _running; + + /// + /// Gets the layout manager. + /// + public static ILayoutManager Instance => AvaloniaLocator.Current.GetService(); + + /// + public void InvalidateMeasure(ILayoutable control) + { + Contract.Requires(control != null); + Dispatcher.UIThread.VerifyAccess(); + + _toMeasure.Enqueue(control); + _toArrange.Enqueue(control); + QueueLayoutPass(); + } + + /// + public void InvalidateArrange(ILayoutable control) + { + Contract.Requires(control != null); + Dispatcher.UIThread.VerifyAccess(); + + _toArrange.Enqueue(control); + QueueLayoutPass(); + } + + /// + public void ExecuteLayoutPass() + { + const int MaxPasses = 3; + + Dispatcher.UIThread.VerifyAccess(); + + if (!_running) + { + _running = true; + + Logger.Information( + LogArea.Layout, + this, + "Started layout pass. To measure: {Measure} To arrange: {Arrange}", + _toMeasure.Count, + _toArrange.Count); + + var stopwatch = new System.Diagnostics.Stopwatch(); + stopwatch.Start(); + + try + { + for (var pass = 0; pass < MaxPasses; ++pass) + { + ExecuteMeasurePass(); + ExecuteArrangePass(); + + if (_toMeasure.Count == 0) + { + break; + } + } + } + finally + { + _running = false; + } + + stopwatch.Stop(); + Logger.Information(LogArea.Layout, this, "Layout pass finised in {Time}", stopwatch.Elapsed); + } + + _queued = false; + } + + /// + public void ExecuteInitialLayoutPass(ILayoutRoot root) + { + Measure(root); + Arrange(root); + + // Running the initial layout pass may have caused some control to be invalidated + // so run a full layout pass now (this usually due to scrollbars; its not known + // whether they will need to be shown until the layout pass has run and if the + // first guess was incorrect the layout will need to be updated). + ExecuteLayoutPass(); + } + + private void ExecuteMeasurePass() + { + while (_toMeasure.Count > 0) + { + var next = _toMeasure.Dequeue(); + Measure(next); + } + } + + private void ExecuteArrangePass() + { + while (_toArrange.Count > 0 && _toMeasure.Count == 0) + { + var next = _toArrange.Dequeue(); + Arrange(next); + } + } + + private void Measure(ILayoutable control) + { + var root = control as ILayoutRoot; + + if (root != null) + { + root.Measure(root.MaxClientSize); + } + else if (control.PreviousMeasure.HasValue) + { + control.Measure(control.PreviousMeasure.Value); + } + } + + private void Arrange(ILayoutable control) + { + var root = control as ILayoutRoot; + + if (root != null) + { + root.Arrange(new Rect(root.DesiredSize)); + } + else if (control.PreviousArrange.HasValue) + { + control.Arrange(control.PreviousArrange.Value); + } + } + + private void QueueLayoutPass() + { + if (!_queued) + { + Dispatcher.UIThread.InvokeAsync(ExecuteLayoutPass, DispatcherPriority.Render); + _queued = true; + } + } + } +} diff --git a/src/Avalonia.Layout/Layoutable.cs b/src/Avalonia.Layout/Layoutable.cs new file mode 100644 index 0000000000..91c230b877 --- /dev/null +++ b/src/Avalonia.Layout/Layoutable.cs @@ -0,0 +1,676 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Linq; +using Avalonia.Logging; +using Avalonia.Platform; +using Avalonia.VisualTree; + +namespace Avalonia.Layout +{ + /// + /// Defines how a control aligns itself horizontally in its parent control. + /// + public enum HorizontalAlignment + { + /// + /// The control stretches to fill the width of the parent control. + /// + Stretch, + + /// + /// The control aligns itself to the left of the parent control. + /// + Left, + + /// + /// The control centers itself in the parent control. + /// + Center, + + /// + /// The control aligns itself to the right of the parent control. + /// + Right, + } + + /// + /// Defines how a control aligns itself vertically in its parent control. + /// + public enum VerticalAlignment + { + /// + /// The control stretches to fill the height of the parent control. + /// + Stretch, + + /// + /// The control aligns itself to the top of the parent control. + /// + Top, + + /// + /// The control centers itself within the parent control. + /// + Center, + + /// + /// The control aligns itself to the bottom of the parent control. + /// + Bottom, + } + + /// + /// Implements layout-related functionality for a control. + /// + public class Layoutable : Visual, ILayoutable + { + /// + /// Defines the property. + /// + public static readonly DirectProperty DesiredSizeProperty = + AvaloniaProperty.RegisterDirect(nameof(DesiredSize), o => o.DesiredSize); + + /// + /// Defines the property. + /// + public static readonly StyledProperty WidthProperty = + AvaloniaProperty.Register(nameof(Width), double.NaN); + + /// + /// Defines the property. + /// + public static readonly StyledProperty HeightProperty = + AvaloniaProperty.Register(nameof(Height), double.NaN); + + /// + /// Defines the property. + /// + public static readonly StyledProperty MinWidthProperty = + AvaloniaProperty.Register(nameof(MinWidth)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty MaxWidthProperty = + AvaloniaProperty.Register(nameof(MaxWidth), double.PositiveInfinity); + + /// + /// Defines the property. + /// + public static readonly StyledProperty MinHeightProperty = + AvaloniaProperty.Register(nameof(MinHeight)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty MaxHeightProperty = + AvaloniaProperty.Register(nameof(MaxHeight), double.PositiveInfinity); + + /// + /// Defines the property. + /// + public static readonly StyledProperty MarginProperty = + AvaloniaProperty.Register(nameof(Margin)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty HorizontalAlignmentProperty = + AvaloniaProperty.Register(nameof(HorizontalAlignment)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty VerticalAlignmentProperty = + AvaloniaProperty.Register(nameof(VerticalAlignment)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty UseLayoutRoundingProperty = + AvaloniaProperty.Register(nameof(UseLayoutRounding), defaultValue: true, inherits: true); + + private bool _measuring; + private Size? _previousMeasure; + private Rect? _previousArrange; + + /// + /// Initializes static members of the class. + /// + static Layoutable() + { + AffectsMeasure( + IsVisibleProperty, + WidthProperty, + HeightProperty, + MinWidthProperty, + MaxWidthProperty, + MinHeightProperty, + MaxHeightProperty, + MarginProperty, + HorizontalAlignmentProperty, + VerticalAlignmentProperty); + } + + /// + /// Gets or sets the width of the element. + /// + public double Width + { + get { return GetValue(WidthProperty); } + set { SetValue(WidthProperty, value); } + } + + /// + /// Gets or sets the height of the element. + /// + public double Height + { + get { return GetValue(HeightProperty); } + set { SetValue(HeightProperty, value); } + } + + /// + /// Gets or sets the minimum width of the element. + /// + public double MinWidth + { + get { return GetValue(MinWidthProperty); } + set { SetValue(MinWidthProperty, value); } + } + + /// + /// Gets or sets the maximum width of the element. + /// + public double MaxWidth + { + get { return GetValue(MaxWidthProperty); } + set { SetValue(MaxWidthProperty, value); } + } + + /// + /// Gets or sets the minimum height of the element. + /// + public double MinHeight + { + get { return GetValue(MinHeightProperty); } + set { SetValue(MinHeightProperty, value); } + } + + /// + /// Gets or sets the maximum height of the element. + /// + public double MaxHeight + { + get { return GetValue(MaxHeightProperty); } + set { SetValue(MaxHeightProperty, value); } + } + + /// + /// Gets or sets the margin around the element. + /// + public Thickness Margin + { + get { return GetValue(MarginProperty); } + set { SetValue(MarginProperty, value); } + } + + /// + /// Gets or sets the element's preferred horizontal alignment in its parent. + /// + public HorizontalAlignment HorizontalAlignment + { + get { return GetValue(HorizontalAlignmentProperty); } + set { SetValue(HorizontalAlignmentProperty, value); } + } + + /// + /// Gets or sets the element's preferred vertical alignment in its parent. + /// + public VerticalAlignment VerticalAlignment + { + get { return GetValue(VerticalAlignmentProperty); } + set { SetValue(VerticalAlignmentProperty, value); } + } + + /// + /// Gets the size that this element computed during the measure pass of the layout process. + /// + public Size DesiredSize + { + get; + private set; + } + + /// + /// Gets a value indicating whether the control's layout measure is valid. + /// + public bool IsMeasureValid + { + get; + private set; + } + + /// + /// Gets a value indicating whether the control's layouts arrange is valid. + /// + public bool IsArrangeValid + { + get; + private set; + } + + /// + /// Gets or sets a value that determines whether the element should be snapped to pixel + /// boundaries at layout time. + /// + public bool UseLayoutRounding + { + get { return GetValue(UseLayoutRoundingProperty); } + set { SetValue(UseLayoutRoundingProperty, value); } + } + + /// + /// Gets the available size passed in the previous layout pass, if any. + /// + Size? ILayoutable.PreviousMeasure => _previousMeasure; + + /// + /// Gets the layout rect passed in the previous layout pass, if any. + /// + Rect? ILayoutable.PreviousArrange => _previousArrange; + + /// + /// Creates the visual children of the control, if necessary + /// + public virtual void ApplyTemplate() + { + } + + /// + /// Carries out a measure of the control. + /// + /// The available size for the control. + public void Measure(Size availableSize) + { + if (double.IsNaN(availableSize.Width) || double.IsNaN(availableSize.Height)) + { + throw new InvalidOperationException("Cannot call Measure using a size with NaN values."); + } + + if (!IsMeasureValid || _previousMeasure != availableSize) + { + var previousDesiredSize = DesiredSize; + var desiredSize = default(Size); + + IsMeasureValid = true; + + try + { + _measuring = true; + desiredSize = MeasureCore(availableSize).Constrain(availableSize); + } + finally + { + _measuring = false; + } + + if (IsInvalidSize(desiredSize)) + { + throw new InvalidOperationException("Invalid size returned for Measure."); + } + + DesiredSize = desiredSize; + _previousMeasure = availableSize; + + Logger.Verbose(LogArea.Layout, this, "Measure requested {DesiredSize}", DesiredSize); + + if (DesiredSize != previousDesiredSize) + { + this.GetVisualParent()?.ChildDesiredSizeChanged(this); + } + } + } + + /// + /// Arranges the control and its children. + /// + /// The control's new bounds. + public void Arrange(Rect rect) + { + if (IsInvalidRect(rect)) + { + throw new InvalidOperationException("Invalid Arrange rectangle."); + } + + if (!IsMeasureValid) + { + Measure(_previousMeasure ?? rect.Size); + } + + if (!IsArrangeValid || _previousArrange != rect) + { + Logger.Verbose(LogArea.Layout, this, "Arrange to {Rect} ", rect); + + IsArrangeValid = true; + ArrangeCore(rect); + _previousArrange = rect; + } + } + + /// + /// Invalidates the measurement of the control and queues a new layout pass. + /// + public void InvalidateMeasure() + { + if (IsMeasureValid) + { + Logger.Verbose(LogArea.Layout, this, "Invalidated measure"); + + IsMeasureValid = false; + IsArrangeValid = false; + LayoutManager.Instance?.InvalidateMeasure(this); + InvalidateVisual(); + } + } + + /// + /// Invalidates the arrangement of the control and queues a new layout pass. + /// + public void InvalidateArrange() + { + if (IsArrangeValid) + { + Logger.Verbose(LogArea.Layout, this, "Invalidated arrange"); + + IsArrangeValid = false; + LayoutManager.Instance?.InvalidateArrange(this); + InvalidateVisual(); + } + } + + /// + void ILayoutable.ChildDesiredSizeChanged(ILayoutable control) + { + if (!_measuring) + { + InvalidateMeasure(); + } + } + + /// + /// Marks a property as affecting the control's measurement. + /// + /// The properties. + /// + /// After a call to this method in a control's static constructor, any change to the + /// property will cause to be called on the element. + /// + protected static void AffectsMeasure(params AvaloniaProperty[] properties) + { + foreach (var property in properties) + { + property.Changed.Subscribe(AffectsMeasureInvalidate); + } + } + + /// + /// Marks a property as affecting the control's arrangement. + /// + /// The properties. + /// + /// After a call to this method in a control's static constructor, any change to the + /// property will cause to be called on the element. + /// + protected static void AffectsArrange(params AvaloniaProperty[] properties) + { + foreach (var property in properties) + { + property.Changed.Subscribe(AffectsArrangeInvalidate); + } + } + + /// + /// The default implementation of the control's measure pass. + /// + /// The size available to the control. + /// The desired size for the control. + /// + /// This method calls which is probably the method you + /// want to override in order to modify a control's arrangement. + /// + protected virtual Size MeasureCore(Size availableSize) + { + if (IsVisible) + { + var margin = Margin; + + ApplyTemplate(); + + var constrained = LayoutHelper + .ApplyLayoutConstraints(this, availableSize) + .Deflate(margin); + + var measured = MeasureOverride(constrained); + + var width = measured.Width; + var height = measured.Height; + + if (!double.IsNaN(Width)) + { + width = Width; + } + + width = Math.Min(width, MaxWidth); + width = Math.Max(width, MinWidth); + + if (!double.IsNaN(Height)) + { + height = Height; + } + + height = Math.Min(height, MaxHeight); + height = Math.Max(height, MinHeight); + + if (UseLayoutRounding) + { + var scale = GetLayoutScale(); + width = Math.Ceiling(width * scale) / scale; + height = Math.Ceiling(height * scale) / scale; + } + + return NonNegative(new Size(width, height).Inflate(margin)); + } + else + { + return new Size(); + } + } + + /// + /// Measures the control and its child elements as part of a layout pass. + /// + /// The size available to the control. + /// The desired size for the control. + protected virtual Size MeasureOverride(Size availableSize) + { + double width = 0; + double height = 0; + + foreach (ILayoutable child in this.GetVisualChildren()) + { + child.Measure(availableSize); + width = Math.Max(width, child.DesiredSize.Width); + height = Math.Max(height, child.DesiredSize.Height); + } + + return new Size(width, height); + } + + /// + /// The default implementation of the control's arrange pass. + /// + /// The control's new bounds. + /// + /// This method calls which is probably the method you + /// want to override in order to modify a control's arrangement. + /// + protected virtual void ArrangeCore(Rect finalRect) + { + if (IsVisible) + { + var margin = Margin; + var originX = finalRect.X + margin.Left; + var originY = finalRect.Y + margin.Top; + var availableSizeMinusMargins = new Size( + Math.Max(0, finalRect.Width - margin.Left - margin.Right), + Math.Max(0, finalRect.Height - margin.Top - margin.Bottom)); + var horizontalAlignment = HorizontalAlignment; + var verticalAlignment = VerticalAlignment; + var size = availableSizeMinusMargins; + var scale = GetLayoutScale(); + + if (horizontalAlignment != HorizontalAlignment.Stretch) + { + size = size.WithWidth(Math.Min(size.Width, DesiredSize.Width - margin.Left - margin.Right)); + } + + if (verticalAlignment != VerticalAlignment.Stretch) + { + size = size.WithHeight(Math.Min(size.Height, DesiredSize.Height - margin.Top - margin.Bottom)); + } + + size = LayoutHelper.ApplyLayoutConstraints(this, size); + + if (UseLayoutRounding) + { + size = new Size( + Math.Ceiling(size.Width * scale) / scale, + Math.Ceiling(size.Height * scale) / scale); + availableSizeMinusMargins = new Size( + Math.Ceiling(availableSizeMinusMargins.Width * scale) / scale, + Math.Ceiling(availableSizeMinusMargins.Height * scale) / scale); + } + + size = ArrangeOverride(size).Constrain(size); + + switch (horizontalAlignment) + { + case HorizontalAlignment.Center: + case HorizontalAlignment.Stretch: + originX += (availableSizeMinusMargins.Width - size.Width) / 2; + break; + case HorizontalAlignment.Right: + originX += availableSizeMinusMargins.Width - size.Width; + break; + } + + switch (verticalAlignment) + { + case VerticalAlignment.Center: + case VerticalAlignment.Stretch: + originY += (availableSizeMinusMargins.Height - size.Height) / 2; + break; + case VerticalAlignment.Bottom: + originY += availableSizeMinusMargins.Height - size.Height; + break; + } + + if (UseLayoutRounding) + { + originX = Math.Floor(originX * scale) / scale; + originY = Math.Floor(originY * scale) / scale; + } + + Bounds = new Rect(originX, originY, size.Width, size.Height); + } + } + + /// + /// Positions child elements as part of a layout pass. + /// + /// The size available to the control. + /// The actual size used. + protected virtual Size ArrangeOverride(Size finalSize) + { + foreach (ILayoutable child in this.GetVisualChildren().OfType()) + { + child.Arrange(new Rect(finalSize)); + } + + return finalSize; + } + + /// + /// Calls on the control on which a property changed. + /// + /// The event args. + private static void AffectsMeasureInvalidate(AvaloniaPropertyChangedEventArgs e) + { + ILayoutable control = e.Sender as ILayoutable; + control?.InvalidateMeasure(); + } + + /// + /// Calls on the control on which a property changed. + /// + /// The event args. + private static void AffectsArrangeInvalidate(AvaloniaPropertyChangedEventArgs e) + { + ILayoutable control = e.Sender as ILayoutable; + control?.InvalidateArrange(); + } + + /// + /// Tests whether any of a 's properties incude nagative values, + /// a NaN or Infinity. + /// + /// The rect. + /// True if the rect is invalid; otherwise false. + private static bool IsInvalidRect(Rect rect) + { + return rect.Width < 0 || rect.Height < 0 || + double.IsInfinity(rect.X) || double.IsInfinity(rect.Y) || + double.IsInfinity(rect.Width) || double.IsInfinity(rect.Height) || + double.IsNaN(rect.X) || double.IsNaN(rect.Y) || + double.IsNaN(rect.Width) || double.IsNaN(rect.Height); + } + + /// + /// Tests whether any of a 's properties incude nagative values, + /// a NaN or Infinity. + /// + /// The size. + /// True if the size is invalid; otherwise false. + private static bool IsInvalidSize(Size size) + { + return size.Width < 0 || size.Height < 0 || + double.IsInfinity(size.Width) || double.IsInfinity(size.Height) || + double.IsNaN(size.Width) || double.IsNaN(size.Height); + } + + /// + /// Ensures neither component of a is negative. + /// + /// The size. + /// The non-negative size. + private static Size NonNegative(Size size) + { + return new Size(Math.Max(size.Width, 0), Math.Max(size.Height, 0)); + } + + private double GetLayoutScale() + { + var result = (VisualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0; + + if (result == 0 || double.IsNaN(result) || double.IsInfinity(result)) + { + throw new Exception($"Invalid LayoutScaling returned from {VisualRoot.GetType()}"); + } + + return result; + } + } +} diff --git a/src/Avalonia.Layout/Properties/AssemblyInfo.cs b/src/Avalonia.Layout/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..126893e189 --- /dev/null +++ b/src/Avalonia.Layout/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; + +[assembly: AssemblyTitle("Avalonia.Layout")] diff --git a/src/Perspex.Layout/app.config b/src/Avalonia.Layout/app.config similarity index 100% rename from src/Perspex.Layout/app.config rename to src/Avalonia.Layout/app.config diff --git a/src/Perspex.Layout/packages.config b/src/Avalonia.Layout/packages.config similarity index 100% rename from src/Perspex.Layout/packages.config rename to src/Avalonia.Layout/packages.config diff --git a/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj b/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj new file mode 100644 index 0000000000..e6490d16f4 --- /dev/null +++ b/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj @@ -0,0 +1,65 @@ + + + + + 10.0 + Debug + AnyCPU + {B61B66A3-B82D-4875-8001-89D3394FE0C9} + Library + Properties + Avalonia.Logging.Serilog + Avalonia.Logging.Serilog + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Avalonia.Logging.Serilog.XML + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Avalonia.Logging.Serilog.XML + + + + + + + + ..\..\packages\Serilog.1.5.14\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Serilog.dll + True + + + + + + + + {b09b78d8-9b26-48b0-9149-d64a2f120f3f} + Avalonia.Base + + + + + \ No newline at end of file diff --git a/src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs b/src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..64c0eaffae --- /dev/null +++ b/src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +using System.Resources; +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("Avalonia.Serilog")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Avalonia.Serilog")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// 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")] diff --git a/src/Avalonia.Logging.Serilog/SerilogLogger.cs b/src/Avalonia.Logging.Serilog/SerilogLogger.cs new file mode 100644 index 0000000000..460469394e --- /dev/null +++ b/src/Avalonia.Logging.Serilog/SerilogLogger.cs @@ -0,0 +1,44 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Collections.Generic; +using Serilog; +using AvaloniaLogEventLevel = Avalonia.Logging.LogEventLevel; +using SerilogLogEventLevel = Serilog.Events.LogEventLevel; + +namespace Avalonia.Logging.Serilog +{ + public class SerilogLogger : ILogSink + { + private readonly ILogger _output; + private readonly Dictionary _areas = new Dictionary(); + + public SerilogLogger(ILogger output) + { + _output = output; + } + + public static void Initialize(ILogger output) + { + Logger.Sink = new SerilogLogger(output); + } + + public void Log( + AvaloniaLogEventLevel level, + string area, + object source, + string messageTemplate, + params object[] propertyValues) + { + ILogger areaLogger; + + if (!_areas.TryGetValue(area, out areaLogger)) + { + areaLogger = _output.ForContext("Area", area); + _areas.Add(area, areaLogger); + } + + areaLogger.Write((SerilogLogEventLevel)level, messageTemplate, propertyValues); + } + } +} diff --git a/src/Perspex.Logging.Serilog/packages.config b/src/Avalonia.Logging.Serilog/packages.config similarity index 100% rename from src/Perspex.Logging.Serilog/packages.config rename to src/Avalonia.Logging.Serilog/packages.config diff --git a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj new file mode 100644 index 0000000000..181c99e975 --- /dev/null +++ b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj @@ -0,0 +1,114 @@ + + + + + 10.0 + Debug + AnyCPU + {6417B24E-49C2-4985-8DB2-3AB9D898EC91} + Library + Properties + Avalonia.ReactiveUI + Avalonia.ReactiveUI + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile259 + v4.5 + + + true + full + false + bin\Debug\ + TRACE;DEBUG;MONO PORTABLE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE;MONO PORTABLE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + ..\..\packages\Splat.1.6.2\lib\Portable-net45+win+wpa81+wp80\Splat.dll + + + ..\..\packages\Rx-Core.2.2.5\lib\portable-net45+winrt45+wp8+wpa81\System.Reactive.Core.dll + + + ..\..\packages\Rx-Interfaces.2.2.5\lib\portable-net45+winrt45+wp8+wpa81\System.Reactive.Interfaces.dll + + + ..\..\packages\Rx-Linq.2.2.5\lib\portable-net45+winrt45+wp8+wpa81\System.Reactive.Linq.dll + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs b/src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..358c6224fb --- /dev/null +++ b/src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Resources; +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("Avalonia.ReactiveUI")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Avalonia.ReactiveUI")] +[assembly: AssemblyCopyright("Copyright \u00A9 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// 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")] diff --git a/src/Avalonia.ReactiveUI/Registrations.cs b/src/Avalonia.ReactiveUI/Registrations.cs new file mode 100644 index 0000000000..066aa46dc1 --- /dev/null +++ b/src/Avalonia.ReactiveUI/Registrations.cs @@ -0,0 +1,23 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Concurrency; +using System.Threading; + + +namespace ReactiveUI +{ + /// + /// Ignore me. This class is a secret handshake between RxUI and RxUI.Xaml + /// in order to register certain classes on startup that would be difficult + /// to register otherwise. + /// + public class PlatformRegistrations : IWantsToRegisterStuff + { + public void Register(Action, Type> registerFunction) + { + RxApp.MainThreadScheduler = new SynchronizationContextScheduler(SynchronizationContext.Current); + } + } +} diff --git a/src/Perspex.ReactiveUI/packages.config b/src/Avalonia.ReactiveUI/packages.config similarity index 100% rename from src/Perspex.ReactiveUI/packages.config rename to src/Avalonia.ReactiveUI/packages.config diff --git a/src/Perspex.ReactiveUI/src b/src/Avalonia.ReactiveUI/src similarity index 100% rename from src/Perspex.ReactiveUI/src rename to src/Avalonia.ReactiveUI/src diff --git a/src/Avalonia.SceneGraph/Animation/CrossFade.cs b/src/Avalonia.SceneGraph/Animation/CrossFade.cs new file mode 100644 index 0000000000..8acf6582bb --- /dev/null +++ b/src/Avalonia.SceneGraph/Animation/CrossFade.cs @@ -0,0 +1,118 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Reactive.Threading.Tasks; +using System.Threading.Tasks; +using Avalonia.VisualTree; + +namespace Avalonia.Animation +{ + /// + /// Defines a cross-fade animation between two s. + /// + public class CrossFade : IPageTransition + { + /// + /// Initializes a new instance of the class. + /// + public CrossFade() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The duration of the animation. + public CrossFade(TimeSpan duration) + { + Duration = duration; + } + + /// + /// Gets the duration of the animation. + /// + public TimeSpan Duration { get; set; } + + /// + /// Starts the animation. + /// + /// + /// The control that is being transitioned away from. May be null. + /// + /// + /// The control that is being transitioned to. May be null. + /// + /// + /// A that tracks the progress of the animation. + /// + public async Task Start(IVisual from, IVisual to) + { + var tasks = new List(); + + if (to != null) + { + to.Opacity = 0; + } + + if (from != null) + { + tasks.Add(Animate.Property( + (IAvaloniaObject)from, + Visual.OpacityProperty, + from.Opacity, + 0, + LinearEasing.For(), + Duration).ToTask()); + } + + if (to != null) + { + to.Opacity = 0; + to.IsVisible = true; + + tasks.Add(Animate.Property( + (IAvaloniaObject)to, + Visual.OpacityProperty, + 0, + 1, + LinearEasing.For(), + Duration).ToTask()); + } + + await Task.WhenAll(tasks.ToArray()); + + if (from != null) + { + from.IsVisible = false; + from.Opacity = 1; + } + + if (to != null) + { + to.Opacity = 1; + } + } + + /// + /// Starts the animation. + /// + /// + /// The control that is being transitioned away from. May be null. + /// + /// + /// The control that is being transitioned to. May be null. + /// + /// + /// Unused for cross-fades. + /// + /// + /// A that tracks the progress of the animation. + /// + Task IPageTransition.Start(IVisual from, IVisual to, bool forward) + { + return Start(from, to); + } + } +} diff --git a/src/Avalonia.SceneGraph/Animation/IPageTransition.cs b/src/Avalonia.SceneGraph/Animation/IPageTransition.cs new file mode 100644 index 0000000000..6dc64de049 --- /dev/null +++ b/src/Avalonia.SceneGraph/Animation/IPageTransition.cs @@ -0,0 +1,31 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Threading.Tasks; +using Avalonia.VisualTree; + +namespace Avalonia.Animation +{ + /// + /// Interface for animations that transition between two pages. + /// + public interface IPageTransition + { + /// + /// Starts the animation. + /// + /// + /// The control that is being transitioned away from. May be null. + /// + /// + /// The control that is being transitioned to. May be null. + /// + /// + /// If the animation is bidirectional, controls the direction of the animation. + /// + /// + /// A that tracks the progress of the animation. + /// + Task Start(IVisual from, IVisual to, bool forward); + } +} diff --git a/src/Avalonia.SceneGraph/Animation/PageSlide.cs b/src/Avalonia.SceneGraph/Animation/PageSlide.cs new file mode 100644 index 0000000000..015f22ec14 --- /dev/null +++ b/src/Avalonia.SceneGraph/Animation/PageSlide.cs @@ -0,0 +1,120 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Reactive.Threading.Tasks; +using System.Threading.Tasks; +using Avalonia.Media; +using Avalonia.VisualTree; + +namespace Avalonia.Animation +{ + /// + /// Transitions between two pages by sliding them horizontally. + /// + public class PageSlide : IPageTransition + { + /// + /// Initializes a new instance of the class. + /// + public PageSlide() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The duration of the animation. + public PageSlide(TimeSpan duration) + { + Duration = duration; + } + + /// + /// Gets the duration of the animation. + /// + public TimeSpan Duration { get; set; } + + /// + /// Starts the animation. + /// + /// + /// The control that is being transitioned away from. May be null. + /// + /// + /// The control that is being transitioned to. May be null. + /// + /// + /// If true, the new page is slid in from the right, or if false from the left. + /// + /// + /// A that tracks the progress of the animation. + /// + public async Task Start(IVisual from, IVisual to, bool forward) + { + var tasks = new List(); + var parent = GetVisualParent(from, to); + var distance = parent.Bounds.Width; + + if (from != null) + { + var transform = new TranslateTransform(); + from.RenderTransform = transform; + tasks.Add(Animate.Property( + transform, + TranslateTransform.XProperty, + 0.0, + forward ? -distance : distance, + LinearEasing.For(), + Duration).ToTask()); + } + + if (to != null) + { + var transform = new TranslateTransform(); + to.RenderTransform = transform; + to.IsVisible = true; + tasks.Add(Animate.Property( + transform, + TranslateTransform.XProperty, + forward ? distance : -distance, + 0.0, + LinearEasing.For(), + Duration).ToTask()); + } + + await Task.WhenAll(tasks.ToArray()); + + if (from != null) + { + from.IsVisible = false; + } + } + + /// + /// Gets the common visual parent of the two control. + /// + /// The from control. + /// The to control. + /// The common parent. + /// + /// The two controls do not share a common parent. + /// + /// + /// Any one of the parameters may be null, but not both. + /// + private static IVisual GetVisualParent(IVisual from, IVisual to) + { + var p1 = (from ?? to).VisualParent; + var p2 = (to ?? from).VisualParent; + + if (p1 != null && p2 != null && p1 != p2) + { + throw new ArgumentException("Controls for PageSlide must have same parent."); + } + + return p1; + } + } +} diff --git a/src/Avalonia.SceneGraph/Avalonia.SceneGraph.csproj b/src/Avalonia.SceneGraph/Avalonia.SceneGraph.csproj new file mode 100644 index 0000000000..681f53f8fc --- /dev/null +++ b/src/Avalonia.SceneGraph/Avalonia.SceneGraph.csproj @@ -0,0 +1,179 @@ + + + + + 11.0 + Debug + AnyCPU + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Library + Properties + Avalonia + Avalonia.SceneGraph + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Avalonia.SceneGraph.XML + CS1591 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Avalonia.SceneGraph.XML + CS1591 + + + + + {D211E587-D8BC-45B9-95A4-F297C8FA5200} + Avalonia.Animation + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll + + + ..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll + + + ..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll + + + ..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/INamed.cs b/src/Avalonia.SceneGraph/INamed.cs new file mode 100644 index 0000000000..21bd233e41 --- /dev/null +++ b/src/Avalonia.SceneGraph/INamed.cs @@ -0,0 +1,16 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia +{ + /// + /// Interface for named elements. + /// + public interface INamed + { + /// + /// Gets the element name. + /// + string Name { get; } + } +} diff --git a/src/Avalonia.SceneGraph/Matrix.cs b/src/Avalonia.SceneGraph/Matrix.cs new file mode 100644 index 0000000000..8812000bdc --- /dev/null +++ b/src/Avalonia.SceneGraph/Matrix.cs @@ -0,0 +1,299 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; + +namespace Avalonia +{ + /// + /// A 2x3 matrix. + /// + public struct Matrix + { + private readonly double _m11; + private readonly double _m12; + private readonly double _m21; + private readonly double _m22; + private readonly double _m31; + private readonly double _m32; + + /// + /// Initializes a new instance of the struct. + /// + /// The first element of the first row. + /// The second element of the first row. + /// The first element of the second row. + /// The second element of the second row. + /// The first element of the third row. + /// The second element of the third row. + public Matrix( + double m11, + double m12, + double m21, + double m22, + double offsetX, + double offsetY) + { + _m11 = m11; + _m12 = m12; + _m21 = m21; + _m22 = m22; + _m31 = offsetX; + _m32 = offsetY; + } + + /// + /// Returns the multiplicative identity matrix. + /// + public static Matrix Identity => new Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); + + /// + /// Returns whether the matrix is the identity matrix. + /// + public bool IsIdentity => Equals(Identity); + + /// + /// HasInverse Property - returns true if this matrix is invertable, false otherwise. + /// + public bool HasInverse => GetDeterminant() != 0; + + /// + /// The first element of the first row + /// + public double M11 => _m11; + + /// + /// The second element of the first row + /// + public double M12 => _m12; + + /// + /// The first element of the second row + /// + public double M21 => _m21; + + /// + /// The second element of the second row + /// + public double M22 => _m22; + + /// + /// The first element of the third row + /// + public double M31 => _m31; + + /// + /// The second element of the third row + /// + public double M32 => _m32; + + /// + /// Multiplies two matrices together and returns the resulting matrix. + /// + /// The first source matrix. + /// The second source matrix. + /// The product matrix. + public static Matrix operator *(Matrix value1, Matrix value2) + { + return new Matrix( + (value1.M11 * value2.M11) + (value1.M12 * value2.M21), + (value1.M11 * value2.M12) + (value1.M12 * value2.M22), + (value1.M21 * value2.M11) + (value1.M22 * value2.M21), + (value1.M21 * value2.M12) + (value1.M22 * value2.M22), + (value1._m31 * value2.M11) + (value1._m32 * value2.M21) + value2._m31, + (value1._m31 * value2.M12) + (value1._m32 * value2.M22) + value2._m32); + } + + /// + /// Negates the given matrix by multiplying all values by -1. + /// + /// The source matrix. + /// The negated matrix. + public static Matrix operator -(Matrix value) + { + return value.Invert(); + } + + /// + /// Returns a boolean indicating whether the given matrices are equal. + /// + /// The first source matrix. + /// The second source matrix. + /// True if the matrices are equal; False otherwise. + public static bool operator ==(Matrix value1, Matrix value2) + { + return value1.Equals(value2); + } + + /// + /// Returns a boolean indicating whether the given matrices are not equal. + /// + /// The first source matrix. + /// The second source matrix. + /// True if the matrices are not equal; False if they are equal. + public static bool operator !=(Matrix value1, Matrix value2) + { + return !value1.Equals(value2); + } + + /// + /// Creates a rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// A rotation matrix. + public static Matrix CreateRotation(double radians) + { + double cos = Math.Cos(radians); + double sin = Math.Sin(radians); + return new Matrix(cos, sin, -sin, cos, 0, 0); + } + + /// + /// Creates a scale matrix from the given X and Y components. + /// + /// Value to scale by on the X-axis. + /// Value to scale by on the Y-axis. + /// A scaling matrix. + public static Matrix CreateScale(double xScale, double yScale) + { + return CreateScale(new Vector(xScale, yScale)); + } + + /// + /// Creates a scale matrix from the given vector scale. + /// + /// The scale to use. + /// A scaling matrix. + public static Matrix CreateScale(Vector scales) + { + return new Matrix(scales.X, 0, 0, scales.Y, 0, 0); + } + + /// + /// Creates a translation matrix from the given vector. + /// + /// The translation position. + /// A translation matrix. + public static Matrix CreateTranslation(Vector position) + { + return CreateTranslation(position.X, position.Y); + } + + /// + /// Creates a translation matrix from the given X and Y components. + /// + /// The X position. + /// The Y position. + /// A translation matrix. + public static Matrix CreateTranslation(double xPosition, double yPosition) + { + return new Matrix(1.0, 0.0, 0.0, 1.0, xPosition, yPosition); + } + + /// + /// Converts an ange in degrees to radians. + /// + /// The angle in degrees. + /// The angle in radians. + public static double ToRadians(double angle) + { + return angle * 0.0174532925; + } + + /// + /// Calculates the determinant for this matrix. + /// + /// The determinant. + /// + /// The determinant is calculated by expanding the matrix with a third column whose + /// values are (0,0,1). + /// + public double GetDeterminant() + { + return (_m11 * _m22) - (_m12 * _m21); + } + + + /// + /// Returns a boolean indicating whether the matrix is equal to the other given matrix. + /// + /// The other matrix to test equality against. + /// True if this matrix is equal to other; False otherwise. + public bool Equals(Matrix other) + { + return _m11 == other.M11 && + _m12 == other.M12 && + _m21 == other.M21 && + _m22 == other.M22 && + _m31 == other.M31 && + _m32 == other.M32; + } + + /// + /// Returns a boolean indicating whether the given Object is equal to this matrix instance. + /// + /// The Object to compare against. + /// True if the Object is equal to this matrix; False otherwise. + public override bool Equals(object obj) + { + if (!(obj is Matrix)) + { + return false; + } + + return Equals((Matrix)obj); + } + + /// + /// Returns the hash code for this instance. + /// + /// The hash code. + public override int GetHashCode() + { + return M11.GetHashCode() + M12.GetHashCode() + + M21.GetHashCode() + M22.GetHashCode() + + M31.GetHashCode() + M32.GetHashCode(); + } + + /// + /// Returns a String representing this matrix instance. + /// + /// The string representation. + public override string ToString() + { + CultureInfo ci = CultureInfo.CurrentCulture; + return string.Format( + ci, + "{{ {{M11:{0} M12:{1}}} {{M21:{2} M22:{3}}} {{M31:{4} M32:{5}}} }}", + M11.ToString(ci), + M12.ToString(ci), + M21.ToString(ci), + M22.ToString(ci), + M31.ToString(ci), + M32.ToString(ci)); + } + + /// + /// Inverts the Matrix. + /// + /// The inverted matrix. + public Matrix Invert() + { + if (GetDeterminant() == 0) + { + throw new InvalidOperationException("Transform is not invertible."); + } + + double d = GetDeterminant(); + + return new Matrix( + _m22 / d, + -_m12 / d, + -_m21 / d, + _m11 / d, + ((_m21 * _m32) - (_m22 * _m31)) / d, + ((_m12 * _m31) - (_m11 * _m32)) / d); + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/AlignmentX.cs b/src/Avalonia.SceneGraph/Media/AlignmentX.cs new file mode 100644 index 0000000000..89bc1f6258 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/AlignmentX.cs @@ -0,0 +1,26 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Describes how content is positioned horizontally in a container. + /// + public enum AlignmentX + { + /// + /// The contents align themselves with the left of the container + /// + Left, + + /// + /// The contents align themselves with the center of the container + /// + Center, + + /// + /// The contents align themselves with the right of the container + /// + Right, + } +} diff --git a/src/Avalonia.SceneGraph/Media/AlignmentY.cs b/src/Avalonia.SceneGraph/Media/AlignmentY.cs new file mode 100644 index 0000000000..b05500e039 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/AlignmentY.cs @@ -0,0 +1,26 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Describes how content is positioned vertically in a container. + /// + public enum AlignmentY + { + /// + /// The contents align themselves with the top of the container + /// + Top, + + /// + /// The contents align themselves with the center of the container + /// + Center, + + /// + /// The contents align themselves with the bottom of the container + /// + Bottom, + } +} diff --git a/src/Avalonia.SceneGraph/Media/ArcSegment.cs b/src/Avalonia.SceneGraph/Media/ArcSegment.cs new file mode 100644 index 0000000000..0e9c4548a4 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/ArcSegment.cs @@ -0,0 +1,103 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + public sealed class ArcSegment : PathSegment + { + /// + /// Defines the property. + /// + public static readonly StyledProperty IsLargeArcProperty + = AvaloniaProperty.Register(nameof(IsLargeArc), false); + + /// + /// Defines the property. + /// + public static readonly StyledProperty PointProperty + = AvaloniaProperty.Register(nameof(Point)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty RotationAngleProperty + = AvaloniaProperty.Register(nameof(RotationAngle), 0); + + /// + /// Defines the property. + /// + public static readonly StyledProperty SizeProperty + = AvaloniaProperty.Register(nameof(Size)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty SweepDirectionProperty + = AvaloniaProperty.Register(nameof(SweepDirection), SweepDirection.Clockwise); + + /// + /// Gets or sets a value indicating whether this instance is large arc. + /// + /// + /// true if this instance is large arc; otherwise, false. + /// + public bool IsLargeArc + { + get { return GetValue(IsLargeArcProperty); } + set { SetValue(IsLargeArcProperty, value); } + } + + /// + /// Gets or sets the point. + /// + /// + /// The point. + /// + public Point Point + { + get { return GetValue(PointProperty); } + set { SetValue(PointProperty, value); } + } + + /// + /// Gets or sets the rotation angle. + /// + /// + /// The rotation angle. + /// + public double RotationAngle + { + get { return GetValue(RotationAngleProperty); } + set { SetValue(RotationAngleProperty, value); } + } + + /// + /// Gets or sets the size. + /// + /// + /// The size. + /// + public Size Size + { + get { return GetValue(SizeProperty); } + set { SetValue(SizeProperty, value); } + } + + /// + /// Gets or sets the sweep direction. + /// + /// + /// The sweep direction. + /// + public SweepDirection SweepDirection + { + get { return GetValue(SweepDirectionProperty); } + set { SetValue(SweepDirectionProperty, value); } + } + + protected internal override void ApplyTo(StreamGeometryContext ctx) + { + ctx.ArcTo(Point, Size, RotationAngle, IsLargeArc, SweepDirection); + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/BezierSegment .cs b/src/Avalonia.SceneGraph/Media/BezierSegment .cs new file mode 100644 index 0000000000..8bea03bc23 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/BezierSegment .cs @@ -0,0 +1,65 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + public sealed class BezierSegment : PathSegment + { + /// + /// Defines the property. + /// + public static readonly StyledProperty Point1Property + = AvaloniaProperty.Register(nameof(Point1)); + /// + /// Defines the property. + /// + public static readonly StyledProperty Point2Property + = AvaloniaProperty.Register(nameof(Point2)); + /// + /// Defines the property. + /// + public static readonly StyledProperty Point3Property + = AvaloniaProperty.Register(nameof(Point3)); + + /// + /// Gets or sets the point1. + /// + /// + /// The point1. + /// + public Point Point1 + { + get { return GetValue(Point1Property); } + set { SetValue(Point1Property, value); } + } + + /// + /// Gets or sets the point2. + /// + /// + /// The point2. + /// + public Point Point2 + { + get { return GetValue(Point2Property); } + set { SetValue(Point2Property, value); } + } + + /// + /// Gets or sets the point3. + /// + /// + /// The point3. + /// + public Point Point3 + { + get { return GetValue(Point3Property); } + set { SetValue(Point3Property, value); } + } + + protected internal override void ApplyTo(StreamGeometryContext ctx) + { + ctx.CubicBezierTo(Point1, Point2, Point3); + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/Brush.cs b/src/Avalonia.SceneGraph/Media/Brush.cs new file mode 100644 index 0000000000..8d9ac02129 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Brush.cs @@ -0,0 +1,58 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Linq; +using System.Reflection; + +namespace Avalonia.Media +{ + /// + /// Describes how an area is painted. + /// + public abstract class Brush : AvaloniaObject, IBrush + { + /// + /// Defines the property. + /// + public static readonly StyledProperty OpacityProperty = + AvaloniaProperty.Register(nameof(Opacity), 1.0); + + /// + /// Gets or sets the opacity of the brush. + /// + public double Opacity + { + get { return GetValue(OpacityProperty); } + set { SetValue(OpacityProperty, value); } + } + + /// + /// Parses a brush string. + /// + /// The brush string. + /// The . + public static IBrush Parse(string s) + { + if (s[0] == '#') + { + return new SolidColorBrush(Color.Parse(s)); + } + else + { + var upper = s.ToUpperInvariant(); + var member = typeof(Brushes).GetTypeInfo().DeclaredProperties + .FirstOrDefault(x => x.Name.ToUpperInvariant() == upper); + + if (member != null) + { + return (IBrush)member.GetValue(null); + } + else + { + throw new FormatException($"Invalid brush string: '{s}'."); + } + } + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/BrushMappingMode.cs b/src/Avalonia.SceneGraph/Media/BrushMappingMode.cs new file mode 100644 index 0000000000..15fb9700ca --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/BrushMappingMode.cs @@ -0,0 +1,17 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Media +{ + public enum BrushMappingMode + { + Absolute, + RelativeToBoundingBox + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/Brushes.cs b/src/Avalonia.SceneGraph/Media/Brushes.cs new file mode 100644 index 0000000000..c57e1ad7cd --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Brushes.cs @@ -0,0 +1,864 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Predefined brushes. + /// + public static class Brushes + { + /// + /// Initializes static members of the class. + /// + static Brushes() + { + AliceBlue = new SolidColorBrush(Colors.AliceBlue); + AntiqueWhite = new SolidColorBrush(Colors.AntiqueWhite); + Aqua = new SolidColorBrush(Colors.Aqua); + Aquamarine = new SolidColorBrush(Colors.Aquamarine); + Azure = new SolidColorBrush(Colors.Azure); + Beige = new SolidColorBrush(Colors.Beige); + Bisque = new SolidColorBrush(Colors.Bisque); + Black = new SolidColorBrush(Colors.Black); + BlanchedAlmond = new SolidColorBrush(Colors.BlanchedAlmond); + Blue = new SolidColorBrush(Colors.Blue); + BlueViolet = new SolidColorBrush(Colors.BlueViolet); + Brown = new SolidColorBrush(Colors.Brown); + BurlyWood = new SolidColorBrush(Colors.BurlyWood); + CadetBlue = new SolidColorBrush(Colors.CadetBlue); + Chartreuse = new SolidColorBrush(Colors.Chartreuse); + Chocolate = new SolidColorBrush(Colors.Chocolate); + Coral = new SolidColorBrush(Colors.Coral); + CornflowerBlue = new SolidColorBrush(Colors.CornflowerBlue); + Cornsilk = new SolidColorBrush(Colors.Cornsilk); + Crimson = new SolidColorBrush(Colors.Crimson); + Cyan = new SolidColorBrush(Colors.Cyan); + DarkBlue = new SolidColorBrush(Colors.DarkBlue); + DarkCyan = new SolidColorBrush(Colors.DarkCyan); + DarkGoldenrod = new SolidColorBrush(Colors.DarkGoldenrod); + DarkGray = new SolidColorBrush(Colors.DarkGray); + DarkGreen = new SolidColorBrush(Colors.DarkGreen); + DarkKhaki = new SolidColorBrush(Colors.DarkKhaki); + DarkMagenta = new SolidColorBrush(Colors.DarkMagenta); + DarkOliveGreen = new SolidColorBrush(Colors.DarkOliveGreen); + DarkOrange = new SolidColorBrush(Colors.DarkOrange); + DarkOrchid = new SolidColorBrush(Colors.DarkOrchid); + DarkRed = new SolidColorBrush(Colors.DarkRed); + DarkSalmon = new SolidColorBrush(Colors.DarkSalmon); + DarkSeaGreen = new SolidColorBrush(Colors.DarkSeaGreen); + DarkSlateBlue = new SolidColorBrush(Colors.DarkSlateBlue); + DarkSlateGray = new SolidColorBrush(Colors.DarkSlateGray); + DarkTurquoise = new SolidColorBrush(Colors.DarkTurquoise); + DarkViolet = new SolidColorBrush(Colors.DarkViolet); + DeepPink = new SolidColorBrush(Colors.DeepPink); + DeepSkyBlue = new SolidColorBrush(Colors.DeepSkyBlue); + DimGray = new SolidColorBrush(Colors.DimGray); + DodgerBlue = new SolidColorBrush(Colors.DodgerBlue); + Firebrick = new SolidColorBrush(Colors.Firebrick); + FloralWhite = new SolidColorBrush(Colors.FloralWhite); + ForestGreen = new SolidColorBrush(Colors.ForestGreen); + Fuchsia = new SolidColorBrush(Colors.Fuchsia); + Gainsboro = new SolidColorBrush(Colors.Gainsboro); + GhostWhite = new SolidColorBrush(Colors.GhostWhite); + Gold = new SolidColorBrush(Colors.Gold); + Goldenrod = new SolidColorBrush(Colors.Goldenrod); + Gray = new SolidColorBrush(Colors.Gray); + Green = new SolidColorBrush(Colors.Green); + GreenYellow = new SolidColorBrush(Colors.GreenYellow); + Honeydew = new SolidColorBrush(Colors.Honeydew); + HotPink = new SolidColorBrush(Colors.HotPink); + IndianRed = new SolidColorBrush(Colors.IndianRed); + Indigo = new SolidColorBrush(Colors.Indigo); + Ivory = new SolidColorBrush(Colors.Ivory); + Khaki = new SolidColorBrush(Colors.Khaki); + Lavender = new SolidColorBrush(Colors.Lavender); + LavenderBlush = new SolidColorBrush(Colors.LavenderBlush); + LawnGreen = new SolidColorBrush(Colors.LawnGreen); + LemonChiffon = new SolidColorBrush(Colors.LemonChiffon); + LightBlue = new SolidColorBrush(Colors.LightBlue); + LightCoral = new SolidColorBrush(Colors.LightCoral); + LightCyan = new SolidColorBrush(Colors.LightCyan); + LightGoldenrodYellow = new SolidColorBrush(Colors.LightGoldenrodYellow); + LightGray = new SolidColorBrush(Colors.LightGray); + LightGreen = new SolidColorBrush(Colors.LightGreen); + LightPink = new SolidColorBrush(Colors.LightPink); + LightSalmon = new SolidColorBrush(Colors.LightSalmon); + LightSeaGreen = new SolidColorBrush(Colors.LightSeaGreen); + LightSkyBlue = new SolidColorBrush(Colors.LightSkyBlue); + LightSlateGray = new SolidColorBrush(Colors.LightSlateGray); + LightSteelBlue = new SolidColorBrush(Colors.LightSteelBlue); + LightYellow = new SolidColorBrush(Colors.LightYellow); + Lime = new SolidColorBrush(Colors.Lime); + LimeGreen = new SolidColorBrush(Colors.LimeGreen); + Linen = new SolidColorBrush(Colors.Linen); + Magenta = new SolidColorBrush(Colors.Magenta); + Maroon = new SolidColorBrush(Colors.Maroon); + MediumAquamarine = new SolidColorBrush(Colors.MediumAquamarine); + MediumBlue = new SolidColorBrush(Colors.MediumBlue); + MediumOrchid = new SolidColorBrush(Colors.MediumOrchid); + MediumPurple = new SolidColorBrush(Colors.MediumPurple); + MediumSeaGreen = new SolidColorBrush(Colors.MediumSeaGreen); + MediumSlateBlue = new SolidColorBrush(Colors.MediumSlateBlue); + MediumSpringGreen = new SolidColorBrush(Colors.MediumSpringGreen); + MediumTurquoise = new SolidColorBrush(Colors.MediumTurquoise); + MediumVioletRed = new SolidColorBrush(Colors.MediumVioletRed); + MidnightBlue = new SolidColorBrush(Colors.MidnightBlue); + MintCream = new SolidColorBrush(Colors.MintCream); + MistyRose = new SolidColorBrush(Colors.MistyRose); + Moccasin = new SolidColorBrush(Colors.Moccasin); + NavajoWhite = new SolidColorBrush(Colors.NavajoWhite); + Navy = new SolidColorBrush(Colors.Navy); + OldLace = new SolidColorBrush(Colors.OldLace); + Olive = new SolidColorBrush(Colors.Olive); + OliveDrab = new SolidColorBrush(Colors.OliveDrab); + Orange = new SolidColorBrush(Colors.Orange); + OrangeRed = new SolidColorBrush(Colors.OrangeRed); + Orchid = new SolidColorBrush(Colors.Orchid); + PaleGoldenrod = new SolidColorBrush(Colors.PaleGoldenrod); + PaleGreen = new SolidColorBrush(Colors.PaleGreen); + PaleTurquoise = new SolidColorBrush(Colors.PaleTurquoise); + PaleVioletRed = new SolidColorBrush(Colors.PaleVioletRed); + PapayaWhip = new SolidColorBrush(Colors.PapayaWhip); + PeachPuff = new SolidColorBrush(Colors.PeachPuff); + Peru = new SolidColorBrush(Colors.Peru); + Pink = new SolidColorBrush(Colors.Pink); + Plum = new SolidColorBrush(Colors.Plum); + PowderBlue = new SolidColorBrush(Colors.PowderBlue); + Purple = new SolidColorBrush(Colors.Purple); + Red = new SolidColorBrush(Colors.Red); + RosyBrown = new SolidColorBrush(Colors.RosyBrown); + RoyalBlue = new SolidColorBrush(Colors.RoyalBlue); + SaddleBrown = new SolidColorBrush(Colors.SaddleBrown); + Salmon = new SolidColorBrush(Colors.Salmon); + SandyBrown = new SolidColorBrush(Colors.SandyBrown); + SeaGreen = new SolidColorBrush(Colors.SeaGreen); + SeaShell = new SolidColorBrush(Colors.SeaShell); + Sienna = new SolidColorBrush(Colors.Sienna); + Silver = new SolidColorBrush(Colors.Silver); + SkyBlue = new SolidColorBrush(Colors.SkyBlue); + SlateBlue = new SolidColorBrush(Colors.SlateBlue); + SlateGray = new SolidColorBrush(Colors.SlateGray); + Snow = new SolidColorBrush(Colors.Snow); + SpringGreen = new SolidColorBrush(Colors.SpringGreen); + SteelBlue = new SolidColorBrush(Colors.SteelBlue); + Tan = new SolidColorBrush(Colors.Tan); + Teal = new SolidColorBrush(Colors.Teal); + Thistle = new SolidColorBrush(Colors.Thistle); + Tomato = new SolidColorBrush(Colors.Tomato); + Transparent = new SolidColorBrush(Colors.Transparent); + Turquoise = new SolidColorBrush(Colors.Turquoise); + Violet = new SolidColorBrush(Colors.Violet); + Wheat = new SolidColorBrush(Colors.Wheat); + White = new SolidColorBrush(Colors.White); + WhiteSmoke = new SolidColorBrush(Colors.WhiteSmoke); + Yellow = new SolidColorBrush(Colors.Yellow); + YellowGreen = new SolidColorBrush(Colors.YellowGreen); + } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush AliceBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush AntiqueWhite { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Aqua { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Aquamarine { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Azure { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Beige { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Bisque { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Black { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush BlanchedAlmond { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Blue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush BlueViolet { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Brown { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush BurlyWood { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush CadetBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Chartreuse { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Chocolate { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Coral { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush CornflowerBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Cornsilk { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Crimson { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Cyan { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkCyan { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkGoldenrod { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkGray { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkKhaki { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkMagenta { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkOliveGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkOrange { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkOrchid { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkRed { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkSalmon { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkSeaGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkSlateBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkSlateGray { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkTurquoise { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DarkViolet { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DeepPink { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DeepSkyBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DimGray { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush DodgerBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Firebrick { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush FloralWhite { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush ForestGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Fuchsia { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Gainsboro { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush GhostWhite { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Gold { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Goldenrod { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Gray { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Green { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush GreenYellow { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Honeydew { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush HotPink { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush IndianRed { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Indigo { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Ivory { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Khaki { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Lavender { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LavenderBlush { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LawnGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LemonChiffon { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightCoral { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightCyan { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightGoldenrodYellow { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightGray { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightPink { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightSalmon { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightSeaGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightSkyBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightSlateGray { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightSteelBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LightYellow { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Lime { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush LimeGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Linen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Magenta { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Maroon { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MediumAquamarine { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MediumBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MediumOrchid { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MediumPurple { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MediumSeaGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MediumSlateBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MediumSpringGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MediumTurquoise { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MediumVioletRed { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MidnightBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MintCream { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush MistyRose { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Moccasin { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush NavajoWhite { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Navy { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush OldLace { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Olive { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush OliveDrab { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Orange { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush OrangeRed { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Orchid { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush PaleGoldenrod { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush PaleGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush PaleTurquoise { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush PaleVioletRed { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush PapayaWhip { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush PeachPuff { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Peru { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Pink { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Plum { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush PowderBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Purple { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Red { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush RosyBrown { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush RoyalBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush SaddleBrown { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Salmon { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush SandyBrown { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush SeaGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush SeaShell { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Sienna { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Silver { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush SkyBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush SlateBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush SlateGray { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Snow { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush SpringGreen { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush SteelBlue { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Tan { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Teal { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Thistle { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Tomato { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Transparent { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Turquoise { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Violet { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Wheat { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush White { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush WhiteSmoke { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush Yellow { get; private set; } + + /// + /// Gets an colored brush. + /// + public static SolidColorBrush YellowGreen { get; private set; } + } +} diff --git a/src/Avalonia.SceneGraph/Media/Color.cs b/src/Avalonia.SceneGraph/Media/Color.cs new file mode 100644 index 0000000000..cbf5a86fd6 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Color.cs @@ -0,0 +1,146 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Linq; +using System.Reflection; + +namespace Avalonia.Media +{ + /// + /// An ARGB color. + /// + public struct Color + { + /// + /// Gets or sets the Alpha component of the color. + /// + public byte A { get; } + + /// + /// Gets or sets the Red component of the color. + /// + public byte R { get; } + + /// + /// Gets or sets the Green component of the color. + /// + public byte G { get; } + + /// + /// Gets or sets the Blue component of the color. + /// + public byte B { get; } + + public Color(byte a, byte r, byte g, byte b) + { + A = a; + R = r; + G = g; + B = b; + } + + /// + /// Creates a from alpha, red, green and blue components. + /// + /// The alpha component. + /// The red component. + /// The green component. + /// The blue component. + /// The color. + public static Color FromArgb(byte a, byte r, byte g, byte b) + { + return new Color(a, r, g, b); + } + + /// + /// Creates a from red, green and blue components. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The color. + public static Color FromRgb(byte r, byte g, byte b) + { + return new Color(0xff, r, g, b); + } + + /// + /// Creates a from an integer. + /// + /// The integer value. + /// The color. + public static Color FromUInt32(uint value) + { + return new Color( + (byte)((value >> 24) & 0xff), + (byte)((value >> 16) & 0xff), + (byte)((value >> 8) & 0xff), + (byte)(value & 0xff) + ); + } + + /// + /// Parses a color string. + /// + /// The color string. + /// The . + public static Color Parse(string s) + { + if (s[0] == '#') + { + var or = 0u; + + if (s.Length == 7) + { + or = 0xff000000; + } + else if (s.Length != 9) + { + throw new FormatException($"Invalid color string: '{s}'."); + } + + return FromUInt32(uint.Parse(s.Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture) | or); + } + else + { + var upper = s.ToUpperInvariant(); + var member = typeof(Colors).GetTypeInfo().DeclaredProperties + .FirstOrDefault(x => x.Name.ToUpperInvariant() == upper); + + if (member != null) + { + return (Color)member.GetValue(null); + } + else + { + throw new FormatException($"Invalid color string: '{s}'."); + } + } + } + + /// + /// Returns the string representation of the color. + /// + /// + /// The string representation of the color. + /// + public override string ToString() + { + uint rgb = ((uint)A << 24) | ((uint)R << 16) | ((uint)G << 8) | (uint)B; + return $"#{rgb:x8}"; + } + + /// + /// Returns the integer representation of the color. + /// + /// + /// The integer representation of the color. + /// + public uint ToUint32() + { + return ((uint)A << 24) | ((uint)R << 16) | ((uint)G << 8) | (uint)B; + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/Colors.cs b/src/Avalonia.SceneGraph/Media/Colors.cs new file mode 100644 index 0000000000..7296d7dd39 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Colors.cs @@ -0,0 +1,716 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Defines a set of predefined colors. + /// + public sealed class Colors + { + /// + /// Gets a color with an ARGB value of #fff0f8ff. + /// + public static Color AliceBlue => Color.FromUInt32(0xfff0f8ff); + + /// + /// Gets a color with an ARGB value of #fffaebd7. + /// + public static Color AntiqueWhite => Color.FromUInt32(0xfffaebd7); + + /// + /// Gets a color with an ARGB value of #ff00ffff. + /// + public static Color Aqua => Color.FromUInt32(0xff00ffff); + + /// + /// Gets a color with an ARGB value of #ff7fffd4. + /// + public static Color Aquamarine => Color.FromUInt32(0xff7fffd4); + + /// + /// Gets a color with an ARGB value of #fff0ffff. + /// + public static Color Azure => Color.FromUInt32(0xfff0ffff); + + /// + /// Gets a color with an ARGB value of #fff5f5dc. + /// + public static Color Beige => Color.FromUInt32(0xfff5f5dc); + + /// + /// Gets a color with an ARGB value of #ffffe4c4. + /// + public static Color Bisque => Color.FromUInt32(0xffffe4c4); + + /// + /// Gets a color with an ARGB value of #ff000000. + /// + public static Color Black => Color.FromUInt32(0xff000000); + + /// + /// Gets a color with an ARGB value of #ffffebcd. + /// + public static Color BlanchedAlmond => Color.FromUInt32(0xffffebcd); + + /// + /// Gets a color with an ARGB value of #ff0000ff. + /// + public static Color Blue => Color.FromUInt32(0xff0000ff); + + /// + /// Gets a color with an ARGB value of #ff8a2be2. + /// + public static Color BlueViolet => Color.FromUInt32(0xff8a2be2); + + /// + /// Gets a color with an ARGB value of #ffa52a2a. + /// + public static Color Brown => Color.FromUInt32(0xffa52a2a); + + /// + /// Gets a color with an ARGB value of #ffdeb887. + /// + public static Color BurlyWood => Color.FromUInt32(0xffdeb887); + + /// + /// Gets a color with an ARGB value of #ff5f9ea0. + /// + public static Color CadetBlue => Color.FromUInt32(0xff5f9ea0); + + /// + /// Gets a color with an ARGB value of #ff7fff00. + /// + public static Color Chartreuse => Color.FromUInt32(0xff7fff00); + + /// + /// Gets a color with an ARGB value of #ffd2691e. + /// + public static Color Chocolate => Color.FromUInt32(0xffd2691e); + + /// + /// Gets a color with an ARGB value of #ffff7f50. + /// + public static Color Coral => Color.FromUInt32(0xffff7f50); + + /// + /// Gets a color with an ARGB value of #ff6495ed. + /// + public static Color CornflowerBlue => Color.FromUInt32(0xff6495ed); + + /// + /// Gets a color with an ARGB value of #fffff8dc. + /// + public static Color Cornsilk => Color.FromUInt32(0xfffff8dc); + + /// + /// Gets a color with an ARGB value of #ffdc143c. + /// + public static Color Crimson => Color.FromUInt32(0xffdc143c); + + /// + /// Gets a color with an ARGB value of #ff00ffff. + /// + public static Color Cyan => Color.FromUInt32(0xff00ffff); + + /// + /// Gets a color with an ARGB value of #ff00008b. + /// + public static Color DarkBlue => Color.FromUInt32(0xff00008b); + + /// + /// Gets a color with an ARGB value of #ff008b8b. + /// + public static Color DarkCyan => Color.FromUInt32(0xff008b8b); + + /// + /// Gets a color with an ARGB value of #ffb8860b. + /// + public static Color DarkGoldenrod => Color.FromUInt32(0xffb8860b); + + /// + /// Gets a color with an ARGB value of #ffa9a9a9. + /// + public static Color DarkGray => Color.FromUInt32(0xffa9a9a9); + + /// + /// Gets a color with an ARGB value of #ff006400. + /// + public static Color DarkGreen => Color.FromUInt32(0xff006400); + + /// + /// Gets a color with an ARGB value of #ffbdb76b. + /// + public static Color DarkKhaki => Color.FromUInt32(0xffbdb76b); + + /// + /// Gets a color with an ARGB value of #ff8b008b. + /// + public static Color DarkMagenta => Color.FromUInt32(0xff8b008b); + + /// + /// Gets a color with an ARGB value of #ff556b2f. + /// + public static Color DarkOliveGreen => Color.FromUInt32(0xff556b2f); + + /// + /// Gets a color with an ARGB value of #ffff8c00. + /// + public static Color DarkOrange => Color.FromUInt32(0xffff8c00); + + /// + /// Gets a color with an ARGB value of #ff9932cc. + /// + public static Color DarkOrchid => Color.FromUInt32(0xff9932cc); + + /// + /// Gets a color with an ARGB value of #ff8b0000. + /// + public static Color DarkRed => Color.FromUInt32(0xff8b0000); + + /// + /// Gets a color with an ARGB value of #ffe9967a. + /// + public static Color DarkSalmon => Color.FromUInt32(0xffe9967a); + + /// + /// Gets a color with an ARGB value of #ff8fbc8f. + /// + public static Color DarkSeaGreen => Color.FromUInt32(0xff8fbc8f); + + /// + /// Gets a color with an ARGB value of #ff483d8b. + /// + public static Color DarkSlateBlue => Color.FromUInt32(0xff483d8b); + + /// + /// Gets a color with an ARGB value of #ff2f4f4f. + /// + public static Color DarkSlateGray => Color.FromUInt32(0xff2f4f4f); + + /// + /// Gets a color with an ARGB value of #ff00ced1. + /// + public static Color DarkTurquoise => Color.FromUInt32(0xff00ced1); + + /// + /// Gets a color with an ARGB value of #ff9400d3. + /// + public static Color DarkViolet => Color.FromUInt32(0xff9400d3); + + /// + /// Gets a color with an ARGB value of #ffff1493. + /// + public static Color DeepPink => Color.FromUInt32(0xffff1493); + + /// + /// Gets a color with an ARGB value of #ff00bfff. + /// + public static Color DeepSkyBlue => Color.FromUInt32(0xff00bfff); + + /// + /// Gets a color with an ARGB value of #ff696969. + /// + public static Color DimGray => Color.FromUInt32(0xff696969); + + /// + /// Gets a color with an ARGB value of #ff1e90ff. + /// + public static Color DodgerBlue => Color.FromUInt32(0xff1e90ff); + + /// + /// Gets a color with an ARGB value of #ffb22222. + /// + public static Color Firebrick => Color.FromUInt32(0xffb22222); + + /// + /// Gets a color with an ARGB value of #fffffaf0. + /// + public static Color FloralWhite => Color.FromUInt32(0xfffffaf0); + + /// + /// Gets a color with an ARGB value of #ff228b22. + /// + public static Color ForestGreen => Color.FromUInt32(0xff228b22); + + /// + /// Gets a color with an ARGB value of #ffff00ff. + /// + public static Color Fuchsia => Color.FromUInt32(0xffff00ff); + + /// + /// Gets a color with an ARGB value of #ffdcdcdc. + /// + public static Color Gainsboro => Color.FromUInt32(0xffdcdcdc); + + /// + /// Gets a color with an ARGB value of #fff8f8ff. + /// + public static Color GhostWhite => Color.FromUInt32(0xfff8f8ff); + + /// + /// Gets a color with an ARGB value of #ffffd700. + /// + public static Color Gold => Color.FromUInt32(0xffffd700); + + /// + /// Gets a color with an ARGB value of #ffdaa520. + /// + public static Color Goldenrod => Color.FromUInt32(0xffdaa520); + + /// + /// Gets a color with an ARGB value of #ff808080. + /// + public static Color Gray => Color.FromUInt32(0xff808080); + + /// + /// Gets a color with an ARGB value of #ff008000. + /// + public static Color Green => Color.FromUInt32(0xff008000); + + /// + /// Gets a color with an ARGB value of #ffadff2f. + /// + public static Color GreenYellow => Color.FromUInt32(0xffadff2f); + + /// + /// Gets a color with an ARGB value of #fff0fff0. + /// + public static Color Honeydew => Color.FromUInt32(0xfff0fff0); + + /// + /// Gets a color with an ARGB value of #ffff69b4. + /// + public static Color HotPink => Color.FromUInt32(0xffff69b4); + + /// + /// Gets a color with an ARGB value of #ffcd5c5c. + /// + public static Color IndianRed => Color.FromUInt32(0xffcd5c5c); + + /// + /// Gets a color with an ARGB value of #ff4b0082. + /// + public static Color Indigo => Color.FromUInt32(0xff4b0082); + + /// + /// Gets a color with an ARGB value of #fffffff0. + /// + public static Color Ivory => Color.FromUInt32(0xfffffff0); + + /// + /// Gets a color with an ARGB value of #fff0e68c. + /// + public static Color Khaki => Color.FromUInt32(0xfff0e68c); + + /// + /// Gets a color with an ARGB value of #ffe6e6fa. + /// + public static Color Lavender => Color.FromUInt32(0xffe6e6fa); + + /// + /// Gets a color with an ARGB value of #fffff0f5. + /// + public static Color LavenderBlush => Color.FromUInt32(0xfffff0f5); + + /// + /// Gets a color with an ARGB value of #ff7cfc00. + /// + public static Color LawnGreen => Color.FromUInt32(0xff7cfc00); + + /// + /// Gets a color with an ARGB value of #fffffacd. + /// + public static Color LemonChiffon => Color.FromUInt32(0xfffffacd); + + /// + /// Gets a color with an ARGB value of #ffadd8e6. + /// + public static Color LightBlue => Color.FromUInt32(0xffadd8e6); + + /// + /// Gets a color with an ARGB value of #fff08080. + /// + public static Color LightCoral => Color.FromUInt32(0xfff08080); + + /// + /// Gets a color with an ARGB value of #ffe0ffff. + /// + public static Color LightCyan => Color.FromUInt32(0xffe0ffff); + + /// + /// Gets a color with an ARGB value of #fffafad2. + /// + public static Color LightGoldenrodYellow => Color.FromUInt32(0xfffafad2); + + /// + /// Gets a color with an ARGB value of #ffd3d3d3. + /// + public static Color LightGray => Color.FromUInt32(0xffd3d3d3); + + /// + /// Gets a color with an ARGB value of #ff90ee90. + /// + public static Color LightGreen => Color.FromUInt32(0xff90ee90); + + /// + /// Gets a color with an ARGB value of #ffffb6c1. + /// + public static Color LightPink => Color.FromUInt32(0xffffb6c1); + + /// + /// Gets a color with an ARGB value of #ffffa07a. + /// + public static Color LightSalmon => Color.FromUInt32(0xffffa07a); + + /// + /// Gets a color with an ARGB value of #ff20b2aa. + /// + public static Color LightSeaGreen => Color.FromUInt32(0xff20b2aa); + + /// + /// Gets a color with an ARGB value of #ff87cefa. + /// + public static Color LightSkyBlue => Color.FromUInt32(0xff87cefa); + + /// + /// Gets a color with an ARGB value of #ff778899. + /// + public static Color LightSlateGray => Color.FromUInt32(0xff778899); + + /// + /// Gets a color with an ARGB value of #ffb0c4de. + /// + public static Color LightSteelBlue => Color.FromUInt32(0xffb0c4de); + + /// + /// Gets a color with an ARGB value of #ffffffe0. + /// + public static Color LightYellow => Color.FromUInt32(0xffffffe0); + + /// + /// Gets a color with an ARGB value of #ff00ff00. + /// + public static Color Lime => Color.FromUInt32(0xff00ff00); + + /// + /// Gets a color with an ARGB value of #ff32cd32. + /// + public static Color LimeGreen => Color.FromUInt32(0xff32cd32); + + /// + /// Gets a color with an ARGB value of #fffaf0e6. + /// + public static Color Linen => Color.FromUInt32(0xfffaf0e6); + + /// + /// Gets a color with an ARGB value of #ffff00ff. + /// + public static Color Magenta => Color.FromUInt32(0xffff00ff); + + /// + /// Gets a color with an ARGB value of #ff800000. + /// + public static Color Maroon => Color.FromUInt32(0xff800000); + + /// + /// Gets a color with an ARGB value of #ff66cdaa. + /// + public static Color MediumAquamarine => Color.FromUInt32(0xff66cdaa); + + /// + /// Gets a color with an ARGB value of #ff0000cd. + /// + public static Color MediumBlue => Color.FromUInt32(0xff0000cd); + + /// + /// Gets a color with an ARGB value of #ffba55d3. + /// + public static Color MediumOrchid => Color.FromUInt32(0xffba55d3); + + /// + /// Gets a color with an ARGB value of #ff9370db. + /// + public static Color MediumPurple => Color.FromUInt32(0xff9370db); + + /// + /// Gets a color with an ARGB value of #ff3cb371. + /// + public static Color MediumSeaGreen => Color.FromUInt32(0xff3cb371); + + /// + /// Gets a color with an ARGB value of #ff7b68ee. + /// + public static Color MediumSlateBlue => Color.FromUInt32(0xff7b68ee); + + /// + /// Gets a color with an ARGB value of #ff00fa9a. + /// + public static Color MediumSpringGreen => Color.FromUInt32(0xff00fa9a); + + /// + /// Gets a color with an ARGB value of #ff48d1cc. + /// + public static Color MediumTurquoise => Color.FromUInt32(0xff48d1cc); + + /// + /// Gets a color with an ARGB value of #ffc71585. + /// + public static Color MediumVioletRed => Color.FromUInt32(0xffc71585); + + /// + /// Gets a color with an ARGB value of #ff191970. + /// + public static Color MidnightBlue => Color.FromUInt32(0xff191970); + + /// + /// Gets a color with an ARGB value of #fff5fffa. + /// + public static Color MintCream => Color.FromUInt32(0xfff5fffa); + + /// + /// Gets a color with an ARGB value of #ffffe4e1. + /// + public static Color MistyRose => Color.FromUInt32(0xffffe4e1); + + /// + /// Gets a color with an ARGB value of #ffffe4b5. + /// + public static Color Moccasin => Color.FromUInt32(0xffffe4b5); + + /// + /// Gets a color with an ARGB value of #ffffdead. + /// + public static Color NavajoWhite => Color.FromUInt32(0xffffdead); + + /// + /// Gets a color with an ARGB value of #ff000080. + /// + public static Color Navy => Color.FromUInt32(0xff000080); + + /// + /// Gets a color with an ARGB value of #fffdf5e6. + /// + public static Color OldLace => Color.FromUInt32(0xfffdf5e6); + + /// + /// Gets a color with an ARGB value of #ff808000. + /// + public static Color Olive => Color.FromUInt32(0xff808000); + + /// + /// Gets a color with an ARGB value of #ff6b8e23. + /// + public static Color OliveDrab => Color.FromUInt32(0xff6b8e23); + + /// + /// Gets a color with an ARGB value of #ffffa500. + /// + public static Color Orange => Color.FromUInt32(0xffffa500); + + /// + /// Gets a color with an ARGB value of #ffff4500. + /// + public static Color OrangeRed => Color.FromUInt32(0xffff4500); + + /// + /// Gets a color with an ARGB value of #ffda70d6. + /// + public static Color Orchid => Color.FromUInt32(0xffda70d6); + + /// + /// Gets a color with an ARGB value of #ffeee8aa. + /// + public static Color PaleGoldenrod => Color.FromUInt32(0xffeee8aa); + + /// + /// Gets a color with an ARGB value of #ff98fb98. + /// + public static Color PaleGreen => Color.FromUInt32(0xff98fb98); + + /// + /// Gets a color with an ARGB value of #ffafeeee. + /// + public static Color PaleTurquoise => Color.FromUInt32(0xffafeeee); + + /// + /// Gets a color with an ARGB value of #ffdb7093. + /// + public static Color PaleVioletRed => Color.FromUInt32(0xffdb7093); + + /// + /// Gets a color with an ARGB value of #ffffefd5. + /// + public static Color PapayaWhip => Color.FromUInt32(0xffffefd5); + + /// + /// Gets a color with an ARGB value of #ffffdab9. + /// + public static Color PeachPuff => Color.FromUInt32(0xffffdab9); + + /// + /// Gets a color with an ARGB value of #ffcd853f. + /// + public static Color Peru => Color.FromUInt32(0xffcd853f); + + /// + /// Gets a color with an ARGB value of #ffffc0cb. + /// + public static Color Pink => Color.FromUInt32(0xffffc0cb); + + /// + /// Gets a color with an ARGB value of #ffdda0dd. + /// + public static Color Plum => Color.FromUInt32(0xffdda0dd); + + /// + /// Gets a color with an ARGB value of #ffb0e0e6. + /// + public static Color PowderBlue => Color.FromUInt32(0xffb0e0e6); + + /// + /// Gets a color with an ARGB value of #ff800080. + /// + public static Color Purple => Color.FromUInt32(0xff800080); + + /// + /// Gets a color with an ARGB value of #ffff0000. + /// + public static Color Red => Color.FromUInt32(0xffff0000); + + /// + /// Gets a color with an ARGB value of #ffbc8f8f. + /// + public static Color RosyBrown => Color.FromUInt32(0xffbc8f8f); + + /// + /// Gets a color with an ARGB value of #ff4169e1. + /// + public static Color RoyalBlue => Color.FromUInt32(0xff4169e1); + + /// + /// Gets a color with an ARGB value of #ff8b4513. + /// + public static Color SaddleBrown => Color.FromUInt32(0xff8b4513); + + /// + /// Gets a color with an ARGB value of #fffa8072. + /// + public static Color Salmon => Color.FromUInt32(0xfffa8072); + + /// + /// Gets a color with an ARGB value of #fff4a460. + /// + public static Color SandyBrown => Color.FromUInt32(0xfff4a460); + + /// + /// Gets a color with an ARGB value of #ff2e8b57. + /// + public static Color SeaGreen => Color.FromUInt32(0xff2e8b57); + + /// + /// Gets a color with an ARGB value of #fffff5ee. + /// + public static Color SeaShell => Color.FromUInt32(0xfffff5ee); + + /// + /// Gets a color with an ARGB value of #ffa0522d. + /// + public static Color Sienna => Color.FromUInt32(0xffa0522d); + + /// + /// Gets a color with an ARGB value of #ffc0c0c0. + /// + public static Color Silver => Color.FromUInt32(0xffc0c0c0); + + /// + /// Gets a color with an ARGB value of #ff87ceeb. + /// + public static Color SkyBlue => Color.FromUInt32(0xff87ceeb); + + /// + /// Gets a color with an ARGB value of #ff6a5acd. + /// + public static Color SlateBlue => Color.FromUInt32(0xff6a5acd); + + /// + /// Gets a color with an ARGB value of #ff708090. + /// + public static Color SlateGray => Color.FromUInt32(0xff708090); + + /// + /// Gets a color with an ARGB value of #fffffafa. + /// + public static Color Snow => Color.FromUInt32(0xfffffafa); + + /// + /// Gets a color with an ARGB value of #ff00ff7f. + /// + public static Color SpringGreen => Color.FromUInt32(0xff00ff7f); + + /// + /// Gets a color with an ARGB value of #ff4682b4. + /// + public static Color SteelBlue => Color.FromUInt32(0xff4682b4); + + /// + /// Gets a color with an ARGB value of #ffd2b48c. + /// + public static Color Tan => Color.FromUInt32(0xffd2b48c); + + /// + /// Gets a color with an ARGB value of #ff008080. + /// + public static Color Teal => Color.FromUInt32(0xff008080); + + /// + /// Gets a color with an ARGB value of #ffd8bfd8. + /// + public static Color Thistle => Color.FromUInt32(0xffd8bfd8); + + /// + /// Gets a color with an ARGB value of #ffff6347. + /// + public static Color Tomato => Color.FromUInt32(0xffff6347); + + /// + /// Gets a color with an ARGB value of #00ffffff. + /// + public static Color Transparent => Color.FromUInt32(0x00ffffff); + + /// + /// Gets a color with an ARGB value of #ff40e0d0. + /// + public static Color Turquoise => Color.FromUInt32(0xff40e0d0); + + /// + /// Gets a color with an ARGB value of #ffee82ee. + /// + public static Color Violet => Color.FromUInt32(0xffee82ee); + + /// + /// Gets a color with an ARGB value of #fff5deb3. + /// + public static Color Wheat => Color.FromUInt32(0xfff5deb3); + + /// + /// Gets a color with an ARGB value of #ffffffff. + /// + public static Color White => Color.FromUInt32(0xffffffff); + + /// + /// Gets a color with an ARGB value of #fff5f5f5. + /// + public static Color WhiteSmoke => Color.FromUInt32(0xfff5f5f5); + + /// + /// Gets a color with an ARGB value of #ffffff00. + /// + public static Color Yellow => Color.FromUInt32(0xffffff00); + + /// + /// Gets a color with an ARGB value of #ff9acd32. + /// + public static Color YellowGreen => Color.FromUInt32(0xff9acd32); + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/DashStyle.cs b/src/Avalonia.SceneGraph/Media/DashStyle.cs new file mode 100644 index 0000000000..3fcfcaee70 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/DashStyle.cs @@ -0,0 +1,76 @@ +namespace Avalonia.Media +{ + using Avalonia.Animation; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + public class DashStyle : Animatable + { + private static DashStyle dash; + public static DashStyle Dash + { + get + { + if (dashDotDot == null) + { + dash = new DashStyle(new double[] { 2, 2 }, 1); + } + + return dash; + } + } + + + + private static DashStyle dot; + public static DashStyle Dot + { + get { return dot ?? (dot = new DashStyle(new double[] {0, 2}, 0)); } + } + + private static DashStyle dashDot; + public static DashStyle DashDot + { + get + { + if (dashDot == null) + { + dashDot = new DashStyle(new double[] { 2, 2, 0, 2 }, 1); + } + + return dashDot; + } + } + + private static DashStyle dashDotDot; + public static DashStyle DashDotDot + { + get + { + if (dashDotDot == null) + { + dashDotDot = new DashStyle(new double[] { 2, 2, 0, 2, 0, 2 }, 1); + } + + return dashDotDot; + } + } + + + public DashStyle(IReadOnlyList dashes = null, double offset = 0.0) + { + this.Dashes = dashes; + this.Offset = offset; + } + + /// + /// Gets and sets the length of alternating dashes and gaps. + /// + public IReadOnlyList Dashes { get; } + + public double Offset { get; } + } +} diff --git a/src/Avalonia.SceneGraph/Media/DrawingContext.cs b/src/Avalonia.SceneGraph/Media/DrawingContext.cs new file mode 100644 index 0000000000..c12434a442 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/DrawingContext.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Media.Imaging; + +namespace Avalonia.Media +{ + public sealed class DrawingContext : IDisposable + { + private readonly IDrawingContextImpl _impl; + private int _currentLevel; + + + + static readonly Stack> StateStackPool = new Stack>(); + static readonly Stack> TransformStackPool = new Stack>(); + + private Stack _states = StateStackPool.Count == 0 ? new Stack() : StateStackPool.Pop(); + + private Stack _transformContainers = TransformStackPool.Count == 0 + ? new Stack() + : TransformStackPool.Pop(); + + struct TransformContainer + { + public readonly Matrix LocalTransform; + public readonly Matrix ContainerTransform; + + public TransformContainer(Matrix localTransform, Matrix containerTransform) + { + LocalTransform = localTransform; + ContainerTransform = containerTransform; + } + } + + public DrawingContext(IDrawingContextImpl impl) + { + _impl = impl; + } + + + private Matrix _currentTransform = Matrix.Identity; + + /// + /// Gets the current transform of the drawing context. + /// + public Matrix CurrentTransform + { + get { return _currentTransform; } + private set + { + _currentTransform = value; + _impl.Transform = _currentTransform*_currentContainerTransform; + } + } + + private Matrix _currentContainerTransform = Matrix.Identity; + + /// + /// Draws a bitmap image. + /// + /// The bitmap image. + /// The opacity to draw with. + /// The rect in the image to draw. + /// The rect in the output to draw to. + public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect) + => _impl.DrawImage(source, opacity, sourceRect, destRect); + + /// + /// Draws a line. + /// + /// The stroke pen. + /// The first point of the line. + /// The second point of the line. + public void DrawLine(Pen pen, Point p1, Point p2) => _impl.DrawLine(pen, p1, p2); + + /// + /// Draws a geometry. + /// + /// The fill brush. + /// The stroke pen. + /// The geometry. + public void DrawGeometry(IBrush brush, Pen pen, Geometry geometry) => _impl.DrawGeometry(brush, pen, geometry); + + /// + /// Draws the outline of a rectangle. + /// + /// The pen. + /// The rectangle bounds. + /// The corner radius. + public void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0.0f) + => _impl.DrawRectangle(pen, rect, cornerRadius); + + /// + /// Draws text. + /// + /// The foreground brush. + /// The upper-left corner of the text. + /// The text. + public void DrawText(IBrush foreground, Point origin, FormattedText text) + => _impl.DrawText(foreground, origin, text); + + /// + /// Draws a filled rectangle. + /// + /// The brush. + /// The rectangle bounds. + /// The corner radius. + public void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0.0f) + => _impl.FillRectangle(brush, rect, cornerRadius); + + public struct PushedState : IDisposable + { + private readonly int _level; + private readonly DrawingContext _context; + private readonly Matrix _matrix; + private readonly PushedStateType _type; + + public enum PushedStateType + { + None, + Matrix, + Opacity, + Clip, + MatrixContainer + } + + public PushedState(DrawingContext context, PushedStateType type, Matrix matrix = default(Matrix)) + { + _context = context; + _type = type; + _matrix = matrix; + _level = context._currentLevel += 1; + context._states.Push(this); + } + + public void Dispose() + { + if(_type == PushedStateType.None) + return; + if (_context._currentLevel != _level) + throw new InvalidOperationException("Wrong Push/Pop state order"); + _context._currentLevel--; + _context._states.Pop(); + if (_type == PushedStateType.Matrix) + _context.CurrentTransform = _matrix; + else if(_type == PushedStateType.Clip) + _context._impl.PopClip(); + else if(_type == PushedStateType.Opacity) + _context._impl.PopOpacity(); + else if (_type == PushedStateType.MatrixContainer) + { + var cont = _context._transformContainers.Pop(); + _context._currentContainerTransform = cont.ContainerTransform; + _context.CurrentTransform = cont.LocalTransform; + } + } + } + + + /// + /// Pushes a clip rectange. + /// + /// The clip rectangle. + /// A disposable used to undo the clip rectangle. + public PushedState PushClip(Rect clip) + { + _impl.PushClip(clip); + return new PushedState(this, PushedState.PushedStateType.Clip); + } + + /// + /// Pushes an opacity value. + /// + /// The opacity. + /// A disposable used to undo the opacity. + public PushedState PushOpacity(double opacity) + //TODO: Eliminate platform-specific push opacity call + { + _impl.PushOpacity(opacity); + return new PushedState(this, PushedState.PushedStateType.Opacity); + } + + /// + /// Pushes a matrix transformation. + /// + /// The matrix + /// A disposable used to undo the transformation. + public PushedState PushPostTransform(Matrix matrix) => PushSetTransform(CurrentTransform*matrix); + + public PushedState PushPreTransform(Matrix matrix) => PushSetTransform(matrix*CurrentTransform); + + + PushedState PushSetTransform(Matrix matrix) + { + var oldMatrix = CurrentTransform; + CurrentTransform = matrix; + + return new PushedState(this, PushedState.PushedStateType.Matrix, oldMatrix); + } + + + public PushedState PushTransformContainer() + { + _transformContainers.Push(new TransformContainer(CurrentTransform, _currentContainerTransform)); + _currentContainerTransform = CurrentTransform*_currentContainerTransform; + _currentTransform = Matrix.Identity; + return new PushedState(this, PushedState.PushedStateType.MatrixContainer); + } + + public void Dispose() + { + while (_states.Count != 0) + _states.Peek().Dispose(); + StateStackPool.Push(_states); + _states = null; + TransformStackPool.Push(_transformContainers); + _transformContainers = null; + _impl.Dispose(); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/EllipseGeometry.cs b/src/Avalonia.SceneGraph/Media/EllipseGeometry.cs new file mode 100644 index 0000000000..414fd9ab59 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/EllipseGeometry.cs @@ -0,0 +1,58 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Platform; + +namespace Avalonia.Media +{ + /// + /// Represents the geometry of an ellipse or circle. + /// + public class EllipseGeometry : Geometry + { + /// + /// Initializes a new instance of the class. + /// + /// The rectangle that the ellipse should fill. + public EllipseGeometry(Rect rect) + { + IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); + IStreamGeometryImpl impl = factory.CreateStreamGeometry(); + + using (IStreamGeometryContextImpl ctx = impl.Open()) + { + double controlPointRatio = (Math.Sqrt(2) - 1) * 4 / 3; + var center = rect.Center; + var radius = new Vector(rect.Width / 2, rect.Height / 2); + + var x0 = center.X - radius.X; + var x1 = center.X - (radius.X * controlPointRatio); + var x2 = center.X; + var x3 = center.X + (radius.X * controlPointRatio); + var x4 = center.X + radius.X; + + var y0 = center.Y - radius.Y; + var y1 = center.Y - (radius.Y * controlPointRatio); + var y2 = center.Y; + var y3 = center.Y + (radius.Y * controlPointRatio); + var y4 = center.Y + radius.Y; + + ctx.BeginFigure(new Point(x2, y0), true); + ctx.CubicBezierTo(new Point(x3, y0), new Point(x4, y1), new Point(x4, y2)); + ctx.CubicBezierTo(new Point(x4, y3), new Point(x3, y4), new Point(x2, y4)); + ctx.CubicBezierTo(new Point(x1, y4), new Point(x0, y3), new Point(x0, y2)); + ctx.CubicBezierTo(new Point(x0, y1), new Point(x1, y0), new Point(x2, y0)); + ctx.EndFigure(true); + } + + PlatformImpl = impl; + } + + /// + public override Geometry Clone() + { + return new EllipseGeometry(Bounds); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/FillRule.cs b/src/Avalonia.SceneGraph/Media/FillRule.cs new file mode 100644 index 0000000000..537bb4fb5b --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/FillRule.cs @@ -0,0 +1,8 @@ +namespace Avalonia.Media +{ + public enum FillRule + { + EvenOdd, + NonZero + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/FontStyle.cs b/src/Avalonia.SceneGraph/Media/FontStyle.cs new file mode 100644 index 0000000000..1320f9d70e --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/FontStyle.cs @@ -0,0 +1,26 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Defines the available font styles. + /// + public enum FontStyle + { + /// + /// A normal font. + /// + Normal, + + /// + /// An oblique font. + /// + Oblique, + + /// + /// An italic font. + /// + Italic, + } +} diff --git a/src/Avalonia.SceneGraph/Media/FontWeight.cs b/src/Avalonia.SceneGraph/Media/FontWeight.cs new file mode 100644 index 0000000000..776f14d647 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/FontWeight.cs @@ -0,0 +1,95 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Defines a set of predefined font weights. + /// + /// + /// As well as the values defined by this enumeration you can also pass any integer value by + /// casting it to , e.g. (FontWeight)550. + /// + public enum FontWeight + { + /// + /// Specifies a "thin" font weight. + /// + Thin = 100, + + /// + /// Specifies an "extra light" font weight. + /// + ExtraLight = 200, + + /// + /// Specifies an "ultra light" font weight. + /// + UltraLight = 200, + + /// + /// Specifies a "light" font weight. + /// + Light = 300, + + /// + /// Specifies a "normal" font weight. + /// + Normal = 400, + + /// + /// Specifies a "regular" font weight. + /// + Regular = 400, + + /// + /// Specifies a "medium" font weight. + /// + Medium = 500, + + /// + /// Specifies a "demi-bold" font weight. + /// + DemiBold = 600, + + /// + /// Specifies a "semi-bold" font weight. + /// + SemiBold = 600, + + /// + /// Specifies a "bold" font weight. + /// + Bold = 700, + + /// + /// Specifies an "extra bold" font weight. + /// + ExtraBold = 800, + + /// + /// Specifies an "ultra bold" font weight. + /// + UltraBold = 800, + + /// + /// Specifies a "black" font weight. + /// + Black = 900, + + /// + /// Specifies a "heavy" font weight. + /// + Heavy = 900, + + /// + /// Specifies an "extra black" font weight. + /// + ExtraBlack = 950, + + /// + /// Specifies an "ultra black" font weight. + /// + UltraBlack = 950 + } +} diff --git a/src/Avalonia.SceneGraph/Media/FormattedText.cs b/src/Avalonia.SceneGraph/Media/FormattedText.cs new file mode 100644 index 0000000000..af065d2f86 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/FormattedText.cs @@ -0,0 +1,215 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using Avalonia.Platform; + +namespace Avalonia.Media +{ + /// + /// Represents a piece of text with formatting. + /// + public class FormattedText : AvaloniaDisposable + { + /// + /// Initializes a new instance of the class. + /// + /// The text. + /// The font family. + /// The font size. + /// The font style. + /// The text alignment. + /// The font weight. + public FormattedText( + string text, + string fontFamilyName, + double fontSize, + FontStyle fontStyle, + TextAlignment textAlignment, + FontWeight fontWeight) + { + Contract.Requires(text != null); + Contract.Requires(fontFamilyName != null); + Contract.Requires(fontSize > 0); + + Text = text; + FontFamilyName = fontFamilyName; + FontSize = fontSize; + FontStyle = fontStyle; + FontWeight = fontWeight; + TextAlignment = textAlignment; + + var platform = AvaloniaLocator.Current.GetService(); + + if (platform == null) + { + throw new Exception("Could not create FormattedText: IPlatformRenderInterface not registered."); + } + + PlatformImpl = platform.CreateFormattedText( + text, + fontFamilyName, + fontSize, + fontStyle, + textAlignment, + fontWeight); + } + + /// + /// Gets or sets the constraint of the text. + /// + public Size Constraint + { + get + { + CheckDisposed(); + return PlatformImpl.Constraint; + } + set + { + CheckDisposed(); + PlatformImpl.Constraint = value; + } + } + + /// + /// Gets the font family. + /// + public string FontFamilyName + { + get; + private set; + } + + /// + /// Gets the font size. + /// + public double FontSize + { + get; + private set; + } + + /// + /// Gets the font style. + /// + public FontStyle FontStyle + { + get; + private set; + } + + /// + /// Gets the font weight. + /// + public FontWeight FontWeight + { + get; + private set; + } + + /// + /// Gets the text. + /// + public string Text + { + get; + private set; + } + + /// + /// Gets platform-specific platform implementation. + /// + public IFormattedTextImpl PlatformImpl + { + get; } + + /// + /// Gets the text alignment. + /// + public TextAlignment TextAlignment + { + get; + private set; + } + + /// + /// Disposes of unmanaged resources associated with the formatted text. + /// + protected override void DoDispose() + { + PlatformImpl.Dispose(); + } + + /// + /// Gets the lines in the text. + /// + /// + /// A collection of objects. + /// + public IEnumerable GetLines() + { + CheckDisposed(); + return PlatformImpl.GetLines(); + } + + /// + /// Hit tests a point in the text. + /// + /// The point. + /// + /// A describing the result of the hit test. + /// + public TextHitTestResult HitTestPoint(Point point) + { + CheckDisposed(); + return PlatformImpl.HitTestPoint(point); + } + + /// + /// Gets the bounds rectangle that the specified character occupies. + /// + /// The index of the character. + /// The character bounds. + public Rect HitTestTextPosition(int index) + { + CheckDisposed(); + return PlatformImpl.HitTestTextPosition(index); + } + + /// + /// Gets the bounds rectangles that the specified text range occupies. + /// + /// The index of the first character. + /// The number of characters in the text range. + /// The character bounds. + public IEnumerable HitTestTextRange(int index, int length) + { + CheckDisposed(); + return PlatformImpl.HitTestTextRange(index, length); + } + + /// + /// Gets the size of the text, taking into account. + /// + /// The bounds box of the text. + public Size Measure() + { + CheckDisposed(); + return PlatformImpl.Measure(); + } + + /// + /// Sets the foreground brush for the specified text range. + /// + /// The brush. + /// The start of the text range. + /// The length of the text range. + public void SetForegroundBrush(IBrush brush, int startIndex, int length) + { + CheckDisposed(); + PlatformImpl.SetForegroundBrush(brush, startIndex, length); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/FormattedTextLine.cs b/src/Avalonia.SceneGraph/Media/FormattedTextLine.cs new file mode 100644 index 0000000000..245e2bc108 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/FormattedTextLine.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Stores information about a line of . + /// + public class FormattedTextLine + { + /// + /// Initializes a new instance of the class. + /// + /// The length of the line, in characters. + /// The height of the line, in pixels. + public FormattedTextLine(int length, double height) + { + Length = length; + Height = height; + } + + /// + /// Gets the length of the line, in characters. + /// + public int Length { get; } + + /// + /// Gets the height of the line, in pixels. + /// + public double Height { get; } + } +} diff --git a/src/Avalonia.SceneGraph/Media/Geometry.cs b/src/Avalonia.SceneGraph/Media/Geometry.cs new file mode 100644 index 0000000000..e6eaaff042 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Geometry.cs @@ -0,0 +1,70 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Platform; + +namespace Avalonia.Media +{ + /// + /// Defines a geometric shape. + /// + public abstract class Geometry : AvaloniaObject + { + /// + /// Defines the property. + /// + public static readonly StyledProperty TransformProperty = + AvaloniaProperty.Register("Transform"); + + /// + /// Initializes static members of the class. + /// + static Geometry() + { + TransformProperty.Changed.Subscribe(x => + { + ((Geometry)x.Sender).PlatformImpl.Transform = ((Transform)x.NewValue).Value; + }); + } + + /// + /// Gets the geometry's bounding rectangle. + /// + public Rect Bounds => PlatformImpl.Bounds; + + /// + /// Gets the platform-specific implementation of the geometry. + /// + public virtual IGeometryImpl PlatformImpl + { + get; + protected set; + } + + /// + /// Gets or sets a transform to apply to the geometry. + /// + public Transform Transform + { + get { return GetValue(TransformProperty); } + set { SetValue(TransformProperty, value); } + } + + /// + /// Clones the geometry. + /// + /// A cloned geometry. + public abstract Geometry Clone(); + + /// + /// Gets the geometry's bounding rectangle with the specified stroke thickness. + /// + /// The stroke thickness. + /// The bounding rectangle. + public Rect GetRenderBounds(double strokeThickness) + { + return PlatformImpl.GetRenderBounds(strokeThickness); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/GradientBrush.cs b/src/Avalonia.SceneGraph/Media/GradientBrush.cs new file mode 100644 index 0000000000..4c62a2b836 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/GradientBrush.cs @@ -0,0 +1,35 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Collections.Generic; +using Avalonia.Metadata; + +namespace Avalonia.Media +{ + public abstract class GradientBrush : Brush + { + public static readonly StyledProperty SpreadMethodProperty = + AvaloniaProperty.Register(nameof(SpreadMethod)); + + public static readonly StyledProperty> GradientStopsProperty = + AvaloniaProperty.Register>(nameof(Opacity)); + + public GradientBrush() + { + this.GradientStops = new List(); + } + + public GradientSpreadMethod SpreadMethod + { + get { return GetValue(SpreadMethodProperty); } + set { SetValue(SpreadMethodProperty, value); } + } + + [Content] + public List GradientStops + { + get { return GetValue(GradientStopsProperty); } + set { SetValue(GradientStopsProperty, value); } + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/GradientSpreadMethod.cs b/src/Avalonia.SceneGraph/Media/GradientSpreadMethod.cs new file mode 100644 index 0000000000..4020a6afbd --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/GradientSpreadMethod.cs @@ -0,0 +1,18 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Media +{ + public enum GradientSpreadMethod + { + Pad, + Reflect, + Repeat + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/GradientStop.cs b/src/Avalonia.SceneGraph/Media/GradientStop.cs new file mode 100644 index 0000000000..78dd32a18a --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/GradientStop.cs @@ -0,0 +1,39 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// GradientStop + /// + public sealed class GradientStop + { + /// + /// Initializes a new instance of the class. + /// + public GradientStop() { } + + /// + /// Initializes a new instance of the class. + /// + /// The color + /// The offset + public GradientStop(Color color, double offset) + { + Color = color; + Offset = offset; + } + + // TODO: Make these dependency properties. + + /// + /// The offset + /// + public double Offset { get; set; } + + /// + /// The color + /// + public Color Color { get; set; } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/IBrush.cs b/src/Avalonia.SceneGraph/Media/IBrush.cs new file mode 100644 index 0000000000..52b4d959cd --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/IBrush.cs @@ -0,0 +1,16 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Describes how an area is painted. + /// + public interface IBrush + { + /// + /// Gets the opacity of the brush. + /// + double Opacity { get; } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/IDrawingContext.cs b/src/Avalonia.SceneGraph/Media/IDrawingContext.cs new file mode 100644 index 0000000000..31f5b0d38a --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/IDrawingContext.cs @@ -0,0 +1,86 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Media.Imaging; + +namespace Avalonia.Media +{ + /// + /// Defines the interface through which drawing occurs. + /// + public interface IDrawingContextImpl : IDisposable + { + /// + /// Gets or sets the current transform of the drawing context. + /// + Matrix Transform { get; set; } + + /// + /// Draws a bitmap image. + /// + /// The bitmap image. + /// The opacity to draw with. + /// The rect in the image to draw. + /// The rect in the output to draw to. + void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect); + + /// + /// Draws a line. + /// + /// The stroke pen. + /// The first point of the line. + /// The second point of the line. + void DrawLine(Pen pen, Point p1, Point p2); + + /// + /// Draws a geometry. + /// + /// The fill brush. + /// The stroke pen. + /// The geometry. + void DrawGeometry(IBrush brush, Pen pen, Geometry geometry); + + /// + /// Draws the outline of a rectangle. + /// + /// The pen. + /// The rectangle bounds. + /// The corner radius. + void DrawRectangle(Pen pen, Rect rect, float cornerRadius = 0.0f); + + /// + /// Draws text. + /// + /// The foreground brush. + /// The upper-left corner of the text. + /// The text. + void DrawText(IBrush foreground, Point origin, FormattedText text); + + /// + /// Draws a filled rectangle. + /// + /// The brush. + /// The rectangle bounds. + /// The corner radius. + void FillRectangle(IBrush brush, Rect rect, float cornerRadius = 0.0f); + + /// + /// Pushes a clip rectange. + /// + /// The clip rectangle. + /// A disposable used to undo the clip rectangle. + void PushClip(Rect clip); + + void PopClip(); + + /// + /// Pushes an opacity value. + /// + /// The opacity. + /// A disposable used to undo the opacity. + void PushOpacity(double opacity); + + void PopOpacity(); + } +} diff --git a/src/Avalonia.SceneGraph/Media/ISolidColorBrush.cs b/src/Avalonia.SceneGraph/Media/ISolidColorBrush.cs new file mode 100644 index 0000000000..73a9fb6795 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/ISolidColorBrush.cs @@ -0,0 +1,16 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Fills an area with a solid color. + /// + public interface ISolidColorBrush : IBrush + { + /// + /// Gets the color of the brush. + /// + Color Color { get; } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/ImageBush.cs b/src/Avalonia.SceneGraph/Media/ImageBush.cs new file mode 100644 index 0000000000..caf43d19a2 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/ImageBush.cs @@ -0,0 +1,44 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Media.Imaging; + +namespace Avalonia.Media +{ + /// + /// Paints an area with an . + /// + public class ImageBrush : TileBrush + { + /// + /// Defines the property. + /// + public static readonly StyledProperty SourceProperty = + AvaloniaProperty.Register("Source"); + + /// + /// Initializes a new instance of the class. + /// + public ImageBrush() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The image to draw. + public ImageBrush(IBitmap source) + { + Source = source; + } + + /// + /// Gets or sets the image to draw. + /// + public IBitmap Source + { + get { return GetValue(SourceProperty); } + set { SetValue(SourceProperty, value); } + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/Imaging/Bitmap.cs b/src/Avalonia.SceneGraph/Media/Imaging/Bitmap.cs new file mode 100644 index 0000000000..5b84b0ddd3 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Imaging/Bitmap.cs @@ -0,0 +1,69 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.IO; +using Avalonia.Platform; + +namespace Avalonia.Media.Imaging +{ + /// + /// Holds a bitmap image. + /// + public class Bitmap : IBitmap + { + /// + /// Initializes a new instance of the class. + /// + /// The filename of the bitmap. + public Bitmap(string fileName) + { + IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); + PlatformImpl = factory.LoadBitmap(fileName); + } + + /// + /// Initializes a new instance of the class. + /// + /// The stream to read the bitmap from. + public Bitmap(Stream stream) + { + IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); + PlatformImpl = factory.LoadBitmap(stream); + } + + /// + /// Initializes a new instance of the class. + /// + /// A platform-specific bitmap implementation. + protected Bitmap(IBitmapImpl impl) + { + PlatformImpl = impl; + } + + /// + /// Gets the width of the bitmap, in pixels. + /// + public int PixelWidth => PlatformImpl.PixelWidth; + + /// + /// Gets the height of the bitmap, in pixels. + /// + public int PixelHeight => PlatformImpl.PixelHeight; + + /// + /// Gets the platform-specific bitmap implementation. + /// + public IBitmapImpl PlatformImpl + { + get; } + + /// + /// Saves the bitmap to a file. + /// + /// The filename. + public void Save(string fileName) + { + PlatformImpl.Save(fileName); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/Imaging/IBitmap.cs b/src/Avalonia.SceneGraph/Media/Imaging/IBitmap.cs new file mode 100644 index 0000000000..b07858799a --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Imaging/IBitmap.cs @@ -0,0 +1,34 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Platform; + +namespace Avalonia.Media.Imaging +{ + /// + /// Represents a bitmap image. + /// + public interface IBitmap + { + /// + /// Gets the width of the bitmap, in pixels. + /// + int PixelWidth { get; } + + /// + /// Gets the height of the bitmap, in pixels. + /// + int PixelHeight { get; } + + /// + /// Gets the platform-specific bitmap implementation. + /// + IBitmapImpl PlatformImpl { get; } + + /// + /// Saves the bitmap to a file. + /// + /// The filename. + void Save(string fileName); + } +} diff --git a/src/Avalonia.SceneGraph/Media/Imaging/RenderTargetBitmap.cs b/src/Avalonia.SceneGraph/Media/Imaging/RenderTargetBitmap.cs new file mode 100644 index 0000000000..1687dc811e --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Imaging/RenderTargetBitmap.cs @@ -0,0 +1,52 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Platform; +using Avalonia.Rendering; + +namespace Avalonia.Media.Imaging +{ + /// + /// A bitmap that holds the rendering of a . + /// + public class RenderTargetBitmap : Bitmap, IDisposable, IRenderTarget + { + /// + /// Initializes a new instance of the class. + /// + /// The width of the bitmap. + /// The height of the bitmap. + public RenderTargetBitmap(int width, int height) + : base(CreateImpl(width, height)) + { + } + + /// + /// Gets the platform-specific bitmap implementation. + /// + public new IRenderTargetBitmapImpl PlatformImpl => (IRenderTargetBitmapImpl)base.PlatformImpl; + + /// + /// Disposes of the bitmap. + /// + public void Dispose() + { + PlatformImpl.Dispose(); + } + + /// + /// Creates a platform-specific imlementation for a . + /// + /// The width of the bitmap. + /// The height of the bitmap. + /// The platform-specific implementation. + private static IBitmapImpl CreateImpl(int width, int height) + { + IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); + return factory.CreateRenderTargetBitmap(width, height); + } + + public DrawingContext CreateDrawingContext() => PlatformImpl.CreateDrawingContext(); + } +} diff --git a/src/Avalonia.SceneGraph/Media/LineGeometry.cs b/src/Avalonia.SceneGraph/Media/LineGeometry.cs new file mode 100644 index 0000000000..2783d7fb26 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/LineGeometry.cs @@ -0,0 +1,44 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Platform; + +namespace Avalonia.Media +{ + /// + /// Represents the geometry of a line. + /// + public class LineGeometry : Geometry + { + private Point _startPoint; + private Point _endPoint; + + /// + /// Initializes a new instance of the class. + /// + /// The start point. + /// The end point. + public LineGeometry(Point startPoint, Point endPoint) + { + _startPoint = startPoint; + _endPoint = endPoint; + IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); + IStreamGeometryImpl impl = factory.CreateStreamGeometry(); + + using (IStreamGeometryContextImpl context = impl.Open()) + { + context.BeginFigure(_startPoint, false); + context.LineTo(_endPoint); + context.EndFigure(false); + } + + PlatformImpl = impl; + } + + /// + public override Geometry Clone() + { + return new LineGeometry(_startPoint, _endPoint); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/LineSegment.cs b/src/Avalonia.SceneGraph/Media/LineSegment.cs new file mode 100644 index 0000000000..d81f67d99f --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/LineSegment.cs @@ -0,0 +1,31 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + public sealed class LineSegment : PathSegment + { + /// + /// Defines the property. + /// + public static readonly StyledProperty PointProperty + = AvaloniaProperty.Register(nameof(Point)); + + /// + /// Gets or sets the point. + /// + /// + /// The point. + /// + public Point Point + { + get { return GetValue(PointProperty); } + set { SetValue(PointProperty, value); } + } + + protected internal override void ApplyTo(StreamGeometryContext ctx) + { + ctx.LineTo(Point); + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/LinearGradientBrush.cs b/src/Avalonia.SceneGraph/Media/LinearGradientBrush.cs new file mode 100644 index 0000000000..6ba2c5093e --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/LinearGradientBrush.cs @@ -0,0 +1,45 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// A brush that draws with a linear gradient. + /// + public sealed class LinearGradientBrush : GradientBrush + { + /// + /// Defines the property. + /// + public static readonly StyledProperty StartPointProperty = + AvaloniaProperty.Register( + nameof(StartPoint), + RelativePoint.TopLeft); + + /// + /// Defines the property. + /// + public static readonly StyledProperty EndPointProperty = + AvaloniaProperty.Register( + nameof(EndPoint), + RelativePoint.BottomRight); + + /// + /// Gets or sets the start point for the gradient. + /// + public RelativePoint StartPoint + { + get { return GetValue(StartPointProperty); } + set { SetValue(StartPointProperty, value); } + } + + /// + /// Gets or sets the end point for the gradient. + /// + public RelativePoint EndPoint + { + get { return GetValue(EndPointProperty); } + set { SetValue(EndPointProperty, value); } + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/MatrixTransform.cs b/src/Avalonia.SceneGraph/Media/MatrixTransform.cs new file mode 100644 index 0000000000..4fa0e3adc1 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/MatrixTransform.cs @@ -0,0 +1,51 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Media +{ + /// + /// Transforms an according to a . + /// + public class MatrixTransform : Transform + { + /// + /// Defines the property. + /// + public static readonly StyledProperty MatrixProperty = + AvaloniaProperty.Register("Matrix", Matrix.Identity); + + /// + /// Initializes a new instance of the class. + /// + public MatrixTransform() + { + this.GetObservable(MatrixProperty).Subscribe(_ => RaiseChanged()); + } + + /// + /// Initializes a new instance of the class. + /// + /// The matrix. + public MatrixTransform(Matrix matrix) + : this() + { + Matrix = matrix; + } + + /// + /// Gets or sets the matrix. + /// + public Matrix Matrix + { + get { return GetValue(MatrixProperty); } + set { SetValue(MatrixProperty, value); } + } + + /// + /// Gets the matrix. + /// + public override Matrix Value => Matrix; + } +} diff --git a/src/Avalonia.SceneGraph/Media/MediaExtensions.cs b/src/Avalonia.SceneGraph/Media/MediaExtensions.cs new file mode 100644 index 0000000000..95d17b454e --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/MediaExtensions.cs @@ -0,0 +1,56 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Media +{ + /// + /// Provides extension methods for Avalonia media. + /// + public static class MediaExtensions + { + /// + /// Calculates scaling based on a value. + /// + /// The stretch mode. + /// The size of the destination viewport. + /// The size of the source. + /// A vector with the X and Y scaling factors. + public static Vector CalculateScaling(this Stretch stretch, Size destinationSize, Size sourceSize) + { + double scaleX = 1; + double scaleY = 1; + + if (stretch != Stretch.None) + { + scaleX = destinationSize.Width / sourceSize.Width; + scaleY = destinationSize.Height / sourceSize.Height; + + switch (stretch) + { + case Stretch.Uniform: + scaleX = scaleY = Math.Min(scaleX, scaleY); + break; + case Stretch.UniformToFill: + scaleX = scaleY = Math.Max(scaleX, scaleY); + break; + } + } + + return new Vector(scaleX, scaleY); + } + + /// + /// Calculates a scaled size based on a value. + /// + /// The stretch mode. + /// The size of the destination viewport. + /// The size of the source. + /// The size of the stretched source. + public static Size CalculateSize(this Stretch stretch, Size destinationSize, Size sourceSize) + { + return sourceSize * stretch.CalculateScaling(destinationSize, sourceSize); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/Mutable/SolidColorBrush.cs b/src/Avalonia.SceneGraph/Media/Mutable/SolidColorBrush.cs new file mode 100644 index 0000000000..eb2698cfed --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Mutable/SolidColorBrush.cs @@ -0,0 +1,35 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media.Mutable +{ + /// + /// Fills an area with a solid color. + /// + /// + /// This is a mutable version of the normal immutable + /// for use in XAML. XAML really needs support for immutable data... + /// + public class SolidColorBrush : Brush, ISolidColorBrush + { + public static readonly DirectProperty ColorProperty = + AvaloniaProperty.RegisterDirect( + "Color", + o => o.Color, + (o, v) => o.Color = v); + + /// + /// Gets the color of the brush. + /// + public Color Color { get; set; } + + /// + /// Returns a string representation of the brush. + /// + /// A string representation of the brush. + public override string ToString() + { + return Color.ToString(); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/PathFigure.cs b/src/Avalonia.SceneGraph/Media/PathFigure.cs new file mode 100644 index 0000000000..6a438a85ee --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/PathFigure.cs @@ -0,0 +1,102 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Metadata; + +namespace Avalonia.Media +{ + public sealed class PathFigure : AvaloniaObject + { + /// + /// Defines the property. + /// + public static readonly StyledProperty IsClosedProperty + = AvaloniaProperty.Register(nameof(IsClosed), true); + /// + /// Defines the property. + /// + public static readonly StyledProperty IsFilledProperty + = AvaloniaProperty.Register(nameof(IsFilled), true); + /// + /// Defines the property. + /// + public static readonly DirectProperty SegmentsProperty + = AvaloniaProperty.RegisterDirect(nameof(Segments), f => f.Segments, (f, s) => f.Segments = s); + /// + /// Defines the property. + /// + public static readonly StyledProperty StartPointProperty + = AvaloniaProperty.Register(nameof(StartPoint)); + + /// + /// Initializes a new instance of the class. + /// + public PathFigure() + { + Segments = new PathSegments(); + } + + /// + /// Gets or sets a value indicating whether this instance is closed. + /// + /// + /// true if this instance is closed; otherwise, false. + /// + public bool IsClosed + { + get { return GetValue(IsClosedProperty); } + set { SetValue(IsClosedProperty, value); } + } + + /// + /// Gets or sets a value indicating whether this instance is filled. + /// + /// + /// true if this instance is filled; otherwise, false. + /// + public bool IsFilled + { + get { return GetValue(IsFilledProperty); } + set { SetValue(IsFilledProperty, value); } + } + + /// + /// Gets or sets the segments. + /// + /// + /// The segments. + /// + [Content] + public PathSegments Segments + { + get { return _segments; } + set { SetAndRaise(SegmentsProperty, ref _segments, value); } + } + + /// + /// Gets or sets the start point. + /// + /// + /// The start point. + /// + public Point StartPoint + { + get { return GetValue(StartPointProperty); } + set { SetValue(StartPointProperty, value); } + } + + internal void ApplyTo(StreamGeometryContext ctx) + { + ctx.BeginFigure(StartPoint, IsFilled); + + foreach (var segment in Segments) + { + segment.ApplyTo(ctx); + } + + ctx.EndFigure(IsClosed); + } + + private PathSegments _segments; + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/PathGeometry.cs b/src/Avalonia.SceneGraph/Media/PathGeometry.cs new file mode 100644 index 0000000000..df3dd47c8a --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/PathGeometry.cs @@ -0,0 +1,123 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Collections; +using Avalonia.Metadata; +using Avalonia.Platform; +using System; + +namespace Avalonia.Media +{ + public class PathGeometry : StreamGeometry + { + /// + /// Defines the property. + /// + public static readonly DirectProperty FiguresProperty = + AvaloniaProperty.RegisterDirect(nameof(Figures), g => g.Figures, (g, f) => g.Figures = f); + + /// + /// Defines the property. + /// + public static readonly StyledProperty FillRuleProperty = + AvaloniaProperty.Register(nameof(FillRule)); + + static PathGeometry() + { + FiguresProperty.Changed.Subscribe(onNext: v => + { + (v.Sender as PathGeometry)?.OnFiguresChanged(v.OldValue as PathFigures, v.NewValue as PathFigures); + }); + } + + /// + /// Initializes a new instance of the class. + /// + public PathGeometry() + { + Figures = new PathFigures(); + } + + /// + /// Gets or sets the figures. + /// + /// + /// The figures. + /// + [Content] + public PathFigures Figures + { + get { return _figures; } + set { SetAndRaise(FiguresProperty, ref _figures, value); } + } + + /// + /// Gets or sets the fill rule. + /// + /// + /// The fill rule. + /// + public FillRule FillRule + { + get { return GetValue(FillRuleProperty); } + set { SetValue(FillRuleProperty, value); } + } + + public override IGeometryImpl PlatformImpl + { + get + { + PrepareIfNeeded(); + return base.PlatformImpl; + } + + protected set + { + base.PlatformImpl = value; + } + } + + public override Geometry Clone() + { + PrepareIfNeeded(); + + return base.Clone(); + } + + public void PrepareIfNeeded() + { + if (_isDirty) + { + _isDirty = false; + + using (var ctx = Open()) + { + ctx.SetFillRule(FillRule); + foreach (var f in Figures) + { + f.ApplyTo(ctx); + } + } + } + } + + internal void NotifyChanged() + { + _isDirty = true; + } + + private PathFigures _figures; + private IDisposable _figuresObserver = null; + private IDisposable _figuresPropertiesObserver = null; + private bool _isDirty = true; + + private void OnFiguresChanged(PathFigures oldValue, PathFigures newValue) + { + _figuresObserver?.Dispose(); + _figuresPropertiesObserver?.Dispose(); + + _figuresObserver = newValue?.ForEachItem(f => NotifyChanged(), f => NotifyChanged(), () => NotifyChanged()); + _figuresPropertiesObserver = newValue?.TrackItemPropertyChanged(t => NotifyChanged()); + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/PathGeometryCollections.cs b/src/Avalonia.SceneGraph/Media/PathGeometryCollections.cs new file mode 100644 index 0000000000..e161cfc32d --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/PathGeometryCollections.cs @@ -0,0 +1,15 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Collections; + +namespace Avalonia.Media +{ + public sealed class PathFigures : AvaloniaList + { + } + + public sealed class PathSegments : AvaloniaList + { + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/PathMarkupParser.cs b/src/Avalonia.SceneGraph/Media/PathMarkupParser.cs new file mode 100644 index 0000000000..a089d71127 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/PathMarkupParser.cs @@ -0,0 +1,350 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + +namespace Avalonia.Media +{ + /// + /// Parses a path markup string. + /// + public class PathMarkupParser + { + private static readonly Dictionary Commands = new Dictionary + { + { 'F', Command.FillRule }, + { 'f', Command.FillRule }, + { 'M', Command.Move }, + { 'm', Command.MoveRelative }, + { 'L', Command.Line }, + { 'l', Command.LineRelative }, + { 'H', Command.HorizontalLine }, + { 'h', Command.HorizontalLineRelative }, + { 'V', Command.VerticalLine }, + { 'v', Command.VerticalLineRelative }, + { 'C', Command.CubicBezierCurve }, + { 'c', Command.CubicBezierCurveRelative }, + { 'A', Command.Arc }, + { 'a', Command.Arc }, + { 'Z', Command.Close }, + { 'z', Command.Close }, + }; + + private StreamGeometry _geometry; + + private readonly StreamGeometryContext _context; + + /// + /// Initializes a new instance of the class. + /// + /// The geometry in which the path should be stored. + /// The context for . + public PathMarkupParser(StreamGeometry geometry, StreamGeometryContext context) + { + _geometry = geometry; + _context = context; + } + + /// + /// Defines the command currently being processed. + /// + private enum Command + { + None, + FillRule, + Move, + MoveRelative, + Line, + LineRelative, + HorizontalLine, + HorizontalLineRelative, + VerticalLine, + VerticalLineRelative, + CubicBezierCurve, + CubicBezierCurveRelative, + Arc, + Close, + Eof, + } + + /// + /// Parses the specified markup string. + /// + /// The markup string. + public void Parse(string s) + { + bool openFigure = false; + + using (StringReader reader = new StringReader(s)) + { + Command lastCommand = Command.None; + Command command; + Point point = new Point(); + + while ((command = ReadCommand(reader, lastCommand)) != Command.Eof) + { + switch (command) + { + case Command.FillRule: + // TODO: Implement. + reader.Read(); + break; + + case Command.Move: + case Command.MoveRelative: + if (openFigure) + { + _context.EndFigure(false); + } + + point = command == Command.Move ? + ReadPoint(reader) : + ReadRelativePoint(reader, point); + + _context.BeginFigure(point, true); + openFigure = true; + break; + + case Command.Line: + point = ReadPoint(reader); + _context.LineTo(point); + break; + + case Command.LineRelative: + point = ReadRelativePoint(reader, point); + _context.LineTo(point); + break; + + case Command.HorizontalLine: + point = point.WithX(ReadDouble(reader)); + _context.LineTo(point); + break; + + case Command.HorizontalLineRelative: + point = new Point(point.X + ReadDouble(reader), point.Y); + _context.LineTo(point); + break; + + case Command.VerticalLine: + point = point.WithY(ReadDouble(reader)); + _context.LineTo(point); + break; + + case Command.VerticalLineRelative: + point = new Point(point.X, point.Y + ReadDouble(reader)); + _context.LineTo(point); + break; + + case Command.CubicBezierCurve: + { + Point point1 = ReadPoint(reader); + Point point2 = ReadPoint(reader); + point = ReadPoint(reader); + _context.CubicBezierTo(point1, point2, point); + break; + } + + case Command.CubicBezierCurveRelative: + { + Point point1 = ReadRelativePoint(reader, point); + Point point2 = ReadRelativePoint(reader, point); + _context.CubicBezierTo(point, point1, point2); + point = point2; + break; + } + + case Command.Arc: + { + //example: A10,10 0 0,0 10,20 + //format - size rotationAngle isLargeArcFlag sweepDirectionFlag endPoint + Size size = ReadSize(reader); + ReadSeparator(reader); + double rotationAngle = ReadDouble(reader); + ReadSeparator(reader); + bool isLargeArc = ReadBool(reader); + ReadSeparator(reader); + SweepDirection sweepDirection = ReadBool(reader) ? SweepDirection.Clockwise : SweepDirection.CounterClockwise; + point = ReadPoint(reader); + + _context.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection); + break; + } + + case Command.Close: + _context.EndFigure(true); + openFigure = false; + break; + + default: + throw new NotSupportedException("Unsupported command"); + } + + lastCommand = command; + } + + if (openFigure) + { + _context.EndFigure(false); + } + } + } + + private static Command ReadCommand(StringReader reader, Command lastCommand) + { + ReadWhitespace(reader); + + int i = reader.Peek(); + + if (i == -1) + { + return Command.Eof; + } + else + { + char c = (char)i; + Command command = Command.None; + + if (!Commands.TryGetValue(c, out command)) + { + if ((char.IsDigit(c) || c == '.' || c == '+' || c == '-') && + (lastCommand != Command.None)) + { + return lastCommand; + } + else + { + throw new InvalidDataException("Unexpected path command '" + c + "'."); + } + } + + reader.Read(); + return command; + } + } + + private static double ReadDouble(StringReader reader) + { + ReadWhitespace(reader); + + // TODO: Handle Infinity, NaN and scientific notation. + StringBuilder b = new StringBuilder(); + bool readSign = false; + bool readPoint = false; + bool readExponent = false; + int i; + + while ((i = reader.Peek()) != -1) + { + char c = char.ToUpperInvariant((char)i); + + if (((c == '+' || c == '-') && !readSign) || + (c == '.' && !readPoint) || + (c == 'E' && !readExponent) || + char.IsDigit(c)) + { + b.Append(c); + reader.Read(); + readSign = c == '+' || c == '-'; + readPoint = c == '.'; + + if (c == 'E') + { + readSign = false; + readExponent = c == 'E'; + } + } + else + { + break; + } + } + + return double.Parse(b.ToString(), CultureInfo.InvariantCulture); + } + + private static Point ReadPoint(StringReader reader) + { + ReadWhitespace(reader); + double x = ReadDouble(reader); + ReadSeparator(reader); + double y = ReadDouble(reader); + return new Point(x, y); + } + + private static Size ReadSize(StringReader reader) + { + ReadWhitespace(reader); + double x = ReadDouble(reader); + ReadSeparator(reader); + double y = ReadDouble(reader); + return new Size(x, y); + } + + private static bool ReadBool(StringReader reader) + { + return ReadDouble(reader) != 0; + } + + private static Point ReadRelativePoint(StringReader reader, Point lastPoint) + { + ReadWhitespace(reader); + double x = ReadDouble(reader); + ReadSeparator(reader); + double y = ReadDouble(reader); + return new Point(lastPoint.X + x, lastPoint.Y + y); + } + + private static void ReadSeparator(StringReader reader) + { + int i; + bool readComma = false; + + while ((i = reader.Peek()) != -1) + { + char c = (char)i; + + if (char.IsWhiteSpace(c)) + { + reader.Read(); + } + else if (c == ',') + { + if (readComma) + { + throw new InvalidDataException("Unexpected ','."); + } + + readComma = true; + reader.Read(); + } + else + { + break; + } + } + } + + private static void ReadWhitespace(StringReader reader) + { + int i; + + while ((i = reader.Peek()) != -1) + { + char c = (char)i; + + if (char.IsWhiteSpace(c)) + { + reader.Read(); + } + else + { + break; + } + } + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/PathSegment.cs b/src/Avalonia.SceneGraph/Media/PathSegment.cs new file mode 100644 index 0000000000..4ee2211763 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/PathSegment.cs @@ -0,0 +1,10 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + public abstract class PathSegment : AvaloniaObject + { + protected internal abstract void ApplyTo(StreamGeometryContext ctx); + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/Pen.cs b/src/Avalonia.SceneGraph/Media/Pen.cs new file mode 100644 index 0000000000..ddd8091801 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Pen.cs @@ -0,0 +1,95 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Describes how a stroke is drawn. + /// + public class Pen + { + /// + /// Initializes a new instance of the class. + /// + /// The brush used to draw. + /// The stroke thickness. + /// The dash style. + /// The dash cap. + /// The start line cap. + /// The end line cap. + /// The line join. + /// The miter limit. + public Pen( + IBrush brush, + double thickness = 1.0, + DashStyle dashStyle = null, + PenLineCap dashCap = PenLineCap.Flat, + PenLineCap startLineCap = PenLineCap.Flat, + PenLineCap endLineCap = PenLineCap.Flat, + PenLineJoin lineJoin = PenLineJoin.Miter, + double miterLimit = 10.0) + { + Brush = brush; + Thickness = thickness; + DashCap = dashCap; + StartLineCap = startLineCap; + EndLineCap = endLineCap; + LineJoin = lineJoin; + MiterLimit = miterLimit; + DashStyle = dashStyle; + } + + /// + /// Initializes a new instance of the class. + /// + /// The stroke color. + /// The stroke thickness. + /// The dash style. + /// The dash cap. + /// The start line cap. + /// The end line cap. + /// The line join. + /// The miter limit. + public Pen( + uint color, + double thickness = 1.0, + DashStyle dashStyle = null, + PenLineCap dashCap = PenLineCap.Flat, + PenLineCap startLineCap = PenLineCap.Flat, + PenLineCap endLineCap = PenLineCap.Flat, + PenLineJoin lineJoin = PenLineJoin.Miter, + double miterLimit = 10.0) + { + Brush = new SolidColorBrush(color); + Thickness = thickness; + StartLineCap = startLineCap; + EndLineCap = endLineCap; + LineJoin = lineJoin; + MiterLimit = miterLimit; + DashStyle = dashStyle; + DashCap = dashCap; + } + + /// + /// Gets the brush used to draw the stroke. + /// + public IBrush Brush { get; } + + /// + /// Gets the stroke thickness. + /// + public double Thickness { get; } = 1.0; + + public DashStyle DashStyle { get; } + + public PenLineCap DashCap { get; } + + public PenLineCap StartLineCap { get; } = PenLineCap.Flat; + + public PenLineCap EndLineCap { get; } = PenLineCap.Flat; + + public PenLineJoin LineJoin { get; } = PenLineJoin.Miter; + + public double MiterLimit { get; } = 10.0; + } +} diff --git a/src/Avalonia.SceneGraph/Media/PenLineCap.cs b/src/Avalonia.SceneGraph/Media/PenLineCap.cs new file mode 100644 index 0000000000..66b43f1b32 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/PenLineCap.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Media +{ + public enum PenLineCap + { + Flat, + Round, + Square, + Triangle + } +} diff --git a/src/Avalonia.SceneGraph/Media/PenLineJoin.cs b/src/Avalonia.SceneGraph/Media/PenLineJoin.cs new file mode 100644 index 0000000000..2ea098383b --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/PenLineJoin.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Media +{ + public enum PenLineJoin + { + Bevel, + Miter, + Round + } +} diff --git a/src/Avalonia.SceneGraph/Media/PolylineGeometry.cs b/src/Avalonia.SceneGraph/Media/PolylineGeometry.cs new file mode 100644 index 0000000000..709ad7a9f5 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/PolylineGeometry.cs @@ -0,0 +1,50 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Platform; + +namespace Avalonia.Media +{ + /// + /// Represents the geometry of an polyline or polygon. + /// + public class PolylineGeometry : Geometry + { + private IList _points; + private bool _isFilled; + + public PolylineGeometry(IList points, bool isFilled) + { + _points = points; + _isFilled = isFilled; + IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); + IStreamGeometryImpl impl = factory.CreateStreamGeometry(); + + using (IStreamGeometryContextImpl context = impl.Open()) + { + if (points.Count > 0) + { + context.BeginFigure(points[0], isFilled); + for (int i = 1; i < points.Count; i++) + { + context.LineTo(points[i]); + } + context.EndFigure(isFilled); + } + } + + PlatformImpl = impl; + } + + /// + public override Geometry Clone() + { + return new PolylineGeometry(new List(_points), _isFilled); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/QuadraticBezierSegment .cs b/src/Avalonia.SceneGraph/Media/QuadraticBezierSegment .cs new file mode 100644 index 0000000000..31c364edf4 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/QuadraticBezierSegment .cs @@ -0,0 +1,46 @@ +namespace Avalonia.Media +{ + public sealed class QuadraticBezierSegment : PathSegment + { + /// + /// Defines the property. + /// + public static readonly StyledProperty Point1Property + = AvaloniaProperty.Register(nameof(Point1)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty Point2Property + = AvaloniaProperty.Register(nameof(Point2)); + + /// + /// Gets or sets the point1. + /// + /// + /// The point1. + /// + public Point Point1 + { + get { return GetValue(Point1Property); } + set { SetValue(Point1Property, value); } + } + + /// + /// Gets or sets the point2. + /// + /// + /// The point2. + /// + public Point Point2 + { + get { return GetValue(Point2Property); } + set { SetValue(Point2Property, value); } + } + + protected internal override void ApplyTo(StreamGeometryContext ctx) + { + ctx.QuadraticBezierTo(Point1, Point2); + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/RadialGradientBrush.cs b/src/Avalonia.SceneGraph/Media/RadialGradientBrush.cs new file mode 100644 index 0000000000..70657abe88 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/RadialGradientBrush.cs @@ -0,0 +1,63 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Paints an area with a radial gradient. A focal point defines the beginning of the gradient, + /// and a circle defines the end point of the gradient. + /// + public sealed class RadialGradientBrush : GradientBrush + { + /// + /// Defines the property. + /// + public static readonly StyledProperty CenterProperty = + AvaloniaProperty.Register( + nameof(Center), + RelativePoint.Center); + + /// + /// Defines the property. + /// + public static readonly StyledProperty GradientOriginProperty = + AvaloniaProperty.Register( + nameof(GradientOrigin), + RelativePoint.Center); + + /// + /// Defines the property. + /// + public static readonly StyledProperty RadiusProperty = + AvaloniaProperty.Register( + nameof(Radius), + 0.5); + + /// + /// Gets or sets the start point for the gradient. + /// + public RelativePoint Center + { + get { return GetValue(CenterProperty); } + set { SetValue(CenterProperty, value); } + } + + /// + /// Gets or sets the location of the two-dimensional focal point that defines the beginning of the gradient. + /// + public RelativePoint GradientOrigin + { + get { return GetValue(GradientOriginProperty); } + set { SetValue(GradientOriginProperty, value); } + } + + /// + /// Gets or sets the horizontal and vertical radius of the outermost circle of the radial gradient. + /// + public double Radius + { + get { return GetValue(RadiusProperty); } + set { SetValue(RadiusProperty, value); } + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/RectangleGeometry.cs b/src/Avalonia.SceneGraph/Media/RectangleGeometry.cs new file mode 100644 index 0000000000..ef7deaa6f6 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/RectangleGeometry.cs @@ -0,0 +1,40 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Platform; + +namespace Avalonia.Media +{ + /// + /// Represents the geometry of a rectangle. + /// + public class RectangleGeometry : Geometry + { + /// + /// Initializes a new instance of the class. + /// + /// The rectangle bounds. + public RectangleGeometry(Rect rect) + { + IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); + IStreamGeometryImpl impl = factory.CreateStreamGeometry(); + + using (IStreamGeometryContextImpl context = impl.Open()) + { + context.BeginFigure(rect.TopLeft, true); + context.LineTo(rect.TopRight); + context.LineTo(rect.BottomRight); + context.LineTo(rect.BottomLeft); + context.EndFigure(true); + } + + PlatformImpl = impl; + } + + /// + public override Geometry Clone() + { + return new RectangleGeometry(Bounds); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/RotateTransform.cs b/src/Avalonia.SceneGraph/Media/RotateTransform.cs new file mode 100644 index 0000000000..be84cda974 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/RotateTransform.cs @@ -0,0 +1,51 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Media +{ + /// + /// Rotates an . + /// + public class RotateTransform : Transform + { + /// + /// Defines the property. + /// + public static readonly StyledProperty AngleProperty = + AvaloniaProperty.Register("Angle"); + + /// + /// Initializes a new instance of the class. + /// + public RotateTransform() + { + this.GetObservable(AngleProperty).Subscribe(_ => RaiseChanged()); + } + + /// + /// Initializes a new instance of the class. + /// + /// The angle, in degrees. + public RotateTransform(double angle) + : this() + { + Angle = angle; + } + + /// + /// Gets or sets the angle of rotation, in degrees. + /// + public double Angle + { + get { return GetValue(AngleProperty); } + set { SetValue(AngleProperty, value); } + } + + /// + /// Gets the tranform's . + /// + public override Matrix Value => Matrix.CreateRotation(Matrix.ToRadians(Angle)); + } +} diff --git a/src/Avalonia.SceneGraph/Media/ScaleTransform.cs b/src/Avalonia.SceneGraph/Media/ScaleTransform.cs new file mode 100644 index 0000000000..c0f291ed88 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/ScaleTransform.cs @@ -0,0 +1,69 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Media +{ + /// + /// Scale an . + /// + public class ScaleTransform : Transform + { + /// + /// Defines the property. + /// + public static readonly StyledProperty ScaleXProperty = + AvaloniaProperty.Register(nameof(ScaleX), 1); + + /// + /// Defines the property. + /// + public static readonly StyledProperty ScaleYProperty = + AvaloniaProperty.Register(nameof(ScaleY), 1); + + /// + /// Initializes a new instance of the class. + /// + public ScaleTransform() + { + this.GetObservable(ScaleXProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(ScaleYProperty).Subscribe(_ => RaiseChanged()); + } + + /// + /// Initializes a new instance of the class. + /// + /// ScaleX + /// ScaleY + public ScaleTransform(double scaleX, double scaleY) + : this() + { + ScaleX = scaleX; + ScaleY = scaleY; + } + + /// + /// Gets or sets the ScaleX property. + /// + public double ScaleX + { + get { return GetValue(ScaleXProperty); } + set { SetValue(ScaleXProperty, value); } + } + + /// + /// Gets or sets the ScaleY property. + /// + public double ScaleY + { + get { return GetValue(ScaleYProperty); } + set { SetValue(ScaleYProperty, value); } + } + + /// + /// Gets the tranform's . + /// + public override Matrix Value => Matrix.CreateScale(ScaleX, ScaleY); + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/SolidColorBrush.cs b/src/Avalonia.SceneGraph/Media/SolidColorBrush.cs new file mode 100644 index 0000000000..23e75a120b --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/SolidColorBrush.cs @@ -0,0 +1,50 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Fills an area with a solid color. + /// + public class SolidColorBrush : ISolidColorBrush + { + /// + /// Initializes a new instance of the class. + /// + /// The color to use. + /// The opacity of the brush. + public SolidColorBrush(Color color, double opacity = 1) + { + Color = color; + Opacity = opacity; + } + + /// + /// Initializes a new instance of the class. + /// + /// The color to use. + public SolidColorBrush(uint color) + : this(Color.FromUInt32(color)) + { + } + + /// + /// Gets the color of the brush. + /// + public Color Color { get; } + + /// + /// Gets the opacity of the brush. + /// + public double Opacity { get; } + + /// + /// Returns a string representation of the brush. + /// + /// A string representation of the brush. + public override string ToString() + { + return Color.ToString(); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/StreamGeometry.cs b/src/Avalonia.SceneGraph/Media/StreamGeometry.cs new file mode 100644 index 0000000000..b68f15d862 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/StreamGeometry.cs @@ -0,0 +1,65 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Platform; + +namespace Avalonia.Media +{ + /// + /// Represents the geometry of an arbitrarily complex shape. + /// + public class StreamGeometry : Geometry + { + /// + /// Initializes a new instance of the class. + /// + public StreamGeometry() + { + IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); + PlatformImpl = factory.CreateStreamGeometry(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The platform-specific implementation. + private StreamGeometry(IGeometryImpl impl) + { + PlatformImpl = impl; + } + + /// + /// Creates a from a string. + /// + /// The string. + /// A . + public static StreamGeometry Parse(string s) + { + StreamGeometry result = new StreamGeometry(); + + using (StreamGeometryContext ctx = result.Open()) + { + PathMarkupParser parser = new PathMarkupParser(result, ctx); + parser.Parse(s); + return result; + } + } + + /// + public override Geometry Clone() + { + return new StreamGeometry(((IStreamGeometryImpl)PlatformImpl).Clone()); + } + + /// + /// Opens the geometry to start defining it. + /// + /// + /// A which can be used to define the geometry. + /// + public StreamGeometryContext Open() + { + return new StreamGeometryContext(((IStreamGeometryImpl)PlatformImpl).Open()); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/StreamGeometryContext.cs b/src/Avalonia.SceneGraph/Media/StreamGeometryContext.cs new file mode 100644 index 0000000000..70b889f817 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/StreamGeometryContext.cs @@ -0,0 +1,113 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Platform; + +namespace Avalonia.Media +{ + /// + /// Describes a geometry using drawing commands. + /// + /// + /// This class is used to define the geometry of a . An instance + /// of is obtained by calling + /// . + /// + /// TODO: This class is just a wrapper around IStreamGeometryContextImpl: is it needed? + public class StreamGeometryContext : IDisposable + { + private readonly IStreamGeometryContextImpl _impl; + + /// + /// Initializes a new instance of the class. + /// + /// The platform-specific implementation. + public StreamGeometryContext(IStreamGeometryContextImpl impl) + { + _impl = impl; + } + + /// + /// Sets path's winding rule (default is EvenOdd). You should call this method before any calls to BeginFigure. If you wonder why, ask Direct2D guys about their design decisions. + /// + /// + + public void SetFillRule(FillRule fillRule) + { + _impl.SetFillRule(fillRule); + } + + /// + /// Draws an arc to the specified point. + /// + /// The destination point. + /// The radii of an oval whose perimeter is used to draw the angle. + /// The rotation angle of the oval that specifies the curve. + /// true to draw the arc greater than 180 degrees; otherwise, false. + /// + /// A value that indicates whether the arc is drawn in the Clockwise or Counterclockwise direction. + /// + public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) + { + _impl.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection); + } + + /// + /// Begins a new figure. + /// + /// The starting point for the figure. + /// Whether the figure is filled. + public void BeginFigure(Point startPoint, bool isFilled) + { + _impl.BeginFigure(startPoint, isFilled); + } + + /// + /// Draws a Bezier curve to the specified point. + /// + /// The first control point used to specify the shape of the curve. + /// The second control point used to specify the shape of the curve. + /// The destination point for the end of the curve. + public void CubicBezierTo(Point point1, Point point2, Point point3) + { + _impl.CubicBezierTo(point1, point2, point3); + } + + /// + /// Draws a quadratic Bezier curve to the specified point + /// + /// The control point used to specify the shape of the curve. + /// The destination point for the end of the curve. + public void QuadraticBezierTo(Point control, Point endPoint) + { + _impl.QuadraticBezierTo(control, endPoint); + } + + /// + /// Draws a line to the specified point. + /// + /// The destination point. + public void LineTo(Point point) + { + _impl.LineTo(point); + } + + /// + /// Ends the figure started by . + /// + /// Whether the figure is closed. + public void EndFigure(bool isClosed) + { + _impl.EndFigure(isClosed); + } + + /// + /// Finishes the drawing session. + /// + public void Dispose() + { + _impl.Dispose(); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/Stretch.cs b/src/Avalonia.SceneGraph/Media/Stretch.cs new file mode 100644 index 0000000000..3265d6eaa2 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Stretch.cs @@ -0,0 +1,35 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Describes how content is resized to fill its allocated space. + /// + public enum Stretch + { + /// + /// The content preserves its original size. + /// + None, + + /// + /// The content is resized to fill the destination dimensions. The aspect ratio is not + /// preserved. + /// + Fill, + + /// + /// The content is resized to fit in the destination dimensions while preserving its + /// native aspect ratio. + /// + Uniform, + + /// + /// The content is resized to completely fill the destination rectangle while preserving + /// its native aspect ratio. A portion of the content may not be visible if the aspect + /// ratio of the content does not match the aspect ratio of the allocated space. + /// + UniformToFill, + } +} diff --git a/src/Avalonia.SceneGraph/Media/SweepDirection.cs b/src/Avalonia.SceneGraph/Media/SweepDirection.cs new file mode 100644 index 0000000000..be1f74ee90 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/SweepDirection.cs @@ -0,0 +1,21 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Defines the direction an which elliptical arc is drawn. + /// + public enum SweepDirection + { + /// + /// Specifies that arcs are drawn in a counter clockwise (negative-angle) direction. + /// + CounterClockwise, + + /// + /// Specifies that arcs are drawn in a clockwise (positive-angle) direction. + /// + Clockwise, + } +} diff --git a/src/Avalonia.SceneGraph/Media/TextAlignment.cs b/src/Avalonia.SceneGraph/Media/TextAlignment.cs new file mode 100644 index 0000000000..5dd152c4a5 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/TextAlignment.cs @@ -0,0 +1,26 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Defines how text is aligned. + /// + public enum TextAlignment + { + /// + /// The text is left-aligned. + /// + Left, + + /// + /// The text is centered. + /// + Center, + + /// + /// The text is right-aligned. + /// + Right, + } +} diff --git a/src/Avalonia.SceneGraph/Media/TextHitTestResult.cs b/src/Avalonia.SceneGraph/Media/TextHitTestResult.cs new file mode 100644 index 0000000000..bf6b2e53db --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/TextHitTestResult.cs @@ -0,0 +1,26 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Holds a hit test result from a . + /// + public class TextHitTestResult + { + /// + /// Gets or sets a value indicating whether the point is inside the bounds of the text. + /// + public bool IsInside { get; set; } + + /// + /// Gets the index of the hit character in the text. + /// + public int TextPosition { get; set; } + + /// + /// Gets a value indicating whether the hit is on the trailing edge of the character. + /// + public bool IsTrailing { get; set; } + } +} diff --git a/src/Avalonia.SceneGraph/Media/TileBrush.cs b/src/Avalonia.SceneGraph/Media/TileBrush.cs new file mode 100644 index 0000000000..1708c7e9f6 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/TileBrush.cs @@ -0,0 +1,133 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Media +{ + /// + /// Describes how a is tiled. + /// + public enum TileMode + { + /// + /// A single repeat of the content will be displayed. + /// + None, + + /// + /// The content will be repeated horizontally, with alternate tiles mirrored. + /// + FlipX, + + /// + /// The content will be repeated vertically, with alternate tiles mirrored. + /// + FlipY, + + /// + /// The content will be repeated horizontally and vertically, with alternate tiles mirrored. + /// + FlipXY, + + /// + /// The content will be repeated. + /// + Tile + } + + /// + /// Base class for brushes which display repeating images. + /// + public abstract class TileBrush : Brush + { + /// + /// Defines the property. + /// + public static readonly StyledProperty AlignmentXProperty = + AvaloniaProperty.Register(nameof(AlignmentX), AlignmentX.Center); + + /// + /// Defines the property. + /// + public static readonly StyledProperty AlignmentYProperty = + AvaloniaProperty.Register(nameof(AlignmentY), AlignmentY.Center); + + /// + /// Defines the property. + /// + public static readonly StyledProperty DestinationRectProperty = + AvaloniaProperty.Register(nameof(DestinationRect), RelativeRect.Fill); + + /// + /// Defines the property. + /// + public static readonly StyledProperty SourceRectProperty = + AvaloniaProperty.Register(nameof(SourceRect), RelativeRect.Fill); + + /// + /// Defines the property. + /// + public static readonly StyledProperty StretchProperty = + AvaloniaProperty.Register(nameof(Stretch), Stretch.Uniform); + + /// + /// Defines the property. + /// + public static readonly StyledProperty TileModeProperty = + AvaloniaProperty.Register(nameof(TileMode)); + + /// + /// Gets or sets the horizontal alignment of a tile in the destination. + /// + public AlignmentX AlignmentX + { + get { return GetValue(AlignmentXProperty); } + set { SetValue(AlignmentXProperty, value); } + } + + /// + /// Gets or sets the horizontal alignment of a tile in the destination. + /// + public AlignmentY AlignmentY + { + get { return GetValue(AlignmentYProperty); } + set { SetValue(AlignmentYProperty, value); } + } + + /// + /// Gets or sets the rectangle on the destination in which to paint a tile. + /// + public RelativeRect DestinationRect + { + get { return GetValue(DestinationRectProperty); } + set { SetValue(DestinationRectProperty, value); } + } + + /// + /// Gets or sets the rectangle of the source image that will be displayed. + /// + public RelativeRect SourceRect + { + get { return GetValue(SourceRectProperty); } + set { SetValue(SourceRectProperty, value); } + } + + /// + /// Gets or sets a value controlling how the source rectangle will be stretched to fill + /// the destination rect. + /// + public Stretch Stretch + { + get { return (Stretch)GetValue(StretchProperty); } + set { SetValue(StretchProperty, value); } + } + + /// + /// Gets or sets the brush's tile mode. + /// + public TileMode TileMode + { + get { return (TileMode)GetValue(TileModeProperty); } + set { SetValue(TileModeProperty, value); } + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/Transform.cs b/src/Avalonia.SceneGraph/Media/Transform.cs new file mode 100644 index 0000000000..075411d3f7 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/Transform.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Animation; + +namespace Avalonia.Media +{ + /// + /// Represents a transform on an . + /// + public abstract class Transform : Animatable + { + /// + /// Raised when the transform changes. + /// + public event EventHandler Changed; + + /// + /// Gets the tranform's . + /// + public abstract Matrix Value { get; } + + /// + /// Raises the event. + /// + protected void RaiseChanged() + { + Changed?.Invoke(this, EventArgs.Empty); + } + } +} diff --git a/src/Avalonia.SceneGraph/Media/TransformGroup.cs b/src/Avalonia.SceneGraph/Media/TransformGroup.cs new file mode 100644 index 0000000000..6d94bf974e --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/TransformGroup.cs @@ -0,0 +1,57 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Collections; +using Avalonia.Metadata; + +namespace Avalonia.Media +{ + public class TransformGroup : Transform + { + /// + /// Defines the property. + /// + public static readonly AvaloniaProperty ChildrenProperty = + AvaloniaProperty.Register(nameof(Children)); + + public TransformGroup() + { + Children = new Transforms(); + } + + /// + /// Gets or sets the children. + /// + /// + /// The children. + /// + [Content] + public Transforms Children + { + get { return GetValue(ChildrenProperty); } + set { SetValue(ChildrenProperty, value); } + } + + /// + /// Gets the tranform's . + /// + public override Matrix Value + { + get + { + Matrix result = Matrix.Identity; + + foreach (var t in Children) + { + result *= t.Value; + } + + return result; + } + } + } + + public sealed class Transforms : AvaloniaList + { + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Media/TranslateTransform.cs b/src/Avalonia.SceneGraph/Media/TranslateTransform.cs new file mode 100644 index 0000000000..f680757925 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/TranslateTransform.cs @@ -0,0 +1,69 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Media +{ + /// + /// Translates (moves) an . + /// + public class TranslateTransform : Transform + { + /// + /// Defines the property. + /// + public static readonly StyledProperty XProperty = + AvaloniaProperty.Register("X"); + + /// + /// Defines the property. + /// + public static readonly StyledProperty YProperty = + AvaloniaProperty.Register("Y"); + + /// + /// Initializes a new instance of the class. + /// + public TranslateTransform() + { + this.GetObservable(XProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(YProperty).Subscribe(_ => RaiseChanged()); + } + + /// + /// Initializes a new instance of the class. + /// + /// Gets the horizontal offset of the translate. + /// Gets the vertical offset of the translate. + public TranslateTransform(double x, double y) + : this() + { + X = x; + Y = y; + } + + /// + /// Gets the horizontal offset of the translate. + /// + public double X + { + get { return GetValue(XProperty); } + set { SetValue(XProperty, value); } + } + + /// + /// Gets the vertical offset of the translate. + /// + public double Y + { + get { return GetValue(YProperty); } + set { SetValue(YProperty, value); } + } + + /// + /// Gets the tranform's . + /// + public override Matrix Value => Matrix.CreateTranslation(X, Y); + } +} diff --git a/src/Avalonia.SceneGraph/Media/VisualBrush.cs b/src/Avalonia.SceneGraph/Media/VisualBrush.cs new file mode 100644 index 0000000000..41a61f6022 --- /dev/null +++ b/src/Avalonia.SceneGraph/Media/VisualBrush.cs @@ -0,0 +1,44 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.VisualTree; + +namespace Avalonia.Media +{ + /// + /// Paints an area with an . + /// + public class VisualBrush : TileBrush + { + /// + /// Defines the property. + /// + public static readonly StyledProperty VisualProperty = + AvaloniaProperty.Register("Visual"); + + /// + /// Initializes a new instance of the class. + /// + public VisualBrush() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The visual to draw. + public VisualBrush(IVisual visual) + { + Visual = visual; + } + + /// + /// Gets or sets the visual to draw. + /// + public IVisual Visual + { + get { return GetValue(VisualProperty); } + set { SetValue(VisualProperty, value); } + } + } +} diff --git a/src/Avalonia.SceneGraph/Platform/IBitmapImpl.cs b/src/Avalonia.SceneGraph/Platform/IBitmapImpl.cs new file mode 100644 index 0000000000..fb47147907 --- /dev/null +++ b/src/Avalonia.SceneGraph/Platform/IBitmapImpl.cs @@ -0,0 +1,27 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Platform +{ + /// + /// Defines the platform-specific interface for a . + /// + public interface IBitmapImpl + { + /// + /// Gets the width of the bitmap, in pixels. + /// + int PixelWidth { get; } + + /// + /// Gets the height of the bitmap, in pixels. + /// + int PixelHeight { get; } + + /// + /// Saves the bitmap to a file. + /// + /// The filename. + void Save(string fileName); + } +} diff --git a/src/Avalonia.SceneGraph/Platform/IFormattedTextImpl.cs b/src/Avalonia.SceneGraph/Platform/IFormattedTextImpl.cs new file mode 100644 index 0000000000..14f9e987bd --- /dev/null +++ b/src/Avalonia.SceneGraph/Platform/IFormattedTextImpl.cs @@ -0,0 +1,66 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using Avalonia.Media; + +namespace Avalonia.Platform +{ + /// + /// Defines the platform-specific interface for . + /// + public interface IFormattedTextImpl : IDisposable + { + /// + /// Gets or sets the constraint of the text. + /// + Size Constraint { get; set; } + + /// + /// Gets the lines in the text. + /// + /// + /// A collection of objects. + /// + IEnumerable GetLines(); + + /// + /// Hit tests a point in the text. + /// + /// The point. + /// + /// A describing the result of the hit test. + /// + TextHitTestResult HitTestPoint(Point point); + + /// + /// Gets the bounds rectangle that the specified character occupies. + /// + /// The index of the character. + /// The character bounds. + Rect HitTestTextPosition(int index); + + /// + /// Gets the bounds rectangles that the specified text range occupies. + /// + /// The index of the first character. + /// The number of characters in the text range. + /// The character bounds. + IEnumerable HitTestTextRange(int index, int length); + + /// + /// Gets the size of the text, taking into account. + /// + /// The bounds box of the text. + Size Measure(); + + /// + /// Sets the foreground brush for the specified text range. + /// + /// The brush. + /// The start of the text range. + /// The length of the text range. + void SetForegroundBrush(IBrush brush, int startIndex, int length); + } +} diff --git a/src/Avalonia.SceneGraph/Platform/IGeometryImpl.cs b/src/Avalonia.SceneGraph/Platform/IGeometryImpl.cs new file mode 100644 index 0000000000..f3a3f655e5 --- /dev/null +++ b/src/Avalonia.SceneGraph/Platform/IGeometryImpl.cs @@ -0,0 +1,28 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Platform +{ + /// + /// Defines the platform-specific interface for . + /// + public interface IGeometryImpl + { + /// + /// Gets the geometry's bounding rectangle. + /// + Rect Bounds { get; } + + /// + /// Gets or sets a transform to apply to the geometry. + /// + Matrix Transform { get; set; } + + /// + /// Gets the geometry's bounding rectangle with the specified stroke thickness. + /// + /// The stroke thickness. + /// The bounding rectangle. + Rect GetRenderBounds(double strokeThickness); + } +} diff --git a/src/Avalonia.SceneGraph/Platform/IPlatformRenderInterface.cs b/src/Avalonia.SceneGraph/Platform/IPlatformRenderInterface.cs new file mode 100644 index 0000000000..4d40957a60 --- /dev/null +++ b/src/Avalonia.SceneGraph/Platform/IPlatformRenderInterface.cs @@ -0,0 +1,67 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.IO; +using Avalonia.Media; + +namespace Avalonia.Platform +{ + /// + /// Defines the main platform-specific interface for the rendering subsystem. + /// + public interface IPlatformRenderInterface + { + /// + /// Creates a formatted text implementation. + /// + /// The text. + /// The font family. + /// The font size. + /// The font style. + /// The text alignment. + /// The font weight. + /// An . + IFormattedTextImpl CreateFormattedText( + string text, + string fontFamilyName, + double fontSize, + FontStyle fontStyle, + TextAlignment textAlignment, + FontWeight fontWeight); + + /// + /// Creates a stream geometry implementation. + /// + /// An . + IStreamGeometryImpl CreateStreamGeometry(); + + /// + /// Creates a renderer. + /// + /// The platform handle for the renderer. + /// An . + IRenderTarget CreateRenderer(IPlatformHandle handle); + + /// + /// Creates a render target bitmap implementation. + /// + /// The width of the bitmap. + /// The height of the bitmap. + /// An . + IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height); + + /// + /// Loads a bitmap implementation from a file.. + /// + /// The filename of the bitmap. + /// An . + IBitmapImpl LoadBitmap(string fileName); + + /// + /// Loads a bitmap implementation from a file.. + /// + /// The stream to read the bitmap from. + /// An . + IBitmapImpl LoadBitmap(Stream stream); + } +} diff --git a/src/Avalonia.SceneGraph/Platform/IPlatformSettings.cs b/src/Avalonia.SceneGraph/Platform/IPlatformSettings.cs new file mode 100644 index 0000000000..e52135433b --- /dev/null +++ b/src/Avalonia.SceneGraph/Platform/IPlatformSettings.cs @@ -0,0 +1,14 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Platform +{ + public interface IPlatformSettings + { + Size DoubleClickSize { get; } + + TimeSpan DoubleClickTime { get; } + } +} diff --git a/src/Avalonia.SceneGraph/Platform/IRenderTarget.cs b/src/Avalonia.SceneGraph/Platform/IRenderTarget.cs new file mode 100644 index 0000000000..75ba9d5a56 --- /dev/null +++ b/src/Avalonia.SceneGraph/Platform/IRenderTarget.cs @@ -0,0 +1,22 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Media; + +namespace Avalonia.Platform +{ + /// + /// Defines a render target + /// + /// + /// The interface used for obtaining drawing context from surfaces you can render on. + /// + public interface IRenderTarget : IDisposable + { + /// + /// Creates an for a rendering session. + /// + DrawingContext CreateDrawingContext(); + } +} diff --git a/src/Avalonia.SceneGraph/Platform/IRenderTargetBitmapImpl.cs b/src/Avalonia.SceneGraph/Platform/IRenderTargetBitmapImpl.cs new file mode 100644 index 0000000000..c3c19ac150 --- /dev/null +++ b/src/Avalonia.SceneGraph/Platform/IRenderTargetBitmapImpl.cs @@ -0,0 +1,15 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Platform +{ + /// + /// Defines the platform-specific interface for a + /// . + /// + public interface IRenderTargetBitmapImpl : IBitmapImpl, IRenderTarget + { + } +} diff --git a/src/Avalonia.SceneGraph/Platform/IStreamGeometryContextImpl.cs b/src/Avalonia.SceneGraph/Platform/IStreamGeometryContextImpl.cs new file mode 100644 index 0000000000..386560c6b6 --- /dev/null +++ b/src/Avalonia.SceneGraph/Platform/IStreamGeometryContextImpl.cs @@ -0,0 +1,62 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Media; + +namespace Avalonia.Platform +{ + /// + /// Describes a geometry using drawing commands. + /// + public interface IStreamGeometryContextImpl : IDisposable + { + /// + /// Draws an arc to the specified point. + /// + /// The destination point. + /// The radii of an oval whose perimeter is used to draw the angle. + /// The rotation angle of the oval that specifies the curve. + /// true to draw the arc greater than 180 degrees; otherwise, false. + /// + /// A value that indicates whether the arc is drawn in the Clockwise or Counterclockwise direction. + /// + void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection); + + /// + /// Begins a new figure. + /// + /// The starting point for the figure. + /// Whether the figure is filled. + void BeginFigure(Point startPoint, bool isFilled); + + /// + /// Draws a Bezier curve to the specified point. + /// + /// The first control point used to specify the shape of the curve. + /// The second control point used to specify the shape of the curve. + /// The destination point for the end of the curve. + void CubicBezierTo(Point point1, Point point2, Point point3); + + /// + /// Draws a quadratic Bezier curve to the specified point + /// + /// Control point + /// DestinationPoint + void QuadraticBezierTo(Point control, Point endPoint); + + /// + /// Draws a line to the specified point. + /// + /// The destination point. + void LineTo(Point point); + + /// + /// Ends the figure started by . + /// + /// Whether the figure is closed. + void EndFigure(bool isClosed); + + void SetFillRule(FillRule fillRule); + } +} diff --git a/src/Avalonia.SceneGraph/Platform/IStreamGeometryImpl.cs b/src/Avalonia.SceneGraph/Platform/IStreamGeometryImpl.cs new file mode 100644 index 0000000000..956864fc73 --- /dev/null +++ b/src/Avalonia.SceneGraph/Platform/IStreamGeometryImpl.cs @@ -0,0 +1,25 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Platform +{ + /// + /// Defines the platform-specific interface for a . + /// + public interface IStreamGeometryImpl : IGeometryImpl + { + /// + /// Clones the geometry. + /// + /// A cloned geometry. + IStreamGeometryImpl Clone(); + + /// + /// Opens the geometry to start defining it. + /// + /// + /// An which can be used to define the geometry. + /// + IStreamGeometryContextImpl Open(); + } +} diff --git a/src/Avalonia.SceneGraph/Point.cs b/src/Avalonia.SceneGraph/Point.cs new file mode 100644 index 0000000000..7c7a3336fc --- /dev/null +++ b/src/Avalonia.SceneGraph/Point.cs @@ -0,0 +1,270 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Linq; + +namespace Avalonia +{ + /// + /// Defines a point. + /// + public struct Point + { + /// + /// The X position. + /// + private readonly double _x; + + /// + /// The Y position. + /// + private readonly double _y; + + /// + /// Initializes a new instance of the structure. + /// + /// The X position. + /// The Y position. + public Point(double x, double y) + { + _x = x; + _y = y; + } + + /// + /// Gets the X position. + /// + public double X => _x; + + /// + /// Gets the Y position. + /// + public double Y => _y; + + /// + /// Converts the to a . + /// + /// The point. + public static implicit operator Vector(Point p) + { + return new Vector(p._x, p._y); + } + + /// + /// Negates a point. + /// + /// The point. + /// The negated point. + public static Point operator -(Point a) + { + return new Point(-a._x, -a._y); + } + + /// + /// Checks for equality between two s. + /// + /// The first point. + /// The second point. + /// True if the points are equal; otherwise false. + public static bool operator ==(Point left, Point right) + { + return left.X == right.X && left.Y == right.Y; + } + + /// + /// Checks for unequality between two s. + /// + /// The first point. + /// The second point. + /// True if the points are unequal; otherwise false. + public static bool operator !=(Point left, Point right) + { + return !(left == right); + } + + /// + /// Adds two points. + /// + /// The first point. + /// The second point. + /// A point that is the result of the addition. + public static Point operator +(Point a, Point b) + { + return new Point(a._x + b._x, a._y + b._y); + } + + /// + /// Adds a vector to a point. + /// + /// The point. + /// The vector. + /// A point that is the result of the addition. + public static Point operator +(Point a, Vector b) + { + return new Point(a._x + b.X, a._y + b.Y); + } + + /// + /// Subtracts two points. + /// + /// The first point. + /// The second point. + /// A point that is the result of the subtraction. + public static Point operator -(Point a, Point b) + { + return new Point(a._x - b._x, a._y - b._y); + } + + /// + /// Subtracts a vector from a point. + /// + /// The point. + /// The vector. + /// A point that is the result of the subtraction. + public static Point operator -(Point a, Vector b) + { + return new Point(a._x - b.X, a._y - b.Y); + } + + /// + /// Multiplies a point by a factor coordinate-wise + /// + /// Point to multiply + /// Factor + /// Points having its coordinates multiplied + public static Point operator *(Point p, double k) => new Point(p.X*k, p.Y*k); + + /// + /// Multiplies a point by a factor coordinate-wise + /// + /// Point to multiply + /// Factor + /// Points having its coordinates multiplied + public static Point operator *(double k, Point p) => new Point(p.X*k, p.Y*k); + + /// + /// Divides a point by a factor coordinate-wise + /// + /// Point to divide by + /// Factor + /// Points having its coordinates divided + public static Point operator /(Point p, double k) => new Point(p.X/k, p.Y/k); + + /// + /// Applies a matrix to a point. + /// + /// The point. + /// The matrix. + /// The resulting point. + public static Point operator *(Point point, Matrix matrix) + { + return new Point( + (point.X * matrix.M11) + (point.Y * matrix.M21) + matrix.M31, + (point.X * matrix.M12) + (point.Y * matrix.M22) + matrix.M32); + } + + /// + /// Parses a string. + /// + /// The string. + /// The current culture. + /// The . + public static Point Parse(string s, CultureInfo culture) + { + var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .ToList(); + + if (parts.Count == 2) + { + return new Point(double.Parse(parts[0], culture), double.Parse(parts[1], culture)); + } + else + { + throw new FormatException("Invalid Thickness."); + } + } + + /// + /// Checks for equality between a point and an object. + /// + /// The object. + /// + /// True if is a point that equals the current point. + /// + public override bool Equals(object obj) + { + if (obj is Point) + { + var other = (Point)obj; + return X == other.X && Y == other.Y; + } + + return false; + } + + /// + /// Returns a hash code for a . + /// + /// The hash code. + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 23) + _x.GetHashCode(); + hash = (hash * 23) + _y.GetHashCode(); + return hash; + } + } + + /// + /// Returns the string representation of the point. + /// + /// The string representation of the point. + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", _x, _y); + } + + /// + /// Transforms the point by a matrix. + /// + /// The transform. + /// The transformed point. + public Point Transform(Matrix transform) + { + var x = X; + var y = Y; + var xadd = y * transform.M21 + transform.M31; + var yadd = x * transform.M12 + transform.M32; + x *= transform.M11; + x += xadd; + y *= transform.M22; + y += yadd; + return new Point(x, y); + } + + /// + /// Returns a new point with the specified X coordinate. + /// + /// The X coordinate. + /// The new point. + public Point WithX(double x) + { + return new Point(x, _y); + } + + /// + /// Returns a new point with the specified Y coordinate. + /// + /// The Y coordinate. + /// The new point. + public Point WithY(double y) + { + return new Point(_x, y); + } + } +} diff --git a/src/Avalonia.SceneGraph/Properties/AssemblyInfo.cs b/src/Avalonia.SceneGraph/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..b70832a031 --- /dev/null +++ b/src/Avalonia.SceneGraph/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; +using Avalonia.Metadata; + +[assembly: AssemblyTitle("Avalonia.SceneGraph")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui/mutable", "Avalonia.Media.Mutable")] \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Rect.cs b/src/Avalonia.SceneGraph/Rect.cs new file mode 100644 index 0000000000..de4d13890b --- /dev/null +++ b/src/Avalonia.SceneGraph/Rect.cs @@ -0,0 +1,460 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Linq; + +namespace Avalonia +{ + /// + /// Defines a rectangle. + /// + public struct Rect + { + /// + /// An empty rectangle. + /// + public static readonly Rect Empty = default(Rect); + + /// + /// The X position. + /// + private readonly double _x; + + /// + /// The Y position. + /// + private readonly double _y; + + /// + /// The width. + /// + private readonly double _width; + + /// + /// The height. + /// + private readonly double _height; + + /// + /// Initializes a new instance of the structure. + /// + /// The X position. + /// The Y position. + /// The width. + /// The height. + public Rect(double x, double y, double width, double height) + { + _x = x; + _y = y; + _width = width; + _height = height; + } + + /// + /// Initializes a new instance of the structure. + /// + /// The size of the rectangle. + public Rect(Size size) + { + _x = 0; + _y = 0; + _width = size.Width; + _height = size.Height; + } + + /// + /// Initializes a new instance of the structure. + /// + /// The position of the rectangle. + /// The size of the rectangle. + public Rect(Point position, Size size) + { + _x = position.X; + _y = position.Y; + _width = size.Width; + _height = size.Height; + } + + /// + /// Initializes a new instance of the structure. + /// + /// The top left position of the rectangle. + /// The bottom right position of the rectangle. + public Rect(Point topLeft, Point bottomRight) + { + _x = topLeft.X; + _y = topLeft.Y; + _width = bottomRight.X - topLeft.X; + _height = bottomRight.Y - topLeft.Y; + } + + /// + /// Gets the X position. + /// + public double X => _x; + + /// + /// Gets the Y position. + /// + public double Y => _y; + + /// + /// Gets the width. + /// + public double Width => _width; + + /// + /// Gets the height. + /// + public double Height => _height; + + /// + /// Gets the position of the rectangle. + /// + public Point Position => new Point(_x, _y); + + /// + /// Gets the size of the rectangle. + /// + public Size Size => new Size(_width, _height); + + /// + /// Gets the right position of the rectangle. + /// + public double Right => _x + _width; + + /// + /// Gets the bottom position of the rectangle. + /// + public double Bottom => _y + _height; + + /// + /// Gets the top left point of the rectangle. + /// + public Point TopLeft => new Point(_x, _y); + + /// + /// Gets the top right point of the rectangle. + /// + public Point TopRight => new Point(Right, _y); + + /// + /// Gets the bottom left point of the rectangle. + /// + public Point BottomLeft => new Point(_x, Bottom); + + /// + /// Gets the bottom right point of the rectangle. + /// + public Point BottomRight => new Point(Right, Bottom); + + /// + /// Gets the center point of the rectangle. + /// + public Point Center => new Point(_x + (_width / 2), _y + (_height / 2)); + + /// + /// Gets a value that indicates whether the rectangle is empty. + /// + public bool IsEmpty => _width == 0 && _height == 0; + + /// + /// Checks for equality between two s. + /// + /// The first rect. + /// The second rect. + /// True if the rects are equal; otherwise false. + public static bool operator ==(Rect left, Rect right) + { + return left.Position == right.Position && left.Size == right.Size; + } + + /// + /// Checks for unequality between two s. + /// + /// The first rect. + /// The second rect. + /// True if the rects are unequal; otherwise false. + public static bool operator !=(Rect left, Rect right) + { + return !(left == right); + } + + /// + /// Multiplies a rectangle by a vector. + /// + /// The rectangle. + /// The vector scale. + /// The scaled rectangle. + public static Rect operator *(Rect rect, Vector scale) + { + return new Rect( + rect.X * scale.X, + rect.Y * scale.Y, + rect.Width * scale.X, + rect.Height * scale.Y); + } + + /// + /// Transforms a rectangle by a matrix and returns the axis-aligned bounding box. + /// + /// The rectangle. + /// The matrix. + /// The axis-aligned bounding box. + public static Rect operator *(Rect rect, Matrix matrix) + { + return new Rect(rect.TopLeft * matrix, rect.BottomRight * matrix); + } + + /// + /// Divides a rectangle by a vector. + /// + /// The rectangle. + /// The vector scale. + /// The scaled rectangle. + public static Rect operator /(Rect rect, Vector scale) + { + return new Rect( + rect.X / scale.X, + rect.Y / scale.Y, + rect.Width / scale.X, + rect.Height / scale.Y); + } + + /// + /// Determines whether a points in in the bounds of the rectangle. + /// + /// The point. + /// true if the point is in the bounds of the rectangle; otherwise false. + public bool Contains(Point p) + { + return p.X >= _x && p.X < _x + _width && + p.Y >= _y && p.Y < _y + _height; + } + + /// + /// Centers another rectangle in this rectangle. + /// + /// The rectangle to center. + /// The centered rectangle. + public Rect CenterIn(Rect rect) + { + return new Rect( + _x + ((_width - rect._width) / 2), + _y + ((_height - rect._height) / 2), + rect._width, + rect._height); + } + + /// + /// Inflates the rectangle. + /// + /// The thickness. + /// The inflated rectangle. + public Rect Inflate(double thickness) + { + return Inflate(new Thickness(thickness)); + } + + /// + /// Inflates the rectangle. + /// + /// The thickness. + /// The inflated rectangle. + public Rect Inflate(Thickness thickness) + { + return new Rect( + new Point(_x - thickness.Left, _y - thickness.Top), + Size.Inflate(thickness)); + } + + /// + /// Deflates the rectangle. + /// + /// The thickness. + /// The deflated rectangle. + /// The deflated rectangle size cannot be less than 0. + public Rect Deflate(double thickness) + { + return Deflate(new Thickness(thickness / 2)); + } + + /// + /// Deflates the rectangle by a . + /// + /// The thickness. + /// The deflated rectangle. + /// The deflated rectangle size cannot be less than 0. + public Rect Deflate(Thickness thickness) + { + return new Rect( + new Point(_x + thickness.Left, _y + thickness.Top), + Size.Deflate(thickness)); + } + + /// + /// Returns a boolean indicating whether the given object is equal to this rectangle. + /// + /// The object to compare against. + /// True if the object is equal to this rectangle; false otherwise. + public override bool Equals(object obj) + { + if (obj is Rect) + { + var other = (Rect)obj; + return Position == other.Position && Size == other.Size; + } + + return false; + } + + /// + /// Returns the hash code for this instance. + /// + /// The hash code. + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 23) + X.GetHashCode(); + hash = (hash * 23) + Y.GetHashCode(); + hash = (hash * 23) + Width.GetHashCode(); + hash = (hash * 23) + Height.GetHashCode(); + return hash; + } + } + + /// + /// Gets the intersection of two rectangles. + /// + /// The other rectangle. + /// The intersection. + public Rect Intersect(Rect rect) + { + var newLeft = (rect.X > X) ? rect.X : X; + var newTop = (rect.Y > Y) ? rect.Y : Y; + var newRight = (rect.Right < Right) ? rect.Right : Right; + var newBottom = (rect.Bottom < Bottom) ? rect.Bottom : Bottom; + + if ((newRight > newLeft) && (newBottom > newTop)) + { + return new Rect(newLeft, newTop, newRight - newLeft, newBottom - newTop); + } + else + { + return Empty; + } + } + + /// + /// Determines whether a rectangle intersects with this rectangle. + /// + /// The other rectangle. + /// + /// True if the specified rectangle intersects with this one; otherwise false. + /// + public bool Intersects(Rect rect) + { + return (rect.X < Right) && (X < rect.Right) && (rect.Y < Bottom) && (Y < rect.Bottom); + } + + /// + /// Returns the axis-aligned bounding box of a transformed rectangle. + /// + /// The transform. + /// The bounding box + public Rect TransformToAABB(Matrix matrix) + { + var points = new[] + { + TopLeft.Transform(matrix), + TopRight.Transform(matrix), + BottomRight.Transform(matrix), + BottomLeft.Transform(matrix), + }; + + var left = double.MaxValue; + var right = double.MinValue; + var top = double.MaxValue; + var bottom = double.MinValue; + + foreach (var p in points) + { + if (p.X < left) left = p.X; + if (p.X > right) right = p.X; + if (p.Y < top) top = p.Y; + if (p.Y > bottom) bottom = p.Y; + } + + return new Rect(new Point(left, top), new Point(right, bottom)); + } + + /// + /// Translates the rectangle by an offset. + /// + /// The offset. + /// The translated rectangle. + public Rect Translate(Vector offset) + { + return new Rect(Position + offset, Size); + } + + /// + /// Returns a new with the specified X position. + /// + /// The x position. + /// The new . + public Rect WithX(double x) + { + return new Rect(x, _y, _width, _height); + } + + /// + /// Returns a new with the specified Y position. + /// + /// The y position. + /// The new . + public Rect WithY(double y) + { + return new Rect(_x, y, _width, _height); + } + + /// + /// Returns a new with the specified width. + /// + /// The width. + /// The new . + public Rect WithWidth(double width) + { + return new Rect(_x, _y, width, _height); + } + + /// + /// Returns a new with the specified height. + /// + /// The height. + /// The new . + public Rect WithHeight(double height) + { + return new Rect(_x, _y, _width, height); + } + + /// + /// Returns the string representation of the rectangle. + /// + /// The string representation of the rectangle. + public override string ToString() + { + return string.Format( + CultureInfo.InvariantCulture, + "{0}, {1}, {2}, {3}", + _x, + _y, + _width, + _height); + } + } +} diff --git a/src/Avalonia.SceneGraph/RelativePoint.cs b/src/Avalonia.SceneGraph/RelativePoint.cs new file mode 100644 index 0000000000..cc34feb5f3 --- /dev/null +++ b/src/Avalonia.SceneGraph/RelativePoint.cs @@ -0,0 +1,193 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Linq; + +namespace Avalonia +{ + /// + /// Defines the reference point units of an or + /// . + /// + public enum RelativeUnit + { + /// + /// The point is expressed as a fraction of the containing element's size. + /// + Relative, + + /// + /// The point is absolute (i.e. in pixels). + /// + Absolute, + } + + /// + /// Defines a point that may be defined relative to a containing element. + /// + public struct RelativePoint : IEquatable + { + /// + /// A point at the top left of the containing element. + /// + public static readonly RelativePoint TopLeft = new RelativePoint(0, 0, RelativeUnit.Relative); + + /// + /// A point at the center of the containing element. + /// + public static readonly RelativePoint Center = new RelativePoint(0.5, 0.5, RelativeUnit.Relative); + + /// + /// A point at the bottom right of the containing element. + /// + public static readonly RelativePoint BottomRight = new RelativePoint(1, 1, RelativeUnit.Relative); + + private Point _point; + + private readonly RelativeUnit _unit; + + /// + /// Initializes a new instance of the struct. + /// + /// The X point. + /// The Y point + /// The unit. + public RelativePoint(double x, double y, RelativeUnit unit) + : this(new Point(x, y), unit) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The point. + /// The unit. + public RelativePoint(Point point, RelativeUnit unit) + { + _point = point; + _unit = unit; + } + + /// + /// Gets the point. + /// + public Point Point => _point; + + /// + /// Gets the unit. + /// + public RelativeUnit Unit => _unit; + + /// + /// Checks for equality between two s. + /// + /// The first point. + /// The second point. + /// True if the points are equal; otherwise false. + public static bool operator ==(RelativePoint left, RelativePoint right) + { + return left.Equals(right); + } + + /// + /// Checks for unequality between two s. + /// + /// The first point. + /// The second point. + /// True if the points are unequal; otherwise false. + public static bool operator !=(RelativePoint left, RelativePoint right) + { + return !left.Equals(right); + } + + /// + /// Checks if the equals another object. + /// + /// The other object. + /// True if the objects are equal, otherwise false. + public override bool Equals(object obj) + { + return (obj is RelativePoint) && Equals((RelativePoint)obj); + } + + /// + /// Checks if the equals another point. + /// + /// The other point. + /// True if the objects are equal, otherwise false. + public bool Equals(RelativePoint p) + { + return Unit == p.Unit && Point == p.Point; + } + + /// + /// Gets a hashcode for a . + /// + /// A hash code. + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 23) + Unit.GetHashCode(); + hash = (hash * 23) + Point.GetHashCode(); + return hash; + } + } + + /// + /// Converts a into pixels. + /// + /// The size of the visual. + /// The origin point in pixels. + public Point ToPixels(Size size) + { + return _unit == RelativeUnit.Absolute ? + _point : + new Point(_point.X * size.Width, _point.Y * size.Height); + } + + /// + /// Parses a string. + /// + /// The string. + /// The current culture. + /// The parsed . + public static RelativePoint Parse(string s, CultureInfo culture) + { + var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .ToList(); + + if (parts.Count == 2) + { + var unit = RelativeUnit.Absolute; + var scale = 1.0; + + if (parts[0].EndsWith("%")) + { + if (!parts[1].EndsWith("%")) + { + throw new FormatException("If one coordinate is relative, both must be."); + } + + parts[0] = parts[0].TrimEnd('%'); + parts[1] = parts[1].TrimEnd('%'); + unit = RelativeUnit.Relative; + scale = 0.01; + } + + return new RelativePoint( + double.Parse(parts[0], culture) * scale, + double.Parse(parts[1], culture) * scale, + unit); + } + else + { + throw new FormatException("Invalid Point."); + } + } + } +} diff --git a/src/Avalonia.SceneGraph/RelativeRect.cs b/src/Avalonia.SceneGraph/RelativeRect.cs new file mode 100644 index 0000000000..3ce3797c49 --- /dev/null +++ b/src/Avalonia.SceneGraph/RelativeRect.cs @@ -0,0 +1,210 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Linq; + +namespace Avalonia +{ + /// + /// Defines a rectangle that may be defined relative to a containing element. + /// + public struct RelativeRect : IEquatable + { + /// + /// A rectangle that represents 100% of an area. + /// + public static readonly RelativeRect Fill = new RelativeRect(0, 0, 1, 1, RelativeUnit.Relative); + + /// + /// Initializes a new instance of the structure. + /// + /// The X position. + /// The Y position. + /// The width. + /// The height. + /// The unit of the rect. + public RelativeRect(double x, double y, double width, double height, RelativeUnit unit) + { + Rect = new Rect(x, y, width, height); + Unit = unit; + } + + /// + /// Initializes a new instance of the structure. + /// + /// The rectangle. + /// The unit of the rect. + public RelativeRect(Rect rect, RelativeUnit unit) + { + Rect = rect; + Unit = unit; + } + + /// + /// Initializes a new instance of the structure. + /// + /// The size of the rectangle. + /// The unit of the rect. + public RelativeRect(Size size, RelativeUnit unit) + { + Rect = new Rect(size); + Unit = unit; + } + + /// + /// Initializes a new instance of the structure. + /// + /// The position of the rectangle. + /// The size of the rectangle. + /// The unit of the rect. + public RelativeRect(Point position, Size size, RelativeUnit unit) + { + Rect = new Rect(position, size); + Unit = unit; + } + + /// + /// Initializes a new instance of the structure. + /// + /// The top left position of the rectangle. + /// The bottom right position of the rectangle. + /// The unit of the rect. + public RelativeRect(Point topLeft, Point bottomRight, RelativeUnit unit) + { + Rect = new Rect(topLeft, bottomRight); + Unit = unit; + } + + /// + /// Gets the unit of the rectangle. + /// + public RelativeUnit Unit { get; } + + /// + /// Gets the rectangle. + /// + public Rect Rect { get; } + + /// + /// Checks for equality between two s. + /// + /// The first rectangle. + /// The second rectangle. + /// True if the rectangles are equal; otherwise false. + public static bool operator ==(RelativeRect left, RelativeRect right) + { + return left.Equals(right); + } + + /// + /// Checks for unequality between two s. + /// + /// The first rectangle. + /// The second rectangle. + /// True if the rectangles are unequal; otherwise false. + public static bool operator !=(RelativeRect left, RelativeRect right) + { + return !left.Equals(right); + } + + /// + /// Checks if the equals another object. + /// + /// The other object. + /// True if the objects are equal, otherwise false. + public override bool Equals(object obj) + { + return (obj is RelativeRect) && Equals((RelativeRect)obj); + } + + /// + /// Checks if the equals another rectangle. + /// + /// The other rectangle. + /// True if the objects are equal, otherwise false. + public bool Equals(RelativeRect p) + { + return Unit == p.Unit && Rect == p.Rect; + } + + /// + /// Gets a hashcode for a . + /// + /// A hash code. + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 23) + Unit.GetHashCode(); + hash = (hash * 23) + Rect.GetHashCode(); + return hash; + } + } + + /// + /// Converts a into pixels. + /// + /// The size of the visual. + /// The origin point in pixels. + public Rect ToPixels(Size size) + { + return Unit == RelativeUnit.Absolute ? + Rect : + new Rect( + Rect.X * size.Width, + Rect.Y * size.Height, + Rect.Width * size.Width, + Rect.Height * size.Height); + } + + /// + /// Parses a string. + /// + /// The string. + /// The current culture. + /// The parsed . + public static RelativeRect Parse(string s, CultureInfo culture) + { + var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .ToList(); + + if (parts.Count == 4) + { + var unit = RelativeUnit.Absolute; + var scale = 1.0; + + if (parts[0].EndsWith("%")) + { + if (!parts[1].EndsWith("%") + || !parts[2].EndsWith("%") + || !parts[3].EndsWith("%")) + { + throw new FormatException("If one coordinate is relative, all other must be too."); + } + + parts[0] = parts[0].TrimEnd('%'); + parts[1] = parts[1].TrimEnd('%'); + parts[2] = parts[2].TrimEnd('%'); + parts[3] = parts[3].TrimEnd('%'); + unit = RelativeUnit.Relative; + scale = 0.01; + } + + return new RelativeRect( + double.Parse(parts[0], culture) * scale, + double.Parse(parts[1], culture) * scale, + double.Parse(parts[2], culture) * scale, + double.Parse(parts[3], culture) * scale, + unit); + } + else + { + throw new FormatException("Invalid Rect."); + } + } + } +} diff --git a/src/Avalonia.SceneGraph/Rendering/IRenderQueueManager.cs b/src/Avalonia.SceneGraph/Rendering/IRenderQueueManager.cs new file mode 100644 index 0000000000..580e8b3046 --- /dev/null +++ b/src/Avalonia.SceneGraph/Rendering/IRenderQueueManager.cs @@ -0,0 +1,31 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive; +using Avalonia.VisualTree; + +namespace Avalonia.Rendering +{ + /// + /// Defines the interface for a . + /// + public interface IRenderQueueManager + { + /// + /// Gets an observable that is fired whenever a render is required. + /// + IObservable RenderNeeded { get; } + + /// + /// Invalidates the render for the specified visual and raises . + /// + /// The visual. + void InvalidateRender(IVisual visual); + + /// + /// Called when rendering is finished. + /// + void RenderFinished(); + } +} diff --git a/src/Avalonia.SceneGraph/Rendering/IRenderRoot.cs b/src/Avalonia.SceneGraph/Rendering/IRenderRoot.cs new file mode 100644 index 0000000000..254cb5bc1b --- /dev/null +++ b/src/Avalonia.SceneGraph/Rendering/IRenderRoot.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Platform; + +namespace Avalonia.Rendering +{ + /// + /// Represents the root of a renderable tree. + /// + public interface IRenderRoot + { + /// + /// Gets the render manager which schedules renders. + /// + IRenderQueueManager RenderQueueManager { get; } + + /// + /// Converts a point from screen to client coordinates. + /// + /// The point in screen coordinates. + /// The point in client coordinates. + Point PointToClient(Point point); + + /// + /// Converts a point from client to screen coordinates. + /// + /// The point in client coordinates. + /// The point in screen coordinates. + Point PointToScreen(Point point); + } +} diff --git a/src/Avalonia.SceneGraph/Rendering/RenderQueueManager.cs b/src/Avalonia.SceneGraph/Rendering/RenderQueueManager.cs new file mode 100644 index 0000000000..8b64788c16 --- /dev/null +++ b/src/Avalonia.SceneGraph/Rendering/RenderQueueManager.cs @@ -0,0 +1,51 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive; +using System.Reactive.Subjects; +using Avalonia.VisualTree; + +namespace Avalonia.Rendering +{ + /// + /// Schedules the rendering of a tree. + /// + public class RenderQueueManager : IRenderQueueManager + { + private readonly Subject _renderNeeded = new Subject(); + + private bool _renderQueued; + + /// + /// Gets an observable that is fired whenever a render is required. + /// + public IObservable RenderNeeded => _renderNeeded; + + /// + /// Gets a value indicating whether a render is queued. + /// + public bool RenderQueued => _renderQueued; + + /// + /// Invalidates the render for the specified visual and raises . + /// + /// The visual. + public void InvalidateRender(IVisual visual) + { + if (!_renderQueued) + { + _renderQueued = true; + _renderNeeded.OnNext(Unit.Default); + } + } + + /// + /// Called when rendering is finished. + /// + public void RenderFinished() + { + _renderQueued = false; + } + } +} diff --git a/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs b/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs new file mode 100644 index 0000000000..cd18b0f152 --- /dev/null +++ b/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs @@ -0,0 +1,178 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Avalonia.Media; +using Avalonia.Platform; +using Avalonia.VisualTree; + +namespace Avalonia.Rendering +{ + /// + /// Extension methods for rendering. + /// + /// + /// This class provides implements the platform-independent parts of . + /// + [SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")] + [SuppressMessage("ReSharper", "ForCanBeConvertedToForeach")] + public static class RendererMixin + { + private static int s_frameNum; + private static int s_fps; + private static int s_currentFrames; + private static TimeSpan s_lastMeasure; + private static readonly Stopwatch s_stopwatch = Stopwatch.StartNew(); + private static readonly Stack> s_listPool = new Stack>(); + private static readonly ZIndexComparer s_visualComparer = new ZIndexComparer(); + + /// + /// Gets or sets a value which determines whether an FPS counted will be drawn on each + /// rendered frame. + /// + public static bool DrawFpsCounter { get; set; } + + /// + /// Renders the specified visual. + /// + /// IRenderer instance + /// The visual to render. + public static void Render(this IRenderTarget renderTarget, IVisual visual) + { + using (var ctx = renderTarget.CreateDrawingContext()) + { + ctx.Render(visual); + s_frameNum++; + if (DrawFpsCounter) + { + s_currentFrames++; + var now = s_stopwatch.Elapsed; + var elapsed = now - s_lastMeasure; + if (elapsed.TotalSeconds > 0) + { + s_fps = (int) (s_currentFrames/elapsed.TotalSeconds); + s_currentFrames = 0; + s_lastMeasure = now; + } + var pt = new Point(40, 40); + using ( + var txt = new FormattedText("Frame #" + s_frameNum + " FPS: " + s_fps, "Arial", 18, + FontStyle.Normal, + TextAlignment.Left, + FontWeight.Normal)) + { + ctx.FillRectangle(Brushes.White, new Rect(pt, txt.Measure())); + ctx.DrawText(Brushes.Black, pt, txt); + } + } + } + } + + /// + /// Renders the specified visual. + /// + /// The visual to render. + /// The drawing context. + public static void Render(this DrawingContext context, IVisual visual) + { + context.Render(visual, visual.Bounds); + } + + /// + /// Renders the specified visual. + /// + /// The visual to render. + /// The drawing context. + /// + /// The current clip rect, in coordinates relative to . + /// + private static void Render(this DrawingContext context, IVisual visual, Rect clipRect) + { + var opacity = visual.Opacity; + var clipToBounds = visual.ClipToBounds; + var bounds = new Rect(visual.Bounds.Size); + + if (visual.IsVisible && opacity > 0) + { + var m = Matrix.CreateTranslation(visual.Bounds.Position); + + var renderTransform = Matrix.Identity; + + if (visual.RenderTransform != null) + { + var origin = visual.TransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height)); + var offset = Matrix.CreateTranslation(origin); + renderTransform = (-offset) * visual.RenderTransform.Value * (offset); + } + + m = renderTransform * m; + + if (clipToBounds) + { + clipRect = clipRect.Intersect(new Rect(visual.Bounds.Size)); + } + + using (context.PushPostTransform(m)) + using (context.PushOpacity(opacity)) + using (clipToBounds ? context.PushClip(bounds) : default(DrawingContext.PushedState)) + using (context.PushTransformContainer()) + { + visual.Render(context); + + var lst = GetSortedVisualList(visual.VisualChildren); + + foreach (var child in lst) + { + var childBounds = GetTransformedBounds(child); + + if (!child.ClipToBounds || clipRect.Intersects(childBounds)) + { + var childClipRect = clipRect.Translate(-childBounds.Position); + context.Render(child, childClipRect); + } + } + + ReturnListToPool(lst); + } + } + } + + private static void ReturnListToPool(List lst) + { + lst.Clear(); + s_listPool.Push(lst); + } + + private static List GetSortedVisualList(IReadOnlyList source) + { + var lst = s_listPool.Count == 0 ? new List() : s_listPool.Pop(); + for (var c = 0; c < source.Count; c++) + lst.Add(source[c]); + lst.Sort(s_visualComparer); + return lst; + } + + private static Rect GetTransformedBounds(IVisual visual) + { + if (visual.RenderTransform == null) + { + return visual.Bounds; + } + else + { + var origin = visual.TransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height)); + var offset = Matrix.CreateTranslation(visual.Bounds.Position + origin); + var m = (-offset) * visual.RenderTransform.Value * (offset); + return visual.Bounds.TransformToAABB(m); + } + } + + class ZIndexComparer : IComparer + { + public int Compare(IVisual x, IVisual y) => x.ZIndex.CompareTo(y.ZIndex); + } + } +} diff --git a/src/Avalonia.SceneGraph/Size.cs b/src/Avalonia.SceneGraph/Size.cs new file mode 100644 index 0000000000..a11411c3ee --- /dev/null +++ b/src/Avalonia.SceneGraph/Size.cs @@ -0,0 +1,253 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Linq; + +namespace Avalonia +{ + /// + /// Defines a size. + /// + public struct Size + { + /// + /// A size representing infinity. + /// + public static readonly Size Infinity = new Size(double.PositiveInfinity, double.PositiveInfinity); + + /// + /// A size representing zero + /// + public static readonly Size Empty = new Size(0, 0); + + /// + /// The width. + /// + private readonly double _width; + + /// + /// The height. + /// + private readonly double _height; + + /// + /// Initializes a new instance of the structure. + /// + /// The width. + /// The height. + public Size(double width, double height) + { + _width = width; + _height = height; + } + + /// + /// Gets the width. + /// + public double Width => _width; + + /// + /// Gets the height. + /// + public double Height => _height; + + /// + /// Checks for equality between two s. + /// + /// The first size. + /// The second size. + /// True if the sizes are equal; otherwise false. + public static bool operator ==(Size left, Size right) + { + return left._width == right._width && left._height == right._height; + } + + /// + /// Checks for unequality between two s. + /// + /// The first size. + /// The second size. + /// True if the sizes are unequal; otherwise false. + public static bool operator !=(Size left, Size right) + { + return !(left == right); + } + + /// + /// Scales a size. + /// + /// The size + /// The scaling factor. + /// The scaled size. + public static Size operator *(Size size, Vector scale) + { + return new Size(size._width * scale.X, size._height * scale.Y); + } + + /// + /// Scales a size. + /// + /// The size + /// The scaling factor. + /// The scaled size. + public static Size operator /(Size size, Vector scale) + { + return new Size(size._width / scale.X, size._height / scale.Y); + } + + /// + /// Scales a size. + /// + /// The size + /// The scaling factor. + /// The scaled size. + public static Size operator *(Size size, double scale) + { + return new Size(size._width * scale, size._height * scale); + } + + /// + /// Scales a size. + /// + /// The size + /// The scaling factor. + /// The scaled size. + public static Size operator /(Size size, double scale) + { + return new Size(size._width / scale, size._height / scale); + } + + public static Size operator +(Size size, Size toAdd) + { + return new Size(size._width + toAdd._width, size._height + toAdd._height); + } + + public static Size operator -(Size size, Size toSubstract) + { + return new Size(size._width - toSubstract._width, size._height - toSubstract._height); + } + + /// + /// Parses a string. + /// + /// The string. + /// The current culture. + /// The . + public static Size Parse(string s, CultureInfo culture) + { + var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .ToList(); + + if (parts.Count == 2) + { + return new Size(double.Parse(parts[0], culture), double.Parse(parts[1], culture)); + } + else + { + throw new FormatException("Invalid Size."); + } + } + + /// + /// Constrains the size. + /// + /// The size to constrain to. + /// The constrained size. + public Size Constrain(Size constraint) + { + return new Size( + Math.Min(_width, constraint._width), + Math.Min(_height, constraint._height)); + } + + /// + /// Deflates the size by a . + /// + /// The thickness. + /// The deflated size. + /// The deflated size cannot be less than 0. + public Size Deflate(Thickness thickness) + { + return new Size( + Math.Max(0, _width - thickness.Left - thickness.Right), + Math.Max(0, _height - thickness.Top - thickness.Bottom)); + } + + /// + /// Checks for equality between a size and an object. + /// + /// The object. + /// + /// True if is a size that equals the current size. + /// + public override bool Equals(object obj) + { + if (obj is Size) + { + var other = (Size)obj; + return Width == other.Width && Height == other.Height; + } + + return false; + } + + /// + /// Returns a hash code for a . + /// + /// The hash code. + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 23) + Width.GetHashCode(); + hash = (hash * 23) + Height.GetHashCode(); + return hash; + } + } + + /// + /// Inflates the size by a . + /// + /// The thickness. + /// The inflated size. + public Size Inflate(Thickness thickness) + { + return new Size( + _width + thickness.Left + thickness.Right, + _height + thickness.Top + thickness.Bottom); + } + + /// + /// Returns a new with the same height and the specified width. + /// + /// The width. + /// The new . + public Size WithWidth(double width) + { + return new Size(width, _height); + } + + /// + /// Returns a new with the same width and the specified height. + /// + /// The height. + /// The new . + public Size WithHeight(double height) + { + return new Size(_width, height); + } + + /// + /// Returns the string representation of the size. + /// + /// The string representation of the size. + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", _width, _height); + } + } +} \ No newline at end of file diff --git a/src/Avalonia.SceneGraph/Thickness.cs b/src/Avalonia.SceneGraph/Thickness.cs new file mode 100644 index 0000000000..dc9be7341d --- /dev/null +++ b/src/Avalonia.SceneGraph/Thickness.cs @@ -0,0 +1,237 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Linq; + +namespace Avalonia +{ + /// + /// Describes the thickness of a frame around a rectangle. + /// + public struct Thickness + { + /// + /// The thickness on the left. + /// + private readonly double _left; + + /// + /// The thickness on the top. + /// + private readonly double _top; + + /// + /// The thickness on the right. + /// + private readonly double _right; + + /// + /// The thickness on the bottom. + /// + private readonly double _bottom; + + /// + /// Initializes a new instance of the structure. + /// + /// The length that should be applied to all sides. + public Thickness(double uniformLength) + { + _left = _top = _right = _bottom = uniformLength; + } + + /// + /// Initializes a new instance of the structure. + /// + /// The thickness on the left and right. + /// The thickness on the top and bottom. + public Thickness(double horizontal, double vertical) + { + _left = _right = horizontal; + _top = _bottom = vertical; + } + + /// + /// Initializes a new instance of the structure. + /// + /// The thickness on the left. + /// The thickness on the top. + /// The thickness on the right. + /// The thickness on the bottom. + public Thickness(double left, double top, double right, double bottom) + { + _left = left; + _top = top; + _right = right; + _bottom = bottom; + } + + /// + /// Gets the thickness on the left. + /// + public double Left => _left; + + /// + /// Gets the thickness on the top. + /// + public double Top => _top; + + /// + /// Gets the thickness on the right. + /// + public double Right => _right; + + /// + /// Gets the thickness on the bottom. + /// + public double Bottom => _bottom; + + /// + /// Gets a value indicating whether all sides are set to 0. + /// + public bool IsEmpty => Left == 0 && Top == 0 && Right == 0 && Bottom == 0; + + /// + /// Compares two Thicknesses. + /// + /// The first thickness. + /// The second thickness. + /// The equality. + public static bool operator ==(Thickness a, Thickness b) + { + return a.Equals(b); + } + + /// + /// Compares two Thicknesses. + /// + /// The first thickness. + /// The second thickness. + /// The unequality. + public static bool operator !=(Thickness a, Thickness b) + { + return !a.Equals(b); + } + + /// + /// Adds two Thicknesses. + /// + /// The first thickness. + /// The second thickness. + /// The equality. + public static Thickness operator +(Thickness a, Thickness b) + { + return new Thickness( + a.Left + b.Left, + a.Top + b.Top, + a.Right + b.Right, + a.Bottom + b.Bottom); + } + + /// + /// Adds a Thickness to a Size. + /// + /// The size. + /// The thickness. + /// The equality. + public static Size operator +(Size size, Thickness thickness) + { + return new Size( + size.Width + thickness.Left + thickness.Right, + size.Height + thickness.Top + thickness.Bottom); + } + + /// + /// Subtracts a Thickness from a Size. + /// + /// The size. + /// The thickness. + /// The equality. + public static Size operator -(Size size, Thickness thickness) + { + return new Size( + size.Width - (thickness.Left + thickness.Right), + size.Height - (thickness.Top + thickness.Bottom)); + } + + /// + /// Parses a string. + /// + /// The string. + /// The current culture. + /// The . + public static Thickness Parse(string s, CultureInfo culture) + { + var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .ToList(); + + switch (parts.Count) + { + case 1: + var uniform = double.Parse(parts[0], culture); + return new Thickness(uniform); + case 2: + var horizontal = double.Parse(parts[0], culture); + var vertical = double.Parse(parts[1], culture); + return new Thickness(horizontal, vertical); + case 4: + var left = double.Parse(parts[0], culture); + var top = double.Parse(parts[1], culture); + var right = double.Parse(parts[2], culture); + var bottom = double.Parse(parts[3], culture); + return new Thickness(left, top, right, bottom); + } + + throw new FormatException("Invalid Thickness."); + } + + /// + /// Checks for equality between a thickness and an object. + /// + /// The object. + /// + /// True if is a size that equals the current size. + /// + public override bool Equals(object obj) + { + if (obj is Thickness) + { + Thickness other = (Thickness)obj; + return Left == other.Left && + Top == other.Top && + Right == other.Right && + Bottom == other.Bottom; + } + + return false; + } + + /// + /// Returns a hash code for a . + /// + /// The hash code. + public override int GetHashCode() + { + unchecked + { + int hash = 17; + hash = (hash * 23) + Left.GetHashCode(); + hash = (hash * 23) + Top.GetHashCode(); + hash = (hash * 23) + Right.GetHashCode(); + hash = (hash * 23) + Bottom.GetHashCode(); + return hash; + } + } + + /// + /// Returns the string representation of the thickness. + /// + /// The string representation of the thickness. + public override string ToString() + { + return $"{_left},{_top},{_right},{_bottom}"; + } + } +} diff --git a/src/Avalonia.SceneGraph/Vector.cs b/src/Avalonia.SceneGraph/Vector.cs new file mode 100644 index 0000000000..cc1c700690 --- /dev/null +++ b/src/Avalonia.SceneGraph/Vector.cs @@ -0,0 +1,134 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Xml.Linq; + +namespace Avalonia +{ + /// + /// Defines a vector. + /// + public struct Vector + { + /// + /// The X vector. + /// + private readonly double _x; + + /// + /// The Y vector. + /// + private readonly double _y; + + /// + /// Initializes a new instance of the structure. + /// + /// The X vector. + /// The Y vector. + public Vector(double x, double y) + { + _x = x; + _y = y; + } + + /// + /// Gets the X vector. + /// + public double X => _x; + + /// + /// Gets the Y vector. + /// + public double Y => _y; + + /// + /// Converts the to a . + /// + /// The vector. + public static explicit operator Point(Vector a) + { + return new Point(a._x, a._y); + } + + + + /// + /// Calculates the dot product of two vectors + /// + /// First vector + /// Second vector + /// The dot product + public static double operator *(Vector a, Vector b) + { + return a.X*b.X + a.Y*b.Y; + } + + /// + /// Length of the vector + /// + public double Length => Math.Sqrt(X*X + Y*Y); + + /// + /// Negates a vector. + /// + /// The vector. + /// The negated vector. + public static Vector operator -(Vector a) + { + return new Vector(-a._x, -a._y); + } + + /// + /// Adds two vectors. + /// + /// The first vector. + /// The second vector. + /// A vector that is the result of the addition. + public static Vector operator +(Vector a, Vector b) + { + return new Vector(a._x + b._x, a._y + b._y); + } + + /// + /// Subtracts two vectors. + /// + /// The first vector. + /// The second vector. + /// A vector that is the result of the subtraction. + public static Vector operator -(Vector a, Vector b) + { + return new Vector(a._x - b._x, a._y - b._y); + } + + /// + /// Returns the string representation of the point. + /// + /// The string representation of the point. + public override string ToString() + { + return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", _x, _y); + } + + /// + /// Returns a new vector with the specified X coordinate. + /// + /// The X coordinate. + /// The new vector. + public Vector WithX(double x) + { + return new Vector(x, _y); + } + + /// + /// Returns a new vector with the specified Y coordinate. + /// + /// The Y coordinate. + /// The new vector. + public Vector WithY(double y) + { + return new Vector(_x, y); + } + } +} diff --git a/src/Avalonia.SceneGraph/Visual.cs b/src/Avalonia.SceneGraph/Visual.cs new file mode 100644 index 0000000000..6ae5d80677 --- /dev/null +++ b/src/Avalonia.SceneGraph/Visual.cs @@ -0,0 +1,496 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Specialized; +using System.Linq; +using System.Reactive.Linq; +using Avalonia.Animation; +using Avalonia.Collections; +using Avalonia.Data; +using Avalonia.Logging; +using Avalonia.Media; +using Avalonia.Platform; +using Avalonia.Rendering; +using Avalonia.VisualTree; + +namespace Avalonia +{ + /// + /// Base class for controls that provides rendering and related visual properties. + /// + /// + /// The class acts as a node in the Avalonia scene graph and holds + /// all the information needed for an to render the control. + /// To traverse the scene graph (aka Visual Tree), use the extension methods defined + /// in . + /// + public class Visual : Animatable, IVisual + { + /// + /// Defines the property. + /// + public static readonly DirectProperty BoundsProperty = + AvaloniaProperty.RegisterDirect(nameof(Bounds), o => o.Bounds); + + /// + /// Defines the property. + /// + public static readonly StyledProperty ClipToBoundsProperty = + AvaloniaProperty.Register(nameof(ClipToBounds)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty IsVisibleProperty = + AvaloniaProperty.Register(nameof(IsVisible), true); + + /// + /// Defines the property. + /// + public static readonly StyledProperty OpacityProperty = + AvaloniaProperty.Register(nameof(Opacity), 1); + + /// + /// Defines the property. + /// + public static readonly StyledProperty RenderTransformProperty = + AvaloniaProperty.Register(nameof(RenderTransform)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty TransformOriginProperty = + AvaloniaProperty.Register(nameof(TransformOrigin), defaultValue: RelativePoint.Center); + + /// + /// Defines the property. + /// + public static readonly DirectProperty VisualParentProperty = + AvaloniaProperty.RegisterDirect("VisualParent", o => o._visualParent); + + /// + /// Defines the property. + /// + public static readonly StyledProperty ZIndexProperty = + AvaloniaProperty.Register(nameof(ZIndex)); + + private Rect _bounds; + private IVisual _visualParent; + + /// + /// Initializes static members of the class. + /// + static Visual() + { + AffectsRender(BoundsProperty, IsVisibleProperty, OpacityProperty); + RenderTransformProperty.Changed.Subscribe(RenderTransformChanged); + } + + /// + /// Initializes a new instance of the class. + /// + public Visual() + { + var visualChildren = new AvaloniaList(); + visualChildren.ResetBehavior = ResetBehavior.Remove; + visualChildren.Validate = ValidateLogicalChild; + visualChildren.CollectionChanged += VisualChildrenChanged; + VisualChildren = visualChildren; + } + + /// + /// Raised when the control is attached to a rooted visual tree. + /// + public event EventHandler AttachedToVisualTree; + + /// + /// Raised when the control is detached from a rooted visual tree. + /// + public event EventHandler DetachedFromVisualTree; + + /// + /// Gets the bounds of the scene graph node relative to its parent. + /// + public Rect Bounds + { + get { return _bounds; } + protected set { SetAndRaise(BoundsProperty, ref _bounds, value); } + } + + /// + /// Gets a value indicating whether the scene graph node should be clipped to its bounds. + /// + public bool ClipToBounds + { + get { return GetValue(ClipToBoundsProperty); } + set { SetValue(ClipToBoundsProperty, value); } + } + + /// + /// Gets a value indicating whether this scene graph node and all its parents are visible. + /// + public bool IsEffectivelyVisible + { + get { return this.GetSelfAndVisualAncestors().All(x => x.IsVisible); } + } + + /// + /// Gets a value indicating whether this scene graph node is visible. + /// + public bool IsVisible + { + get { return GetValue(IsVisibleProperty); } + set { SetValue(IsVisibleProperty, value); } + } + + /// + /// Gets the opacity of the scene graph node. + /// + public double Opacity + { + get { return GetValue(OpacityProperty); } + set { SetValue(OpacityProperty, value); } + } + + /// + /// Gets the render transform of the scene graph node. + /// + public Transform RenderTransform + { + get { return GetValue(RenderTransformProperty); } + set { SetValue(RenderTransformProperty, value); } + } + + /// + /// Gets the transform origin of the scene graph node. + /// + public RelativePoint TransformOrigin + { + get { return GetValue(TransformOriginProperty); } + set { SetValue(TransformOriginProperty, value); } + } + + /// + /// Gets the Z index of the node. + /// + /// + /// Controls with a higher will appear in front of controls with + /// a lower ZIndex. If two controls have the same ZIndex then the control that appears + /// later in the containing element's children collection will appear on top. + /// + public int ZIndex + { + get { return GetValue(ZIndexProperty); } + set { SetValue(ZIndexProperty, value); } + } + + /// + /// Gets the control's visual children. + /// + protected IAvaloniaList VisualChildren + { + get; + private set; + } + + /// + /// Gets the root of the visual tree, if the control is attached to a visual tree. + /// + protected IRenderRoot VisualRoot + { + get; + private set; + } + + /// + /// Gets a value indicating whether this scene graph node is attached to a visual root. + /// + bool IVisual.IsAttachedToVisualTree => VisualRoot != null; + + /// + /// Gets the scene graph node's child nodes. + /// + IAvaloniaReadOnlyList IVisual.VisualChildren => VisualChildren; + + /// + /// Gets the scene graph node's parent node. + /// + IVisual IVisual.VisualParent => _visualParent; + + /// + /// Gets the root of the visual tree, if the control is attached to a visual tree. + /// + IRenderRoot IVisual.VisualRoot => VisualRoot; + + /// + /// Invalidates the visual and queues a repaint. + /// + public void InvalidateVisual() + { + VisualRoot?.RenderQueueManager?.InvalidateRender(this); + } + + /// + /// Renders the visual to a . + /// + /// The drawing context. + public virtual void Render(DrawingContext context) + { + Contract.Requires(context != null); + } + + /// + /// Returns a transform that transforms the visual's coordinates into the coordinates + /// of the specified . + /// + /// The visual to translate the coordinates to. + /// + /// A containing the transform or null if the visuals don't share a + /// common ancestor. + /// + public Matrix? TransformToVisual(IVisual visual) + { + var common = this.FindCommonVisualAncestor(visual); + + if (common != null) + { + var thisOffset = GetOffsetFrom(common, this); + var thatOffset = GetOffsetFrom(common, visual); + return Matrix.CreateTranslation(-thatOffset) * Matrix.CreateTranslation(thisOffset); + } + + return null; + } + + /// + /// Indicates that a property change should cause to be + /// called. + /// + /// The properties. + /// + /// This method should be called in a control's static constructor with each property + /// on the control which when changed should cause a redraw. This is similar to WPF's + /// FrameworkPropertyMetadata.AffectsRender flag. + /// + protected static void AffectsRender(params AvaloniaProperty[] properties) + { + foreach (var property in properties) + { + property.Changed.Subscribe(AffectsRenderInvalidate); + } + } + + /// + /// Calls the method + /// for this control and all of its visual descendents. + /// + /// The event args. + protected virtual void OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs e) + { + Logger.Verbose(LogArea.Visual, this, "Attached to visual tree"); + + VisualRoot = e.Root; + + if (RenderTransform != null) + { + RenderTransform.Changed += RenderTransformChanged; + } + + OnAttachedToVisualTree(e); + + if (VisualChildren != null) + { + foreach (Visual child in VisualChildren.OfType()) + { + child.OnAttachedToVisualTreeCore(e); + } + } + } + + /// + /// Calls the method + /// for this control and all of its visual descendents. + /// + /// The event args. + protected virtual void OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) + { + Logger.Verbose(LogArea.Visual, this, "Detached from visual tree"); + + VisualRoot = null; + + if (RenderTransform != null) + { + RenderTransform.Changed -= RenderTransformChanged; + } + + OnDetachedFromVisualTree(e); + + if (VisualChildren != null) + { + foreach (Visual child in VisualChildren.OfType()) + { + child.OnDetachedFromVisualTreeCore(e); + } + } + } + + /// + /// Called when the control is added to a visual tree. + /// + /// The event args. + protected virtual void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + AttachedToVisualTree?.Invoke(this, e); + } + + /// + /// Called when the control is removed from a visual tree. + /// + /// The event args. + protected virtual void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + DetachedFromVisualTree?.Invoke(this, e); + } + + /// + /// Called when a property changes that should invalidate the visual. + /// + /// The event args. + private static void AffectsRenderInvalidate(AvaloniaPropertyChangedEventArgs e) + { + (e.Sender as Visual)?.InvalidateVisual(); + } + + /// + /// Gets the visual offset from the specified ancestor. + /// + /// The ancestor visual. + /// The visual. + /// The visual offset. + private static Vector GetOffsetFrom(IVisual ancestor, IVisual visual) + { + var result = new Vector(); + + while (visual != ancestor) + { + result = new Vector(result.X + visual.Bounds.X, result.Y + visual.Bounds.Y); + visual = visual.VisualParent; + + if (visual == null) + { + throw new ArgumentException("'visual' is not a descendent of 'ancestor'."); + } + } + + return result; + } + + /// + /// Called when a visual's changes. + /// + /// The event args. + private static void RenderTransformChanged(AvaloniaPropertyChangedEventArgs e) + { + var sender = e.Sender as Visual; + + if (sender?.VisualRoot != null) + { + var oldValue = e.OldValue as Transform; + var newValue = e.NewValue as Transform; + + if (oldValue != null) + { + oldValue.Changed -= sender.RenderTransformChanged; + } + + if (newValue != null) + { + newValue.Changed += sender.RenderTransformChanged; + } + + sender.InvalidateVisual(); + } + } + + /// + /// Ensures a visual child is not null. + /// + /// The visual child. + private static void ValidateLogicalChild(IVisual c) + { + if (c == null) + { + throw new ArgumentNullException("Cannot add null to VisualChildren."); + } + } + + /// + /// Called when the 's event + /// is fired. + /// + /// The sender. + /// The event args. + private void RenderTransformChanged(object sender, EventArgs e) + { + InvalidateVisual(); + } + + /// + /// Sets the visual parent of the Visual. + /// + /// The visual parent. + private void SetVisualParent(Visual value) + { + if (_visualParent == value) + { + return; + } + + var old = _visualParent; + _visualParent = value; + + if (VisualRoot != null) + { + var e = new VisualTreeAttachmentEventArgs(VisualRoot); + OnDetachedFromVisualTreeCore(e); + } + + if (_visualParent is IRenderRoot || _visualParent?.IsAttachedToVisualTree == true) + { + var root = this.GetVisualAncestors().OfType().FirstOrDefault(); + var e = new VisualTreeAttachmentEventArgs(root); + OnAttachedToVisualTreeCore(e); + } + + RaisePropertyChanged(VisualParentProperty, old, value, BindingPriority.LocalValue); + } + + /// + /// Called when the collection changes. + /// + /// The sender. + /// The event args. + private void VisualChildrenChanged(object sender, NotifyCollectionChangedEventArgs e) + { + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + foreach (Visual v in e.NewItems) + { + v.SetVisualParent(this); + } + + break; + + case NotifyCollectionChangedAction.Remove: + foreach (Visual v in e.OldItems) + { + v.SetVisualParent(null); + } + + break; + } + } + } +} diff --git a/src/Avalonia.SceneGraph/VisualExtensions.cs b/src/Avalonia.SceneGraph/VisualExtensions.cs new file mode 100644 index 0000000000..6e55070702 --- /dev/null +++ b/src/Avalonia.SceneGraph/VisualExtensions.cs @@ -0,0 +1,72 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Reactive.Linq; +using Avalonia.Animation; +using Avalonia.Collections; +using Avalonia.Data; +using Avalonia.Media; +using Avalonia.Platform; +using Avalonia.Rendering; +using Avalonia.VisualTree; + +namespace Avalonia +{ + /// + /// Extension methods for . + /// + public static class VisualExtensions + { + /// + /// Converts a point from screen to client coordinates. + /// + /// The visual. + /// The point in screen coordinates. + /// The point in client coordinates. + public static Point PointToClient(this IVisual visual, Point point) + { + var p = GetRootAndPosition(visual); + return p.Item1.PointToClient(point + p.Item2); + } + + /// + /// Converts a point from client to screen coordinates. + /// + /// The visual. + /// The point in client coordinates. + /// The point in screen coordinates. + public static Point PointToScreen(this IVisual visual, Point point) + { + var p = GetRootAndPosition(visual); + return p.Item1.PointToScreen(point + p.Item2); + } + + /// + /// Gets the root of the control's visual tree and the position of the control + /// in the root's coordinate space. + /// + /// The visual. + /// A tuple containing the root and the position of the control. + private static Tuple GetRootAndPosition(IVisual v) + { + var result = new Vector(); + + while (!(v is IRenderRoot)) + { + result = new Vector(result.X + v.Bounds.X, result.Y + v.Bounds.Y); + v = v.VisualParent; + + if (v == null) + { + throw new InvalidOperationException("Control is not attached to visual tree."); + } + } + + return Tuple.Create((IRenderRoot)v, result); + } + } +} diff --git a/src/Avalonia.SceneGraph/VisualTree/BoundsTracker.cs b/src/Avalonia.SceneGraph/VisualTree/BoundsTracker.cs new file mode 100644 index 0000000000..f39c0f0c87 --- /dev/null +++ b/src/Avalonia.SceneGraph/VisualTree/BoundsTracker.cs @@ -0,0 +1,64 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Linq; + +namespace Avalonia.VisualTree +{ + /// + /// Tracks the bounds of a control. + /// + /// + /// This class is used by Adorners to track the control that the adorner is attached to. + /// + public class BoundsTracker + { + /// + /// Starts tracking the specified visual. + /// + /// The visual. + /// An observable that returns the tracked bounds. + public IObservable Track(Visual visual) + { + return Track(visual, (Visual)visual.GetVisualRoot()); + } + + /// + /// Starts tracking the specified visual relative to another control. + /// + /// The visual. + /// The control that the tracking should be relative to. + /// An observable that returns the tracked bounds. + public IObservable Track(Visual visual, Visual relativeTo) + { + var visuals = visual.GetSelfAndVisualAncestors() + .TakeWhile(x => x != relativeTo) + .Reverse(); + var boundsSubscriptions = new List>(); + + foreach (var v in visuals.Cast()) + { + boundsSubscriptions.Add(v.GetObservable(Visual.BoundsProperty)); + } + + var bounds = boundsSubscriptions.CombineLatest().Select(ExtractBounds); + + // TODO: Track transform and clip rectangle. + return bounds.Select(x => new TransformedBounds(x, new Rect(), Matrix.Identity)); + } + + /// + /// Sums a collection of rectangles. + /// + /// The collection of rectangles. + /// The summed rectangle. + private static Rect ExtractBounds(IList rects) + { + var position = rects.Select(x => x.Position).Aggregate((a, b) => a + b); + return new Rect(position, rects.Last().Size); + } + } +} diff --git a/src/Avalonia.SceneGraph/VisualTree/IHostedVisualTreeRoot.cs b/src/Avalonia.SceneGraph/VisualTree/IHostedVisualTreeRoot.cs new file mode 100644 index 0000000000..6baf5d18a1 --- /dev/null +++ b/src/Avalonia.SceneGraph/VisualTree/IHostedVisualTreeRoot.cs @@ -0,0 +1,19 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.VisualTree +{ + /// + /// Interface for controls that are at the root of a hosted visual tree, such as popups. + /// + public interface IHostedVisualTreeRoot + { + /// + /// Gets the visual tree host. + /// + /// + /// The visual tree host. + /// + IVisual Host { get; } + } +} diff --git a/src/Avalonia.SceneGraph/VisualTree/IVisual.cs b/src/Avalonia.SceneGraph/VisualTree/IVisual.cs new file mode 100644 index 0000000000..4d6a33b99c --- /dev/null +++ b/src/Avalonia.SceneGraph/VisualTree/IVisual.cs @@ -0,0 +1,116 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Collections; +using Avalonia.Media; +using Avalonia.Rendering; + +namespace Avalonia.VisualTree +{ + /// + /// Represents a node in the visual scene graph. + /// + /// + /// The interface defines the interface required for a renderer to + /// render a scene graph. You should not usually need to reference this interface unless + /// you are writing a renderer; instead use the extension methods defined in + /// to traverse the scene graph. This interface is + /// implemented by . It should not be necessary to implement it + /// anywhere else. + /// + public interface IVisual + { + /// + /// Raised when the control is attached to a rooted visual tree. + /// + event EventHandler AttachedToVisualTree; + + /// + /// Raised when the control is detached from a rooted visual tree. + /// + event EventHandler DetachedFromVisualTree; + + /// + /// Gets the bounds of the scene graph node relative to its parent. + /// + Rect Bounds { get; } + + /// + /// Gets a value indicating whether the scene graph node should be clipped to its bounds. + /// + bool ClipToBounds { get; set; } + + /// + /// Gets a value indicating whether this scene graph node is attached to a visual root. + /// + bool IsAttachedToVisualTree { get; } + + /// + /// Gets a value indicating whether this scene graph node and all its parents are visible. + /// + bool IsEffectivelyVisible { get; } + + /// + /// Gets or sets a value indicating whether this scene graph node is visible. + /// + bool IsVisible { get; set; } + + /// + /// Gets or sets the opacity of the scene graph node. + /// + double Opacity { get; set; } + + /// + /// Gets or sets the render transform of the scene graph node. + /// + Transform RenderTransform { get; set; } + + /// + /// Gets or sets the transform origin of the scene graph node. + /// + RelativePoint TransformOrigin { get; set; } + + /// + /// Gets the scene graph node's child nodes. + /// + IAvaloniaReadOnlyList VisualChildren { get; } + + /// + /// Gets the scene graph node's parent node. + /// + IVisual VisualParent { get; } + + /// + /// Gets the root of the visual tree, if the control is attached to a visual tree. + /// + IRenderRoot VisualRoot { get; } + + /// + /// Gets or sets the Z index of the node. + /// + int ZIndex { get; set; } + + /// + /// Invalidates the visual and queues a repaint. + /// + void InvalidateVisual(); + + /// + /// Renders the scene graph node to a . + /// + /// The context. + void Render(DrawingContext context); + + /// + /// Returns a transform that transforms the visual's coordinates into the coordinates + /// of the specified . + /// + /// The visual to translate the coordinates to. + /// + /// A containing the transform or null if the visuals don't share a + /// common ancestor. + /// + Matrix? TransformToVisual(IVisual visual); + } +} diff --git a/src/Avalonia.SceneGraph/VisualTree/IVisualTreeHost.cs b/src/Avalonia.SceneGraph/VisualTree/IVisualTreeHost.cs new file mode 100644 index 0000000000..43560476da --- /dev/null +++ b/src/Avalonia.SceneGraph/VisualTree/IVisualTreeHost.cs @@ -0,0 +1,19 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.VisualTree +{ + /// + /// Interface for controls that host their own separate visual tree, such as popups. + /// + public interface IVisualTreeHost + { + /// + /// Gets the root of the hosted visual tree. + /// + /// + /// The root of the hosted visual tree. + /// + IVisual Root { get; } + } +} diff --git a/src/Avalonia.SceneGraph/VisualTree/TransformedBounds.cs b/src/Avalonia.SceneGraph/VisualTree/TransformedBounds.cs new file mode 100644 index 0000000000..c7e0f3abe0 --- /dev/null +++ b/src/Avalonia.SceneGraph/VisualTree/TransformedBounds.cs @@ -0,0 +1,39 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.VisualTree +{ + /// + /// Holds information about the bounds of a control, together with a transform and a clip/ + /// + public class TransformedBounds + { + /// + /// Initializes a new instance of the class. + /// + /// The control's bounds. + /// The control's clip rectangle. + /// The control's transform. + public TransformedBounds(Rect bounds, Rect clip, Matrix transform) + { + Bounds = bounds; + Clip = clip; + Transform = transform; + } + + /// + /// Gets the control's bounds. + /// + public Rect Bounds { get; } + + /// + /// Gets the control's clip rectangle. + /// + public Rect Clip { get; } + + /// + /// Gets the control's transform. + /// + public Matrix Transform { get; } + } +} diff --git a/src/Avalonia.SceneGraph/VisualTree/VisualExtensions.cs b/src/Avalonia.SceneGraph/VisualTree/VisualExtensions.cs new file mode 100644 index 0000000000..916f4c9bc6 --- /dev/null +++ b/src/Avalonia.SceneGraph/VisualTree/VisualExtensions.cs @@ -0,0 +1,196 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Avalonia.VisualTree +{ + /// + /// Provides extension methods for working with the visual tree. + /// + public static class VisualExtensions + { + /// + /// Tries to get the first common ancestor of two visuals. + /// + /// The first visual. + /// The second visual. + /// The common ancestor, or null if not found. + public static IVisual FindCommonVisualAncestor(this IVisual visual, IVisual target) + { + return visual.GetSelfAndVisualAncestors().Intersect(target.GetSelfAndVisualAncestors()) + .FirstOrDefault(); + } + + /// + /// Enumerates the ancestors of an in the visual tree. + /// + /// The visual. + /// The visual's ancestors. + public static IEnumerable GetVisualAncestors(this IVisual visual) + { + Contract.Requires(visual != null); + + visual = visual.VisualParent; + + while (visual != null) + { + yield return visual; + visual = visual.VisualParent; + } + } + + /// + /// Enumerates an and its ancestors in the visual tree. + /// + /// The visual. + /// The visual and its ancestors. + public static IEnumerable GetSelfAndVisualAncestors(this IVisual visual) + { + yield return visual; + + foreach (var ancestor in visual.GetVisualAncestors()) + { + yield return ancestor; + } + } + + /// + /// Gets the first visual in the visual tree whose bounds contain a point. + /// + /// The root visual to test. + /// The point. + /// The visuals at the requested point. + public static IVisual GetVisualAt(this IVisual visual, Point p) + { + Contract.Requires(visual != null); + + return visual.GetVisualsAt(p).FirstOrDefault(); + } + + /// + /// Enumerates the visuals in the visual tree whose bounds contain a point. + /// + /// The root visual to test. + /// The point. + /// The visuals at the requested point. + public static IEnumerable GetVisualsAt(this IVisual visual, Point p) + { + Contract.Requires(visual != null); + + if (visual.Bounds.Contains(p)) + { + p -= visual.Bounds.Position; + + if (visual.VisualChildren.Any()) + { + foreach (IVisual child in visual.VisualChildren) + { + foreach (IVisual v in child.GetVisualsAt(p)) + { + yield return v; + } + } + } + + yield return visual; + } + } + + /// + /// Enumerates the children of an in the visual tree. + /// + /// The visual. + /// The visual children. + public static IEnumerable GetVisualChildren(this IVisual visual) + { + return visual.VisualChildren; + } + + /// + /// Enumerates the descendents of an in the visual tree. + /// + /// The visual. + /// The visual's ancestors. + public static IEnumerable GetVisualDescendents(this IVisual visual) + { + foreach (IVisual child in visual.VisualChildren) + { + yield return child; + + foreach (IVisual descendent in child.GetVisualDescendents()) + { + yield return descendent; + } + } + } + + /// + /// Enumerates an and its descendents in the visual tree. + /// + /// The visual. + /// The visual and its ancestors. + public static IEnumerable GetSelfAndVisualDescendents(this IVisual visual) + { + yield return visual; + + foreach (var ancestor in visual.GetVisualDescendents()) + { + yield return ancestor; + } + } + + /// + /// Gets the visual parent of an . + /// + /// The visual. + /// The parent, or null if the visual is unparented. + public static IVisual GetVisualParent(this IVisual visual) + { + return visual.VisualParent; + } + + /// + /// Gets the visual parent of an . + /// + /// The type of the visual parent. + /// The visual. + /// + /// The parent, or null if the visual is unparented or its parent is not of type . + /// + public static T GetVisualParent(this IVisual visual) where T : class + { + return visual.VisualParent as T; + } + + /// + /// Gets the root visual for an . + /// + /// The visual. + /// + /// The root visual or null if the visual is not rooted. + /// + public static IVisual GetVisualRoot(this IVisual visual) + { + Contract.Requires(visual != null); + + return visual.VisualRoot as IVisual; + } + + /// + /// Tests whether an is an ancestor of another visual. + /// + /// The visual. + /// The potential descendent. + /// + /// True if is an ancestor of ; + /// otherwise false. + /// + public static bool IsVisualAncestorOf(this IVisual visual, IVisual target) + { + return target.GetVisualAncestors().Any(x => x == visual); + } + } +} diff --git a/src/Avalonia.SceneGraph/VisualTreeAttachmentEventArgs.cs b/src/Avalonia.SceneGraph/VisualTreeAttachmentEventArgs.cs new file mode 100644 index 0000000000..7a3b97f55b --- /dev/null +++ b/src/Avalonia.SceneGraph/VisualTreeAttachmentEventArgs.cs @@ -0,0 +1,31 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Rendering; + +namespace Avalonia +{ + /// + /// Holds the event arguments for the and + /// events. + /// + public class VisualTreeAttachmentEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The root visual. + public VisualTreeAttachmentEventArgs(IRenderRoot root) + { + Contract.Requires(root != null); + + Root = root; + } + + /// + /// Gets the root of the visual tree that the visual is being attached to or detached from. + /// + public IRenderRoot Root { get; } + } +} diff --git a/src/Perspex.SceneGraph/app.config b/src/Avalonia.SceneGraph/app.config similarity index 100% rename from src/Perspex.SceneGraph/app.config rename to src/Avalonia.SceneGraph/app.config diff --git a/src/Perspex.SceneGraph/packages.config b/src/Avalonia.SceneGraph/packages.config similarity index 100% rename from src/Perspex.SceneGraph/packages.config rename to src/Avalonia.SceneGraph/packages.config diff --git a/src/Avalonia.Styling/Avalonia.Styling.csproj b/src/Avalonia.Styling/Avalonia.Styling.csproj new file mode 100644 index 0000000000..d40627a16e --- /dev/null +++ b/src/Avalonia.Styling/Avalonia.Styling.csproj @@ -0,0 +1,112 @@ + + + + + 11.0 + Debug + AnyCPU + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} + Library + Properties + Avalonia + Avalonia.Styling + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Avalonia.Styling.XML + CS1591 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Avalonia.Styling.XML + CS1591 + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll + + + ..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll + + + ..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll + + + ..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll + + + + + + + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Avalonia.SceneGraph + + + + + \ No newline at end of file diff --git a/src/Avalonia.Styling/LogicalTree/ILogical.cs b/src/Avalonia.Styling/LogicalTree/ILogical.cs new file mode 100644 index 0000000000..f2291b42e9 --- /dev/null +++ b/src/Avalonia.Styling/LogicalTree/ILogical.cs @@ -0,0 +1,49 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Collections; + +namespace Avalonia.LogicalTree +{ + /// + /// Represents a node in the logical tree. + /// + public interface ILogical + { + /// + /// Raised when the control is attached to a rooted logical tree. + /// + event EventHandler AttachedToLogicalTree; + + /// + /// Raised when the control is detached from a rooted logical tree. + /// + event EventHandler DetachedFromLogicalTree; + + /// + /// Gets a value indicating whether the element is attached to a rooted logical tree. + /// + bool IsAttachedToLogicalTree { get; } + + /// + /// Gets the logical parent. + /// + ILogical LogicalParent { get; } + + /// + /// Gets the logical children. + /// + IAvaloniaReadOnlyList LogicalChildren { get; } + + /// + /// Notifies the control that it is being detached from a rooted logical tree. + /// + /// The event args. + /// + /// This method will be called automatically by the framework, you should not need to call + /// this method yourself. + /// + void NotifyDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e); + } +} diff --git a/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs b/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs new file mode 100644 index 0000000000..0d9c0f6daa --- /dev/null +++ b/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs @@ -0,0 +1,81 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Avalonia.LogicalTree +{ + public static class LogicalExtensions + { + public static IEnumerable GetLogicalAncestors(this ILogical logical) + { + Contract.Requires(logical != null); + + logical = logical.LogicalParent; + + while (logical != null) + { + yield return logical; + logical = logical.LogicalParent; + } + } + + public static IEnumerable GetSelfAndLogicalAncestors(this ILogical logical) + { + yield return logical; + + foreach (var ancestor in logical.GetLogicalAncestors()) + { + yield return ancestor; + } + } + + public static IEnumerable GetLogicalChildren(this ILogical logical) + { + return logical.LogicalChildren; + } + + public static IEnumerable GetLogicalDescendents(this ILogical logical) + { + foreach (ILogical child in logical.LogicalChildren) + { + yield return child; + + foreach (ILogical descendent in child.GetLogicalDescendents()) + { + yield return descendent; + } + } + } + + public static ILogical GetLogicalParent(this ILogical logical) + { + return logical.LogicalParent; + } + + public static T GetLogicalParent(this ILogical logical) where T : class + { + return logical.LogicalParent as T; + } + + public static IEnumerable GetLogicalSiblings(this ILogical logical) + { + ILogical parent = logical.LogicalParent; + + if (parent != null) + { + foreach (ILogical sibling in parent.LogicalChildren) + { + yield return sibling; + } + } + } + + public static bool IsLogicalParentOf(this ILogical logical, ILogical target) + { + return target.GetLogicalAncestors().Any(x => x == logical); + } + } +} diff --git a/src/Avalonia.Styling/LogicalTree/LogicalTreeAttachmentEventArgs.cs b/src/Avalonia.Styling/LogicalTree/LogicalTreeAttachmentEventArgs.cs new file mode 100644 index 0000000000..1b0eb2b61b --- /dev/null +++ b/src/Avalonia.Styling/LogicalTree/LogicalTreeAttachmentEventArgs.cs @@ -0,0 +1,31 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Styling; + +namespace Avalonia.LogicalTree +{ + /// + /// Holds the event arguments for the and + /// events. + /// + public class LogicalTreeAttachmentEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The root of the logical tree. + public LogicalTreeAttachmentEventArgs(IStyleHost root) + { + Contract.Requires(root != null); + + Root = root; + } + + /// + /// Gets the root of the logical tree that the control is being attached to or detached from. + /// + public IStyleHost Root { get; } + } +} diff --git a/src/Avalonia.Styling/Properties/AssemblyInfo.cs b/src/Avalonia.Styling/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..b53681aeed --- /dev/null +++ b/src/Avalonia.Styling/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using Avalonia.Metadata; + +[assembly: AssemblyTitle("Avalonia.Styling")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")] +[assembly: InternalsVisibleTo("Avalonia.Styling.UnitTests")] \ No newline at end of file diff --git a/src/Avalonia.Styling/Styling/ActivatedObservable.cs b/src/Avalonia.Styling/Styling/ActivatedObservable.cs new file mode 100644 index 0000000000..2cd324fff4 --- /dev/null +++ b/src/Avalonia.Styling/Styling/ActivatedObservable.cs @@ -0,0 +1,77 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive; +using System.Reactive.Linq; + +namespace Avalonia.Styling +{ + /// + /// An observable which is switched on or off according to an activator observable. + /// + /// + /// An has two inputs: an activator observable a + /// observable which produces the activated value. When the activator + /// produces true, the will produce the current activated + /// value. When the activator produces false it will produce + /// . + /// + internal class ActivatedObservable : ObservableBase, IDescription + { + /// + /// Initializes a new instance of the class. + /// + /// The activator. + /// An observable that produces the activated value. + /// The binding description. + public ActivatedObservable( + IObservable activator, + IObservable source, + string description) + { + Contract.Requires(activator != null); + Contract.Requires(source != null); + + Activator = activator; + Description = description; + Source = source; + } + + /// + /// Gets the activator observable. + /// + public IObservable Activator { get; } + + /// + /// Gets a description of the binding. + /// + public string Description { get; } + + /// + /// Gets an observable which produces the . + /// + public IObservable Source { get; } + + /// + /// Notifies the provider that an observer is to receive notifications. + /// + /// The observer. + /// IDisposable object used to unsubscribe from the observable sequence. + protected override IDisposable SubscribeCore(IObserver observer) + { + Contract.Requires(observer != null); + + var sourceCompleted = Source.LastOrDefaultAsync().Select(_ => Unit.Default); + var activatorCompleted = Activator.LastOrDefaultAsync().Select(_ => Unit.Default); + var completed = sourceCompleted.Merge(activatorCompleted); + + return Activator + .CombineLatest(Source, (x, y) => new { Active = x, Value = y }) + .Select(x => x.Active ? x.Value : AvaloniaProperty.UnsetValue) + .DistinctUntilChanged() + .TakeUntil(completed) + .Subscribe(observer); + } + } +} diff --git a/src/Avalonia.Styling/Styling/ActivatedSubject.cs b/src/Avalonia.Styling/Styling/ActivatedSubject.cs new file mode 100644 index 0000000000..4c2e8dde85 --- /dev/null +++ b/src/Avalonia.Styling/Styling/ActivatedSubject.cs @@ -0,0 +1,111 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Linq; +using System.Reactive.Subjects; + +namespace Avalonia.Styling +{ + /// + /// A subject which is switched on or off according to an activator observable. + /// + /// + /// An has two inputs: an activator observable and either an + /// or a observable which produces the + /// activated value. When the activator produces true, the will + /// produce the current activated value. When the activator produces false it will produce + /// . + /// + internal class ActivatedSubject : ActivatedObservable, ISubject, IDescription + { + private bool? _active; + private bool _completed; + private object _value; + + /// + /// Initializes a new instance of the class. + /// + /// The activator. + /// An observable that produces the activated value. + /// The binding description. + public ActivatedSubject( + IObservable activator, + ISubject source, + string description) + : base(activator, source, description) + { + Activator.Subscribe(ActivatorChanged, ActivatorError, ActivatorCompleted); + } + + /// + /// Gets the underlying subject. + /// + public new ISubject Source + { + get { return (ISubject)base.Source; } + } + + /// + /// Notifies all subscribed observers about the end of the sequence. + /// + public void OnCompleted() + { + if (_active.Value && !_completed) + { + Source.OnCompleted(); + } + } + + /// + /// Notifies all subscribed observers with the exception. + /// + /// The exception to send to all subscribed observers. + /// is null. + public void OnError(Exception error) + { + if (_active.Value && !_completed) + { + Source.OnError(error); + } + } + + /// + /// Notifies all subscribed observers with the value. + /// + /// The value to send to all subscribed observers. + public void OnNext(object value) + { + _value = value; + + if (_active.Value && !_completed) + { + Source.OnNext(value); + } + } + + private void ActivatorChanged(bool active) + { + bool first = !_active.HasValue; + + _active = active; + + if (!first) + { + Source.OnNext(active ? _value : AvaloniaProperty.UnsetValue); + } + } + + private void ActivatorCompleted() + { + _completed = true; + Source.OnCompleted(); + } + + private void ActivatorError(Exception e) + { + _completed = true; + Source.OnError(e); + } + } +} diff --git a/src/Avalonia.Styling/Styling/ActivatedValue.cs b/src/Avalonia.Styling/Styling/ActivatedValue.cs new file mode 100644 index 0000000000..3b9324c059 --- /dev/null +++ b/src/Avalonia.Styling/Styling/ActivatedValue.cs @@ -0,0 +1,72 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive; +using System.Reactive.Linq; + +namespace Avalonia.Styling +{ + /// + /// An value which is switched on or off according to an activator observable. + /// + /// + /// An has two inputs: an activator observable and an + /// . When the activator produces true, the + /// will produce the current value. When the activator + /// produces false it will produce . + /// + internal class ActivatedValue : ObservableBase, IDescription + { + /// + /// The activator. + /// + private readonly IObservable _activator; + + /// + /// Initializes a new instance of the class. + /// + /// The activator. + /// The activated value. + /// The binding description. + public ActivatedValue( + IObservable activator, + object value, + string description) + { + _activator = activator; + Value = value; + Description = description; + } + + /// + /// Gets the activated value. + /// + public object Value + { + get; + } + + /// + /// Gets a description of the binding. + /// + public string Description + { + get; + } + + /// + /// Notifies the provider that an observer is to receive notifications. + /// + /// The observer. + /// IDisposable object used to unsubscribe from the observable sequence. + protected override IDisposable SubscribeCore(IObserver observer) + { + Contract.Requires(observer != null); + + return _activator + .Select(active => active ? Value : AvaloniaProperty.UnsetValue) + .Subscribe(observer); + } + } +} diff --git a/src/Avalonia.Styling/Styling/ChildSelector.cs b/src/Avalonia.Styling/Styling/ChildSelector.cs new file mode 100644 index 0000000000..bcbf358721 --- /dev/null +++ b/src/Avalonia.Styling/Styling/ChildSelector.cs @@ -0,0 +1,56 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.LogicalTree; + +namespace Avalonia.Styling +{ + internal class ChildSelector : Selector + { + private readonly Selector _parent; + private string _selectorString; + + public ChildSelector(Selector parent) + { + if (parent == null) + { + throw new InvalidOperationException("Child selector must be preceeded by a selector."); + } + + _parent = parent; + } + + /// + public override bool InTemplate => _parent.InTemplate; + + /// + public override Type TargetType => null; + + public override string ToString() + { + if (_selectorString == null) + { + _selectorString = _parent.ToString() + " > "; + } + + return _selectorString; + } + + protected override SelectorMatch Evaluate(IStyleable control, bool subscribe) + { + var controlParent = ((ILogical)control).LogicalParent; + + if (controlParent != null) + { + return _parent.Match((IStyleable)controlParent, subscribe); + } + else + { + return SelectorMatch.False; + } + } + + protected override Selector MovePrevious() => null; + } +} diff --git a/src/Avalonia.Styling/Styling/DescendentSelector.cs b/src/Avalonia.Styling/Styling/DescendentSelector.cs new file mode 100644 index 0000000000..525f31cbf1 --- /dev/null +++ b/src/Avalonia.Styling/Styling/DescendentSelector.cs @@ -0,0 +1,80 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using Avalonia.LogicalTree; + +namespace Avalonia.Styling +{ + internal class DescendentSelector : Selector + { + private readonly Selector _parent; + private string _selectorString; + + public DescendentSelector(Selector parent) + { + if (parent == null) + { + throw new InvalidOperationException("Descendent selector must be preceeded by a selector."); + } + + _parent = parent; + } + + /// + public override bool InTemplate => _parent.InTemplate; + + /// + public override Type TargetType => null; + + public override string ToString() + { + if (_selectorString == null) + { + _selectorString = _parent.ToString() + ' '; + } + + return _selectorString; + } + + protected override SelectorMatch Evaluate(IStyleable control, bool subscribe) + { + ILogical c = (ILogical)control; + List> descendentMatches = new List>(); + + while (c != null) + { + c = c.LogicalParent; + + if (c is IStyleable) + { + var match = _parent.Match((IStyleable)c, subscribe); + + if (match.ImmediateResult != null) + { + if (match.ImmediateResult == true) + { + return SelectorMatch.True; + } + } + else + { + descendentMatches.Add(match.ObservableResult); + } + } + } + + if (descendentMatches.Count > 0) + { + return new SelectorMatch(StyleActivator.Or(descendentMatches)); + } + else + { + return SelectorMatch.False; + } + } + + protected override Selector MovePrevious() => null; + } +} diff --git a/src/Avalonia.Styling/Styling/IGlobalStyles.cs b/src/Avalonia.Styling/Styling/IGlobalStyles.cs new file mode 100644 index 0000000000..8bdf6f869b --- /dev/null +++ b/src/Avalonia.Styling/Styling/IGlobalStyles.cs @@ -0,0 +1,12 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Styling +{ + /// + /// Defines the style host that provides styles global to the application. + /// + public interface IGlobalStyles : IStyleRoot + { + } +} diff --git a/src/Avalonia.Styling/Styling/ISetter.cs b/src/Avalonia.Styling/Styling/ISetter.cs new file mode 100644 index 0000000000..da97638f07 --- /dev/null +++ b/src/Avalonia.Styling/Styling/ISetter.cs @@ -0,0 +1,21 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Styling +{ + /// + /// Represents a setter for a . + /// + public interface ISetter + { + /// + /// Applies the setter to a control. + /// + /// The style that is being applied. + /// The control. + /// An optional activator. + IDisposable Apply(IStyle style, IStyleable control, IObservable activator); + } +} \ No newline at end of file diff --git a/src/Avalonia.Styling/Styling/IStyle.cs b/src/Avalonia.Styling/Styling/IStyle.cs new file mode 100644 index 0000000000..7b8510fe2d --- /dev/null +++ b/src/Avalonia.Styling/Styling/IStyle.cs @@ -0,0 +1,29 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Styling +{ + /// + /// Defines the interface for styles. + /// + public interface IStyle + { + /// + /// Attaches the style to a control if the style's selector matches. + /// + /// The control to attach to. + /// + /// The control that contains this style. May be null. + /// + void Attach(IStyleable control, IStyleHost container); + + /// + /// Tries to find a named resource within the style. + /// + /// The resource name. + /// + /// The resource if found, otherwise . + /// + object FindResource(string name); + } +} diff --git a/src/Avalonia.Styling/Styling/IStyleHost.cs b/src/Avalonia.Styling/Styling/IStyleHost.cs new file mode 100644 index 0000000000..8422f18b46 --- /dev/null +++ b/src/Avalonia.Styling/Styling/IStyleHost.cs @@ -0,0 +1,22 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Styling +{ + /// + /// Defines an element that has a collection. + /// + public interface IStyleHost + { + /// + /// Gets the styles for the element. + /// + Styles Styles { get; } + + /// + /// Gets the parent style host element. + /// + IStyleHost StylingParent { get; } + + } +} diff --git a/src/Avalonia.Styling/Styling/IStyleRoot.cs b/src/Avalonia.Styling/Styling/IStyleRoot.cs new file mode 100644 index 0000000000..56778dcb9f --- /dev/null +++ b/src/Avalonia.Styling/Styling/IStyleRoot.cs @@ -0,0 +1,12 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Styling +{ + /// + /// Denotes the root in a tree. + /// + public interface IStyleRoot : IStyleHost + { + } +} diff --git a/src/Avalonia.Styling/Styling/IStyleable.cs b/src/Avalonia.Styling/Styling/IStyleable.cs new file mode 100644 index 0000000000..e03231e4ac --- /dev/null +++ b/src/Avalonia.Styling/Styling/IStyleable.cs @@ -0,0 +1,34 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Collections; + +namespace Avalonia.Styling +{ + /// + /// Interface for styleable elements. + /// + public interface IStyleable : IAvaloniaObject, INamed + { + /// + /// Signalled when the control's style should be removed. + /// + IObservable StyleDetach { get; } + + /// + /// Gets the list of classes for the control. + /// + IAvaloniaReadOnlyList Classes { get; } + + /// + /// Gets the type by which the control is styled. + /// + Type StyleKey { get; } + + /// + /// Gets the template parent of this element if the control comes from a template. + /// + ITemplatedControl TemplatedParent { get; } + } +} diff --git a/src/Avalonia.Styling/Styling/IStyler.cs b/src/Avalonia.Styling/Styling/IStyler.cs new file mode 100644 index 0000000000..0789c3d3cc --- /dev/null +++ b/src/Avalonia.Styling/Styling/IStyler.cs @@ -0,0 +1,12 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Styling +{ + public interface IStyler + { + void ApplyStyles(IStyleable control); + } +} diff --git a/src/Avalonia.Styling/Styling/ITemplatedControl.cs b/src/Avalonia.Styling/Styling/ITemplatedControl.cs new file mode 100644 index 0000000000..3bf981b69b --- /dev/null +++ b/src/Avalonia.Styling/Styling/ITemplatedControl.cs @@ -0,0 +1,11 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Styling +{ + public interface ITemplatedControl : IAvaloniaObject + { + } +} diff --git a/src/Avalonia.Styling/Styling/PropertyEqualsSelector.cs b/src/Avalonia.Styling/Styling/PropertyEqualsSelector.cs new file mode 100644 index 0000000000..57d5ad9271 --- /dev/null +++ b/src/Avalonia.Styling/Styling/PropertyEqualsSelector.cs @@ -0,0 +1,91 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Linq; +using System.Text; + +namespace Avalonia.Styling +{ + /// + /// A selector that matches the common case of a type and/or name followed by a collection of + /// style classes and pseudoclasses. + /// + internal class PropertyEqualsSelector : Selector + { + private readonly Selector _previous; + private readonly AvaloniaProperty _property; + private readonly object _value; + private string _selectorString; + + public PropertyEqualsSelector(Selector previous, AvaloniaProperty property, object value) + { + Contract.Requires(property != null); + + _previous = previous; + _property = property; + _value = value; + } + + /// + public override bool InTemplate => _previous?.InTemplate ?? false; + + /// + /// Gets the name of the control to match. + /// + public string Name { get; private set; } + + /// + public override Type TargetType => _previous?.TargetType; + + /// + public override string ToString() + { + if (_selectorString == null) + { + var builder = new StringBuilder(); + + if (_previous != null) + { + builder.Append(_previous.ToString()); + } + + builder.Append('['); + + if (_property.IsAttached) + { + builder.Append(_property.OwnerType.Name); + builder.Append('.'); + } + + builder.Append(_property.Name); + builder.Append('='); + builder.Append(_value); + builder.Append(']'); + + _selectorString = builder.ToString(); + } + + return _selectorString; + } + + /// + protected override SelectorMatch Evaluate(IStyleable control, bool subscribe) + { + if (!AvaloniaPropertyRegistry.Instance.IsRegistered(control, _property)) + { + return SelectorMatch.False; + } + else if (subscribe) + { + return new SelectorMatch(control.GetObservable(_property).Select(v => Equals(v, _value))); + } + else + { + return new SelectorMatch(control.GetValue(_property).Equals(_value)); + } + } + + protected override Selector MovePrevious() => _previous; + } +} diff --git a/src/Avalonia.Styling/Styling/Selector.cs b/src/Avalonia.Styling/Styling/Selector.cs new file mode 100644 index 0000000000..24c6be9b7a --- /dev/null +++ b/src/Avalonia.Styling/Styling/Selector.cs @@ -0,0 +1,86 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; + +namespace Avalonia.Styling +{ + /// + /// A selector in a . + /// + public abstract class Selector + { + /// + /// Gets a value indicating whether either this selector or a previous selector has moved + /// into a template. + /// + public abstract bool InTemplate { get; } + + /// + /// Gets the target type of the selector, if available. + /// + public abstract Type TargetType { get; } + + /// + /// Tries to match the selector with a control. + /// + /// The control. + /// + /// Whether the match should subscribe to changes in order to track the match over time, + /// or simply return an immediate result. + /// + /// A . + public SelectorMatch Match(IStyleable control, bool subscribe = true) + { + List> inputs = new List>(); + Selector selector = this; + + while (selector != null) + { + if (selector.InTemplate && control.TemplatedParent == null) + { + return SelectorMatch.False; + } + + var match = selector.Evaluate(control, subscribe); + + if (match.ImmediateResult == false) + { + return match; + } + else if (match.ObservableResult != null) + { + inputs.Add(match.ObservableResult); + } + + selector = selector.MovePrevious(); + } + + if (inputs.Count > 0) + { + return new SelectorMatch(StyleActivator.And(inputs)); + } + else + { + return SelectorMatch.True; + } + } + + /// + /// Evaluates the selector for a match. + /// + /// The control. + /// + /// Whether the match should subscribe to changes in order to track the match over time, + /// or simply return an immediate result. + /// + /// A . + protected abstract SelectorMatch Evaluate(IStyleable control, bool subscribe); + + /// + /// Moves to the previous selector. + /// + protected abstract Selector MovePrevious(); + } +} diff --git a/src/Avalonia.Styling/Styling/SelectorMatch.cs b/src/Avalonia.Styling/Styling/SelectorMatch.cs new file mode 100644 index 0000000000..e1d7f8dbaf --- /dev/null +++ b/src/Avalonia.Styling/Styling/SelectorMatch.cs @@ -0,0 +1,55 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Styling +{ + /// + /// Holds the result of a match. + /// + /// + /// There are two types of selectors - ones whose match can never change for a particular + /// control (such as ) and ones whose result can + /// change over time (such as . For the first + /// category of selectors, the value of will be set but for the + /// second, will be null and will + /// hold an observable which tracks the match. + /// + public class SelectorMatch + { + public static readonly SelectorMatch False = new SelectorMatch(false); + + public static readonly SelectorMatch True = new SelectorMatch(true); + + /// + /// Initializes a new instance of the class. + /// + /// The immediate match value. + public SelectorMatch(bool match) + { + ImmediateResult = match; + } + + /// + /// Initializes a new instance of the class. + /// + /// The observable match value. + public SelectorMatch(IObservable match) + { + ObservableResult = match; + } + + /// + /// Gets the immedate result of the selector match, in the case of selectors that cannot + /// change over time. + /// + public bool? ImmediateResult { get; } + + /// + /// Gets an observable which tracks the selector match, in the case of selectors that can + /// change over time. + /// + public IObservable ObservableResult { get; } + } +} diff --git a/src/Avalonia.Styling/Styling/Selectors.cs b/src/Avalonia.Styling/Styling/Selectors.cs new file mode 100644 index 0000000000..1b4c876f81 --- /dev/null +++ b/src/Avalonia.Styling/Styling/Selectors.cs @@ -0,0 +1,154 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Styling +{ + /// + /// Extension methods for . + /// + public static class Selectors + { + /// + /// Returns a selector which matches a previous selector's child. + /// + /// The previous selector. + /// The selector. + public static Selector Child(this Selector previous) + { + return new ChildSelector(previous); + } + + /// + /// Returns a selector which matches a control's style class. + /// + /// The previous selector. + /// The name of the style class. + /// The selector. + public static Selector Class(this Selector previous, string name) + { + var tac = previous as TypeNameAndClassSelector; + + if (tac != null) + { + tac.Classes.Add(name); + return tac; + } + else + { + return TypeNameAndClassSelector.ForClass(previous, name); + } + } + + /// + /// Returns a selector which matches a descendent of a previous selector. + /// + /// The previous selector. + /// The selector. + public static Selector Descendent(this Selector previous) + { + return new DescendentSelector(previous); + } + + /// + /// Returns a selector which matches a type or a derived type. + /// + /// The previous selector. + /// The type. + /// The selector. + public static Selector Is(this Selector previous, Type type) + { + return TypeNameAndClassSelector.Is(previous, type); + } + + /// + /// Returns a selector which matches a type or a derived type. + /// + /// The type. + /// The previous selector. + /// The selector. + public static Selector Is(this Selector previous) where T : IStyleable + { + return previous.Is(typeof(T)); + } + + /// + /// Returns a selector which matches a control's Name. + /// + /// The previous selector. + /// The name. + /// The selector. + public static Selector Name(this Selector previous, string name) + { + var tac = previous as TypeNameAndClassSelector; + + if (tac != null) + { + tac.Name = name; + return tac; + } + else + { + return TypeNameAndClassSelector.ForName(previous, name); + } + } + + /// + /// Returns a selector which matches a type. + /// + /// The previous selector. + /// The type. + /// The selector. + public static Selector OfType(this Selector previous, Type type) + { + return TypeNameAndClassSelector.OfType(previous, type); + } + + /// + /// Returns a selector which matches a type. + /// + /// The type. + /// The previous selector. + /// The selector. + public static Selector OfType(this Selector previous) where T : IStyleable + { + return previous.OfType(typeof(T)); + } + + /// + /// Returns a selector which matches a control with the specified property value. + /// + /// The property type. + /// The previous selector. + /// The property. + /// The property value. + /// The selector. + public static Selector PropertyEquals(this Selector previous, AvaloniaProperty property, object value) + { + return new PropertyEqualsSelector(previous, property, value); + } + + /// + /// Returns a selector which matches a control with the specified property value. + /// + /// The previous selector. + /// The property. + /// The property value. + /// The selector. + public static Selector PropertyEquals(this Selector previous, AvaloniaProperty property, object value) + { + return new PropertyEqualsSelector(previous, property, value); + } + + /// + /// Returns a selector which enters a lookless control's template. + /// + /// The previous selector. + /// The selector. + public static Selector Template(this Selector previous) + { + return new TemplateSelector(previous); + } + } +} diff --git a/src/Avalonia.Styling/Styling/Setter.cs b/src/Avalonia.Styling/Styling/Setter.cs new file mode 100644 index 0000000000..09faf37360 --- /dev/null +++ b/src/Avalonia.Styling/Styling/Setter.cs @@ -0,0 +1,149 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Disposables; +using System.Reactive.Subjects; +using Avalonia.Data; +using Avalonia.Metadata; +using Avalonia.Reactive; + +namespace Avalonia.Styling +{ + /// + /// A setter for a . + /// + /// + /// A is used to set a value on a + /// depending on a condition. + /// + public class Setter : ISetter + { + /// + /// Initializes a new instance of the class. + /// + public Setter() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The property to set. + /// The property value. + public Setter(AvaloniaProperty property, object value) + { + Property = property; + Value = value; + } + + /// + /// Gets or sets the property to set. + /// + public AvaloniaProperty Property + { + get; + set; + } + + /// + /// Gets or sets the property value. + /// + [Content] + [AssignBinding] + [DependsOn(nameof(Property))] + public object Value + { + get; + set; + } + + /// + /// Applies the setter to a control. + /// + /// The style that is being applied. + /// The control. + /// An optional activator. + public IDisposable Apply(IStyle style, IStyleable control, IObservable activator) + { + Contract.Requires(control != null); + + var description = style?.ToString(); + + if (Property == null) + { + throw new InvalidOperationException("Setter.Property must be set."); + } + + var binding = Value as IBinding; + + if (binding == null) + { + if (activator == null) + { + return control.Bind(Property, ObservableEx.SingleValue(Value), BindingPriority.Style); + } + else + { + var activated = new ActivatedValue(activator, Value, description); + return control.Bind(Property, activated, BindingPriority.StyleTrigger); + } + } + else + { + var source = binding.Initiate(control, Property); + + if (source != null) + { + var cloned = Clone(source, style, activator); + return BindingOperations.Apply(control, Property, cloned, null); + } + } + + return Disposable.Empty; + } + + private InstancedBinding Clone(InstancedBinding sourceInstance, IStyle style, IObservable activator) + { + InstancedBinding cloned; + + if (activator != null) + { + var description = style?.ToString(); + + if (sourceInstance.Subject != null) + { + var activated = new ActivatedSubject(activator, sourceInstance.Subject, description); + cloned = new InstancedBinding(activated, sourceInstance.Mode, BindingPriority.StyleTrigger); + } + else if (sourceInstance.Observable != null) + { + var activated = new ActivatedObservable(activator, sourceInstance.Observable, description); + cloned = new InstancedBinding(activated, sourceInstance.Mode, BindingPriority.StyleTrigger); + } + else + { + var activated = new ActivatedValue(activator, sourceInstance.Value, description); + cloned = new InstancedBinding(activated, BindingMode.OneWay, BindingPriority.StyleTrigger); + } + } + else + { + if (sourceInstance.Subject != null) + { + cloned = new InstancedBinding(sourceInstance.Subject, sourceInstance.Mode, BindingPriority.Style); + } + else if (sourceInstance.Observable != null) + { + cloned = new InstancedBinding(sourceInstance.Observable, sourceInstance.Mode, BindingPriority.Style); + } + else + { + cloned = new InstancedBinding(sourceInstance.Value, BindingPriority.Style); + } + } + + return cloned; + } + } +} diff --git a/src/Avalonia.Styling/Styling/Style.cs b/src/Avalonia.Styling/Styling/Style.cs new file mode 100644 index 0000000000..865b066b86 --- /dev/null +++ b/src/Avalonia.Styling/Styling/Style.cs @@ -0,0 +1,179 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Reactive.Linq; +using Avalonia.Metadata; + +namespace Avalonia.Styling +{ + /// + /// Defines a style. + /// + public class Style : IStyle + { + private static Dictionary> _applied = + new Dictionary>(); + + private Dictionary _resources; + + /// + /// Initializes a new instance of the class. + /// + public Style() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The style selector. + public Style(Func selector) + { + Selector = selector(null); + } + + /// + /// Gets or sets a dictionary of style resources. + /// + public IDictionary Resources + { + get + { + if (_resources == null) + { + _resources = new Dictionary(); + } + + return _resources; + } + + set + { + var resources = Resources; + + foreach (var i in value) + { + resources.Add(i); + } + } + } + + /// + /// Gets or sets style's selector. + /// + public Selector Selector { get; set; } + + /// + /// Gets or sets style's setters. + /// + [Content] + public IEnumerable Setters { get; set; } = new List(); + + /// + /// Attaches the style to a control if the style's selector matches. + /// + /// The control to attach to. + /// + /// The control that contains this style. May be null. + /// + public void Attach(IStyleable control, IStyleHost container) + { + if (Selector != null) + { + var description = "Style " + Selector.ToString(); + var match = Selector.Match(control); + + if (match.ImmediateResult != false) + { + var subs = GetSubscriptions(control); + + foreach (var setter in Setters) + { + var sub = setter.Apply(this, control, match.ObservableResult); + subs.Add(sub); + } + } + } + else if (control == container) + { + var subs = GetSubscriptions(control); + + foreach (var setter in Setters) + { + var sub = setter.Apply(this, control, null); + subs.Add(sub); + } + } + } + + /// + /// Tries to find a named resource within the style. + /// + /// The resource name. + /// + /// The resource if found, otherwise . + /// + public object FindResource(string name) + { + object result = null; + + if (_resources?.TryGetValue(name, out result) == true) + { + return result; + } + else + { + return AvaloniaProperty.UnsetValue; + } + } + + /// + /// Returns a string representation of the style. + /// + /// A string representation of the style. + public override string ToString() + { + if (Selector != null) + { + return "Style: " + Selector.ToString(); + } + else + { + return "Style"; + } + } + + private static List GetSubscriptions(IStyleable control) + { + List subscriptions; + + if (!_applied.TryGetValue(control, out subscriptions)) + { + subscriptions = new List(2); + subscriptions.Add(control.StyleDetach.Subscribe(ControlDetach)); + _applied.Add(control, subscriptions); + } + + return subscriptions; + } + + /// + /// Called when a control's is signalled to remove + /// all applied styles. + /// + /// The control. + private static void ControlDetach(IStyleable control) + { + var subscriptions = _applied[control]; + + foreach (var subscription in subscriptions) + { + subscription.Dispose(); + } + + _applied.Remove(control); + } + } +} diff --git a/src/Avalonia.Styling/Styling/StyleActivator.cs b/src/Avalonia.Styling/Styling/StyleActivator.cs new file mode 100644 index 0000000000..5bdea9f42e --- /dev/null +++ b/src/Avalonia.Styling/Styling/StyleActivator.cs @@ -0,0 +1,56 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive; +using System.Reactive.Linq; + +namespace Avalonia.Styling +{ + public enum ActivatorMode + { + And, + Or, + } + + public static class StyleActivator + { + public static IObservable And(IList> inputs) + { + if (inputs.Count == 0) + { + throw new ArgumentException("StyleActivator.And inputs may not be empty."); + } + else if (inputs.Count == 1) + { + return inputs[0]; + } + else + { + return inputs.CombineLatest() + .Select(values => values.All(x => x)) + .DistinctUntilChanged(); + } + } + + public static IObservable Or(IList> inputs) + { + if (inputs.Count == 0) + { + throw new ArgumentException("StyleActivator.Or inputs may not be empty."); + } + else if (inputs.Count == 1) + { + return inputs[0]; + } + else + { + return inputs.CombineLatest() + .Select(values => values.Any(x => x)) + .DistinctUntilChanged(); + } + } + } +} diff --git a/src/Avalonia.Styling/Styling/StyleExtensions.cs b/src/Avalonia.Styling/Styling/StyleExtensions.cs new file mode 100644 index 0000000000..e1073335a0 --- /dev/null +++ b/src/Avalonia.Styling/Styling/StyleExtensions.cs @@ -0,0 +1,39 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Styling +{ + public static class StyleExtensions + { + /// + /// Tries to find a named style resource. + /// + /// The control from which to find the resource. + /// The resource name. + /// + /// The resource if found, otherwise . + /// + public static object FindStyleResource(this IStyleHost control, string name) + { + Contract.Requires(control != null); + Contract.Requires(name != null); + Contract.Requires(!string.IsNullOrWhiteSpace(name)); + + while (control != null) + { + var result = control.Styles.FindResource(name); + + if (result != AvaloniaProperty.UnsetValue) + { + return result; + } + + control = control.StylingParent; + } + + return AvaloniaProperty.UnsetValue; + } + } +} diff --git a/src/Avalonia.Styling/Styling/Styler.cs b/src/Avalonia.Styling/Styling/Styler.cs new file mode 100644 index 0000000000..880e435b58 --- /dev/null +++ b/src/Avalonia.Styling/Styling/Styler.cs @@ -0,0 +1,35 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Styling +{ + public class Styler : IStyler + { + public void ApplyStyles(IStyleable control) + { + var styleHost = control as IStyleHost; + + if (styleHost != null) + { + ApplyStyles(control, styleHost); + } + } + + private void ApplyStyles(IStyleable control, IStyleHost styleHost) + { + Contract.Requires(control != null); + Contract.Requires(styleHost != null); + + var parentContainer = styleHost.StylingParent; + + if (parentContainer != null) + { + ApplyStyles(control, parentContainer); + } + + styleHost.Styles.Attach(control, styleHost); + } + } +} diff --git a/src/Avalonia.Styling/Styling/Styles.cs b/src/Avalonia.Styling/Styling/Styles.cs new file mode 100644 index 0000000000..770ef8344f --- /dev/null +++ b/src/Avalonia.Styling/Styling/Styles.cs @@ -0,0 +1,51 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Linq; +using Avalonia.Collections; + +namespace Avalonia.Styling +{ + /// + /// A style that consists of a number of child styles. + /// + public class Styles : AvaloniaList, IStyle + { + /// + /// Attaches the style to a control if the style's selector matches. + /// + /// The control to attach to. + /// + /// The control that contains this style. May be null. + /// + public void Attach(IStyleable control, IStyleHost container) + { + foreach (IStyle style in this) + { + style.Attach(control, container); + } + } + + /// + /// Tries to find a named resource within the style. + /// + /// The resource name. + /// + /// The resource if found, otherwise . + /// + public object FindResource(string name) + { + foreach (var style in this.Reverse()) + { + var result = style.FindResource(name); + + if (result != AvaloniaProperty.UnsetValue) + { + return result; + } + } + + return AvaloniaProperty.UnsetValue; + } + } +} diff --git a/src/Avalonia.Styling/Styling/TemplateSelector.cs b/src/Avalonia.Styling/Styling/TemplateSelector.cs new file mode 100644 index 0000000000..6919b4ad27 --- /dev/null +++ b/src/Avalonia.Styling/Styling/TemplateSelector.cs @@ -0,0 +1,54 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Styling +{ + internal class TemplateSelector : Selector + { + private readonly Selector _parent; + private string _selectorString; + + public TemplateSelector(Selector parent) + { + if (parent == null) + { + throw new InvalidOperationException("Template selector must be preceeded by a selector."); + } + + _parent = parent; + } + + /// + public override bool InTemplate => true; + + /// + public override Type TargetType => null; + + public override string ToString() + { + if (_selectorString == null) + { + _selectorString = _parent.ToString() + " /template/ "; + } + + return _selectorString; + } + + protected override SelectorMatch Evaluate(IStyleable control, bool subscribe) + { + IStyleable templatedParent = control.TemplatedParent as IStyleable; + + if (templatedParent == null) + { + throw new InvalidOperationException( + "Cannot call Template selector on control with null TemplatedParent."); + } + + return _parent.Match(templatedParent, subscribe) ?? SelectorMatch.True; + } + + protected override Selector MovePrevious() => null; + } +} diff --git a/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs b/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs new file mode 100644 index 0000000000..2edbed803a --- /dev/null +++ b/src/Avalonia.Styling/Styling/TypeNameAndClassSelector.cs @@ -0,0 +1,207 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Reactive; +using System.Reactive.Linq; +using System.Reflection; +using System.Text; + +namespace Avalonia.Styling +{ + /// + /// A selector that matches the common case of a type and/or name followed by a collection of + /// style classes and pseudoclasses. + /// + internal class TypeNameAndClassSelector : Selector + { + private readonly Selector _previous; + private Type _targetType; + private Lazy> _classes = new Lazy>(() => new List()); + private string _selectorString; + + public static TypeNameAndClassSelector OfType(Selector previous, Type targetType) + { + var result = new TypeNameAndClassSelector(previous); + result._targetType = targetType; + result.IsConcreteType = true; + return result; + } + + public static TypeNameAndClassSelector Is(Selector previous, Type targetType) + { + var result = new TypeNameAndClassSelector(previous); + result._targetType = targetType; + result.IsConcreteType = false; + return result; + } + + public static TypeNameAndClassSelector ForName(Selector previous, string name) + { + var result = new TypeNameAndClassSelector(previous); + result.Name = name; + return result; + } + + public static TypeNameAndClassSelector ForClass(Selector previous, string className) + { + var result = new TypeNameAndClassSelector(previous); + result.Classes.Add(className); + return result; + } + + protected TypeNameAndClassSelector(Selector previous) + { + _previous = previous; + } + + /// + public override bool InTemplate => _previous?.InTemplate ?? false; + + /// + /// Gets the name of the control to match. + /// + public string Name { get; set; } + + /// + public override Type TargetType => _targetType ?? _previous?.TargetType; + + /// + /// Whether the selector matches the concrete or any object which + /// implements . + /// + public bool IsConcreteType { get; private set; } + + /// + /// The style classes which the selector matches. + /// + public IList Classes => _classes.Value; + + /// + public override string ToString() + { + if (_selectorString == null) + { + _selectorString = BuildSelectorString(); + } + + return _selectorString; + } + + /// + protected override SelectorMatch Evaluate(IStyleable control, bool subscribe) + { + if (TargetType != null) + { + var controlType = control.StyleKey ?? control.GetType(); + + if (IsConcreteType) + { + if (controlType != TargetType) + { + return SelectorMatch.False; + } + } + else + { + if (!TargetType.GetTypeInfo().IsAssignableFrom(controlType.GetTypeInfo())) + { + return SelectorMatch.False; + } + } + } + + if (Name != null && control.Name != Name) + { + return SelectorMatch.False; + } + + if (_classes.IsValueCreated && _classes.Value.Count > 0) + { + if (subscribe) + { + var observable = Observable.FromEventPattern< + NotifyCollectionChangedEventHandler, + NotifyCollectionChangedEventArgs>( + x => control.Classes.CollectionChanged += x, + x => control.Classes.CollectionChanged -= x) + .StartWith((EventPattern)null) + .Select(_ => Matches(control.Classes)); + return new SelectorMatch(observable); + } + else + { + return new SelectorMatch(Matches(control.Classes)); + } + } + else + { + return SelectorMatch.True; + } + } + + protected override Selector MovePrevious() => _previous; + + private bool Matches(IEnumerable classes) + { + int remaining = Classes.Count; + + foreach (var c in classes) + { + if (Classes.Contains(c)) + { + --remaining; + } + } + + return remaining == 0; + } + + private string BuildSelectorString() + { + var builder = new StringBuilder(); + + if (_previous != null) + { + builder.Append(_previous.ToString()); + } + + if (TargetType != null) + { + if (IsConcreteType) + { + builder.Append(TargetType.Name); + } + else + { + builder.Append(":is("); + builder.Append(TargetType.Name); + builder.Append(")"); + } + } + + if (Name != null) + { + builder.Append('#'); + builder.Append(Name); + } + + if (_classes.IsValueCreated && _classes.Value.Count > 0) + { + foreach (var c in Classes) + { + if (!c.StartsWith(":")) + { + builder.Append('.'); + } + + builder.Append(c); + } + } + + return builder.ToString(); + } + } +} diff --git a/src/Perspex.Styling/Styling/packages.config b/src/Avalonia.Styling/Styling/packages.config similarity index 100% rename from src/Perspex.Styling/Styling/packages.config rename to src/Avalonia.Styling/Styling/packages.config diff --git a/src/Perspex.Styling/app.config b/src/Avalonia.Styling/app.config similarity index 100% rename from src/Perspex.Styling/app.config rename to src/Avalonia.Styling/app.config diff --git a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml new file mode 100644 index 0000000000..2d1e833199 --- /dev/null +++ b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj b/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj new file mode 100644 index 0000000000..2c07188234 --- /dev/null +++ b/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj @@ -0,0 +1,216 @@ + + + + + 11.0 + Debug + AnyCPU + {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F} + Library + Properties + Avalonia.Themes.Default + Avalonia.Themes.Default + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Avalonia.Themes.Default.XML + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Avalonia.Themes.Default.XML + + + + + {3e53a01a-b331-47f3-b828-4a5717e77a24} + Avalonia.Markup.Xaml + + + {D211E587-D8BC-45B9-95A4-F297C8FA5200} + Avalonia.Animation + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + {D2221C82-4A25-4583-9B43-D791E3F6820C} + Avalonia.Controls + + + {62024B2D-53EB-4638-B26B-85EEAA54866E} + Avalonia.Input + + + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B} + Avalonia.Interactivity + + + {42472427-4774-4C81-8AFF-9F27B8E31721} + Avalonia.Layout + + + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Avalonia.SceneGraph + + + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} + Avalonia.Styling + + + + + Properties\SharedAssemblyInfo.cs + + + DefaultTheme.xaml + + + + + + ..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll + + + ..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll + + + ..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll + + + ..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll + + + + + Designer + + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + + Designer + + + Designer + + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + + + Designer + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Button.xaml b/src/Avalonia.Themes.Default/Button.xaml new file mode 100644 index 0000000000..bf8072d588 --- /dev/null +++ b/src/Avalonia.Themes.Default/Button.xaml @@ -0,0 +1,33 @@ + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Carousel.xaml b/src/Avalonia.Themes.Default/Carousel.xaml new file mode 100644 index 0000000000..c7bf296ede --- /dev/null +++ b/src/Avalonia.Themes.Default/Carousel.xaml @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/CheckBox.xaml b/src/Avalonia.Themes.Default/CheckBox.xaml new file mode 100644 index 0000000000..b1596e6b74 --- /dev/null +++ b/src/Avalonia.Themes.Default/CheckBox.xaml @@ -0,0 +1,44 @@ + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ContentControl.xaml b/src/Avalonia.Themes.Default/ContentControl.xaml new file mode 100644 index 0000000000..1af449a447 --- /dev/null +++ b/src/Avalonia.Themes.Default/ContentControl.xaml @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ContextMenu.xaml b/src/Avalonia.Themes.Default/ContextMenu.xaml new file mode 100644 index 0000000000..88454036dc --- /dev/null +++ b/src/Avalonia.Themes.Default/ContextMenu.xaml @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml new file mode 100644 index 0000000000..0fab9ceec7 --- /dev/null +++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml.cs b/src/Avalonia.Themes.Default/DefaultTheme.xaml.cs new file mode 100644 index 0000000000..0a65a8ce42 --- /dev/null +++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml.cs @@ -0,0 +1,22 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Markup.Xaml; +using Avalonia.Styling; + +namespace Avalonia.Themes.Default +{ + /// + /// The default Avalonia theme. + /// + public class DefaultTheme : Styles + { + /// + /// Initializes a new instance of the class. + /// + public DefaultTheme() + { + AvaloniaXamlLoader.Load(this); + } + } +} diff --git a/src/Avalonia.Themes.Default/DropDown.xaml b/src/Avalonia.Themes.Default/DropDown.xaml new file mode 100644 index 0000000000..20c497bfd4 --- /dev/null +++ b/src/Avalonia.Themes.Default/DropDown.xaml @@ -0,0 +1,52 @@ + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/DropDownItem.xaml b/src/Avalonia.Themes.Default/DropDownItem.xaml new file mode 100644 index 0000000000..f4e7e3a5b5 --- /dev/null +++ b/src/Avalonia.Themes.Default/DropDownItem.xaml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Expander.xaml b/src/Avalonia.Themes.Default/Expander.xaml new file mode 100644 index 0000000000..4123d1a9df --- /dev/null +++ b/src/Avalonia.Themes.Default/Expander.xaml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/FocusAdorner.xaml b/src/Avalonia.Themes.Default/FocusAdorner.xaml new file mode 100644 index 0000000000..573c43dc8d --- /dev/null +++ b/src/Avalonia.Themes.Default/FocusAdorner.xaml @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/GridSplitter.xaml b/src/Avalonia.Themes.Default/GridSplitter.xaml new file mode 100644 index 0000000000..9fc46e18a5 --- /dev/null +++ b/src/Avalonia.Themes.Default/GridSplitter.xaml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Themes.Default/ItemsControl.xaml b/src/Avalonia.Themes.Default/ItemsControl.xaml new file mode 100644 index 0000000000..aa56a21e82 --- /dev/null +++ b/src/Avalonia.Themes.Default/ItemsControl.xaml @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/LayoutTransformControl.xaml b/src/Avalonia.Themes.Default/LayoutTransformControl.xaml new file mode 100644 index 0000000000..b1ebb2a819 --- /dev/null +++ b/src/Avalonia.Themes.Default/LayoutTransformControl.xaml @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ListBox.xaml b/src/Avalonia.Themes.Default/ListBox.xaml new file mode 100644 index 0000000000..ad410c1b5f --- /dev/null +++ b/src/Avalonia.Themes.Default/ListBox.xaml @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ListBoxItem.xaml b/src/Avalonia.Themes.Default/ListBoxItem.xaml new file mode 100644 index 0000000000..af384ae83b --- /dev/null +++ b/src/Avalonia.Themes.Default/ListBoxItem.xaml @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Menu.xaml b/src/Avalonia.Themes.Default/Menu.xaml new file mode 100644 index 0000000000..397f247a4f --- /dev/null +++ b/src/Avalonia.Themes.Default/Menu.xaml @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/MenuItem.xaml b/src/Avalonia.Themes.Default/MenuItem.xaml new file mode 100644 index 0000000000..bb7c6337a6 --- /dev/null +++ b/src/Avalonia.Themes.Default/MenuItem.xaml @@ -0,0 +1,133 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/PopupRoot.xaml b/src/Avalonia.Themes.Default/PopupRoot.xaml new file mode 100644 index 0000000000..b0b75f3652 --- /dev/null +++ b/src/Avalonia.Themes.Default/PopupRoot.xaml @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ProgressBar.xaml b/src/Avalonia.Themes.Default/ProgressBar.xaml new file mode 100644 index 0000000000..94102c2712 --- /dev/null +++ b/src/Avalonia.Themes.Default/ProgressBar.xaml @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Properties/AssemblyInfo.cs b/src/Avalonia.Themes.Default/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..3657673618 --- /dev/null +++ b/src/Avalonia.Themes.Default/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; + +[assembly: AssemblyTitle("Avalonia.Themes.Default")] diff --git a/src/Avalonia.Themes.Default/RadioButton.xaml b/src/Avalonia.Themes.Default/RadioButton.xaml new file mode 100644 index 0000000000..25a2510078 --- /dev/null +++ b/src/Avalonia.Themes.Default/RadioButton.xaml @@ -0,0 +1,43 @@ + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ScrollBar.xaml b/src/Avalonia.Themes.Default/ScrollBar.xaml new file mode 100644 index 0000000000..89f6f26c08 --- /dev/null +++ b/src/Avalonia.Themes.Default/ScrollBar.xaml @@ -0,0 +1,35 @@ + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ScrollViewer.xaml b/src/Avalonia.Themes.Default/ScrollViewer.xaml new file mode 100644 index 0000000000..3e211f460c --- /dev/null +++ b/src/Avalonia.Themes.Default/ScrollViewer.xaml @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Separator.xaml b/src/Avalonia.Themes.Default/Separator.xaml new file mode 100644 index 0000000000..e20ff9fc36 --- /dev/null +++ b/src/Avalonia.Themes.Default/Separator.xaml @@ -0,0 +1,25 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Slider.xaml b/src/Avalonia.Themes.Default/Slider.xaml new file mode 100644 index 0000000000..4fa293fbc5 --- /dev/null +++ b/src/Avalonia.Themes.Default/Slider.xaml @@ -0,0 +1,66 @@ + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/TabControl.xaml b/src/Avalonia.Themes.Default/TabControl.xaml new file mode 100644 index 0000000000..2397ce4e95 --- /dev/null +++ b/src/Avalonia.Themes.Default/TabControl.xaml @@ -0,0 +1,50 @@ + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/TabStrip.xaml b/src/Avalonia.Themes.Default/TabStrip.xaml new file mode 100644 index 0000000000..df52d7afbe --- /dev/null +++ b/src/Avalonia.Themes.Default/TabStrip.xaml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/TabStripItem.xaml b/src/Avalonia.Themes.Default/TabStripItem.xaml new file mode 100644 index 0000000000..8a33c7f8c1 --- /dev/null +++ b/src/Avalonia.Themes.Default/TabStripItem.xaml @@ -0,0 +1,19 @@ + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/TextBox.xaml new file mode 100644 index 0000000000..d4208d211c --- /dev/null +++ b/src/Avalonia.Themes.Default/TextBox.xaml @@ -0,0 +1,60 @@ + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ToggleButton.xaml b/src/Avalonia.Themes.Default/ToggleButton.xaml new file mode 100644 index 0000000000..32b9b4b991 --- /dev/null +++ b/src/Avalonia.Themes.Default/ToggleButton.xaml @@ -0,0 +1,37 @@ + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/ToolTip.xaml b/src/Avalonia.Themes.Default/ToolTip.xaml new file mode 100644 index 0000000000..97a326f033 --- /dev/null +++ b/src/Avalonia.Themes.Default/ToolTip.xaml @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/TreeView.xaml b/src/Avalonia.Themes.Default/TreeView.xaml new file mode 100644 index 0000000000..c8c22fe299 --- /dev/null +++ b/src/Avalonia.Themes.Default/TreeView.xaml @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/TreeViewItem.xaml b/src/Avalonia.Themes.Default/TreeViewItem.xaml new file mode 100644 index 0000000000..54aebb2951 --- /dev/null +++ b/src/Avalonia.Themes.Default/TreeViewItem.xaml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia.Themes.Default/Window.xaml b/src/Avalonia.Themes.Default/Window.xaml new file mode 100644 index 0000000000..9953cba32a --- /dev/null +++ b/src/Avalonia.Themes.Default/Window.xaml @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/src/Perspex.Themes.Default/app.config b/src/Avalonia.Themes.Default/app.config similarity index 100% rename from src/Perspex.Themes.Default/app.config rename to src/Avalonia.Themes.Default/app.config diff --git a/src/Perspex.Themes.Default/packages.config b/src/Avalonia.Themes.Default/packages.config similarity index 100% rename from src/Perspex.Themes.Default/packages.config rename to src/Avalonia.Themes.Default/packages.config diff --git a/src/Gtk/Avalonia.Cairo/Avalonia.Cairo.csproj b/src/Gtk/Avalonia.Cairo/Avalonia.Cairo.csproj new file mode 100644 index 0000000000..ab5d4c10cc --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Avalonia.Cairo.csproj @@ -0,0 +1,121 @@ + + + + + Debug + AnyCPU + {FB05AC90-89BA-4F2F-A924-F37875FB547C} + Library + Properties + Avalonia.Cairo + Avalonia.Cairo + v4.5 + 512 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + ..\..\..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + + + ..\..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + + + + + + + + + + + + + + + + + + + + + + + + + {D211E587-D8BC-45B9-95A4-F297C8FA5200} + Avalonia.Animation + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + {d2221c82-4a25-4583-9b43-d791e3f6820c} + Avalonia.Controls + + + {62024b2d-53eb-4638-b26b-85eeaa54866e} + Avalonia.Input + + + {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} + Avalonia.Interactivity + + + {42472427-4774-4C81-8AFF-9F27B8E31721} + Avalonia.Layout + + + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Avalonia.SceneGraph + + + {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} + Avalonia.Styling + + + + + + + + + + \ No newline at end of file diff --git a/src/Gtk/Avalonia.Cairo/CairoExtensions.cs b/src/Gtk/Avalonia.Cairo/CairoExtensions.cs new file mode 100644 index 0000000000..daea3b0239 --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/CairoExtensions.cs @@ -0,0 +1,64 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Cairo +{ + using Cairo = global::Cairo; + + public static class CairoExtensions + { + public static Cairo.Color ToCairo(this Avalonia.Media.Color color) + { + return new Cairo.Color(color.R / 255.0, color.G / 255.0, color.B / 255.0, color.A / 255.0); + } + + public static Cairo.Matrix ToCairo(this Matrix m) + { + return new Cairo.Matrix(m.M11, m.M12, m.M21, m.M22, m.M31, m.M32); + } + + public static Cairo.PointD ToCairo(this Point p) + { + return new Cairo.PointD(p.X, p.Y); + } + + public static Cairo.Rectangle ToCairo(this Rect rect) + { + return new Cairo.Rectangle(rect.X, rect.Y, rect.Width, rect.Height); + } + + public static Rect ToAvalonia(this Cairo.Rectangle rect) + { + return new Rect(rect.X, rect.Y, rect.Width, rect.Height); + } + + public static Rect ToAvalonia(this Pango.Rectangle rect) + { + return new Rect( + Pango.Units.ToDouble(rect.X), + Pango.Units.ToDouble(rect.Y), + Pango.Units.ToDouble(rect.Width), + Pango.Units.ToDouble(rect.Height)); + } + + public static Pango.Weight ToCairo(this Avalonia.Media.FontWeight weight) + { + return (Pango.Weight)weight; + } + + public static Pango.Alignment ToCairo(this Avalonia.Media.TextAlignment alignment) + { + if (alignment == Avalonia.Media.TextAlignment.Left) + { + return Pango.Alignment.Left; + } + + if (alignment == Avalonia.Media.TextAlignment.Center) + { + return Pango.Alignment.Center; + } + + return Pango.Alignment.Right; + } + } +} \ No newline at end of file diff --git a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs new file mode 100644 index 0000000000..0dd708d9d3 --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs @@ -0,0 +1,93 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Cairo.Media; +using Avalonia.Cairo.Media.Imaging; +using Avalonia.Media; +using Avalonia.Platform; + +namespace Avalonia +{ + public static class GtkApplicationExtensions + { + public static TApp UseCairo(this TApp app) where TApp : Application + { + Avalonia.Cairo.CairoPlatform.Initialize(); + return app; + } + } +} + +namespace Avalonia.Cairo +{ + using System.IO; + using global::Cairo; + + public class CairoPlatform : IPlatformRenderInterface + { + private static readonly CairoPlatform s_instance = new CairoPlatform(); + + private static readonly Pango.Context s_pangoContext = CreatePangoContext(); + + public static void Initialize() => AvaloniaLocator.CurrentMutable.Bind().ToConstant(s_instance); + + public IBitmapImpl CreateBitmap(int width, int height) + { + return new BitmapImpl(new Gdk.Pixbuf(Gdk.Colorspace.Rgb, true, 32, width, height)); + } + + public IFormattedTextImpl CreateFormattedText( + string text, + string fontFamily, + double fontSize, + FontStyle fontStyle, + TextAlignment textAlignment, + Avalonia.Media.FontWeight fontWeight) + { + return new FormattedTextImpl(s_pangoContext, text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight); + } + + public IRenderTarget CreateRenderer(IPlatformHandle handle) + { + var window = handle as Gtk.Window; + if (window == null) + throw new NotSupportedException(string.Format( + "Don't know how to create a Cairo renderer from a '{0}' handle which isn't Gtk.Window", + handle.HandleDescriptor)); + + window.DoubleBuffered = true; + return new RenderTarget(window); + } + + public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height) + { + return new RenderTargetBitmapImpl(new ImageSurface(Format.Argb32, width, height)); + } + + public IStreamGeometryImpl CreateStreamGeometry() + { + return new StreamGeometryImpl(); + } + + public IBitmapImpl LoadBitmap(string fileName) + { + var pixbuf = new Gdk.Pixbuf(fileName); + + return new BitmapImpl(pixbuf); + } + + public IBitmapImpl LoadBitmap(Stream stream) + { + var pixbuf = new Gdk.Pixbuf(stream); + + return new BitmapImpl(pixbuf); + } + + private static Pango.Context CreatePangoContext() + { + Gtk.Application.Init(); + return new Gtk.Invisible().CreatePangoContext(); + } + } +} diff --git a/src/Gtk/Avalonia.Cairo/Media/BrushImpl.cs b/src/Gtk/Avalonia.Cairo/Media/BrushImpl.cs new file mode 100644 index 0000000000..7008c7a66f --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/BrushImpl.cs @@ -0,0 +1,17 @@ +using System; +using global::Cairo; + +namespace Avalonia.Cairo +{ + public abstract class BrushImpl : IDisposable + { + public Pattern PlatformBrush { get; protected set; } + + public void Dispose() + { + if (this.PlatformBrush != null) + this.PlatformBrush.Dispose(); + } + } +} + diff --git a/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs b/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs new file mode 100644 index 0000000000..74e1c17cf0 --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/DrawingContext.cs @@ -0,0 +1,344 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reactive.Disposables; +using System.Runtime.InteropServices; +using Avalonia.Cairo.Media.Imaging; +using Avalonia.Media; + +namespace Avalonia.Cairo.Media +{ + using Avalonia.Media.Imaging; + using Cairo = global::Cairo; + + /// + /// Draws using Direct2D1. + /// + public class DrawingContext : IDrawingContextImpl, IDisposable + { + /// + /// The cairo context. + /// + private readonly Cairo.Context _context; + + /// + /// Initializes a new instance of the class. + /// + /// The target surface. + public DrawingContext(Cairo.Surface surface) + { + _context = new Cairo.Context(surface); + } + + /// + /// Initializes a new instance of the class. + /// + /// The GDK drawable. + public DrawingContext(Gdk.Drawable drawable) + { + _context = Gdk.CairoHelper.Create(drawable); + } + + + private Matrix _transform = Matrix.Identity; + /// + /// Gets the current transform of the drawing context. + /// + public Matrix Transform + { + get { return _transform; } + set + { + _transform = value; + _context.Matrix = value.ToCairo(); + + } + } + + /// + /// Ends a draw operation. + /// + public void Dispose() + { + _context.Dispose(); + } + + /// + /// Draws a bitmap image. + /// + /// The bitmap image. + /// The opacity to draw with. + /// The rect in the image to draw. + /// The rect in the output to draw to. + public void DrawImage(IBitmap bitmap, double opacity, Rect sourceRect, Rect destRect) + { + var impl = bitmap.PlatformImpl as BitmapImpl; + var size = new Size(impl.PixelWidth, impl.PixelHeight); + var scale = new Vector(destRect.Width / sourceRect.Width, destRect.Height / sourceRect.Height); + + _context.Save(); + _context.Scale(scale.X, scale.Y); + destRect /= scale; + + if (opacityOverride < 1.0f) { + _context.PushGroup (); + Gdk.CairoHelper.SetSourcePixbuf ( + _context, + impl.Surface, + -sourceRect.X + destRect.X, + -sourceRect.Y + destRect.Y); + + _context.Rectangle (destRect.ToCairo ()); + _context.Fill (); + _context.PopGroupToSource (); + _context.PaintWithAlpha (opacityOverride); + } else { + _context.PushGroup (); + Gdk.CairoHelper.SetSourcePixbuf ( + _context, + impl.Surface, + -sourceRect.X + destRect.X, + -sourceRect.Y + destRect.Y); + + _context.Rectangle (destRect.ToCairo ()); + _context.Fill (); + _context.PopGroupToSource (); + _context.PaintWithAlpha (opacityOverride); + } + _context.Restore(); + } + + /// + /// Draws a line. + /// + /// The stroke pen. + /// The first point of the line. + /// The second point of the line. + public void DrawLine(Pen pen, Point p1, Point p2) + { + var size = new Rect(p1, p2).Size; + + using (var p = SetPen(pen, size)) + { + _context.MoveTo(p1.ToCairo()); + _context.LineTo(p2.ToCairo()); + _context.Stroke(); + } + } + + /// + /// Draws a geometry. + /// + /// The fill brush. + /// The stroke pen. + /// The geometry. + public void DrawGeometry(IBrush brush, Pen pen, Geometry geometry) + { + var impl = geometry.PlatformImpl as StreamGeometryImpl; + + var oldMatrix = Transform; + Transform = impl.Transform * Transform; + + + if (brush != null) + { + _context.AppendPath(impl.Path); + using (var b = SetBrush(brush, geometry.Bounds.Size)) + { + _context.FillRule = impl.FillRule == FillRule.EvenOdd + ? Cairo.FillRule.EvenOdd + : Cairo.FillRule.Winding; + + if (pen != null) + _context.FillPreserve(); + else + _context.Fill(); + } + } + Transform = oldMatrix; + + if (pen != null) + { + _context.AppendPath(impl.Path); + using (var p = SetPen(pen, geometry.Bounds.Size)) + { + _context.Stroke(); + } + } + } + + /// + /// Draws the outline of a rectangle. + /// + /// The pen. + /// The rectangle bounds. + public void DrawRectangle(Pen pen, Rect rect, float cornerRadius) + { + using (var p = SetPen(pen, rect.Size)) + { + _context.Rectangle(rect.ToCairo ()); + _context.Stroke(); + } + } + + /// + /// Draws text. + /// + /// The foreground brush. + /// The upper-left corner of the text. + /// The text. + public void DrawText(IBrush foreground, Point origin, FormattedText text) + { + var layout = ((FormattedTextImpl)text.PlatformImpl).Layout; + _context.MoveTo(origin.X, origin.Y); + + using (var b = SetBrush(foreground, new Size(0, 0))) + { + Pango.CairoHelper.ShowLayout(_context, layout); + } + } + + /// + /// Draws a filled rectangle. + /// + /// The brush. + /// The rectangle bounds. + public void FillRectangle(IBrush brush, Rect rect, float cornerRadius) + { + using (var b = SetBrush(brush, rect.Size)) + { + _context.Rectangle(rect.ToCairo ()); + _context.Fill(); + } + } + + /// + /// Pushes a clip rectange. + /// + /// The clip rectangle. + /// A disposable used to undo the clip rectangle. + public void PushClip(Rect clip) + { + _context.Save(); + _context.Rectangle(clip.ToCairo()); + _context.Clip(); + } + + public void PopClip() + { + _context.Restore(); + } + + readonly Stack _opacityStack = new Stack(); + + /// + /// Pushes an opacity value. + /// + /// The opacity. + /// A disposable used to undo the opacity. + public void PushOpacity(double opacity) + { + _opacityStack.Push(opacityOverride); + + if (opacity < 1.0f) + opacityOverride *= opacity; + + } + + public void PopOpacity() + { + opacityOverride = _opacityStack.Pop(); + } + + /// + /// Pushes a matrix transformation. + /// + /// The matrix + /// A disposable used to undo the transformation. + public IDisposable PushTransform(Matrix matrix) + { + _context.Save(); + _context.Transform(matrix.ToCairo()); + + return Disposable.Create(() => + { + _context.Restore(); + }); + } + + private double opacityOverride = 1.0f; + + private IDisposable SetBrush(IBrush brush, Size destinationSize) + { + _context.Save (); + + var solid = brush as SolidColorBrush; + var linearGradientBrush = brush as LinearGradientBrush; + var radialGradientBrush = brush as RadialGradientBrush; + var imageBrush = brush as ImageBrush; + var visualBrush = brush as VisualBrush; + BrushImpl impl = null; + + if (solid != null) + { + impl = new SolidColorBrushImpl(solid, opacityOverride); + } + else if (linearGradientBrush != null) + { + impl = new LinearGradientBrushImpl(linearGradientBrush, destinationSize); + } + else if (radialGradientBrush != null) + { + impl = new RadialGradientBrushImpl(radialGradientBrush, destinationSize); + } + else if (imageBrush != null) + { + impl = new ImageBrushImpl(imageBrush, destinationSize); + } + else if (visualBrush != null) + { + impl = new VisualBrushImpl(visualBrush, destinationSize); + } + else + { + impl = new SolidColorBrushImpl(null, opacityOverride); + } + + _context.SetSource(impl.PlatformBrush); + return Disposable.Create(() => + { + impl.Dispose(); + _context.Restore(); + }); + } + + private IDisposable SetPen(Pen pen, Size destinationSize) + { + if (pen.DashStyle != null) + { + if (pen.DashStyle.Dashes != null && pen.DashStyle.Dashes.Count > 0) + { + var cray = pen.DashStyle.Dashes.ToArray(); + _context.SetDash(cray, pen.DashStyle.Offset); + } + } + + _context.LineWidth = pen.Thickness; + _context.MiterLimit = pen.MiterLimit; + + // Line caps and joins are currently broken on Cairo. I've defaulted them to sensible defaults for now. + // Cairo does not have StartLineCap, EndLineCap, and DashCap properties, whereas Direct2D does. + // TODO: Figure out a solution for this. + _context.LineJoin = Cairo.LineJoin.Miter; + _context.LineCap = Cairo.LineCap.Butt; + + if (pen.Brush == null) + return Disposable.Empty; + + return SetBrush(pen.Brush, destinationSize); + } + } +} diff --git a/src/Gtk/Avalonia.Cairo/Media/FormattedTextImpl.cs b/src/Gtk/Avalonia.Cairo/Media/FormattedTextImpl.cs new file mode 100644 index 0000000000..e9d092559d --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/FormattedTextImpl.cs @@ -0,0 +1,153 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Avalonia.Media; +using Avalonia.Platform; + +namespace Avalonia.Cairo.Media +{ + public class FormattedTextImpl : IFormattedTextImpl + { + private Size _size; + private readonly string _text; + + static double CorrectScale(double input) + { + return input * 0.75; + } + + public FormattedTextImpl( + Pango.Context context, + string text, + string fontFamily, + double fontSize, + FontStyle fontStyle, + TextAlignment textAlignment, + FontWeight fontWeight) + { + Contract.Requires(context != null); + Contract.Requires(text != null); + Layout = new Pango.Layout(context); + _text = text; + Layout.SetText(text); + Layout.FontDescription = new Pango.FontDescription + { + Family = fontFamily, + Size = Pango.Units.FromDouble(CorrectScale(fontSize)), + Style = (Pango.Style)fontStyle, + Weight = fontWeight.ToCairo() + }; + + Layout.Alignment = textAlignment.ToCairo(); + Layout.Attributes = new Pango.AttrList(); + } + + public Size Constraint + { + get + { + return _size; + } + + set + { + _size = value; + Layout.Width = double.IsPositiveInfinity(value.Width) ? + -1 : Pango.Units.FromDouble(value.Width); + } + } + + public Pango.Layout Layout + { + get; + } + + public void Dispose() + { + Layout.Dispose(); + } + + public IEnumerable GetLines() + { + return new FormattedTextLine[0]; + } + + public TextHitTestResult HitTestPoint(Point point) + { + int textPosition; + int trailing; + + var isInside = Layout.XyToIndex( + Pango.Units.FromDouble(point.X), + Pango.Units.FromDouble(point.Y), + out textPosition, + out trailing); + + textPosition = PangoIndexToTextIndex(textPosition); + + return new TextHitTestResult + { + IsInside = isInside, + TextPosition = textPosition, + IsTrailing = trailing == 0, + }; + } + + int PangoIndexToTextIndex(int pangoIndex) + { + return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(_text), 0, Math.Min(pangoIndex, _text.Length)).Length; + } + + public Rect HitTestTextPosition(int index) + { + return Layout.IndexToPos(TextIndexToPangoIndex(index)).ToAvalonia(); + } + + int TextIndexToPangoIndex(int textIndex) + { + return Encoding.UTF8.GetByteCount(textIndex < _text.Length ? _text.Remove(textIndex) : _text); + } + + public IEnumerable HitTestTextRange(int index, int length) + { + var ranges = new List(); + + for (var i = 0; i < length; i++) + { + ranges.Add(HitTestTextPosition(index + i)); + } + + return ranges; + } + + public Size Measure() + { + int width; + int height; + Layout.GetPixelSize(out width, out height); + + return new Size(width, height); + } + + public void SetForegroundBrush(IBrush brush, int startIndex, int count) + { + var scb = brush as SolidColorBrush; + if (scb != null) + { + + var color = new Pango.Color(); + color.Parse(string.Format("#{0}", scb.Color.ToString().Substring(3))); + + var brushAttr = new Pango.AttrForeground(color); + brushAttr.StartIndex = (uint)TextIndexToPangoIndex(startIndex); + brushAttr.EndIndex = (uint)TextIndexToPangoIndex(startIndex + count); + + Layout.Attributes.Insert(brushAttr); + } + } + } +} diff --git a/src/Gtk/Avalonia.Cairo/Media/ImageBrushImpl.cs b/src/Gtk/Avalonia.Cairo/Media/ImageBrushImpl.cs new file mode 100644 index 0000000000..486ad50b1f --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/ImageBrushImpl.cs @@ -0,0 +1,14 @@ +using System; +using global::Cairo; + +namespace Avalonia.Cairo.Media +{ + public class ImageBrushImpl : BrushImpl + { + public ImageBrushImpl(Avalonia.Media.ImageBrush brush, Size destinationSize) + { + this.PlatformBrush = TileBrushes.CreateTileBrush(brush, destinationSize); + } + } +} + diff --git a/src/Gtk/Avalonia.Cairo/Media/Imaging/BitmapImpl.cs b/src/Gtk/Avalonia.Cairo/Media/Imaging/BitmapImpl.cs new file mode 100644 index 0000000000..1ae0ab8ae3 --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/Imaging/BitmapImpl.cs @@ -0,0 +1,33 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Platform; + +namespace Avalonia.Cairo.Media.Imaging +{ + using Cairo = global::Cairo; + + public class BitmapImpl : IBitmapImpl + { + public BitmapImpl(Gdk.Pixbuf pixbuf) + { + Surface = pixbuf; + } + + public int PixelWidth => Surface.Width; + + public int PixelHeight => Surface.Height; + + public Gdk.Pixbuf Surface + { + get; + } + + public void Save(string fileName) + { + // TODO: Test + Surface.Save(fileName, "png"); + } + } +} diff --git a/src/Gtk/Avalonia.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs b/src/Gtk/Avalonia.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs new file mode 100644 index 0000000000..4e7e25bd38 --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs @@ -0,0 +1,47 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Media; +using Avalonia.Platform; +using Avalonia.Rendering; + +namespace Avalonia.Cairo.Media.Imaging +{ + using Cairo = global::Cairo; + + public class RenderTargetBitmapImpl : IRenderTargetBitmapImpl + { + + private readonly RenderTarget _renderTarget; + public RenderTargetBitmapImpl(Cairo.ImageSurface surface) + { + Surface = surface; + _renderTarget = new RenderTarget(Surface); + } + + public int PixelWidth => Surface.Width; + + public int PixelHeight => Surface.Height; + + public void Dispose() + { + _renderTarget.Dispose(); + } + + public Cairo.ImageSurface Surface + { + get; + } + + public void Save(string fileName) + { + Surface.WriteToPng(fileName); + } + + public Avalonia.Media.DrawingContext CreateDrawingContext() + { + return _renderTarget.CreateDrawingContext(); + } + } +} \ No newline at end of file diff --git a/src/Gtk/Avalonia.Cairo/Media/LinearGradientBrushImpl.cs b/src/Gtk/Avalonia.Cairo/Media/LinearGradientBrushImpl.cs new file mode 100644 index 0000000000..c809e5d2da --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/LinearGradientBrushImpl.cs @@ -0,0 +1,22 @@ +using System; +using global::Cairo; + +namespace Avalonia.Cairo +{ + public class LinearGradientBrushImpl : BrushImpl + { + public LinearGradientBrushImpl(Avalonia.Media.LinearGradientBrush brush, Size destinationSize) + { + var start = brush.StartPoint.ToPixels(destinationSize); + var end = brush.EndPoint.ToPixels(destinationSize); + + this.PlatformBrush = new LinearGradient(start.X, start.Y, end.X, end.Y); + + foreach (var stop in brush.GradientStops) + ((LinearGradient)this.PlatformBrush).AddColorStop(stop.Offset, stop.Color.ToCairo()); + + ((LinearGradient)this.PlatformBrush).Extend = Extend.Pad; + } + } +} + diff --git a/src/Gtk/Avalonia.Cairo/Media/RadialGradientBrushImpl.cs b/src/Gtk/Avalonia.Cairo/Media/RadialGradientBrushImpl.cs new file mode 100644 index 0000000000..3fcb9c8244 --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/RadialGradientBrushImpl.cs @@ -0,0 +1,25 @@ +using System; +using global::Cairo; + +namespace Avalonia.Cairo +{ + public class RadialGradientBrushImpl : BrushImpl + { + public RadialGradientBrushImpl(Avalonia.Media.RadialGradientBrush brush, Size destinationSize) + { + var center = brush.Center.ToPixels(destinationSize); + var gradientOrigin = brush.GradientOrigin.ToPixels(destinationSize); + var radius = brush.Radius; + + this.PlatformBrush = new RadialGradient(center.X, center.Y, radius, gradientOrigin.X, gradientOrigin.Y, radius); + + foreach (var stop in brush.GradientStops) + { + ((RadialGradient)this.PlatformBrush).AddColorStop(stop.Offset, stop.Color.ToCairo()); + } + + ((RadialGradient)this.PlatformBrush).Extend = Extend.Pad; + } + } +} + diff --git a/src/Gtk/Avalonia.Cairo/Media/SolidColorBrushImpl.cs b/src/Gtk/Avalonia.Cairo/Media/SolidColorBrushImpl.cs new file mode 100644 index 0000000000..421e44710d --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/SolidColorBrushImpl.cs @@ -0,0 +1,22 @@ +using System; +using global::Cairo; + +namespace Avalonia.Cairo +{ + public class SolidColorBrushImpl : BrushImpl + { + public SolidColorBrushImpl(Avalonia.Media.SolidColorBrush brush, double opacityOverride = 1.0f) + { + var color = brush?.Color.ToCairo() ?? new Color(); + + if (brush != null) + color.A = Math.Min(brush.Opacity, color.A); + + if (opacityOverride < 1.0f) + color.A = Math.Min(opacityOverride, color.A); + + this.PlatformBrush = new SolidPattern(color); + } + } +} + diff --git a/src/Gtk/Avalonia.Cairo/Media/StreamGeometryContextImpl.cs b/src/Gtk/Avalonia.Cairo/Media/StreamGeometryContextImpl.cs new file mode 100644 index 0000000000..126db894be --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/StreamGeometryContextImpl.cs @@ -0,0 +1,103 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using Avalonia.Media; +using Avalonia.Platform; +using Avalonia.RenderHelpers; + +namespace Avalonia.Cairo.Media +{ + using Cairo = global::Cairo; + + public class StreamGeometryContextImpl : IStreamGeometryContextImpl + { + private readonly StreamGeometryImpl _target; + private Point _currentPoint; + public StreamGeometryContextImpl(StreamGeometryImpl target, Cairo.Path path) + { + _target = target; + + _surf = new Cairo.ImageSurface (Cairo.Format.Argb32, 0, 0); + _context = new Cairo.Context (_surf); + this.Path = path; + + if (this.Path != null) + { + _context.AppendPath(this.Path); + } + } + + public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) + { + ArcToHelper.ArcTo(this, _currentPoint, point, size, rotationAngle, isLargeArc, sweepDirection); + _currentPoint = point; + } + + public void BeginFigure(Point startPoint, bool isFilled) + { + if (this.Path == null) + { + _context.MoveTo(startPoint.ToCairo()); + _currentPoint = startPoint; + } + } + + public void CubicBezierTo(Point point1, Point point2, Point point3) + { + if (this.Path == null) + { + _context.CurveTo(point1.ToCairo(), point2.ToCairo(), point3.ToCairo()); + _currentPoint = point3; + } + } + + public void QuadraticBezierTo(Point control, Point endPoint) + { + if (this.Path == null) + { + QuadBezierHelper.QuadraticBezierTo(this, _currentPoint, control, endPoint); + _currentPoint = endPoint; + } + } + + public void LineTo(Point point) + { + if (this.Path == null) + { + _context.LineTo(point.ToCairo()); + _currentPoint = point; + } + } + + private readonly Cairo.Context _context; + private readonly Cairo.ImageSurface _surf; + public Cairo.Path Path { get; private set; } + public Rect Bounds { get; private set; } + + public void EndFigure(bool isClosed) + { + if (this.Path == null) + { + if (isClosed) + _context.ClosePath (); + + Path = _context.CopyPath (); + Bounds = _context.FillExtents ().ToAvalonia (); + } + } + + public void SetFillRule(FillRule fillRule) + { + _target.FillRule = fillRule; + } + + + public void Dispose() + { + _context.Dispose (); + _surf.Dispose (); + } + } +} diff --git a/src/Gtk/Avalonia.Cairo/Media/StreamGeometryImpl.cs b/src/Gtk/Avalonia.Cairo/Media/StreamGeometryImpl.cs new file mode 100644 index 0000000000..6152e73489 --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/StreamGeometryImpl.cs @@ -0,0 +1,71 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Media; +using Avalonia.Platform; +using System.Collections.Generic; + +namespace Avalonia.Cairo.Media +{ + using Cairo = global::Cairo; + + public class StreamGeometryImpl : IStreamGeometryImpl + { + public StreamGeometryImpl() + { + _impl = new StreamGeometryContextImpl(this, null); + } + + public StreamGeometryImpl(StreamGeometryContextImpl impl) + { + _impl = impl; + } + + public Rect Bounds + { + get { return _impl.Bounds; } + } + + public Cairo.Path Path + { + get { return _impl.Path; } + } + + private readonly StreamGeometryContextImpl _impl; + + private Matrix _transform = Matrix.Identity; + public Matrix Transform + { + get { return _transform; } + set + { + if (value != Transform) + { + if (!value.IsIdentity) + { + _transform = value; + } + } + } + } + + public FillRule FillRule { get; set; } + + public IStreamGeometryImpl Clone() + { + return new StreamGeometryImpl(_impl); + } + + public Rect GetRenderBounds(double strokeThickness) + { + // TODO: Calculate properly. + return Bounds.Inflate(strokeThickness); + } + + public IStreamGeometryContextImpl Open() + { + return _impl; + } + } +} diff --git a/src/Gtk/Avalonia.Cairo/Media/TileBrushes.cs b/src/Gtk/Avalonia.Cairo/Media/TileBrushes.cs new file mode 100644 index 0000000000..b533210749 --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/TileBrushes.cs @@ -0,0 +1,55 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Cairo; +using Avalonia.Cairo.Media.Imaging; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Platform; +using Avalonia.Rendering; +using Avalonia.RenderHelpers; + +namespace Avalonia.Cairo.Media +{ + internal static class TileBrushes + { + public static SurfacePattern CreateTileBrush(TileBrush brush, Size targetSize) + { + var helper = new TileBrushImplHelper(brush, targetSize); + if (!helper.IsValid) + return null; + + using (var intermediate = new ImageSurface(Format.ARGB32, (int)helper.IntermediateSize.Width, (int)helper.IntermediateSize.Height)) + using (var ctx = new RenderTarget(intermediate).CreateDrawingContext()) + { + helper.DrawIntermediate(ctx); + + var result = new SurfacePattern(intermediate); + + if ((brush.TileMode & TileMode.FlipXY) != 0) + { + // TODO: Currently always FlipXY as that's all cairo supports natively. + // Support separate FlipX and FlipY by drawing flipped images to intermediate + // surface. + result.Extend = Extend.Reflect; + } + else + { + result.Extend = Extend.Repeat; + } + + if (brush.TileMode != TileMode.None) + { + var matrix = result.Matrix; + matrix.InitTranslate(-helper.DestinationRect.X, -helper.DestinationRect.Y); + result.Matrix = matrix; + } + + return result; + } + } + + + } +} diff --git a/src/Gtk/Avalonia.Cairo/Media/VisualBrushImpl.cs b/src/Gtk/Avalonia.Cairo/Media/VisualBrushImpl.cs new file mode 100644 index 0000000000..7c0e59e4d9 --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Media/VisualBrushImpl.cs @@ -0,0 +1,14 @@ +using System; +using global::Cairo; + +namespace Avalonia.Cairo.Media +{ + public class VisualBrushImpl : BrushImpl + { + public VisualBrushImpl(Avalonia.Media.VisualBrush brush, Size destinationSize) + { + this.PlatformBrush = TileBrushes.CreateTileBrush(brush, destinationSize); + } + } +} + diff --git a/src/Gtk/Avalonia.Cairo/Properties/AssemblyInfo.cs b/src/Gtk/Avalonia.Cairo/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..cdda1132bb --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/Properties/AssemblyInfo.cs @@ -0,0 +1,39 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 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("Avalonia.Cairo")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Avalonia.Cairo")] +[assembly: AssemblyCopyright("Copyright \u00A9 2014")] +[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("f999ba8b-64e7-40cc-98a4-003f1852d2a3")] + +// 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")] diff --git a/src/Gtk/Avalonia.Cairo/RenderTarget.cs b/src/Gtk/Avalonia.Cairo/RenderTarget.cs new file mode 100644 index 0000000000..cb7241f32e --- /dev/null +++ b/src/Gtk/Avalonia.Cairo/RenderTarget.cs @@ -0,0 +1,55 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Runtime.InteropServices; +using Avalonia.Cairo.Media; +using Avalonia.Media; +using Avalonia.Platform; +using Avalonia.Rendering; +using DrawingContext = Avalonia.Media.DrawingContext; + +namespace Avalonia.Cairo +{ + using global::Cairo; + + /// + /// A cairo render target. + /// + public class RenderTarget : IRenderTarget + { + private readonly Surface _surface; + private readonly Gtk.Window _window; + + /// + /// Initializes a new instance of the class. + /// + /// The window. + /// The width of the window. + /// The height of the window. + public RenderTarget(Gtk.Window window) + { + _window = window; + } + + public RenderTarget(ImageSurface surface) + { + _surface = surface; + } + + + /// + /// Creates a cairo surface that targets a platform-specific resource. + /// + /// A surface wrapped in an . + public DrawingContext CreateDrawingContext() + { + var ctx = _surface != null + ? new Media.DrawingContext(_surface) + : new Media.DrawingContext(_window.GdkWindow); + return new DrawingContext(ctx); + } + + public void Dispose() => _surface?.Dispose(); + } +} diff --git a/src/Gtk/Perspex.Cairo/app.config b/src/Gtk/Avalonia.Cairo/app.config similarity index 100% rename from src/Gtk/Perspex.Cairo/app.config rename to src/Gtk/Avalonia.Cairo/app.config diff --git a/src/Gtk/Perspex.Cairo/packages.config b/src/Gtk/Avalonia.Cairo/packages.config similarity index 100% rename from src/Gtk/Perspex.Cairo/packages.config rename to src/Gtk/Avalonia.Cairo/packages.config diff --git a/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj b/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj new file mode 100644 index 0000000000..98b779995b --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj @@ -0,0 +1,100 @@ + + + + Debug + AnyCPU + {54F237D5-A70A-4752-9656-0C70B1A7B047} + Library + Avalonia.Gtk + Avalonia.Gtk + v4.5 + + + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + + + + ..\..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + + + ..\..\..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + + + ..\..\..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + + + + + + + + + + + + + + + + + + + {D211E587-D8BC-45B9-95A4-F297C8FA5200} + Avalonia.Animation + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + {62024B2D-53EB-4638-B26B-85EEAA54866E} + Avalonia.Input + + + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Avalonia.SceneGraph + + + {42472427-4774-4C81-8AFF-9F27B8E31721} + Avalonia.Layout + + + {D2221C82-4A25-4583-9B43-D791E3F6820C} + Avalonia.Controls + + + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} + Avalonia.Styling + + + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B} + Avalonia.Interactivity + + + + + + + + \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk/ClipboardImpl.cs b/src/Gtk/Avalonia.Gtk/ClipboardImpl.cs new file mode 100644 index 0000000000..db59789bc9 --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/ClipboardImpl.cs @@ -0,0 +1,42 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Threading.Tasks; +using Gdk; +using Avalonia.Input.Platform; + +namespace Avalonia.Gtk +{ + using Gtk = global::Gtk; + + internal class ClipboardImpl : IClipboard + { + private static Gtk.Clipboard GetClipboard() => Gtk.Clipboard.GetForDisplay(Display.Default, new Atom(IntPtr.Zero)); + + public Task GetTextAsync() + { + var clip = GetClipboard(); + var tcs = new TaskCompletionSource(); + clip.RequestText((_, text) => + { + tcs.TrySetResult(text); + }); + return tcs.Task; + } + + public Task SetTextAsync(string text) + { + using (var cl = GetClipboard()) + cl.Text = text; + return Task.FromResult(0); + } + + public Task ClearAsync() + { + using (var cl = GetClipboard()) + cl.Clear(); + return Task.FromResult(0); + } + } +} diff --git a/src/Gtk/Avalonia.Gtk/CursorFactory.cs b/src/Gtk/Avalonia.Gtk/CursorFactory.cs new file mode 100644 index 0000000000..bd8166c59e --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/CursorFactory.cs @@ -0,0 +1,85 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Collections.Generic; +using Gdk; +using Avalonia.Input; +using Avalonia.Platform; + +namespace Avalonia.Gtk +{ + using Gtk = global::Gtk; + + internal class CursorFactory : IStandardCursorFactory + { + public static CursorFactory Instance { get; } = new CursorFactory(); + + private CursorFactory() + { + } + + private static readonly Dictionary CursorTypeMapping = new Dictionary + + { + {StandardCursorType.AppStarting, CursorType.Watch}, + {StandardCursorType.Arrow, CursorType.LeftPtr}, + {StandardCursorType.Cross, CursorType.Cross}, + {StandardCursorType.Hand, CursorType.Hand1}, + {StandardCursorType.Ibeam, CursorType.Xterm}, + {StandardCursorType.No, Gtk.Stock.Cancel}, + {StandardCursorType.SizeAll, CursorType.Sizing}, + //{ StandardCursorType.SizeNorthEastSouthWest, 32643 }, + {StandardCursorType.SizeNorthSouth, CursorType.SbVDoubleArrow}, + //{ StandardCursorType.SizeNorthWestSouthEast, 32642 }, + {StandardCursorType.SizeWestEast, CursorType.SbHDoubleArrow}, + {StandardCursorType.UpArrow, CursorType.BasedArrowUp}, + {StandardCursorType.Wait, CursorType.Watch}, + {StandardCursorType.Help, Gtk.Stock.Help}, + {StandardCursorType.TopSide, CursorType.TopSide}, + {StandardCursorType.BottomSize, CursorType.BottomSide}, + {StandardCursorType.LeftSide, CursorType.LeftSide}, + {StandardCursorType.RightSide, CursorType.RightSide}, + {StandardCursorType.TopLeftCorner, CursorType.TopLeftCorner}, + {StandardCursorType.TopRightCorner, CursorType.TopRightCorner}, + {StandardCursorType.BottomLeftCorner, CursorType.BottomLeftCorner}, + {StandardCursorType.BottomRightCorner, CursorType.BottomRightCorner} + }; + + private static readonly Dictionary Cache = + new Dictionary(); + + private Gdk.Cursor GetCursor(object desc) + { + Gdk.Cursor rv; + var name = desc as string; + if (name != null) + { + var theme = Gtk.IconTheme.Default; + var icon = theme.LoadIcon(name, 32, default(Gtk.IconLookupFlags)); + rv = icon == null ? new Gdk.Cursor(CursorType.XCursor) : new Gdk.Cursor(Display.Default, icon, 0, 0); + } + else + { + rv = new Gdk.Cursor((CursorType)desc); + } + + rv.Owned = false; + return rv; + } + + public IPlatformHandle GetCursor(StandardCursorType cursorType) + { + IPlatformHandle rv; + if (!Cache.TryGetValue(cursorType, out rv)) + { + Cache[cursorType] = + rv = + new PlatformHandle( + GetCursor(CursorTypeMapping[cursorType]).Handle, + "GTKCURSOR"); + } + + return rv; + } + } +} diff --git a/src/Gtk/Avalonia.Gtk/GtkExtensions.cs b/src/Gtk/Avalonia.Gtk/GtkExtensions.cs new file mode 100644 index 0000000000..b9bb9a778a --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/GtkExtensions.cs @@ -0,0 +1,15 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Gtk +{ + using Gtk = global::Gtk; + + public static class GtkExtensions + { + public static Rect ToAvalonia(this Gdk.Rectangle rect) + { + return new Rect(rect.Left, rect.Top, rect.Right, rect.Bottom); + } + } +} diff --git a/src/Gtk/Avalonia.Gtk/GtkPlatform.cs b/src/Gtk/Avalonia.Gtk/GtkPlatform.cs new file mode 100644 index 0000000000..cc19110e86 --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/GtkPlatform.cs @@ -0,0 +1,115 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Disposables; +using System.Threading; +using Avalonia.Controls.Platform; +using Avalonia.Input.Platform; +using Avalonia.Input; +using Avalonia.Platform; +using Avalonia.Shared.PlatformSupport; + +namespace Avalonia +{ + public static class GtkApplicationExtensions + { + public static TApp UseGtk(this TApp app) where TApp : Application + { + Avalonia.Gtk.GtkPlatform.Initialize(); + return app; + } + } +} + +namespace Avalonia.Gtk +{ + using Gtk = global::Gtk; + + public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform + { + private static readonly GtkPlatform s_instance = new GtkPlatform(); + private static Thread _uiThread; + + public GtkPlatform() + { + Gtk.Application.Init(); + } + + 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() + { + AvaloniaLocator.CurrentMutable + .Bind().ToConstant(s_instance) + .Bind().ToSingleton() + .Bind().ToConstant(CursorFactory.Instance) + .Bind().ToConstant(GtkKeyboardDevice.Instance) + .Bind().ToConstant(GtkMouseDevice.Instance) + .Bind().ToConstant(s_instance) + .Bind().ToConstant(s_instance) + .Bind().ToSingleton(); + SharedPlatform.Register(); + _uiThread = Thread.CurrentThread; + } + + public bool HasMessages() + { + return Gtk.Application.EventsPending(); + } + + public void ProcessMessage() + { + Gtk.Application.RunIteration(); + } + + public void RunLoop(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + Gtk.Application.RunIteration(); + } + + public IDisposable StartTimer(TimeSpan interval, Action tick) + { + var result = true; + var handle = GLib.Timeout.Add( + (uint)interval.TotalMilliseconds, + () => + { + tick(); + return result; + }); + + return Disposable.Create(() => result = false); + } + + + + public void Signal() + { + Gtk.Application.Invoke(delegate { Signaled?.Invoke(); }); + } + + public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _uiThread; + + public event Action Signaled; + public IWindowImpl CreateWindow() + { + return new WindowImpl(); + } + + public IWindowImpl CreateEmbeddableWindow() + { + throw new NotSupportedException(); + } + + public IPopupImpl CreatePopup() + { + return new PopupImpl(); + } + } +} \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk/Input/GtkKeyboardDevice.cs b/src/Gtk/Avalonia.Gtk/Input/GtkKeyboardDevice.cs new file mode 100644 index 0000000000..4e88dcda9a --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/Input/GtkKeyboardDevice.cs @@ -0,0 +1,225 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using Avalonia.Input; + +namespace Avalonia.Gtk +{ + public class GtkKeyboardDevice : KeyboardDevice + { + private static readonly Dictionary KeyDic = new Dictionary + { + { Gdk.Key.Cancel, Key.Cancel }, + { Gdk.Key.BackSpace, Key.Back }, + { Gdk.Key.Tab, Key.Tab }, + { Gdk.Key.Linefeed, Key.LineFeed }, + { Gdk.Key.Clear, Key.Clear }, + { Gdk.Key.Return, Key.Return }, + { Gdk.Key.Pause, Key.Pause }, + //{ Gdk.Key.?, Key.CapsLock } + //{ Gdk.Key.?, Key.HangulMode } + //{ Gdk.Key.?, Key.JunjaMode } + //{ Gdk.Key.?, Key.FinalMode } + //{ Gdk.Key.?, Key.KanjiMode } + { Gdk.Key.Escape, Key.Escape }, + //{ Gdk.Key.?, Key.ImeConvert } + //{ Gdk.Key.?, Key.ImeNonConvert } + //{ Gdk.Key.?, Key.ImeAccept } + //{ Gdk.Key.?, Key.ImeModeChange } + { Gdk.Key.space, Key.Space }, + { Gdk.Key.Prior, Key.Prior }, + //{ Gdk.Key.?, Key.PageDown } + { Gdk.Key.End, Key.End }, + { Gdk.Key.Home, Key.Home }, + { Gdk.Key.Left, Key.Left }, + { Gdk.Key.Up, Key.Up }, + { Gdk.Key.Right, Key.Right }, + { Gdk.Key.Down, Key.Down }, + { Gdk.Key.Select, Key.Select }, + { Gdk.Key.Print, Key.Print }, + { Gdk.Key.Execute, Key.Execute }, + //{ Gdk.Key.?, Key.Snapshot } + { Gdk.Key.Insert, Key.Insert }, + { Gdk.Key.Delete, Key.Delete }, + { Gdk.Key.Help, Key.Help }, + //{ Gdk.Key.?, Key.D0 } + //{ Gdk.Key.?, Key.D1 } + //{ Gdk.Key.?, Key.D2 } + //{ Gdk.Key.?, Key.D3 } + //{ Gdk.Key.?, Key.D4 } + //{ Gdk.Key.?, Key.D5 } + //{ Gdk.Key.?, Key.D6 } + //{ Gdk.Key.?, Key.D7 } + //{ Gdk.Key.?, Key.D8 } + //{ Gdk.Key.?, Key.D9 } + { Gdk.Key.A, Key.A }, + { Gdk.Key.B, Key.B }, + { Gdk.Key.C, Key.C }, + { Gdk.Key.D, Key.D }, + { Gdk.Key.E, Key.E }, + { Gdk.Key.F, Key.F }, + { Gdk.Key.G, Key.G }, + { Gdk.Key.H, Key.H }, + { Gdk.Key.I, Key.I }, + { Gdk.Key.J, Key.J }, + { Gdk.Key.K, Key.K }, + { Gdk.Key.L, Key.L }, + { Gdk.Key.M, Key.M }, + { Gdk.Key.N, Key.N }, + { Gdk.Key.O, Key.O }, + { Gdk.Key.P, Key.P }, + { Gdk.Key.Q, Key.Q }, + { Gdk.Key.R, Key.R }, + { Gdk.Key.S, Key.S }, + { Gdk.Key.T, Key.T }, + { Gdk.Key.U, Key.U }, + { Gdk.Key.V, Key.V }, + { Gdk.Key.W, Key.W }, + { Gdk.Key.X, Key.X }, + { Gdk.Key.Y, Key.Y }, + { Gdk.Key.Z, Key.Z }, + { Gdk.Key.a, Key.A }, + { Gdk.Key.b, Key.B }, + { Gdk.Key.c, Key.C }, + { Gdk.Key.d, Key.D }, + { Gdk.Key.e, Key.E }, + { Gdk.Key.f, Key.F }, + { Gdk.Key.g, Key.G }, + { Gdk.Key.h, Key.H }, + { Gdk.Key.i, Key.I }, + { Gdk.Key.j, Key.J }, + { Gdk.Key.k, Key.K }, + { Gdk.Key.l, Key.L }, + { Gdk.Key.m, Key.M }, + { Gdk.Key.n, Key.N }, + { Gdk.Key.o, Key.O }, + { Gdk.Key.p, Key.P }, + { Gdk.Key.q, Key.Q }, + { Gdk.Key.r, Key.R }, + { Gdk.Key.s, Key.S }, + { Gdk.Key.t, Key.T }, + { Gdk.Key.u, Key.U }, + { Gdk.Key.v, Key.V }, + { Gdk.Key.w, Key.W }, + { Gdk.Key.x, Key.X }, + { Gdk.Key.y, Key.Y }, + { Gdk.Key.z, Key.Z }, + //{ Gdk.Key.?, Key.LWin } + //{ Gdk.Key.?, Key.RWin } + //{ Gdk.Key.?, Key.Apps } + //{ Gdk.Key.?, Key.Sleep } + //{ Gdk.Key.?, Key.NumPad0 } + //{ Gdk.Key.?, Key.NumPad1 } + //{ Gdk.Key.?, Key.NumPad2 } + //{ Gdk.Key.?, Key.NumPad3 } + //{ Gdk.Key.?, Key.NumPad4 } + //{ Gdk.Key.?, Key.NumPad5 } + //{ Gdk.Key.?, Key.NumPad6 } + //{ Gdk.Key.?, Key.NumPad7 } + //{ Gdk.Key.?, Key.NumPad8 } + //{ Gdk.Key.?, Key.NumPad9 } + { Gdk.Key.multiply, Key.Multiply }, + //{ Gdk.Key.?, Key.Add } + //{ Gdk.Key.?, Key.Separator } + //{ Gdk.Key.?, Key.Subtract } + //{ Gdk.Key.?, Key.Decimal } + //{ Gdk.Key.?, Key.Divide } + { Gdk.Key.F1, Key.F1 }, + { Gdk.Key.F2, Key.F2 }, + { Gdk.Key.F3, Key.F3 }, + { Gdk.Key.F4, Key.F4 }, + { Gdk.Key.F5, Key.F5 }, + { Gdk.Key.F6, Key.F6 }, + { Gdk.Key.F7, Key.F7 }, + { Gdk.Key.F8, Key.F8 }, + { Gdk.Key.F9, Key.F9 }, + { Gdk.Key.F10, Key.F10 }, + { Gdk.Key.F11, Key.F11 }, + { Gdk.Key.F12, Key.F12 }, + { Gdk.Key.L3, Key.F13 }, + { Gdk.Key.F14, Key.F14 }, + { Gdk.Key.L5, Key.F15 }, + { Gdk.Key.F16, Key.F16 }, + { Gdk.Key.F17, Key.F17 }, + { Gdk.Key.L8, Key.F18 }, + { Gdk.Key.L9, Key.F19 }, + { Gdk.Key.L10, Key.F20 }, + { Gdk.Key.R1, Key.F21 }, + { Gdk.Key.R2, Key.F22 }, + { Gdk.Key.F23, Key.F23 }, + { Gdk.Key.R4, Key.F24 }, + //{ Gdk.Key.?, Key.NumLock } + //{ Gdk.Key.?, Key.Scroll } + //{ Gdk.Key.?, Key.LeftShift } + //{ Gdk.Key.?, Key.RightShift } + //{ Gdk.Key.?, Key.LeftCtrl } + //{ Gdk.Key.?, Key.RightCtrl } + //{ Gdk.Key.?, Key.LeftAlt } + //{ Gdk.Key.?, Key.RightAlt } + //{ Gdk.Key.?, Key.BrowserBack } + //{ Gdk.Key.?, Key.BrowserForward } + //{ Gdk.Key.?, Key.BrowserRefresh } + //{ Gdk.Key.?, Key.BrowserStop } + //{ Gdk.Key.?, Key.BrowserSearch } + //{ Gdk.Key.?, Key.BrowserFavorites } + //{ Gdk.Key.?, Key.BrowserHome } + //{ Gdk.Key.?, Key.VolumeMute } + //{ Gdk.Key.?, Key.VolumeDown } + //{ Gdk.Key.?, Key.VolumeUp } + //{ Gdk.Key.?, Key.MediaNextTrack } + //{ Gdk.Key.?, Key.MediaPreviousTrack } + //{ Gdk.Key.?, Key.MediaStop } + //{ Gdk.Key.?, Key.MediaPlayPause } + //{ Gdk.Key.?, Key.LaunchMail } + //{ Gdk.Key.?, Key.SelectMedia } + //{ Gdk.Key.?, Key.LaunchApplication1 } + //{ Gdk.Key.?, Key.LaunchApplication2 } + //{ Gdk.Key.?, Key.OemSemicolon } + //{ Gdk.Key.?, Key.OemPlus } + //{ Gdk.Key.?, Key.OemComma } + //{ Gdk.Key.?, Key.OemMinus } + //{ Gdk.Key.?, Key.OemPeriod } + //{ Gdk.Key.?, Key.Oem2 } + //{ Gdk.Key.?, Key.OemTilde } + //{ Gdk.Key.?, Key.AbntC1 } + //{ Gdk.Key.?, Key.AbntC2 } + //{ Gdk.Key.?, Key.Oem4 } + //{ Gdk.Key.?, Key.OemPipe } + //{ Gdk.Key.?, Key.OemCloseBrackets } + //{ Gdk.Key.?, Key.Oem7 } + //{ Gdk.Key.?, Key.Oem8 } + //{ Gdk.Key.?, Key.Oem102 } + //{ Gdk.Key.?, Key.ImeProcessed } + //{ Gdk.Key.?, Key.System } + //{ Gdk.Key.?, Key.OemAttn } + //{ Gdk.Key.?, Key.OemFinish } + //{ Gdk.Key.?, Key.DbeHiragana } + //{ Gdk.Key.?, Key.OemAuto } + //{ Gdk.Key.?, Key.DbeDbcsChar } + //{ Gdk.Key.?, Key.OemBackTab } + //{ Gdk.Key.?, Key.Attn } + //{ Gdk.Key.?, Key.DbeEnterWordRegisterMode } + //{ Gdk.Key.?, Key.DbeEnterImeConfigureMode } + //{ Gdk.Key.?, Key.EraseEof } + //{ Gdk.Key.?, Key.Play } + //{ Gdk.Key.?, Key.Zoom } + //{ Gdk.Key.?, Key.NoName } + //{ Gdk.Key.?, Key.DbeEnterDialogConversionMode } + //{ Gdk.Key.?, Key.OemClear } + //{ Gdk.Key.?, Key.DeadCharProcessed } + }; + + public new static GtkKeyboardDevice Instance { get; } = new GtkKeyboardDevice(); + + public static Key ConvertKey(Gdk.Key key) + { + Key result; + return KeyDic.TryGetValue(key, out result) ? result : Key.None; + } + } +} \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk/Input/GtkMouseDevice.cs b/src/Gtk/Avalonia.Gtk/Input/GtkMouseDevice.cs new file mode 100644 index 0000000000..c5de869647 --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/Input/GtkMouseDevice.cs @@ -0,0 +1,29 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Input; +namespace Avalonia.Gtk +{ + public class GtkMouseDevice : MouseDevice + { + private static readonly GtkMouseDevice s_instance; + + private Point _clientPosition; + + static GtkMouseDevice() + { + s_instance = new GtkMouseDevice(); + } + + private GtkMouseDevice() + { + } + + public static new GtkMouseDevice Instance => s_instance; + + internal void SetClientPosition(Point p) + { + _clientPosition = p; + } + } +} \ No newline at end of file diff --git a/src/Gtk/Avalonia.Gtk/MyClass.cs b/src/Gtk/Avalonia.Gtk/MyClass.cs new file mode 100644 index 0000000000..589431fcb1 --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/MyClass.cs @@ -0,0 +1,12 @@ +using System; + +namespace Avalonia.Gtk +{ + public class MyClass + { + public MyClass () + { + } + } +} + diff --git a/src/Gtk/Avalonia.Gtk/PopupImpl.cs b/src/Gtk/Avalonia.Gtk/PopupImpl.cs new file mode 100644 index 0000000000..41ee4354fe --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/PopupImpl.cs @@ -0,0 +1,16 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Gtk; +using Avalonia.Platform; + +namespace Avalonia.Gtk +{ + public class PopupImpl : WindowImpl, IPopupImpl + { + public PopupImpl() + : base(WindowType.Popup) + { + } + } +} diff --git a/src/Gtk/Avalonia.Gtk/Properties/AssemblyInfo.cs b/src/Gtk/Avalonia.Gtk/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..6c970b77f6 --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/Properties/AssemblyInfo.cs @@ -0,0 +1,21 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle("Avalonia.Gtk")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("steven")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion("1.0.*")] diff --git a/src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs b/src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs new file mode 100644 index 0000000000..a47a0a0ef8 --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Controls; +using Avalonia.Controls.Platform; +using Avalonia.Platform; + +namespace Avalonia.Gtk +{ + using global::Gtk; + class SystemDialogImpl : ISystemDialogImpl + { + public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) + { + var tcs = new TaskCompletionSource(); + var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImpl)parent), + dialog is OpenFileDialog + ? FileChooserAction.Open + : FileChooserAction.Save, + "Cancel", ResponseType.Cancel, + "Open", ResponseType.Accept) + { + SelectMultiple = (dialog as OpenFileDialog)?.AllowMultiple ?? false, + }; + foreach (var filter in dialog.Filters) + { + var ffilter = new FileFilter() + { + Name = filter.Name + " (" + string.Join(";", filter.Extensions.Select(e => "*." + e)) + ")" + }; + foreach (var ext in filter.Extensions) + ffilter.AddPattern("*." + ext); + dlg.AddFilter(ffilter); + } + dlg.SetFilename(dialog.InitialFileName); + dlg.Modal = true; + + dlg.Response += (_, args) => + { + if (args.ResponseId == ResponseType.Accept) + tcs.TrySetResult(dlg.Filenames); + dlg.Hide(); + dlg.Dispose(); + }; + + dlg.Close += delegate + { + tcs.TrySetResult(null); + dlg.Dispose(); + }; + dlg.Show(); + return tcs.Task; + } + + public Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) + { + var tcs = new TaskCompletionSource(); + var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImpl)parent), + FileChooserAction.SelectFolder, + "Cancel", ResponseType.Cancel, + "Select Folder", ResponseType.Accept) + { + + }; + + dlg.Modal = true; + + dlg.Response += (_, args) => + { + if (args.ResponseId == ResponseType.Accept) + tcs.TrySetResult(dlg.Filename); + + dlg.Hide(); + dlg.Dispose(); + }; + + dlg.Close += delegate + { + tcs.TrySetResult(null); + dlg.Dispose(); + }; + dlg.Show(); + return tcs.Task; + } + } +} diff --git a/src/Gtk/Avalonia.Gtk/WindowImpl.cs b/src/Gtk/Avalonia.Gtk/WindowImpl.cs new file mode 100644 index 0000000000..3b8065ce57 --- /dev/null +++ b/src/Gtk/Avalonia.Gtk/WindowImpl.cs @@ -0,0 +1,387 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Disposables; +using System.Runtime.InteropServices; +using Gdk; +using Avalonia.Controls; +using Avalonia.Input.Raw; +using Avalonia.Platform; +using Avalonia.Input; +using Avalonia.Threading; +using Action = System.Action; +using WindowEdge = Avalonia.Controls.WindowEdge; + +namespace Avalonia.Gtk +{ + using Gtk = global::Gtk; + + public class WindowImpl : Gtk.Window, IWindowImpl, IPlatformHandle + { + private IInputRoot _inputRoot; + + private Size _clientSize; + + private Gtk.IMContext _imContext; + + private uint _lastKeyEventTimestamp; + + private static readonly Gdk.Cursor DefaultCursor = new Gdk.Cursor(CursorType.LeftPtr); + + public WindowImpl() + : base(Gtk.WindowType.Toplevel) + { + DefaultSize = new Gdk.Size(900, 480); + Init(); + } + + public WindowImpl(Gtk.WindowType type) + : base(type) + { + Init(); + } + + private void Init() + { + Events = EventMask.PointerMotionMask | + EventMask.ButtonPressMask | + EventMask.ButtonReleaseMask; + _imContext = new Gtk.IMMulticontext(); + _imContext.Commit += ImContext_Commit; + DoubleBuffered = false; + Realize(); + } + + protected override void OnRealized () + { + base.OnRealized (); + _imContext.ClientWindow = this.GdkWindow; + } + + public Size ClientSize + { + get; + set; + } + + public Size MaxClientSize + { + get + { + // TODO: This should take into account things such as taskbar and window border + // thickness etc. + return new Size(Screen.Width, Screen.Height); + } + } + + public Avalonia.Controls.WindowState WindowState + { + get + { + switch (GdkWindow.State) + { + case Gdk.WindowState.Iconified: + return Controls.WindowState.Minimized; + case Gdk.WindowState.Maximized: + return Controls.WindowState.Maximized; + default: + return Controls.WindowState.Normal; + } + } + + set + { + switch (value) + { + case Controls.WindowState.Minimized: + GdkWindow.Iconify(); + break; + case Controls.WindowState.Maximized: + GdkWindow.Maximize(); + break; + case Controls.WindowState.Normal: + GdkWindow.Deiconify(); + GdkWindow.Unmaximize(); + break; + } + } + } + + public double Scaling => 1; + + IPlatformHandle ITopLevelImpl.Handle => this; + + [DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] + extern static IntPtr gdk_win32_drawable_get_handle(IntPtr gdkWindow); + + [DllImport("libgtk-x11-2.0.so.0", CallingConvention = CallingConvention.Cdecl)] + extern static IntPtr gdk_x11_drawable_get_xid(IntPtr gdkWindow); + + [DllImport("libgdk-quartz-2.0-0.dylib", CallingConvention = CallingConvention.Cdecl)] + extern static IntPtr gdk_quartz_window_get_nswindow(IntPtr gdkWindow); + + IntPtr _nativeWindow; + + IntPtr GetNativeWindow() + { + IntPtr h = GdkWindow.Handle; + if (_nativeWindow != IntPtr.Zero) + return _nativeWindow; + //Try whatever backend that works + try + { + return _nativeWindow = gdk_quartz_window_get_nswindow(h); + } + catch + { + } + try + { + return _nativeWindow = gdk_x11_drawable_get_xid(h); + } + catch + { + } + return _nativeWindow = gdk_win32_drawable_get_handle(h); + } + + + IntPtr IPlatformHandle.Handle => GetNativeWindow(); + public string HandleDescriptor => "HWND"; + + public Action Activated { get; set; } + + public Action Closed { get; set; } + + public Action Deactivated { get; set; } + + public Action Input { get; set; } + + public Action Paint { get; set; } + + public Action Resized { get; set; } + + public Action ScalingChanged { get; set; } + + public IPopupImpl CreatePopup() + { + return new PopupImpl(); + } + + public void Invalidate(Rect rect) + { + if (base.GdkWindow != null) + base.GdkWindow.InvalidateRect( + new Rectangle((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height), true); + } + + public Point PointToClient(Point point) + { + int x, y; + GdkWindow.GetDeskrelativeOrigin(out x, out y); + + return new Point(point.X - x, point.Y - y); + } + + public Point PointToScreen(Point point) + { + int x, y; + GdkWindow.GetDeskrelativeOrigin(out x, out y); + + return new Point(point.X + x, point.Y + y); + } + + public void SetInputRoot(IInputRoot inputRoot) + { + _inputRoot = inputRoot; + } + + public void SetTitle(string title) + { + Title = title; + } + + + public void SetCursor(IPlatformHandle cursor) + { + GdkWindow.Cursor = cursor != null ? new Gdk.Cursor(cursor.Handle) : DefaultCursor; + } + + public void BeginMoveDrag() + { + int x, y; + ModifierType mod; + Screen.RootWindow.GetPointer(out x, out y, out mod); + BeginMoveDrag(1, x, y, 0); + } + + public void BeginResizeDrag(WindowEdge edge) + { + int x, y; + ModifierType mod; + Screen.RootWindow.GetPointer(out x, out y, out mod); + BeginResizeDrag((Gdk.WindowEdge) (int) edge, 1, x, y, 0); + } + + public Point Position + { + get + { + int x, y; + GetPosition(out x, out y); + return new Point(x, y); + } + set + { + Move((int)value.X, (int)value.Y); + } + } + + public IDisposable ShowDialog() + { + Modal = true; + Show(); + + return Disposable.Empty; + } + + public void SetSystemDecorations(bool enabled) => Decorated = enabled; + + void ITopLevelImpl.Activate() + { + Activate(); + } + + private static InputModifiers GetModifierKeys(ModifierType state) + { + var rv = InputModifiers.None; + if (state.HasFlag(ModifierType.ControlMask)) + rv |= InputModifiers.Control; + if (state.HasFlag(ModifierType.ShiftMask)) + rv |= InputModifiers.Shift; + if (state.HasFlag(ModifierType.Mod1Mask)) + rv |= InputModifiers.Control; + if(state.HasFlag(ModifierType.Button1Mask)) + rv |= InputModifiers.LeftMouseButton; + if (state.HasFlag(ModifierType.Button2Mask)) + rv |= InputModifiers.RightMouseButton; + if (state.HasFlag(ModifierType.Button3Mask)) + rv |= InputModifiers.MiddleMouseButton; + return rv; + } + + protected override bool OnButtonPressEvent(EventButton evnt) + { + + var e = new RawMouseEventArgs( + GtkMouseDevice.Instance, + evnt.Time, + _inputRoot, + evnt.Button == 1 + ? RawMouseEventType.LeftButtonDown + : evnt.Button == 3 ? RawMouseEventType.RightButtonDown : RawMouseEventType.MiddleButtonDown, + new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State)); + Input(e); + return true; + } + + protected override bool OnScrollEvent(EventScroll evnt) + { + double step = 1; + var delta = new Vector(); + if (evnt.Direction == ScrollDirection.Down) + delta = new Vector(0, -step); + else if (evnt.Direction == ScrollDirection.Up) + delta = new Vector(0, step); + else if (evnt.Direction == ScrollDirection.Right) + delta = new Vector(-step, 0); + if (evnt.Direction == ScrollDirection.Left) + delta = new Vector(step, 0); + var e = new RawMouseWheelEventArgs(GtkMouseDevice.Instance, evnt.Time, _inputRoot, new Point(evnt.X, evnt.Y), delta, GetModifierKeys(evnt.State)); + Input(e); + return base.OnScrollEvent(evnt); + } + + protected override bool OnButtonReleaseEvent(EventButton evnt) + { + var e = new RawMouseEventArgs( + GtkMouseDevice.Instance, + evnt.Time, + _inputRoot, + evnt.Button == 1 + ? RawMouseEventType.LeftButtonUp + : evnt.Button == 3 ? RawMouseEventType.RightButtonUp : RawMouseEventType.MiddleButtonUp, + new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State)); + Input(e); + return true; + } + + protected override bool OnConfigureEvent(EventConfigure evnt) + { + var newSize = new Size(evnt.Width, evnt.Height); + + if (newSize != _clientSize) + { + Resized(newSize); + } + + return true; + } + + protected override void OnDestroyed() + { + Closed(); + } + + private bool ProcessKeyEvent(EventKey evnt) + { + _lastKeyEventTimestamp = evnt.Time; + if (_imContext.FilterKeypress(evnt)) + return true; + var e = new RawKeyEventArgs( + GtkKeyboardDevice.Instance, + evnt.Time, + evnt.Type == EventType.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, + GtkKeyboardDevice.ConvertKey(evnt.Key), GetModifierKeys(evnt.State)); + Input(e); + return true; + } + + protected override bool OnKeyPressEvent(EventKey evnt) => ProcessKeyEvent(evnt); + + protected override bool OnKeyReleaseEvent(EventKey evnt) => ProcessKeyEvent(evnt); + + private void ImContext_Commit(object o, Gtk.CommitArgs args) + { + Input(new RawTextInputEventArgs(GtkKeyboardDevice.Instance, _lastKeyEventTimestamp, args.Str)); + } + + protected override bool OnExposeEvent(EventExpose evnt) + { + Paint(evnt.Area.ToAvalonia()); + return true; + } + + protected override void OnFocusActivated() + { + Activated(); + } + + protected override bool OnMotionNotifyEvent(EventMotion evnt) + { + var position = new Point(evnt.X, evnt.Y); + + GtkMouseDevice.Instance.SetClientPosition(position); + + var e = new RawMouseEventArgs( + GtkMouseDevice.Instance, + evnt.Time, + _inputRoot, + RawMouseEventType.Move, + position, GetModifierKeys(evnt.State)); + Input(e); + return true; + } + } +} diff --git a/src/Gtk/Perspex.Gtk/packages.config b/src/Gtk/Avalonia.Gtk/packages.config similarity index 100% rename from src/Gtk/Perspex.Gtk/packages.config rename to src/Gtk/Avalonia.Gtk/packages.config diff --git a/src/Gtk/Perspex.Cairo/CairoExtensions.cs b/src/Gtk/Perspex.Cairo/CairoExtensions.cs deleted file mode 100644 index fa66837194..0000000000 --- a/src/Gtk/Perspex.Cairo/CairoExtensions.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Cairo -{ - using Cairo = global::Cairo; - - public static class CairoExtensions - { - public static Cairo.Color ToCairo(this Perspex.Media.Color color) - { - return new Cairo.Color(color.R / 255.0, color.G / 255.0, color.B / 255.0, color.A / 255.0); - } - - public static Cairo.Matrix ToCairo(this Matrix m) - { - return new Cairo.Matrix(m.M11, m.M12, m.M21, m.M22, m.M31, m.M32); - } - - public static Cairo.PointD ToCairo(this Point p) - { - return new Cairo.PointD(p.X, p.Y); - } - - public static Cairo.Rectangle ToCairo(this Rect rect) - { - return new Cairo.Rectangle(rect.X, rect.Y, rect.Width, rect.Height); - } - - public static Rect ToPerspex(this Cairo.Rectangle rect) - { - return new Rect(rect.X, rect.Y, rect.Width, rect.Height); - } - - public static Rect ToPerspex(this Pango.Rectangle rect) - { - return new Rect( - Pango.Units.ToDouble(rect.X), - Pango.Units.ToDouble(rect.Y), - Pango.Units.ToDouble(rect.Width), - Pango.Units.ToDouble(rect.Height)); - } - - public static Pango.Weight ToCairo(this Perspex.Media.FontWeight weight) - { - return (Pango.Weight)weight; - } - - public static Pango.Alignment ToCairo(this Perspex.Media.TextAlignment alignment) - { - if (alignment == Perspex.Media.TextAlignment.Left) - { - return Pango.Alignment.Left; - } - - if (alignment == Perspex.Media.TextAlignment.Center) - { - return Pango.Alignment.Center; - } - - return Pango.Alignment.Right; - } - } -} \ No newline at end of file diff --git a/src/Gtk/Perspex.Cairo/CairoPlatform.cs b/src/Gtk/Perspex.Cairo/CairoPlatform.cs deleted file mode 100644 index 4e2c6727a5..0000000000 --- a/src/Gtk/Perspex.Cairo/CairoPlatform.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Cairo.Media; -using Perspex.Cairo.Media.Imaging; -using Perspex.Media; -using Perspex.Platform; - -namespace Perspex -{ - public static class GtkApplicationExtensions - { - public static TApp UseCairo(this TApp app) where TApp : Application - { - Perspex.Cairo.CairoPlatform.Initialize(); - return app; - } - } -} - -namespace Perspex.Cairo -{ - using System.IO; - using global::Cairo; - - public class CairoPlatform : IPlatformRenderInterface - { - private static readonly CairoPlatform s_instance = new CairoPlatform(); - - private static readonly Pango.Context s_pangoContext = CreatePangoContext(); - - public static void Initialize() => PerspexLocator.CurrentMutable.Bind().ToConstant(s_instance); - - public IBitmapImpl CreateBitmap(int width, int height) - { - return new BitmapImpl(new Gdk.Pixbuf(Gdk.Colorspace.Rgb, true, 32, width, height)); - } - - public IFormattedTextImpl CreateFormattedText( - string text, - string fontFamily, - double fontSize, - FontStyle fontStyle, - TextAlignment textAlignment, - Perspex.Media.FontWeight fontWeight) - { - return new FormattedTextImpl(s_pangoContext, text, fontFamily, fontSize, fontStyle, textAlignment, fontWeight); - } - - public IRenderTarget CreateRenderer(IPlatformHandle handle) - { - var window = handle as Gtk.Window; - if (window == null) - throw new NotSupportedException(string.Format( - "Don't know how to create a Cairo renderer from a '{0}' handle which isn't Gtk.Window", - handle.HandleDescriptor)); - - window.DoubleBuffered = true; - return new RenderTarget(window); - } - - public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height) - { - return new RenderTargetBitmapImpl(new ImageSurface(Format.Argb32, width, height)); - } - - public IStreamGeometryImpl CreateStreamGeometry() - { - return new StreamGeometryImpl(); - } - - public IBitmapImpl LoadBitmap(string fileName) - { - var pixbuf = new Gdk.Pixbuf(fileName); - - return new BitmapImpl(pixbuf); - } - - public IBitmapImpl LoadBitmap(Stream stream) - { - var pixbuf = new Gdk.Pixbuf(stream); - - return new BitmapImpl(pixbuf); - } - - private static Pango.Context CreatePangoContext() - { - Gtk.Application.Init(); - return new Gtk.Invisible().CreatePangoContext(); - } - } -} diff --git a/src/Gtk/Perspex.Cairo/Media/BrushImpl.cs b/src/Gtk/Perspex.Cairo/Media/BrushImpl.cs deleted file mode 100644 index 76ad34b19a..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/BrushImpl.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using global::Cairo; - -namespace Perspex.Cairo -{ - public abstract class BrushImpl : IDisposable - { - public Pattern PlatformBrush { get; protected set; } - - public void Dispose() - { - if (this.PlatformBrush != null) - this.PlatformBrush.Dispose(); - } - } -} - diff --git a/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs b/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs deleted file mode 100644 index b22bcd1893..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reactive.Disposables; -using System.Runtime.InteropServices; -using Perspex.Cairo.Media.Imaging; -using Perspex.Media; - -namespace Perspex.Cairo.Media -{ - using Perspex.Media.Imaging; - using Cairo = global::Cairo; - - /// - /// Draws using Direct2D1. - /// - public class DrawingContext : IDrawingContextImpl, IDisposable - { - /// - /// The cairo context. - /// - private readonly Cairo.Context _context; - - /// - /// Initializes a new instance of the class. - /// - /// The target surface. - public DrawingContext(Cairo.Surface surface) - { - _context = new Cairo.Context(surface); - } - - /// - /// Initializes a new instance of the class. - /// - /// The GDK drawable. - public DrawingContext(Gdk.Drawable drawable) - { - _context = Gdk.CairoHelper.Create(drawable); - } - - - private Matrix _transform = Matrix.Identity; - /// - /// Gets the current transform of the drawing context. - /// - public Matrix Transform - { - get { return _transform; } - set - { - _transform = value; - _context.Matrix = value.ToCairo(); - - } - } - - /// - /// Ends a draw operation. - /// - public void Dispose() - { - _context.Dispose(); - } - - /// - /// Draws a bitmap image. - /// - /// The bitmap image. - /// The opacity to draw with. - /// The rect in the image to draw. - /// The rect in the output to draw to. - public void DrawImage(IBitmap bitmap, double opacity, Rect sourceRect, Rect destRect) - { - var impl = bitmap.PlatformImpl as BitmapImpl; - var size = new Size(impl.PixelWidth, impl.PixelHeight); - var scale = new Vector(destRect.Width / sourceRect.Width, destRect.Height / sourceRect.Height); - - _context.Save(); - _context.Scale(scale.X, scale.Y); - destRect /= scale; - - if (opacityOverride < 1.0f) { - _context.PushGroup (); - Gdk.CairoHelper.SetSourcePixbuf ( - _context, - impl.Surface, - -sourceRect.X + destRect.X, - -sourceRect.Y + destRect.Y); - - _context.Rectangle (destRect.ToCairo ()); - _context.Fill (); - _context.PopGroupToSource (); - _context.PaintWithAlpha (opacityOverride); - } else { - _context.PushGroup (); - Gdk.CairoHelper.SetSourcePixbuf ( - _context, - impl.Surface, - -sourceRect.X + destRect.X, - -sourceRect.Y + destRect.Y); - - _context.Rectangle (destRect.ToCairo ()); - _context.Fill (); - _context.PopGroupToSource (); - _context.PaintWithAlpha (opacityOverride); - } - _context.Restore(); - } - - /// - /// Draws a line. - /// - /// The stroke pen. - /// The first point of the line. - /// The second point of the line. - public void DrawLine(Pen pen, Point p1, Point p2) - { - var size = new Rect(p1, p2).Size; - - using (var p = SetPen(pen, size)) - { - _context.MoveTo(p1.ToCairo()); - _context.LineTo(p2.ToCairo()); - _context.Stroke(); - } - } - - /// - /// Draws a geometry. - /// - /// The fill brush. - /// The stroke pen. - /// The geometry. - public void DrawGeometry(IBrush brush, Pen pen, Geometry geometry) - { - var impl = geometry.PlatformImpl as StreamGeometryImpl; - - var oldMatrix = Transform; - Transform = impl.Transform * Transform; - - - if (brush != null) - { - _context.AppendPath(impl.Path); - using (var b = SetBrush(brush, geometry.Bounds.Size)) - { - _context.FillRule = impl.FillRule == FillRule.EvenOdd - ? Cairo.FillRule.EvenOdd - : Cairo.FillRule.Winding; - - if (pen != null) - _context.FillPreserve(); - else - _context.Fill(); - } - } - Transform = oldMatrix; - - if (pen != null) - { - _context.AppendPath(impl.Path); - using (var p = SetPen(pen, geometry.Bounds.Size)) - { - _context.Stroke(); - } - } - } - - /// - /// Draws the outline of a rectangle. - /// - /// The pen. - /// The rectangle bounds. - public void DrawRectangle(Pen pen, Rect rect, float cornerRadius) - { - using (var p = SetPen(pen, rect.Size)) - { - _context.Rectangle(rect.ToCairo ()); - _context.Stroke(); - } - } - - /// - /// Draws text. - /// - /// The foreground brush. - /// The upper-left corner of the text. - /// The text. - public void DrawText(IBrush foreground, Point origin, FormattedText text) - { - var layout = ((FormattedTextImpl)text.PlatformImpl).Layout; - _context.MoveTo(origin.X, origin.Y); - - using (var b = SetBrush(foreground, new Size(0, 0))) - { - Pango.CairoHelper.ShowLayout(_context, layout); - } - } - - /// - /// Draws a filled rectangle. - /// - /// The brush. - /// The rectangle bounds. - public void FillRectangle(IBrush brush, Rect rect, float cornerRadius) - { - using (var b = SetBrush(brush, rect.Size)) - { - _context.Rectangle(rect.ToCairo ()); - _context.Fill(); - } - } - - /// - /// Pushes a clip rectange. - /// - /// The clip rectangle. - /// A disposable used to undo the clip rectangle. - public void PushClip(Rect clip) - { - _context.Save(); - _context.Rectangle(clip.ToCairo()); - _context.Clip(); - } - - public void PopClip() - { - _context.Restore(); - } - - readonly Stack _opacityStack = new Stack(); - - /// - /// Pushes an opacity value. - /// - /// The opacity. - /// A disposable used to undo the opacity. - public void PushOpacity(double opacity) - { - _opacityStack.Push(opacityOverride); - - if (opacity < 1.0f) - opacityOverride *= opacity; - - } - - public void PopOpacity() - { - opacityOverride = _opacityStack.Pop(); - } - - /// - /// Pushes a matrix transformation. - /// - /// The matrix - /// A disposable used to undo the transformation. - public IDisposable PushTransform(Matrix matrix) - { - _context.Save(); - _context.Transform(matrix.ToCairo()); - - return Disposable.Create(() => - { - _context.Restore(); - }); - } - - private double opacityOverride = 1.0f; - - private IDisposable SetBrush(IBrush brush, Size destinationSize) - { - _context.Save (); - - var solid = brush as SolidColorBrush; - var linearGradientBrush = brush as LinearGradientBrush; - var radialGradientBrush = brush as RadialGradientBrush; - var imageBrush = brush as ImageBrush; - var visualBrush = brush as VisualBrush; - BrushImpl impl = null; - - if (solid != null) - { - impl = new SolidColorBrushImpl(solid, opacityOverride); - } - else if (linearGradientBrush != null) - { - impl = new LinearGradientBrushImpl(linearGradientBrush, destinationSize); - } - else if (radialGradientBrush != null) - { - impl = new RadialGradientBrushImpl(radialGradientBrush, destinationSize); - } - else if (imageBrush != null) - { - impl = new ImageBrushImpl(imageBrush, destinationSize); - } - else if (visualBrush != null) - { - impl = new VisualBrushImpl(visualBrush, destinationSize); - } - else - { - impl = new SolidColorBrushImpl(null, opacityOverride); - } - - _context.SetSource(impl.PlatformBrush); - return Disposable.Create(() => - { - impl.Dispose(); - _context.Restore(); - }); - } - - private IDisposable SetPen(Pen pen, Size destinationSize) - { - if (pen.DashStyle != null) - { - if (pen.DashStyle.Dashes != null && pen.DashStyle.Dashes.Count > 0) - { - var cray = pen.DashStyle.Dashes.ToArray(); - _context.SetDash(cray, pen.DashStyle.Offset); - } - } - - _context.LineWidth = pen.Thickness; - _context.MiterLimit = pen.MiterLimit; - - // Line caps and joins are currently broken on Cairo. I've defaulted them to sensible defaults for now. - // Cairo does not have StartLineCap, EndLineCap, and DashCap properties, whereas Direct2D does. - // TODO: Figure out a solution for this. - _context.LineJoin = Cairo.LineJoin.Miter; - _context.LineCap = Cairo.LineCap.Butt; - - if (pen.Brush == null) - return Disposable.Empty; - - return SetBrush(pen.Brush, destinationSize); - } - } -} diff --git a/src/Gtk/Perspex.Cairo/Media/FormattedTextImpl.cs b/src/Gtk/Perspex.Cairo/Media/FormattedTextImpl.cs deleted file mode 100644 index e3a6e50125..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/FormattedTextImpl.cs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Perspex.Media; -using Perspex.Platform; - -namespace Perspex.Cairo.Media -{ - public class FormattedTextImpl : IFormattedTextImpl - { - private Size _size; - private readonly string _text; - - static double CorrectScale(double input) - { - return input * 0.75; - } - - public FormattedTextImpl( - Pango.Context context, - string text, - string fontFamily, - double fontSize, - FontStyle fontStyle, - TextAlignment textAlignment, - FontWeight fontWeight) - { - Contract.Requires(context != null); - Contract.Requires(text != null); - Layout = new Pango.Layout(context); - _text = text; - Layout.SetText(text); - Layout.FontDescription = new Pango.FontDescription - { - Family = fontFamily, - Size = Pango.Units.FromDouble(CorrectScale(fontSize)), - Style = (Pango.Style)fontStyle, - Weight = fontWeight.ToCairo() - }; - - Layout.Alignment = textAlignment.ToCairo(); - Layout.Attributes = new Pango.AttrList(); - } - - public Size Constraint - { - get - { - return _size; - } - - set - { - _size = value; - Layout.Width = double.IsPositiveInfinity(value.Width) ? - -1 : Pango.Units.FromDouble(value.Width); - } - } - - public Pango.Layout Layout - { - get; - } - - public void Dispose() - { - Layout.Dispose(); - } - - public IEnumerable GetLines() - { - return new FormattedTextLine[0]; - } - - public TextHitTestResult HitTestPoint(Point point) - { - int textPosition; - int trailing; - - var isInside = Layout.XyToIndex( - Pango.Units.FromDouble(point.X), - Pango.Units.FromDouble(point.Y), - out textPosition, - out trailing); - - textPosition = PangoIndexToTextIndex(textPosition); - - return new TextHitTestResult - { - IsInside = isInside, - TextPosition = textPosition, - IsTrailing = trailing == 0, - }; - } - - int PangoIndexToTextIndex(int pangoIndex) - { - return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(_text), 0, Math.Min(pangoIndex, _text.Length)).Length; - } - - public Rect HitTestTextPosition(int index) - { - return Layout.IndexToPos(TextIndexToPangoIndex(index)).ToPerspex(); - } - - int TextIndexToPangoIndex(int textIndex) - { - return Encoding.UTF8.GetByteCount(textIndex < _text.Length ? _text.Remove(textIndex) : _text); - } - - public IEnumerable HitTestTextRange(int index, int length) - { - var ranges = new List(); - - for (var i = 0; i < length; i++) - { - ranges.Add(HitTestTextPosition(index + i)); - } - - return ranges; - } - - public Size Measure() - { - int width; - int height; - Layout.GetPixelSize(out width, out height); - - return new Size(width, height); - } - - public void SetForegroundBrush(IBrush brush, int startIndex, int count) - { - var scb = brush as SolidColorBrush; - if (scb != null) - { - - var color = new Pango.Color(); - color.Parse(string.Format("#{0}", scb.Color.ToString().Substring(3))); - - var brushAttr = new Pango.AttrForeground(color); - brushAttr.StartIndex = (uint)TextIndexToPangoIndex(startIndex); - brushAttr.EndIndex = (uint)TextIndexToPangoIndex(startIndex + count); - - Layout.Attributes.Insert(brushAttr); - } - } - } -} diff --git a/src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs b/src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs deleted file mode 100644 index 0a7dedc1a7..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/ImageBrushImpl.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using global::Cairo; - -namespace Perspex.Cairo.Media -{ - public class ImageBrushImpl : BrushImpl - { - public ImageBrushImpl(Perspex.Media.ImageBrush brush, Size destinationSize) - { - this.PlatformBrush = TileBrushes.CreateTileBrush(brush, destinationSize); - } - } -} - diff --git a/src/Gtk/Perspex.Cairo/Media/Imaging/BitmapImpl.cs b/src/Gtk/Perspex.Cairo/Media/Imaging/BitmapImpl.cs deleted file mode 100644 index 4abecba6c6..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/Imaging/BitmapImpl.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Platform; - -namespace Perspex.Cairo.Media.Imaging -{ - using Cairo = global::Cairo; - - public class BitmapImpl : IBitmapImpl - { - public BitmapImpl(Gdk.Pixbuf pixbuf) - { - Surface = pixbuf; - } - - public int PixelWidth => Surface.Width; - - public int PixelHeight => Surface.Height; - - public Gdk.Pixbuf Surface - { - get; - } - - public void Save(string fileName) - { - // TODO: Test - Surface.Save(fileName, "png"); - } - } -} diff --git a/src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs b/src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs deleted file mode 100644 index bb12d1887e..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/Imaging/RenderTargetBitmapImpl.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Media; -using Perspex.Platform; -using Perspex.Rendering; - -namespace Perspex.Cairo.Media.Imaging -{ - using Cairo = global::Cairo; - - public class RenderTargetBitmapImpl : IRenderTargetBitmapImpl - { - - private readonly RenderTarget _renderTarget; - public RenderTargetBitmapImpl(Cairo.ImageSurface surface) - { - Surface = surface; - _renderTarget = new RenderTarget(Surface); - } - - public int PixelWidth => Surface.Width; - - public int PixelHeight => Surface.Height; - - public void Dispose() - { - _renderTarget.Dispose(); - } - - public Cairo.ImageSurface Surface - { - get; - } - - public void Save(string fileName) - { - Surface.WriteToPng(fileName); - } - - public Perspex.Media.DrawingContext CreateDrawingContext() - { - return _renderTarget.CreateDrawingContext(); - } - } -} \ No newline at end of file diff --git a/src/Gtk/Perspex.Cairo/Media/LinearGradientBrushImpl.cs b/src/Gtk/Perspex.Cairo/Media/LinearGradientBrushImpl.cs deleted file mode 100644 index f1502275c7..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/LinearGradientBrushImpl.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using global::Cairo; - -namespace Perspex.Cairo -{ - public class LinearGradientBrushImpl : BrushImpl - { - public LinearGradientBrushImpl(Perspex.Media.LinearGradientBrush brush, Size destinationSize) - { - var start = brush.StartPoint.ToPixels(destinationSize); - var end = brush.EndPoint.ToPixels(destinationSize); - - this.PlatformBrush = new LinearGradient(start.X, start.Y, end.X, end.Y); - - foreach (var stop in brush.GradientStops) - ((LinearGradient)this.PlatformBrush).AddColorStop(stop.Offset, stop.Color.ToCairo()); - - ((LinearGradient)this.PlatformBrush).Extend = Extend.Pad; - } - } -} - diff --git a/src/Gtk/Perspex.Cairo/Media/RadialGradientBrushImpl.cs b/src/Gtk/Perspex.Cairo/Media/RadialGradientBrushImpl.cs deleted file mode 100644 index 2d54882324..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/RadialGradientBrushImpl.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using global::Cairo; - -namespace Perspex.Cairo -{ - public class RadialGradientBrushImpl : BrushImpl - { - public RadialGradientBrushImpl(Perspex.Media.RadialGradientBrush brush, Size destinationSize) - { - var center = brush.Center.ToPixels(destinationSize); - var gradientOrigin = brush.GradientOrigin.ToPixels(destinationSize); - var radius = brush.Radius; - - this.PlatformBrush = new RadialGradient(center.X, center.Y, radius, gradientOrigin.X, gradientOrigin.Y, radius); - - foreach (var stop in brush.GradientStops) - { - ((RadialGradient)this.PlatformBrush).AddColorStop(stop.Offset, stop.Color.ToCairo()); - } - - ((RadialGradient)this.PlatformBrush).Extend = Extend.Pad; - } - } -} - diff --git a/src/Gtk/Perspex.Cairo/Media/SolidColorBrushImpl.cs b/src/Gtk/Perspex.Cairo/Media/SolidColorBrushImpl.cs deleted file mode 100644 index 10e63f0382..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/SolidColorBrushImpl.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using global::Cairo; - -namespace Perspex.Cairo -{ - public class SolidColorBrushImpl : BrushImpl - { - public SolidColorBrushImpl(Perspex.Media.SolidColorBrush brush, double opacityOverride = 1.0f) - { - var color = brush?.Color.ToCairo() ?? new Color(); - - if (brush != null) - color.A = Math.Min(brush.Opacity, color.A); - - if (opacityOverride < 1.0f) - color.A = Math.Min(opacityOverride, color.A); - - this.PlatformBrush = new SolidPattern(color); - } - } -} - diff --git a/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs b/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs deleted file mode 100644 index f4cf9294dc..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using Perspex.Media; -using Perspex.Platform; -using Perspex.RenderHelpers; - -namespace Perspex.Cairo.Media -{ - using Cairo = global::Cairo; - - public class StreamGeometryContextImpl : IStreamGeometryContextImpl - { - private readonly StreamGeometryImpl _target; - private Point _currentPoint; - public StreamGeometryContextImpl(StreamGeometryImpl target, Cairo.Path path) - { - _target = target; - - _surf = new Cairo.ImageSurface (Cairo.Format.Argb32, 0, 0); - _context = new Cairo.Context (_surf); - this.Path = path; - - if (this.Path != null) - { - _context.AppendPath(this.Path); - } - } - - public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) - { - ArcToHelper.ArcTo(this, _currentPoint, point, size, rotationAngle, isLargeArc, sweepDirection); - _currentPoint = point; - } - - public void BeginFigure(Point startPoint, bool isFilled) - { - if (this.Path == null) - { - _context.MoveTo(startPoint.ToCairo()); - _currentPoint = startPoint; - } - } - - public void CubicBezierTo(Point point1, Point point2, Point point3) - { - if (this.Path == null) - { - _context.CurveTo(point1.ToCairo(), point2.ToCairo(), point3.ToCairo()); - _currentPoint = point3; - } - } - - public void QuadraticBezierTo(Point control, Point endPoint) - { - if (this.Path == null) - { - QuadBezierHelper.QuadraticBezierTo(this, _currentPoint, control, endPoint); - _currentPoint = endPoint; - } - } - - public void LineTo(Point point) - { - if (this.Path == null) - { - _context.LineTo(point.ToCairo()); - _currentPoint = point; - } - } - - private readonly Cairo.Context _context; - private readonly Cairo.ImageSurface _surf; - public Cairo.Path Path { get; private set; } - public Rect Bounds { get; private set; } - - public void EndFigure(bool isClosed) - { - if (this.Path == null) - { - if (isClosed) - _context.ClosePath (); - - Path = _context.CopyPath (); - Bounds = _context.FillExtents ().ToPerspex (); - } - } - - public void SetFillRule(FillRule fillRule) - { - _target.FillRule = fillRule; - } - - - public void Dispose() - { - _context.Dispose (); - _surf.Dispose (); - } - } -} diff --git a/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs b/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs deleted file mode 100644 index 2dd844c687..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Media; -using Perspex.Platform; -using System.Collections.Generic; - -namespace Perspex.Cairo.Media -{ - using Cairo = global::Cairo; - - public class StreamGeometryImpl : IStreamGeometryImpl - { - public StreamGeometryImpl() - { - _impl = new StreamGeometryContextImpl(this, null); - } - - public StreamGeometryImpl(StreamGeometryContextImpl impl) - { - _impl = impl; - } - - public Rect Bounds - { - get { return _impl.Bounds; } - } - - public Cairo.Path Path - { - get { return _impl.Path; } - } - - private readonly StreamGeometryContextImpl _impl; - - private Matrix _transform = Matrix.Identity; - public Matrix Transform - { - get { return _transform; } - set - { - if (value != Transform) - { - if (!value.IsIdentity) - { - _transform = value; - } - } - } - } - - public FillRule FillRule { get; set; } - - public IStreamGeometryImpl Clone() - { - return new StreamGeometryImpl(_impl); - } - - public Rect GetRenderBounds(double strokeThickness) - { - // TODO: Calculate properly. - return Bounds.Inflate(strokeThickness); - } - - public IStreamGeometryContextImpl Open() - { - return _impl; - } - } -} diff --git a/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs b/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs deleted file mode 100644 index 91262ce714..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Cairo; -using Perspex.Cairo.Media.Imaging; -using Perspex.Layout; -using Perspex.Media; -using Perspex.Platform; -using Perspex.Rendering; -using Perspex.RenderHelpers; - -namespace Perspex.Cairo.Media -{ - internal static class TileBrushes - { - public static SurfacePattern CreateTileBrush(TileBrush brush, Size targetSize) - { - var helper = new TileBrushImplHelper(brush, targetSize); - if (!helper.IsValid) - return null; - - using (var intermediate = new ImageSurface(Format.ARGB32, (int)helper.IntermediateSize.Width, (int)helper.IntermediateSize.Height)) - using (var ctx = new RenderTarget(intermediate).CreateDrawingContext()) - { - helper.DrawIntermediate(ctx); - - var result = new SurfacePattern(intermediate); - - if ((brush.TileMode & TileMode.FlipXY) != 0) - { - // TODO: Currently always FlipXY as that's all cairo supports natively. - // Support separate FlipX and FlipY by drawing flipped images to intermediate - // surface. - result.Extend = Extend.Reflect; - } - else - { - result.Extend = Extend.Repeat; - } - - if (brush.TileMode != TileMode.None) - { - var matrix = result.Matrix; - matrix.InitTranslate(-helper.DestinationRect.X, -helper.DestinationRect.Y); - result.Matrix = matrix; - } - - return result; - } - } - - - } -} diff --git a/src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs b/src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs deleted file mode 100644 index 39a3c9afde..0000000000 --- a/src/Gtk/Perspex.Cairo/Media/VisualBrushImpl.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using global::Cairo; - -namespace Perspex.Cairo.Media -{ - public class VisualBrushImpl : BrushImpl - { - public VisualBrushImpl(Perspex.Media.VisualBrush brush, Size destinationSize) - { - this.PlatformBrush = TileBrushes.CreateTileBrush(brush, destinationSize); - } - } -} - diff --git a/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj b/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj deleted file mode 100644 index 6e72118062..0000000000 --- a/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj +++ /dev/null @@ -1,121 +0,0 @@ - - - - - Debug - AnyCPU - {FB05AC90-89BA-4F2F-A924-F37875FB547C} - Library - Properties - Perspex.Cairo - Perspex.Cairo - v4.5 - 512 - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - ..\..\..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll - - - ..\..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll - - - - - - - - - - - - - - - - - - - - - - - - - {D211E587-D8BC-45B9-95A4-F297C8FA5200} - Perspex.Animation - - - {B09B78D8-9B26-48B0-9149-D64A2F120F3F} - Perspex.Base - - - {d2221c82-4a25-4583-9b43-d791e3f6820c} - Perspex.Controls - - - {62024b2d-53eb-4638-b26b-85eeaa54866e} - Perspex.Input - - - {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} - Perspex.Interactivity - - - {42472427-4774-4C81-8AFF-9F27B8E31721} - Perspex.Layout - - - {EB582467-6ABB-43A1-B052-E981BA910E3A} - Perspex.SceneGraph - - - {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} - Perspex.Styling - - - - - - - - - - \ No newline at end of file diff --git a/src/Gtk/Perspex.Cairo/Properties/AssemblyInfo.cs b/src/Gtk/Perspex.Cairo/Properties/AssemblyInfo.cs deleted file mode 100644 index 18361d7ad5..0000000000 --- a/src/Gtk/Perspex.Cairo/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 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.Cairo")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Perspex.Cairo")] -[assembly: AssemblyCopyright("Copyright \u00A9 2014")] -[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("f999ba8b-64e7-40cc-98a4-003f1852d2a3")] - -// 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")] diff --git a/src/Gtk/Perspex.Cairo/RenderTarget.cs b/src/Gtk/Perspex.Cairo/RenderTarget.cs deleted file mode 100644 index e562ccfded..0000000000 --- a/src/Gtk/Perspex.Cairo/RenderTarget.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Runtime.InteropServices; -using Perspex.Cairo.Media; -using Perspex.Media; -using Perspex.Platform; -using Perspex.Rendering; -using DrawingContext = Perspex.Media.DrawingContext; - -namespace Perspex.Cairo -{ - using global::Cairo; - - /// - /// A cairo render target. - /// - public class RenderTarget : IRenderTarget - { - private readonly Surface _surface; - private readonly Gtk.Window _window; - - /// - /// Initializes a new instance of the class. - /// - /// The window. - /// The width of the window. - /// The height of the window. - public RenderTarget(Gtk.Window window) - { - _window = window; - } - - public RenderTarget(ImageSurface surface) - { - _surface = surface; - } - - - /// - /// Creates a cairo surface that targets a platform-specific resource. - /// - /// A surface wrapped in an . - public DrawingContext CreateDrawingContext() - { - var ctx = _surface != null - ? new Media.DrawingContext(_surface) - : new Media.DrawingContext(_window.GdkWindow); - return new DrawingContext(ctx); - } - - public void Dispose() => _surface?.Dispose(); - } -} diff --git a/src/Gtk/Perspex.Gtk/ClipboardImpl.cs b/src/Gtk/Perspex.Gtk/ClipboardImpl.cs deleted file mode 100644 index 2eabbe551c..0000000000 --- a/src/Gtk/Perspex.Gtk/ClipboardImpl.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Threading.Tasks; -using Gdk; -using Perspex.Input.Platform; - -namespace Perspex.Gtk -{ - using Gtk = global::Gtk; - - internal class ClipboardImpl : IClipboard - { - private static Gtk.Clipboard GetClipboard() => Gtk.Clipboard.GetForDisplay(Display.Default, new Atom(IntPtr.Zero)); - - public Task GetTextAsync() - { - var clip = GetClipboard(); - var tcs = new TaskCompletionSource(); - clip.RequestText((_, text) => - { - tcs.TrySetResult(text); - }); - return tcs.Task; - } - - public Task SetTextAsync(string text) - { - using (var cl = GetClipboard()) - cl.Text = text; - return Task.FromResult(0); - } - - public Task ClearAsync() - { - using (var cl = GetClipboard()) - cl.Clear(); - return Task.FromResult(0); - } - } -} diff --git a/src/Gtk/Perspex.Gtk/CursorFactory.cs b/src/Gtk/Perspex.Gtk/CursorFactory.cs deleted file mode 100644 index 6a250024bf..0000000000 --- a/src/Gtk/Perspex.Gtk/CursorFactory.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Collections.Generic; -using Gdk; -using Perspex.Input; -using Perspex.Platform; - -namespace Perspex.Gtk -{ - using Gtk = global::Gtk; - - internal class CursorFactory : IStandardCursorFactory - { - public static CursorFactory Instance { get; } = new CursorFactory(); - - private CursorFactory() - { - } - - private static readonly Dictionary CursorTypeMapping = new Dictionary - - { - {StandardCursorType.AppStarting, CursorType.Watch}, - {StandardCursorType.Arrow, CursorType.LeftPtr}, - {StandardCursorType.Cross, CursorType.Cross}, - {StandardCursorType.Hand, CursorType.Hand1}, - {StandardCursorType.Ibeam, CursorType.Xterm}, - {StandardCursorType.No, Gtk.Stock.Cancel}, - {StandardCursorType.SizeAll, CursorType.Sizing}, - //{ StandardCursorType.SizeNorthEastSouthWest, 32643 }, - {StandardCursorType.SizeNorthSouth, CursorType.SbVDoubleArrow}, - //{ StandardCursorType.SizeNorthWestSouthEast, 32642 }, - {StandardCursorType.SizeWestEast, CursorType.SbHDoubleArrow}, - {StandardCursorType.UpArrow, CursorType.BasedArrowUp}, - {StandardCursorType.Wait, CursorType.Watch}, - {StandardCursorType.Help, Gtk.Stock.Help}, - {StandardCursorType.TopSide, CursorType.TopSide}, - {StandardCursorType.BottomSize, CursorType.BottomSide}, - {StandardCursorType.LeftSide, CursorType.LeftSide}, - {StandardCursorType.RightSide, CursorType.RightSide}, - {StandardCursorType.TopLeftCorner, CursorType.TopLeftCorner}, - {StandardCursorType.TopRightCorner, CursorType.TopRightCorner}, - {StandardCursorType.BottomLeftCorner, CursorType.BottomLeftCorner}, - {StandardCursorType.BottomRightCorner, CursorType.BottomRightCorner} - }; - - private static readonly Dictionary Cache = - new Dictionary(); - - private Gdk.Cursor GetCursor(object desc) - { - Gdk.Cursor rv; - var name = desc as string; - if (name != null) - { - var theme = Gtk.IconTheme.Default; - var icon = theme.LoadIcon(name, 32, default(Gtk.IconLookupFlags)); - rv = icon == null ? new Gdk.Cursor(CursorType.XCursor) : new Gdk.Cursor(Display.Default, icon, 0, 0); - } - else - { - rv = new Gdk.Cursor((CursorType)desc); - } - - rv.Owned = false; - return rv; - } - - public IPlatformHandle GetCursor(StandardCursorType cursorType) - { - IPlatformHandle rv; - if (!Cache.TryGetValue(cursorType, out rv)) - { - Cache[cursorType] = - rv = - new PlatformHandle( - GetCursor(CursorTypeMapping[cursorType]).Handle, - "GTKCURSOR"); - } - - return rv; - } - } -} diff --git a/src/Gtk/Perspex.Gtk/GtkExtensions.cs b/src/Gtk/Perspex.Gtk/GtkExtensions.cs deleted file mode 100644 index 691a17c391..0000000000 --- a/src/Gtk/Perspex.Gtk/GtkExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Gtk -{ - using Gtk = global::Gtk; - - public static class GtkExtensions - { - public static Rect ToPerspex(this Gdk.Rectangle rect) - { - return new Rect(rect.Left, rect.Top, rect.Right, rect.Bottom); - } - } -} diff --git a/src/Gtk/Perspex.Gtk/GtkPlatform.cs b/src/Gtk/Perspex.Gtk/GtkPlatform.cs deleted file mode 100644 index 6a1d269dba..0000000000 --- a/src/Gtk/Perspex.Gtk/GtkPlatform.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Disposables; -using System.Threading; -using Perspex.Controls.Platform; -using Perspex.Input.Platform; -using Perspex.Input; -using Perspex.Platform; -using Perspex.Shared.PlatformSupport; - -namespace Perspex -{ - public static class GtkApplicationExtensions - { - public static TApp UseGtk(this TApp app) where TApp : Application - { - Perspex.Gtk.GtkPlatform.Initialize(); - return app; - } - } -} - -namespace Perspex.Gtk -{ - using Gtk = global::Gtk; - - public class GtkPlatform : IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform - { - private static readonly GtkPlatform s_instance = new GtkPlatform(); - private static Thread _uiThread; - - public GtkPlatform() - { - Gtk.Application.Init(); - } - - 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() - { - PerspexLocator.CurrentMutable - .Bind().ToConstant(s_instance) - .Bind().ToSingleton() - .Bind().ToConstant(CursorFactory.Instance) - .Bind().ToConstant(GtkKeyboardDevice.Instance) - .Bind().ToConstant(GtkMouseDevice.Instance) - .Bind().ToConstant(s_instance) - .Bind().ToConstant(s_instance) - .Bind().ToSingleton(); - SharedPlatform.Register(); - _uiThread = Thread.CurrentThread; - } - - public bool HasMessages() - { - return Gtk.Application.EventsPending(); - } - - public void ProcessMessage() - { - Gtk.Application.RunIteration(); - } - - public void RunLoop(CancellationToken cancellationToken) - { - while (!cancellationToken.IsCancellationRequested) - Gtk.Application.RunIteration(); - } - - public IDisposable StartTimer(TimeSpan interval, Action tick) - { - var result = true; - var handle = GLib.Timeout.Add( - (uint)interval.TotalMilliseconds, - () => - { - tick(); - return result; - }); - - return Disposable.Create(() => result = false); - } - - - - public void Signal() - { - Gtk.Application.Invoke(delegate { Signaled?.Invoke(); }); - } - - public bool CurrentThreadIsLoopThread => Thread.CurrentThread == _uiThread; - - public event Action Signaled; - public IWindowImpl CreateWindow() - { - return new WindowImpl(); - } - - public IWindowImpl CreateEmbeddableWindow() - { - throw new NotSupportedException(); - } - - public IPopupImpl CreatePopup() - { - return new PopupImpl(); - } - } -} \ No newline at end of file diff --git a/src/Gtk/Perspex.Gtk/Input/GtkKeyboardDevice.cs b/src/Gtk/Perspex.Gtk/Input/GtkKeyboardDevice.cs deleted file mode 100644 index b0b9016ff6..0000000000 --- a/src/Gtk/Perspex.Gtk/Input/GtkKeyboardDevice.cs +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using Perspex.Input; - -namespace Perspex.Gtk -{ - public class GtkKeyboardDevice : KeyboardDevice - { - private static readonly Dictionary KeyDic = new Dictionary - { - { Gdk.Key.Cancel, Key.Cancel }, - { Gdk.Key.BackSpace, Key.Back }, - { Gdk.Key.Tab, Key.Tab }, - { Gdk.Key.Linefeed, Key.LineFeed }, - { Gdk.Key.Clear, Key.Clear }, - { Gdk.Key.Return, Key.Return }, - { Gdk.Key.Pause, Key.Pause }, - //{ Gdk.Key.?, Key.CapsLock } - //{ Gdk.Key.?, Key.HangulMode } - //{ Gdk.Key.?, Key.JunjaMode } - //{ Gdk.Key.?, Key.FinalMode } - //{ Gdk.Key.?, Key.KanjiMode } - { Gdk.Key.Escape, Key.Escape }, - //{ Gdk.Key.?, Key.ImeConvert } - //{ Gdk.Key.?, Key.ImeNonConvert } - //{ Gdk.Key.?, Key.ImeAccept } - //{ Gdk.Key.?, Key.ImeModeChange } - { Gdk.Key.space, Key.Space }, - { Gdk.Key.Prior, Key.Prior }, - //{ Gdk.Key.?, Key.PageDown } - { Gdk.Key.End, Key.End }, - { Gdk.Key.Home, Key.Home }, - { Gdk.Key.Left, Key.Left }, - { Gdk.Key.Up, Key.Up }, - { Gdk.Key.Right, Key.Right }, - { Gdk.Key.Down, Key.Down }, - { Gdk.Key.Select, Key.Select }, - { Gdk.Key.Print, Key.Print }, - { Gdk.Key.Execute, Key.Execute }, - //{ Gdk.Key.?, Key.Snapshot } - { Gdk.Key.Insert, Key.Insert }, - { Gdk.Key.Delete, Key.Delete }, - { Gdk.Key.Help, Key.Help }, - //{ Gdk.Key.?, Key.D0 } - //{ Gdk.Key.?, Key.D1 } - //{ Gdk.Key.?, Key.D2 } - //{ Gdk.Key.?, Key.D3 } - //{ Gdk.Key.?, Key.D4 } - //{ Gdk.Key.?, Key.D5 } - //{ Gdk.Key.?, Key.D6 } - //{ Gdk.Key.?, Key.D7 } - //{ Gdk.Key.?, Key.D8 } - //{ Gdk.Key.?, Key.D9 } - { Gdk.Key.A, Key.A }, - { Gdk.Key.B, Key.B }, - { Gdk.Key.C, Key.C }, - { Gdk.Key.D, Key.D }, - { Gdk.Key.E, Key.E }, - { Gdk.Key.F, Key.F }, - { Gdk.Key.G, Key.G }, - { Gdk.Key.H, Key.H }, - { Gdk.Key.I, Key.I }, - { Gdk.Key.J, Key.J }, - { Gdk.Key.K, Key.K }, - { Gdk.Key.L, Key.L }, - { Gdk.Key.M, Key.M }, - { Gdk.Key.N, Key.N }, - { Gdk.Key.O, Key.O }, - { Gdk.Key.P, Key.P }, - { Gdk.Key.Q, Key.Q }, - { Gdk.Key.R, Key.R }, - { Gdk.Key.S, Key.S }, - { Gdk.Key.T, Key.T }, - { Gdk.Key.U, Key.U }, - { Gdk.Key.V, Key.V }, - { Gdk.Key.W, Key.W }, - { Gdk.Key.X, Key.X }, - { Gdk.Key.Y, Key.Y }, - { Gdk.Key.Z, Key.Z }, - { Gdk.Key.a, Key.A }, - { Gdk.Key.b, Key.B }, - { Gdk.Key.c, Key.C }, - { Gdk.Key.d, Key.D }, - { Gdk.Key.e, Key.E }, - { Gdk.Key.f, Key.F }, - { Gdk.Key.g, Key.G }, - { Gdk.Key.h, Key.H }, - { Gdk.Key.i, Key.I }, - { Gdk.Key.j, Key.J }, - { Gdk.Key.k, Key.K }, - { Gdk.Key.l, Key.L }, - { Gdk.Key.m, Key.M }, - { Gdk.Key.n, Key.N }, - { Gdk.Key.o, Key.O }, - { Gdk.Key.p, Key.P }, - { Gdk.Key.q, Key.Q }, - { Gdk.Key.r, Key.R }, - { Gdk.Key.s, Key.S }, - { Gdk.Key.t, Key.T }, - { Gdk.Key.u, Key.U }, - { Gdk.Key.v, Key.V }, - { Gdk.Key.w, Key.W }, - { Gdk.Key.x, Key.X }, - { Gdk.Key.y, Key.Y }, - { Gdk.Key.z, Key.Z }, - //{ Gdk.Key.?, Key.LWin } - //{ Gdk.Key.?, Key.RWin } - //{ Gdk.Key.?, Key.Apps } - //{ Gdk.Key.?, Key.Sleep } - //{ Gdk.Key.?, Key.NumPad0 } - //{ Gdk.Key.?, Key.NumPad1 } - //{ Gdk.Key.?, Key.NumPad2 } - //{ Gdk.Key.?, Key.NumPad3 } - //{ Gdk.Key.?, Key.NumPad4 } - //{ Gdk.Key.?, Key.NumPad5 } - //{ Gdk.Key.?, Key.NumPad6 } - //{ Gdk.Key.?, Key.NumPad7 } - //{ Gdk.Key.?, Key.NumPad8 } - //{ Gdk.Key.?, Key.NumPad9 } - { Gdk.Key.multiply, Key.Multiply }, - //{ Gdk.Key.?, Key.Add } - //{ Gdk.Key.?, Key.Separator } - //{ Gdk.Key.?, Key.Subtract } - //{ Gdk.Key.?, Key.Decimal } - //{ Gdk.Key.?, Key.Divide } - { Gdk.Key.F1, Key.F1 }, - { Gdk.Key.F2, Key.F2 }, - { Gdk.Key.F3, Key.F3 }, - { Gdk.Key.F4, Key.F4 }, - { Gdk.Key.F5, Key.F5 }, - { Gdk.Key.F6, Key.F6 }, - { Gdk.Key.F7, Key.F7 }, - { Gdk.Key.F8, Key.F8 }, - { Gdk.Key.F9, Key.F9 }, - { Gdk.Key.F10, Key.F10 }, - { Gdk.Key.F11, Key.F11 }, - { Gdk.Key.F12, Key.F12 }, - { Gdk.Key.L3, Key.F13 }, - { Gdk.Key.F14, Key.F14 }, - { Gdk.Key.L5, Key.F15 }, - { Gdk.Key.F16, Key.F16 }, - { Gdk.Key.F17, Key.F17 }, - { Gdk.Key.L8, Key.F18 }, - { Gdk.Key.L9, Key.F19 }, - { Gdk.Key.L10, Key.F20 }, - { Gdk.Key.R1, Key.F21 }, - { Gdk.Key.R2, Key.F22 }, - { Gdk.Key.F23, Key.F23 }, - { Gdk.Key.R4, Key.F24 }, - //{ Gdk.Key.?, Key.NumLock } - //{ Gdk.Key.?, Key.Scroll } - //{ Gdk.Key.?, Key.LeftShift } - //{ Gdk.Key.?, Key.RightShift } - //{ Gdk.Key.?, Key.LeftCtrl } - //{ Gdk.Key.?, Key.RightCtrl } - //{ Gdk.Key.?, Key.LeftAlt } - //{ Gdk.Key.?, Key.RightAlt } - //{ Gdk.Key.?, Key.BrowserBack } - //{ Gdk.Key.?, Key.BrowserForward } - //{ Gdk.Key.?, Key.BrowserRefresh } - //{ Gdk.Key.?, Key.BrowserStop } - //{ Gdk.Key.?, Key.BrowserSearch } - //{ Gdk.Key.?, Key.BrowserFavorites } - //{ Gdk.Key.?, Key.BrowserHome } - //{ Gdk.Key.?, Key.VolumeMute } - //{ Gdk.Key.?, Key.VolumeDown } - //{ Gdk.Key.?, Key.VolumeUp } - //{ Gdk.Key.?, Key.MediaNextTrack } - //{ Gdk.Key.?, Key.MediaPreviousTrack } - //{ Gdk.Key.?, Key.MediaStop } - //{ Gdk.Key.?, Key.MediaPlayPause } - //{ Gdk.Key.?, Key.LaunchMail } - //{ Gdk.Key.?, Key.SelectMedia } - //{ Gdk.Key.?, Key.LaunchApplication1 } - //{ Gdk.Key.?, Key.LaunchApplication2 } - //{ Gdk.Key.?, Key.OemSemicolon } - //{ Gdk.Key.?, Key.OemPlus } - //{ Gdk.Key.?, Key.OemComma } - //{ Gdk.Key.?, Key.OemMinus } - //{ Gdk.Key.?, Key.OemPeriod } - //{ Gdk.Key.?, Key.Oem2 } - //{ Gdk.Key.?, Key.OemTilde } - //{ Gdk.Key.?, Key.AbntC1 } - //{ Gdk.Key.?, Key.AbntC2 } - //{ Gdk.Key.?, Key.Oem4 } - //{ Gdk.Key.?, Key.OemPipe } - //{ Gdk.Key.?, Key.OemCloseBrackets } - //{ Gdk.Key.?, Key.Oem7 } - //{ Gdk.Key.?, Key.Oem8 } - //{ Gdk.Key.?, Key.Oem102 } - //{ Gdk.Key.?, Key.ImeProcessed } - //{ Gdk.Key.?, Key.System } - //{ Gdk.Key.?, Key.OemAttn } - //{ Gdk.Key.?, Key.OemFinish } - //{ Gdk.Key.?, Key.DbeHiragana } - //{ Gdk.Key.?, Key.OemAuto } - //{ Gdk.Key.?, Key.DbeDbcsChar } - //{ Gdk.Key.?, Key.OemBackTab } - //{ Gdk.Key.?, Key.Attn } - //{ Gdk.Key.?, Key.DbeEnterWordRegisterMode } - //{ Gdk.Key.?, Key.DbeEnterImeConfigureMode } - //{ Gdk.Key.?, Key.EraseEof } - //{ Gdk.Key.?, Key.Play } - //{ Gdk.Key.?, Key.Zoom } - //{ Gdk.Key.?, Key.NoName } - //{ Gdk.Key.?, Key.DbeEnterDialogConversionMode } - //{ Gdk.Key.?, Key.OemClear } - //{ Gdk.Key.?, Key.DeadCharProcessed } - }; - - public new static GtkKeyboardDevice Instance { get; } = new GtkKeyboardDevice(); - - public static Key ConvertKey(Gdk.Key key) - { - Key result; - return KeyDic.TryGetValue(key, out result) ? result : Key.None; - } - } -} \ No newline at end of file diff --git a/src/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs b/src/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs deleted file mode 100644 index 055421a04a..0000000000 --- a/src/Gtk/Perspex.Gtk/Input/GtkMouseDevice.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Input; -namespace Perspex.Gtk -{ - public class GtkMouseDevice : MouseDevice - { - private static readonly GtkMouseDevice s_instance; - - private Point _clientPosition; - - static GtkMouseDevice() - { - s_instance = new GtkMouseDevice(); - } - - private GtkMouseDevice() - { - } - - public static new GtkMouseDevice Instance => s_instance; - - internal void SetClientPosition(Point p) - { - _clientPosition = p; - } - } -} \ No newline at end of file diff --git a/src/Gtk/Perspex.Gtk/MyClass.cs b/src/Gtk/Perspex.Gtk/MyClass.cs deleted file mode 100644 index ef330fa832..0000000000 --- a/src/Gtk/Perspex.Gtk/MyClass.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Perspex.Gtk -{ - public class MyClass - { - public MyClass () - { - } - } -} - diff --git a/src/Gtk/Perspex.Gtk/Perspex.Gtk.csproj b/src/Gtk/Perspex.Gtk/Perspex.Gtk.csproj deleted file mode 100644 index 81cb022a3e..0000000000 --- a/src/Gtk/Perspex.Gtk/Perspex.Gtk.csproj +++ /dev/null @@ -1,100 +0,0 @@ - - - - Debug - AnyCPU - {54F237D5-A70A-4752-9656-0C70B1A7B047} - Library - Perspex.Gtk - Perspex.Gtk - v4.5 - - - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - full - true - bin\Release - prompt - 4 - false - - - - - - - - ..\..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll - - - ..\..\..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll - - - ..\..\..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll - - - - - - - - - - - - - - - - - - - {D211E587-D8BC-45B9-95A4-F297C8FA5200} - Perspex.Animation - - - {B09B78D8-9B26-48B0-9149-D64A2F120F3F} - Perspex.Base - - - {62024B2D-53EB-4638-B26B-85EEAA54866E} - Perspex.Input - - - {EB582467-6ABB-43A1-B052-E981BA910E3A} - Perspex.SceneGraph - - - {42472427-4774-4C81-8AFF-9F27B8E31721} - Perspex.Layout - - - {D2221C82-4A25-4583-9B43-D791E3F6820C} - Perspex.Controls - - - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} - Perspex.Styling - - - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B} - Perspex.Interactivity - - - - - - - - \ No newline at end of file diff --git a/src/Gtk/Perspex.Gtk/PopupImpl.cs b/src/Gtk/Perspex.Gtk/PopupImpl.cs deleted file mode 100644 index 63e34460b4..0000000000 --- a/src/Gtk/Perspex.Gtk/PopupImpl.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Gtk; -using Perspex.Platform; - -namespace Perspex.Gtk -{ - public class PopupImpl : WindowImpl, IPopupImpl - { - public PopupImpl() - : base(WindowType.Popup) - { - } - } -} diff --git a/src/Gtk/Perspex.Gtk/Properties/AssemblyInfo.cs b/src/Gtk/Perspex.Gtk/Properties/AssemblyInfo.cs deleted file mode 100644 index 46f447c301..0000000000 --- a/src/Gtk/Perspex.Gtk/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Reflection; -using System.Runtime.CompilerServices; - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. -[assembly: AssemblyTitle("Perspex.Gtk")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("steven")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". -// The form "{Major}.{Minor}.*" will automatically update the build and revision, -// and "{Major}.{Minor}.{Build}.*" will update just the revision. -[assembly: AssemblyVersion("1.0.*")] diff --git a/src/Gtk/Perspex.Gtk/SystemDialogImpl.cs b/src/Gtk/Perspex.Gtk/SystemDialogImpl.cs deleted file mode 100644 index 9789beb7c7..0000000000 --- a/src/Gtk/Perspex.Gtk/SystemDialogImpl.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Perspex.Controls; -using Perspex.Controls.Platform; -using Perspex.Platform; - -namespace Perspex.Gtk -{ - using global::Gtk; - class SystemDialogImpl : ISystemDialogImpl - { - public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) - { - var tcs = new TaskCompletionSource(); - var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImpl)parent), - dialog is OpenFileDialog - ? FileChooserAction.Open - : FileChooserAction.Save, - "Cancel", ResponseType.Cancel, - "Open", ResponseType.Accept) - { - SelectMultiple = (dialog as OpenFileDialog)?.AllowMultiple ?? false, - }; - foreach (var filter in dialog.Filters) - { - var ffilter = new FileFilter() - { - Name = filter.Name + " (" + string.Join(";", filter.Extensions.Select(e => "*." + e)) + ")" - }; - foreach (var ext in filter.Extensions) - ffilter.AddPattern("*." + ext); - dlg.AddFilter(ffilter); - } - dlg.SetFilename(dialog.InitialFileName); - dlg.Modal = true; - - dlg.Response += (_, args) => - { - if (args.ResponseId == ResponseType.Accept) - tcs.TrySetResult(dlg.Filenames); - dlg.Hide(); - dlg.Dispose(); - }; - - dlg.Close += delegate - { - tcs.TrySetResult(null); - dlg.Dispose(); - }; - dlg.Show(); - return tcs.Task; - } - - public Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) - { - var tcs = new TaskCompletionSource(); - var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImpl)parent), - FileChooserAction.SelectFolder, - "Cancel", ResponseType.Cancel, - "Select Folder", ResponseType.Accept) - { - - }; - - dlg.Modal = true; - - dlg.Response += (_, args) => - { - if (args.ResponseId == ResponseType.Accept) - tcs.TrySetResult(dlg.Filename); - - dlg.Hide(); - dlg.Dispose(); - }; - - dlg.Close += delegate - { - tcs.TrySetResult(null); - dlg.Dispose(); - }; - dlg.Show(); - return tcs.Task; - } - } -} diff --git a/src/Gtk/Perspex.Gtk/WindowImpl.cs b/src/Gtk/Perspex.Gtk/WindowImpl.cs deleted file mode 100644 index cf0278d133..0000000000 --- a/src/Gtk/Perspex.Gtk/WindowImpl.cs +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Disposables; -using System.Runtime.InteropServices; -using Gdk; -using Perspex.Controls; -using Perspex.Input.Raw; -using Perspex.Platform; -using Perspex.Input; -using Perspex.Threading; -using Action = System.Action; -using WindowEdge = Perspex.Controls.WindowEdge; - -namespace Perspex.Gtk -{ - using Gtk = global::Gtk; - - public class WindowImpl : Gtk.Window, IWindowImpl, IPlatformHandle - { - private IInputRoot _inputRoot; - - private Size _clientSize; - - private Gtk.IMContext _imContext; - - private uint _lastKeyEventTimestamp; - - private static readonly Gdk.Cursor DefaultCursor = new Gdk.Cursor(CursorType.LeftPtr); - - public WindowImpl() - : base(Gtk.WindowType.Toplevel) - { - DefaultSize = new Gdk.Size(900, 480); - Init(); - } - - public WindowImpl(Gtk.WindowType type) - : base(type) - { - Init(); - } - - private void Init() - { - Events = EventMask.PointerMotionMask | - EventMask.ButtonPressMask | - EventMask.ButtonReleaseMask; - _imContext = new Gtk.IMMulticontext(); - _imContext.Commit += ImContext_Commit; - DoubleBuffered = false; - Realize(); - } - - protected override void OnRealized () - { - base.OnRealized (); - _imContext.ClientWindow = this.GdkWindow; - } - - public Size ClientSize - { - get; - set; - } - - public Size MaxClientSize - { - get - { - // TODO: This should take into account things such as taskbar and window border - // thickness etc. - return new Size(Screen.Width, Screen.Height); - } - } - - public Perspex.Controls.WindowState WindowState - { - get - { - switch (GdkWindow.State) - { - case Gdk.WindowState.Iconified: - return Controls.WindowState.Minimized; - case Gdk.WindowState.Maximized: - return Controls.WindowState.Maximized; - default: - return Controls.WindowState.Normal; - } - } - - set - { - switch (value) - { - case Controls.WindowState.Minimized: - GdkWindow.Iconify(); - break; - case Controls.WindowState.Maximized: - GdkWindow.Maximize(); - break; - case Controls.WindowState.Normal: - GdkWindow.Deiconify(); - GdkWindow.Unmaximize(); - break; - } - } - } - - public double Scaling => 1; - - IPlatformHandle ITopLevelImpl.Handle => this; - - [DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] - extern static IntPtr gdk_win32_drawable_get_handle(IntPtr gdkWindow); - - [DllImport("libgtk-x11-2.0.so.0", CallingConvention = CallingConvention.Cdecl)] - extern static IntPtr gdk_x11_drawable_get_xid(IntPtr gdkWindow); - - [DllImport("libgdk-quartz-2.0-0.dylib", CallingConvention = CallingConvention.Cdecl)] - extern static IntPtr gdk_quartz_window_get_nswindow(IntPtr gdkWindow); - - IntPtr _nativeWindow; - - IntPtr GetNativeWindow() - { - IntPtr h = GdkWindow.Handle; - if (_nativeWindow != IntPtr.Zero) - return _nativeWindow; - //Try whatever backend that works - try - { - return _nativeWindow = gdk_quartz_window_get_nswindow(h); - } - catch - { - } - try - { - return _nativeWindow = gdk_x11_drawable_get_xid(h); - } - catch - { - } - return _nativeWindow = gdk_win32_drawable_get_handle(h); - } - - - IntPtr IPlatformHandle.Handle => GetNativeWindow(); - public string HandleDescriptor => "HWND"; - - public Action Activated { get; set; } - - public Action Closed { get; set; } - - public Action Deactivated { get; set; } - - public Action Input { get; set; } - - public Action Paint { get; set; } - - public Action Resized { get; set; } - - public Action ScalingChanged { get; set; } - - public IPopupImpl CreatePopup() - { - return new PopupImpl(); - } - - public void Invalidate(Rect rect) - { - if (base.GdkWindow != null) - base.GdkWindow.InvalidateRect( - new Rectangle((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height), true); - } - - public Point PointToClient(Point point) - { - int x, y; - GdkWindow.GetDeskrelativeOrigin(out x, out y); - - return new Point(point.X - x, point.Y - y); - } - - public Point PointToScreen(Point point) - { - int x, y; - GdkWindow.GetDeskrelativeOrigin(out x, out y); - - return new Point(point.X + x, point.Y + y); - } - - public void SetInputRoot(IInputRoot inputRoot) - { - _inputRoot = inputRoot; - } - - public void SetTitle(string title) - { - Title = title; - } - - - public void SetCursor(IPlatformHandle cursor) - { - GdkWindow.Cursor = cursor != null ? new Gdk.Cursor(cursor.Handle) : DefaultCursor; - } - - public void BeginMoveDrag() - { - int x, y; - ModifierType mod; - Screen.RootWindow.GetPointer(out x, out y, out mod); - BeginMoveDrag(1, x, y, 0); - } - - public void BeginResizeDrag(WindowEdge edge) - { - int x, y; - ModifierType mod; - Screen.RootWindow.GetPointer(out x, out y, out mod); - BeginResizeDrag((Gdk.WindowEdge) (int) edge, 1, x, y, 0); - } - - public Point Position - { - get - { - int x, y; - GetPosition(out x, out y); - return new Point(x, y); - } - set - { - Move((int)value.X, (int)value.Y); - } - } - - public IDisposable ShowDialog() - { - Modal = true; - Show(); - - return Disposable.Empty; - } - - public void SetSystemDecorations(bool enabled) => Decorated = enabled; - - void ITopLevelImpl.Activate() - { - Activate(); - } - - private static InputModifiers GetModifierKeys(ModifierType state) - { - var rv = InputModifiers.None; - if (state.HasFlag(ModifierType.ControlMask)) - rv |= InputModifiers.Control; - if (state.HasFlag(ModifierType.ShiftMask)) - rv |= InputModifiers.Shift; - if (state.HasFlag(ModifierType.Mod1Mask)) - rv |= InputModifiers.Control; - if(state.HasFlag(ModifierType.Button1Mask)) - rv |= InputModifiers.LeftMouseButton; - if (state.HasFlag(ModifierType.Button2Mask)) - rv |= InputModifiers.RightMouseButton; - if (state.HasFlag(ModifierType.Button3Mask)) - rv |= InputModifiers.MiddleMouseButton; - return rv; - } - - protected override bool OnButtonPressEvent(EventButton evnt) - { - - var e = new RawMouseEventArgs( - GtkMouseDevice.Instance, - evnt.Time, - _inputRoot, - evnt.Button == 1 - ? RawMouseEventType.LeftButtonDown - : evnt.Button == 3 ? RawMouseEventType.RightButtonDown : RawMouseEventType.MiddleButtonDown, - new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State)); - Input(e); - return true; - } - - protected override bool OnScrollEvent(EventScroll evnt) - { - double step = 1; - var delta = new Vector(); - if (evnt.Direction == ScrollDirection.Down) - delta = new Vector(0, -step); - else if (evnt.Direction == ScrollDirection.Up) - delta = new Vector(0, step); - else if (evnt.Direction == ScrollDirection.Right) - delta = new Vector(-step, 0); - if (evnt.Direction == ScrollDirection.Left) - delta = new Vector(step, 0); - var e = new RawMouseWheelEventArgs(GtkMouseDevice.Instance, evnt.Time, _inputRoot, new Point(evnt.X, evnt.Y), delta, GetModifierKeys(evnt.State)); - Input(e); - return base.OnScrollEvent(evnt); - } - - protected override bool OnButtonReleaseEvent(EventButton evnt) - { - var e = new RawMouseEventArgs( - GtkMouseDevice.Instance, - evnt.Time, - _inputRoot, - evnt.Button == 1 - ? RawMouseEventType.LeftButtonUp - : evnt.Button == 3 ? RawMouseEventType.RightButtonUp : RawMouseEventType.MiddleButtonUp, - new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State)); - Input(e); - return true; - } - - protected override bool OnConfigureEvent(EventConfigure evnt) - { - var newSize = new Size(evnt.Width, evnt.Height); - - if (newSize != _clientSize) - { - Resized(newSize); - } - - return true; - } - - protected override void OnDestroyed() - { - Closed(); - } - - private bool ProcessKeyEvent(EventKey evnt) - { - _lastKeyEventTimestamp = evnt.Time; - if (_imContext.FilterKeypress(evnt)) - return true; - var e = new RawKeyEventArgs( - GtkKeyboardDevice.Instance, - evnt.Time, - evnt.Type == EventType.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, - GtkKeyboardDevice.ConvertKey(evnt.Key), GetModifierKeys(evnt.State)); - Input(e); - return true; - } - - protected override bool OnKeyPressEvent(EventKey evnt) => ProcessKeyEvent(evnt); - - protected override bool OnKeyReleaseEvent(EventKey evnt) => ProcessKeyEvent(evnt); - - private void ImContext_Commit(object o, Gtk.CommitArgs args) - { - Input(new RawTextInputEventArgs(GtkKeyboardDevice.Instance, _lastKeyEventTimestamp, args.Str)); - } - - protected override bool OnExposeEvent(EventExpose evnt) - { - Paint(evnt.Area.ToPerspex()); - return true; - } - - protected override void OnFocusActivated() - { - Activated(); - } - - protected override bool OnMotionNotifyEvent(EventMotion evnt) - { - var position = new Point(evnt.X, evnt.Y); - - GtkMouseDevice.Instance.SetClientPosition(position); - - var e = new RawMouseEventArgs( - GtkMouseDevice.Instance, - evnt.Time, - _inputRoot, - RawMouseEventType.Move, - position, GetModifierKeys(evnt.State)); - Input(e); - return true; - } - } -} diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj new file mode 100644 index 0000000000..31e3930a49 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -0,0 +1,349 @@ + + + + + 11.0 + Debug + AnyCPU + {3E53A01A-B331-47F3-B828-4A5717E77A24} + Library + Properties + Avalonia.Markup.Xaml + Avalonia.Markup.Xaml + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + CS1591 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Avalonia.Markup.Xaml.XML + CS1591 + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {D211E587-D8BC-45B9-95A4-F297C8FA5200} + Avalonia.Animation + + + {B09B78D8-9B26-48B0-9149-D64A2F120F3F} + Avalonia.Base + + + {D2221C82-4A25-4583-9B43-D791E3F6820C} + Avalonia.Controls + + + {62024B2D-53EB-4638-B26B-85EEAA54866E} + Avalonia.Input + + + {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B} + Avalonia.Interactivity + + + {42472427-4774-4C81-8AFF-9F27B8E31721} + Avalonia.Layout + + + {EB582467-6ABB-43A1-B052-E981BA910E3A} + Avalonia.SceneGraph + + + {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} + Avalonia.Styling + + + {6417e941-21bc-467b-a771-0de389353ce6} + Avalonia.Markup + + + + + ..\..\..\packages\Sprache.2.0.0.50\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid+Xamarin.iOS10+MonoTouch\Sprache.dll + True + + + ..\..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll + + + ..\..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll + + + ..\..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll + + + ..\..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll + + + + + + + + \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs new file mode 100644 index 0000000000..c36a58cf0b --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs @@ -0,0 +1,237 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using OmniXaml; +using Avalonia.Platform; + +namespace Avalonia.Markup.Xaml +{ + using Context; + using Controls; + using Data; + using OmniXaml.ObjectAssembler; + using System.Linq; + /// + /// Loads XAML for a avalonia application. + /// + public class AvaloniaXamlLoader : XmlLoader + { + private static AvaloniaParserFactory s_parserFactory; + private static IInstanceLifeCycleListener s_lifeCycleListener = new AvaloniaLifeCycleListener(); + private static Stack s_uriStack = new Stack(); + + /// + /// Initializes a new instance of the class. + /// + public AvaloniaXamlLoader() + : this(GetParserFactory()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The parser factory to use. + public AvaloniaXamlLoader(IParserFactory xamlParserFactory) + : base(xamlParserFactory) + { + } + + /// + /// Gets the URI of the XAML file currently being loaded. + /// + /// + /// TODO: Making this internal for now as I'm not sure that this is the correct + /// thing to do, but its needd by to get the URL of + /// the currently loading XAML file, as we can't use the OmniXAML parsing context + /// there. Maybe we need a way to inject OmniXAML context into the objects its + /// constructing? + /// + internal static Uri UriContext => s_uriStack.Count > 0 ? s_uriStack.Peek() : null; + + /// + /// Loads the XAML into a Avalonia component. + /// + /// The object to load the XAML into. + public static void Load(object obj) + { + Contract.Requires(obj != null); + + var loader = new AvaloniaXamlLoader(); + loader.Load(obj.GetType(), obj); + } + + /// + /// Loads the XAML for a type. + /// + /// The type. + /// + /// The optional instance into which the XAML should be loaded. + /// + /// The loaded object. + public object Load(Type type, object rootInstance = null) + { + Contract.Requires(type != null); + + // HACK: Currently Visual Studio is forcing us to change the extension of xaml files + // in certain situations, so we try to load .xaml and if that's not found we try .xaml. + // Ideally we'd be able to use .xaml everywhere + var assetLocator = AvaloniaLocator.Current.GetService(); + + if (assetLocator == null) + { + throw new InvalidOperationException( + "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); + } + + foreach (var uri in GetUrisFor(type)) + { + if (assetLocator.Exists(uri)) + { + using (var stream = assetLocator.Open(uri)) + { + var initialize = rootInstance as ISupportInitialize; + initialize?.BeginInit(); + return Load(stream, rootInstance, uri); + } + } + } + + throw new FileNotFoundException("Unable to find view for " + type.FullName); + } + + /// + /// Loads XAML from a URI. + /// + /// The URI of the XAML file. + /// + /// A base URI to use if is relative. + /// + /// + /// The optional instance into which the XAML should be loaded. + /// + /// The loaded object. + public object Load(Uri uri, Uri baseUri = null, object rootInstance = null) + { + Contract.Requires(uri != null); + + var assetLocator = AvaloniaLocator.Current.GetService(); + + if (assetLocator == null) + { + throw new InvalidOperationException( + "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); + } + + using (var stream = assetLocator.Open(uri, baseUri)) + { + return Load(stream, rootInstance, uri); + } + } + + /// + /// Loads XAML from a string. + /// + /// The string containing the XAML. + /// + /// The optional instance into which the XAML should be loaded. + /// + /// The loaded object. + public object Load(string xaml, object rootInstance = null) + { + Contract.Requires(xaml != null); + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml))) + { + return Load(stream, rootInstance); + } + } + + /// + /// Loads XAML from a stream. + /// + /// The stream containing the XAML. + /// + /// The optional instance into which the XAML should be loaded. + /// + /// The URI of the XAML + /// The loaded object. + public object Load(Stream stream, object rootInstance = null, Uri uri = null) + { + try + { + if (uri != null) + { + s_uriStack.Push(uri); + } + + var result = base.Load(stream, new Settings + { + RootInstance = rootInstance, + InstanceLifeCycleListener = s_lifeCycleListener, + ParsingContext = new Dictionary + { + { "Uri", uri } + } + }); + + var topLevel = result as TopLevel; + + if (topLevel != null) + { + DelayedBinding.ApplyBindings(topLevel); + } + + return result; + } + finally + { + if (uri != null) + { + s_uriStack.Pop(); + } + } + } + + private static AvaloniaParserFactory GetParserFactory() + { + if (s_parserFactory == null) + { + s_parserFactory = new AvaloniaParserFactory(); + } + + return s_parserFactory; + } + + /// + /// Gets the URI for a type. + /// + /// The type. + /// The URI. + private static IEnumerable GetUrisFor(Type type) + { + var asm = type.GetTypeInfo().Assembly.GetName().Name; + var typeName = type.FullName; + yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm); + yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm); + + } + } +} + +namespace Avalonia +{ + public static class XamlObjectExtensions + { + public static TObject LoadFromXaml(this TObject obj) + { + Markup.Xaml.AvaloniaXamlLoader.Load(obj); + return obj; + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaAttachableXamlMember.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaAttachableXamlMember.cs new file mode 100644 index 0000000000..be8aa8eb9f --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaAttachableXamlMember.cs @@ -0,0 +1,33 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Markup.Xaml.Data; +using OmniXaml; +using OmniXaml.Typing; +using System.Reflection; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaAttachableXamlMember : AttachableMember + { + public AvaloniaAttachableXamlMember(string name, + XamlType owner, + MethodInfo getter, + MethodInfo setter, + ITypeRepository xamlTypeRepository, + ITypeFeatureProvider featureProvider) + : base(name, getter, setter, xamlTypeRepository, featureProvider) + { + } + + public override string ToString() + { + return "Avalonia Attachable XAML Member " + base.ToString(); + } + + protected override IMemberValuePlugin LookupXamlMemberValueConnector() + { + return new AvaloniaMemberValuePlugin(this); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaContentPropertyProvider.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaContentPropertyProvider.cs new file mode 100644 index 0000000000..164d948e10 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaContentPropertyProvider.cs @@ -0,0 +1,58 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Glass; +using OmniXaml; +using OmniXaml.Builder; +using Avalonia.Metadata; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaContentPropertyProvider : IContentPropertyProvider + { + private readonly Dictionary _values = new Dictionary(); + + public string GetContentPropertyName(Type type) + { + string result; + + if (!_values.TryGetValue(type, out result)) + { + result = LookupContentProperty(type); + _values[type] = result; + } + + return result; + } + + private string LookupContentProperty(Type type) + { + var result = (from member in type.GetRuntimeProperties() + let att = member.GetCustomAttribute() + where att != null + select member).FirstOrDefault(); + + return result?.Name; + } + + void IAdd.Add(ContentPropertyDefinition item) + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaLifeCycleListener.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaLifeCycleListener.cs new file mode 100644 index 0000000000..db5a19b484 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaLifeCycleListener.cs @@ -0,0 +1,31 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using OmniXaml; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaLifeCycleListener : IInstanceLifeCycleListener + { + public void OnAfterProperties(object instance) + { + } + + public void OnAssociatedToParent(object instance) + { + } + + public void OnBegin(object instance) + { + var isi = instance as ISupportInitialize; + isi?.BeginInit(); + } + + public void OnEnd(object instance) + { + var isi = instance as ISupportInitialize; + isi?.EndInit(); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaMemberValuePlugin.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaMemberValuePlugin.cs new file mode 100644 index 0000000000..0494e9d1fe --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaMemberValuePlugin.cs @@ -0,0 +1,25 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using OmniXaml.TypeConversion; +using OmniXaml.Typing; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaMemberValuePlugin : MemberValuePlugin + { + private readonly MutableMember _xamlMember; + + public AvaloniaMemberValuePlugin(MutableMember xamlMember) + : base(xamlMember) + { + _xamlMember = xamlMember; + } + + public override void SetValue(object instance, object value, IValueContext valueContext) + { + PropertyAccessor.SetValue(instance, _xamlMember, value, valueContext); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaNamespaceRegistry.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaNamespaceRegistry.cs new file mode 100644 index 0000000000..b0f6145423 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaNamespaceRegistry.cs @@ -0,0 +1,172 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using OmniXaml.Builder; +using OmniXaml.Typing; +using Avalonia.Controls; +using Avalonia.Markup.Xaml.Templates; +using Avalonia.Media; +using Avalonia.Metadata; +using Avalonia.Platform; +using Avalonia.Styling; +using Glass.Core; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaNamespaceRegistry : INamespaceRegistry + { + private const string ClrNamespace = "clr-namespace:"; + private const string AvaloniaNs = "https://github.com/avaloniaui"; + + private static readonly IEnumerable ForcedAssemblies = new[] + { + typeof(AvaloniaObject).GetTypeInfo().Assembly, + typeof(Control).GetTypeInfo().Assembly, + typeof(Style).GetTypeInfo().Assembly, + typeof(DataTemplate).GetTypeInfo().Assembly, + typeof(SolidColorBrush).GetTypeInfo().Assembly, + typeof(IValueConverter).GetTypeInfo().Assembly, + }; + + private List _clrNamespaces = new List(); + private List _namespaces = new List(); + private Dictionary _prefixes = new Dictionary(); + private List _scanned = new List(); + + public AvaloniaNamespaceRegistry() + { + ScanAssemblies(ForcedAssemblies); + ScanNewAssemblies(); + RegisterPrefix(new PrefixRegistration(string.Empty, AvaloniaNs)); + } + + public IEnumerable RegisteredPrefixes => + _prefixes.Select(x => new PrefixRegistration(x.Key, x.Value)); + + public void AddNamespace(XamlNamespace xamlNamespace) + { + _namespaces.Add(xamlNamespace); + } + + public Namespace GetNamespace(string name) + { + Namespace result; + + if (!IsClrNamespace(name)) + { + ScanNewAssemblies(); + result = _namespaces.FirstOrDefault(x => x.Name == name); + + if (result == null) + { + result = _namespaces.FirstOrDefault(x => x.Name == name); + } + } + else + { + result = _clrNamespaces.FirstOrDefault(x => x.Name == name); + + if (result == null) + { + var clr = CreateClrNamespace(name); + _clrNamespaces.Add(clr); + result = clr; + } + } + + return result; + } + + public Namespace GetNamespaceByPrefix(string prefix) + { + string uri; + + if (_prefixes.TryGetValue(prefix, out uri)) + { + return GetNamespace(uri); + } + + return null; + } + + public void RegisterPrefix(PrefixRegistration prefixRegistration) + { + _prefixes[prefixRegistration.Prefix] = prefixRegistration.Ns; + } + + private static bool IsClrNamespace(string ns) + { + return ns.StartsWith(ClrNamespace); + } + + private static ClrNamespace CreateClrNamespace(string formattedClrString) + { + var startOfNamespace = formattedClrString.IndexOf(":", StringComparison.Ordinal) + 1; + var endOfNamespace = formattedClrString.IndexOf(";", startOfNamespace, StringComparison.Ordinal); + + if (endOfNamespace < 0) + { + endOfNamespace = formattedClrString.Length - startOfNamespace; + } + + var ns = formattedClrString.Substring(startOfNamespace, endOfNamespace - startOfNamespace); + + var remainingPartStart = startOfNamespace + ns.Length + 1; + var remainingPartLenght = formattedClrString.Length - remainingPartStart; + var assemblyPart = formattedClrString.Substring(remainingPartStart, remainingPartLenght); + + var assembly = GetAssembly(assemblyPart); + + return new ClrNamespace(assembly, ns); + } + + private static Assembly GetAssembly(string assemblyPart) + { + var dicotomize = assemblyPart.Dicotomize('='); + return Assembly.Load(new AssemblyName(dicotomize.Item2)); + } + + private void ScanAssemblies(IEnumerable assemblies) + { + foreach (var assembly in assemblies) + { + var namespaces = assembly.GetCustomAttributes() + .Select(x => new { x.XmlNamespace, x.ClrNamespace }) + .GroupBy(x => x.XmlNamespace); + + foreach (var nsa in namespaces) + { + var xamlNamespace = _namespaces.FirstOrDefault(x => x.Name == nsa.Key); + + if (xamlNamespace == null) + { + xamlNamespace = new XamlNamespace(nsa.Key); + _namespaces.Add(xamlNamespace); + } + + var clrNamespaces = nsa.Select(x => x.ClrNamespace); + xamlNamespace.Addresses.Add(new ConfiguredAssemblyWithNamespaces(assembly, clrNamespaces)); + } + + _scanned.Add(assembly); + } + } + + private void ScanNewAssemblies() + { + IEnumerable assemblies = AvaloniaLocator.Current + .GetService() + ?.GetLoadedAssemblies(); + + if (assemblies != null) + { + assemblies = assemblies.Except(_scanned); + ScanAssemblies(assemblies); + } + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaObjectAssembler.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaObjectAssembler.cs new file mode 100644 index 0000000000..f5dd4b5f4b --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaObjectAssembler.cs @@ -0,0 +1,78 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using OmniXaml; +using OmniXaml.ObjectAssembler; +using OmniXaml.ObjectAssembler.Commands; +using OmniXaml.TypeConversion; +using Avalonia.Markup.Xaml.Templates; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaObjectAssembler : IObjectAssembler + { + private readonly TemplateHostingObjectAssembler objectAssembler; + private readonly ObjectAssembler assembler; + + public AvaloniaObjectAssembler( + IRuntimeTypeSource typeSource, + ITopDownValueContext topDownValueContext, + Settings settings = null) + { + var mapping = new DeferredLoaderMapping(); + mapping.Map(x => x.Content, new TemplateLoader()); + mapping.Map(x => x.Content, new TemplateLoader()); + mapping.Map(x => x.Content, new TemplateLoader()); + mapping.Map(x => x.Content, new TemplateLoader()); + mapping.Map(x => x.Content, new TemplateLoader()); + + var parsingDictionary = GetDictionary(settings); + var valueContext = new ValueContext(typeSource, topDownValueContext, parsingDictionary); + assembler = new ObjectAssembler(typeSource, valueContext, settings); + objectAssembler = new TemplateHostingObjectAssembler(assembler, mapping); + } + + + public object Result => objectAssembler.Result; + + public EventHandler XamlSetValueHandler { get; set; } + + public IRuntimeTypeSource TypeSource => assembler.TypeSource; + + public ITopDownValueContext TopDownValueContext => assembler.TopDownValueContext; + + public IInstanceLifeCycleListener LifecycleListener + { + get { throw new NotImplementedException(); } + } + + public void Process(Instruction node) + { + objectAssembler.Process(node); + } + + public void OverrideInstance(object instance) + { + objectAssembler.OverrideInstance(instance); + } + + private static IReadOnlyDictionary GetDictionary(Settings settings) + { + IReadOnlyDictionary dict; + + if (settings != null) + { + dict = settings.ParsingContext; + } + else + { + dict = new ReadOnlyDictionary(new Dictionary()); + } + + return dict; + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaParserFactory.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaParserFactory.cs new file mode 100644 index 0000000000..9e0c21edd4 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaParserFactory.cs @@ -0,0 +1,41 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using OmniXaml; +using OmniXaml.ObjectAssembler; +using OmniXaml.Parsers.Parser; +using OmniXaml.Parsers.ProtoParser; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaParserFactory : IParserFactory + { + private readonly IRuntimeTypeSource runtimeTypeSource; + + public AvaloniaParserFactory() + : this(new TypeFactory()) + { + } + + public AvaloniaParserFactory(ITypeFactory typeFactory) + { + runtimeTypeSource = new AvaloniaRuntimeTypeSource(typeFactory); + } + + public IParser Create(Settings settings) + { + var xamlInstructionParser = new OrderAwareInstructionParser(new InstructionParser(runtimeTypeSource)); + + IObjectAssembler objectAssembler = new AvaloniaObjectAssembler( + runtimeTypeSource, + new TopDownValueContext(), + settings); + var phaseParserKit = new PhaseParserKit( + new ProtoInstructionParser(runtimeTypeSource), + xamlInstructionParser, + objectAssembler); + + return new XmlParser(phaseParserKit); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaRuntimeTypeSource.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaRuntimeTypeSource.cs new file mode 100644 index 0000000000..762ffdb24b --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaRuntimeTypeSource.cs @@ -0,0 +1,91 @@ +namespace Avalonia.Markup.Xaml.Context +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using Collections; + using Controls; + using Controls.Primitives; + using Controls.Templates; + using Converters; + using Data; + using Glass; + using Input; + using Media; + using Media.Imaging; + using Metadata; + using OmniXaml; + using OmniXaml.Builder; + using OmniXaml.TypeConversion; + using OmniXaml.Typing; + using Avalonia.Styling; + using Platform; + using Templates; + + public class AvaloniaRuntimeTypeSource : IRuntimeTypeSource + { + private readonly RuntimeTypeSource inner; + + public AvaloniaRuntimeTypeSource(ITypeFactory typeFactory) + { + var namespaceRegistry = new AvaloniaNamespaceRegistry(); + var featureProvider = new AvaloniaTypeFeatureProvider(); + var typeRepository = new AvaloniaTypeRepository(namespaceRegistry, typeFactory, featureProvider); + + inner = new RuntimeTypeSource(typeRepository, namespaceRegistry); + } + + public Namespace GetNamespace(string name) + { + return inner.GetNamespace(name); + } + + public Namespace GetNamespaceByPrefix(string prefix) + { + return inner.GetNamespaceByPrefix(prefix); + } + + public void RegisterPrefix(PrefixRegistration prefixRegistration) + { + inner.RegisterPrefix(prefixRegistration); + } + + public void AddNamespace(XamlNamespace xamlNamespace) + { + inner.AddNamespace(xamlNamespace); + } + + public IEnumerable RegisteredPrefixes => inner.RegisteredPrefixes; + + public XamlType GetByType(Type type) + { + return inner.GetByType(type); + } + + public XamlType GetByQualifiedName(string qualifiedName) + { + return inner.GetByQualifiedName(qualifiedName); + } + + public XamlType GetByPrefix(string prefix, string typeName) + { + return inner.GetByPrefix(prefix, typeName); + } + + public XamlType GetByFullAddress(XamlTypeName xamlTypeName) + { + return inner.GetByFullAddress(xamlTypeName); + } + + public Member GetMember(PropertyInfo propertyInfo) + { + return inner.GetMember(propertyInfo); + } + + public AttachableMember GetAttachableMember(string name, MethodInfo getter, MethodInfo setter) + { + return inner.GetAttachableMember(name, getter, setter); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeFeatureProvider.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeFeatureProvider.cs new file mode 100644 index 0000000000..a0411b1d84 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeFeatureProvider.cs @@ -0,0 +1,177 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using OmniXaml; +using OmniXaml.Builder; +using OmniXaml.TypeConversion; +using OmniXaml.TypeConversion.BuiltInConverters; +using OmniXaml.Typing; +using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using Avalonia.Input; +using Avalonia.Markup.Xaml.Converters; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Metadata; +using Avalonia.Styling; +using OmniMetadata = OmniXaml.Typing.Metadata; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaTypeFeatureProvider : ITypeFeatureProvider + { + private Dictionary _metadata = + new Dictionary(); + + private Dictionary _typeConverters = + new Dictionary(); + + public IEnumerable TypeConverters => _typeConverters.Values; + + public AvaloniaTypeFeatureProvider() + { + RegisterTypeConverters(); + } + + public string GetContentPropertyName(Type type) + { + return GetMetadata(type)?.ContentProperty; + } + + public OmniMetadata GetMetadata(Type type) + { + OmniMetadata result; + + if (!_metadata.TryGetValue(type, out result)) + { + result = LoadMetadata(type); + _metadata.Add(type, result); + } + + return result; + } + + public ITypeConverter GetTypeConverter(Type type) + { + TypeConverterRegistration result; + _typeConverters.TryGetValue(type, out result); + return result?.TypeConverter; + } + + public void RegisterMetadata(Type type, OmniMetadata metadata) + { + _metadata.Add(type, metadata); + } + + public void RegisterTypeConverter(Type type, ITypeConverter converter) + { + _typeConverters.Add(type, new TypeConverterRegistration(type, converter)); + } + + private static OmniMetadata LoadMetadata(Type type) + { + return new OmniMetadata + { + ContentProperty = GetContentProperty(type), + PropertyDependencies = GetPropertyDependencies(type), + RuntimePropertyName = type.GetRuntimeProperty("Name")?.Name, + }; + } + + private static string GetContentProperty(Type type) + { + while (type != null) + { + var properties = type.GetTypeInfo().DeclaredProperties + .Where(x => x.GetCustomAttribute() != null); + string result = null; + + foreach (var property in properties) + { + if (result != null) + { + throw new Exception($"Content property defined more than once on {type}."); + } + + result = property.Name; + } + + if (result != null) + { + return result; + } + + type = type.GetTypeInfo().BaseType; + } + + return null; + } + + private static DependencyRegistrations GetPropertyDependencies(Type type) + { + var result = new List(); + + while (type != null) + { + var registrations = type.GetTypeInfo().DeclaredProperties + .Select(x => new + { + Property = x.Name, + Attributes = x.GetCustomAttributes(), + }) + .Where(x => x.Attributes.Any()) + .SelectMany(x => x.Attributes.Select(y => new DependencyRegistration(x.Property, y.Name))); + + result.AddRange(registrations); + type = type.GetTypeInfo().BaseType; + } + + return result.Count > 0 ? new DependencyRegistrations(result) : null; + } + + private void RegisterTypeConverters() + { + // HACK: For now these are hard-coded. Hopefully when the .NET Standard Platform + // is available we can use the System.ComponentModel.TypeConverters so don't want to + // spend time for now inventing a mechanism to register type converters if it's all + // going to change. + RegisterTypeConverter(typeof(string), new StringTypeConverter()); + RegisterTypeConverter(typeof(int), new IntTypeConverter()); + RegisterTypeConverter(typeof(long), new IntTypeConverter()); + RegisterTypeConverter(typeof(short), new IntTypeConverter()); + RegisterTypeConverter(typeof(double), new DoubleTypeConverter()); + RegisterTypeConverter(typeof(float), new IntTypeConverter()); + RegisterTypeConverter(typeof(bool), new BooleanConverter()); + RegisterTypeConverter(typeof(Type), new TypeTypeConverter()); + + RegisterTypeConverter(typeof(IBitmap), new BitmapTypeConverter()); + RegisterTypeConverter(typeof(IBrush), new BrushTypeConverter()); + RegisterTypeConverter(typeof(Color), new ColorTypeConverter()); + RegisterTypeConverter(typeof(Classes), new ClassesTypeConverter()); + RegisterTypeConverter(typeof(ColumnDefinitions), new ColumnDefinitionsTypeConverter()); + RegisterTypeConverter(typeof(Geometry), new GeometryTypeConverter()); + RegisterTypeConverter(typeof(GridLength), new GridLengthTypeConverter()); + RegisterTypeConverter(typeof(KeyGesture), new KeyGestureConverter()); + RegisterTypeConverter(typeof(AvaloniaList), new AvaloniaListTypeConverter()); + RegisterTypeConverter(typeof(IMemberSelector), new MemberSelectorTypeConverter()); + RegisterTypeConverter(typeof(Point), new PointTypeConverter()); + RegisterTypeConverter(typeof(IList), new PointsListTypeConverter()); + RegisterTypeConverter(typeof(AvaloniaProperty), new AvaloniaPropertyTypeConverter()); + RegisterTypeConverter(typeof(RelativePoint), new RelativePointTypeConverter()); + RegisterTypeConverter(typeof(RelativeRect), new RelativeRectTypeConverter()); + RegisterTypeConverter(typeof(RowDefinitions), new RowDefinitionsTypeConverter()); + RegisterTypeConverter(typeof(Size), new SizeTypeConverter()); + RegisterTypeConverter(typeof(Selector), new SelectorTypeConverter()); + RegisterTypeConverter(typeof(SolidColorBrush), new BrushTypeConverter()); + RegisterTypeConverter(typeof(Thickness), new ThicknessTypeConverter()); + RegisterTypeConverter(typeof(TimeSpan), new TimeSpanTypeConverter()); + RegisterTypeConverter(typeof(Uri), new UriTypeConverter()); + RegisterTypeConverter(typeof(Cursor), new CursorTypeConverter()); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeRepository.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeRepository.cs new file mode 100644 index 0000000000..e97396e9a5 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaTypeRepository.cs @@ -0,0 +1,28 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using OmniXaml; +using OmniXaml.Typing; +using Glass.Core; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaTypeRepository : TypeRepository + { + private readonly ITypeFactory _typeFactory; + + public AvaloniaTypeRepository(INamespaceRegistry xamlNamespaceRegistry, + ITypeFactory typeFactory, + ITypeFeatureProvider featureProvider) : base(xamlNamespaceRegistry, typeFactory, featureProvider) + { + _typeFactory = typeFactory; + } + + public override XamlType GetByType(Type type) + { + Guard.ThrowIfNull(type, nameof(type)); + return new AvaloniaXamlType(type, this, _typeFactory, FeatureProvider); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaWiringContext.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaWiringContext.cs new file mode 100644 index 0000000000..f70637f9a9 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaWiringContext.cs @@ -0,0 +1,126 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Linq; +using System.Reflection; +using Glass; +using OmniXaml; +using OmniXaml.Builder; +using OmniXaml.TypeConversion; +using OmniXaml.Typing; +using Avalonia.Collections; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Controls.Templates; +using Avalonia.Input; +using Avalonia.Markup.Xaml.Converters; +using Avalonia.Markup.Xaml.Data; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Metadata; +using Avalonia.Platform; +using Avalonia.Styling; +using System.Collections.Generic; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaWiringContext : WiringContext + { + private const string AvaloniaNs = "https://github.com/avaloniaui"; + + public AvaloniaWiringContext(ITypeFactory typeFactory) + : this(typeFactory, new TypeFeatureProvider(GetContentPropertyProvider(), GetConverterProvider())) + { + } + + public AvaloniaWiringContext(ITypeFactory typeFactory, TypeFeatureProvider featureProvider) + : base(CreateTypeContext(typeFactory, featureProvider), featureProvider) + { + } + + private static ITypeContext CreateTypeContext(ITypeFactory typeFactory, TypeFeatureProvider featureProvider) + { + var xamlNamespaceRegistry = CreateXamlNamespaceRegistry(); + var typeRepository = new AvaloniaTypeRepository(xamlNamespaceRegistry, typeFactory, featureProvider); + + typeRepository.RegisterMetadata(new GenericMetadata().WithRuntimeNameProperty(d => d.Name)); + typeRepository.RegisterMetadata(new GenericMetadata().WithMemberDependency(x => x.Value, x => x.Property)); + typeRepository.RegisterMetadata( + new GenericMetadata() + .WithMemberDependency(x => x.SelectedIndex, x => x.Items) + .WithMemberDependency(x => x.SelectedItem, x => x.Items)); + + return new TypeContext(typeRepository, xamlNamespaceRegistry, typeFactory); + } + + private static XamlNamespaceRegistry CreateXamlNamespaceRegistry() + { + var xamlNamespaceRegistry = new XamlNamespaceRegistry(); + + var forcedAssemblies = new[] + { + typeof(Binding), + typeof(Control), + typeof(IValueConverter), + typeof(Style), + }.Select(t => t.GetTypeInfo().Assembly); + + foreach (var nsa in + forcedAssemblies + .Concat(AvaloniaLocator.Current.GetService().GetLoadedAssemblies()) + .Distinct() + .SelectMany(asm + => asm.GetCustomAttributes().Select(attr => new {asm, attr})) + .GroupBy(entry => entry.attr.XmlNamespace)) + { + var def = XamlNamespace.Map(nsa.Key) + .With(nsa.GroupBy(x => x.asm).Select( + a => Route.Assembly(a.Key) + .WithNamespaces(a.Select(entry => entry.attr.ClrNamespace).ToList()) + )); + xamlNamespaceRegistry.AddNamespace(def); + } + xamlNamespaceRegistry.RegisterPrefix(new PrefixRegistration(string.Empty, AvaloniaNs)); + + return xamlNamespaceRegistry; + } + + private static ITypeConverterProvider GetConverterProvider() + { + var typeConverterProvider = new TypeConverterProvider(); + var converters = new[] + { + new TypeConverterRegistration(typeof(IBitmap), new BitmapTypeConverter()), + new TypeConverterRegistration(typeof(Brush), new BrushTypeConverter()), + new TypeConverterRegistration(typeof(Color), new ColorTypeConverter()), + new TypeConverterRegistration(typeof(Classes), new ClassesTypeConverter()), + new TypeConverterRegistration(typeof(ColumnDefinitions), new ColumnDefinitionsTypeConverter()), + new TypeConverterRegistration(typeof(Geometry), new GeometryTypeConverter()), + new TypeConverterRegistration(typeof(GridLength), new GridLengthTypeConverter()), + new TypeConverterRegistration(typeof(KeyGesture), new KeyGestureConverter()), + new TypeConverterRegistration(typeof(AvaloniaList), new AvaloniaListTypeConverter()), + new TypeConverterRegistration(typeof(IMemberSelector), new MemberSelectorTypeConverter()), + new TypeConverterRegistration(typeof(Point), new PointTypeConverter()), + new TypeConverterRegistration(typeof(IList), new PointsListTypeConverter()), + new TypeConverterRegistration(typeof(AvaloniaProperty), new AvaloniaPropertyTypeConverter()), + new TypeConverterRegistration(typeof(RelativePoint), new RelativePointTypeConverter()), + new TypeConverterRegistration(typeof(RelativeRect), new RelativeRectTypeConverter()), + new TypeConverterRegistration(typeof(RowDefinitions), new RowDefinitionsTypeConverter()), + new TypeConverterRegistration(typeof(Selector), new SelectorTypeConverter()), + new TypeConverterRegistration(typeof(Thickness), new ThicknessTypeConverter()), + new TypeConverterRegistration(typeof(TimeSpan), new TimeSpanTypeConverter()), + new TypeConverterRegistration(typeof(Uri), new UriTypeConverter()), + new TypeConverterRegistration(typeof(Cursor), new CursorTypeConverter()) + }; + + typeConverterProvider.AddAll(converters); + return typeConverterProvider; + } + + private static IContentPropertyProvider GetContentPropertyProvider() + { + return new AvaloniaContentPropertyProvider(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaXamlMember.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaXamlMember.cs new file mode 100644 index 0000000000..876ca1f0f0 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaXamlMember.cs @@ -0,0 +1,31 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Markup.Xaml.Data; +using OmniXaml; +using OmniXaml.Typing; +using System; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaXamlMember : Member + { + public AvaloniaXamlMember(string name, + XamlType owner, + ITypeRepository xamlTypeRepository, + ITypeFeatureProvider featureProvider) + : base(name, owner, xamlTypeRepository, featureProvider) + { + } + + protected override IMemberValuePlugin LookupXamlMemberValueConnector() + { + return new AvaloniaMemberValuePlugin(this); + } + + public override string ToString() + { + return "Avalonia XAML Member " + base.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaXamlType.cs b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaXamlType.cs new file mode 100644 index 0000000000..0ec8394bf3 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/AvaloniaXamlType.cs @@ -0,0 +1,61 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reflection; +using OmniXaml; +using OmniXaml.Typing; +using Avalonia.Controls; + +namespace Avalonia.Markup.Xaml.Context +{ + public class AvaloniaXamlType : XamlType + { + public AvaloniaXamlType(Type type, + ITypeRepository typeRepository, + ITypeFactory typeFactory, + ITypeFeatureProvider featureProvider) : base(type, typeRepository, typeFactory, featureProvider) + { + } + + public override OmniXaml.INameScope GetNamescope(object instance) + { + var result = instance as OmniXaml.INameScope; + + if (result == null) + { + var control = instance as Control; + + if (control != null) + { + var avaloniaNs = (instance as Avalonia.Controls.INameScope) ?? NameScope.GetNameScope(control); + + if (avaloniaNs != null) + { + result = new NameScopeWrapper(avaloniaNs); + } + } + } + + return result; + } + + protected override Member LookupMember(string name) + { + return new AvaloniaXamlMember(name, this, TypeRepository, FeatureProvider); + } + + protected override AttachableMember LookupAttachableMember(string name) + { + // OmniXAML seems to require a getter and setter even though we don't use them. + var getter = UnderlyingType.GetTypeInfo().GetDeclaredMethod("Get" + name); + var setter = UnderlyingType.GetTypeInfo().GetDeclaredMethod("Set" + name); + return new AvaloniaAttachableXamlMember(name, this, getter, setter, TypeRepository, FeatureProvider); + } + + public override string ToString() + { + return "Avalonia XAML Type " + base.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/NameScopeWrapper.cs b/src/Markup/Avalonia.Markup.Xaml/Context/NameScopeWrapper.cs new file mode 100644 index 0000000000..e7443c416f --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/NameScopeWrapper.cs @@ -0,0 +1,30 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Markup.Xaml.Context +{ + internal class NameScopeWrapper : OmniXaml.INameScope + { + private readonly Avalonia.Controls.INameScope _inner; + + public NameScopeWrapper(Avalonia.Controls.INameScope inner) + { + _inner = inner; + } + + public object Find(string name) + { + return _inner.Find(name); + } + + public void Register(string name, object scopedElement) + { + _inner.Register(name, scopedElement); + } + + public void Unregister(string name) + { + _inner.Unregister(name); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Context/PropertyAccessor.cs b/src/Markup/Avalonia.Markup.Xaml/Context/PropertyAccessor.cs new file mode 100644 index 0000000000..20d9b07daf --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Context/PropertyAccessor.cs @@ -0,0 +1,167 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using OmniXaml.ObjectAssembler; +using OmniXaml.TypeConversion; +using OmniXaml.Typing; +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Markup.Xaml.Data; +using Avalonia.Styling; + +namespace Avalonia.Markup.Xaml.Context +{ + internal static class PropertyAccessor + { + public static void SetValue( + object instance, + MutableMember member, + object value, + IValueContext context) + { + var avaloniaProperty = FindAvaloniaProperty(instance, member); + + if (value is IBinding) + { + SetBinding(instance, member, avaloniaProperty, context, (IBinding)value); + } + else if (avaloniaProperty != null) + { + ((AvaloniaObject)instance).SetValue(avaloniaProperty, value); + } + else if (instance is Setter && member.Name == "Value") + { + // TODO: Make this more generic somehow. + var setter = (Setter)instance; + var targetType = setter.Property.PropertyType; + var xamlType = member.TypeRepository.GetByType(targetType); + var convertedValue = default(object); + + if (CommonValueConversion.TryConvert(value, xamlType, context, out convertedValue)) + { + SetClrProperty(instance, member, convertedValue); + } + } + else + { + SetClrProperty(instance, member, value); + } + } + + private static AvaloniaProperty FindAvaloniaProperty(object instance, MutableMember member) + { + var registry = AvaloniaPropertyRegistry.Instance; + var attached = member as AvaloniaAttachableXamlMember; + var target = instance as AvaloniaObject; + + if (target == null) + { + return null; + } + + if (attached == null) + { + return registry.FindRegistered(target, member.Name); + } + else + { + var ownerType = attached.DeclaringType.UnderlyingType; + + RuntimeHelpers.RunClassConstructor(ownerType.TypeHandle); + + return registry.GetRegistered(target) + .Where(x => x.OwnerType == ownerType && x.Name == attached.Name) + .FirstOrDefault(); + } + } + + private static void SetBinding( + object instance, + MutableMember member, + AvaloniaProperty property, + IValueContext context, + IBinding binding) + { + if (!(AssignBinding(instance, member, binding) || + ApplyBinding(instance, property, context, binding))) + { + throw new InvalidOperationException( + $"Cannot assign to '{member.Name}' on '{instance.GetType()}"); + } + } + + private static void SetClrProperty(object instance, MutableMember member, object value) + { + if (member.IsAttachable) + { + member.Setter.Invoke(null, new[] { instance, value }); + } + else + { + member.Setter.Invoke(instance, new[] { value }); + } + } + + private static bool AssignBinding(object instance, MutableMember member, IBinding binding) + { + var property = instance.GetType() + .GetRuntimeProperties() + .FirstOrDefault(x => x.Name == member.Name); + + if (property?.GetCustomAttribute() != null) + { + property.SetValue(instance, binding); + return true; + } + + return false; + } + + private static bool ApplyBinding( + object instance, + AvaloniaProperty property, + IValueContext context, + IBinding binding) + { + if (property == null) + { + return false; + } + + var control = instance as IControl; + + if (control != null) + { + DelayedBinding.Add(control, property, binding); + } + else + { + // The target is not a control, so we need to find an anchor that will let us look + // up named controls and style resources. First look for the closest IControl in + // the TopDownValueContext. + object anchor = context.TopDownValueContext.StoredInstances + .Select(x => x.Instance) + .OfType() + .LastOrDefault(); + + // If a control was not found, then try to find the highest-level style as the XAML + // file could be a XAML file containing only styles. + if (anchor == null) + { + anchor = context.TopDownValueContext.StoredInstances + .Select(x => x.Instance) + .OfType() + .FirstOrDefault(); + } + + ((IAvaloniaObject)instance).Bind(property, binding, anchor); + } + + return true; + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaListTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaListTypeConverter.cs new file mode 100644 index 0000000000..f865767e6f --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaListTypeConverter.cs @@ -0,0 +1,52 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Linq; +using OmniXaml.TypeConversion; +using Avalonia.Collections; +using Avalonia.Utilities; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class AvaloniaListTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + var result = new AvaloniaList(); + var values = ((string)value).Split(','); + + foreach (var s in values) + { + object v; + + if (TypeUtilities.TryConvert(typeof(T), s, culture, out v)) + { + result.Add((T)v); + } + else + { + throw new InvalidCastException($"Could not convert '{s}' to {typeof(T)}."); + } + } + + return result; + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs new file mode 100644 index 0000000000..026217eacb --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/AvaloniaPropertyTypeConverter.cs @@ -0,0 +1,96 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Linq; +using OmniXaml; +using OmniXaml.TypeConversion; +using Avalonia.Styling; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class AvaloniaPropertyTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + var s = (string)value; + + string typeName; + string propertyName; + Type type; + + ParseProperty(s, out typeName, out propertyName); + + if (typeName == null) + { + var styleType = context.TypeRepository.GetByType(typeof(Style)); + var style = (Style)context.TopDownValueContext.GetLastInstance(styleType); + type = style.Selector?.TargetType; + + if (type == null) + { + throw new ParseException( + "Could not determine the target type. Please fully qualify the property name."); + } + } + else + { + type = context.TypeRepository.GetByQualifiedName(typeName)?.UnderlyingType; + + if (type == null) + { + throw new ParseException($"Could not find type '{typeName}'."); + } + } + + // First look for non-attached property on the type and then look for an attached property. + var property = AvaloniaPropertyRegistry.Instance.FindRegistered(type, s) ?? + AvaloniaPropertyRegistry.Instance.GetAttached(type) + .FirstOrDefault(x => x.Name == propertyName); + + if (property == null) + { + throw new ParseException( + $"Could not find AvaloniaProperty '{type.Name}.{propertyName}'."); + } + + return property; + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + + private void ParseProperty(string s, out string typeName, out string propertyName) + { + var split = s.Split('.'); + + if (split.Length == 1) + { + typeName = null; + propertyName = split[0]; + } + else if (split.Length == 2) + { + typeName = split[0]; + propertyName = split[1]; + } + else + { + throw new ParseException($"Invalid property name: '{s}'."); + } + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs new file mode 100644 index 0000000000..583874bdd0 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/BitmapTypeConverter.cs @@ -0,0 +1,52 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Media.Imaging; +using Avalonia.Platform; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class BitmapTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + var uri = new Uri((string)value, UriKind.RelativeOrAbsolute); + var baseUri = GetBaseUri(context); + var scheme = uri.IsAbsoluteUri ? uri.Scheme : "file"; + + switch (scheme) + { + case "file": + return new Bitmap((string)value); + default: + var assets = AvaloniaLocator.Current.GetService(); + return new Bitmap(assets.Open(uri, baseUri)); + } + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + + private Uri GetBaseUri(IValueContext context) + { + object result; + context.ParsingDictionary.TryGetValue("Uri", out result); + return result as Uri; + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/BrushTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/BrushTypeConverter.cs new file mode 100644 index 0000000000..45f835914f --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/BrushTypeConverter.cs @@ -0,0 +1,33 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Media; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class BrushTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return Brush.Parse((string)value); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/ClassesTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/ClassesTypeConverter.cs new file mode 100644 index 0000000000..2168702940 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/ClassesTypeConverter.cs @@ -0,0 +1,34 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Controls; +using Avalonia.Styling; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class ClassesTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return new Classes(((string)value).Split(' ')); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/ColorTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/ColorTypeConverter.cs new file mode 100644 index 0000000000..d39eb96ec1 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/ColorTypeConverter.cs @@ -0,0 +1,33 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Media; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class ColorTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return Color.Parse((string)value); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs new file mode 100644 index 0000000000..e23c09de55 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs @@ -0,0 +1,33 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Controls; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class ColumnDefinitionsTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return new ColumnDefinitions((string)value); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/CursorTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/CursorTypeConverter.cs new file mode 100644 index 0000000000..4780a8e23a --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/CursorTypeConverter.cs @@ -0,0 +1,36 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Input; +using Avalonia.Media.Imaging; +using Avalonia.Platform; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class CursorTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + var cursor = (StandardCursorType)Enum.Parse(typeof (StandardCursorType), ((string) value).Trim(), true); + return new Cursor(cursor); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/GeometryTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/GeometryTypeConverter.cs new file mode 100644 index 0000000000..4bb8daacab --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/GeometryTypeConverter.cs @@ -0,0 +1,30 @@ +namespace Avalonia.Markup.Xaml.Converters +{ + using System; + using System.Globalization; + using Media; + using OmniXaml.TypeConversion; + + public class GeometryTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return StreamGeometry.Parse((string)value); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/GridLengthTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/GridLengthTypeConverter.cs new file mode 100644 index 0000000000..d17e4a0de0 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/GridLengthTypeConverter.cs @@ -0,0 +1,33 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Controls; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class GridLengthTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return GridLength.Parse((string)value, culture); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/KeyGestureConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/KeyGestureConverter.cs new file mode 100644 index 0000000000..7454873a7d --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/KeyGestureConverter.cs @@ -0,0 +1,30 @@ +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Input; + +namespace Avalonia.Markup.Xaml.Converters +{ + class KeyGestureConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return KeyGesture.Parse((string)value); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs new file mode 100644 index 0000000000..01ddd058fb --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs @@ -0,0 +1,36 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Markup.Xaml.Templates; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class MemberSelectorTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return new MemberSelector + { + MemberName = (string)value, + }; + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/PointTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/PointTypeConverter.cs new file mode 100644 index 0000000000..cec52e1efc --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/PointTypeConverter.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class PointTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return Point.Parse((string)value, culture); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/PointsListTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/PointsListTypeConverter.cs new file mode 100644 index 0000000000..371ab02b69 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/PointsListTypeConverter.cs @@ -0,0 +1,40 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using OmniXaml.TypeConversion; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class PointsListTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + string strValue = (string)value; + string[] pointStrs = strValue.Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + var result = new List(pointStrs.Length); + foreach (var pointStr in pointStrs) + { + result.Add(Point.Parse(pointStr, culture)); + } + return result; + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/RelativePointTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/RelativePointTypeConverter.cs new file mode 100644 index 0000000000..a5576bf8c4 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/RelativePointTypeConverter.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class RelativePointTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return RelativePoint.Parse((string)value, culture); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/RelativeRectTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/RelativeRectTypeConverter.cs new file mode 100644 index 0000000000..fcad3ec12b --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/RelativeRectTypeConverter.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class RelativeRectTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return RelativeRect.Parse((string)value, culture); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs new file mode 100644 index 0000000000..a8551797e7 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs @@ -0,0 +1,33 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Controls; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class RowDefinitionsTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return new RowDefinitions((string)value); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs new file mode 100644 index 0000000000..0970f42724 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/SelectorTypeConverter.cs @@ -0,0 +1,34 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Markup.Xaml.Parsers; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class SelectorTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + var parser = new SelectorParser((t, ns) => context.TypeRepository.GetByPrefix(ns ?? "", t).UnderlyingType); + return parser.Parse((string)value); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/SizeTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/SizeTypeConverter.cs new file mode 100644 index 0000000000..668d4945a8 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/SizeTypeConverter.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class SizeTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return Size.Parse((string)value, culture); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/ThicknessTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/ThicknessTypeConverter.cs new file mode 100644 index 0000000000..f8a976036e --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/ThicknessTypeConverter.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class ThicknessTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return Thickness.Parse((string)value, culture); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/TimeSpanTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/TimeSpanTypeConverter.cs new file mode 100644 index 0000000000..3d1ffb23cd --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/TimeSpanTypeConverter.cs @@ -0,0 +1,41 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; +using Avalonia.Media; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class TimeSpanTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + var valueStr = (string)value; + if (!valueStr.Contains(":")) + { + // shorthand seconds format (ie. "0.25") + var secs = double.Parse(valueStr, CultureInfo.InvariantCulture); + return TimeSpan.FromSeconds(secs); + } + + return TimeSpan.Parse(valueStr); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Converters/UriTypeConverter.cs b/src/Markup/Avalonia.Markup.Xaml/Converters/UriTypeConverter.cs new file mode 100644 index 0000000000..64ae367397 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Converters/UriTypeConverter.cs @@ -0,0 +1,32 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using OmniXaml.TypeConversion; + +namespace Avalonia.Markup.Xaml.Converters +{ + public class UriTypeConverter : ITypeConverter + { + public bool CanConvertFrom(IValueContext context, Type sourceType) + { + return sourceType == typeof(string); + } + + public bool CanConvertTo(IValueContext context, Type destinationType) + { + return false; + } + + public object ConvertFrom(IValueContext context, CultureInfo culture, object value) + { + return new Uri((string)value); + } + + public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs new file mode 100644 index 0000000000..34bd577900 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs @@ -0,0 +1,266 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Markup.Data; + +namespace Avalonia.Markup.Xaml.Data +{ + /// + /// A XAML binding. + /// + public class Binding : IBinding + { + /// + /// Initializes a new instance of the class. + /// + public Binding() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The binding path. + public Binding(string path) + { + Path = path; + } + + /// + /// Gets or sets the to use. + /// + public IValueConverter Converter { get; set; } + + /// + /// Gets or sets a parameter to pass to . + /// + public object ConverterParameter { get; set; } + + /// + /// Gets or sets the name of the element to use as the binding source. + /// + public string ElementName { get; set; } + + /// + /// Gets or sets the value to use when the binding is unable to produce a value. + /// + public object FallbackValue { get; set; } + + /// + /// Gets or sets the binding mode. + /// + public BindingMode Mode { get; set; } + + /// + /// Gets or sets the binding path. + /// + public string Path { get; set; } + + /// + /// Gets or sets the binding priority. + /// + public BindingPriority Priority { get; set; } + + /// + /// Gets or sets the relative source for the binding. + /// + public RelativeSource RelativeSource { get; set; } + + /// + /// Gets or sets the source for the binding. + /// + public object Source { get; set; } + + /// + /// Gets or sets the validation methods for the binding to use. + /// + public ValidationMethods ValidationMethods { get; set; } + + /// + public InstancedBinding Initiate( + IAvaloniaObject target, + AvaloniaProperty targetProperty, + object anchor = null) + { + Contract.Requires(target != null); + + var pathInfo = ParsePath(Path); + ValidateState(pathInfo); + + ExpressionObserver observer; + + if (pathInfo.ElementName != null || ElementName != null) + { + observer = CreateElementObserver( + (target as IControl) ?? (anchor as IControl), + pathInfo.ElementName ?? ElementName, + pathInfo.Path); + } + else if (Source != null) + { + observer = CreateSourceObserver(Source, pathInfo.Path); + } + else if (RelativeSource == null || RelativeSource.Mode == RelativeSourceMode.DataContext) + { + observer = CreateDataContexObserver( + target, + pathInfo.Path, + targetProperty == Control.DataContextProperty, + anchor); + } + else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent) + { + observer = CreateTemplatedParentObserver(target, pathInfo.Path); + } + else + { + throw new NotSupportedException(); + } + + var subject = new ExpressionSubject( + observer, + targetProperty?.PropertyType ?? typeof(object), + Converter ?? DefaultValueConverter.Instance, + ConverterParameter, + FallbackValue, + Priority); + + return new InstancedBinding(subject, Mode, Priority); + } + + private static PathInfo ParsePath(string path) + { + var result = new PathInfo(); + + if (string.IsNullOrWhiteSpace(path) || path == ".") + { + result.Path = string.Empty; + } + else if (path.StartsWith("#")) + { + var dot = path.IndexOf('.'); + + if (dot != -1) + { + result.Path = path.Substring(dot + 1); + result.ElementName = path.Substring(1, dot - 1); + } + else + { + result.Path = string.Empty; + result.ElementName = path.Substring(1); + } + } + else + { + result.Path = path; + } + + return result; + } + + private void ValidateState(PathInfo pathInfo) + { + if (pathInfo.ElementName != null && ElementName != null) + { + throw new InvalidOperationException( + "ElementName property cannot be set when an #elementName path is provided."); + } + + if ((pathInfo.ElementName != null || ElementName != null) && + RelativeSource != null) + { + throw new InvalidOperationException( + "ElementName property cannot be set with a RelativeSource."); + } + } + + private ExpressionObserver CreateDataContexObserver( + IAvaloniaObject target, + string path, + bool targetIsDataContext, + object anchor) + { + Contract.Requires(target != null); + + if (!(target is IControl)) + { + target = anchor as IControl; + + if (target == null) + { + throw new InvalidOperationException("Cannot find a DataContext to bind to."); + } + } + + if (!targetIsDataContext) + { + var update = target.GetObservable(Control.DataContextProperty) + .Skip(1) + .Select(_ => Unit.Default); + var result = new ExpressionObserver( + () => target.GetValue(Control.DataContextProperty), + path, + update, ValidationMethods); + + return result; + } + else + { + return new ExpressionObserver( + target.GetObservable(Visual.VisualParentProperty) + .OfType() + .Select(x => x.GetObservable(Control.DataContextProperty)) + .Switch(), + path, ValidationMethods); + } + } + + private ExpressionObserver CreateElementObserver(IControl target, string elementName, string path) + { + Contract.Requires(target != null); + + var result = new ExpressionObserver( + ControlLocator.Track(target, elementName), + path, ValidationMethods); + return result; + } + + private ExpressionObserver CreateSourceObserver(object source, string path) + { + Contract.Requires(source != null); + + return new ExpressionObserver(source, path, ValidationMethods); + } + + private ExpressionObserver CreateTemplatedParentObserver( + IAvaloniaObject target, + string path) + { + Contract.Requires(target != null); + + var update = target.GetObservable(Control.TemplatedParentProperty) + .Skip(1) + .Select(_ => Unit.Default); + + var result = new ExpressionObserver( + () => target.GetValue(Control.TemplatedParentProperty), + path, + update); + + return result; + } + + private class PathInfo + { + public string Path { get; set; } + public string ElementName { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/DelayedBinding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/DelayedBinding.cs new file mode 100644 index 0000000000..ea79c7429f --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Data/DelayedBinding.cs @@ -0,0 +1,95 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Avalonia.Controls; +using Avalonia.Data; + +namespace Avalonia.Markup.Xaml.Data +{ + /// + /// Provides delayed bindings for controls. + /// + /// + /// The XAML engine applies its bindings in a delayed manner where bindings are only applied + /// when a control has finished initializing. This was done because applying bindings as soon + /// as controls are created means that long-form bindings (i.e. bindings that don't use the + /// `{Binding}` markup extension) don't work as the binding is applied to the property before + /// the binding properties are set, and looking at WPF it uses a similar mechanism for bindings + /// that come from XAML. + /// + public static class DelayedBinding + { + private static ConditionalWeakTable> _entries = + new ConditionalWeakTable>(); + + /// + /// Adds a delayed binding to a control. + /// + /// The control. + /// The property on the control to bind to. + /// The binding. + public static void Add(IControl target, AvaloniaProperty property, IBinding binding) + { + if (target.IsInitialized) + { + target.Bind(property, binding); + } + else + { + List bindings; + + if (!_entries.TryGetValue(target, out bindings)) + { + bindings = new List(); + _entries.Add(target, bindings); + + // TODO: Make this a weak event listener. + target.Initialized += ApplyBindings; + } + + bindings.Add(new Entry(binding, property)); + } + } + + /// + /// Applies any delayed bindings to a control. + /// + /// The control. + public static void ApplyBindings(IControl control) + { + List bindings; + + if (_entries.TryGetValue(control, out bindings)) + { + foreach (var binding in bindings) + { + control.Bind(binding.Property, binding.Binding); + } + + _entries.Remove(control); + } + } + + private static void ApplyBindings(object sender, EventArgs e) + { + var target = (IControl)sender; + ApplyBindings(target); + target.Initialized -= ApplyBindings; + } + + private class Entry + { + public Entry(IBinding binding, AvaloniaProperty property) + { + Binding = binding; + Property = property; + } + + public IBinding Binding { get; } + public AvaloniaProperty Property { get; } + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs new file mode 100644 index 0000000000..91a502a44f --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs @@ -0,0 +1,114 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Metadata; + +namespace Avalonia.Markup.Xaml.Data +{ + /// + /// A XAML binding that calculates an aggregate value from multiple child . + /// + public class MultiBinding : IBinding + { + /// + /// Gets the collection of child bindings. + /// + [Content] + public IList Bindings { get; set; } = new List(); + + /// + /// Gets or sets the to use. + /// + public IMultiValueConverter Converter { get; set; } + + /// + /// Gets or sets the value to use when the binding is unable to produce a value. + /// + public object FallbackValue { get; set; } + + /// + /// Gets or sets the binding mode. + /// + public BindingMode Mode { get; set; } = BindingMode.OneWay; + + /// + /// Gets or sets the binding priority. + /// + public BindingPriority Priority { get; set; } + + /// + /// Gets or sets the relative source for the binding. + /// + public RelativeSource RelativeSource { get; set; } + + /// + public InstancedBinding Initiate( + IAvaloniaObject target, + AvaloniaProperty targetProperty, + object anchor = null) + { + if (Converter == null) + { + throw new NotSupportedException("MultiBinding without Converter not currently supported."); + } + + var targetType = targetProperty?.PropertyType ?? typeof(object); + var result = new BehaviorSubject(AvaloniaProperty.UnsetValue); + var children = Bindings.Select(x => x.Initiate(target, null)); + var input = children.Select(x => x.Subject).CombineLatest().Select(x => ConvertValue(x, targetType)); + input.Subscribe(result); + return new InstancedBinding(result, Mode, Priority); + } + + /// + /// Applies a binding subject to a property on an instance. + /// + /// The target instance. + /// The target property. + /// The binding subject. + internal void Bind(IAvaloniaObject target, AvaloniaProperty property, ISubject subject) + { + var mode = Mode == BindingMode.Default ? + property.GetMetadata(target.GetType()).DefaultBindingMode : Mode; + + switch (mode) + { + case BindingMode.Default: + case BindingMode.OneWay: + target.Bind(property, subject, Priority); + break; + case BindingMode.TwoWay: + throw new NotSupportedException("TwoWay MultiBinding not currently supported."); + case BindingMode.OneTime: + target.GetObservable(Control.DataContextProperty).Subscribe(dataContext => + { + subject.Take(1).Subscribe(x => target.SetValue(property, x, Priority)); + }); + break; + case BindingMode.OneWayToSource: + target.GetObservable(property).Subscribe(subject); + break; + } + } + + private object ConvertValue(IList values, Type targetType) + { + var converted = Converter.Convert(values, targetType, null, CultureInfo.CurrentUICulture); + + if (converted == AvaloniaProperty.UnsetValue && FallbackValue != null) + { + converted = FallbackValue; + } + + return converted; + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/RelativeSource.cs b/src/Markup/Avalonia.Markup.Xaml/Data/RelativeSource.cs new file mode 100644 index 0000000000..6771aaf644 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Data/RelativeSource.cs @@ -0,0 +1,25 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Markup.Xaml.Data +{ + public enum RelativeSourceMode + { + DataContext, + TemplatedParent, + } + + public class RelativeSource + { + public RelativeSource() + { + } + + public RelativeSource(RelativeSourceMode mode) + { + Mode = mode; + } + + public RelativeSourceMode Mode { get; set; } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/SourceBindingEndpoint.cs b/src/Markup/Avalonia.Markup.Xaml/Data/SourceBindingEndpoint.cs new file mode 100644 index 0000000000..95cd6d4ab7 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Data/SourceBindingEndpoint.cs @@ -0,0 +1,27 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.ComponentModel; + +namespace Avalonia.Markup.Xaml.Data +{ + public class SourceBindingEndpoint + { + public Type PropertyType { get; } + + public INotifyPropertyChanged Source { get; } + + public dynamic PropertyGetter { get; } + + public Delegate PropertySetter { get; } + + public SourceBindingEndpoint(INotifyPropertyChanged source, Type propertyType, dynamic propertyGetter, Delegate propertySetter) + { + Source = source; + PropertyType = propertyType; + PropertyGetter = propertyGetter; + PropertySetter = propertySetter; + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs new file mode 100644 index 0000000000..442f9199e8 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs @@ -0,0 +1,69 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Styling; + +namespace Avalonia.Markup.Xaml.Data +{ + public class StyleResourceBinding : IBinding + { + /// + /// Initializes a new instance of the class. + /// + /// The resource name. + public StyleResourceBinding(string name) + { + Name = name; + } + + /// + public BindingMode Mode => BindingMode.OneTime; + + /// + /// Gets the resource name. + /// + public string Name { get; } + + /// + public BindingPriority Priority => BindingPriority.LocalValue; + + /// + public InstancedBinding Initiate( + IAvaloniaObject target, + AvaloniaProperty targetProperty, + object anchor = null) + { + if (Name == "Red") + { + } + + var host = (target as IControl) ?? (anchor as IControl); + var style = anchor as IStyle; + var resource = AvaloniaProperty.UnsetValue; + + if (host != null) + { + resource = host.FindStyleResource(Name); + } + else if (style != null) + { + resource = style.FindResource(Name); + } + + if (resource != AvaloniaProperty.UnsetValue) + { + return new InstancedBinding(resource, Priority); + } + else + { + return null; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/TargetBindingEndpoint.cs b/src/Markup/Avalonia.Markup.Xaml/Data/TargetBindingEndpoint.cs new file mode 100644 index 0000000000..d480ab2291 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Data/TargetBindingEndpoint.cs @@ -0,0 +1,18 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Markup.Xaml.Data +{ + public class TargetBindingEndpoint + { + public AvaloniaObject Object { get; } + + public AvaloniaProperty Property { get; } + + public TargetBindingEndpoint(AvaloniaObject obj, AvaloniaProperty property) + { + Object = obj; + Property = property; + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs new file mode 100644 index 0000000000..e93fc1991c --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs @@ -0,0 +1,46 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using OmniXaml; +using Avalonia.Data; +using Avalonia.Markup.Xaml.Data; + +namespace Avalonia.Markup.Xaml.MarkupExtensions +{ + public class BindingExtension : MarkupExtension + { + public BindingExtension() + { + } + + public BindingExtension(string path) + { + Path = path; + } + + public override object ProvideValue(MarkupExtensionContext extensionContext) + { + return new Binding + { + Converter = Converter, + ConverterParameter = ConverterParameter, + ElementName = ElementName, + FallbackValue = FallbackValue, + Mode = Mode, + Path = Path, + Priority = Priority, + ValidationMethods = ValidationMethods + }; + } + + public IValueConverter Converter { get; set; } + public object ConverterParameter { get; set; } + public string ElementName { get; set; } + public object FallbackValue { get; set; } + public BindingMode Mode { get; set; } + public string Path { get; set; } + public BindingPriority Priority { get; set; } = BindingPriority.LocalValue; + public object Source { get; set; } + public ValidationMethods ValidationMethods { get; set; } = ValidationMethods.None; + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs new file mode 100644 index 0000000000..1120494dfa --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs @@ -0,0 +1,30 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using OmniXaml; +using Avalonia.Markup.Xaml.Data; + +namespace Avalonia.Markup.Xaml.MarkupExtensions +{ + public class RelativeSourceExtension : MarkupExtension + { + public RelativeSourceExtension() + { + } + + public RelativeSourceExtension(RelativeSourceMode mode) + { + Mode = mode; + } + + public override object ProvideValue(MarkupExtensionContext extensionContext) + { + return new RelativeSource + { + Mode = Mode, + }; + } + + public RelativeSourceMode Mode { get; set; } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticExtension.cs new file mode 100644 index 0000000000..051862a167 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticExtension.cs @@ -0,0 +1,86 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Linq; +using System.Reflection; +using OmniXaml; +using Glass.Core; + +namespace Avalonia.Markup.Xaml.MarkupExtensions +{ + public class StaticExtension : MarkupExtension + { + public StaticExtension() + { + } + + public StaticExtension(string identifier) + { + Identifier = identifier; + } + + public string Identifier { get; set; } + + public override object ProvideValue(MarkupExtensionContext markupExtensionContext) + { + var typeRepository = markupExtensionContext.ValueContext.TypeRepository; + var typeAndMember = GetTypeAndMember(Identifier); + var prefixAndType = GetPrefixAndType(typeAndMember.Item1); + var xamlType = typeRepository.GetByPrefix(prefixAndType.Item1, prefixAndType.Item2); + return GetValue(xamlType.UnderlyingType, typeAndMember.Item2); + } + + private static Tuple GetTypeAndMember(string s) + { + var parts = s.Split('.'); + + if (parts.Length != 2) + { + throw new ArgumentException("Static member must be in the form Type.Member."); + } + + return Tuple.Create(parts[0], parts[1]); + } + + private static Tuple GetPrefixAndType(string s) + { + if (s.Contains(":")) + { + return s.Dicotomize(':'); + } + else + { + return new Tuple(string.Empty, s); + } + } + + private object GetValue(Type type, string name) + { + var t = type; + + while (t != null) + { + var result = t.GetTypeInfo().DeclaredMembers.FirstOrDefault(x => x.Name == name); + + if (result is PropertyInfo) + { + var property = ((PropertyInfo)result); + + if (property.GetMethod.IsStatic) + { + return ((PropertyInfo)result).GetValue(null); + } + } + else if (result is FieldInfo) + { + return ((FieldInfo)result).GetValue(null); + } + + t = t.GetTypeInfo().BaseType; + } + + throw new ArgumentException($"Static member '{type}.{name}' not found."); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs new file mode 100644 index 0000000000..9b1c520bf0 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs @@ -0,0 +1,27 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Linq; +using OmniXaml; +using Avalonia.LogicalTree; +using Avalonia.Markup.Xaml.Data; +using Avalonia.Styling; + +namespace Avalonia.Markup.Xaml.MarkupExtensions +{ + public class StyleResourceExtension : MarkupExtension + { + public StyleResourceExtension(string name) + { + Name = name; + } + + public override object ProvideValue(MarkupExtensionContext extensionContext) + { + return new StyleResourceBinding(this.Name); + } + + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs new file mode 100644 index 0000000000..3c4faac3a8 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs @@ -0,0 +1,41 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using OmniXaml; +using Avalonia.Data; +using Avalonia.Markup.Xaml.Data; + +namespace Avalonia.Markup.Xaml.MarkupExtensions +{ + public class TemplateBindingExtension : MarkupExtension + { + public TemplateBindingExtension() + { + } + + public TemplateBindingExtension(string path) + { + Path = path; + } + + public override object ProvideValue(MarkupExtensionContext extensionContext) + { + return new Binding + { + Converter = Converter, + ElementName = ElementName, + Mode = Mode, + RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent), + Path = Path, + Priority = Priority, + }; + } + + public IValueConverter Converter { get; set; } + public string ElementName { get; set; } + public object FallbackValue { get; set; } + public BindingMode Mode { get; set; } + public string Path { get; set; } + public BindingPriority Priority { get; set; } = BindingPriority.TemplatedParent; + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs new file mode 100644 index 0000000000..3a6f946f3a --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TypeExtension.cs @@ -0,0 +1,49 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using OmniXaml; +using OmniXaml.Attributes; +using OmniXaml.Typing; +using Glass.Core; + +namespace Avalonia.Markup.Xaml.MarkupExtensions +{ + [ContentProperty("TargetType")] + public class TypeExtension : MarkupExtension + { + public Type Type { get; set; } + + public TypeExtension() + { + } + + public TypeExtension(Type type) + { + Type = type; + } + + public string TypeName { get; set; } + + private Type ResolveFromString(string type, ITypeRepository typeRepository) + { + Guard.ThrowIfNull(type, nameof(type)); + + var split = type.Split(':'); + var prefix = split.Length == 1 ? split[0] : null; + var typeName = split.Length == 1 ? split[1] : split[0]; + var xamlType = typeRepository.GetByPrefix(prefix, typeName); + return xamlType.UnderlyingType; + } + + public override object ProvideValue(MarkupExtensionContext markupExtensionContext) + { + if (Type != null) + { + return Type; + } + + return ResolveFromString(TypeName, markupExtensionContext.ValueContext.TypeRepository); + } + } +} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/OmniXAML b/src/Markup/Avalonia.Markup.Xaml/OmniXAML similarity index 100% rename from src/Markup/Perspex.Markup.Xaml/OmniXAML rename to src/Markup/Avalonia.Markup.Xaml/OmniXAML diff --git a/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorGrammar.cs b/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorGrammar.cs new file mode 100644 index 0000000000..d11df1a9e9 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorGrammar.cs @@ -0,0 +1,210 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Collections.Generic; +using System.Globalization; +using Sprache; + +// Don't need to override GetHashCode as the ISyntax objects will not be stored in a hash; the +// only reason they have overridden Equals methods is for unit testing. +#pragma warning disable 659 + +namespace Avalonia.Markup.Xaml.Parsers +{ + internal class SelectorGrammar + { + public static readonly Parser CombiningCharacter = Parse.Char( + c => + { + var cat = CharUnicodeInfo.GetUnicodeCategory(c); + return cat == UnicodeCategory.NonSpacingMark || + cat == UnicodeCategory.SpacingCombiningMark; + }, + "Connecting Character"); + + public static readonly Parser ConnectingCharacter = Parse.Char( + c => CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.ConnectorPunctuation, + "Connecting Character"); + + public static readonly Parser FormattingCharacter = Parse.Char( + c => CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.Format, + "Connecting Character"); + + public static readonly Parser IdentifierStart = Parse.Letter.Or(Parse.Char('_')); + + public static readonly Parser IdentifierChar = Parse + .LetterOrDigit + .Or(ConnectingCharacter) + .Or(CombiningCharacter) + .Or(FormattingCharacter); + + public static readonly Parser Identifier = + from start in IdentifierStart.Once().Text() + from @char in IdentifierChar.Many().Text() + select start + @char; + + public static readonly Parser Namespace = + from ns in Parse.Letter.Many().Text() + from bar in Parse.Char('|') + select ns; + + public static readonly Parser OfType = + from ns in Namespace.Optional() + from identifier in Identifier + select new OfTypeSyntax + { + TypeName = identifier, + Xmlns = ns.GetOrDefault(), + }; + + public static readonly Parser Name = + from hash in Parse.Char('#') + from identifier in Identifier + select new NameSyntax { Name = identifier }; + + public static readonly Parser ClassStart = Parse.Char('_').Or(Parse.Letter); + + public static readonly Parser ClassChar = ClassStart.Or(Parse.Numeric); + + public static readonly Parser ClassIdentifier = + from start in ClassStart.Once().Text() + from @char in ClassChar.Many().Text() + select start + @char; + + public static readonly Parser StandardClass = + from dot in Parse.Char('.').Once() + from identifier in ClassIdentifier + select new ClassSyntax { Class = identifier }; + + public static readonly Parser Pseduoclass = + from colon in Parse.Char(':').Once() + from identifier in ClassIdentifier + select new ClassSyntax { Class = ':' + identifier }; + + public static readonly Parser Class = StandardClass.Or(Pseduoclass); + + public static readonly Parser Property = + from open in Parse.Char('[').Once() + from identifier in Identifier + from eq in Parse.Char('=').Once() + from value in Parse.CharExcept(']').Many().Text() + from close in Parse.Char(']').Once() + select new PropertySyntax { Property = identifier, Value = value }; + + public static readonly Parser Child = Parse.Char('>').Token().Return(new ChildSyntax()); + + public static readonly Parser Descendent = + from child in Parse.WhiteSpace.Many() + select new DescendentSyntax(); + + public static readonly Parser Template = + from template in Parse.String("/template/").Token() + select new TemplateSyntax(); + + public static readonly Parser Is = + from function in Parse.String(":is(") + from type in OfType + from close in Parse.Char(')') + select new IsSyntax { TypeName = type.TypeName, Xmlns = type.Xmlns }; + + public static readonly Parser SingleSelector = + OfType + .Or(Is) + .Or(Name) + .Or(Class) + .Or(Property) + .Or(Child) + .Or(Template) + .Or(Descendent); + + public static readonly Parser> Selector = SingleSelector.Many().End(); + + public interface ISyntax + { + } + + public class OfTypeSyntax : ISyntax + { + public string TypeName { get; set; } + + public string Xmlns { get; set; } + + public override bool Equals(object obj) + { + var other = obj as OfTypeSyntax; + return other != null && other.TypeName == TypeName && other.Xmlns == Xmlns; + } + } + + public class IsSyntax : ISyntax + { + public string TypeName { get; set; } + + public string Xmlns { get; set; } + + public override bool Equals(object obj) + { + var other = obj as IsSyntax; + return other != null && other.TypeName == TypeName && other.Xmlns == Xmlns; + } + } + + public class ClassSyntax : ISyntax + { + public string Class { get; set; } + + public override bool Equals(object obj) + { + return obj is ClassSyntax && ((ClassSyntax)obj).Class == Class; + } + } + + public class NameSyntax : ISyntax + { + public string Name { get; set; } + + public override bool Equals(object obj) + { + return obj is NameSyntax && ((NameSyntax)obj).Name == Name; + } + } + + public class PropertySyntax : ISyntax + { + public string Property { get; set; } + + public string Value { get; set; } + + public override bool Equals(object obj) + { + return obj is PropertySyntax && + ((PropertySyntax)obj).Property == Property && + ((PropertySyntax)obj).Value == Value; + } + } + + public class ChildSyntax : ISyntax + { + public override bool Equals(object obj) + { + return obj is ChildSyntax; + } + } + + public class DescendentSyntax : ISyntax + { + public override bool Equals(object obj) + { + return obj is DescendentSyntax; + } + } + + public class TemplateSyntax : ISyntax + { + public override bool Equals(object obj) + { + return obj is TemplateSyntax; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs b/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs new file mode 100644 index 0000000000..8cf6f9794e --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Parsers/SelectorParser.cs @@ -0,0 +1,118 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using Avalonia.Styling; +using Avalonia.Utilities; +using Sprache; + +namespace Avalonia.Markup.Xaml.Parsers +{ + /// + /// Parses a from text. + /// + public class SelectorParser + { + private readonly Func _typeResolver; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The type resolver to use. The type resolver is a function which accepts two strings: + /// a type name and a XML namespace prefix and a type name, and should return the resolved + /// type or throw an exception. + /// + public SelectorParser(Func typeResolver) + { + this._typeResolver = typeResolver; + } + + /// + /// Parses a from a string. + /// + /// The string. + /// The parsed selector. + public Selector Parse(string s) + { + var syntax = SelectorGrammar.Selector.Parse(s); + var result = default(Selector); + + foreach (var i in syntax) + { + var ofType = i as SelectorGrammar.OfTypeSyntax; + var @is = i as SelectorGrammar.IsSyntax; + var @class = i as SelectorGrammar.ClassSyntax; + var name = i as SelectorGrammar.NameSyntax; + var property = i as SelectorGrammar.PropertySyntax; + var child = i as SelectorGrammar.ChildSyntax; + var descendent = i as SelectorGrammar.DescendentSyntax; + var template = i as SelectorGrammar.TemplateSyntax; + + if (ofType != null) + { + result = result.OfType(_typeResolver(ofType.TypeName, ofType.Xmlns)); + } + if (@is != null) + { + result = result.Is(_typeResolver(@is.TypeName, @is.Xmlns)); + } + else if (@class != null) + { + result = result.Class(@class.Class); + } + else if (name != null) + { + result = result.Name(name.Name); + } + else if (property != null) + { + var type = result.TargetType; + + if (type == null) + { + throw new InvalidOperationException("Property selectors must be applied to a type."); + } + + var targetProperty = AvaloniaPropertyRegistry.Instance.FindRegistered(type, property.Property); + + if (targetProperty == null) + { + throw new InvalidOperationException($"Cannot find '{property.Property}' on '{type}"); + } + + object typedValue; + + if (TypeUtilities.TryConvert( + targetProperty.PropertyType, + property.Value, + CultureInfo.InvariantCulture, + out typedValue)) + { + result = result.PropertyEquals(targetProperty, typedValue); + } + else + { + throw new InvalidOperationException( + $"Could not convert '{property.Value}' to '{targetProperty.PropertyType}"); + } + } + else if (child != null) + { + result = result.Child(); + } + else if (descendent != null) + { + result = result.Descendent(); + } + else if (template != null) + { + result = result.Template(); + } + } + + return result; + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs b/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..d14f5d82b6 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs @@ -0,0 +1,14 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; +using Avalonia.Metadata; +using System.Runtime.CompilerServices; + +[assembly: AssemblyTitle("Avalonia.Markup.Xaml")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Data")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.MarkupExtensions")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Styling")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Templates")] +[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")] + diff --git a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs new file mode 100644 index 0000000000..c6c69973cc --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs @@ -0,0 +1,71 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Styling; + +namespace Avalonia.Markup.Xaml.Styling +{ + /// + /// Includes a style from a URL. + /// + public class StyleInclude : IStyle + { + private Uri _baseUri; + private IStyle _loaded; + + /// + /// Initializes a new instance of the class. + /// + public StyleInclude() + { + // StyleInclude will usually be loaded from XAML and its URI can be relative to the + // XAML file that its included in, so store the current XAML file's URI if any as + // a base URI. + _baseUri = AvaloniaXamlLoader.UriContext; + } + + /// + /// Gets or sets the source URL. + /// + public Uri Source { get; set; } + + /// + /// Gets the loaded style. + /// + public IStyle Loaded + { + get + { + if (_loaded == null) + { + var loader = new AvaloniaXamlLoader(); + _loaded = (IStyle)loader.Load(Source, _baseUri); + } + + return _loaded; + } + } + + /// + public void Attach(IStyleable control, IStyleHost container) + { + if (Source != null) + { + Loaded.Attach(control, container); + } + } + + /// + /// Tries to find a named resource within the style. + /// + /// The resource name. + /// + /// The resource if found, otherwise . + /// + public object FindResource(string name) + { + return Loaded.FindResource(name); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/ControlTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/ControlTemplate.cs new file mode 100644 index 0000000000..96e977b265 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/ControlTemplate.cs @@ -0,0 +1,21 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using Avalonia.Metadata; +using Avalonia.Styling; + +namespace Avalonia.Markup.Xaml.Templates +{ + public class ControlTemplate : IControlTemplate + { + [Content] + public TemplateContent Content { get; set; } + + public IControl Build(ITemplatedControl control) + { + return Content.Load(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs new file mode 100644 index 0000000000..2886b63c55 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs @@ -0,0 +1,38 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reflection; +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using Avalonia.Metadata; + +namespace Avalonia.Markup.Xaml.Templates +{ + public class DataTemplate : IDataTemplate + { + public Type DataType { get; set; } + + [Content] + public TemplateContent Content { get; set; } + + public bool Match(object data) + { + if (DataType == null) + { + return true; + } + else + { + return DataType.GetTypeInfo().IsAssignableFrom(data.GetType().GetTypeInfo()); + } + } + + public IControl Build(object data) + { + var visualTreeForItem = Content.Load(); + visualTreeForItem.DataContext = data; + return visualTreeForItem; + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/FocusAdornerTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/FocusAdornerTemplate.cs new file mode 100644 index 0000000000..a59e4231de --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/FocusAdornerTemplate.cs @@ -0,0 +1,19 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Controls; +using Avalonia.Metadata; + +namespace Avalonia.Markup.Xaml.Templates +{ + public class FocusAdornerTemplate : ITemplate + { + [Content] + public TemplateContent Content { get; set; } + + public IControl Build() + { + return Content.Load(); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs new file mode 100644 index 0000000000..d5811924f2 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Avalonia.Controls; +using Avalonia.Metadata; + +namespace Avalonia.Markup.Xaml.Templates +{ + public class ItemsPanelTemplate : ITemplate + { + [Content] + public TemplateContent Content { get; set; } + + public IPanel Build() + { + return (IPanel)Content.Load(); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs new file mode 100644 index 0000000000..6836dbf9df --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/MemberSelector.cs @@ -0,0 +1,20 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; +using Avalonia.Controls.Templates; + +namespace Avalonia.Markup.Xaml.Templates +{ + public class MemberSelector : IMemberSelector + { + public string MemberName { get; set; } + + public object Select(object o) + { + // TODO: Handle nested property paths, changing values etc. + var property = o.GetType().GetRuntimeProperty(MemberName); + return property?.GetValue(o); + } + } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs new file mode 100644 index 0000000000..53edea6ce4 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs @@ -0,0 +1,10 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Markup.Xaml.Templates +{ + public class Template + { + public TemplateContent Content { get; set; } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs new file mode 100644 index 0000000000..325b9bf53f --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs @@ -0,0 +1,37 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Collections.Generic; +using OmniXaml; +using OmniXaml.ObjectAssembler; +using Avalonia.Controls; +using Avalonia.Markup.Xaml.Context; + +namespace Avalonia.Markup.Xaml.Templates +{ + public class TemplateContent + { + private readonly IEnumerable nodes; + private readonly IRuntimeTypeSource runtimeTypeSource; + + public TemplateContent(IEnumerable nodes, IRuntimeTypeSource runtimeTypeSource) + { + this.nodes = nodes; + this.runtimeTypeSource = runtimeTypeSource; + } + + public Control Load() + { + var assembler = new AvaloniaObjectAssembler( + runtimeTypeSource, + new TopDownValueContext()); + + foreach (var xamlNode in nodes) + { + assembler.Process(xamlNode); + } + + return (Control)assembler.Result; + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs new file mode 100644 index 0000000000..75f0329629 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateLoader.cs @@ -0,0 +1,16 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Collections.Generic; +using OmniXaml; + +namespace Avalonia.Markup.Xaml.Templates +{ + public class TemplateLoader : IDeferredLoader + { + public object Load(IEnumerable nodes, IRuntimeTypeSource runtimeTypeSource) + { + return new TemplateContent(nodes, runtimeTypeSource); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs new file mode 100644 index 0000000000..3c4d3c5baa --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs @@ -0,0 +1,62 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections; +using System.Reactive.Linq; +using System.Reflection; +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using Avalonia.Data; +using Avalonia.Markup.Data; +using Avalonia.Markup.Xaml.Data; +using Avalonia.Metadata; + +namespace Avalonia.Markup.Xaml.Templates +{ + public class TreeDataTemplate : ITreeDataTemplate + { + public Type DataType { get; set; } + + [Content] + public TemplateContent Content { get; set; } + + [AssignBinding] + public Binding ItemsSource { get; set; } + + public bool Match(object data) + { + if (DataType == null) + { + return true; + } + else + { + return DataType.GetTypeInfo().IsAssignableFrom(data.GetType().GetTypeInfo()); + } + } + + public InstancedBinding ItemsSelector(object item) + { + if (ItemsSource != null) + { + var obs = new ExpressionObserver(item, ItemsSource.Path); + return new InstancedBinding(obs); + } + + return null; + } + + public bool IsExpanded(object item) + { + return true; + } + + public IControl Build(object data) + { + var visualTreeForItem = Content.Load(); + visualTreeForItem.DataContext = data; + return visualTreeForItem; + } + } +} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/app.config b/src/Markup/Avalonia.Markup.Xaml/app.config similarity index 100% rename from src/Markup/Perspex.Markup.Xaml/app.config rename to src/Markup/Avalonia.Markup.Xaml/app.config diff --git a/src/Markup/Perspex.Markup.Xaml/glass b/src/Markup/Avalonia.Markup.Xaml/glass similarity index 100% rename from src/Markup/Perspex.Markup.Xaml/glass rename to src/Markup/Avalonia.Markup.Xaml/glass diff --git a/src/Markup/Perspex.Markup.Xaml/packages.config b/src/Markup/Avalonia.Markup.Xaml/packages.config similarity index 100% rename from src/Markup/Perspex.Markup.Xaml/packages.config rename to src/Markup/Avalonia.Markup.Xaml/packages.config diff --git a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj new file mode 100644 index 0000000000..1ca067452a --- /dev/null +++ b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj @@ -0,0 +1,135 @@ + + + + + 11.0 + Debug + AnyCPU + {6417E941-21BC-467B-A771-0DE389353CE6} + Library + Properties + Avalonia.Markup + Avalonia.Markup + en-US + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Profile7 + v4.5 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Avalonia.Markup.XML + CS1591 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Avalonia.Markup.XML + CS1591 + + + + Properties\SharedAssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll + True + + + ..\..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll + True + + + ..\..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll + True + + + ..\..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll + True + + + + + + + + {b09b78d8-9b26-48b0-9149-d64a2f120f3f} + Avalonia.Base + + + {d2221c82-4a25-4583-9b43-d791e3f6820c} + Avalonia.Controls + + + {62024b2d-53eb-4638-b26b-85eeaa54866e} + Avalonia.Input + + + {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} + Avalonia.Interactivity + + + {42472427-4774-4c81-8aff-9f27b8e31721} + Avalonia.Layout + + + {eb582467-6abb-43a1-b052-e981ba910e3a} + Avalonia.SceneGraph + + + {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} + Avalonia.Styling + + + + + \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup/BoolConverters.cs b/src/Markup/Avalonia.Markup/BoolConverters.cs new file mode 100644 index 0000000000..e049dccc06 --- /dev/null +++ b/src/Markup/Avalonia.Markup/BoolConverters.cs @@ -0,0 +1,19 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Linq; + +namespace Avalonia.Markup +{ + /// + /// Provides a set of useful s for working with string values. + /// + public static class BoolConverters + { + /// + /// A multi-value converter that returns true if all inputs are true. + /// + public static readonly IMultiValueConverter And = + new FuncMultiValueConverter(x => x.All(y => y)); + } +} diff --git a/src/Markup/Avalonia.Markup/ControlLocator.cs b/src/Markup/Avalonia.Markup/ControlLocator.cs new file mode 100644 index 0000000000..a10fd7e283 --- /dev/null +++ b/src/Markup/Avalonia.Markup/ControlLocator.cs @@ -0,0 +1,63 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Linq; +using System.Reactive.Linq; +using Avalonia.Controls; +using Avalonia.LogicalTree; + +namespace Avalonia.Markup +{ + /// + /// Locates controls relative to other controls. + /// + public static class ControlLocator + { + /// + /// Tracks a named control relative to another control. + /// + /// + /// The control relative from which the other control should be found. + /// + /// The name of the control to find. + public static IObservable Track(IControl relativeTo, string name) + { + var attached = Observable.FromEventPattern( + x => relativeTo.AttachedToLogicalTree += x, + x => relativeTo.DetachedFromLogicalTree += x) + .Select(x => ((IControl)x.Sender).FindNameScope()) + .StartWith(relativeTo.FindNameScope()); + + var detached = Observable.FromEventPattern( + x => relativeTo.DetachedFromLogicalTree += x, + x => relativeTo.DetachedFromLogicalTree += x) + .Select(x => (INameScope)null); + + return attached.Merge(detached).Select(nameScope => + { + if (nameScope != null) + { + var registered = Observable.FromEventPattern( + x => nameScope.Registered += x, + x => nameScope.Registered -= x) + .Where(x => x.EventArgs.Name == name) + .Select(x => x.EventArgs.Element) + .OfType(); + var unregistered = Observable.FromEventPattern( + x => nameScope.Unregistered += x, + x => nameScope.Unregistered -= x) + .Where(x => x.EventArgs.Name == name) + .Select(_ => (IControl)null); + return registered + .StartWith(nameScope.Find(name)) + .Merge(unregistered); + } + else + { + return Observable.Return(null); + } + }).Switch(); + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/CommonPropertyNames.cs b/src/Markup/Avalonia.Markup/Data/CommonPropertyNames.cs new file mode 100644 index 0000000000..f91940baf7 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/CommonPropertyNames.cs @@ -0,0 +1,10 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +namespace Avalonia.Markup.Data +{ + public static class CommonPropertyNames + { + public const string IndexerName = "Item"; + } +} diff --git a/src/Markup/Avalonia.Markup/Data/ExpressionNode.cs b/src/Markup/Avalonia.Markup/Data/ExpressionNode.cs new file mode 100644 index 0000000000..b46091df70 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/ExpressionNode.cs @@ -0,0 +1,125 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Subjects; +using Avalonia.Data; + +namespace Avalonia.Markup.Data +{ + internal abstract class ExpressionNode : IObservable + { + protected static readonly WeakReference UnsetReference = + new WeakReference(AvaloniaProperty.UnsetValue); + + private WeakReference _target; + + private Subject _subject; + + private WeakReference _value = UnsetReference; + + public ExpressionNode Next { get; set; } + + public WeakReference Target + { + get + { + return _target; + } + set + { + var newInstance = value?.Target; + var oldInstance = _target?.Target; + + if (!object.Equals(oldInstance, newInstance)) + { + if (oldInstance != null) + { + Unsubscribe(oldInstance); + } + + _target = value; + + if (newInstance != null) + { + SubscribeAndUpdate(_target); + } + else + { + CurrentValue = UnsetReference; + } + + if (Next != null) + { + Next.Target = _value; + } + } + } + } + + public WeakReference CurrentValue + { + get + { + return _value; + } + + set + { + _value = value; + + if (Next != null) + { + Next.Target = value; + } + + _subject?.OnNext(value.Target); + } + } + + public virtual bool SetValue(object value, BindingPriority priority) + { + return Next?.SetValue(value, priority) ?? false; + } + + public virtual IDisposable Subscribe(IObserver observer) + { + if (Next != null) + { + return Next.Subscribe(observer); + } + else + { + if (_subject == null) + { + _subject = new Subject(); + } + + observer.OnNext(CurrentValue.Target); + return _subject.Subscribe(observer); + } + } + + protected virtual void SubscribeAndUpdate(WeakReference reference) + { + CurrentValue = reference; + } + + protected virtual void SendValidationStatus(ValidationStatus status) + { + //Even if elements only bound to sub-values, send validation changes along so they will be surfaced to the UI level. + if (_subject != null) + { + _subject.OnNext(status); + } + else + { + Next?.SendValidationStatus(status); + } + } + + protected virtual void Unsubscribe(object target) + { + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/ExpressionNodeBuilder.cs b/src/Markup/Avalonia.Markup/Data/ExpressionNodeBuilder.cs new file mode 100644 index 0000000000..a4623be0ae --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/ExpressionNodeBuilder.cs @@ -0,0 +1,29 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Markup.Data.Parsers; + +namespace Avalonia.Markup.Data +{ + internal static class ExpressionNodeBuilder + { + public static ExpressionNode Build(string expression) + { + if (string.IsNullOrWhiteSpace(expression)) + { + throw new ArgumentException("'expression' may not be empty."); + } + + var reader = new Reader(expression); + var node = ExpressionParser.Parse(reader); + + if (!reader.End) + { + throw new ExpressionParseException(reader.Position, "Expected end of expression."); + } + + return node; + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs b/src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs new file mode 100644 index 0000000000..0b1ebeeb7e --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs @@ -0,0 +1,301 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using Avalonia.Data; +using Avalonia.Markup.Data.Plugins; + +namespace Avalonia.Markup.Data +{ + /// + /// Observes and sets the value of an expression on an object. + /// + public class ExpressionObserver : ObservableBase, IDescription + { + /// + /// An ordered collection of property accessor plugins that can be used to customize + /// the reading and subscription of property values on a type. + /// + public static readonly IList PropertyAccessors = + new List + { + new AvaloniaPropertyAccessorPlugin(), + new InpcPropertyAccessorPlugin(), + }; + + /// + /// An ordered collection of validation checker plugins that can be used to customize + /// the validation of view model and model data. + /// + public static readonly IList ValidationCheckers = + new List + { + new IndeiValidationCheckerPlugin(), + new ExceptionValidationCheckerPlugin() + }; + + private readonly WeakReference _root; + private readonly Func _rootGetter; + private readonly IObservable _rootObservable; + private readonly IObservable _update; + private IDisposable _rootObserverSubscription; + private IDisposable _updateSubscription; + private int _count; + private readonly ExpressionNode _node; + private ValidationMethods _methods; + + /// + /// Initializes a new instance of the class. + /// + /// The root object. + /// The expression. + /// The validation methods to enable on this observer. + public ExpressionObserver(object root, string expression, ValidationMethods methods = ValidationMethods.None) + { + Contract.Requires(expression != null); + + _root = new WeakReference(root); + _methods = methods; + if (!string.IsNullOrWhiteSpace(expression)) + { + _node = ExpressionNodeBuilder.Build(expression); + } + + Expression = expression; + } + + /// + /// Initializes a new instance of the class. + /// + /// An observable which provides the root object. + /// The expression. + /// The validation methods to enable on this observer. + public ExpressionObserver(IObservable rootObservable, string expression, ValidationMethods methods = ValidationMethods.None) + { + Contract.Requires(rootObservable != null); + Contract.Requires(expression != null); + + _rootObservable = rootObservable; + _methods = methods; + if (!string.IsNullOrWhiteSpace(expression)) + { + _node = ExpressionNodeBuilder.Build(expression); + } + + Expression = expression; + } + + /// + /// Initializes a new instance of the class. + /// + /// A function which gets the root object. + /// The expression. + /// An observable which triggers a re-read of the getter. + /// The validation methods to enable on this observer. + public ExpressionObserver( + Func rootGetter, + string expression, + IObservable update, + ValidationMethods methods = ValidationMethods.None) + { + Contract.Requires(rootGetter != null); + Contract.Requires(expression != null); + Contract.Requires(update != null); + + _rootGetter = rootGetter; + _update = update; + _methods = methods; + if (!string.IsNullOrWhiteSpace(expression)) + { + _node = ExpressionNodeBuilder.Build(expression); + } + + Expression = expression; + } + + /// + /// Attempts to set the value of a property expression. + /// + /// The value to set. + /// The binding priority to use. + /// + /// True if the value could be set; false if the expression does not evaluate to a + /// property. + /// + public bool SetValue(object value, BindingPriority priority = BindingPriority.LocalValue) + { + IncrementCount(); + + if (_rootGetter != null && _node != null) + { + _node.Target = new WeakReference(_rootGetter()); + } + + try + { + return _node?.SetValue(value, priority) ?? false; + } + finally + { + DecrementCount(); + } + } + + /// + /// Gets the expression being observed. + /// + public string Expression { get; } + + /// + /// Gets the type of the expression result or null if the expression could not be + /// evaluated. + /// + public Type ResultType + { + get + { + IncrementCount(); + + try + { + if (_node != null) + { + return (Leaf as PropertyAccessorNode)?.PropertyType; + } + else if(_rootGetter != null) + { + return _rootGetter()?.GetType(); + } + else + { + return _root.Target?.GetType(); + } + } + finally + { + DecrementCount(); + } + } + } + + /// + string IDescription.Description => Expression; + + /// + /// Gets the root expression node. Used for testing. + /// + internal ExpressionNode Node => _node; + + /// + /// Gets the leaf node. + /// + private ExpressionNode Leaf + { + get + { + var node = _node; + while (node.Next != null) node = node.Next; + return node; + } + } + + /// + protected override IDisposable SubscribeCore(IObserver observer) + { + IncrementCount(); + + if (_node != null) + { + IObservable source = _node; + + if (_rootObservable != null) + { + source = source.TakeUntil(_rootObservable.LastOrDefaultAsync()); + } + else if (_update != null) + { + source = source.TakeUntil(_update.LastOrDefaultAsync()); + } + var validationFiltered = source.Where(o => (o as ValidationStatus)?.Match(_methods) ?? true); + var subscription = validationFiltered.Subscribe(observer); + + return Disposable.Create(() => + { + DecrementCount(); + subscription.Dispose(); + }); + } + else if (_rootObservable != null) + { + return _rootObservable.Subscribe(observer); + } + else + { + if (_update == null) + { + return Observable.Never() + .StartWith(_root.Target) + .Subscribe(observer); + } + else + { + return _update + .Select(_ => _rootGetter()) + .StartWith(_rootGetter()) + .Subscribe(observer); + } + } + } + + private void IncrementCount() + { + if (_count++ == 0 && _node != null) + { + if (_rootGetter != null) + { + _node.Target = new WeakReference(_rootGetter()); + + if (_update != null) + { + _updateSubscription = _update.Subscribe(x => + _node.Target = new WeakReference(_rootGetter())); + } + } + else if (_rootObservable != null) + { + _rootObserverSubscription = _rootObservable.Subscribe(x => + _node.Target = new WeakReference(x)); + } + else + { + _node.Target = _root; + } + } + } + + private void DecrementCount() + { + if (--_count == 0 && _node != null) + { + if (_rootObserverSubscription != null) + { + _rootObserverSubscription.Dispose(); + _rootObserverSubscription = null; + } + + if (_updateSubscription != null) + { + _updateSubscription.Dispose(); + _updateSubscription = null; + } + + _node.Target = null; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/ExpressionParseException.cs b/src/Markup/Avalonia.Markup/Data/ExpressionParseException.cs new file mode 100644 index 0000000000..d06bdd1e52 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/ExpressionParseException.cs @@ -0,0 +1,31 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Markup.Data.Parsers; + +namespace Avalonia.Markup.Data +{ + /// + /// Exception thrown when could not parse the provided + /// expression string. + /// + public class ExpressionParseException : Exception + { + /// + /// Initializes a new instance of the class. + /// + /// The column position of the error. + /// The exception message. + public ExpressionParseException(int column, string message) + : base(message) + { + Column = column; + } + + /// + /// Gets the column position at which the error occurred. + /// + public int Column { get; } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs b/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs new file mode 100644 index 0000000000..1180ee51a6 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs @@ -0,0 +1,193 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using Avalonia.Data; +using Avalonia.Logging; +using Avalonia.Utilities; + +namespace Avalonia.Markup.Data +{ + /// + /// Turns an into a subject that can be bound two-way with + /// a value converter. + /// + public class ExpressionSubject : ISubject, IDescription + { + private readonly ExpressionObserver _inner; + private readonly Type _targetType; + private readonly object _fallbackValue; + private readonly BindingPriority _priority; + + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The type to convert the value to. + public ExpressionSubject(ExpressionObserver inner, Type targetType) + : this(inner, targetType, DefaultValueConverter.Instance) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The type to convert the value to. + /// The value converter to use. + /// + /// A parameter to pass to . + /// + /// + /// The value to use when the binding is unable to produce a value. + /// + /// The binding priority. + public ExpressionSubject( + ExpressionObserver inner, + Type targetType, + IValueConverter converter, + object converterParameter = null, + object fallbackValue = null, + BindingPriority priority = BindingPriority.LocalValue) + { + Contract.Requires(inner != null); + Contract.Requires(targetType != null); + Contract.Requires(converter != null); + + _inner = inner; + _targetType = targetType; + Converter = converter; + ConverterParameter = converterParameter; + _fallbackValue = fallbackValue; + _priority = priority; + } + + /// + /// Gets the converter to use on the expression. + /// + public IValueConverter Converter { get; } + + /// + /// Gets a parameter to pass to . + /// + public object ConverterParameter { get; } + + /// + string IDescription.Description => _inner.Expression; + + /// + public void OnCompleted() + { + } + + /// + public void OnError(Exception error) + { + } + + /// + public void OnNext(object value) + { + var type = _inner.ResultType; + + if (type != null) + { + var converted = Converter.ConvertBack( + value, + type, + ConverterParameter, + CultureInfo.CurrentUICulture); + + if (converted == AvaloniaProperty.UnsetValue) + { + converted = TypeUtilities.Default(type); + _inner.SetValue(converted, _priority); + } + else if (converted is BindingError) + { + var error = converted as BindingError; + + Logger.Error( + LogArea.Binding, + this, + "Error binding to {Expression}: {Message}", + _inner.Expression, + error.Exception.Message); + + if (_fallbackValue != null) + { + if (TypeUtilities.TryConvert( + type, + _fallbackValue, + CultureInfo.InvariantCulture, + out converted)) + { + _inner.SetValue(converted, _priority); + } + else + { + Logger.Error( + LogArea.Binding, + this, + "Could not convert FallbackValue {FallbackValue} to {Type}", + _fallbackValue, + type); + } + } + } + else + { + _inner.SetValue(converted, _priority); + } + } + } + + /// + public IDisposable Subscribe(IObserver observer) + { + return _inner.Select(ConvertValue).Subscribe(observer); + } + + private object ConvertValue(object value) + { + var converted = + value as BindingError ?? + value as ValidationStatus ?? + Converter.Convert( + value, + _targetType, + ConverterParameter, + CultureInfo.CurrentUICulture); + + if (_fallbackValue != null && + (converted == AvaloniaProperty.UnsetValue || + converted is BindingError)) + { + var error = converted as BindingError; + + if (TypeUtilities.TryConvert( + _targetType, + _fallbackValue, + CultureInfo.InvariantCulture, + out converted)) + { + if (error != null) + { + converted = new BindingError(error.Exception, converted); + } + } + else + { + converted = new BindingError( + new InvalidCastException( + $"Could not convert FallbackValue '{_fallbackValue}' to '{_targetType}'")); + } + } + + return converted; + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/IndexerNode.cs b/src/Markup/Avalonia.Markup/Data/IndexerNode.cs new file mode 100644 index 0000000000..8849e7edbc --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/IndexerNode.cs @@ -0,0 +1,277 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using Avalonia.Utilities; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Reflection; + +namespace Avalonia.Markup.Data +{ + internal class IndexerNode : ExpressionNode, + IWeakSubscriber, + IWeakSubscriber + { + public IndexerNode(IList arguments) + { + Arguments = arguments; + } + + public IList Arguments { get; } + + void IWeakSubscriber.OnEvent(object sender, NotifyCollectionChangedEventArgs e) + { + var update = false; + if (sender is IList) + { + object indexObject; + if (!TypeUtilities.TryConvert(typeof(int), Arguments[0], CultureInfo.InvariantCulture, out indexObject)) + { + return; + } + var index = (int)indexObject; + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + update = index >= e.NewStartingIndex; + break; + case NotifyCollectionChangedAction.Remove: + update = index >= e.OldStartingIndex; + break; + case NotifyCollectionChangedAction.Replace: + update = index >= e.NewStartingIndex && + index < e.NewStartingIndex + e.NewItems.Count; + break; + case NotifyCollectionChangedAction.Move: + update = (index >= e.NewStartingIndex && + index < e.NewStartingIndex + e.NewItems.Count) || + (index >= e.OldStartingIndex && + index < e.OldStartingIndex + e.OldItems.Count); + break; + case NotifyCollectionChangedAction.Reset: + update = true; + break; + } + } + else + { + update = true; + } + + if (update) + { + CurrentValue = new WeakReference(GetValue(sender)); + } + } + + void IWeakSubscriber.OnEvent(object sender, PropertyChangedEventArgs e) + { + var typeInfo = sender.GetType().GetTypeInfo(); + + if (typeInfo.GetDeclaredProperty(e.PropertyName) == null) + { + return; + } + + if (typeInfo.GetDeclaredProperty(e.PropertyName).GetIndexParameters().Any()) + { + CurrentValue = new WeakReference(GetValue(sender)); + } + } + + protected override void SubscribeAndUpdate(WeakReference reference) + { + object target = reference.Target; + + CurrentValue = new WeakReference(GetValue(target)); + + var incc = target as INotifyCollectionChanged; + + if (incc != null) + { + WeakSubscriptionManager.Subscribe( + incc, + nameof(incc.CollectionChanged), + this); + } + + var inpc = target as INotifyPropertyChanged; + + if (inpc != null) + { + WeakSubscriptionManager.Subscribe( + inpc, + nameof(inpc.PropertyChanged), + this); + } + } + + protected override void Unsubscribe(object target) + { + var incc = target as INotifyCollectionChanged; + + if (incc != null) + { + WeakSubscriptionManager.Unsubscribe( + incc, + nameof(incc.CollectionChanged), + this); + } + + var inpc = target as INotifyPropertyChanged; + + if (inpc != null) + { + WeakSubscriptionManager.Unsubscribe( + inpc, + nameof(inpc.PropertyChanged), + this); + } + } + + private object GetValue(object target) + { + var typeInfo = target.GetType().GetTypeInfo(); + var list = target as IList; + var dictionary = target as IDictionary; + var indexerProperty = GetIndexer(typeInfo); + var indexerParameters = indexerProperty?.GetIndexParameters(); + if (indexerProperty != null && indexerParameters.Length == Arguments.Count) + { + var convertedObjectArray = new object[indexerParameters.Length]; + for (int i = 0; i < Arguments.Count; i++) + { + object temp = null; + if (!TypeUtilities.TryConvert(indexerParameters[i].ParameterType, Arguments[i], CultureInfo.InvariantCulture, out temp)) + { + return AvaloniaProperty.UnsetValue; + } + convertedObjectArray[i] = temp; + } + var intArgs = convertedObjectArray.OfType().ToArray(); + + // Try special cases where we can validate indicies + if (typeInfo.IsArray) + { + return GetValueFromArray((Array)target, intArgs); + } + else if (Arguments.Count == 1) + { + if (list != null) + { + if (intArgs.Length == Arguments.Count && intArgs[0] >= 0 && intArgs[0] < list.Count) + { + return list[intArgs[0]]; + } + return AvaloniaProperty.UnsetValue; + } + else if (dictionary != null) + { + if (dictionary.Contains(convertedObjectArray[0])) + { + return dictionary[convertedObjectArray[0]]; + } + return AvaloniaProperty.UnsetValue; + } + else + { + // Fallback to unchecked access + return indexerProperty.GetValue(target, convertedObjectArray); + } + } + else + { + // Fallback to unchecked access + return indexerProperty.GetValue(target, convertedObjectArray); + } + } + // Multidimensional arrays end up here because the indexer search picks up the IList indexer instead of the + // multidimensional indexer, which doesn't take the same number of arguments + else if (typeInfo.IsArray) + { + return GetValueFromArray((Array)target); + } + + return AvaloniaProperty.UnsetValue; + } + + private object GetValueFromArray(Array array) + { + int[] intArgs; + if (!ConvertArgumentsToInts(out intArgs)) + return AvaloniaProperty.UnsetValue; + return GetValueFromArray(array, intArgs); + } + + private object GetValueFromArray(Array array, int[] indicies) + { + if (ValidBounds(indicies, array)) + { + return array.GetValue(indicies); + } + return AvaloniaProperty.UnsetValue; + } + + private bool ConvertArgumentsToInts(out int[] intArgs) + { + intArgs = new int[Arguments.Count]; + for (int i = 0; i < Arguments.Count; ++i) + { + object value; + if (!TypeUtilities.TryConvert(typeof(int), Arguments[i], CultureInfo.InvariantCulture, out value)) + { + return false; + } + intArgs[i] = (int)value; + } + return true; + } + + private static PropertyInfo GetIndexer(TypeInfo typeInfo) + { + PropertyInfo indexer; + for (;typeInfo != null; typeInfo = typeInfo.BaseType?.GetTypeInfo()) + { + // Check for the default indexer name first to make this faster. + // This will only be false when a class in VB has a custom indexer name. + if ((indexer = typeInfo.GetDeclaredProperty(CommonPropertyNames.IndexerName)) != null) + { + return indexer; + } + foreach (var property in typeInfo.DeclaredProperties) + { + if (property.GetIndexParameters().Any()) + { + return property; + } + } + } + return null; + } + + private bool ValidBounds(int[] indicies, Array array) + { + if (indicies.Length == array.Rank) + { + for (var i = 0; i < indicies.Length; ++i) + { + if (indicies[i] >= array.GetLength(i)) + { + return false; + } + } + + return true; + } + else + { + return false; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/LogicalNotNode.cs b/src/Markup/Avalonia.Markup/Data/LogicalNotNode.cs new file mode 100644 index 0000000000..29fa842439 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/LogicalNotNode.cs @@ -0,0 +1,55 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Reactive.Linq; +using Avalonia.Data; + +namespace Avalonia.Markup.Data +{ + internal class LogicalNotNode : ExpressionNode + { + public override bool SetValue(object value, BindingPriority priority) + { + return false; + } + + public override IDisposable Subscribe(IObserver observer) + { + return Next.Select(Negate).Subscribe(observer); + } + + private static object Negate(object v) + { + if (v != AvaloniaProperty.UnsetValue) + { + var s = v as string; + + if (s != null) + { + bool result; + + if (bool.TryParse(s, out result)) + { + return !result; + } + } + else + { + try + { + var boolean = Convert.ToBoolean(v, CultureInfo.InvariantCulture); + return !boolean; + } + catch + { + // TODO: Maybe should log something here. + } + } + } + + return AvaloniaProperty.UnsetValue; + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Parsers/ArgumentListParser.cs b/src/Markup/Avalonia.Markup/Data/Parsers/ArgumentListParser.cs new file mode 100644 index 0000000000..a824a38867 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Parsers/ArgumentListParser.cs @@ -0,0 +1,68 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Avalonia.Markup.Data.Parsers +{ + internal static class ArgumentListParser + { + public static IList Parse(Reader r, char open, char close) + { + if (r.Peek == open) + { + var result = new List(); + + r.Take(); + + while (!r.End) + { + var builder = new StringBuilder(); + while (!r.End && r.Peek != ',' && r.Peek != close && !char.IsWhiteSpace(r.Peek)) + { + builder.Append(r.Take()); + } + if (builder.Length == 0) + { + throw new ExpressionParseException(r.Position, "Expected indexer argument."); + } + result.Add(builder.ToString()); + + r.SkipWhitespace(); + + if (r.End) + { + throw new ExpressionParseException(r.Position, "Expected ','."); + } + else if (r.TakeIf(close)) + { + return result; + } + else + { + if (r.Take() != ',') + { + throw new ExpressionParseException(r.Position, "Expected ','."); + } + + r.SkipWhitespace(); + } + } + + if (!r.End) + { + r.Take(); + return result; + } + else + { + throw new ExpressionParseException(r.Position, "Expected ']'."); + } + } + + return null; + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Parsers/ExpressionParser.cs b/src/Markup/Avalonia.Markup/Data/Parsers/ExpressionParser.cs new file mode 100644 index 0000000000..d8a613c055 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Parsers/ExpressionParser.cs @@ -0,0 +1,166 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Avalonia.Markup.Data.Parsers +{ + internal static class ExpressionParser + { + public static ExpressionNode Parse(Reader r) + { + var nodes = new List(); + var state = State.Start; + + while (!r.End && state != State.End) + { + switch (state) + { + case State.Start: + state = ParseStart(r, nodes); + break; + + case State.AfterMember: + state = ParseAfterMember(r, nodes); + break; + + case State.BeforeMember: + state = ParseBeforeMember(r, nodes); + break; + + case State.AttachedProperty: + state = ParseAttachedProperty(r, nodes); + break; + } + } + + if (state == State.BeforeMember) + { + throw new ExpressionParseException(r.Position, "Unexpected end of expression."); + } + + for (int n = 0; n < nodes.Count - 1; ++n) + { + nodes[n].Next = nodes[n + 1]; + } + + return nodes.FirstOrDefault(); + } + + private static State ParseStart(Reader r, IList nodes) + { + if (ParseNot(r)) + { + nodes.Add(new LogicalNotNode()); + return State.Start; + } + else if (ParseOpenBrace(r)) + { + return State.AttachedProperty; + } + else + { + var identifier = IdentifierParser.Parse(r); + + if (identifier != null) + { + nodes.Add(new PropertyAccessorNode(identifier)); + return State.AfterMember; + } + } + + return State.End; + } + + private static State ParseAfterMember(Reader r, IList nodes) + { + if (ParseMemberAccessor(r)) + { + return State.BeforeMember; + } + else + { + var args = ArgumentListParser.Parse(r, '[', ']'); + + if (args != null) + { + if (args.Count == 0) + { + throw new ExpressionParseException(r.Position, "Indexer may not be empty."); + } + + nodes.Add(new IndexerNode(args)); + return State.AfterMember; + } + } + + return State.End; + } + + private static State ParseBeforeMember(Reader r, IList nodes) + { + if (ParseOpenBrace(r)) + { + return State.AttachedProperty; + } + else + { + var identifier = IdentifierParser.Parse(r); + + if (identifier != null) + { + nodes.Add(new PropertyAccessorNode(identifier)); + return State.AfterMember; + } + + return State.End; + } + } + + private static State ParseAttachedProperty(Reader r, List nodes) + { + var owner = IdentifierParser.Parse(r); + + if (r.End || !r.TakeIf('.')) + { + throw new ExpressionParseException(r.Position, "Invalid attached property name."); + } + + var name = IdentifierParser.Parse(r); + + if (r.End || !r.TakeIf(')')) + { + throw new ExpressionParseException(r.Position, "Expected ')'."); + } + + nodes.Add(new PropertyAccessorNode(owner + '.' + name)); + return State.AfterMember; + } + + private static bool ParseNot(Reader r) + { + return !r.End && r.TakeIf('!'); + } + + private static bool ParseMemberAccessor(Reader r) + { + return !r.End && r.TakeIf('.'); + } + + private static bool ParseOpenBrace(Reader r) + { + return !r.End && r.TakeIf('('); + } + + private enum State + { + Start, + AfterMember, + BeforeMember, + AttachedProperty, + End, + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Parsers/IdentifierParser.cs b/src/Markup/Avalonia.Markup/Data/Parsers/IdentifierParser.cs new file mode 100644 index 0000000000..fa9051af06 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Parsers/IdentifierParser.cs @@ -0,0 +1,52 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Globalization; +using System.Text; + +namespace Avalonia.Markup.Data.Parsers +{ + internal static class IdentifierParser + { + public static string Parse(Reader r) + { + if (IsValidIdentifierStart(r.Peek)) + { + var result = new StringBuilder(); + + while (!r.End && IsValidIdentifierChar(r.Peek)) + { + result.Append(r.Take()); + } + + return result.ToString(); + } + else + { + return null; + } + } + + private static bool IsValidIdentifierStart(char c) + { + return char.IsLetter(c) || c == '_'; + } + + private static bool IsValidIdentifierChar(char c) + { + if (IsValidIdentifierStart(c)) + { + return true; + } + else + { + var cat = CharUnicodeInfo.GetUnicodeCategory(c); + return cat == UnicodeCategory.NonSpacingMark || + cat == UnicodeCategory.SpacingCombiningMark || + cat == UnicodeCategory.ConnectorPunctuation || + cat == UnicodeCategory.Format || + cat == UnicodeCategory.DecimalDigitNumber; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Parsers/Reader.cs b/src/Markup/Avalonia.Markup/Data/Parsers/Reader.cs new file mode 100644 index 0000000000..414648a10c --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Parsers/Reader.cs @@ -0,0 +1,44 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Markup.Data.Parsers +{ + internal class Reader + { + private readonly string _s; + private int _i; + + public Reader(string s) + { + _s = s; + } + + public bool End => _i == _s.Length; + public char Peek => _s[_i]; + public int Position => _i; + public char Take() => _s[_i++]; + + public void SkipWhitespace() + { + while (!End && char.IsWhiteSpace(Peek)) + { + Take(); + } + } + + public bool TakeIf(char c) + { + if (Peek == c) + { + Take(); + return true; + } + else + { + return false; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs b/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs new file mode 100644 index 0000000000..b2d73ab8fc --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Plugins/AvaloniaPropertyAccessorPlugin.cs @@ -0,0 +1,118 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Reactive.Linq; +using Avalonia.Data; +using Avalonia.Logging; + +namespace Avalonia.Markup.Data.Plugins +{ + /// + /// Reads a property from a . + /// + public class AvaloniaPropertyAccessorPlugin : IPropertyAccessorPlugin + { + /// + /// Checks whether this plugin can handle accessing the properties of the specified object. + /// + /// A weak reference to the object. + /// True if the plugin can handle the object; otherwise false. + public bool Match(WeakReference reference) + { + Contract.Requires(reference != null); + + return reference.Target is AvaloniaObject; + } + + /// + /// Starts monitoring the value of a property on an object. + /// + /// A weak reference to the object. + /// The property name. + /// A function to call when the property changes. + /// + /// An interface through which future interactions with the + /// property will be made. + /// + public IPropertyAccessor Start( + WeakReference reference, + string propertyName, + Action changed) + { + Contract.Requires(reference != null); + Contract.Requires(propertyName != null); + Contract.Requires(changed != null); + + var instance = reference.Target; + var o = (AvaloniaObject)instance; + var p = AvaloniaPropertyRegistry.Instance.FindRegistered(o, propertyName); + + if (p != null) + { + return new Accessor(new WeakReference(o), p, changed); + } + else if (instance != AvaloniaProperty.UnsetValue) + { + var message = $"Could not find AvaloniaProperty '{propertyName}' on '{instance}'"; + var exception = new MissingMemberException(message); + return new PropertyError(new BindingError(exception)); + } + else + { + return null; + } + } + + private class Accessor : IPropertyAccessor + { + private readonly WeakReference _reference; + private readonly AvaloniaProperty _property; + private IDisposable _subscription; + + public Accessor( + WeakReference reference, + AvaloniaProperty property, + Action changed) + { + Contract.Requires(reference != null); + Contract.Requires(property != null); + + _reference = reference; + _property = property; + _subscription = Instance.GetWeakObservable(property).Skip(1).Subscribe(changed); + } + + public AvaloniaObject Instance + { + get + { + AvaloniaObject result; + _reference.TryGetTarget(out result); + return result; + } + } + + public Type PropertyType => _property.PropertyType; + + public object Value => Instance.GetValue(_property); + + public void Dispose() + { + _subscription?.Dispose(); + _subscription = null; + } + + public bool SetValue(object value, BindingPriority priority) + { + if (!_property.IsReadOnly) + { + Instance.SetValue(_property, value, priority); + return true; + } + + return false; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/ExceptionValidationCheckerPlugin.cs b/src/Markup/Avalonia.Markup/Data/Plugins/ExceptionValidationCheckerPlugin.cs new file mode 100644 index 0000000000..07a8a23df6 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Plugins/ExceptionValidationCheckerPlugin.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Data; + +namespace Avalonia.Markup.Data.Plugins +{ + /// + /// Validates properties that report errors by throwing exceptions. + /// + public class ExceptionValidationCheckerPlugin : IValidationCheckerPlugin + { + + /// + public bool Match(WeakReference reference) => true; + + + /// + public ValidationCheckerBase Start(WeakReference reference, string name, IPropertyAccessor accessor, Action callback) + { + return new ExceptionValidationChecker(reference, name, accessor, callback); + } + + private class ExceptionValidationChecker : ValidationCheckerBase + { + public ExceptionValidationChecker(WeakReference reference, string name, IPropertyAccessor accessor, Action callback) + : base(reference, name, accessor, callback) + { + } + + public override bool SetValue(object value, BindingPriority priority) + { + try + { + var success = base.SetValue(value, priority); + SendValidationCallback(new ExceptionValidationStatus(null)); + return success; + } + catch (Exception ex) + { + SendValidationCallback(new ExceptionValidationStatus(ex)); + } + return false; + } + } + + /// + /// Describes the current validation status after setting a property value. + /// + public class ExceptionValidationStatus : ValidationStatus + { + internal ExceptionValidationStatus(Exception exception) + { + Exception = exception; + } + + /// + /// The thrown exception. If there was no thrown exception, null. + /// + public Exception Exception { get; } + + + /// + public override bool IsValid => Exception == null; + + public override bool Match(ValidationMethods enabledMethods) + { + return (enabledMethods & ValidationMethods.Exceptions) != 0; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessor.cs b/src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessor.cs new file mode 100644 index 0000000000..d9da4b906f --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessor.cs @@ -0,0 +1,39 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Data; + +namespace Avalonia.Markup.Data.Plugins +{ + /// + /// Defines an accessor to a property on an object returned by a + /// + /// + public interface IPropertyAccessor : IDisposable + { + /// + /// Gets the type of the property. + /// + Type PropertyType { get; } + + /// + /// Gets the current value of the property. + /// + object Value { get; } + + /// + /// Sets the property value. + /// + /// + /// The value to set. Guaranteed to be of a valid type for the property. + /// + /// + /// The priority with which to set the value. + /// + /// + /// True if the property was set; false if the property could not be set. + /// + bool SetValue(object value, BindingPriority priority); + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessorPlugin.cs b/src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessorPlugin.cs new file mode 100644 index 0000000000..0d6b57e424 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Plugins/IPropertyAccessorPlugin.cs @@ -0,0 +1,37 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections; + +namespace Avalonia.Markup.Data.Plugins +{ + /// + /// Defines how a member is read, written and observed by an + /// . + /// + public interface IPropertyAccessorPlugin + { + /// + /// Checks whether this plugin can handle accessing the properties of the specified object. + /// + /// A weak reference to the object. + /// True if the plugin can handle the object; otherwise false. + bool Match(WeakReference reference); + + /// + /// Starts monitoring the value of a property on an object. + /// + /// A weak reference to the object. + /// The property name. + /// A function to call when the property changes. + /// + /// An interface through which future interactions with the + /// property will be made. + /// + IPropertyAccessor Start( + WeakReference reference, + string propertyName, + Action changed); + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/IValidationCheckerPlugin.cs b/src/Markup/Avalonia.Markup/Data/Plugins/IValidationCheckerPlugin.cs new file mode 100644 index 0000000000..ace63f1c15 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Plugins/IValidationCheckerPlugin.cs @@ -0,0 +1,36 @@ +using Avalonia.Data; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Markup.Data.Plugins +{ + /// + /// Defines how view model data validation is observed by an . + /// + public interface IValidationCheckerPlugin + { + + /// + /// Checks whether the data uses a validation scheme supported by this plugin. + /// + /// A weak reference to the data. + /// true if this plugin can observe the validation; otherwise, false. + bool Match(WeakReference reference); + + /// + /// Starts monitering the validation state of an object for the given property. + /// + /// A weak reference to the object. + /// The property name. + /// An underlying to access the property. + /// A function to call when the validation state changes. + /// + /// A subclass through which future interactions with the + /// property will be made. + /// + ValidationCheckerBase Start(WeakReference reference, string name, IPropertyAccessor accessor, Action callback); + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/IndeiValidationCheckerPlugin.cs b/src/Markup/Avalonia.Markup/Data/Plugins/IndeiValidationCheckerPlugin.cs new file mode 100644 index 0000000000..39297d1283 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Plugins/IndeiValidationCheckerPlugin.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Data; +using System.ComponentModel; +using System.Collections; +using Avalonia.Utilities; + +namespace Avalonia.Markup.Data.Plugins +{ + /// + /// Validates properties on objects that implement . + /// + public class IndeiValidationCheckerPlugin : IValidationCheckerPlugin + { + /// + public bool Match(WeakReference reference) + { + return reference.Target is INotifyDataErrorInfo; + } + + /// + public ValidationCheckerBase Start(WeakReference reference, string name, IPropertyAccessor accessor, Action callback) + { + return new IndeiValidationChecker(reference, name, accessor, callback); + } + + private class IndeiValidationChecker : ValidationCheckerBase, IWeakSubscriber + { + public IndeiValidationChecker(WeakReference reference, string name, IPropertyAccessor accessor, Action callback) + : base(reference, name, accessor, callback) + { + var target = reference.Target as INotifyDataErrorInfo; + if (target != null) + { + if (target.HasErrors) + { + SendValidationCallback(new IndeiValidationStatus(target.GetErrors(name))); + } + WeakSubscriptionManager.Subscribe( + target, + nameof(target.ErrorsChanged), + this); + } + } + + public override void Dispose() + { + base.Dispose(); + var target = _reference.Target as INotifyDataErrorInfo; + if (target != null) + { + WeakSubscriptionManager.Unsubscribe( + target, + nameof(target.ErrorsChanged), + this); + } + } + + public void OnEvent(object sender, DataErrorsChangedEventArgs e) + { + if (e.PropertyName == _name || string.IsNullOrEmpty(e.PropertyName)) + { + var indei = _reference.Target as INotifyDataErrorInfo; + SendValidationCallback(new IndeiValidationStatus(indei.GetErrors(e.PropertyName))); + } + } + } + + /// + /// Describes the current validation status of a property as reported by an object that implements . + /// + public class IndeiValidationStatus : ValidationStatus + { + internal IndeiValidationStatus(IEnumerable errors) + { + Errors = errors; + } + + /// + public override bool IsValid => !Errors.OfType().Any(); + + /// + /// The errors on the given property and on the object as a whole. + /// + public IEnumerable Errors { get; } + + public override bool Match(ValidationMethods enabledMethods) + { + return (enabledMethods & ValidationMethods.INotifyDataErrorInfo) != 0; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs b/src/Markup/Avalonia.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs new file mode 100644 index 0000000000..36046dd742 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs @@ -0,0 +1,144 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.ComponentModel; +using System.Linq; +using System.Reactive.Linq; +using System.Reflection; +using Avalonia.Data; +using Avalonia.Logging; +using Avalonia.Utilities; +using System.Collections; + +namespace Avalonia.Markup.Data.Plugins +{ + /// + /// Reads a property from a standard C# object that optionally supports the + /// interface. + /// + public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin + { + /// + /// Checks whether this plugin can handle accessing the properties of the specified object. + /// + /// The object. + /// True if the plugin can handle the object; otherwise false. + public bool Match(WeakReference reference) + { + Contract.Requires(reference != null); + + return true; + } + + /// + /// Starts monitoring the value of a property on an object. + /// + /// The object. + /// The property name. + /// A function to call when the property changes. + /// + /// An interface through which future interactions with the + /// property will be made. + /// + public IPropertyAccessor Start( + WeakReference reference, + string propertyName, + Action changed) + { + Contract.Requires(reference != null); + Contract.Requires(propertyName != null); + Contract.Requires(changed != null); + + var instance = reference.Target; + var p = instance.GetType().GetRuntimeProperties().FirstOrDefault(_ => _.Name == propertyName); + + if (p != null) + { + return new Accessor(reference, p, changed); + } + else + { + var message = $"Could not find CLR property '{propertyName}' on '{instance}'"; + var exception = new MissingMemberException(message); + return new PropertyError(new BindingError(exception)); + } + } + + private class Accessor : IPropertyAccessor, IWeakSubscriber + { + private readonly WeakReference _reference; + private readonly PropertyInfo _property; + private readonly Action _changed; + + public Accessor( + WeakReference reference, + PropertyInfo property, + Action changed) + { + Contract.Requires(reference != null); + Contract.Requires(property != null); + + _reference = reference; + _property = property; + _changed = changed; + + var inpc = reference.Target as INotifyPropertyChanged; + + if (inpc != null) + { + WeakSubscriptionManager.Subscribe( + inpc, + nameof(inpc.PropertyChanged), + this); + } + else + { + Logger.Warning( + LogArea.Binding, + this, + "Bound to property {Property} on {Source} which does not implement INotifyPropertyChanged", + property.Name, + reference.Target, + reference.Target.GetType()); + } + } + + public Type PropertyType => _property.PropertyType; + + public object Value => _property.GetValue(_reference.Target); + + public void Dispose() + { + var inpc = _reference.Target as INotifyPropertyChanged; + + if (inpc != null) + { + WeakSubscriptionManager.Unsubscribe( + inpc, + nameof(inpc.PropertyChanged), + this); + } + } + + public bool SetValue(object value, BindingPriority priority) + { + if (_property.CanWrite) + { + _property.SetValue(_reference.Target, value); + return true; + } + + return false; + } + + void IWeakSubscriber.OnEvent(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == _property.Name || string.IsNullOrEmpty(e.PropertyName)) + { + _changed(Value); + } + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/PropertyError.cs b/src/Markup/Avalonia.Markup/Data/Plugins/PropertyError.cs new file mode 100644 index 0000000000..f73bb1fc94 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Plugins/PropertyError.cs @@ -0,0 +1,39 @@ +using System; +using Avalonia.Data; + +namespace Avalonia.Markup.Data.Plugins +{ + /// + /// An that represents an error. + /// + public class PropertyError : IPropertyAccessor + { + private BindingError _error; + + /// + /// Initializes a new instance of the class. + /// + /// The error to report. + public PropertyError(BindingError error) + { + _error = error; + } + + /// + public Type PropertyType => null; + + /// + public object Value => _error; + + /// + public void Dispose() + { + } + + /// + public bool SetValue(object value, BindingPriority priority) + { + return false; + } + } +} diff --git a/src/Markup/Avalonia.Markup/Data/Plugins/ValidationCheckerBase.cs b/src/Markup/Avalonia.Markup/Data/Plugins/ValidationCheckerBase.cs new file mode 100644 index 0000000000..0f3669eaf7 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/Plugins/ValidationCheckerBase.cs @@ -0,0 +1,34 @@ +using System; +using Avalonia.Data; + +namespace Avalonia.Markup.Data.Plugins +{ + public abstract class ValidationCheckerBase : IPropertyAccessor + { + protected readonly WeakReference _reference; + protected readonly string _name; + private readonly IPropertyAccessor _accessor; + private readonly Action _callback; + + protected ValidationCheckerBase(WeakReference reference, string name, IPropertyAccessor accessor, Action callback) + { + _reference = reference; + _name = name; + _accessor = accessor; + _callback = callback; + } + + public Type PropertyType => _accessor.PropertyType; + + public object Value => _accessor.Value; + + public virtual void Dispose() => _accessor.Dispose(); + + public virtual bool SetValue(object value, BindingPriority priority) => _accessor.SetValue(value, priority); + + protected void SendValidationCallback(ValidationStatus status) + { + _callback?.Invoke(status); + } + } +} \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup/Data/PropertyAccessorNode.cs b/src/Markup/Avalonia.Markup/Data/PropertyAccessorNode.cs new file mode 100644 index 0000000000..e6095640b3 --- /dev/null +++ b/src/Markup/Avalonia.Markup/Data/PropertyAccessorNode.cs @@ -0,0 +1,132 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Linq; +using System.Reactive.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using Avalonia.Data; +using Avalonia.Markup.Data.Plugins; + +namespace Avalonia.Markup.Data +{ + internal class PropertyAccessorNode : ExpressionNode + { + private IPropertyAccessor _accessor; + private IDisposable _subscription; + + public PropertyAccessorNode(string propertyName) + { + PropertyName = propertyName; + } + + public string PropertyName { get; } + + public Type PropertyType => _accessor?.PropertyType; + + public override bool SetValue(object value, BindingPriority priority) + { + if (Next != null) + { + return Next.SetValue(value, priority); + } + else + { + if (_accessor != null) + { + return _accessor.SetValue(value, priority); + } + + return false; + } + } + + protected override void SubscribeAndUpdate(WeakReference reference) + { + var instance = reference.Target; + + if (instance != null && instance != AvaloniaProperty.UnsetValue) + { + var accessorPlugin = ExpressionObserver.PropertyAccessors.FirstOrDefault(x => x.Match(reference)); + + if (accessorPlugin != null) + { + _accessor = accessorPlugin.Start(reference, PropertyName, SetCurrentValue); + foreach (var validationPlugin in ExpressionObserver.ValidationCheckers.Where(x => x.Match(reference))) + { + if (validationPlugin != null) + { + _accessor = validationPlugin.Start(reference, PropertyName, _accessor, SendValidationStatus); + } + } + + if (_accessor != null) + { + SetCurrentValue(_accessor.Value); + return; + } + } + } + + CurrentValue = UnsetReference; + } + + protected override void Unsubscribe(object target) + { + _accessor?.Dispose(); + _accessor = null; + } + + private void SetCurrentValue(object value) + { + var observable = value as IObservable; + var command = value as ICommand; + var task = value as Task; + bool set = false; + + // HACK: ReactiveCommand is an IObservable but we want to bind to it, not its value. + // We may need to make this a more general solution. + if (observable != null && command == null) + { + CurrentValue = UnsetReference; + set = true; + _subscription = observable + .ObserveOn(SynchronizationContext.Current) + .Subscribe(x => CurrentValue = new WeakReference(x)); + } + else if (task != null) + { + var resultProperty = task.GetType().GetTypeInfo().GetDeclaredProperty("Result"); + + if (resultProperty != null) + { + if (task.Status == TaskStatus.RanToCompletion) + { + CurrentValue = new WeakReference(resultProperty.GetValue(task)); + set = true; + } + else + { + task.ContinueWith( + x => CurrentValue = new WeakReference(resultProperty.GetValue(task)), + TaskScheduler.FromCurrentSynchronizationContext()) + .ConfigureAwait(false); + } + } + } + else + { + CurrentValue = new WeakReference(value); + set = true; + } + + if (!set) + { + CurrentValue = UnsetReference; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/DefaultValueConverter.cs b/src/Markup/Avalonia.Markup/DefaultValueConverter.cs new file mode 100644 index 0000000000..469b00d3ad --- /dev/null +++ b/src/Markup/Avalonia.Markup/DefaultValueConverter.cs @@ -0,0 +1,95 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using System.Linq; +using System.Reflection; +using Avalonia.Data; +using Avalonia.Logging; +using Avalonia.Utilities; + +namespace Avalonia.Markup +{ + /// + /// Provides a default set of value conversions for bindings that do not specify a value + /// converter. + /// + public class DefaultValueConverter : IValueConverter + { + /// + /// Gets an instance of a . + /// + public static readonly DefaultValueConverter Instance = new DefaultValueConverter(); + + /// + /// Converts a value. + /// + /// The value to convert. + /// The type of the target. + /// A user-defined parameter. + /// The culture to use. + /// The converted value. + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + object result; + + if (value != null && + (TypeUtilities.TryConvert(targetType, value, culture, out result) || + TryConvertEnum(value, targetType, culture, out result))) + { + return result; + } + + if (value != null) + { + var message = $"Could not convert '{value}' to '{targetType}'"; + return new BindingError(new InvalidCastException(message)); + } + + return AvaloniaProperty.UnsetValue; + } + + /// + /// Converts a value. + /// + /// The value to convert. + /// The type of the target. + /// A user-defined parameter. + /// The culture to use. + /// The converted value. + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return Convert(value, targetType, parameter, culture); + } + + private bool TryConvertEnum(object value, Type targetType, CultureInfo cultur, out object result) + { + var valueTypeInfo = value.GetType().GetTypeInfo(); + var targetTypeInfo = targetType.GetTypeInfo(); + + if (valueTypeInfo.IsEnum && !targetTypeInfo.IsEnum) + { + var enumValue = (int)value; + + if (TypeUtilities.TryCast(targetType, enumValue, out result)) + { + return true; + } + } + else if (!valueTypeInfo.IsEnum && targetTypeInfo.IsEnum) + { + object intValue; + + if (TypeUtilities.TryCast(typeof(int), value, out intValue)) + { + result = Enum.ToObject(targetType, intValue); + return true; + } + } + + result = null; + return false; + } + } +} diff --git a/src/Markup/Avalonia.Markup/FuncMultiValueConverter.cs b/src/Markup/Avalonia.Markup/FuncMultiValueConverter.cs new file mode 100644 index 0000000000..75aace0bd9 --- /dev/null +++ b/src/Markup/Avalonia.Markup/FuncMultiValueConverter.cs @@ -0,0 +1,45 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace Avalonia.Markup +{ + /// + /// A general purpose that uses a + /// to provide the converter logic. + /// + /// The type of the inputs. + /// The output type. + public class FuncMultiValueConverter : IMultiValueConverter + { + private readonly Func, TOut> _convert; + + /// + /// Initializes a new instance of the class. + /// + /// The convert function. + public FuncMultiValueConverter(Func, TOut> convert) + { + _convert = convert; + } + + /// + public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) + { + var converted = values.OfType().ToList(); + + if (converted.Count == values.Count) + { + return _convert(converted); + } + else + { + return AvaloniaProperty.UnsetValue; + } + } + } +} diff --git a/src/Markup/Avalonia.Markup/FuncValueConverter.cs b/src/Markup/Avalonia.Markup/FuncValueConverter.cs new file mode 100644 index 0000000000..109de9371d --- /dev/null +++ b/src/Markup/Avalonia.Markup/FuncValueConverter.cs @@ -0,0 +1,48 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using Avalonia.Utilities; + +namespace Avalonia.Markup +{ + /// + /// A general purpose that uses a + /// to provide the converter logic. + /// + /// The input type. + /// The output type. + public class FuncValueConverter : IValueConverter + { + private readonly Func _convert; + + /// + /// Initializes a new instance of the class. + /// + /// The convert function. + public FuncValueConverter(Func convert) + { + _convert = convert; + } + + /// + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is TIn || (value == null && TypeUtilities.AcceptsNull(typeof(TIn)))) + { + return _convert((TIn)value); + } + else + { + return AvaloniaProperty.UnsetValue; + } + } + + /// + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Markup/Avalonia.Markup/IMultiValueConverter.cs b/src/Markup/Avalonia.Markup/IMultiValueConverter.cs new file mode 100644 index 0000000000..be75dabb1c --- /dev/null +++ b/src/Markup/Avalonia.Markup/IMultiValueConverter.cs @@ -0,0 +1,30 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace Avalonia.Markup +{ + /// + /// Converts multi-binding inputs to a final value. + /// + public interface IMultiValueConverter + { + /// + /// Converts multi-binding inputs to a final value. + /// + /// The values to convert. + /// The type of the target. + /// A user-defined parameter. + /// The culture to use. + /// The converted value. + /// + /// This method should not throw exceptions. If the value is not convertible, return + /// . Any exception thrown will be treated as + /// an application exception. + /// + object Convert(IList values, Type targetType, object parameter, CultureInfo culture); + } +} diff --git a/src/Markup/Avalonia.Markup/IValueConverter.cs b/src/Markup/Avalonia.Markup/IValueConverter.cs new file mode 100644 index 0000000000..23117a3fac --- /dev/null +++ b/src/Markup/Avalonia.Markup/IValueConverter.cs @@ -0,0 +1,44 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; + +namespace Avalonia.Markup +{ + /// + /// Converts a binding value. + /// + public interface IValueConverter + { + /// + /// Converts a value. + /// + /// The value to convert. + /// The type of the target. + /// A user-defined parameter. + /// The culture to use. + /// The converted value. + /// + /// This method should not throw exceptions. If the value is not convertible, return + /// . Any exception thrown will be treated as + /// an application exception. + /// + object Convert(object value, Type targetType, object parameter, CultureInfo culture); + + /// + /// Converts a value. + /// + /// The value to convert. + /// The type of the target. + /// A user-defined parameter. + /// The culture to use. + /// The converted value. + /// + /// This method should not throw exceptions. If the value is not convertible, return + /// . Any exception thrown will be treated as + /// an application exception. + /// + object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture); + } +} diff --git a/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs b/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..4d6ccdf31a --- /dev/null +++ b/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System.Reflection; +using Avalonia.Metadata; +using System.Runtime.CompilerServices; + +[assembly: AssemblyTitle("Avalonia.Markup")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup")] +[assembly: InternalsVisibleTo("Avalonia.Markup.UnitTests")] \ No newline at end of file diff --git a/src/Markup/Avalonia.Markup/StringConverters.cs b/src/Markup/Avalonia.Markup/StringConverters.cs new file mode 100644 index 0000000000..fda79c76a3 --- /dev/null +++ b/src/Markup/Avalonia.Markup/StringConverters.cs @@ -0,0 +1,27 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.Globalization; +using Avalonia.Utilities; + +namespace Avalonia.Markup +{ + /// + /// Provides a set of useful s for working with string values. + /// + public static class StringConverters + { + /// + /// A value converter that returns true if the input string is null or an empty string. + /// + public static readonly IValueConverter NullOrEmpty = + new FuncValueConverter(string.IsNullOrEmpty); + + /// + /// A value converter that returns true if the input string is not null or empty. + /// + public static readonly IValueConverter NotNullOrEmpty = + new FuncValueConverter(x => !string.IsNullOrEmpty(x)); + } +} diff --git a/src/Markup/Perspex.Markup/packages.config b/src/Markup/Avalonia.Markup/packages.config similarity index 100% rename from src/Markup/Perspex.Markup/packages.config rename to src/Markup/Avalonia.Markup/packages.config diff --git a/src/Markup/Perspex.Markup.Xaml/Context/NameScopeWrapper.cs b/src/Markup/Perspex.Markup.Xaml/Context/NameScopeWrapper.cs deleted file mode 100644 index 2a5e46825a..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/NameScopeWrapper.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Markup.Xaml.Context -{ - internal class NameScopeWrapper : OmniXaml.INameScope - { - private readonly Perspex.Controls.INameScope _inner; - - public NameScopeWrapper(Perspex.Controls.INameScope inner) - { - _inner = inner; - } - - public object Find(string name) - { - return _inner.Find(name); - } - - public void Register(string name, object scopedElement) - { - _inner.Register(name, scopedElement); - } - - public void Unregister(string name) - { - _inner.Unregister(name); - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexAttachableXamlMember.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexAttachableXamlMember.cs deleted file mode 100644 index 8b48e8e871..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexAttachableXamlMember.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Markup.Xaml.Data; -using OmniXaml; -using OmniXaml.Typing; -using System.Reflection; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexAttachableXamlMember : AttachableMember - { - public PerspexAttachableXamlMember(string name, - XamlType owner, - MethodInfo getter, - MethodInfo setter, - ITypeRepository xamlTypeRepository, - ITypeFeatureProvider featureProvider) - : base(name, getter, setter, xamlTypeRepository, featureProvider) - { - } - - public override string ToString() - { - return "Perspex Attachable XAML Member " + base.ToString(); - } - - protected override IMemberValuePlugin LookupXamlMemberValueConnector() - { - return new PerspexMemberValuePlugin(this); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexContentPropertyProvider.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexContentPropertyProvider.cs deleted file mode 100644 index 590ffde841..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexContentPropertyProvider.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Glass; -using OmniXaml; -using OmniXaml.Builder; -using Perspex.Metadata; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexContentPropertyProvider : IContentPropertyProvider - { - private readonly Dictionary _values = new Dictionary(); - - public string GetContentPropertyName(Type type) - { - string result; - - if (!_values.TryGetValue(type, out result)) - { - result = LookupContentProperty(type); - _values[type] = result; - } - - return result; - } - - private string LookupContentProperty(Type type) - { - var result = (from member in type.GetRuntimeProperties() - let att = member.GetCustomAttribute() - where att != null - select member).FirstOrDefault(); - - return result?.Name; - } - - void IAdd.Add(ContentPropertyDefinition item) - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexLifeCycleListener.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexLifeCycleListener.cs deleted file mode 100644 index 99dfc6e600..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexLifeCycleListener.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using OmniXaml; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexLifeCycleListener : IInstanceLifeCycleListener - { - public void OnAfterProperties(object instance) - { - } - - public void OnAssociatedToParent(object instance) - { - } - - public void OnBegin(object instance) - { - var isi = instance as ISupportInitialize; - isi?.BeginInit(); - } - - public void OnEnd(object instance) - { - var isi = instance as ISupportInitialize; - isi?.EndInit(); - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexMemberValuePlugin.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexMemberValuePlugin.cs deleted file mode 100644 index f4433f6a76..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexMemberValuePlugin.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using OmniXaml.TypeConversion; -using OmniXaml.Typing; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexMemberValuePlugin : MemberValuePlugin - { - private readonly MutableMember _xamlMember; - - public PerspexMemberValuePlugin(MutableMember xamlMember) - : base(xamlMember) - { - _xamlMember = xamlMember; - } - - public override void SetValue(object instance, object value, IValueContext valueContext) - { - PropertyAccessor.SetValue(instance, _xamlMember, value, valueContext); - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexNamespaceRegistry.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexNamespaceRegistry.cs deleted file mode 100644 index 5efc4b2fa0..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexNamespaceRegistry.cs +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using OmniXaml.Builder; -using OmniXaml.Typing; -using Perspex.Controls; -using Perspex.Markup.Xaml.Templates; -using Perspex.Media; -using Perspex.Metadata; -using Perspex.Platform; -using Perspex.Styling; -using Glass.Core; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexNamespaceRegistry : INamespaceRegistry - { - private const string ClrNamespace = "clr-namespace:"; - private const string PerspexNs = "https://github.com/perspex"; - - private static readonly IEnumerable ForcedAssemblies = new[] - { - typeof(PerspexObject).GetTypeInfo().Assembly, - typeof(Control).GetTypeInfo().Assembly, - typeof(Style).GetTypeInfo().Assembly, - typeof(DataTemplate).GetTypeInfo().Assembly, - typeof(SolidColorBrush).GetTypeInfo().Assembly, - typeof(IValueConverter).GetTypeInfo().Assembly, - }; - - private List _clrNamespaces = new List(); - private List _namespaces = new List(); - private Dictionary _prefixes = new Dictionary(); - private List _scanned = new List(); - - public PerspexNamespaceRegistry() - { - ScanAssemblies(ForcedAssemblies); - ScanNewAssemblies(); - RegisterPrefix(new PrefixRegistration(string.Empty, PerspexNs)); - } - - public IEnumerable RegisteredPrefixes => - _prefixes.Select(x => new PrefixRegistration(x.Key, x.Value)); - - public void AddNamespace(XamlNamespace xamlNamespace) - { - _namespaces.Add(xamlNamespace); - } - - public Namespace GetNamespace(string name) - { - Namespace result; - - if (!IsClrNamespace(name)) - { - ScanNewAssemblies(); - result = _namespaces.FirstOrDefault(x => x.Name == name); - - if (result == null) - { - result = _namespaces.FirstOrDefault(x => x.Name == name); - } - } - else - { - result = _clrNamespaces.FirstOrDefault(x => x.Name == name); - - if (result == null) - { - var clr = CreateClrNamespace(name); - _clrNamespaces.Add(clr); - result = clr; - } - } - - return result; - } - - public Namespace GetNamespaceByPrefix(string prefix) - { - string uri; - - if (_prefixes.TryGetValue(prefix, out uri)) - { - return GetNamespace(uri); - } - - return null; - } - - public void RegisterPrefix(PrefixRegistration prefixRegistration) - { - _prefixes[prefixRegistration.Prefix] = prefixRegistration.Ns; - } - - private static bool IsClrNamespace(string ns) - { - return ns.StartsWith(ClrNamespace); - } - - private static ClrNamespace CreateClrNamespace(string formattedClrString) - { - var startOfNamespace = formattedClrString.IndexOf(":", StringComparison.Ordinal) + 1; - var endOfNamespace = formattedClrString.IndexOf(";", startOfNamespace, StringComparison.Ordinal); - - if (endOfNamespace < 0) - { - endOfNamespace = formattedClrString.Length - startOfNamespace; - } - - var ns = formattedClrString.Substring(startOfNamespace, endOfNamespace - startOfNamespace); - - var remainingPartStart = startOfNamespace + ns.Length + 1; - var remainingPartLenght = formattedClrString.Length - remainingPartStart; - var assemblyPart = formattedClrString.Substring(remainingPartStart, remainingPartLenght); - - var assembly = GetAssembly(assemblyPart); - - return new ClrNamespace(assembly, ns); - } - - private static Assembly GetAssembly(string assemblyPart) - { - var dicotomize = assemblyPart.Dicotomize('='); - return Assembly.Load(new AssemblyName(dicotomize.Item2)); - } - - private void ScanAssemblies(IEnumerable assemblies) - { - foreach (var assembly in assemblies) - { - var namespaces = assembly.GetCustomAttributes() - .Select(x => new { x.XmlNamespace, x.ClrNamespace }) - .GroupBy(x => x.XmlNamespace); - - foreach (var nsa in namespaces) - { - var xamlNamespace = _namespaces.FirstOrDefault(x => x.Name == nsa.Key); - - if (xamlNamespace == null) - { - xamlNamespace = new XamlNamespace(nsa.Key); - _namespaces.Add(xamlNamespace); - } - - var clrNamespaces = nsa.Select(x => x.ClrNamespace); - xamlNamespace.Addresses.Add(new ConfiguredAssemblyWithNamespaces(assembly, clrNamespaces)); - } - - _scanned.Add(assembly); - } - } - - private void ScanNewAssemblies() - { - IEnumerable assemblies = PerspexLocator.Current - .GetService() - ?.GetLoadedAssemblies(); - - if (assemblies != null) - { - assemblies = assemblies.Except(_scanned); - ScanAssemblies(assemblies); - } - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs deleted file mode 100644 index 7e4320be93..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexObjectAssembler.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using OmniXaml; -using OmniXaml.ObjectAssembler; -using OmniXaml.ObjectAssembler.Commands; -using OmniXaml.TypeConversion; -using Perspex.Markup.Xaml.Templates; -using System.Collections.Generic; -using System.Collections.ObjectModel; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexObjectAssembler : IObjectAssembler - { - private readonly TemplateHostingObjectAssembler objectAssembler; - private readonly ObjectAssembler assembler; - - public PerspexObjectAssembler( - IRuntimeTypeSource typeSource, - ITopDownValueContext topDownValueContext, - Settings settings = null) - { - var mapping = new DeferredLoaderMapping(); - mapping.Map(x => x.Content, new TemplateLoader()); - mapping.Map(x => x.Content, new TemplateLoader()); - mapping.Map(x => x.Content, new TemplateLoader()); - mapping.Map(x => x.Content, new TemplateLoader()); - mapping.Map(x => x.Content, new TemplateLoader()); - - var parsingDictionary = GetDictionary(settings); - var valueContext = new ValueContext(typeSource, topDownValueContext, parsingDictionary); - assembler = new ObjectAssembler(typeSource, valueContext, settings); - objectAssembler = new TemplateHostingObjectAssembler(assembler, mapping); - } - - - public object Result => objectAssembler.Result; - - public EventHandler XamlSetValueHandler { get; set; } - - public IRuntimeTypeSource TypeSource => assembler.TypeSource; - - public ITopDownValueContext TopDownValueContext => assembler.TopDownValueContext; - - public IInstanceLifeCycleListener LifecycleListener - { - get { throw new NotImplementedException(); } - } - - public void Process(Instruction node) - { - objectAssembler.Process(node); - } - - public void OverrideInstance(object instance) - { - objectAssembler.OverrideInstance(instance); - } - - private static IReadOnlyDictionary GetDictionary(Settings settings) - { - IReadOnlyDictionary dict; - - if (settings != null) - { - dict = settings.ParsingContext; - } - else - { - dict = new ReadOnlyDictionary(new Dictionary()); - } - - return dict; - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexParserFactory.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexParserFactory.cs deleted file mode 100644 index 6f7a6574a1..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexParserFactory.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using OmniXaml; -using OmniXaml.ObjectAssembler; -using OmniXaml.Parsers.Parser; -using OmniXaml.Parsers.ProtoParser; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexParserFactory : IParserFactory - { - private readonly IRuntimeTypeSource runtimeTypeSource; - - public PerspexParserFactory() - : this(new TypeFactory()) - { - } - - public PerspexParserFactory(ITypeFactory typeFactory) - { - runtimeTypeSource = new PerspexRuntimeTypeSource(typeFactory); - } - - public IParser Create(Settings settings) - { - var xamlInstructionParser = new OrderAwareInstructionParser(new InstructionParser(runtimeTypeSource)); - - IObjectAssembler objectAssembler = new PerspexObjectAssembler( - runtimeTypeSource, - new TopDownValueContext(), - settings); - var phaseParserKit = new PhaseParserKit( - new ProtoInstructionParser(runtimeTypeSource), - xamlInstructionParser, - objectAssembler); - - return new XmlParser(phaseParserKit); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexRuntimeTypeSource.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexRuntimeTypeSource.cs deleted file mode 100644 index f27aa226d8..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexRuntimeTypeSource.cs +++ /dev/null @@ -1,91 +0,0 @@ -namespace Perspex.Markup.Xaml.Context -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - using Collections; - using Controls; - using Controls.Primitives; - using Controls.Templates; - using Converters; - using Data; - using Glass; - using Input; - using Media; - using Media.Imaging; - using Metadata; - using OmniXaml; - using OmniXaml.Builder; - using OmniXaml.TypeConversion; - using OmniXaml.Typing; - using Perspex.Styling; - using Platform; - using Templates; - - public class PerspexRuntimeTypeSource : IRuntimeTypeSource - { - private readonly RuntimeTypeSource inner; - - public PerspexRuntimeTypeSource(ITypeFactory typeFactory) - { - var namespaceRegistry = new PerspexNamespaceRegistry(); - var featureProvider = new PerspexTypeFeatureProvider(); - var typeRepository = new PerspexTypeRepository(namespaceRegistry, typeFactory, featureProvider); - - inner = new RuntimeTypeSource(typeRepository, namespaceRegistry); - } - - public Namespace GetNamespace(string name) - { - return inner.GetNamespace(name); - } - - public Namespace GetNamespaceByPrefix(string prefix) - { - return inner.GetNamespaceByPrefix(prefix); - } - - public void RegisterPrefix(PrefixRegistration prefixRegistration) - { - inner.RegisterPrefix(prefixRegistration); - } - - public void AddNamespace(XamlNamespace xamlNamespace) - { - inner.AddNamespace(xamlNamespace); - } - - public IEnumerable RegisteredPrefixes => inner.RegisteredPrefixes; - - public XamlType GetByType(Type type) - { - return inner.GetByType(type); - } - - public XamlType GetByQualifiedName(string qualifiedName) - { - return inner.GetByQualifiedName(qualifiedName); - } - - public XamlType GetByPrefix(string prefix, string typeName) - { - return inner.GetByPrefix(prefix, typeName); - } - - public XamlType GetByFullAddress(XamlTypeName xamlTypeName) - { - return inner.GetByFullAddress(xamlTypeName); - } - - public Member GetMember(PropertyInfo propertyInfo) - { - return inner.GetMember(propertyInfo); - } - - public AttachableMember GetAttachableMember(string name, MethodInfo getter, MethodInfo setter) - { - return inner.GetAttachableMember(name, getter, setter); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeFeatureProvider.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeFeatureProvider.cs deleted file mode 100644 index 66e1d810f5..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeFeatureProvider.cs +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using OmniXaml; -using OmniXaml.Builder; -using OmniXaml.TypeConversion; -using OmniXaml.TypeConversion.BuiltInConverters; -using OmniXaml.Typing; -using Perspex.Collections; -using Perspex.Controls; -using Perspex.Controls.Templates; -using Perspex.Input; -using Perspex.Markup.Xaml.Converters; -using Perspex.Media; -using Perspex.Media.Imaging; -using Perspex.Metadata; -using Perspex.Styling; -using OmniMetadata = OmniXaml.Typing.Metadata; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexTypeFeatureProvider : ITypeFeatureProvider - { - private Dictionary _metadata = - new Dictionary(); - - private Dictionary _typeConverters = - new Dictionary(); - - public IEnumerable TypeConverters => _typeConverters.Values; - - public PerspexTypeFeatureProvider() - { - RegisterTypeConverters(); - } - - public string GetContentPropertyName(Type type) - { - return GetMetadata(type)?.ContentProperty; - } - - public OmniMetadata GetMetadata(Type type) - { - OmniMetadata result; - - if (!_metadata.TryGetValue(type, out result)) - { - result = LoadMetadata(type); - _metadata.Add(type, result); - } - - return result; - } - - public ITypeConverter GetTypeConverter(Type type) - { - TypeConverterRegistration result; - _typeConverters.TryGetValue(type, out result); - return result?.TypeConverter; - } - - public void RegisterMetadata(Type type, OmniMetadata metadata) - { - _metadata.Add(type, metadata); - } - - public void RegisterTypeConverter(Type type, ITypeConverter converter) - { - _typeConverters.Add(type, new TypeConverterRegistration(type, converter)); - } - - private static OmniMetadata LoadMetadata(Type type) - { - return new OmniMetadata - { - ContentProperty = GetContentProperty(type), - PropertyDependencies = GetPropertyDependencies(type), - RuntimePropertyName = type.GetRuntimeProperty("Name")?.Name, - }; - } - - private static string GetContentProperty(Type type) - { - while (type != null) - { - var properties = type.GetTypeInfo().DeclaredProperties - .Where(x => x.GetCustomAttribute() != null); - string result = null; - - foreach (var property in properties) - { - if (result != null) - { - throw new Exception($"Content property defined more than once on {type}."); - } - - result = property.Name; - } - - if (result != null) - { - return result; - } - - type = type.GetTypeInfo().BaseType; - } - - return null; - } - - private static DependencyRegistrations GetPropertyDependencies(Type type) - { - var result = new List(); - - while (type != null) - { - var registrations = type.GetTypeInfo().DeclaredProperties - .Select(x => new - { - Property = x.Name, - Attributes = x.GetCustomAttributes(), - }) - .Where(x => x.Attributes.Any()) - .SelectMany(x => x.Attributes.Select(y => new DependencyRegistration(x.Property, y.Name))); - - result.AddRange(registrations); - type = type.GetTypeInfo().BaseType; - } - - return result.Count > 0 ? new DependencyRegistrations(result) : null; - } - - private void RegisterTypeConverters() - { - // HACK: For now these are hard-coded. Hopefully when the .NET Standard Platform - // is available we can use the System.ComponentModel.TypeConverters so don't want to - // spend time for now inventing a mechanism to register type converters if it's all - // going to change. - RegisterTypeConverter(typeof(string), new StringTypeConverter()); - RegisterTypeConverter(typeof(int), new IntTypeConverter()); - RegisterTypeConverter(typeof(long), new IntTypeConverter()); - RegisterTypeConverter(typeof(short), new IntTypeConverter()); - RegisterTypeConverter(typeof(double), new DoubleTypeConverter()); - RegisterTypeConverter(typeof(float), new IntTypeConverter()); - RegisterTypeConverter(typeof(bool), new BooleanConverter()); - RegisterTypeConverter(typeof(Type), new TypeTypeConverter()); - - RegisterTypeConverter(typeof(IBitmap), new BitmapTypeConverter()); - RegisterTypeConverter(typeof(IBrush), new BrushTypeConverter()); - RegisterTypeConverter(typeof(Color), new ColorTypeConverter()); - RegisterTypeConverter(typeof(Classes), new ClassesTypeConverter()); - RegisterTypeConverter(typeof(ColumnDefinitions), new ColumnDefinitionsTypeConverter()); - RegisterTypeConverter(typeof(Geometry), new GeometryTypeConverter()); - RegisterTypeConverter(typeof(GridLength), new GridLengthTypeConverter()); - RegisterTypeConverter(typeof(KeyGesture), new KeyGestureConverter()); - RegisterTypeConverter(typeof(PerspexList), new PerspexListTypeConverter()); - RegisterTypeConverter(typeof(IMemberSelector), new MemberSelectorTypeConverter()); - RegisterTypeConverter(typeof(Point), new PointTypeConverter()); - RegisterTypeConverter(typeof(IList), new PointsListTypeConverter()); - RegisterTypeConverter(typeof(PerspexProperty), new PerspexPropertyTypeConverter()); - RegisterTypeConverter(typeof(RelativePoint), new RelativePointTypeConverter()); - RegisterTypeConverter(typeof(RelativeRect), new RelativeRectTypeConverter()); - RegisterTypeConverter(typeof(RowDefinitions), new RowDefinitionsTypeConverter()); - RegisterTypeConverter(typeof(Size), new SizeTypeConverter()); - RegisterTypeConverter(typeof(Selector), new SelectorTypeConverter()); - RegisterTypeConverter(typeof(SolidColorBrush), new BrushTypeConverter()); - RegisterTypeConverter(typeof(Thickness), new ThicknessTypeConverter()); - RegisterTypeConverter(typeof(TimeSpan), new TimeSpanTypeConverter()); - RegisterTypeConverter(typeof(Uri), new UriTypeConverter()); - RegisterTypeConverter(typeof(Cursor), new CursorTypeConverter()); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeRepository.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeRepository.cs deleted file mode 100644 index 4bcb7a20a6..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexTypeRepository.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using OmniXaml; -using OmniXaml.Typing; -using Glass.Core; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexTypeRepository : TypeRepository - { - private readonly ITypeFactory _typeFactory; - - public PerspexTypeRepository(INamespaceRegistry xamlNamespaceRegistry, - ITypeFactory typeFactory, - ITypeFeatureProvider featureProvider) : base(xamlNamespaceRegistry, typeFactory, featureProvider) - { - _typeFactory = typeFactory; - } - - public override XamlType GetByType(Type type) - { - Guard.ThrowIfNull(type, nameof(type)); - return new PerspexXamlType(type, this, _typeFactory, FeatureProvider); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs deleted file mode 100644 index 45e3e7285d..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Linq; -using System.Reflection; -using Glass; -using OmniXaml; -using OmniXaml.Builder; -using OmniXaml.TypeConversion; -using OmniXaml.Typing; -using Perspex.Collections; -using Perspex.Controls; -using Perspex.Controls.Primitives; -using Perspex.Controls.Templates; -using Perspex.Input; -using Perspex.Markup.Xaml.Converters; -using Perspex.Markup.Xaml.Data; -using Perspex.Media; -using Perspex.Media.Imaging; -using Perspex.Metadata; -using Perspex.Platform; -using Perspex.Styling; -using System.Collections.Generic; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexWiringContext : WiringContext - { - private const string PerspexNs = "https://github.com/perspex"; - - public PerspexWiringContext(ITypeFactory typeFactory) - : this(typeFactory, new TypeFeatureProvider(GetContentPropertyProvider(), GetConverterProvider())) - { - } - - public PerspexWiringContext(ITypeFactory typeFactory, TypeFeatureProvider featureProvider) - : base(CreateTypeContext(typeFactory, featureProvider), featureProvider) - { - } - - private static ITypeContext CreateTypeContext(ITypeFactory typeFactory, TypeFeatureProvider featureProvider) - { - var xamlNamespaceRegistry = CreateXamlNamespaceRegistry(); - var typeRepository = new PerspexTypeRepository(xamlNamespaceRegistry, typeFactory, featureProvider); - - typeRepository.RegisterMetadata(new GenericMetadata().WithRuntimeNameProperty(d => d.Name)); - typeRepository.RegisterMetadata(new GenericMetadata().WithMemberDependency(x => x.Value, x => x.Property)); - typeRepository.RegisterMetadata( - new GenericMetadata() - .WithMemberDependency(x => x.SelectedIndex, x => x.Items) - .WithMemberDependency(x => x.SelectedItem, x => x.Items)); - - return new TypeContext(typeRepository, xamlNamespaceRegistry, typeFactory); - } - - private static XamlNamespaceRegistry CreateXamlNamespaceRegistry() - { - var xamlNamespaceRegistry = new XamlNamespaceRegistry(); - - var forcedAssemblies = new[] - { - typeof(Binding), - typeof(Control), - typeof(IValueConverter), - typeof(Style), - }.Select(t => t.GetTypeInfo().Assembly); - - foreach (var nsa in - forcedAssemblies - .Concat(PerspexLocator.Current.GetService().GetLoadedAssemblies()) - .Distinct() - .SelectMany(asm - => asm.GetCustomAttributes().Select(attr => new {asm, attr})) - .GroupBy(entry => entry.attr.XmlNamespace)) - { - var def = XamlNamespace.Map(nsa.Key) - .With(nsa.GroupBy(x => x.asm).Select( - a => Route.Assembly(a.Key) - .WithNamespaces(a.Select(entry => entry.attr.ClrNamespace).ToList()) - )); - xamlNamespaceRegistry.AddNamespace(def); - } - xamlNamespaceRegistry.RegisterPrefix(new PrefixRegistration(string.Empty, PerspexNs)); - - return xamlNamespaceRegistry; - } - - private static ITypeConverterProvider GetConverterProvider() - { - var typeConverterProvider = new TypeConverterProvider(); - var converters = new[] - { - new TypeConverterRegistration(typeof(IBitmap), new BitmapTypeConverter()), - new TypeConverterRegistration(typeof(Brush), new BrushTypeConverter()), - new TypeConverterRegistration(typeof(Color), new ColorTypeConverter()), - new TypeConverterRegistration(typeof(Classes), new ClassesTypeConverter()), - new TypeConverterRegistration(typeof(ColumnDefinitions), new ColumnDefinitionsTypeConverter()), - new TypeConverterRegistration(typeof(Geometry), new GeometryTypeConverter()), - new TypeConverterRegistration(typeof(GridLength), new GridLengthTypeConverter()), - new TypeConverterRegistration(typeof(KeyGesture), new KeyGestureConverter()), - new TypeConverterRegistration(typeof(PerspexList), new PerspexListTypeConverter()), - new TypeConverterRegistration(typeof(IMemberSelector), new MemberSelectorTypeConverter()), - new TypeConverterRegistration(typeof(Point), new PointTypeConverter()), - new TypeConverterRegistration(typeof(IList), new PointsListTypeConverter()), - new TypeConverterRegistration(typeof(PerspexProperty), new PerspexPropertyTypeConverter()), - new TypeConverterRegistration(typeof(RelativePoint), new RelativePointTypeConverter()), - new TypeConverterRegistration(typeof(RelativeRect), new RelativeRectTypeConverter()), - new TypeConverterRegistration(typeof(RowDefinitions), new RowDefinitionsTypeConverter()), - new TypeConverterRegistration(typeof(Selector), new SelectorTypeConverter()), - new TypeConverterRegistration(typeof(Thickness), new ThicknessTypeConverter()), - new TypeConverterRegistration(typeof(TimeSpan), new TimeSpanTypeConverter()), - new TypeConverterRegistration(typeof(Uri), new UriTypeConverter()), - new TypeConverterRegistration(typeof(Cursor), new CursorTypeConverter()) - }; - - typeConverterProvider.AddAll(converters); - return typeConverterProvider; - } - - private static IContentPropertyProvider GetContentPropertyProvider() - { - return new PerspexContentPropertyProvider(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMember.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMember.cs deleted file mode 100644 index b7e85d73ab..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlMember.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Markup.Xaml.Data; -using OmniXaml; -using OmniXaml.Typing; -using System; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexXamlMember : Member - { - public PerspexXamlMember(string name, - XamlType owner, - ITypeRepository xamlTypeRepository, - ITypeFeatureProvider featureProvider) - : base(name, owner, xamlTypeRepository, featureProvider) - { - } - - protected override IMemberValuePlugin LookupXamlMemberValueConnector() - { - return new PerspexMemberValuePlugin(this); - } - - public override string ToString() - { - return "Perspex XAML Member " + base.ToString(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs b/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs deleted file mode 100644 index 287e9505ef..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PerspexXamlType.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reflection; -using OmniXaml; -using OmniXaml.Typing; -using Perspex.Controls; - -namespace Perspex.Markup.Xaml.Context -{ - public class PerspexXamlType : XamlType - { - public PerspexXamlType(Type type, - ITypeRepository typeRepository, - ITypeFactory typeFactory, - ITypeFeatureProvider featureProvider) : base(type, typeRepository, typeFactory, featureProvider) - { - } - - public override OmniXaml.INameScope GetNamescope(object instance) - { - var result = instance as OmniXaml.INameScope; - - if (result == null) - { - var control = instance as Control; - - if (control != null) - { - var perspexNs = (instance as Perspex.Controls.INameScope) ?? NameScope.GetNameScope(control); - - if (perspexNs != null) - { - result = new NameScopeWrapper(perspexNs); - } - } - } - - return result; - } - - protected override Member LookupMember(string name) - { - return new PerspexXamlMember(name, this, TypeRepository, FeatureProvider); - } - - protected override AttachableMember LookupAttachableMember(string name) - { - // OmniXAML seems to require a getter and setter even though we don't use them. - var getter = UnderlyingType.GetTypeInfo().GetDeclaredMethod("Get" + name); - var setter = UnderlyingType.GetTypeInfo().GetDeclaredMethod("Set" + name); - return new PerspexAttachableXamlMember(name, this, getter, setter, TypeRepository, FeatureProvider); - } - - public override string ToString() - { - return "Perspex XAML Type " + base.ToString(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Context/PropertyAccessor.cs b/src/Markup/Perspex.Markup.Xaml/Context/PropertyAccessor.cs deleted file mode 100644 index 0c4ed4aefb..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Context/PropertyAccessor.cs +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using OmniXaml.ObjectAssembler; -using OmniXaml.TypeConversion; -using OmniXaml.Typing; -using Perspex.Controls; -using Perspex.Data; -using Perspex.Markup.Xaml.Data; -using Perspex.Styling; - -namespace Perspex.Markup.Xaml.Context -{ - internal static class PropertyAccessor - { - public static void SetValue( - object instance, - MutableMember member, - object value, - IValueContext context) - { - var perspexProperty = FindPerspexProperty(instance, member); - - if (value is IBinding) - { - SetBinding(instance, member, perspexProperty, context, (IBinding)value); - } - else if (perspexProperty != null) - { - ((PerspexObject)instance).SetValue(perspexProperty, value); - } - else if (instance is Setter && member.Name == "Value") - { - // TODO: Make this more generic somehow. - var setter = (Setter)instance; - var targetType = setter.Property.PropertyType; - var xamlType = member.TypeRepository.GetByType(targetType); - var convertedValue = default(object); - - if (CommonValueConversion.TryConvert(value, xamlType, context, out convertedValue)) - { - SetClrProperty(instance, member, convertedValue); - } - } - else - { - SetClrProperty(instance, member, value); - } - } - - private static PerspexProperty FindPerspexProperty(object instance, MutableMember member) - { - var registry = PerspexPropertyRegistry.Instance; - var attached = member as PerspexAttachableXamlMember; - var target = instance as PerspexObject; - - if (target == null) - { - return null; - } - - if (attached == null) - { - return registry.FindRegistered(target, member.Name); - } - else - { - var ownerType = attached.DeclaringType.UnderlyingType; - - RuntimeHelpers.RunClassConstructor(ownerType.TypeHandle); - - return registry.GetRegistered(target) - .Where(x => x.OwnerType == ownerType && x.Name == attached.Name) - .FirstOrDefault(); - } - } - - private static void SetBinding( - object instance, - MutableMember member, - PerspexProperty property, - IValueContext context, - IBinding binding) - { - if (!(AssignBinding(instance, member, binding) || - ApplyBinding(instance, property, context, binding))) - { - throw new InvalidOperationException( - $"Cannot assign to '{member.Name}' on '{instance.GetType()}"); - } - } - - private static void SetClrProperty(object instance, MutableMember member, object value) - { - if (member.IsAttachable) - { - member.Setter.Invoke(null, new[] { instance, value }); - } - else - { - member.Setter.Invoke(instance, new[] { value }); - } - } - - private static bool AssignBinding(object instance, MutableMember member, IBinding binding) - { - var property = instance.GetType() - .GetRuntimeProperties() - .FirstOrDefault(x => x.Name == member.Name); - - if (property?.GetCustomAttribute() != null) - { - property.SetValue(instance, binding); - return true; - } - - return false; - } - - private static bool ApplyBinding( - object instance, - PerspexProperty property, - IValueContext context, - IBinding binding) - { - if (property == null) - { - return false; - } - - var control = instance as IControl; - - if (control != null) - { - DelayedBinding.Add(control, property, binding); - } - else - { - // The target is not a control, so we need to find an anchor that will let us look - // up named controls and style resources. First look for the closest IControl in - // the TopDownValueContext. - object anchor = context.TopDownValueContext.StoredInstances - .Select(x => x.Instance) - .OfType() - .LastOrDefault(); - - // If a control was not found, then try to find the highest-level style as the XAML - // file could be a XAML file containing only styles. - if (anchor == null) - { - anchor = context.TopDownValueContext.StoredInstances - .Select(x => x.Instance) - .OfType() - .FirstOrDefault(); - } - - ((IPerspexObject)instance).Bind(property, binding, anchor); - } - - return true; - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/BitmapTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/BitmapTypeConverter.cs deleted file mode 100644 index 9fb58c2a73..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/BitmapTypeConverter.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Media.Imaging; -using Perspex.Platform; - -namespace Perspex.Markup.Xaml.Converters -{ - public class BitmapTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - var uri = new Uri((string)value, UriKind.RelativeOrAbsolute); - var baseUri = GetBaseUri(context); - var scheme = uri.IsAbsoluteUri ? uri.Scheme : "file"; - - switch (scheme) - { - case "file": - return new Bitmap((string)value); - default: - var assets = PerspexLocator.Current.GetService(); - return new Bitmap(assets.Open(uri, baseUri)); - } - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - - private Uri GetBaseUri(IValueContext context) - { - object result; - context.ParsingDictionary.TryGetValue("Uri", out result); - return result as Uri; - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/BrushTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/BrushTypeConverter.cs deleted file mode 100644 index b463143840..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/BrushTypeConverter.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Media; - -namespace Perspex.Markup.Xaml.Converters -{ - public class BrushTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return Brush.Parse((string)value); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/ClassesTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/ClassesTypeConverter.cs deleted file mode 100644 index 8d32c30369..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/ClassesTypeConverter.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Controls; -using Perspex.Styling; - -namespace Perspex.Markup.Xaml.Converters -{ - public class ClassesTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return new Classes(((string)value).Split(' ')); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/ColorTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/ColorTypeConverter.cs deleted file mode 100644 index a780bf0b14..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/ColorTypeConverter.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Media; - -namespace Perspex.Markup.Xaml.Converters -{ - public class ColorTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return Color.Parse((string)value); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs deleted file mode 100644 index e82e50b96a..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/ColumnDefinitionsTypeConverter.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Controls; - -namespace Perspex.Markup.Xaml.Converters -{ - public class ColumnDefinitionsTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return new ColumnDefinitions((string)value); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs deleted file mode 100644 index 86eeb8067c..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/CursorTypeConverter.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Input; -using Perspex.Media.Imaging; -using Perspex.Platform; - -namespace Perspex.Markup.Xaml.Converters -{ - public class CursorTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - var cursor = (StandardCursorType)Enum.Parse(typeof (StandardCursorType), ((string) value).Trim(), true); - return new Cursor(cursor); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/GeometryTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/GeometryTypeConverter.cs deleted file mode 100644 index 7035bb07cb..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/GeometryTypeConverter.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Perspex.Markup.Xaml.Converters -{ - using System; - using System.Globalization; - using Media; - using OmniXaml.TypeConversion; - - public class GeometryTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return StreamGeometry.Parse((string)value); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/GridLengthTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/GridLengthTypeConverter.cs deleted file mode 100644 index df1eb29711..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/GridLengthTypeConverter.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Controls; - -namespace Perspex.Markup.Xaml.Converters -{ - public class GridLengthTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return GridLength.Parse((string)value, culture); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/KeyGestureConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/KeyGestureConverter.cs deleted file mode 100644 index f631d7a740..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/KeyGestureConverter.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Input; - -namespace Perspex.Markup.Xaml.Converters -{ - class KeyGestureConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return KeyGesture.Parse((string)value); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs deleted file mode 100644 index 367a5f299f..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/MemberSelectorTypeConverter.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Markup.Xaml.Templates; - -namespace Perspex.Markup.Xaml.Converters -{ - public class MemberSelectorTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return new MemberSelector - { - MemberName = (string)value, - }; - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/PerspexListTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/PerspexListTypeConverter.cs deleted file mode 100644 index ab72c85d8f..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/PerspexListTypeConverter.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using System.Linq; -using OmniXaml.TypeConversion; -using Perspex.Collections; -using Perspex.Utilities; - -namespace Perspex.Markup.Xaml.Converters -{ - public class PerspexListTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - var result = new PerspexList(); - var values = ((string)value).Split(','); - - foreach (var s in values) - { - object v; - - if (TypeUtilities.TryConvert(typeof(T), s, culture, out v)) - { - result.Add((T)v); - } - else - { - throw new InvalidCastException($"Could not convert '{s}' to {typeof(T)}."); - } - } - - return result; - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/PerspexPropertyTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/PerspexPropertyTypeConverter.cs deleted file mode 100644 index 54fe698354..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/PerspexPropertyTypeConverter.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using System.Linq; -using OmniXaml; -using OmniXaml.TypeConversion; -using Perspex.Styling; - -namespace Perspex.Markup.Xaml.Converters -{ - public class PerspexPropertyTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - var s = (string)value; - - string typeName; - string propertyName; - Type type; - - ParseProperty(s, out typeName, out propertyName); - - if (typeName == null) - { - var styleType = context.TypeRepository.GetByType(typeof(Style)); - var style = (Style)context.TopDownValueContext.GetLastInstance(styleType); - type = style.Selector?.TargetType; - - if (type == null) - { - throw new ParseException( - "Could not determine the target type. Please fully qualify the property name."); - } - } - else - { - type = context.TypeRepository.GetByQualifiedName(typeName)?.UnderlyingType; - - if (type == null) - { - throw new ParseException($"Could not find type '{typeName}'."); - } - } - - // First look for non-attached property on the type and then look for an attached property. - var property = PerspexPropertyRegistry.Instance.FindRegistered(type, s) ?? - PerspexPropertyRegistry.Instance.GetAttached(type) - .FirstOrDefault(x => x.Name == propertyName); - - if (property == null) - { - throw new ParseException( - $"Could not find PerspexProperty '{type.Name}.{propertyName}'."); - } - - return property; - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - - private void ParseProperty(string s, out string typeName, out string propertyName) - { - var split = s.Split('.'); - - if (split.Length == 1) - { - typeName = null; - propertyName = split[0]; - } - else if (split.Length == 2) - { - typeName = split[0]; - propertyName = split[1]; - } - else - { - throw new ParseException($"Invalid property name: '{s}'."); - } - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/PointTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/PointTypeConverter.cs deleted file mode 100644 index 6ca3f316f1..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/PointTypeConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; - -namespace Perspex.Markup.Xaml.Converters -{ - public class PointTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return Point.Parse((string)value, culture); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/PointsListTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/PointsListTypeConverter.cs deleted file mode 100644 index ccb893b0aa..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/PointsListTypeConverter.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Globalization; -using OmniXaml.TypeConversion; - -namespace Perspex.Markup.Xaml.Converters -{ - public class PointsListTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - string strValue = (string)value; - string[] pointStrs = strValue.Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - var result = new List(pointStrs.Length); - foreach (var pointStr in pointStrs) - { - result.Add(Point.Parse(pointStr, culture)); - } - return result; - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/RelativePointTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/RelativePointTypeConverter.cs deleted file mode 100644 index e93dcdaabc..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/RelativePointTypeConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; - -namespace Perspex.Markup.Xaml.Converters -{ - public class RelativePointTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return RelativePoint.Parse((string)value, culture); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/RelativeRectTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/RelativeRectTypeConverter.cs deleted file mode 100644 index 58d8f88d40..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/RelativeRectTypeConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; - -namespace Perspex.Markup.Xaml.Converters -{ - public class RelativeRectTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return RelativeRect.Parse((string)value, culture); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs deleted file mode 100644 index ea05eedc51..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/RowDefinitionsTypeConverter.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Controls; - -namespace Perspex.Markup.Xaml.Converters -{ - public class RowDefinitionsTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return new RowDefinitions((string)value); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/SelectorTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/SelectorTypeConverter.cs deleted file mode 100644 index f9fe83bb0b..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/SelectorTypeConverter.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Markup.Xaml.Parsers; - -namespace Perspex.Markup.Xaml.Converters -{ - public class SelectorTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - var parser = new SelectorParser((t, ns) => context.TypeRepository.GetByPrefix(ns ?? "", t).UnderlyingType); - return parser.Parse((string)value); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/SizeTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/SizeTypeConverter.cs deleted file mode 100644 index ec6763c555..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/SizeTypeConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; - -namespace Perspex.Markup.Xaml.Converters -{ - public class SizeTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return Size.Parse((string)value, culture); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/ThicknessTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/ThicknessTypeConverter.cs deleted file mode 100644 index 5f2239a18c..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/ThicknessTypeConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; - -namespace Perspex.Markup.Xaml.Converters -{ - public class ThicknessTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return Thickness.Parse((string)value, culture); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/TimeSpanTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/TimeSpanTypeConverter.cs deleted file mode 100644 index c1663454a5..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/TimeSpanTypeConverter.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; -using Perspex.Media; - -namespace Perspex.Markup.Xaml.Converters -{ - public class TimeSpanTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - var valueStr = (string)value; - if (!valueStr.Contains(":")) - { - // shorthand seconds format (ie. "0.25") - var secs = double.Parse(valueStr, CultureInfo.InvariantCulture); - return TimeSpan.FromSeconds(secs); - } - - return TimeSpan.Parse(valueStr); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Converters/UriTypeConverter.cs b/src/Markup/Perspex.Markup.Xaml/Converters/UriTypeConverter.cs deleted file mode 100644 index 6447d6fedc..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Converters/UriTypeConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using OmniXaml.TypeConversion; - -namespace Perspex.Markup.Xaml.Converters -{ - public class UriTypeConverter : ITypeConverter - { - public bool CanConvertFrom(IValueContext context, Type sourceType) - { - return sourceType == typeof(string); - } - - public bool CanConvertTo(IValueContext context, Type destinationType) - { - return false; - } - - public object ConvertFrom(IValueContext context, CultureInfo culture, object value) - { - return new Uri((string)value); - } - - public object ConvertTo(IValueContext context, CultureInfo culture, object value, Type destinationType) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs b/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs deleted file mode 100644 index 5a3f647013..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Data/Binding.cs +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using Perspex.Controls; -using Perspex.Data; -using Perspex.Markup.Data; - -namespace Perspex.Markup.Xaml.Data -{ - /// - /// A XAML binding. - /// - public class Binding : IBinding - { - /// - /// Initializes a new instance of the class. - /// - public Binding() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The binding path. - public Binding(string path) - { - Path = path; - } - - /// - /// Gets or sets the to use. - /// - public IValueConverter Converter { get; set; } - - /// - /// Gets or sets a parameter to pass to . - /// - public object ConverterParameter { get; set; } - - /// - /// Gets or sets the name of the element to use as the binding source. - /// - public string ElementName { get; set; } - - /// - /// Gets or sets the value to use when the binding is unable to produce a value. - /// - public object FallbackValue { get; set; } - - /// - /// Gets or sets the binding mode. - /// - public BindingMode Mode { get; set; } - - /// - /// Gets or sets the binding path. - /// - public string Path { get; set; } - - /// - /// Gets or sets the binding priority. - /// - public BindingPriority Priority { get; set; } - - /// - /// Gets or sets the relative source for the binding. - /// - public RelativeSource RelativeSource { get; set; } - - /// - /// Gets or sets the source for the binding. - /// - public object Source { get; set; } - - /// - /// Gets or sets the validation methods for the binding to use. - /// - public ValidationMethods ValidationMethods { get; set; } - - /// - public InstancedBinding Initiate( - IPerspexObject target, - PerspexProperty targetProperty, - object anchor = null) - { - Contract.Requires(target != null); - - var pathInfo = ParsePath(Path); - ValidateState(pathInfo); - - ExpressionObserver observer; - - if (pathInfo.ElementName != null || ElementName != null) - { - observer = CreateElementObserver( - (target as IControl) ?? (anchor as IControl), - pathInfo.ElementName ?? ElementName, - pathInfo.Path); - } - else if (Source != null) - { - observer = CreateSourceObserver(Source, pathInfo.Path); - } - else if (RelativeSource == null || RelativeSource.Mode == RelativeSourceMode.DataContext) - { - observer = CreateDataContexObserver( - target, - pathInfo.Path, - targetProperty == Control.DataContextProperty, - anchor); - } - else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent) - { - observer = CreateTemplatedParentObserver(target, pathInfo.Path); - } - else - { - throw new NotSupportedException(); - } - - var subject = new ExpressionSubject( - observer, - targetProperty?.PropertyType ?? typeof(object), - Converter ?? DefaultValueConverter.Instance, - ConverterParameter, - FallbackValue, - Priority); - - return new InstancedBinding(subject, Mode, Priority); - } - - private static PathInfo ParsePath(string path) - { - var result = new PathInfo(); - - if (string.IsNullOrWhiteSpace(path) || path == ".") - { - result.Path = string.Empty; - } - else if (path.StartsWith("#")) - { - var dot = path.IndexOf('.'); - - if (dot != -1) - { - result.Path = path.Substring(dot + 1); - result.ElementName = path.Substring(1, dot - 1); - } - else - { - result.Path = string.Empty; - result.ElementName = path.Substring(1); - } - } - else - { - result.Path = path; - } - - return result; - } - - private void ValidateState(PathInfo pathInfo) - { - if (pathInfo.ElementName != null && ElementName != null) - { - throw new InvalidOperationException( - "ElementName property cannot be set when an #elementName path is provided."); - } - - if ((pathInfo.ElementName != null || ElementName != null) && - RelativeSource != null) - { - throw new InvalidOperationException( - "ElementName property cannot be set with a RelativeSource."); - } - } - - private ExpressionObserver CreateDataContexObserver( - IPerspexObject target, - string path, - bool targetIsDataContext, - object anchor) - { - Contract.Requires(target != null); - - if (!(target is IControl)) - { - target = anchor as IControl; - - if (target == null) - { - throw new InvalidOperationException("Cannot find a DataContext to bind to."); - } - } - - if (!targetIsDataContext) - { - var update = target.GetObservable(Control.DataContextProperty) - .Skip(1) - .Select(_ => Unit.Default); - var result = new ExpressionObserver( - () => target.GetValue(Control.DataContextProperty), - path, - update, ValidationMethods); - - return result; - } - else - { - return new ExpressionObserver( - target.GetObservable(Visual.VisualParentProperty) - .OfType() - .Select(x => x.GetObservable(Control.DataContextProperty)) - .Switch(), - path, ValidationMethods); - } - } - - private ExpressionObserver CreateElementObserver(IControl target, string elementName, string path) - { - Contract.Requires(target != null); - - var result = new ExpressionObserver( - ControlLocator.Track(target, elementName), - path, ValidationMethods); - return result; - } - - private ExpressionObserver CreateSourceObserver(object source, string path) - { - Contract.Requires(source != null); - - return new ExpressionObserver(source, path, ValidationMethods); - } - - private ExpressionObserver CreateTemplatedParentObserver( - IPerspexObject target, - string path) - { - Contract.Requires(target != null); - - var update = target.GetObservable(Control.TemplatedParentProperty) - .Skip(1) - .Select(_ => Unit.Default); - - var result = new ExpressionObserver( - () => target.GetValue(Control.TemplatedParentProperty), - path, - update); - - return result; - } - - private class PathInfo - { - public string Path { get; set; } - public string ElementName { get; set; } - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Data/DelayedBinding.cs b/src/Markup/Perspex.Markup.Xaml/Data/DelayedBinding.cs deleted file mode 100644 index f0005b65a4..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Data/DelayedBinding.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using Perspex.Controls; -using Perspex.Data; - -namespace Perspex.Markup.Xaml.Data -{ - /// - /// Provides delayed bindings for controls. - /// - /// - /// The XAML engine applies its bindings in a delayed manner where bindings are only applied - /// when a control has finished initializing. This was done because applying bindings as soon - /// as controls are created means that long-form bindings (i.e. bindings that don't use the - /// `{Binding}` markup extension) don't work as the binding is applied to the property before - /// the binding properties are set, and looking at WPF it uses a similar mechanism for bindings - /// that come from XAML. - /// - public static class DelayedBinding - { - private static ConditionalWeakTable> _entries = - new ConditionalWeakTable>(); - - /// - /// Adds a delayed binding to a control. - /// - /// The control. - /// The property on the control to bind to. - /// The binding. - public static void Add(IControl target, PerspexProperty property, IBinding binding) - { - if (target.IsInitialized) - { - target.Bind(property, binding); - } - else - { - List bindings; - - if (!_entries.TryGetValue(target, out bindings)) - { - bindings = new List(); - _entries.Add(target, bindings); - - // TODO: Make this a weak event listener. - target.Initialized += ApplyBindings; - } - - bindings.Add(new Entry(binding, property)); - } - } - - /// - /// Applies any delayed bindings to a control. - /// - /// The control. - public static void ApplyBindings(IControl control) - { - List bindings; - - if (_entries.TryGetValue(control, out bindings)) - { - foreach (var binding in bindings) - { - control.Bind(binding.Property, binding.Binding); - } - - _entries.Remove(control); - } - } - - private static void ApplyBindings(object sender, EventArgs e) - { - var target = (IControl)sender; - ApplyBindings(target); - target.Initialized -= ApplyBindings; - } - - private class Entry - { - public Entry(IBinding binding, PerspexProperty property) - { - Binding = binding; - Property = property; - } - - public IBinding Binding { get; } - public PerspexProperty Property { get; } - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Data/MultiBinding.cs b/src/Markup/Perspex.Markup.Xaml/Data/MultiBinding.cs deleted file mode 100644 index 747ef15972..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Data/MultiBinding.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using Perspex.Controls; -using Perspex.Data; -using Perspex.Metadata; - -namespace Perspex.Markup.Xaml.Data -{ - /// - /// A XAML binding that calculates an aggregate value from multiple child . - /// - public class MultiBinding : IBinding - { - /// - /// Gets the collection of child bindings. - /// - [Content] - public IList Bindings { get; set; } = new List(); - - /// - /// Gets or sets the to use. - /// - public IMultiValueConverter Converter { get; set; } - - /// - /// Gets or sets the value to use when the binding is unable to produce a value. - /// - public object FallbackValue { get; set; } - - /// - /// Gets or sets the binding mode. - /// - public BindingMode Mode { get; set; } = BindingMode.OneWay; - - /// - /// Gets or sets the binding priority. - /// - public BindingPriority Priority { get; set; } - - /// - /// Gets or sets the relative source for the binding. - /// - public RelativeSource RelativeSource { get; set; } - - /// - public InstancedBinding Initiate( - IPerspexObject target, - PerspexProperty targetProperty, - object anchor = null) - { - if (Converter == null) - { - throw new NotSupportedException("MultiBinding without Converter not currently supported."); - } - - var targetType = targetProperty?.PropertyType ?? typeof(object); - var result = new BehaviorSubject(PerspexProperty.UnsetValue); - var children = Bindings.Select(x => x.Initiate(target, null)); - var input = children.Select(x => x.Subject).CombineLatest().Select(x => ConvertValue(x, targetType)); - input.Subscribe(result); - return new InstancedBinding(result, Mode, Priority); - } - - /// - /// Applies a binding subject to a property on an instance. - /// - /// The target instance. - /// The target property. - /// The binding subject. - internal void Bind(IPerspexObject target, PerspexProperty property, ISubject subject) - { - var mode = Mode == BindingMode.Default ? - property.GetMetadata(target.GetType()).DefaultBindingMode : Mode; - - switch (mode) - { - case BindingMode.Default: - case BindingMode.OneWay: - target.Bind(property, subject, Priority); - break; - case BindingMode.TwoWay: - throw new NotSupportedException("TwoWay MultiBinding not currently supported."); - case BindingMode.OneTime: - target.GetObservable(Control.DataContextProperty).Subscribe(dataContext => - { - subject.Take(1).Subscribe(x => target.SetValue(property, x, Priority)); - }); - break; - case BindingMode.OneWayToSource: - target.GetObservable(property).Subscribe(subject); - break; - } - } - - private object ConvertValue(IList values, Type targetType) - { - var converted = Converter.Convert(values, targetType, null, CultureInfo.CurrentUICulture); - - if (converted == PerspexProperty.UnsetValue && FallbackValue != null) - { - converted = FallbackValue; - } - - return converted; - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Data/RelativeSource.cs b/src/Markup/Perspex.Markup.Xaml/Data/RelativeSource.cs deleted file mode 100644 index 125f2d8ad5..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Data/RelativeSource.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Markup.Xaml.Data -{ - public enum RelativeSourceMode - { - DataContext, - TemplatedParent, - } - - public class RelativeSource - { - public RelativeSource() - { - } - - public RelativeSource(RelativeSourceMode mode) - { - Mode = mode; - } - - public RelativeSourceMode Mode { get; set; } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Data/SourceBindingEndpoint.cs b/src/Markup/Perspex.Markup.Xaml/Data/SourceBindingEndpoint.cs deleted file mode 100644 index c800f2a27c..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Data/SourceBindingEndpoint.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.ComponentModel; - -namespace Perspex.Markup.Xaml.Data -{ - public class SourceBindingEndpoint - { - public Type PropertyType { get; } - - public INotifyPropertyChanged Source { get; } - - public dynamic PropertyGetter { get; } - - public Delegate PropertySetter { get; } - - public SourceBindingEndpoint(INotifyPropertyChanged source, Type propertyType, dynamic propertyGetter, Delegate propertySetter) - { - Source = source; - PropertyType = propertyType; - PropertyGetter = propertyGetter; - PropertySetter = propertySetter; - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Data/StyleResourceBinding.cs b/src/Markup/Perspex.Markup.Xaml/Data/StyleResourceBinding.cs deleted file mode 100644 index a95afe6b44..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Data/StyleResourceBinding.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using Perspex.Controls; -using Perspex.Data; -using Perspex.Styling; - -namespace Perspex.Markup.Xaml.Data -{ - public class StyleResourceBinding : IBinding - { - /// - /// Initializes a new instance of the class. - /// - /// The resource name. - public StyleResourceBinding(string name) - { - Name = name; - } - - /// - public BindingMode Mode => BindingMode.OneTime; - - /// - /// Gets the resource name. - /// - public string Name { get; } - - /// - public BindingPriority Priority => BindingPriority.LocalValue; - - /// - public InstancedBinding Initiate( - IPerspexObject target, - PerspexProperty targetProperty, - object anchor = null) - { - if (Name == "Red") - { - } - - var host = (target as IControl) ?? (anchor as IControl); - var style = anchor as IStyle; - var resource = PerspexProperty.UnsetValue; - - if (host != null) - { - resource = host.FindStyleResource(Name); - } - else if (style != null) - { - resource = style.FindResource(Name); - } - - if (resource != PerspexProperty.UnsetValue) - { - return new InstancedBinding(resource, Priority); - } - else - { - return null; - } - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Data/TargetBindingEndpoint.cs b/src/Markup/Perspex.Markup.Xaml/Data/TargetBindingEndpoint.cs deleted file mode 100644 index 02a1c79f7c..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Data/TargetBindingEndpoint.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Markup.Xaml.Data -{ - public class TargetBindingEndpoint - { - public PerspexObject Object { get; } - - public PerspexProperty Property { get; } - - public TargetBindingEndpoint(PerspexObject obj, PerspexProperty property) - { - Object = obj; - Property = property; - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs deleted file mode 100644 index d0dcd069a3..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/BindingExtension.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using OmniXaml; -using Perspex.Data; -using Perspex.Markup.Xaml.Data; - -namespace Perspex.Markup.Xaml.MarkupExtensions -{ - public class BindingExtension : MarkupExtension - { - public BindingExtension() - { - } - - public BindingExtension(string path) - { - Path = path; - } - - public override object ProvideValue(MarkupExtensionContext extensionContext) - { - return new Binding - { - Converter = Converter, - ConverterParameter = ConverterParameter, - ElementName = ElementName, - FallbackValue = FallbackValue, - Mode = Mode, - Path = Path, - Priority = Priority, - ValidationMethods = ValidationMethods - }; - } - - public IValueConverter Converter { get; set; } - public object ConverterParameter { get; set; } - public string ElementName { get; set; } - public object FallbackValue { get; set; } - public BindingMode Mode { get; set; } - public string Path { get; set; } - public BindingPriority Priority { get; set; } = BindingPriority.LocalValue; - public object Source { get; set; } - public ValidationMethods ValidationMethods { get; set; } = ValidationMethods.None; - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs deleted file mode 100644 index fc805c29cd..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/RelativeSourceExtension.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using OmniXaml; -using Perspex.Markup.Xaml.Data; - -namespace Perspex.Markup.Xaml.MarkupExtensions -{ - public class RelativeSourceExtension : MarkupExtension - { - public RelativeSourceExtension() - { - } - - public RelativeSourceExtension(RelativeSourceMode mode) - { - Mode = mode; - } - - public override object ProvideValue(MarkupExtensionContext extensionContext) - { - return new RelativeSource - { - Mode = Mode, - }; - } - - public RelativeSourceMode Mode { get; set; } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StaticExtension.cs b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StaticExtension.cs deleted file mode 100644 index 7c89dd1e0d..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StaticExtension.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Linq; -using System.Reflection; -using OmniXaml; -using Glass.Core; - -namespace Perspex.Markup.Xaml.MarkupExtensions -{ - public class StaticExtension : MarkupExtension - { - public StaticExtension() - { - } - - public StaticExtension(string identifier) - { - Identifier = identifier; - } - - public string Identifier { get; set; } - - public override object ProvideValue(MarkupExtensionContext markupExtensionContext) - { - var typeRepository = markupExtensionContext.ValueContext.TypeRepository; - var typeAndMember = GetTypeAndMember(Identifier); - var prefixAndType = GetPrefixAndType(typeAndMember.Item1); - var xamlType = typeRepository.GetByPrefix(prefixAndType.Item1, prefixAndType.Item2); - return GetValue(xamlType.UnderlyingType, typeAndMember.Item2); - } - - private static Tuple GetTypeAndMember(string s) - { - var parts = s.Split('.'); - - if (parts.Length != 2) - { - throw new ArgumentException("Static member must be in the form Type.Member."); - } - - return Tuple.Create(parts[0], parts[1]); - } - - private static Tuple GetPrefixAndType(string s) - { - if (s.Contains(":")) - { - return s.Dicotomize(':'); - } - else - { - return new Tuple(string.Empty, s); - } - } - - private object GetValue(Type type, string name) - { - var t = type; - - while (t != null) - { - var result = t.GetTypeInfo().DeclaredMembers.FirstOrDefault(x => x.Name == name); - - if (result is PropertyInfo) - { - var property = ((PropertyInfo)result); - - if (property.GetMethod.IsStatic) - { - return ((PropertyInfo)result).GetValue(null); - } - } - else if (result is FieldInfo) - { - return ((FieldInfo)result).GetValue(null); - } - - t = t.GetTypeInfo().BaseType; - } - - throw new ArgumentException($"Static member '{type}.{name}' not found."); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs deleted file mode 100644 index 48bec12be2..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Linq; -using OmniXaml; -using Perspex.LogicalTree; -using Perspex.Markup.Xaml.Data; -using Perspex.Styling; - -namespace Perspex.Markup.Xaml.MarkupExtensions -{ - public class StyleResourceExtension : MarkupExtension - { - public StyleResourceExtension(string name) - { - Name = name; - } - - public override object ProvideValue(MarkupExtensionContext extensionContext) - { - return new StyleResourceBinding(this.Name); - } - - public string Name { get; set; } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs deleted file mode 100644 index a4b808f9c0..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using OmniXaml; -using Perspex.Data; -using Perspex.Markup.Xaml.Data; - -namespace Perspex.Markup.Xaml.MarkupExtensions -{ - public class TemplateBindingExtension : MarkupExtension - { - public TemplateBindingExtension() - { - } - - public TemplateBindingExtension(string path) - { - Path = path; - } - - public override object ProvideValue(MarkupExtensionContext extensionContext) - { - return new Binding - { - Converter = Converter, - ElementName = ElementName, - Mode = Mode, - RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent), - Path = Path, - Priority = Priority, - }; - } - - public IValueConverter Converter { get; set; } - public string ElementName { get; set; } - public object FallbackValue { get; set; } - public BindingMode Mode { get; set; } - public string Path { get; set; } - public BindingPriority Priority { get; set; } = BindingPriority.TemplatedParent; - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TypeExtension.cs b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TypeExtension.cs deleted file mode 100644 index b82f8eb998..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/TypeExtension.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using OmniXaml; -using OmniXaml.Attributes; -using OmniXaml.Typing; -using Glass.Core; - -namespace Perspex.Markup.Xaml.MarkupExtensions -{ - [ContentProperty("TargetType")] - public class TypeExtension : MarkupExtension - { - public Type Type { get; set; } - - public TypeExtension() - { - } - - public TypeExtension(Type type) - { - Type = type; - } - - public string TypeName { get; set; } - - private Type ResolveFromString(string type, ITypeRepository typeRepository) - { - Guard.ThrowIfNull(type, nameof(type)); - - var split = type.Split(':'); - var prefix = split.Length == 1 ? split[0] : null; - var typeName = split.Length == 1 ? split[1] : split[0]; - var xamlType = typeRepository.GetByPrefix(prefix, typeName); - return xamlType.UnderlyingType; - } - - public override object ProvideValue(MarkupExtensionContext markupExtensionContext) - { - if (Type != null) - { - return Type; - } - - return ResolveFromString(TypeName, markupExtensionContext.ValueContext.TypeRepository); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Parsers/SelectorGrammar.cs b/src/Markup/Perspex.Markup.Xaml/Parsers/SelectorGrammar.cs deleted file mode 100644 index 1823995321..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Parsers/SelectorGrammar.cs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Collections.Generic; -using System.Globalization; -using Sprache; - -// Don't need to override GetHashCode as the ISyntax objects will not be stored in a hash; the -// only reason they have overridden Equals methods is for unit testing. -#pragma warning disable 659 - -namespace Perspex.Markup.Xaml.Parsers -{ - internal class SelectorGrammar - { - public static readonly Parser CombiningCharacter = Parse.Char( - c => - { - var cat = CharUnicodeInfo.GetUnicodeCategory(c); - return cat == UnicodeCategory.NonSpacingMark || - cat == UnicodeCategory.SpacingCombiningMark; - }, - "Connecting Character"); - - public static readonly Parser ConnectingCharacter = Parse.Char( - c => CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.ConnectorPunctuation, - "Connecting Character"); - - public static readonly Parser FormattingCharacter = Parse.Char( - c => CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.Format, - "Connecting Character"); - - public static readonly Parser IdentifierStart = Parse.Letter.Or(Parse.Char('_')); - - public static readonly Parser IdentifierChar = Parse - .LetterOrDigit - .Or(ConnectingCharacter) - .Or(CombiningCharacter) - .Or(FormattingCharacter); - - public static readonly Parser Identifier = - from start in IdentifierStart.Once().Text() - from @char in IdentifierChar.Many().Text() - select start + @char; - - public static readonly Parser Namespace = - from ns in Parse.Letter.Many().Text() - from bar in Parse.Char('|') - select ns; - - public static readonly Parser OfType = - from ns in Namespace.Optional() - from identifier in Identifier - select new OfTypeSyntax - { - TypeName = identifier, - Xmlns = ns.GetOrDefault(), - }; - - public static readonly Parser Name = - from hash in Parse.Char('#') - from identifier in Identifier - select new NameSyntax { Name = identifier }; - - public static readonly Parser ClassStart = Parse.Char('_').Or(Parse.Letter); - - public static readonly Parser ClassChar = ClassStart.Or(Parse.Numeric); - - public static readonly Parser ClassIdentifier = - from start in ClassStart.Once().Text() - from @char in ClassChar.Many().Text() - select start + @char; - - public static readonly Parser StandardClass = - from dot in Parse.Char('.').Once() - from identifier in ClassIdentifier - select new ClassSyntax { Class = identifier }; - - public static readonly Parser Pseduoclass = - from colon in Parse.Char(':').Once() - from identifier in ClassIdentifier - select new ClassSyntax { Class = ':' + identifier }; - - public static readonly Parser Class = StandardClass.Or(Pseduoclass); - - public static readonly Parser Property = - from open in Parse.Char('[').Once() - from identifier in Identifier - from eq in Parse.Char('=').Once() - from value in Parse.CharExcept(']').Many().Text() - from close in Parse.Char(']').Once() - select new PropertySyntax { Property = identifier, Value = value }; - - public static readonly Parser Child = Parse.Char('>').Token().Return(new ChildSyntax()); - - public static readonly Parser Descendent = - from child in Parse.WhiteSpace.Many() - select new DescendentSyntax(); - - public static readonly Parser Template = - from template in Parse.String("/template/").Token() - select new TemplateSyntax(); - - public static readonly Parser Is = - from function in Parse.String(":is(") - from type in OfType - from close in Parse.Char(')') - select new IsSyntax { TypeName = type.TypeName, Xmlns = type.Xmlns }; - - public static readonly Parser SingleSelector = - OfType - .Or(Is) - .Or(Name) - .Or(Class) - .Or(Property) - .Or(Child) - .Or(Template) - .Or(Descendent); - - public static readonly Parser> Selector = SingleSelector.Many().End(); - - public interface ISyntax - { - } - - public class OfTypeSyntax : ISyntax - { - public string TypeName { get; set; } - - public string Xmlns { get; set; } - - public override bool Equals(object obj) - { - var other = obj as OfTypeSyntax; - return other != null && other.TypeName == TypeName && other.Xmlns == Xmlns; - } - } - - public class IsSyntax : ISyntax - { - public string TypeName { get; set; } - - public string Xmlns { get; set; } - - public override bool Equals(object obj) - { - var other = obj as IsSyntax; - return other != null && other.TypeName == TypeName && other.Xmlns == Xmlns; - } - } - - public class ClassSyntax : ISyntax - { - public string Class { get; set; } - - public override bool Equals(object obj) - { - return obj is ClassSyntax && ((ClassSyntax)obj).Class == Class; - } - } - - public class NameSyntax : ISyntax - { - public string Name { get; set; } - - public override bool Equals(object obj) - { - return obj is NameSyntax && ((NameSyntax)obj).Name == Name; - } - } - - public class PropertySyntax : ISyntax - { - public string Property { get; set; } - - public string Value { get; set; } - - public override bool Equals(object obj) - { - return obj is PropertySyntax && - ((PropertySyntax)obj).Property == Property && - ((PropertySyntax)obj).Value == Value; - } - } - - public class ChildSyntax : ISyntax - { - public override bool Equals(object obj) - { - return obj is ChildSyntax; - } - } - - public class DescendentSyntax : ISyntax - { - public override bool Equals(object obj) - { - return obj is DescendentSyntax; - } - } - - public class TemplateSyntax : ISyntax - { - public override bool Equals(object obj) - { - return obj is TemplateSyntax; - } - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Parsers/SelectorParser.cs b/src/Markup/Perspex.Markup.Xaml/Parsers/SelectorParser.cs deleted file mode 100644 index a3d741149d..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Parsers/SelectorParser.cs +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using Perspex.Styling; -using Perspex.Utilities; -using Sprache; - -namespace Perspex.Markup.Xaml.Parsers -{ - /// - /// Parses a from text. - /// - public class SelectorParser - { - private readonly Func _typeResolver; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The type resolver to use. The type resolver is a function which accepts two strings: - /// a type name and a XML namespace prefix and a type name, and should return the resolved - /// type or throw an exception. - /// - public SelectorParser(Func typeResolver) - { - this._typeResolver = typeResolver; - } - - /// - /// Parses a from a string. - /// - /// The string. - /// The parsed selector. - public Selector Parse(string s) - { - var syntax = SelectorGrammar.Selector.Parse(s); - var result = default(Selector); - - foreach (var i in syntax) - { - var ofType = i as SelectorGrammar.OfTypeSyntax; - var @is = i as SelectorGrammar.IsSyntax; - var @class = i as SelectorGrammar.ClassSyntax; - var name = i as SelectorGrammar.NameSyntax; - var property = i as SelectorGrammar.PropertySyntax; - var child = i as SelectorGrammar.ChildSyntax; - var descendent = i as SelectorGrammar.DescendentSyntax; - var template = i as SelectorGrammar.TemplateSyntax; - - if (ofType != null) - { - result = result.OfType(_typeResolver(ofType.TypeName, ofType.Xmlns)); - } - if (@is != null) - { - result = result.Is(_typeResolver(@is.TypeName, @is.Xmlns)); - } - else if (@class != null) - { - result = result.Class(@class.Class); - } - else if (name != null) - { - result = result.Name(name.Name); - } - else if (property != null) - { - var type = result.TargetType; - - if (type == null) - { - throw new InvalidOperationException("Property selectors must be applied to a type."); - } - - var targetProperty = PerspexPropertyRegistry.Instance.FindRegistered(type, property.Property); - - if (targetProperty == null) - { - throw new InvalidOperationException($"Cannot find '{property.Property}' on '{type}"); - } - - object typedValue; - - if (TypeUtilities.TryConvert( - targetProperty.PropertyType, - property.Value, - CultureInfo.InvariantCulture, - out typedValue)) - { - result = result.PropertyEquals(targetProperty, typedValue); - } - else - { - throw new InvalidOperationException( - $"Could not convert '{property.Value}' to '{targetProperty.PropertyType}"); - } - } - else if (child != null) - { - result = result.Child(); - } - else if (descendent != null) - { - result = result.Descendent(); - } - else if (template != null) - { - result = result.Template(); - } - } - - return result; - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj deleted file mode 100644 index 9b72487a60..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj +++ /dev/null @@ -1,349 +0,0 @@ - - - - - 11.0 - Debug - AnyCPU - {3E53A01A-B331-47F3-B828-4A5717E77A24} - Library - Properties - Perspex.Markup.Xaml - Perspex.Markup.Xaml - en-US - 512 - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Profile7 - v4.5 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - CS1591 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Perspex.Markup.Xaml.XML - CS1591 - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {D211E587-D8BC-45B9-95A4-F297C8FA5200} - Perspex.Animation - - - {B09B78D8-9B26-48B0-9149-D64A2F120F3F} - Perspex.Base - - - {D2221C82-4A25-4583-9B43-D791E3F6820C} - Perspex.Controls - - - {62024B2D-53EB-4638-B26B-85EEAA54866E} - Perspex.Input - - - {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B} - Perspex.Interactivity - - - {42472427-4774-4C81-8AFF-9F27B8E31721} - Perspex.Layout - - - {EB582467-6ABB-43A1-B052-E981BA910E3A} - Perspex.SceneGraph - - - {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F} - Perspex.Styling - - - {6417e941-21bc-467b-a771-0de389353ce6} - Perspex.Markup - - - - - ..\..\..\packages\Sprache.2.0.0.50\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid+Xamarin.iOS10+MonoTouch\Sprache.dll - True - - - ..\..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll - - - ..\..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll - - - ..\..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll - - - ..\..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll - - - - - - - - \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/PerspexXamlLoader.cs b/src/Markup/Perspex.Markup.Xaml/PerspexXamlLoader.cs deleted file mode 100644 index c1216b16a9..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/PerspexXamlLoader.cs +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Text; -using OmniXaml; -using Perspex.Platform; - -namespace Perspex.Markup.Xaml -{ - using Context; - using Controls; - using Data; - using OmniXaml.ObjectAssembler; - using System.Linq; - /// - /// Loads XAML for a perspex application. - /// - public class PerspexXamlLoader : XmlLoader - { - private static PerspexParserFactory s_parserFactory; - private static IInstanceLifeCycleListener s_lifeCycleListener = new PerspexLifeCycleListener(); - private static Stack s_uriStack = new Stack(); - - /// - /// Initializes a new instance of the class. - /// - public PerspexXamlLoader() - : this(GetParserFactory()) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The parser factory to use. - public PerspexXamlLoader(IParserFactory xamlParserFactory) - : base(xamlParserFactory) - { - } - - /// - /// Gets the URI of the XAML file currently being loaded. - /// - /// - /// TODO: Making this internal for now as I'm not sure that this is the correct - /// thing to do, but its needd by to get the URL of - /// the currently loading XAML file, as we can't use the OmniXAML parsing context - /// there. Maybe we need a way to inject OmniXAML context into the objects its - /// constructing? - /// - internal static Uri UriContext => s_uriStack.Count > 0 ? s_uriStack.Peek() : null; - - /// - /// Loads the XAML into a Perspex component. - /// - /// The object to load the XAML into. - public static void Load(object obj) - { - Contract.Requires(obj != null); - - var loader = new PerspexXamlLoader(); - loader.Load(obj.GetType(), obj); - } - - /// - /// Loads the XAML for a type. - /// - /// The type. - /// - /// The optional instance into which the XAML should be loaded. - /// - /// The loaded object. - public object Load(Type type, object rootInstance = null) - { - Contract.Requires(type != null); - - // HACK: Currently Visual Studio is forcing us to change the extension of xaml files - // in certain situations, so we try to load .xaml and if that's not found we try .xaml. - // Ideally we'd be able to use .xaml everywhere - var assetLocator = PerspexLocator.Current.GetService(); - - if (assetLocator == null) - { - throw new InvalidOperationException( - "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); - } - - foreach (var uri in GetUrisFor(type)) - { - if (assetLocator.Exists(uri)) - { - using (var stream = assetLocator.Open(uri)) - { - var initialize = rootInstance as ISupportInitialize; - initialize?.BeginInit(); - return Load(stream, rootInstance, uri); - } - } - } - - throw new FileNotFoundException("Unable to find view for " + type.FullName); - } - - /// - /// Loads XAML from a URI. - /// - /// The URI of the XAML file. - /// - /// A base URI to use if is relative. - /// - /// - /// The optional instance into which the XAML should be loaded. - /// - /// The loaded object. - public object Load(Uri uri, Uri baseUri = null, object rootInstance = null) - { - Contract.Requires(uri != null); - - var assetLocator = PerspexLocator.Current.GetService(); - - if (assetLocator == null) - { - throw new InvalidOperationException( - "Could not create IAssetLoader : maybe Application.RegisterServices() wasn't called?"); - } - - using (var stream = assetLocator.Open(uri, baseUri)) - { - return Load(stream, rootInstance, uri); - } - } - - /// - /// Loads XAML from a string. - /// - /// The string containing the XAML. - /// - /// The optional instance into which the XAML should be loaded. - /// - /// The loaded object. - public object Load(string xaml, object rootInstance = null) - { - Contract.Requires(xaml != null); - - using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xaml))) - { - return Load(stream, rootInstance); - } - } - - /// - /// Loads XAML from a stream. - /// - /// The stream containing the XAML. - /// - /// The optional instance into which the XAML should be loaded. - /// - /// The URI of the XAML - /// The loaded object. - public object Load(Stream stream, object rootInstance = null, Uri uri = null) - { - try - { - if (uri != null) - { - s_uriStack.Push(uri); - } - - var result = base.Load(stream, new Settings - { - RootInstance = rootInstance, - InstanceLifeCycleListener = s_lifeCycleListener, - ParsingContext = new Dictionary - { - { "Uri", uri } - } - }); - - var topLevel = result as TopLevel; - - if (topLevel != null) - { - DelayedBinding.ApplyBindings(topLevel); - } - - return result; - } - finally - { - if (uri != null) - { - s_uriStack.Pop(); - } - } - } - - private static PerspexParserFactory GetParserFactory() - { - if (s_parserFactory == null) - { - s_parserFactory = new PerspexParserFactory(); - } - - return s_parserFactory; - } - - /// - /// Gets the URI for a type. - /// - /// The type. - /// The URI. - private static IEnumerable GetUrisFor(Type type) - { - var asm = type.GetTypeInfo().Assembly.GetName().Name; - var typeName = type.FullName; - yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm); - yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm); - - } - } -} - -namespace Perspex -{ - public static class XamlObjectExtensions - { - public static TObject LoadFromXaml(this TObject obj) - { - Markup.Xaml.PerspexXamlLoader.Load(obj); - return obj; - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Properties/AssemblyInfo.cs b/src/Markup/Perspex.Markup.Xaml/Properties/AssemblyInfo.cs deleted file mode 100644 index b78f719a20..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Reflection; -using Perspex.Metadata; -using System.Runtime.CompilerServices; - -[assembly: AssemblyTitle("Perspex.Markup.Xaml")] -[assembly: XmlnsDefinition("https://github.com/perspex", "Perspex.Markup.Xaml.Data")] -[assembly: XmlnsDefinition("https://github.com/perspex", "Perspex.Markup.Xaml.MarkupExtensions")] -[assembly: XmlnsDefinition("https://github.com/perspex", "Perspex.Markup.Xaml.Styling")] -[assembly: XmlnsDefinition("https://github.com/perspex", "Perspex.Markup.Xaml.Templates")] -[assembly: InternalsVisibleTo("Perspex.Markup.Xaml.UnitTests")] - diff --git a/src/Markup/Perspex.Markup.Xaml/Styling/StyleInclude.cs b/src/Markup/Perspex.Markup.Xaml/Styling/StyleInclude.cs deleted file mode 100644 index 08641e0dfe..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Styling/StyleInclude.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Styling; - -namespace Perspex.Markup.Xaml.Styling -{ - /// - /// Includes a style from a URL. - /// - public class StyleInclude : IStyle - { - private Uri _baseUri; - private IStyle _loaded; - - /// - /// Initializes a new instance of the class. - /// - public StyleInclude() - { - // StyleInclude will usually be loaded from XAML and its URI can be relative to the - // XAML file that its included in, so store the current XAML file's URI if any as - // a base URI. - _baseUri = PerspexXamlLoader.UriContext; - } - - /// - /// Gets or sets the source URL. - /// - public Uri Source { get; set; } - - /// - /// Gets the loaded style. - /// - public IStyle Loaded - { - get - { - if (_loaded == null) - { - var loader = new PerspexXamlLoader(); - _loaded = (IStyle)loader.Load(Source, _baseUri); - } - - return _loaded; - } - } - - /// - public void Attach(IStyleable control, IStyleHost container) - { - if (Source != null) - { - Loaded.Attach(control, container); - } - } - - /// - /// Tries to find a named resource within the style. - /// - /// The resource name. - /// - /// The resource if found, otherwise . - /// - public object FindResource(string name) - { - return Loaded.FindResource(name); - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Templates/ControlTemplate.cs b/src/Markup/Perspex.Markup.Xaml/Templates/ControlTemplate.cs deleted file mode 100644 index 3ce81dc266..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Templates/ControlTemplate.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Controls; -using Perspex.Controls.Templates; -using Perspex.Metadata; -using Perspex.Styling; - -namespace Perspex.Markup.Xaml.Templates -{ - public class ControlTemplate : IControlTemplate - { - [Content] - public TemplateContent Content { get; set; } - - public IControl Build(ITemplatedControl control) - { - return Content.Load(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Templates/DataTemplate.cs b/src/Markup/Perspex.Markup.Xaml/Templates/DataTemplate.cs deleted file mode 100644 index 96e38fd292..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Templates/DataTemplate.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reflection; -using Perspex.Controls; -using Perspex.Controls.Templates; -using Perspex.Metadata; - -namespace Perspex.Markup.Xaml.Templates -{ - public class DataTemplate : IDataTemplate - { - public Type DataType { get; set; } - - [Content] - public TemplateContent Content { get; set; } - - public bool Match(object data) - { - if (DataType == null) - { - return true; - } - else - { - return DataType.GetTypeInfo().IsAssignableFrom(data.GetType().GetTypeInfo()); - } - } - - public IControl Build(object data) - { - var visualTreeForItem = Content.Load(); - visualTreeForItem.DataContext = data; - return visualTreeForItem; - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Templates/FocusAdornerTemplate.cs b/src/Markup/Perspex.Markup.Xaml/Templates/FocusAdornerTemplate.cs deleted file mode 100644 index a1834d3b7c..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Templates/FocusAdornerTemplate.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Controls; -using Perspex.Metadata; - -namespace Perspex.Markup.Xaml.Templates -{ - public class FocusAdornerTemplate : ITemplate - { - [Content] - public TemplateContent Content { get; set; } - - public IControl Build() - { - return Content.Load(); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Templates/ItemsPanelTemplate.cs b/src/Markup/Perspex.Markup.Xaml/Templates/ItemsPanelTemplate.cs deleted file mode 100644 index 8b79c125ea..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Templates/ItemsPanelTemplate.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using Perspex.Controls; -using Perspex.Metadata; - -namespace Perspex.Markup.Xaml.Templates -{ - public class ItemsPanelTemplate : ITemplate - { - [Content] - public TemplateContent Content { get; set; } - - public IPanel Build() - { - return (IPanel)Content.Load(); - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Templates/MemberSelector.cs b/src/Markup/Perspex.Markup.Xaml/Templates/MemberSelector.cs deleted file mode 100644 index 1231fd2a28..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Templates/MemberSelector.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Reflection; -using Perspex.Controls.Templates; - -namespace Perspex.Markup.Xaml.Templates -{ - public class MemberSelector : IMemberSelector - { - public string MemberName { get; set; } - - public object Select(object o) - { - // TODO: Handle nested property paths, changing values etc. - var property = o.GetType().GetRuntimeProperty(MemberName); - return property?.GetValue(o); - } - } -} diff --git a/src/Markup/Perspex.Markup.Xaml/Templates/Template.cs b/src/Markup/Perspex.Markup.Xaml/Templates/Template.cs deleted file mode 100644 index e09a83cbea..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Templates/Template.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Markup.Xaml.Templates -{ - public class Template - { - public TemplateContent Content { get; set; } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Templates/TemplateContent.cs b/src/Markup/Perspex.Markup.Xaml/Templates/TemplateContent.cs deleted file mode 100644 index f9f7aef0f2..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Templates/TemplateContent.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Collections.Generic; -using OmniXaml; -using OmniXaml.ObjectAssembler; -using Perspex.Controls; -using Perspex.Markup.Xaml.Context; - -namespace Perspex.Markup.Xaml.Templates -{ - public class TemplateContent - { - private readonly IEnumerable nodes; - private readonly IRuntimeTypeSource runtimeTypeSource; - - public TemplateContent(IEnumerable nodes, IRuntimeTypeSource runtimeTypeSource) - { - this.nodes = nodes; - this.runtimeTypeSource = runtimeTypeSource; - } - - public Control Load() - { - var assembler = new PerspexObjectAssembler( - runtimeTypeSource, - new TopDownValueContext()); - - foreach (var xamlNode in nodes) - { - assembler.Process(xamlNode); - } - - return (Control)assembler.Result; - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Templates/TemplateLoader.cs b/src/Markup/Perspex.Markup.Xaml/Templates/TemplateLoader.cs deleted file mode 100644 index 34ac77e374..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Templates/TemplateLoader.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Collections.Generic; -using OmniXaml; - -namespace Perspex.Markup.Xaml.Templates -{ - public class TemplateLoader : IDeferredLoader - { - public object Load(IEnumerable nodes, IRuntimeTypeSource runtimeTypeSource) - { - return new TemplateContent(nodes, runtimeTypeSource); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs b/src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs deleted file mode 100644 index 5de25e4c97..0000000000 --- a/src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections; -using System.Reactive.Linq; -using System.Reflection; -using Perspex.Controls; -using Perspex.Controls.Templates; -using Perspex.Data; -using Perspex.Markup.Data; -using Perspex.Markup.Xaml.Data; -using Perspex.Metadata; - -namespace Perspex.Markup.Xaml.Templates -{ - public class TreeDataTemplate : ITreeDataTemplate - { - public Type DataType { get; set; } - - [Content] - public TemplateContent Content { get; set; } - - [AssignBinding] - public Binding ItemsSource { get; set; } - - public bool Match(object data) - { - if (DataType == null) - { - return true; - } - else - { - return DataType.GetTypeInfo().IsAssignableFrom(data.GetType().GetTypeInfo()); - } - } - - public InstancedBinding ItemsSelector(object item) - { - if (ItemsSource != null) - { - var obs = new ExpressionObserver(item, ItemsSource.Path); - return new InstancedBinding(obs); - } - - return null; - } - - public bool IsExpanded(object item) - { - return true; - } - - public IControl Build(object data) - { - var visualTreeForItem = Content.Load(); - visualTreeForItem.DataContext = data; - return visualTreeForItem; - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup/BoolConverters.cs b/src/Markup/Perspex.Markup/BoolConverters.cs deleted file mode 100644 index 80380c12da..0000000000 --- a/src/Markup/Perspex.Markup/BoolConverters.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Linq; - -namespace Perspex.Markup -{ - /// - /// Provides a set of useful s for working with string values. - /// - public static class BoolConverters - { - /// - /// A multi-value converter that returns true if all inputs are true. - /// - public static readonly IMultiValueConverter And = - new FuncMultiValueConverter(x => x.All(y => y)); - } -} diff --git a/src/Markup/Perspex.Markup/ControlLocator.cs b/src/Markup/Perspex.Markup/ControlLocator.cs deleted file mode 100644 index b6080ae059..0000000000 --- a/src/Markup/Perspex.Markup/ControlLocator.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Linq; -using System.Reactive.Linq; -using Perspex.Controls; -using Perspex.LogicalTree; - -namespace Perspex.Markup -{ - /// - /// Locates controls relative to other controls. - /// - public static class ControlLocator - { - /// - /// Tracks a named control relative to another control. - /// - /// - /// The control relative from which the other control should be found. - /// - /// The name of the control to find. - public static IObservable Track(IControl relativeTo, string name) - { - var attached = Observable.FromEventPattern( - x => relativeTo.AttachedToLogicalTree += x, - x => relativeTo.DetachedFromLogicalTree += x) - .Select(x => ((IControl)x.Sender).FindNameScope()) - .StartWith(relativeTo.FindNameScope()); - - var detached = Observable.FromEventPattern( - x => relativeTo.DetachedFromLogicalTree += x, - x => relativeTo.DetachedFromLogicalTree += x) - .Select(x => (INameScope)null); - - return attached.Merge(detached).Select(nameScope => - { - if (nameScope != null) - { - var registered = Observable.FromEventPattern( - x => nameScope.Registered += x, - x => nameScope.Registered -= x) - .Where(x => x.EventArgs.Name == name) - .Select(x => x.EventArgs.Element) - .OfType(); - var unregistered = Observable.FromEventPattern( - x => nameScope.Unregistered += x, - x => nameScope.Unregistered -= x) - .Where(x => x.EventArgs.Name == name) - .Select(_ => (IControl)null); - return registered - .StartWith(nameScope.Find(name)) - .Merge(unregistered); - } - else - { - return Observable.Return(null); - } - }).Switch(); - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/CommonPropertyNames.cs b/src/Markup/Perspex.Markup/Data/CommonPropertyNames.cs deleted file mode 100644 index 5082a89862..0000000000 --- a/src/Markup/Perspex.Markup/Data/CommonPropertyNames.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Markup.Data -{ - public static class CommonPropertyNames - { - public const string IndexerName = "Item"; - } -} diff --git a/src/Markup/Perspex.Markup/Data/ExpressionNode.cs b/src/Markup/Perspex.Markup/Data/ExpressionNode.cs deleted file mode 100644 index b68c1ed426..0000000000 --- a/src/Markup/Perspex.Markup/Data/ExpressionNode.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Subjects; -using Perspex.Data; - -namespace Perspex.Markup.Data -{ - internal abstract class ExpressionNode : IObservable - { - protected static readonly WeakReference UnsetReference = - new WeakReference(PerspexProperty.UnsetValue); - - private WeakReference _target; - - private Subject _subject; - - private WeakReference _value = UnsetReference; - - public ExpressionNode Next { get; set; } - - public WeakReference Target - { - get - { - return _target; - } - set - { - var newInstance = value?.Target; - var oldInstance = _target?.Target; - - if (!object.Equals(oldInstance, newInstance)) - { - if (oldInstance != null) - { - Unsubscribe(oldInstance); - } - - _target = value; - - if (newInstance != null) - { - SubscribeAndUpdate(_target); - } - else - { - CurrentValue = UnsetReference; - } - - if (Next != null) - { - Next.Target = _value; - } - } - } - } - - public WeakReference CurrentValue - { - get - { - return _value; - } - - set - { - _value = value; - - if (Next != null) - { - Next.Target = value; - } - - _subject?.OnNext(value.Target); - } - } - - public virtual bool SetValue(object value, BindingPriority priority) - { - return Next?.SetValue(value, priority) ?? false; - } - - public virtual IDisposable Subscribe(IObserver observer) - { - if (Next != null) - { - return Next.Subscribe(observer); - } - else - { - if (_subject == null) - { - _subject = new Subject(); - } - - observer.OnNext(CurrentValue.Target); - return _subject.Subscribe(observer); - } - } - - protected virtual void SubscribeAndUpdate(WeakReference reference) - { - CurrentValue = reference; - } - - protected virtual void SendValidationStatus(ValidationStatus status) - { - //Even if elements only bound to sub-values, send validation changes along so they will be surfaced to the UI level. - if (_subject != null) - { - _subject.OnNext(status); - } - else - { - Next?.SendValidationStatus(status); - } - } - - protected virtual void Unsubscribe(object target) - { - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/ExpressionNodeBuilder.cs b/src/Markup/Perspex.Markup/Data/ExpressionNodeBuilder.cs deleted file mode 100644 index 93b38a438a..0000000000 --- a/src/Markup/Perspex.Markup/Data/ExpressionNodeBuilder.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Markup.Data.Parsers; - -namespace Perspex.Markup.Data -{ - internal static class ExpressionNodeBuilder - { - public static ExpressionNode Build(string expression) - { - if (string.IsNullOrWhiteSpace(expression)) - { - throw new ArgumentException("'expression' may not be empty."); - } - - var reader = new Reader(expression); - var node = ExpressionParser.Parse(reader); - - if (!reader.End) - { - throw new ExpressionParseException(reader.Position, "Expected end of expression."); - } - - return node; - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/ExpressionObserver.cs b/src/Markup/Perspex.Markup/Data/ExpressionObserver.cs deleted file mode 100644 index d7fd25d237..0000000000 --- a/src/Markup/Perspex.Markup/Data/ExpressionObserver.cs +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Reactive; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using Perspex.Data; -using Perspex.Markup.Data.Plugins; - -namespace Perspex.Markup.Data -{ - /// - /// Observes and sets the value of an expression on an object. - /// - public class ExpressionObserver : ObservableBase, IDescription - { - /// - /// An ordered collection of property accessor plugins that can be used to customize - /// the reading and subscription of property values on a type. - /// - public static readonly IList PropertyAccessors = - new List - { - new PerspexPropertyAccessorPlugin(), - new InpcPropertyAccessorPlugin(), - }; - - /// - /// An ordered collection of validation checker plugins that can be used to customize - /// the validation of view model and model data. - /// - public static readonly IList ValidationCheckers = - new List - { - new IndeiValidationCheckerPlugin(), - new ExceptionValidationCheckerPlugin() - }; - - private readonly WeakReference _root; - private readonly Func _rootGetter; - private readonly IObservable _rootObservable; - private readonly IObservable _update; - private IDisposable _rootObserverSubscription; - private IDisposable _updateSubscription; - private int _count; - private readonly ExpressionNode _node; - private ValidationMethods _methods; - - /// - /// Initializes a new instance of the class. - /// - /// The root object. - /// The expression. - /// The validation methods to enable on this observer. - public ExpressionObserver(object root, string expression, ValidationMethods methods = ValidationMethods.None) - { - Contract.Requires(expression != null); - - _root = new WeakReference(root); - _methods = methods; - if (!string.IsNullOrWhiteSpace(expression)) - { - _node = ExpressionNodeBuilder.Build(expression); - } - - Expression = expression; - } - - /// - /// Initializes a new instance of the class. - /// - /// An observable which provides the root object. - /// The expression. - /// The validation methods to enable on this observer. - public ExpressionObserver(IObservable rootObservable, string expression, ValidationMethods methods = ValidationMethods.None) - { - Contract.Requires(rootObservable != null); - Contract.Requires(expression != null); - - _rootObservable = rootObservable; - _methods = methods; - if (!string.IsNullOrWhiteSpace(expression)) - { - _node = ExpressionNodeBuilder.Build(expression); - } - - Expression = expression; - } - - /// - /// Initializes a new instance of the class. - /// - /// A function which gets the root object. - /// The expression. - /// An observable which triggers a re-read of the getter. - /// The validation methods to enable on this observer. - public ExpressionObserver( - Func rootGetter, - string expression, - IObservable update, - ValidationMethods methods = ValidationMethods.None) - { - Contract.Requires(rootGetter != null); - Contract.Requires(expression != null); - Contract.Requires(update != null); - - _rootGetter = rootGetter; - _update = update; - _methods = methods; - if (!string.IsNullOrWhiteSpace(expression)) - { - _node = ExpressionNodeBuilder.Build(expression); - } - - Expression = expression; - } - - /// - /// Attempts to set the value of a property expression. - /// - /// The value to set. - /// The binding priority to use. - /// - /// True if the value could be set; false if the expression does not evaluate to a - /// property. - /// - public bool SetValue(object value, BindingPriority priority = BindingPriority.LocalValue) - { - IncrementCount(); - - if (_rootGetter != null && _node != null) - { - _node.Target = new WeakReference(_rootGetter()); - } - - try - { - return _node?.SetValue(value, priority) ?? false; - } - finally - { - DecrementCount(); - } - } - - /// - /// Gets the expression being observed. - /// - public string Expression { get; } - - /// - /// Gets the type of the expression result or null if the expression could not be - /// evaluated. - /// - public Type ResultType - { - get - { - IncrementCount(); - - try - { - if (_node != null) - { - return (Leaf as PropertyAccessorNode)?.PropertyType; - } - else if(_rootGetter != null) - { - return _rootGetter()?.GetType(); - } - else - { - return _root.Target?.GetType(); - } - } - finally - { - DecrementCount(); - } - } - } - - /// - string IDescription.Description => Expression; - - /// - /// Gets the root expression node. Used for testing. - /// - internal ExpressionNode Node => _node; - - /// - /// Gets the leaf node. - /// - private ExpressionNode Leaf - { - get - { - var node = _node; - while (node.Next != null) node = node.Next; - return node; - } - } - - /// - protected override IDisposable SubscribeCore(IObserver observer) - { - IncrementCount(); - - if (_node != null) - { - IObservable source = _node; - - if (_rootObservable != null) - { - source = source.TakeUntil(_rootObservable.LastOrDefaultAsync()); - } - else if (_update != null) - { - source = source.TakeUntil(_update.LastOrDefaultAsync()); - } - var validationFiltered = source.Where(o => (o as ValidationStatus)?.Match(_methods) ?? true); - var subscription = validationFiltered.Subscribe(observer); - - return Disposable.Create(() => - { - DecrementCount(); - subscription.Dispose(); - }); - } - else if (_rootObservable != null) - { - return _rootObservable.Subscribe(observer); - } - else - { - if (_update == null) - { - return Observable.Never() - .StartWith(_root.Target) - .Subscribe(observer); - } - else - { - return _update - .Select(_ => _rootGetter()) - .StartWith(_rootGetter()) - .Subscribe(observer); - } - } - } - - private void IncrementCount() - { - if (_count++ == 0 && _node != null) - { - if (_rootGetter != null) - { - _node.Target = new WeakReference(_rootGetter()); - - if (_update != null) - { - _updateSubscription = _update.Subscribe(x => - _node.Target = new WeakReference(_rootGetter())); - } - } - else if (_rootObservable != null) - { - _rootObserverSubscription = _rootObservable.Subscribe(x => - _node.Target = new WeakReference(x)); - } - else - { - _node.Target = _root; - } - } - } - - private void DecrementCount() - { - if (--_count == 0 && _node != null) - { - if (_rootObserverSubscription != null) - { - _rootObserverSubscription.Dispose(); - _rootObserverSubscription = null; - } - - if (_updateSubscription != null) - { - _updateSubscription.Dispose(); - _updateSubscription = null; - } - - _node.Target = null; - } - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/ExpressionParseException.cs b/src/Markup/Perspex.Markup/Data/ExpressionParseException.cs deleted file mode 100644 index d92f42cab7..0000000000 --- a/src/Markup/Perspex.Markup/Data/ExpressionParseException.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Markup.Data.Parsers; - -namespace Perspex.Markup.Data -{ - /// - /// Exception thrown when could not parse the provided - /// expression string. - /// - public class ExpressionParseException : Exception - { - /// - /// Initializes a new instance of the class. - /// - /// The column position of the error. - /// The exception message. - public ExpressionParseException(int column, string message) - : base(message) - { - Column = column; - } - - /// - /// Gets the column position at which the error occurred. - /// - public int Column { get; } - } -} diff --git a/src/Markup/Perspex.Markup/Data/ExpressionSubject.cs b/src/Markup/Perspex.Markup/Data/ExpressionSubject.cs deleted file mode 100644 index 2ba0a5b2db..0000000000 --- a/src/Markup/Perspex.Markup/Data/ExpressionSubject.cs +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using Perspex.Data; -using Perspex.Logging; -using Perspex.Utilities; - -namespace Perspex.Markup.Data -{ - /// - /// Turns an into a subject that can be bound two-way with - /// a value converter. - /// - public class ExpressionSubject : ISubject, IDescription - { - private readonly ExpressionObserver _inner; - private readonly Type _targetType; - private readonly object _fallbackValue; - private readonly BindingPriority _priority; - - /// - /// Initializes a new instance of the class. - /// - /// The . - /// The type to convert the value to. - public ExpressionSubject(ExpressionObserver inner, Type targetType) - : this(inner, targetType, DefaultValueConverter.Instance) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The . - /// The type to convert the value to. - /// The value converter to use. - /// - /// A parameter to pass to . - /// - /// - /// The value to use when the binding is unable to produce a value. - /// - /// The binding priority. - public ExpressionSubject( - ExpressionObserver inner, - Type targetType, - IValueConverter converter, - object converterParameter = null, - object fallbackValue = null, - BindingPriority priority = BindingPriority.LocalValue) - { - Contract.Requires(inner != null); - Contract.Requires(targetType != null); - Contract.Requires(converter != null); - - _inner = inner; - _targetType = targetType; - Converter = converter; - ConverterParameter = converterParameter; - _fallbackValue = fallbackValue; - _priority = priority; - } - - /// - /// Gets the converter to use on the expression. - /// - public IValueConverter Converter { get; } - - /// - /// Gets a parameter to pass to . - /// - public object ConverterParameter { get; } - - /// - string IDescription.Description => _inner.Expression; - - /// - public void OnCompleted() - { - } - - /// - public void OnError(Exception error) - { - } - - /// - public void OnNext(object value) - { - var type = _inner.ResultType; - - if (type != null) - { - var converted = Converter.ConvertBack( - value, - type, - ConverterParameter, - CultureInfo.CurrentUICulture); - - if (converted == PerspexProperty.UnsetValue) - { - converted = TypeUtilities.Default(type); - _inner.SetValue(converted, _priority); - } - else if (converted is BindingError) - { - var error = converted as BindingError; - - Logger.Error( - LogArea.Binding, - this, - "Error binding to {Expression}: {Message}", - _inner.Expression, - error.Exception.Message); - - if (_fallbackValue != null) - { - if (TypeUtilities.TryConvert( - type, - _fallbackValue, - CultureInfo.InvariantCulture, - out converted)) - { - _inner.SetValue(converted, _priority); - } - else - { - Logger.Error( - LogArea.Binding, - this, - "Could not convert FallbackValue {FallbackValue} to {Type}", - _fallbackValue, - type); - } - } - } - else - { - _inner.SetValue(converted, _priority); - } - } - } - - /// - public IDisposable Subscribe(IObserver observer) - { - return _inner.Select(ConvertValue).Subscribe(observer); - } - - private object ConvertValue(object value) - { - var converted = - value as BindingError ?? - value as ValidationStatus ?? - Converter.Convert( - value, - _targetType, - ConverterParameter, - CultureInfo.CurrentUICulture); - - if (_fallbackValue != null && - (converted == PerspexProperty.UnsetValue || - converted is BindingError)) - { - var error = converted as BindingError; - - if (TypeUtilities.TryConvert( - _targetType, - _fallbackValue, - CultureInfo.InvariantCulture, - out converted)) - { - if (error != null) - { - converted = new BindingError(error.Exception, converted); - } - } - else - { - converted = new BindingError( - new InvalidCastException( - $"Could not convert FallbackValue '{_fallbackValue}' to '{_targetType}'")); - } - } - - return converted; - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/IndexerNode.cs b/src/Markup/Perspex.Markup/Data/IndexerNode.cs deleted file mode 100644 index 59082f1bd8..0000000000 --- a/src/Markup/Perspex.Markup/Data/IndexerNode.cs +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Utilities; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Reflection; - -namespace Perspex.Markup.Data -{ - internal class IndexerNode : ExpressionNode, - IWeakSubscriber, - IWeakSubscriber - { - public IndexerNode(IList arguments) - { - Arguments = arguments; - } - - public IList Arguments { get; } - - void IWeakSubscriber.OnEvent(object sender, NotifyCollectionChangedEventArgs e) - { - var update = false; - if (sender is IList) - { - object indexObject; - if (!TypeUtilities.TryConvert(typeof(int), Arguments[0], CultureInfo.InvariantCulture, out indexObject)) - { - return; - } - var index = (int)indexObject; - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - update = index >= e.NewStartingIndex; - break; - case NotifyCollectionChangedAction.Remove: - update = index >= e.OldStartingIndex; - break; - case NotifyCollectionChangedAction.Replace: - update = index >= e.NewStartingIndex && - index < e.NewStartingIndex + e.NewItems.Count; - break; - case NotifyCollectionChangedAction.Move: - update = (index >= e.NewStartingIndex && - index < e.NewStartingIndex + e.NewItems.Count) || - (index >= e.OldStartingIndex && - index < e.OldStartingIndex + e.OldItems.Count); - break; - case NotifyCollectionChangedAction.Reset: - update = true; - break; - } - } - else - { - update = true; - } - - if (update) - { - CurrentValue = new WeakReference(GetValue(sender)); - } - } - - void IWeakSubscriber.OnEvent(object sender, PropertyChangedEventArgs e) - { - var typeInfo = sender.GetType().GetTypeInfo(); - - if (typeInfo.GetDeclaredProperty(e.PropertyName) == null) - { - return; - } - - if (typeInfo.GetDeclaredProperty(e.PropertyName).GetIndexParameters().Any()) - { - CurrentValue = new WeakReference(GetValue(sender)); - } - } - - protected override void SubscribeAndUpdate(WeakReference reference) - { - object target = reference.Target; - - CurrentValue = new WeakReference(GetValue(target)); - - var incc = target as INotifyCollectionChanged; - - if (incc != null) - { - WeakSubscriptionManager.Subscribe( - incc, - nameof(incc.CollectionChanged), - this); - } - - var inpc = target as INotifyPropertyChanged; - - if (inpc != null) - { - WeakSubscriptionManager.Subscribe( - inpc, - nameof(inpc.PropertyChanged), - this); - } - } - - protected override void Unsubscribe(object target) - { - var incc = target as INotifyCollectionChanged; - - if (incc != null) - { - WeakSubscriptionManager.Unsubscribe( - incc, - nameof(incc.CollectionChanged), - this); - } - - var inpc = target as INotifyPropertyChanged; - - if (inpc != null) - { - WeakSubscriptionManager.Unsubscribe( - inpc, - nameof(inpc.PropertyChanged), - this); - } - } - - private object GetValue(object target) - { - var typeInfo = target.GetType().GetTypeInfo(); - var list = target as IList; - var dictionary = target as IDictionary; - var indexerProperty = GetIndexer(typeInfo); - var indexerParameters = indexerProperty?.GetIndexParameters(); - if (indexerProperty != null && indexerParameters.Length == Arguments.Count) - { - var convertedObjectArray = new object[indexerParameters.Length]; - for (int i = 0; i < Arguments.Count; i++) - { - object temp = null; - if (!TypeUtilities.TryConvert(indexerParameters[i].ParameterType, Arguments[i], CultureInfo.InvariantCulture, out temp)) - { - return PerspexProperty.UnsetValue; - } - convertedObjectArray[i] = temp; - } - var intArgs = convertedObjectArray.OfType().ToArray(); - - // Try special cases where we can validate indicies - if (typeInfo.IsArray) - { - return GetValueFromArray((Array)target, intArgs); - } - else if (Arguments.Count == 1) - { - if (list != null) - { - if (intArgs.Length == Arguments.Count && intArgs[0] >= 0 && intArgs[0] < list.Count) - { - return list[intArgs[0]]; - } - return PerspexProperty.UnsetValue; - } - else if (dictionary != null) - { - if (dictionary.Contains(convertedObjectArray[0])) - { - return dictionary[convertedObjectArray[0]]; - } - return PerspexProperty.UnsetValue; - } - else - { - // Fallback to unchecked access - return indexerProperty.GetValue(target, convertedObjectArray); - } - } - else - { - // Fallback to unchecked access - return indexerProperty.GetValue(target, convertedObjectArray); - } - } - // Multidimensional arrays end up here because the indexer search picks up the IList indexer instead of the - // multidimensional indexer, which doesn't take the same number of arguments - else if (typeInfo.IsArray) - { - return GetValueFromArray((Array)target); - } - - return PerspexProperty.UnsetValue; - } - - private object GetValueFromArray(Array array) - { - int[] intArgs; - if (!ConvertArgumentsToInts(out intArgs)) - return PerspexProperty.UnsetValue; - return GetValueFromArray(array, intArgs); - } - - private object GetValueFromArray(Array array, int[] indicies) - { - if (ValidBounds(indicies, array)) - { - return array.GetValue(indicies); - } - return PerspexProperty.UnsetValue; - } - - private bool ConvertArgumentsToInts(out int[] intArgs) - { - intArgs = new int[Arguments.Count]; - for (int i = 0; i < Arguments.Count; ++i) - { - object value; - if (!TypeUtilities.TryConvert(typeof(int), Arguments[i], CultureInfo.InvariantCulture, out value)) - { - return false; - } - intArgs[i] = (int)value; - } - return true; - } - - private static PropertyInfo GetIndexer(TypeInfo typeInfo) - { - PropertyInfo indexer; - for (;typeInfo != null; typeInfo = typeInfo.BaseType?.GetTypeInfo()) - { - // Check for the default indexer name first to make this faster. - // This will only be false when a class in VB has a custom indexer name. - if ((indexer = typeInfo.GetDeclaredProperty(CommonPropertyNames.IndexerName)) != null) - { - return indexer; - } - foreach (var property in typeInfo.DeclaredProperties) - { - if (property.GetIndexParameters().Any()) - { - return property; - } - } - } - return null; - } - - private bool ValidBounds(int[] indicies, Array array) - { - if (indicies.Length == array.Rank) - { - for (var i = 0; i < indicies.Length; ++i) - { - if (indicies[i] >= array.GetLength(i)) - { - return false; - } - } - - return true; - } - else - { - return false; - } - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/LogicalNotNode.cs b/src/Markup/Perspex.Markup/Data/LogicalNotNode.cs deleted file mode 100644 index 9a1eec8d83..0000000000 --- a/src/Markup/Perspex.Markup/Data/LogicalNotNode.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using System.Reactive.Linq; -using Perspex.Data; - -namespace Perspex.Markup.Data -{ - internal class LogicalNotNode : ExpressionNode - { - public override bool SetValue(object value, BindingPriority priority) - { - return false; - } - - public override IDisposable Subscribe(IObserver observer) - { - return Next.Select(Negate).Subscribe(observer); - } - - private static object Negate(object v) - { - if (v != PerspexProperty.UnsetValue) - { - var s = v as string; - - if (s != null) - { - bool result; - - if (bool.TryParse(s, out result)) - { - return !result; - } - } - else - { - try - { - var boolean = Convert.ToBoolean(v, CultureInfo.InvariantCulture); - return !boolean; - } - catch - { - // TODO: Maybe should log something here. - } - } - } - - return PerspexProperty.UnsetValue; - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/Parsers/ArgumentListParser.cs b/src/Markup/Perspex.Markup/Data/Parsers/ArgumentListParser.cs deleted file mode 100644 index 21061d7075..0000000000 --- a/src/Markup/Perspex.Markup/Data/Parsers/ArgumentListParser.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Text; - -namespace Perspex.Markup.Data.Parsers -{ - internal static class ArgumentListParser - { - public static IList Parse(Reader r, char open, char close) - { - if (r.Peek == open) - { - var result = new List(); - - r.Take(); - - while (!r.End) - { - var builder = new StringBuilder(); - while (!r.End && r.Peek != ',' && r.Peek != close && !char.IsWhiteSpace(r.Peek)) - { - builder.Append(r.Take()); - } - if (builder.Length == 0) - { - throw new ExpressionParseException(r.Position, "Expected indexer argument."); - } - result.Add(builder.ToString()); - - r.SkipWhitespace(); - - if (r.End) - { - throw new ExpressionParseException(r.Position, "Expected ','."); - } - else if (r.TakeIf(close)) - { - return result; - } - else - { - if (r.Take() != ',') - { - throw new ExpressionParseException(r.Position, "Expected ','."); - } - - r.SkipWhitespace(); - } - } - - if (!r.End) - { - r.Take(); - return result; - } - else - { - throw new ExpressionParseException(r.Position, "Expected ']'."); - } - } - - return null; - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/Parsers/ExpressionParser.cs b/src/Markup/Perspex.Markup/Data/Parsers/ExpressionParser.cs deleted file mode 100644 index 983336dc11..0000000000 --- a/src/Markup/Perspex.Markup/Data/Parsers/ExpressionParser.cs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Perspex.Markup.Data.Parsers -{ - internal static class ExpressionParser - { - public static ExpressionNode Parse(Reader r) - { - var nodes = new List(); - var state = State.Start; - - while (!r.End && state != State.End) - { - switch (state) - { - case State.Start: - state = ParseStart(r, nodes); - break; - - case State.AfterMember: - state = ParseAfterMember(r, nodes); - break; - - case State.BeforeMember: - state = ParseBeforeMember(r, nodes); - break; - - case State.AttachedProperty: - state = ParseAttachedProperty(r, nodes); - break; - } - } - - if (state == State.BeforeMember) - { - throw new ExpressionParseException(r.Position, "Unexpected end of expression."); - } - - for (int n = 0; n < nodes.Count - 1; ++n) - { - nodes[n].Next = nodes[n + 1]; - } - - return nodes.FirstOrDefault(); - } - - private static State ParseStart(Reader r, IList nodes) - { - if (ParseNot(r)) - { - nodes.Add(new LogicalNotNode()); - return State.Start; - } - else if (ParseOpenBrace(r)) - { - return State.AttachedProperty; - } - else - { - var identifier = IdentifierParser.Parse(r); - - if (identifier != null) - { - nodes.Add(new PropertyAccessorNode(identifier)); - return State.AfterMember; - } - } - - return State.End; - } - - private static State ParseAfterMember(Reader r, IList nodes) - { - if (ParseMemberAccessor(r)) - { - return State.BeforeMember; - } - else - { - var args = ArgumentListParser.Parse(r, '[', ']'); - - if (args != null) - { - if (args.Count == 0) - { - throw new ExpressionParseException(r.Position, "Indexer may not be empty."); - } - - nodes.Add(new IndexerNode(args)); - return State.AfterMember; - } - } - - return State.End; - } - - private static State ParseBeforeMember(Reader r, IList nodes) - { - if (ParseOpenBrace(r)) - { - return State.AttachedProperty; - } - else - { - var identifier = IdentifierParser.Parse(r); - - if (identifier != null) - { - nodes.Add(new PropertyAccessorNode(identifier)); - return State.AfterMember; - } - - return State.End; - } - } - - private static State ParseAttachedProperty(Reader r, List nodes) - { - var owner = IdentifierParser.Parse(r); - - if (r.End || !r.TakeIf('.')) - { - throw new ExpressionParseException(r.Position, "Invalid attached property name."); - } - - var name = IdentifierParser.Parse(r); - - if (r.End || !r.TakeIf(')')) - { - throw new ExpressionParseException(r.Position, "Expected ')'."); - } - - nodes.Add(new PropertyAccessorNode(owner + '.' + name)); - return State.AfterMember; - } - - private static bool ParseNot(Reader r) - { - return !r.End && r.TakeIf('!'); - } - - private static bool ParseMemberAccessor(Reader r) - { - return !r.End && r.TakeIf('.'); - } - - private static bool ParseOpenBrace(Reader r) - { - return !r.End && r.TakeIf('('); - } - - private enum State - { - Start, - AfterMember, - BeforeMember, - AttachedProperty, - End, - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/Parsers/IdentifierParser.cs b/src/Markup/Perspex.Markup/Data/Parsers/IdentifierParser.cs deleted file mode 100644 index 8100099cd7..0000000000 --- a/src/Markup/Perspex.Markup/Data/Parsers/IdentifierParser.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Globalization; -using System.Text; - -namespace Perspex.Markup.Data.Parsers -{ - internal static class IdentifierParser - { - public static string Parse(Reader r) - { - if (IsValidIdentifierStart(r.Peek)) - { - var result = new StringBuilder(); - - while (!r.End && IsValidIdentifierChar(r.Peek)) - { - result.Append(r.Take()); - } - - return result.ToString(); - } - else - { - return null; - } - } - - private static bool IsValidIdentifierStart(char c) - { - return char.IsLetter(c) || c == '_'; - } - - private static bool IsValidIdentifierChar(char c) - { - if (IsValidIdentifierStart(c)) - { - return true; - } - else - { - var cat = CharUnicodeInfo.GetUnicodeCategory(c); - return cat == UnicodeCategory.NonSpacingMark || - cat == UnicodeCategory.SpacingCombiningMark || - cat == UnicodeCategory.ConnectorPunctuation || - cat == UnicodeCategory.Format || - cat == UnicodeCategory.DecimalDigitNumber; - } - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/Parsers/Reader.cs b/src/Markup/Perspex.Markup/Data/Parsers/Reader.cs deleted file mode 100644 index 6c86dbf733..0000000000 --- a/src/Markup/Perspex.Markup/Data/Parsers/Reader.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Markup.Data.Parsers -{ - internal class Reader - { - private readonly string _s; - private int _i; - - public Reader(string s) - { - _s = s; - } - - public bool End => _i == _s.Length; - public char Peek => _s[_i]; - public int Position => _i; - public char Take() => _s[_i++]; - - public void SkipWhitespace() - { - while (!End && char.IsWhiteSpace(Peek)) - { - Take(); - } - } - - public bool TakeIf(char c) - { - if (Peek == c) - { - Take(); - return true; - } - else - { - return false; - } - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/Plugins/ExceptionValidationCheckerPlugin.cs b/src/Markup/Perspex.Markup/Data/Plugins/ExceptionValidationCheckerPlugin.cs deleted file mode 100644 index 5110f4713e..0000000000 --- a/src/Markup/Perspex.Markup/Data/Plugins/ExceptionValidationCheckerPlugin.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Perspex.Data; - -namespace Perspex.Markup.Data.Plugins -{ - /// - /// Validates properties that report errors by throwing exceptions. - /// - public class ExceptionValidationCheckerPlugin : IValidationCheckerPlugin - { - - /// - public bool Match(WeakReference reference) => true; - - - /// - public ValidationCheckerBase Start(WeakReference reference, string name, IPropertyAccessor accessor, Action callback) - { - return new ExceptionValidationChecker(reference, name, accessor, callback); - } - - private class ExceptionValidationChecker : ValidationCheckerBase - { - public ExceptionValidationChecker(WeakReference reference, string name, IPropertyAccessor accessor, Action callback) - : base(reference, name, accessor, callback) - { - } - - public override bool SetValue(object value, BindingPriority priority) - { - try - { - var success = base.SetValue(value, priority); - SendValidationCallback(new ExceptionValidationStatus(null)); - return success; - } - catch (Exception ex) - { - SendValidationCallback(new ExceptionValidationStatus(ex)); - } - return false; - } - } - - /// - /// Describes the current validation status after setting a property value. - /// - public class ExceptionValidationStatus : ValidationStatus - { - internal ExceptionValidationStatus(Exception exception) - { - Exception = exception; - } - - /// - /// The thrown exception. If there was no thrown exception, null. - /// - public Exception Exception { get; } - - - /// - public override bool IsValid => Exception == null; - - public override bool Match(ValidationMethods enabledMethods) - { - return (enabledMethods & ValidationMethods.Exceptions) != 0; - } - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/Plugins/IPropertyAccessor.cs b/src/Markup/Perspex.Markup/Data/Plugins/IPropertyAccessor.cs deleted file mode 100644 index 776993b220..0000000000 --- a/src/Markup/Perspex.Markup/Data/Plugins/IPropertyAccessor.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Data; - -namespace Perspex.Markup.Data.Plugins -{ - /// - /// Defines an accessor to a property on an object returned by a - /// - /// - public interface IPropertyAccessor : IDisposable - { - /// - /// Gets the type of the property. - /// - Type PropertyType { get; } - - /// - /// Gets the current value of the property. - /// - object Value { get; } - - /// - /// Sets the property value. - /// - /// - /// The value to set. Guaranteed to be of a valid type for the property. - /// - /// - /// The priority with which to set the value. - /// - /// - /// True if the property was set; false if the property could not be set. - /// - bool SetValue(object value, BindingPriority priority); - } -} diff --git a/src/Markup/Perspex.Markup/Data/Plugins/IPropertyAccessorPlugin.cs b/src/Markup/Perspex.Markup/Data/Plugins/IPropertyAccessorPlugin.cs deleted file mode 100644 index 2f36352983..0000000000 --- a/src/Markup/Perspex.Markup/Data/Plugins/IPropertyAccessorPlugin.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections; - -namespace Perspex.Markup.Data.Plugins -{ - /// - /// Defines how a member is read, written and observed by an - /// . - /// - public interface IPropertyAccessorPlugin - { - /// - /// Checks whether this plugin can handle accessing the properties of the specified object. - /// - /// A weak reference to the object. - /// True if the plugin can handle the object; otherwise false. - bool Match(WeakReference reference); - - /// - /// Starts monitoring the value of a property on an object. - /// - /// A weak reference to the object. - /// The property name. - /// A function to call when the property changes. - /// - /// An interface through which future interactions with the - /// property will be made. - /// - IPropertyAccessor Start( - WeakReference reference, - string propertyName, - Action changed); - } -} diff --git a/src/Markup/Perspex.Markup/Data/Plugins/IValidationCheckerPlugin.cs b/src/Markup/Perspex.Markup/Data/Plugins/IValidationCheckerPlugin.cs deleted file mode 100644 index 9aff3cf3cc..0000000000 --- a/src/Markup/Perspex.Markup/Data/Plugins/IValidationCheckerPlugin.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Perspex.Data; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Perspex.Markup.Data.Plugins -{ - /// - /// Defines how view model data validation is observed by an . - /// - public interface IValidationCheckerPlugin - { - - /// - /// Checks whether the data uses a validation scheme supported by this plugin. - /// - /// A weak reference to the data. - /// true if this plugin can observe the validation; otherwise, false. - bool Match(WeakReference reference); - - /// - /// Starts monitering the validation state of an object for the given property. - /// - /// A weak reference to the object. - /// The property name. - /// An underlying to access the property. - /// A function to call when the validation state changes. - /// - /// A subclass through which future interactions with the - /// property will be made. - /// - ValidationCheckerBase Start(WeakReference reference, string name, IPropertyAccessor accessor, Action callback); - } -} diff --git a/src/Markup/Perspex.Markup/Data/Plugins/IndeiValidationCheckerPlugin.cs b/src/Markup/Perspex.Markup/Data/Plugins/IndeiValidationCheckerPlugin.cs deleted file mode 100644 index ee4e87076f..0000000000 --- a/src/Markup/Perspex.Markup/Data/Plugins/IndeiValidationCheckerPlugin.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Perspex.Data; -using System.ComponentModel; -using System.Collections; -using Perspex.Utilities; - -namespace Perspex.Markup.Data.Plugins -{ - /// - /// Validates properties on objects that implement . - /// - public class IndeiValidationCheckerPlugin : IValidationCheckerPlugin - { - /// - public bool Match(WeakReference reference) - { - return reference.Target is INotifyDataErrorInfo; - } - - /// - public ValidationCheckerBase Start(WeakReference reference, string name, IPropertyAccessor accessor, Action callback) - { - return new IndeiValidationChecker(reference, name, accessor, callback); - } - - private class IndeiValidationChecker : ValidationCheckerBase, IWeakSubscriber - { - public IndeiValidationChecker(WeakReference reference, string name, IPropertyAccessor accessor, Action callback) - : base(reference, name, accessor, callback) - { - var target = reference.Target as INotifyDataErrorInfo; - if (target != null) - { - if (target.HasErrors) - { - SendValidationCallback(new IndeiValidationStatus(target.GetErrors(name))); - } - WeakSubscriptionManager.Subscribe( - target, - nameof(target.ErrorsChanged), - this); - } - } - - public override void Dispose() - { - base.Dispose(); - var target = _reference.Target as INotifyDataErrorInfo; - if (target != null) - { - WeakSubscriptionManager.Unsubscribe( - target, - nameof(target.ErrorsChanged), - this); - } - } - - public void OnEvent(object sender, DataErrorsChangedEventArgs e) - { - if (e.PropertyName == _name || string.IsNullOrEmpty(e.PropertyName)) - { - var indei = _reference.Target as INotifyDataErrorInfo; - SendValidationCallback(new IndeiValidationStatus(indei.GetErrors(e.PropertyName))); - } - } - } - - /// - /// Describes the current validation status of a property as reported by an object that implements . - /// - public class IndeiValidationStatus : ValidationStatus - { - internal IndeiValidationStatus(IEnumerable errors) - { - Errors = errors; - } - - /// - public override bool IsValid => !Errors.OfType().Any(); - - /// - /// The errors on the given property and on the object as a whole. - /// - public IEnumerable Errors { get; } - - public override bool Match(ValidationMethods enabledMethods) - { - return (enabledMethods & ValidationMethods.INotifyDataErrorInfo) != 0; - } - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs b/src/Markup/Perspex.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs deleted file mode 100644 index a16903ea42..0000000000 --- a/src/Markup/Perspex.Markup/Data/Plugins/InpcPropertyAccessorPlugin.cs +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.ComponentModel; -using System.Linq; -using System.Reactive.Linq; -using System.Reflection; -using Perspex.Data; -using Perspex.Logging; -using Perspex.Utilities; -using System.Collections; - -namespace Perspex.Markup.Data.Plugins -{ - /// - /// Reads a property from a standard C# object that optionally supports the - /// interface. - /// - public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin - { - /// - /// Checks whether this plugin can handle accessing the properties of the specified object. - /// - /// The object. - /// True if the plugin can handle the object; otherwise false. - public bool Match(WeakReference reference) - { - Contract.Requires(reference != null); - - return true; - } - - /// - /// Starts monitoring the value of a property on an object. - /// - /// The object. - /// The property name. - /// A function to call when the property changes. - /// - /// An interface through which future interactions with the - /// property will be made. - /// - public IPropertyAccessor Start( - WeakReference reference, - string propertyName, - Action changed) - { - Contract.Requires(reference != null); - Contract.Requires(propertyName != null); - Contract.Requires(changed != null); - - var instance = reference.Target; - var p = instance.GetType().GetRuntimeProperties().FirstOrDefault(_ => _.Name == propertyName); - - if (p != null) - { - return new Accessor(reference, p, changed); - } - else - { - var message = $"Could not find CLR property '{propertyName}' on '{instance}'"; - var exception = new MissingMemberException(message); - return new PropertyError(new BindingError(exception)); - } - } - - private class Accessor : IPropertyAccessor, IWeakSubscriber - { - private readonly WeakReference _reference; - private readonly PropertyInfo _property; - private readonly Action _changed; - - public Accessor( - WeakReference reference, - PropertyInfo property, - Action changed) - { - Contract.Requires(reference != null); - Contract.Requires(property != null); - - _reference = reference; - _property = property; - _changed = changed; - - var inpc = reference.Target as INotifyPropertyChanged; - - if (inpc != null) - { - WeakSubscriptionManager.Subscribe( - inpc, - nameof(inpc.PropertyChanged), - this); - } - else - { - Logger.Warning( - LogArea.Binding, - this, - "Bound to property {Property} on {Source} which does not implement INotifyPropertyChanged", - property.Name, - reference.Target, - reference.Target.GetType()); - } - } - - public Type PropertyType => _property.PropertyType; - - public object Value => _property.GetValue(_reference.Target); - - public void Dispose() - { - var inpc = _reference.Target as INotifyPropertyChanged; - - if (inpc != null) - { - WeakSubscriptionManager.Unsubscribe( - inpc, - nameof(inpc.PropertyChanged), - this); - } - } - - public bool SetValue(object value, BindingPriority priority) - { - if (_property.CanWrite) - { - _property.SetValue(_reference.Target, value); - return true; - } - - return false; - } - - void IWeakSubscriber.OnEvent(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == _property.Name || string.IsNullOrEmpty(e.PropertyName)) - { - _changed(Value); - } - } - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/Plugins/PerspexPropertyAccessorPlugin.cs b/src/Markup/Perspex.Markup/Data/Plugins/PerspexPropertyAccessorPlugin.cs deleted file mode 100644 index bc16989a7a..0000000000 --- a/src/Markup/Perspex.Markup/Data/Plugins/PerspexPropertyAccessorPlugin.cs +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Linq; -using Perspex.Data; -using Perspex.Logging; - -namespace Perspex.Markup.Data.Plugins -{ - /// - /// Reads a property from a . - /// - public class PerspexPropertyAccessorPlugin : IPropertyAccessorPlugin - { - /// - /// Checks whether this plugin can handle accessing the properties of the specified object. - /// - /// A weak reference to the object. - /// True if the plugin can handle the object; otherwise false. - public bool Match(WeakReference reference) - { - Contract.Requires(reference != null); - - return reference.Target is PerspexObject; - } - - /// - /// Starts monitoring the value of a property on an object. - /// - /// A weak reference to the object. - /// The property name. - /// A function to call when the property changes. - /// - /// An interface through which future interactions with the - /// property will be made. - /// - public IPropertyAccessor Start( - WeakReference reference, - string propertyName, - Action changed) - { - Contract.Requires(reference != null); - Contract.Requires(propertyName != null); - Contract.Requires(changed != null); - - var instance = reference.Target; - var o = (PerspexObject)instance; - var p = PerspexPropertyRegistry.Instance.FindRegistered(o, propertyName); - - if (p != null) - { - return new Accessor(new WeakReference(o), p, changed); - } - else if (instance != PerspexProperty.UnsetValue) - { - var message = $"Could not find PerspexProperty '{propertyName}' on '{instance}'"; - var exception = new MissingMemberException(message); - return new PropertyError(new BindingError(exception)); - } - else - { - return null; - } - } - - private class Accessor : IPropertyAccessor - { - private readonly WeakReference _reference; - private readonly PerspexProperty _property; - private IDisposable _subscription; - - public Accessor( - WeakReference reference, - PerspexProperty property, - Action changed) - { - Contract.Requires(reference != null); - Contract.Requires(property != null); - - _reference = reference; - _property = property; - _subscription = Instance.GetWeakObservable(property).Skip(1).Subscribe(changed); - } - - public PerspexObject Instance - { - get - { - PerspexObject result; - _reference.TryGetTarget(out result); - return result; - } - } - - public Type PropertyType => _property.PropertyType; - - public object Value => Instance.GetValue(_property); - - public void Dispose() - { - _subscription?.Dispose(); - _subscription = null; - } - - public bool SetValue(object value, BindingPriority priority) - { - if (!_property.IsReadOnly) - { - Instance.SetValue(_property, value, priority); - return true; - } - - return false; - } - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/Plugins/PropertyError.cs b/src/Markup/Perspex.Markup/Data/Plugins/PropertyError.cs deleted file mode 100644 index c147a315d5..0000000000 --- a/src/Markup/Perspex.Markup/Data/Plugins/PropertyError.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using Perspex.Data; - -namespace Perspex.Markup.Data.Plugins -{ - /// - /// An that represents an error. - /// - public class PropertyError : IPropertyAccessor - { - private BindingError _error; - - /// - /// Initializes a new instance of the class. - /// - /// The error to report. - public PropertyError(BindingError error) - { - _error = error; - } - - /// - public Type PropertyType => null; - - /// - public object Value => _error; - - /// - public void Dispose() - { - } - - /// - public bool SetValue(object value, BindingPriority priority) - { - return false; - } - } -} diff --git a/src/Markup/Perspex.Markup/Data/Plugins/ValidationCheckerBase.cs b/src/Markup/Perspex.Markup/Data/Plugins/ValidationCheckerBase.cs deleted file mode 100644 index 8ab7b7e43e..0000000000 --- a/src/Markup/Perspex.Markup/Data/Plugins/ValidationCheckerBase.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using Perspex.Data; - -namespace Perspex.Markup.Data.Plugins -{ - public abstract class ValidationCheckerBase : IPropertyAccessor - { - protected readonly WeakReference _reference; - protected readonly string _name; - private readonly IPropertyAccessor _accessor; - private readonly Action _callback; - - protected ValidationCheckerBase(WeakReference reference, string name, IPropertyAccessor accessor, Action callback) - { - _reference = reference; - _name = name; - _accessor = accessor; - _callback = callback; - } - - public Type PropertyType => _accessor.PropertyType; - - public object Value => _accessor.Value; - - public virtual void Dispose() => _accessor.Dispose(); - - public virtual bool SetValue(object value, BindingPriority priority) => _accessor.SetValue(value, priority); - - protected void SendValidationCallback(ValidationStatus status) - { - _callback?.Invoke(status); - } - } -} \ No newline at end of file diff --git a/src/Markup/Perspex.Markup/Data/PropertyAccessorNode.cs b/src/Markup/Perspex.Markup/Data/PropertyAccessorNode.cs deleted file mode 100644 index e0561ecfcf..0000000000 --- a/src/Markup/Perspex.Markup/Data/PropertyAccessorNode.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Linq; -using System.Reactive.Linq; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Input; -using Perspex.Data; -using Perspex.Markup.Data.Plugins; - -namespace Perspex.Markup.Data -{ - internal class PropertyAccessorNode : ExpressionNode - { - private IPropertyAccessor _accessor; - private IDisposable _subscription; - - public PropertyAccessorNode(string propertyName) - { - PropertyName = propertyName; - } - - public string PropertyName { get; } - - public Type PropertyType => _accessor?.PropertyType; - - public override bool SetValue(object value, BindingPriority priority) - { - if (Next != null) - { - return Next.SetValue(value, priority); - } - else - { - if (_accessor != null) - { - return _accessor.SetValue(value, priority); - } - - return false; - } - } - - protected override void SubscribeAndUpdate(WeakReference reference) - { - var instance = reference.Target; - - if (instance != null && instance != PerspexProperty.UnsetValue) - { - var accessorPlugin = ExpressionObserver.PropertyAccessors.FirstOrDefault(x => x.Match(reference)); - - if (accessorPlugin != null) - { - _accessor = accessorPlugin.Start(reference, PropertyName, SetCurrentValue); - foreach (var validationPlugin in ExpressionObserver.ValidationCheckers.Where(x => x.Match(reference))) - { - if (validationPlugin != null) - { - _accessor = validationPlugin.Start(reference, PropertyName, _accessor, SendValidationStatus); - } - } - - if (_accessor != null) - { - SetCurrentValue(_accessor.Value); - return; - } - } - } - - CurrentValue = UnsetReference; - } - - protected override void Unsubscribe(object target) - { - _accessor?.Dispose(); - _accessor = null; - } - - private void SetCurrentValue(object value) - { - var observable = value as IObservable; - var command = value as ICommand; - var task = value as Task; - bool set = false; - - // HACK: ReactiveCommand is an IObservable but we want to bind to it, not its value. - // We may need to make this a more general solution. - if (observable != null && command == null) - { - CurrentValue = UnsetReference; - set = true; - _subscription = observable - .ObserveOn(SynchronizationContext.Current) - .Subscribe(x => CurrentValue = new WeakReference(x)); - } - else if (task != null) - { - var resultProperty = task.GetType().GetTypeInfo().GetDeclaredProperty("Result"); - - if (resultProperty != null) - { - if (task.Status == TaskStatus.RanToCompletion) - { - CurrentValue = new WeakReference(resultProperty.GetValue(task)); - set = true; - } - else - { - task.ContinueWith( - x => CurrentValue = new WeakReference(resultProperty.GetValue(task)), - TaskScheduler.FromCurrentSynchronizationContext()) - .ConfigureAwait(false); - } - } - } - else - { - CurrentValue = new WeakReference(value); - set = true; - } - - if (!set) - { - CurrentValue = UnsetReference; - } - } - } -} diff --git a/src/Markup/Perspex.Markup/DefaultValueConverter.cs b/src/Markup/Perspex.Markup/DefaultValueConverter.cs deleted file mode 100644 index 0cc5f0df8e..0000000000 --- a/src/Markup/Perspex.Markup/DefaultValueConverter.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using System.Linq; -using System.Reflection; -using Perspex.Data; -using Perspex.Logging; -using Perspex.Utilities; - -namespace Perspex.Markup -{ - /// - /// Provides a default set of value conversions for bindings that do not specify a value - /// converter. - /// - public class DefaultValueConverter : IValueConverter - { - /// - /// Gets an instance of a . - /// - public static readonly DefaultValueConverter Instance = new DefaultValueConverter(); - - /// - /// Converts a value. - /// - /// The value to convert. - /// The type of the target. - /// A user-defined parameter. - /// The culture to use. - /// The converted value. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - object result; - - if (value != null && - (TypeUtilities.TryConvert(targetType, value, culture, out result) || - TryConvertEnum(value, targetType, culture, out result))) - { - return result; - } - - if (value != null) - { - var message = $"Could not convert '{value}' to '{targetType}'"; - return new BindingError(new InvalidCastException(message)); - } - - return PerspexProperty.UnsetValue; - } - - /// - /// Converts a value. - /// - /// The value to convert. - /// The type of the target. - /// A user-defined parameter. - /// The culture to use. - /// The converted value. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return Convert(value, targetType, parameter, culture); - } - - private bool TryConvertEnum(object value, Type targetType, CultureInfo cultur, out object result) - { - var valueTypeInfo = value.GetType().GetTypeInfo(); - var targetTypeInfo = targetType.GetTypeInfo(); - - if (valueTypeInfo.IsEnum && !targetTypeInfo.IsEnum) - { - var enumValue = (int)value; - - if (TypeUtilities.TryCast(targetType, enumValue, out result)) - { - return true; - } - } - else if (!valueTypeInfo.IsEnum && targetTypeInfo.IsEnum) - { - object intValue; - - if (TypeUtilities.TryCast(typeof(int), value, out intValue)) - { - result = Enum.ToObject(targetType, intValue); - return true; - } - } - - result = null; - return false; - } - } -} diff --git a/src/Markup/Perspex.Markup/FuncMultiValueConverter.cs b/src/Markup/Perspex.Markup/FuncMultiValueConverter.cs deleted file mode 100644 index 66165e5876..0000000000 --- a/src/Markup/Perspex.Markup/FuncMultiValueConverter.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; - -namespace Perspex.Markup -{ - /// - /// A general purpose that uses a - /// to provide the converter logic. - /// - /// The type of the inputs. - /// The output type. - public class FuncMultiValueConverter : IMultiValueConverter - { - private readonly Func, TOut> _convert; - - /// - /// Initializes a new instance of the class. - /// - /// The convert function. - public FuncMultiValueConverter(Func, TOut> convert) - { - _convert = convert; - } - - /// - public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) - { - var converted = values.OfType().ToList(); - - if (converted.Count == values.Count) - { - return _convert(converted); - } - else - { - return PerspexProperty.UnsetValue; - } - } - } -} diff --git a/src/Markup/Perspex.Markup/FuncValueConverter.cs b/src/Markup/Perspex.Markup/FuncValueConverter.cs deleted file mode 100644 index 2dec0c43a4..0000000000 --- a/src/Markup/Perspex.Markup/FuncValueConverter.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using Perspex.Utilities; - -namespace Perspex.Markup -{ - /// - /// A general purpose that uses a - /// to provide the converter logic. - /// - /// The input type. - /// The output type. - public class FuncValueConverter : IValueConverter - { - private readonly Func _convert; - - /// - /// Initializes a new instance of the class. - /// - /// The convert function. - public FuncValueConverter(Func convert) - { - _convert = convert; - } - - /// - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is TIn || (value == null && TypeUtilities.AcceptsNull(typeof(TIn)))) - { - return _convert((TIn)value); - } - else - { - return PerspexProperty.UnsetValue; - } - } - - /// - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Markup/Perspex.Markup/IMultiValueConverter.cs b/src/Markup/Perspex.Markup/IMultiValueConverter.cs deleted file mode 100644 index 68dd5f0098..0000000000 --- a/src/Markup/Perspex.Markup/IMultiValueConverter.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Globalization; - -namespace Perspex.Markup -{ - /// - /// Converts multi-binding inputs to a final value. - /// - public interface IMultiValueConverter - { - /// - /// Converts multi-binding inputs to a final value. - /// - /// The values to convert. - /// The type of the target. - /// A user-defined parameter. - /// The culture to use. - /// The converted value. - /// - /// This method should not throw exceptions. If the value is not convertible, return - /// . Any exception thrown will be treated as - /// an application exception. - /// - object Convert(IList values, Type targetType, object parameter, CultureInfo culture); - } -} diff --git a/src/Markup/Perspex.Markup/IValueConverter.cs b/src/Markup/Perspex.Markup/IValueConverter.cs deleted file mode 100644 index 532066d644..0000000000 --- a/src/Markup/Perspex.Markup/IValueConverter.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; - -namespace Perspex.Markup -{ - /// - /// Converts a binding value. - /// - public interface IValueConverter - { - /// - /// Converts a value. - /// - /// The value to convert. - /// The type of the target. - /// A user-defined parameter. - /// The culture to use. - /// The converted value. - /// - /// This method should not throw exceptions. If the value is not convertible, return - /// . Any exception thrown will be treated as - /// an application exception. - /// - object Convert(object value, Type targetType, object parameter, CultureInfo culture); - - /// - /// Converts a value. - /// - /// The value to convert. - /// The type of the target. - /// A user-defined parameter. - /// The culture to use. - /// The converted value. - /// - /// This method should not throw exceptions. If the value is not convertible, return - /// . Any exception thrown will be treated as - /// an application exception. - /// - object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture); - } -} diff --git a/src/Markup/Perspex.Markup/Perspex.Markup.csproj b/src/Markup/Perspex.Markup/Perspex.Markup.csproj deleted file mode 100644 index 443991b120..0000000000 --- a/src/Markup/Perspex.Markup/Perspex.Markup.csproj +++ /dev/null @@ -1,135 +0,0 @@ - - - - - 11.0 - Debug - AnyCPU - {6417E941-21BC-467B-A771-0DE389353CE6} - Library - Properties - Perspex.Markup - Perspex.Markup - en-US - 512 - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Profile7 - v4.5 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Perspex.Markup.XML - CS1591 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Perspex.Markup.XML - CS1591 - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll - True - - - ..\..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll - True - - - ..\..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll - True - - - ..\..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll - True - - - - - - - - {b09b78d8-9b26-48b0-9149-d64a2f120f3f} - Perspex.Base - - - {d2221c82-4a25-4583-9b43-d791e3f6820c} - Perspex.Controls - - - {62024b2d-53eb-4638-b26b-85eeaa54866e} - Perspex.Input - - - {6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b} - Perspex.Interactivity - - - {42472427-4774-4c81-8aff-9f27b8e31721} - Perspex.Layout - - - {eb582467-6abb-43a1-b052-e981ba910e3a} - Perspex.SceneGraph - - - {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} - Perspex.Styling - - - - - \ No newline at end of file diff --git a/src/Markup/Perspex.Markup/Properties/AssemblyInfo.cs b/src/Markup/Perspex.Markup/Properties/AssemblyInfo.cs deleted file mode 100644 index f3387d7682..0000000000 --- a/src/Markup/Perspex.Markup/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Reflection; -using Perspex.Metadata; -using System.Runtime.CompilerServices; - -[assembly: AssemblyTitle("Perspex.Markup")] -[assembly: XmlnsDefinition("https://github.com/perspex", "Perspex.Markup")] -[assembly: InternalsVisibleTo("Perspex.Markup.UnitTests")] \ No newline at end of file diff --git a/src/Markup/Perspex.Markup/StringConverters.cs b/src/Markup/Perspex.Markup/StringConverters.cs deleted file mode 100644 index 950617a52d..0000000000 --- a/src/Markup/Perspex.Markup/StringConverters.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Globalization; -using Perspex.Utilities; - -namespace Perspex.Markup -{ - /// - /// Provides a set of useful s for working with string values. - /// - public static class StringConverters - { - /// - /// A value converter that returns true if the input string is null or an empty string. - /// - public static readonly IValueConverter NullOrEmpty = - new FuncValueConverter(string.IsNullOrEmpty); - - /// - /// A value converter that returns true if the input string is not null or empty. - /// - public static readonly IValueConverter NotNullOrEmpty = - new FuncValueConverter(x => !string.IsNullOrEmpty(x)); - } -} diff --git a/src/Perspex.Animation/Animatable.cs b/src/Perspex.Animation/Animatable.cs deleted file mode 100644 index 8e77b28dfe..0000000000 --- a/src/Perspex.Animation/Animatable.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Linq; -using Perspex.Data; - -namespace Perspex.Animation -{ - /// - /// Base class for control which can have property transitions. - /// - public class Animatable : PerspexObject - { - /// - /// The property transitions for the control. - /// - private PropertyTransitions _propertyTransitions; - - /// - /// Gets or sets the property transitions for the control. - /// - /// - /// The property transitions for the control. - /// - public PropertyTransitions PropertyTransitions - { - get - { - return _propertyTransitions ?? (_propertyTransitions = new PropertyTransitions()); - } - - set - { - _propertyTransitions = value; - } - } - - /// - /// Reacts to a change in a value in order to animate the - /// change if a is set for the property.. - /// - /// The event args. - protected override void OnPropertyChanged(PerspexPropertyChangedEventArgs e) - { - if (e.Priority != BindingPriority.Animation && _propertyTransitions != null) - { - var match = _propertyTransitions.FirstOrDefault(x => x.Property == e.Property); - - if (match != null) - { - Animate.Property(this, e.Property, e.OldValue, e.NewValue, match.Easing, match.Duration); - } - } - } - } -} diff --git a/src/Perspex.Animation/Animate.cs b/src/Perspex.Animation/Animate.cs deleted file mode 100644 index 1f85ffaadf..0000000000 --- a/src/Perspex.Animation/Animate.cs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Diagnostics; -using System.Linq; -using System.Reactive.Linq; -using Perspex.Data; -using Perspex.Threading; - -namespace Perspex.Animation -{ - /// - /// Utilities for creating animations. - /// - public static class Animate - { - /// - /// The number of frames per second. - /// - public const int FramesPerSecond = 60; - - /// - /// The time span of each frame. - /// - private static readonly TimeSpan Tick = TimeSpan.FromSeconds(1.0 / FramesPerSecond); - - /// - /// Initializes static members of the class. - /// - static Animate() - { - Stopwatch = new Stopwatch(); - Stopwatch.Start(); - Timer = Observable.Interval(Tick, PerspexScheduler.Instance) - .Select(_ => Stopwatch.Elapsed) - .Publish() - .RefCount(); - } - - /// - /// The stopwatch used to track time. - /// - /// - /// The stopwatch used to track time. - /// - public static Stopwatch Stopwatch - { - get; } - - /// - /// Gets the animation timer. - /// - /// - /// The animation timer ticks times per second. The - /// parameter passed to a subsciber is the time span since the animation system was - /// initialized. - /// - /// - /// The animation timer. - /// - public static IObservable Timer - { - get; } - - /// - /// Gets a timer that fires every frame for the specified duration. - /// - /// The duration of the animation. - /// - /// An observable that notifies the subscriber of the progress along the animation. - /// - /// - /// The parameter passed to the subscriber is the progress along the animation, with - /// 0 being the start and 1 being the end. The observable is guaranteed to fire 0 - /// immediately on subscribe and 1 at the end of the duration. - /// - public static IObservable GetTimer(TimeSpan duration) - { - var startTime = Stopwatch.Elapsed.Ticks; - var endTime = startTime + duration.Ticks; - return Timer - .TakeWhile(x => x.Ticks < endTime) - .Select(x => (x.Ticks - startTime) / (double)duration.Ticks) - .StartWith(0.0) - .Concat(Observable.Return(1.0)); - } - - /// - /// Animates a . - /// - /// The target object. - /// The target property. - /// The value of the property at the start of the animation. - /// The value of the property at the end of the animation. - /// The easing function to use. - /// The duration of the animation. - /// An that can be used to track or stop the animation. - public static Animation Property( - IPerspexObject target, - PerspexProperty property, - object start, - object finish, - IEasing easing, - TimeSpan duration) - { - var o = GetTimer(duration).Select(progress => easing.Ease(progress, start, finish)); - return new Animation(o, target.Bind(property, o, BindingPriority.Animation)); - } - - /// - /// Animates a . - /// - /// The property type. - /// The target object. - /// The target property. - /// The value of the property at the start of the animation. - /// The value of the property at the end of the animation. - /// The easing function to use. - /// The duration of the animation. - /// An that can be used to track or stop the animation. - public static Animation Property( - IPerspexObject target, - PerspexProperty property, - T start, - T finish, - IEasing easing, - TimeSpan duration) - { - var o = GetTimer(duration).Select(progress => easing.Ease(progress, start, finish)); - return new Animation(o, target.Bind(property, o, BindingPriority.Animation)); - } - } -} diff --git a/src/Perspex.Animation/Animation.cs b/src/Perspex.Animation/Animation.cs deleted file mode 100644 index 26e839e154..0000000000 --- a/src/Perspex.Animation/Animation.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Animation -{ - /// - /// Tracks the progress of an animation. - /// - public class Animation : IObservable, IDisposable - { - /// - /// The animation being tracked. - /// - private readonly IObservable _inner; - - /// - /// The disposable used to cancel the animation. - /// - private readonly IDisposable _subscription; - - /// - /// Initializes a new instance of the class. - /// - /// The animation observable being tracked. - /// A disposable used to cancel the animation. - public Animation(IObservable inner, IDisposable subscription) - { - _inner = inner; - _subscription = subscription; - } - - /// - /// Cancels the animation. - /// - public void Dispose() - { - _subscription.Dispose(); - } - - /// - /// Notifies the provider that an observer is to receive notifications. - /// - /// The observer. - /// - /// A reference to an interface that allows observers to stop receiving notifications - /// before the provider has finished sending them. - /// - public IDisposable Subscribe(IObserver observer) - { - return _inner.Subscribe(observer); - } - } -} diff --git a/src/Perspex.Animation/AnimationExtensions.cs b/src/Perspex.Animation/AnimationExtensions.cs deleted file mode 100644 index e78de91219..0000000000 --- a/src/Perspex.Animation/AnimationExtensions.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Animation -{ - /// - /// Defines animation extension methods. - /// - public static class AnimationExtensions - { - /// - /// Returns a new for the specified - /// using linear easing. - /// - /// The type of the . - /// The property to animate. - /// The animation duration in milliseconds. - /// - /// A that can be added to the - /// collection. - /// - public static PropertyTransition Transition(this PerspexProperty property, int milliseconds) - { - return Transition(property, TimeSpan.FromMilliseconds(milliseconds)); - } - - /// - /// Returns a new for the specified - /// using linear easing. - /// - /// The type of the . - /// The property to animate. - /// The animation duration. - /// - /// A that can be added to the - /// collection. - /// - public static PropertyTransition Transition(this PerspexProperty property, TimeSpan duration) - { - return new PropertyTransition(property, duration, LinearEasing.For()); - } - } -} diff --git a/src/Perspex.Animation/Animation`1.cs b/src/Perspex.Animation/Animation`1.cs deleted file mode 100644 index be04a5a33d..0000000000 --- a/src/Perspex.Animation/Animation`1.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Animation -{ - /// - /// Tracks the progress of an animation. - /// - /// The type of the value being animated./ - public class Animation : IObservable, IDisposable - { - /// - /// The animation being tracked. - /// - private readonly IObservable _inner; - - /// - /// The disposable used to cancel the animation. - /// - private readonly IDisposable _subscription; - - /// - /// Initializes a new instance of the class. - /// - /// The animation observable being tracked. - /// A disposable used to cancel the animation. - public Animation(IObservable inner, IDisposable subscription) - { - _inner = inner; - _subscription = subscription; - } - - /// - /// Cancels the animation. - /// - public void Dispose() - { - _subscription.Dispose(); - } - - /// - /// Notifies the provider that an observer is to receive notifications. - /// - /// The observer. - /// - /// A reference to an interface that allows observers to stop receiving notifications - /// before the provider has finished sending them. - /// - public IDisposable Subscribe(IObserver observer) - { - return _inner.Subscribe(observer); - } - } -} diff --git a/src/Perspex.Animation/IEasing.cs b/src/Perspex.Animation/IEasing.cs deleted file mode 100644 index 34dab15f9f..0000000000 --- a/src/Perspex.Animation/IEasing.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Animation -{ - /// - /// Defines the interface for easing functions. - /// - public interface IEasing - { - /// - /// Returns the value of the transition for the specified progress. - /// - /// The progress of the transition, from 0 to 1. - /// The start value of the transition. - /// The end value of the transition. - /// - /// A value between and as determined - /// by . - /// - object Ease(double progress, object start, object finish); - } -} diff --git a/src/Perspex.Animation/IEasing`1.cs b/src/Perspex.Animation/IEasing`1.cs deleted file mode 100644 index aa042d188d..0000000000 --- a/src/Perspex.Animation/IEasing`1.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Animation -{ - /// - /// Defines the interface for easing functions. - /// - /// The type of the property being transitioned. - public interface IEasing : IEasing - { - /// - /// Returns the value of the transition for the specified progress. - /// - /// The progress of the transition, from 0 to 1. - /// The start value of the transition. - /// The end value of the transition. - /// - /// A value between and as determined - /// by . - /// - T Ease(double progress, T start, T finish); - } -} diff --git a/src/Perspex.Animation/LinearDoubleEasing.cs b/src/Perspex.Animation/LinearDoubleEasing.cs deleted file mode 100644 index 5953c720b3..0000000000 --- a/src/Perspex.Animation/LinearDoubleEasing.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Animation -{ - /// - /// Linearly eases a double value. - /// - public class LinearDoubleEasing : IEasing - { - /// - /// Returns the value of the transition for the specified progress. - /// - /// The progress of the transition, from 0 to 1. - /// The start value of the transition. - /// The end value of the transition. - /// - /// A value between and as determined - /// by . - /// - public double Ease(double progress, double start, double finish) - { - return ((finish - start) * progress) + start; - } - - /// - /// Returns the value of the transition for the specified progress. - /// - /// The progress of the transition, from 0 to 1. - /// The start value of the transition. - /// The end value of the transition. - /// - /// A value between and as determined - /// by . - /// - object IEasing.Ease(double progress, object start, object finish) - { - return Ease(progress, (double)start, (double)finish); - } - } -} diff --git a/src/Perspex.Animation/LinearEasing.cs b/src/Perspex.Animation/LinearEasing.cs deleted file mode 100644 index 57583a505c..0000000000 --- a/src/Perspex.Animation/LinearEasing.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Animation -{ - /// - /// Returns a linear for the specified type. - /// - /// - /// Unfortunately this class is needed as there's no way to create a true generic easing - /// function at compile time, as mathematical operators don't have an interface. - /// - public static class LinearEasing - { - /// - /// A linear easing function for the specified type. - /// - /// The type. - /// An easing function. - public static IEasing For() - { - if (typeof(T) == typeof(double)) - { - return (IEasing)new LinearDoubleEasing(); - } - else - { - throw new NotSupportedException( - $"Don't know how to create a LinearEasing for type '{typeof(T).FullName}'."); - } - } - } -} diff --git a/src/Perspex.Animation/Perspex.Animation.csproj b/src/Perspex.Animation/Perspex.Animation.csproj deleted file mode 100644 index 822d7abc73..0000000000 --- a/src/Perspex.Animation/Perspex.Animation.csproj +++ /dev/null @@ -1,88 +0,0 @@ - - - - - 11.0 - Debug - AnyCPU - {D211E587-D8BC-45B9-95A4-F297C8FA5200} - Library - Properties - Perspex.Animation - Perspex.Animation - en-US - 512 - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Profile7 - v4.5 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Perspex.Animation.XML - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Perspex.Animation.XML - CS1591 - - - - - {B09B78D8-9B26-48B0-9149-D64A2F120F3F} - Perspex.Base - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - ..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll - - - ..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll - - - ..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll - - - ..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll - - - - - - - - \ No newline at end of file diff --git a/src/Perspex.Animation/Properties/AssemblyInfo.cs b/src/Perspex.Animation/Properties/AssemblyInfo.cs deleted file mode 100644 index a359255e83..0000000000 --- a/src/Perspex.Animation/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Reflection; - -[assembly: AssemblyTitle("Perspex.Animation")] diff --git a/src/Perspex.Animation/PropertyTransition.cs b/src/Perspex.Animation/PropertyTransition.cs deleted file mode 100644 index c919957fbe..0000000000 --- a/src/Perspex.Animation/PropertyTransition.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Animation -{ - /// - /// Defines how a property should be animated using a transition. - /// - public class PropertyTransition - { - /// - /// Initializes a new instance of the class. - /// - /// The property to be animated/ - /// The duration of the animation. - /// The easing function to use. - public PropertyTransition(PerspexProperty property, TimeSpan duration, IEasing easing) - { - Property = property; - Duration = duration; - Easing = easing; - } - - /// - /// Gets the property to be animated. - /// - /// - /// The property to be animated. - /// - public PerspexProperty Property { get; } - - /// - /// Gets the duration of the animation. - /// - /// - /// The duration of the animation. - /// - public TimeSpan Duration { get; } - - /// - /// Gets the easing function used. - /// - /// - /// The easing function. - /// - public IEasing Easing { get; } - } -} diff --git a/src/Perspex.Animation/PropertyTransitions.cs b/src/Perspex.Animation/PropertyTransitions.cs deleted file mode 100644 index 42d2b76904..0000000000 --- a/src/Perspex.Animation/PropertyTransitions.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Collections; - -namespace Perspex.Animation -{ - /// - /// A collection of definitions. - /// - public class PropertyTransitions : PerspexList - { - /// - /// Initializes a new instance of the class. - /// - public PropertyTransitions() - { - ResetBehavior = ResetBehavior.Remove; - } - } -} diff --git a/src/Perspex.Base/AttachedProperty.cs b/src/Perspex.Base/AttachedProperty.cs deleted file mode 100644 index e91cfecc39..0000000000 --- a/src/Perspex.Base/AttachedProperty.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex -{ - /// - /// An attached perspex property. - /// - /// The type of the property's value. - public class AttachedProperty : StyledPropertyBase - { - /// - /// Initializes a new instance of the class. - /// - /// The name of the property. - /// The class that is registering the property. - /// The property metadata. - /// Whether the property inherits its value. - public AttachedProperty( - string name, - Type ownerType, - StyledPropertyMetadata metadata, - bool inherits = false) - : base(name, ownerType, metadata, inherits) - { - } - - /// - public override bool IsAttached => true; - - /// - /// Attaches the property as a non-attached property on the specified type. - /// - /// The owner type. - /// The property. - public StyledProperty AddOwner() where TOwner : IPerspexObject - { - var result = new StyledProperty(this, typeof(TOwner)); - PerspexPropertyRegistry.Instance.Register(typeof(TOwner), result); - return result; - } - } -} diff --git a/src/Perspex.Base/Collections/IPerspexList.cs b/src/Perspex.Base/Collections/IPerspexList.cs deleted file mode 100644 index 2c8debb684..0000000000 --- a/src/Perspex.Base/Collections/IPerspexList.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Collections.Generic; - -namespace Perspex.Collections -{ - /// - /// A notiftying list. - /// - /// The type of the items in the list. - public interface IPerspexList : IList, IPerspexReadOnlyList - { - /// - /// Gets the number of items in the list. - /// - new int Count { get; } - - /// - /// Gets or sets the element at the specified index. - /// - /// The index. - /// The element at the requested index. - new T this[int index] { get; set; } - - /// - /// Adds multiple items to the collection. - /// - /// The items. - void AddRange(IEnumerable items); - - /// - /// Inserts multiple items at the specified index. - /// - /// The index. - /// The items. - void InsertRange(int index, IEnumerable items); - - /// - /// Removes multiple items from the collection. - /// - /// The items. - void RemoveAll(IEnumerable items); - - /// - /// Removes a range of elements from the collection. - /// - /// The first index to remove. - /// The number of items to remove. - void RemoveRange(int index, int count); - } -} \ No newline at end of file diff --git a/src/Perspex.Base/Collections/IPerspexReadOnlyList.cs b/src/Perspex.Base/Collections/IPerspexReadOnlyList.cs deleted file mode 100644 index 6507c8002d..0000000000 --- a/src/Perspex.Base/Collections/IPerspexReadOnlyList.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; - -namespace Perspex.Collections -{ - /// - /// A read-only notiftying list. - /// - /// The type of the items in the list. - public interface IPerspexReadOnlyList : IReadOnlyList, INotifyCollectionChanged, INotifyPropertyChanged - { - } -} \ No newline at end of file diff --git a/src/Perspex.Base/Collections/PerspexDictionary.cs b/src/Perspex.Base/Collections/PerspexDictionary.cs deleted file mode 100644 index d3da0c031d..0000000000 --- a/src/Perspex.Base/Collections/PerspexDictionary.cs +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Linq; - -namespace Perspex.Collections -{ - /// - /// A notifying dictionary. - /// - /// The type of the dictionary key. - /// The type of the dictionary value. - public class PerspexDictionary : IDictionary, - INotifyCollectionChanged, - INotifyPropertyChanged - { - private Dictionary _inner; - - /// - /// Initializes a new instance of the class. - /// - public PerspexDictionary() - { - _inner = new Dictionary(); - } - - /// - /// Occurs when the collection changes. - /// - public event NotifyCollectionChangedEventHandler CollectionChanged; - - /// - /// Raised when a property on the collection changes. - /// - public event PropertyChangedEventHandler PropertyChanged; - - /// - public int Count => _inner.Count; - - /// - public bool IsReadOnly => false; - - /// - public ICollection Keys => _inner.Keys; - - /// - public ICollection Values => _inner.Values; - - /// - /// Gets or sets the named resource. - /// - /// The resource key. - /// The resource, or null if not found. - public TValue this[TKey key] - { - get - { - return _inner[key]; - } - - set - { - TValue old; - bool replace = _inner.TryGetValue(key, out old); - _inner[key] = value; - - if (replace) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]")); - - if (CollectionChanged != null) - { - var e = new NotifyCollectionChangedEventArgs( - NotifyCollectionChangedAction.Replace, - new KeyValuePair(key, value), - new KeyValuePair(key, old)); - CollectionChanged(this, e); - } - } - else - { - NotifyAdd(key, value); - } - } - } - - /// - public void Add(TKey key, TValue value) - { - _inner.Add(key, value); - NotifyAdd(key, value); - } - - /// - public void Clear() - { - var old = _inner; - - _inner = new Dictionary(); - - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs("Count")); - PropertyChanged(this, new PropertyChangedEventArgs($"Item[]")); - } - - if (CollectionChanged != null) - { - var e = new NotifyCollectionChangedEventArgs( - NotifyCollectionChangedAction.Remove, - old.ToList(), - -1); - CollectionChanged(this, e); - } - } - - /// - public bool ContainsKey(TKey key) - { - return _inner.ContainsKey(key); - } - - /// - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - ((IDictionary)_inner).CopyTo(array, arrayIndex); - } - - /// - public IEnumerator> GetEnumerator() - { - return _inner.GetEnumerator(); - } - - /// - public bool Remove(TKey key) - { - TValue value; - - if (_inner.TryGetValue(key, out value)) - { - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs("Count")); - PropertyChanged(this, new PropertyChangedEventArgs($"Item[{key}]")); - } - - if (CollectionChanged != null) - { - var e = new NotifyCollectionChangedEventArgs( - NotifyCollectionChangedAction.Remove, - new[] { new KeyValuePair(key, value) }, - -1); - CollectionChanged(this, e); - } - - return true; - } - else - { - return false; - } - } - - /// - public bool TryGetValue(TKey key, out TValue value) - { - return _inner.TryGetValue(key, out value); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return _inner.GetEnumerator(); - } - - /// - void ICollection>.Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - /// - bool ICollection>.Contains(KeyValuePair item) - { - return _inner.Contains(item); - } - - /// - bool ICollection>.Remove(KeyValuePair item) - { - return Remove(item.Key); - } - - private void NotifyAdd(TKey key, TValue value) - { - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs("Count")); - PropertyChanged(this, new PropertyChangedEventArgs($"Item[{key}]")); - } - - if (CollectionChanged != null) - { - var val = new KeyValuePair(key, value); - var e = new NotifyCollectionChangedEventArgs( - NotifyCollectionChangedAction.Add, - new[] { new KeyValuePair(key, value) }, - -1); - CollectionChanged(this, e); - } - } - } -} \ No newline at end of file diff --git a/src/Perspex.Base/Collections/PerspexList.cs b/src/Perspex.Base/Collections/PerspexList.cs deleted file mode 100644 index 17f40f2056..0000000000 --- a/src/Perspex.Base/Collections/PerspexList.cs +++ /dev/null @@ -1,500 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Linq; -using Perspex.Diagnostics; -using Perspex.Platform; - -namespace Perspex.Collections -{ - /// - /// Describes the action notified on a clear of a . - /// - public enum ResetBehavior - { - /// - /// Clearing the list notifies a with a - /// . - /// - Reset, - - /// - /// Clearing the list notifies a with a - /// . - /// - Remove, - } - - /// - /// A notifying list. - /// - /// The type of the list items. - /// - /// - /// PerspexList is similar to - /// with a few added features: - /// - /// - /// - /// - /// It can be configured to notify the event with a - /// action instead of a - /// when the list is cleared by - /// setting to . - /// removed - /// - /// - /// A function can be used to validate each item before insertion. - /// removed - /// - /// - /// - public class PerspexList : IPerspexList, IList, INotifyCollectionChangedDebug - { - private List _inner; - private NotifyCollectionChangedEventHandler _collectionChanged; - - /// - /// Initializes a new instance of the class. - /// - public PerspexList() - : this(Enumerable.Empty()) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The initial items for the collection. - public PerspexList(IEnumerable items) - { - _inner = new List(items); - } - - /// - /// Initializes a new instance of the class. - /// - /// The initial items for the collection. - public PerspexList(params T[] items) - { - _inner = new List(items); - } - - /// - /// Raised when a change is made to the collection's items. - /// - public event NotifyCollectionChangedEventHandler CollectionChanged - { - add { _collectionChanged += value; } - remove { _collectionChanged -= value; } - } - - /// - /// Raised when a property on the collection changes. - /// - public event PropertyChangedEventHandler PropertyChanged; - - /// - /// Gets the number of items in the collection. - /// - public int Count => _inner.Count; - - /// - /// Gets or sets the reset behavior of the list. - /// - public ResetBehavior ResetBehavior { get; set; } - - /// - /// Gets or sets a validation routine that can be used to validate items before they are - /// added. - /// - public Action Validate { get; set; } - - /// - bool IList.IsFixedSize => false; - - /// - bool IList.IsReadOnly => false; - - /// - int ICollection.Count => _inner.Count; - - /// - bool ICollection.IsSynchronized => false; - - /// - object ICollection.SyncRoot => null; - - /// - bool ICollection.IsReadOnly => false; - - /// - /// Gets or sets the item at the specified index. - /// - /// The index. - /// The item. - public T this[int index] - { - get - { - return _inner[index]; - } - - set - { - Validate?.Invoke(value); - - T old = _inner[index]; - _inner[index] = value; - - if (_collectionChanged != null) - { - var e = new NotifyCollectionChangedEventArgs( - NotifyCollectionChangedAction.Replace, - value, - old, - index); - _collectionChanged(this, e); - } - } - } - - /// - /// Gets or sets the item at the specified index. - /// - /// The index. - /// The item. - object IList.this[int index] - { - get { return this[index]; } - set { this[index] = (T)value; } - } - - /// - /// Adds an item to the collection. - /// - /// The item. - public virtual void Add(T item) - { - Validate?.Invoke(item); - int index = _inner.Count; - _inner.Add(item); - NotifyAdd(new[] { item }, index); - } - - /// - /// Adds multiple items to the collection. - /// - /// The items. - public virtual void AddRange(IEnumerable items) - { - Contract.Requires(items != null); - - var list = (items as IList) ?? items.ToList(); - - if (list.Count > 0) - { - if (Validate != null) - { - foreach (var item in list) - { - Validate((T)item); - } - } - - int index = _inner.Count; - _inner.AddRange(items); - NotifyAdd(list, index); - } - } - - /// - /// Removes all items from the collection. - /// - public void Clear() - { - if (this.Count > 0) - { - var old = _inner; - _inner = new List(); - NotifyReset(old); - } - } - - /// - /// Tests if the collection contains the specified item. - /// - /// The item. - /// True if the collection contains the item; otherwise false. - public bool Contains(T item) - { - return _inner.Contains(item); - } - - /// - /// Copies the collection's contents to an array. - /// - /// The array. - /// The first index of the array to copy to. - public void CopyTo(T[] array, int arrayIndex) - { - _inner.CopyTo(array, arrayIndex); - } - - /// - /// Returns an enumerator that enumerates the items in the collection. - /// - /// An . - public IEnumerator GetEnumerator() - { - return _inner.GetEnumerator(); - } - - /// - /// Gets a range of items from the collection. - /// - /// The first index to remove. - /// The number of items to remove. - public IEnumerable GetRange(int index, int count) - { - return _inner.GetRange(index, count); - } - - /// - /// Gets the index of the specified item in the collection. - /// - /// The item. - /// - /// The index of the item or -1 if the item is not contained in the collection. - /// - public int IndexOf(T item) - { - return _inner.IndexOf(item); - } - - /// - /// Inserts an item at the specified index. - /// - /// The index. - /// The item. - public virtual void Insert(int index, T item) - { - Validate?.Invoke(item); - _inner.Insert(index, item); - NotifyAdd(new[] { item }, index); - } - - /// - /// Inserts multiple items at the specified index. - /// - /// The index. - /// The items. - public virtual void InsertRange(int index, IEnumerable items) - { - Contract.Requires(items != null); - - var list = (items as IList) ?? items.ToList(); - - if (list.Count > 0) - { - if (Validate != null) - { - foreach (var item in list) - { - Validate((T)item); - } - } - - _inner.InsertRange(index, items); - NotifyAdd((items as IList) ?? items.ToList(), index); - } - } - - /// - /// Removes an item from the collection. - /// - /// The item. - /// True if the item was found and removed, otherwise false. - public virtual bool Remove(T item) - { - int index = _inner.IndexOf(item); - - if (index != -1) - { - _inner.RemoveAt(index); - NotifyRemove(new[] { item }, index); - return true; - } - - return false; - } - - /// - /// Removes multiple items from the collection. - /// - /// The items. - public virtual void RemoveAll(IEnumerable items) - { - Contract.Requires(items != null); - - var list = (items as IList) ?? items.ToList(); - - foreach (var i in items) - { - // TODO: Optimize to only send as many notifications as necessary. - Remove(i); - } - } - - /// - /// Removes the item at the specified index. - /// - /// The index. - public virtual void RemoveAt(int index) - { - T item = _inner[index]; - _inner.RemoveAt(index); - NotifyRemove(new[] { item }, index); - } - - /// - /// Removes a range of elements from the collection. - /// - /// The first index to remove. - /// The number of items to remove. - public virtual void RemoveRange(int index, int count) - { - if (count > 0) - { - var list = _inner.GetRange(index, count); - _inner.RemoveRange(index, count); - NotifyRemove(list, index); - } - } - - /// - int IList.Add(object value) - { - int index = Count; - Add((T)value); - return index; - } - - /// - bool IList.Contains(object value) - { - return Contains((T)value); - } - - /// - void IList.Clear() - { - Clear(); - } - - /// - int IList.IndexOf(object value) - { - return IndexOf((T)value); - } - - /// - void IList.Insert(int index, object value) - { - Insert(index, (T)value); - } - - /// - void IList.Remove(object value) - { - Remove((T)value); - } - - /// - void IList.RemoveAt(int index) - { - RemoveAt(index); - } - - /// - void ICollection.CopyTo(Array array, int index) - { - _inner.CopyTo((T[])array, index); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return _inner.GetEnumerator(); - } - - /// - Delegate[] INotifyCollectionChangedDebug.GetCollectionChangedSubscribers() => _collectionChanged?.GetInvocationList(); - - /// - /// Raises the event with an add action. - /// - /// The items that were added. - /// The starting index. - private void NotifyAdd(IList t, int index) - { - if (_collectionChanged != null) - { - var e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, t, index); - _collectionChanged(this, e); - } - - NotifyCountChanged(); - } - - /// - /// Raises the event when the property - /// changes. - /// - private void NotifyCountChanged() - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count")); - } - - /// - /// Raises the event with a remove action. - /// - /// The items that were removed. - /// The starting index. - private void NotifyRemove(IList t, int index) - { - if (_collectionChanged != null) - { - var e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, t, index); - _collectionChanged(this, e); - } - - NotifyCountChanged(); - } - - /// - /// Raises the event with a reset action. - /// - /// The items that were removed. - private void NotifyReset(IList t) - { - if (_collectionChanged != null) - { - NotifyCollectionChangedEventArgs e; - - e = ResetBehavior == ResetBehavior.Reset ? - new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset) : - new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, t, 0); - - _collectionChanged(this, e); - } - - NotifyCountChanged(); - } - } -} \ No newline at end of file diff --git a/src/Perspex.Base/Collections/PerspexListExtensions.cs b/src/Perspex.Base/Collections/PerspexListExtensions.cs deleted file mode 100644 index af70a4aa86..0000000000 --- a/src/Perspex.Base/Collections/PerspexListExtensions.cs +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Linq; -using System.Reactive.Disposables; - -namespace Perspex.Collections -{ - /// - /// Defines extension methods for working with s. - /// - public static class PerspexListExtensions - { - /// - /// Invokes an action for each item in a collection and subsequently each item added or - /// removed from the collection. - /// - /// The type of the collection items. - /// The collection. - /// - /// An action called initially for each item in the collection and subsequently for each - /// item added to the collection. The parameters passed are the index in the collection and - /// the item. - /// - /// - /// An action called for each item removed from the collection. The parameters passed are - /// the index in the collection and the item. - /// - /// - /// An action called when the collection is reset. - /// - /// A disposable used to terminate the subscription. - public static IDisposable ForEachItem( - this IPerspexReadOnlyList collection, - Action added, - Action removed, - Action reset) - { - return collection.ForEachItem((_, i) => added(i), (_, i) => removed(i), reset); - } - - /// - /// Invokes an action for each item in a collection and subsequently each item added or - /// removed from the collection. - /// - /// The type of the collection items. - /// The collection. - /// - /// An action called initially for each item in the collection and subsequently for each - /// item added to the collection. The parameters passed are the index in the collection and - /// the item. - /// - /// - /// An action called for each item removed from the collection. The parameters passed are - /// the index in the collection and the item. - /// - /// - /// An action called when the collection is reset. - /// - /// A disposable used to terminate the subscription. - public static IDisposable ForEachItem( - this IPerspexReadOnlyList collection, - Action added, - Action removed, - Action reset) - { - int index; - - NotifyCollectionChangedEventHandler handler = (_, e) => - { - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - index = e.NewStartingIndex; - - foreach (T item in e.NewItems) - { - added(index++, item); - } - - break; - - case NotifyCollectionChangedAction.Replace: - index = e.OldStartingIndex; - - foreach (T item in e.OldItems) - { - removed(index++, item); - } - - index = e.NewStartingIndex; - - foreach (T item in e.NewItems) - { - added(index++, item); - } - - break; - - case NotifyCollectionChangedAction.Remove: - index = e.OldStartingIndex; - - foreach (T item in e.OldItems) - { - removed(index++, item); - } - - break; - - case NotifyCollectionChangedAction.Reset: - if (reset == null) - { - throw new InvalidOperationException( - "Reset called on collection without reset handler."); - } - - reset(); - break; - } - }; - - index = 0; - foreach (T i in collection) - { - added(index++, i); - } - - collection.CollectionChanged += handler; - - return Disposable.Create(() => collection.CollectionChanged -= handler); - } - - /// - /// Invokes an action for each item in a collection and subsequently each item added or - /// removed from the collection. - /// - /// The type of the collection items. - /// The collection. - /// - /// An action called initially with all items in the collection and subsequently with a - /// list of items added to the collection. The parameters passed are the index of the - /// first item added to the collection and the items added. - /// - /// - /// An action called with all items removed from the collection. The parameters passed - /// are the index of the first item removed from the collection and the items removed. - /// - /// - /// An action called when the collection is reset. - /// - /// A disposable used to terminate the subscription. - public static IDisposable ForEachItem( - this IPerspexReadOnlyList collection, - Action> added, - Action> removed, - Action reset) - { - NotifyCollectionChangedEventHandler handler = (_, e) => - { - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - added(e.NewStartingIndex, e.NewItems.Cast()); - break; - - case NotifyCollectionChangedAction.Replace: - removed(e.OldStartingIndex, e.OldItems.Cast()); - added(e.NewStartingIndex, e.NewItems.Cast()); - break; - - case NotifyCollectionChangedAction.Remove: - removed(e.OldStartingIndex, e.OldItems.Cast()); - break; - - case NotifyCollectionChangedAction.Reset: - if (reset == null) - { - throw new InvalidOperationException( - "Reset called on collection without reset handler."); - } - - reset(); - break; - } - }; - - added(0, collection); - collection.CollectionChanged += handler; - - return Disposable.Create(() => collection.CollectionChanged -= handler); - } - - /// - /// Listens for property changed events from all items in a collection. - /// - /// The type of the collection items. - /// The collection. - /// A callback to call for each property changed event. - /// A disposable used to terminate the subscription. - public static IDisposable TrackItemPropertyChanged( - this IPerspexReadOnlyList collection, - Action> callback) - { - List tracked = new List(); - - PropertyChangedEventHandler handler = (s, e) => - { - callback(Tuple.Create(s, e)); - }; - - collection.ForEachItem( - x => - { - var inpc = x as INotifyPropertyChanged; - - if (inpc != null) - { - inpc.PropertyChanged += handler; - tracked.Add(inpc); - } - }, - x => - { - var inpc = x as INotifyPropertyChanged; - - if (inpc != null) - { - inpc.PropertyChanged -= handler; - tracked.Remove(inpc); - } - }, - null); - - return Disposable.Create(() => - { - foreach (var i in tracked) - { - i.PropertyChanged -= handler; - } - }); - } - } -} diff --git a/src/Perspex.Base/Contract.cs b/src/Perspex.Base/Contract.cs deleted file mode 100644 index ffc47a2123..0000000000 --- a/src/Perspex.Base/Contract.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Runtime.CompilerServices; -using JetBrains.Annotations; - -namespace Perspex -{ - /// - /// A stub of Code Contract's Contract class. - /// - /// - /// It would be nice to use Code Contracts on Perspex but last time I tried it slowed things - /// to a crawl and often crashed. Instead use the same signature for checking preconditions - /// in the hope that it might become usable at some point. - /// - public static class Contract - { - /// - /// Specifies a precondition. - /// - /// - /// The exception to throw if is false. - /// - /// The precondition. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [ContractAnnotation("condition:false=>stop")] - public static void Requires(bool condition) where TException : Exception, new() - { - if (!condition) - { - throw new TException(); - } - } - } -} diff --git a/src/Perspex.Base/Data/AssignBindingAttribute.cs b/src/Perspex.Base/Data/AssignBindingAttribute.cs deleted file mode 100644 index d44b66b58e..0000000000 --- a/src/Perspex.Base/Data/AssignBindingAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Data -{ - /// - /// Signifies that a binding can be assigned to a property. - /// - /// - /// Usually in markup, when a binding is set for a property that property will be bound. - /// Applying this attribute to a property indicates that the binding should be assigned to - /// the property rather than bound. - /// - [AttributeUsage(AttributeTargets.Property)] - public sealed class AssignBindingAttribute : Attribute - { - } -} diff --git a/src/Perspex.Base/Data/BindingError.cs b/src/Perspex.Base/Data/BindingError.cs deleted file mode 100644 index b9330bd278..0000000000 --- a/src/Perspex.Base/Data/BindingError.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Data -{ - /// - /// Represents a recoverable binding error. - /// - /// - /// When produced by a binding source observable, informs the binding system that an error - /// occurred. It can also provide an optional fallback value to be pushed to the binding - /// target. - /// - /// Instead of using , one could simply not push a value (in the - /// case of a no fallback value) or push a fallback value, but BindingError also causes an - /// error to be logged with the correct binding target. - /// - public class BindingError - { - /// - /// Initializes a new instance of the class. - /// - /// An exception describing the binding error. - public BindingError(Exception exception) - { - Exception = exception; - } - - /// - /// Initializes a new instance of the class. - /// - /// An exception describing the binding error. - /// The fallback value. - public BindingError(Exception exception, object fallbackValue) - { - Exception = exception; - FallbackValue = fallbackValue; - UseFallbackValue = true; - } - - /// - /// Gets the exception describing the binding error. - /// - public Exception Exception { get; } - - /// - /// Get the fallback value. - /// - public object FallbackValue { get; } - - /// - /// Get a value indicating whether the fallback value should be pushed to the binding - /// target. - /// - public bool UseFallbackValue { get; } - } -} diff --git a/src/Perspex.Base/Data/BindingMode.cs b/src/Perspex.Base/Data/BindingMode.cs deleted file mode 100644 index 885f58ed1a..0000000000 --- a/src/Perspex.Base/Data/BindingMode.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Data -{ - /// - /// Defines possible binding modes. - /// - public enum BindingMode - { - /// - /// Uses the default binding mode specified for the property. - /// - Default, - - /// - /// Binds one way from source to target. - /// - OneWay, - - /// - /// Binds two-way with the initial value coming from the target. - /// - TwoWay, - - /// - /// Updates the target when the application starts or when the data context changes. - /// - OneTime, - - /// - /// Binds one way from target to source. - /// - OneWayToSource, - } -} diff --git a/src/Perspex.Base/Data/BindingOperations.cs b/src/Perspex.Base/Data/BindingOperations.cs deleted file mode 100644 index efa0c8500d..0000000000 --- a/src/Perspex.Base/Data/BindingOperations.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Linq; -using System.Reactive.Disposables; -using System.Reactive.Linq; - -namespace Perspex.Data -{ - public static class BindingOperations - { - /// - /// Applies an a property on an . - /// - /// The target object. - /// The property to bind. - /// The instanced binding. - /// - /// An optional anchor from which to locate required context. When binding to objects that - /// are not in the logical tree, certain types of binding need an anchor into the tree in - /// order to locate named controls or resources. The parameter - /// can be used to provice this context. - /// - /// An which can be used to cancel the binding. - public static IDisposable Apply( - IPerspexObject target, - PerspexProperty property, - InstancedBinding binding, - object anchor) - { - Contract.Requires(target != null); - Contract.Requires(property != null); - Contract.Requires(binding != null); - - var mode = binding.Mode; - - if (mode == BindingMode.Default) - { - mode = property.GetMetadata(target.GetType()).DefaultBindingMode; - } - - switch (mode) - { - case BindingMode.Default: - case BindingMode.OneWay: - return target.Bind(property, binding.Observable ?? binding.Subject, binding.Priority); - case BindingMode.TwoWay: - return new CompositeDisposable( - target.Bind(property, binding.Subject, binding.Priority), - target.GetObservable(property).Subscribe(binding.Subject)); - case BindingMode.OneTime: - var source = binding.Subject ?? binding.Observable; - - if (source != null) - { - return source.Take(1).Subscribe(x => target.SetValue(property, x, binding.Priority)); - } - else - { - target.SetValue(property, binding.Value, binding.Priority); - return Disposable.Empty; - } - case BindingMode.OneWayToSource: - return target.GetObservable(property).Subscribe(binding.Subject); - default: - throw new ArgumentException("Invalid binding mode."); - } - } - } -} diff --git a/src/Perspex.Base/Data/BindingPriority.cs b/src/Perspex.Base/Data/BindingPriority.cs deleted file mode 100644 index 055b252fa3..0000000000 --- a/src/Perspex.Base/Data/BindingPriority.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Data -{ - /// - /// The priority of a binding. - /// - public enum BindingPriority - { - /// - /// A value that comes from an animation. - /// - Animation = -1, - - /// - /// A local value. - /// - LocalValue = 0, - - /// - /// A triggered style binding. - /// - /// - /// A style trigger is a selector such as .class which overrides a - /// binding. In this way, a basic control can have - /// for example a Background from the templated parent which changes when the - /// control has the :pointerover class. - /// - StyleTrigger, - - /// - /// A binding to a property on the templated parent. - /// - TemplatedParent, - - /// - /// A style binding. - /// - Style, - - /// - /// The binding is uninitialized. - /// - Unset = int.MaxValue, - } -} \ No newline at end of file diff --git a/src/Perspex.Base/Data/IBinding.cs b/src/Perspex.Base/Data/IBinding.cs deleted file mode 100644 index 0b7bbef108..0000000000 --- a/src/Perspex.Base/Data/IBinding.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Data -{ - /// - /// Holds a binding that can be applied to a property on an object. - /// - public interface IBinding - { - /// - /// Initiates the binding on a target object. - /// - /// The target instance. - /// The target property. May be null. - /// - /// An optional anchor from which to locate required context. When binding to objects that - /// are not in the logical tree, certain types of binding need an anchor into the tree in - /// order to locate named controls or resources. The parameter - /// can be used to provice this context. - /// - /// - /// A or null if the binding could not be resolved. - /// - InstancedBinding Initiate( - IPerspexObject target, - PerspexProperty targetProperty, - object anchor = null); - } -} diff --git a/src/Perspex.Base/Data/IndexerDescriptor.cs b/src/Perspex.Base/Data/IndexerDescriptor.cs deleted file mode 100644 index 94563a5499..0000000000 --- a/src/Perspex.Base/Data/IndexerDescriptor.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive; - -namespace Perspex.Data -{ - /// - /// Holds a description of a binding for 's [] operator. - /// - public class IndexerDescriptor : ObservableBase, IDescription - { - /// - /// Gets or sets the binding mode. - /// - public BindingMode Mode - { - get; - set; - } - - /// - /// Gets or sets the binding priority. - /// - public BindingPriority Priority - { - get; - set; - } - - /// - /// Gets or sets the source property. - /// - public PerspexProperty Property - { - get; - set; - } - - /// - /// Gets or sets the source object. - /// - public PerspexObject Source - { - get; - set; - } - - /// - /// Gets or sets the source observable. - /// - /// - /// If null, then . will be used. - /// - public IObservable SourceObservable - { - get; - set; - } - - /// - /// Gets a description of the binding. - /// - public string Description => $"{Source?.GetType().Name}.{Property.Name}"; - - /// - /// Makes a two-way binding. - /// - /// The current binding. - /// A two-way binding. - public static IndexerDescriptor operator !(IndexerDescriptor binding) - { - return binding.WithMode(BindingMode.TwoWay); - } - - /// - /// Makes a two-way binding. - /// - /// The current binding. - /// A two-way binding. - public static IndexerDescriptor operator ~(IndexerDescriptor binding) - { - return binding.WithMode(BindingMode.TwoWay); - } - - /// - /// Modifies the binding mode. - /// - /// The binding mode. - /// The object that the method was called on. - public IndexerDescriptor WithMode(BindingMode mode) - { - Mode = mode; - return this; - } - - /// - /// Modifies the binding priority. - /// - /// The binding priority. - /// The object that the method was called on. - public IndexerDescriptor WithPriority(BindingPriority priority) - { - Priority = priority; - return this; - } - - /// - protected override IDisposable SubscribeCore(IObserver observer) - { - return (SourceObservable ?? Source.GetObservable(Property)).Subscribe(observer); - } - } -} diff --git a/src/Perspex.Base/Data/InstancedBinding.cs b/src/Perspex.Base/Data/InstancedBinding.cs deleted file mode 100644 index 50daf56e97..0000000000 --- a/src/Perspex.Base/Data/InstancedBinding.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Subjects; - -namespace Perspex.Data -{ - /// - /// Holds the result of calling . - /// - /// - /// Whereas an holds a description of a binding such as "Bind to the X - /// property on a control's DataContext"; this class represents a binding that has been - /// *instanced* by calling - /// on a target object. - /// - /// When a binding is initiated, it can return one of 3 possible sources for the binding: - /// - An which can be used for any type of binding. - /// - An which can be used for all types of bindings except - /// and . - /// - A plain object, which can only represent a binding. - /// - public class InstancedBinding - { - /// - /// Initializes a new instance of the class. - /// - /// - /// The value used for the binding. - /// - /// The binding priority. - public InstancedBinding(object value, - BindingPriority priority = BindingPriority.LocalValue) - { - Mode = BindingMode.OneTime; - Priority = priority; - Value = value; - } - - /// - /// Initializes a new instance of the class. - /// - /// The observable for a one-way binding. - /// The binding mode. - /// The binding priority. - public InstancedBinding( - IObservable observable, - BindingMode mode = BindingMode.OneWay, - BindingPriority priority = BindingPriority.LocalValue) - { - Contract.Requires(observable != null); - - if (mode == BindingMode.OneWayToSource || mode == BindingMode.TwoWay) - { - throw new ArgumentException( - "Invalid BindingResult mode: OneWayToSource and TwoWay bindings" + - "require a Subject."); - } - - Mode = mode; - Priority = priority; - Observable = observable; - } - - /// - /// Initializes a new instance of the class. - /// - /// The subject for a two-way binding. - /// The binding mode. - /// The binding priority. - public InstancedBinding( - ISubject subject, - BindingMode mode = BindingMode.OneWay, - BindingPriority priority = BindingPriority.LocalValue) - { - Contract.Requires(subject != null); - - Mode = mode; - Priority = priority; - Subject = subject; - } - - /// - /// Gets the binding mode with which the binding was initiated. - /// - public BindingMode Mode { get; } - - /// - /// Gets the binding priority. - /// - public BindingPriority Priority { get; } - - /// - /// Gets the value used for a binding. - /// - public object Value { get; } - - /// - /// Gets the observable for a one-way binding. - /// - public IObservable Observable { get; } - - /// - /// Gets the subject for a two-way binding. - /// - public ISubject Subject { get; } - } -} diff --git a/src/Perspex.Base/Data/ValidationMethods.cs b/src/Perspex.Base/Data/ValidationMethods.cs deleted file mode 100644 index 491a7bbe50..0000000000 --- a/src/Perspex.Base/Data/ValidationMethods.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Perspex.Data -{ - [Flags] - public enum ValidationMethods - { - None = 0, - Exceptions = 1, - INotifyDataErrorInfo = 2, - All = -1 - } -} \ No newline at end of file diff --git a/src/Perspex.Base/Data/ValidationStatus.cs b/src/Perspex.Base/Data/ValidationStatus.cs deleted file mode 100644 index ac2600c13c..0000000000 --- a/src/Perspex.Base/Data/ValidationStatus.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Perspex.Data -{ - /// - /// Contains information on if the current object passed validation. - /// Subclasses of this class contain additional information depending on the method of validation checking. - /// - public abstract class ValidationStatus - { - /// - /// True when the data passes validation; otherwise, false. - /// - public abstract bool IsValid { get; } - - /// - /// Checks if this validation status came from a currently enabled method of validation checking. - /// - /// The enabled methods of validation checking. - /// True if enabled; otherwise, false. - public abstract bool Match(ValidationMethods enabledMethods); - } -} diff --git a/src/Perspex.Base/Diagnostics/INotifyCollectionChangedDebug.cs b/src/Perspex.Base/Diagnostics/INotifyCollectionChangedDebug.cs deleted file mode 100644 index 468c2b3ff7..0000000000 --- a/src/Perspex.Base/Diagnostics/INotifyCollectionChangedDebug.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Specialized; -using Perspex.Collections; - -namespace Perspex.Diagnostics -{ - /// - /// Provides a debug interface into subscribers on - /// - /// - public interface INotifyCollectionChangedDebug - { - /// - /// Gets the subscriber list for the - /// event. - /// - /// - /// The subscribers or null if no subscribers. - /// - Delegate[] GetCollectionChangedSubscribers(); - } -} diff --git a/src/Perspex.Base/Diagnostics/IPerspexObjectDebug.cs b/src/Perspex.Base/Diagnostics/IPerspexObjectDebug.cs deleted file mode 100644 index 1d2778dc30..0000000000 --- a/src/Perspex.Base/Diagnostics/IPerspexObjectDebug.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Diagnostics -{ - /// - /// Provides a debug interface into . - /// - public interface IPerspexObjectDebug - { - /// - /// Gets the subscriber list for the - /// event. - /// - /// - /// The subscribers or null if no subscribers. - /// - Delegate[] GetPropertyChangedSubscribers(); - } -} diff --git a/src/Perspex.Base/Diagnostics/PerspexObjectExtensions.cs b/src/Perspex.Base/Diagnostics/PerspexObjectExtensions.cs deleted file mode 100644 index 3efc5fbe98..0000000000 --- a/src/Perspex.Base/Diagnostics/PerspexObjectExtensions.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Data; - -namespace Perspex.Diagnostics -{ - /// - /// Defines diagnostic extensions on s. - /// - public static class PerspexObjectExtensions - { - /// - /// Gets a diagnostic for a on a . - /// - /// The object. - /// The property. - /// - /// A that can be used to diagnose the state of the - /// property on the object. - /// - public static PerspexPropertyValue GetDiagnostic(this PerspexObject o, PerspexProperty property) - { - var set = o.GetSetValues(); - - PriorityValue value; - - if (set.TryGetValue(property, out value)) - { - return new PerspexPropertyValue( - property, - o.GetValue(property), - (BindingPriority)value.ValuePriority, - value.GetDiagnostic()); - } - else - { - return new PerspexPropertyValue( - property, - o.GetValue(property), - BindingPriority.Unset, - "Unset"); - } - } - } -} diff --git a/src/Perspex.Base/Diagnostics/PerspexPropertyValue.cs b/src/Perspex.Base/Diagnostics/PerspexPropertyValue.cs deleted file mode 100644 index 5b1d46bcf1..0000000000 --- a/src/Perspex.Base/Diagnostics/PerspexPropertyValue.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Data; - -namespace Perspex.Diagnostics -{ - /// - /// Holds diagnostic-related information about the value of a - /// on a . - /// - public class PerspexPropertyValue - { - /// - /// Initializes a new instance of the class. - /// - /// The property. - /// The current property value. - /// The priority of the current value. - /// A diagnostic string. - public PerspexPropertyValue( - PerspexProperty property, - object value, - BindingPriority priority, - string diagnostic) - { - Property = property; - Value = value; - Priority = priority; - Diagnostic = diagnostic; - } - - /// - /// Gets the property. - /// - public PerspexProperty Property { get; } - - /// - /// Gets the current property value. - /// - public object Value { get; } - - /// - /// Gets the priority of the current value. - /// - public BindingPriority Priority { get; } - - /// - /// Gets a diagnostic string. - /// - public string Diagnostic { get; } - } -} diff --git a/src/Perspex.Base/DirectProperty.cs b/src/Perspex.Base/DirectProperty.cs deleted file mode 100644 index 82d47e7c1d..0000000000 --- a/src/Perspex.Base/DirectProperty.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Data; - -namespace Perspex -{ - /// - /// A direct perspex property. - /// - /// The class that registered the property. - /// The type of the property's value. - /// - /// Direct perspex properties are backed by a field on the object, but exposed via the - /// system. They hold a getter and an optional setter which - /// allows the perspex property system to read and write the current value. - /// - public class DirectProperty : PerspexProperty, IDirectPropertyAccessor - where TOwner : IPerspexObject - { - /// - /// Initializes a new instance of the class. - /// - /// The name of the property. - /// Gets the current value of the property. - /// Sets the value of the property. May be null. - /// The property metadata. - public DirectProperty( - string name, - Func getter, - Action setter, - PropertyMetadata metadata) - : base(name, typeof(TOwner), metadata) - { - Contract.Requires(getter != null); - - Getter = getter; - Setter = setter; - } - - /// - /// Initializes a new instance of the class. - /// - /// The property to copy. - /// Gets the current value of the property. - /// Sets the value of the property. May be null. - /// Optional overridden metadata. - private DirectProperty( - PerspexProperty source, - Func getter, - Action setter, - PropertyMetadata metadata) - : base(source, typeof(TOwner), metadata) - { - Contract.Requires(getter != null); - - Getter = getter; - Setter = setter; - } - - /// - public override bool IsDirect => true; - - /// - public override bool IsReadOnly => Setter == null; - - /// - /// Gets the getter function. - /// - public Func Getter { get; } - - /// - /// Gets the setter function. - /// - public Action Setter { get; } - - /// - /// Registers the direct property on another type. - /// - /// The type of the additional owner. - /// Gets the current value of the property. - /// Sets the value of the property. - /// - /// The value to use when the property is set to - /// - /// The default binding mode for the property. - /// The property. - public DirectProperty AddOwner( - Func getter, - Action setter = null, - TValue unsetValue = default(TValue), - BindingMode defaultBindingMode = BindingMode.OneWay) - where TNewOwner : PerspexObject - { - var result = new DirectProperty( - this, - getter, - setter, - new DirectPropertyMetadata(unsetValue, defaultBindingMode)); - - PerspexPropertyRegistry.Instance.Register(typeof(TNewOwner), result); - return result; - } - - /// - object IDirectPropertyAccessor.GetValue(IPerspexObject instance) - { - return Getter((TOwner)instance); - } - - /// - void IDirectPropertyAccessor.SetValue(IPerspexObject instance, object value) - { - if (Setter == null) - { - throw new ArgumentException($"The property {Name} is readonly."); - } - - Setter((TOwner)instance, (TValue)value); - } - } -} diff --git a/src/Perspex.Base/DirectPropertyMetadata`1.cs b/src/Perspex.Base/DirectPropertyMetadata`1.cs deleted file mode 100644 index 162fc788fc..0000000000 --- a/src/Perspex.Base/DirectPropertyMetadata`1.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Data; - -namespace Perspex -{ - /// - /// Metadata for direct perspex properties. - /// - public class DirectPropertyMetadata : PropertyMetadata, IDirectPropertyMetadata - { - /// - /// Initializes a new instance of the class. - /// - /// - /// The value to use when the property is set to - /// - /// The default binding mode. - public DirectPropertyMetadata( - TValue unsetValue = default(TValue), - BindingMode defaultBindingMode = BindingMode.Default) - : base(defaultBindingMode) - { - UnsetValue = unsetValue; - } - - /// - /// Gets the to use when the property is set to . - /// - public TValue UnsetValue { get; private set; } - - /// - object IDirectPropertyMetadata.UnsetValue => UnsetValue; - - /// - public override void Merge(PropertyMetadata baseMetadata, PerspexProperty property) - { - base.Merge(baseMetadata, property); - - var src = baseMetadata as DirectPropertyMetadata; - - if (src != null) - { - if (UnsetValue == null) - { - UnsetValue = src.UnsetValue; - } - } - } - } -} diff --git a/src/Perspex.Base/IDescription.cs b/src/Perspex.Base/IDescription.cs deleted file mode 100644 index 5bb7640fea..0000000000 --- a/src/Perspex.Base/IDescription.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex -{ - /// - /// Interface for objects with a . - /// - public interface IDescription - { - /// - /// Gets the description of the object. - /// - /// - /// The description of the object. - /// - string Description { get; } - } -} diff --git a/src/Perspex.Base/IDirectPropertyAccessor.cs b/src/Perspex.Base/IDirectPropertyAccessor.cs deleted file mode 100644 index 497be4f122..0000000000 --- a/src/Perspex.Base/IDirectPropertyAccessor.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex -{ - /// - /// Provides a runtime interface for getting and setting - /// values. - /// - internal interface IDirectPropertyAccessor - { - /// - /// Gets a value indicating whether the property is read-only. - /// - bool IsReadOnly { get; } - - /// - /// Gets the value of the property on the instance. - /// - /// The instance. - /// The property value. - object GetValue(IPerspexObject instance); - - /// - /// Sets the value of the property on the instance. - /// - /// The instance. - /// The value. - void SetValue(IPerspexObject instance, object value); - } -} diff --git a/src/Perspex.Base/IDirectPropertyMetadata.cs b/src/Perspex.Base/IDirectPropertyMetadata.cs deleted file mode 100644 index 72c55300ed..0000000000 --- a/src/Perspex.Base/IDirectPropertyMetadata.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex -{ - /// - /// Untyped interface to - /// - public interface IDirectPropertyMetadata - { - /// - /// Gets the to use when the property is set to . - /// - object UnsetValue { get; } - } -} \ No newline at end of file diff --git a/src/Perspex.Base/IPerspexObject.cs b/src/Perspex.Base/IPerspexObject.cs deleted file mode 100644 index 4290bfe792..0000000000 --- a/src/Perspex.Base/IPerspexObject.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Data; - -namespace Perspex -{ - /// - /// Interface for getting/setting values on an object. - /// - public interface IPerspexObject - { - /// - /// Raised when a value changes on this object. - /// - event EventHandler PropertyChanged; - - /// - /// Gets a value. - /// - /// The property. - /// The value. - object GetValue(PerspexProperty property); - - /// - /// Gets a value. - /// - /// The type of the property. - /// The property. - /// The value. - T GetValue(PerspexProperty property); - - /// - /// Checks whether a is set on this object. - /// - /// The property. - /// True if the property is set, otherwise false. - bool IsSet(PerspexProperty property); - - /// - /// Sets a value. - /// - /// The property. - /// The value. - /// The priority of the value. - void SetValue( - PerspexProperty property, - object value, - BindingPriority priority = BindingPriority.LocalValue); - - /// - /// Sets a value. - /// - /// The type of the property. - /// The property. - /// The value. - /// The priority of the value. - void SetValue( - PerspexProperty property, - T value, - BindingPriority priority = BindingPriority.LocalValue); - - /// - /// Binds a to an observable. - /// - /// The property. - /// The observable. - /// The priority of the binding. - /// - /// A disposable which can be used to terminate the binding. - /// - IDisposable Bind( - PerspexProperty property, - IObservable source, - BindingPriority priority = BindingPriority.LocalValue); - - /// - /// Binds a to an observable. - /// - /// The type of the property. - /// The property. - /// The observable. - /// The priority of the binding. - /// - /// A disposable which can be used to terminate the binding. - /// - IDisposable Bind( - PerspexProperty property, - IObservable source, - BindingPriority priority = BindingPriority.LocalValue); - } -} \ No newline at end of file diff --git a/src/Perspex.Base/IPriorityValueOwner.cs b/src/Perspex.Base/IPriorityValueOwner.cs deleted file mode 100644 index 1afc005bad..0000000000 --- a/src/Perspex.Base/IPriorityValueOwner.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Data; - -namespace Perspex -{ - /// - /// An owner of a . - /// - internal interface IPriorityValueOwner - { - /// - /// Called when a 's value changes. - /// - /// The source of the change. - /// The old value. - /// The new value. - void Changed(PriorityValue sender, object oldValue, object newValue); - - /// - /// Called when the validation state of a changes. - /// - /// The source of the change. - /// The validation status. - void DataValidationChanged(PriorityValue sender, ValidationStatus status); - } -} diff --git a/src/Perspex.Base/IStyledPropertyAccessor.cs b/src/Perspex.Base/IStyledPropertyAccessor.cs deleted file mode 100644 index c8207332a4..0000000000 --- a/src/Perspex.Base/IStyledPropertyAccessor.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex -{ - /// - /// Provides a runtime interface for interfacing with . - /// - internal interface IStyledPropertyAccessor - { - /// - /// Gets the default value for the property for the specified type. - /// - /// The type. - /// - /// The default value. - /// - object GetDefaultValue(Type type); - - /// - /// Gets a validation function for the property on the specified type. - /// - /// The type. - /// - /// The validation function, or null if no validation function exists. - /// - Func GetValidationFunc(Type type); - } -} diff --git a/src/Perspex.Base/IStyledPropertyMetadata.cs b/src/Perspex.Base/IStyledPropertyMetadata.cs deleted file mode 100644 index c5bdba5024..0000000000 --- a/src/Perspex.Base/IStyledPropertyMetadata.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex -{ - /// - /// Untyped interface to - /// - public interface IStyledPropertyMetadata - { - /// - /// Gets the default value for the property. - /// - object DefaultValue { get; } - - /// - /// Gets the property's validation function. - /// - Func Validate { get; } - } -} \ No newline at end of file diff --git a/src/Perspex.Base/ISupportInitialize.cs b/src/Perspex.Base/ISupportInitialize.cs deleted file mode 100644 index 9405476044..0000000000 --- a/src/Perspex.Base/ISupportInitialize.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex -{ - /// - /// Specifies that this object supports a simple, transacted notification for batch - /// initialization. - /// - public interface ISupportInitialize - { - /// - /// Signals the object that initialization is starting. - /// - void BeginInit(); - - /// - /// Signals the object that initialization is complete. - /// - void EndInit(); - } -} diff --git a/src/Perspex.Base/Logging/ILogSink.cs b/src/Perspex.Base/Logging/ILogSink.cs deleted file mode 100644 index d2b6b62b4f..0000000000 --- a/src/Perspex.Base/Logging/ILogSink.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Logging -{ - /// - /// Defines a sink for Perspex logging messages. - /// - public interface ILogSink - { - /// - /// Logs a new event. - /// - /// The log event level. - /// The area that the event originates. - /// The object from which the event originates. - /// The message template. - /// The message property values. - void Log( - LogEventLevel level, - string area, - object source, - string messageTemplate, - params object[] propertyValues); - } -} diff --git a/src/Perspex.Base/Logging/LogArea.cs b/src/Perspex.Base/Logging/LogArea.cs deleted file mode 100644 index c77966be4b..0000000000 --- a/src/Perspex.Base/Logging/LogArea.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Logging -{ - /// - /// Specifies the area in which a log event occurred. - /// - public static class LogArea - { - /// - /// The log event comes from the property system. - /// - public const string Property = "Property"; - - /// - /// The log event comes from the binding system. - /// - public const string Binding = "Binding"; - - /// - /// The log event comes from the visual system. - /// - public const string Visual = "Visual"; - - /// - /// The log event comes from the layout system. - /// - public const string Layout = "Layout"; - - /// - /// The log event comes from the control system. - /// - public const string Control = "Control"; - } -} diff --git a/src/Perspex.Base/Logging/LogEventLevel.cs b/src/Perspex.Base/Logging/LogEventLevel.cs deleted file mode 100644 index a49b192b16..0000000000 --- a/src/Perspex.Base/Logging/LogEventLevel.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Logging -{ - /// - /// Specifies the meaning and relative importance of a log event. - /// - public enum LogEventLevel - { - /// - /// Anything and everything you might want to know about a running block of code. - /// - Verbose, - - /// - /// Internal system events that aren't necessarily observable from the outside. - /// - Debug, - - /// - /// The lifeblood of operational intelligence - things happen. - /// - Information, - - /// - /// Service is degraded or endangered. - /// - Warning, - - /// - /// Functionality is unavailable, invariants are broken or data is lost. - /// - Error, - - /// - /// If you have a pager, it goes off when one of these occurs. - /// - Fatal - } -} diff --git a/src/Perspex.Base/Logging/Logger.cs b/src/Perspex.Base/Logging/Logger.cs deleted file mode 100644 index f21915a332..0000000000 --- a/src/Perspex.Base/Logging/Logger.cs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Runtime.CompilerServices; - -namespace Perspex.Logging -{ - /// - /// Logs perspex messages. - /// - public static class Logger - { - /// - /// Gets or sets the application-defined sink that recieves the messages. - /// - public static ILogSink Sink { get; set; } - - /// - /// Logs an event. - /// - /// The log event level. - /// The area that the event originates. - /// The object from which the event originates. - /// The message template. - /// The message property values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Log( - LogEventLevel level, - string area, - object source, - string messageTemplate, - params object[] propertyValues) - { - Sink?.Log(level, area, source, messageTemplate, propertyValues); - } - - /// - /// Logs an event with the level. - /// - /// The area that the event originates. - /// The object from which the event originates. - /// The message template. - /// The message property values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Verbose( - string area, - object source, - string messageTemplate, - params object[] propertyValues) - { - Log(LogEventLevel.Verbose, area, source, messageTemplate, propertyValues); - } - - /// - /// Logs an event with the level. - /// - /// The area that the event originates. - /// The object from which the event originates. - /// The message template. - /// The message property values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Debug( - string area, - object source, - string messageTemplate, - params object[] propertyValues) - { - Log(LogEventLevel.Debug, area, source, messageTemplate, propertyValues); - } - - /// - /// Logs an event with the level. - /// - /// The area that the event originates. - /// The object from which the event originates. - /// The message template. - /// The message property values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Information( - string area, - object source, - string messageTemplate, - params object[] propertyValues) - { - Log(LogEventLevel.Information, area, source, messageTemplate, propertyValues); - } - - /// - /// Logs an event with the level. - /// - /// The area that the event originates. - /// The object from which the event originates. - /// The message template. - /// The message property values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Warning( - string area, - object source, - string messageTemplate, - params object[] propertyValues) - { - Log(LogEventLevel.Warning, area, source, messageTemplate, propertyValues); - } - - /// - /// Logs an event with the level. - /// - /// The area that the event originates. - /// The object from which the event originates. - /// The message template. - /// The message property values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Error( - string area, - object source, - string messageTemplate, - params object[] propertyValues) - { - Log(LogEventLevel.Error, area, source, messageTemplate, propertyValues); - } - - /// - /// Logs an event with the level. - /// - /// The area that the event originates. - /// The object from which the event originates. - /// The message template. - /// The message property values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Fatal( - string area, - object source, - string messageTemplate, - params object[] propertyValues) - { - Log(LogEventLevel.Fatal, area, source, messageTemplate, propertyValues); - } - } -} diff --git a/src/Perspex.Base/Metadata/ContentAttribute.cs b/src/Perspex.Base/Metadata/ContentAttribute.cs deleted file mode 100644 index 3cca10545a..0000000000 --- a/src/Perspex.Base/Metadata/ContentAttribute.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Metadata -{ - /// - /// Defines the property that contains the object's content in markup. - /// - [AttributeUsage(AttributeTargets.Property)] - public class ContentAttribute : Attribute - { - } -} diff --git a/src/Perspex.Base/Metadata/DependsOnAttribute.cs b/src/Perspex.Base/Metadata/DependsOnAttribute.cs deleted file mode 100644 index d06649e9e9..0000000000 --- a/src/Perspex.Base/Metadata/DependsOnAttribute.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Metadata -{ - /// - /// Indicates that the property depends on the value of another property in markup. - /// - [AttributeUsage(AttributeTargets.Property)] - public class DependsOnAttribute : Attribute - { - /// - /// Initializes a new instance of the class. - /// - /// - /// The name of the property that this property depends on. - /// - public DependsOnAttribute(string propertyName) - { - Name = propertyName; - } - - /// - /// Gets the name of the property that this property depends on. - /// - public string Name { get; } - } -} diff --git a/src/Perspex.Base/Metadata/XmlnsDefinitionAttribute.cs b/src/Perspex.Base/Metadata/XmlnsDefinitionAttribute.cs deleted file mode 100644 index ad30517dcd..0000000000 --- a/src/Perspex.Base/Metadata/XmlnsDefinitionAttribute.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Metadata -{ - /// - /// Maps an XML namespace to a CLR namespace for use in XAML. - /// - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public class XmlnsDefinitionAttribute : Attribute - { - /// - /// Initializes a new instance of the class. - /// - /// The URL of the XML namespace. - /// The CLR namespace. - public XmlnsDefinitionAttribute(string xmlNamespace, string clrNamespace) - { - XmlNamespace = xmlNamespace; - ClrNamespace = clrNamespace; - } - - /// - /// Gets or sets the URL of the XML namespace. - /// - public string XmlNamespace { get; } - - /// - /// Gets or sets the CLR namespace. - /// - public string ClrNamespace { get; } - } -} diff --git a/src/Perspex.Base/Perspex.Base.csproj b/src/Perspex.Base/Perspex.Base.csproj deleted file mode 100644 index 234af801ca..0000000000 --- a/src/Perspex.Base/Perspex.Base.csproj +++ /dev/null @@ -1,154 +0,0 @@ - - - - - 11.0 - Debug - AnyCPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F} - Library - Properties - Perspex - Perspex.Base - en-US - 512 - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Profile7 - v4.5 - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - bin\Debug\Perspex.Base.XML - CS1591 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Perspex.Base.XML - CS1591 - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ..\..\packages\JetBrains.Annotations.10.0.0\lib\portable-net4+sl5+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\JetBrains.Annotations.PCL328.dll - True - - - ..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll - - - ..\..\packages\Rx-Interfaces.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Interfaces.dll - - - ..\..\packages\Rx-Linq.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Linq.dll - - - ..\..\packages\Rx-PlatformServices.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.PlatformServices.dll - - - - - - - - - \ No newline at end of file diff --git a/src/Perspex.Base/PerspexDisposable.cs b/src/Perspex.Base/PerspexDisposable.cs deleted file mode 100644 index d3017e4b44..0000000000 --- a/src/Perspex.Base/PerspexDisposable.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Perspex.Platform; - -namespace Perspex -{ - public abstract class PerspexDisposable : IDisposable - { -#if DEBUG_DISPOSE - public string DisposedAt { get; private set; } -#endif - - - public bool IsDisposed { get; private set; } - - public void Dispose() - { - IsDisposed = true; -#if DEBUG_DISPOSE - DisposedAt = PerspexLocator.Current.GetService().GetStackTrace(); -#endif - DoDispose(); - } - - protected void CheckDisposed() - { - if (IsDisposed) - throw new ObjectDisposedException(GetType().FullName -#if DEBUG_DISPOSE - , "Disposed at: \n" + DisposedAt -#endif - - ); - } - - protected abstract void DoDispose(); - } -} diff --git a/src/Perspex.Base/PerspexInternalException.cs b/src/Perspex.Base/PerspexInternalException.cs deleted file mode 100644 index 5ab4341e1a..0000000000 --- a/src/Perspex.Base/PerspexInternalException.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex -{ - /// - /// Exception signifying an internal logic error in Perspex. - /// - public class PerspexInternalException : Exception - { - /// - /// Initializes a new instance of the class. - /// - /// The exception message. - public PerspexInternalException(string message) - : base(message) - { - } - } -} diff --git a/src/Perspex.Base/PerspexLocator.cs b/src/Perspex.Base/PerspexLocator.cs deleted file mode 100644 index 142e78dd8c..0000000000 --- a/src/Perspex.Base/PerspexLocator.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reactive.Disposables; - -#pragma warning disable CS1591 // Enable me later - -namespace Perspex -{ - public class PerspexLocator : IPerspexDependencyResolver - { - private readonly IPerspexDependencyResolver _parentScope; - public static IPerspexDependencyResolver Current { get; set; } - public static PerspexLocator CurrentMutable { get; set; } - private readonly Dictionary> _registry = new Dictionary>(); - - static PerspexLocator() - { - Current = CurrentMutable = new PerspexLocator(); - } - - public PerspexLocator() - { - - } - - public PerspexLocator(IPerspexDependencyResolver parentScope) - { - _parentScope = parentScope; - } - - public object GetService(Type t) - { - Func rv; - return _registry.TryGetValue(t, out rv) ? rv() : _parentScope?.GetService(t); - } - - public class RegistrationHelper - { - private readonly PerspexLocator _locator; - - public RegistrationHelper(PerspexLocator locator) - { - _locator = locator; - } - - public PerspexLocator ToConstant(TImpl constant) where TImpl : TService - { - _locator._registry[typeof (TService)] = () => constant; - return _locator; - } - - public PerspexLocator ToFunc(Func func) where TImlp : TService - { - _locator._registry[typeof (TService)] = () => func(); - return _locator; - } - - public PerspexLocator ToSingleton() where TImpl : class, TService, new() - { - TImpl instance = null; - return ToFunc(() => instance ?? (instance = new TImpl())); - } - - public PerspexLocator ToTransient() where TImpl : class, TService, new() => ToFunc(() => new TImpl()); - } - - public RegistrationHelper Bind() => new RegistrationHelper(this); - - - public PerspexLocator BindToSelf(T constant) - => Bind().ToConstant(constant); - - public PerspexLocator BindToSelfSingleton() where T : class, new() => Bind().ToSingleton(); - - class ResolverDisposable : IDisposable - { - private readonly IPerspexDependencyResolver _resolver; - private readonly PerspexLocator _mutable; - - public ResolverDisposable(IPerspexDependencyResolver resolver, PerspexLocator mutable) - { - _resolver = resolver; - _mutable = mutable; - } - - public void Dispose() - { - Current = _resolver; - CurrentMutable = _mutable; - } - } - - - public static IDisposable EnterScope() - { - var d = new ResolverDisposable(Current, CurrentMutable); - Current = CurrentMutable = new PerspexLocator(Current); - return d; - } - } - - public interface IPerspexDependencyResolver - { - object GetService(Type t); - } - - public static class LocatorExtensions - { - public static T GetService(this IPerspexDependencyResolver resolver) - { - return (T) resolver.GetService(typeof (T)); - } - } -} - diff --git a/src/Perspex.Base/PerspexObject.cs b/src/Perspex.Base/PerspexObject.cs deleted file mode 100644 index 81640237e8..0000000000 --- a/src/Perspex.Base/PerspexObject.cs +++ /dev/null @@ -1,821 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using Perspex.Data; -using Perspex.Diagnostics; -using Perspex.Logging; -using Perspex.Threading; -using Perspex.Utilities; - -namespace Perspex -{ - /// - /// An object with support. - /// - /// - /// This class is analogous to DependencyObject in WPF. - /// - public class PerspexObject : IPerspexObject, IPerspexObjectDebug, INotifyPropertyChanged, IPriorityValueOwner - { - /// - /// The parent object that inherited values are inherited from. - /// - private PerspexObject _inheritanceParent; - - /// - /// The set values/bindings on this object. - /// - private readonly Dictionary _values = - new Dictionary(); - - /// - /// Maintains a list of direct property binding subscriptions so that the binding source - /// doesn't get collected. - /// - private List _directBindings; - - /// - /// Event handler for implementation. - /// - private PropertyChangedEventHandler _inpcChanged; - - /// - /// Event handler for implementation. - /// - private EventHandler _propertyChanged; - - /// - /// Initializes a new instance of the class. - /// - public PerspexObject() - { - foreach (var property in PerspexPropertyRegistry.Instance.GetRegistered(this)) - { - object value = property.IsDirect ? - ((IDirectPropertyAccessor)property).GetValue(this) : - ((IStyledPropertyAccessor)property).GetDefaultValue(GetType()); - - var e = new PerspexPropertyChangedEventArgs( - this, - property, - PerspexProperty.UnsetValue, - value, - BindingPriority.Unset); - - property.NotifyInitialized(e); - } - } - - /// - /// Raised when a value changes on this object. - /// - public event EventHandler PropertyChanged - { - add { _propertyChanged += value; } - remove { _propertyChanged -= value; } - } - - /// - /// Raised when a value changes on this object. - /// - event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged - { - add { _inpcChanged += value; } - remove { _inpcChanged -= value; } - } - - /// - /// Gets or sets the parent object that inherited values - /// are inherited from. - /// - /// - /// The inheritance parent. - /// - protected PerspexObject InheritanceParent - { - get - { - return _inheritanceParent; - } - - set - { - if (_inheritanceParent != value) - { - if (_inheritanceParent != null) - { - _inheritanceParent.PropertyChanged -= ParentPropertyChanged; - } - - var inherited = (from property in PerspexPropertyRegistry.Instance.GetRegistered(this) - where property.Inherits - select new - { - Property = property, - Value = GetValue(property), - }).ToList(); - - _inheritanceParent = value; - - foreach (var i in inherited) - { - object newValue = GetValue(i.Property); - - if (!Equals(i.Value, newValue)) - { - RaisePropertyChanged(i.Property, i.Value, newValue, BindingPriority.LocalValue); - } - } - - if (_inheritanceParent != null) - { - _inheritanceParent.PropertyChanged += ParentPropertyChanged; - } - } - } - } - - /// - /// Gets or sets the value of a . - /// - /// The property. - public object this[PerspexProperty property] - { - get { return GetValue(property); } - set { SetValue(property, value); } - } - - /// - /// Gets or sets a binding for a . - /// - /// The binding information. - public IObservable this[IndexerDescriptor binding] - { - get - { - return CreateBindingDescriptor(binding); - } - - set - { - var metadata = binding.Property.GetMetadata(GetType()); - - var mode = (binding.Mode == BindingMode.Default) ? - metadata.DefaultBindingMode : - binding.Mode; - var sourceBinding = value as IndexerDescriptor; - - if (sourceBinding == null && mode > BindingMode.OneWay) - { - mode = BindingMode.OneWay; - } - - switch (mode) - { - case BindingMode.Default: - case BindingMode.OneWay: - Bind(binding.Property, value, binding.Priority); - break; - case BindingMode.OneTime: - SetValue(binding.Property, sourceBinding.Source.GetValue(sourceBinding.Property), binding.Priority); - break; - case BindingMode.OneWayToSource: - sourceBinding.Source.Bind(sourceBinding.Property, this.GetObservable(binding.Property), binding.Priority); - break; - case BindingMode.TwoWay: - var subject = sourceBinding.Source.GetSubject(sourceBinding.Property, sourceBinding.Priority); - var instanced = new InstancedBinding(subject, BindingMode.TwoWay, sourceBinding.Priority); - BindingOperations.Apply(this, binding.Property, instanced, null); - break; - } - } - } - - protected virtual IndexerDescriptor CreateBindingDescriptor(IndexerDescriptor source) - { - return new IndexerDescriptor - { - Mode = source.Mode, - Priority = source.Priority, - Property = source.Property, - Source = this, - }; - } - - public bool CheckAccess() => Dispatcher.UIThread.CheckAccess(); - - public void VerifyAccess() => Dispatcher.UIThread.VerifyAccess(); - - /// - /// Clears a 's local value. - /// - /// The property. - public void ClearValue(PerspexProperty property) - { - Contract.Requires(property != null); - - SetValue(property, PerspexProperty.UnsetValue); - } - - /// - /// Gets a value. - /// - /// The property. - /// The value. - public object GetValue(PerspexProperty property) - { - Contract.Requires(property != null); - - if (property.IsDirect) - { - return ((IDirectPropertyAccessor)GetRegistered(property)).GetValue(this); - } - else - { - object result = PerspexProperty.UnsetValue; - PriorityValue value; - - if (!PerspexPropertyRegistry.Instance.IsRegistered(this, property)) - { - ThrowNotRegistered(property); - } - - if (_values.TryGetValue(property, out value)) - { - result = value.Value; - } - - if (result == PerspexProperty.UnsetValue) - { - result = GetDefaultValue(property); - } - - return result; - } - } - - /// - /// Gets a value. - /// - /// The type of the property. - /// The property. - /// The value. - public T GetValue(PerspexProperty property) - { - Contract.Requires(property != null); - - return (T)GetValue((PerspexProperty)property); - } - - /// - /// Checks whether a is set on this object. - /// - /// The property. - /// True if the property is set, otherwise false. - public bool IsSet(PerspexProperty property) - { - Contract.Requires(property != null); - - PriorityValue value; - - if (_values.TryGetValue(property, out value)) - { - return value.Value != PerspexProperty.UnsetValue; - } - - return false; - } - - /// - /// Sets a value. - /// - /// The property. - /// The value. - /// The priority of the value. - public void SetValue( - PerspexProperty property, - object value, - BindingPriority priority = BindingPriority.LocalValue) - { - Contract.Requires(property != null); - VerifyAccess(); - - if (property.IsDirect) - { - var accessor = (IDirectPropertyAccessor)GetRegistered(property); - LogPropertySet(property, value, priority); - accessor.SetValue(this, DirectUnsetToDefault(value, property)); - } - else - { - PriorityValue v; - var originalValue = value; - - if (!PerspexPropertyRegistry.Instance.IsRegistered(this, property)) - { - ThrowNotRegistered(property); - } - - if (!TypeUtilities.TryCast(property.PropertyType, value, out value)) - { - throw new ArgumentException(string.Format( - "Invalid value for Property '{0}': '{1}' ({2})", - property.Name, - originalValue, - originalValue?.GetType().FullName ?? "(null)")); - } - - if (!_values.TryGetValue(property, out v)) - { - if (value == PerspexProperty.UnsetValue) - { - return; - } - - v = CreatePriorityValue(property); - _values.Add(property, v); - } - - LogPropertySet(property, value, priority); - v.SetValue(value, (int)priority); - } - } - - /// - /// Sets a value. - /// - /// The type of the property. - /// The property. - /// The value. - /// The priority of the value. - public void SetValue( - PerspexProperty property, - T value, - BindingPriority priority = BindingPriority.LocalValue) - { - Contract.Requires(property != null); - - SetValue((PerspexProperty)property, value, priority); - } - - /// - /// Binds a to an observable. - /// - /// The property. - /// The observable. - /// The priority of the binding. - /// - /// A disposable which can be used to terminate the binding. - /// - public IDisposable Bind( - PerspexProperty property, - IObservable source, - BindingPriority priority = BindingPriority.LocalValue) - { - Contract.Requires(property != null); - VerifyAccess(); - - if (property.IsDirect) - { - if (property.IsReadOnly) - { - throw new ArgumentException($"The property {property.Name} is readonly."); - } - - Logger.Verbose( - LogArea.Property, - this, - "Bound {Property} to {Binding} with priority LocalValue", - property, - GetDescription(source)); - - IDisposable subscription = null; - IDisposable validationSubcription = null; - - if (_directBindings == null) - { - _directBindings = new List(); - } - - subscription = source - .Where(x => !(x is ValidationStatus)) - .Select(x => CastOrDefault(x, property.PropertyType)) - .Do(_ => { }, () => _directBindings.Remove(subscription)) - .Subscribe(x => DirectBindingSet(property, x)); - validationSubcription = source - .OfType() - .Subscribe(x => DataValidation(property, x)); - - _directBindings.Add(subscription); - - return Disposable.Create(() => - { - validationSubcription.Dispose(); - subscription.Dispose(); - _directBindings.Remove(subscription); - }); - } - else - { - PriorityValue v; - - if (!PerspexPropertyRegistry.Instance.IsRegistered(this, property)) - { - ThrowNotRegistered(property); - } - - if (!_values.TryGetValue(property, out v)) - { - v = CreatePriorityValue(property); - _values.Add(property, v); - } - - Logger.Verbose( - LogArea.Property, - this, - "Bound {Property} to {Binding} with priority {Priority}", - property, - GetDescription(source), - priority); - - return v.Add(source, (int)priority); - } - } - - /// - /// Binds a to an observable. - /// - /// The type of the property. - /// The property. - /// The observable. - /// The priority of the binding. - /// - /// A disposable which can be used to terminate the binding. - /// - public IDisposable Bind( - PerspexProperty property, - IObservable source, - BindingPriority priority = BindingPriority.LocalValue) - { - Contract.Requires(property != null); - - return Bind(property, source.Select(x => (object)x), priority); - } - - /// - /// Forces the specified property to be revalidated. - /// - /// The property. - public void Revalidate(PerspexProperty property) - { - VerifyAccess(); - PriorityValue value; - - if (_values.TryGetValue(property, out value)) - { - value.Revalidate(); - } - } - - /// - void IPriorityValueOwner.Changed(PriorityValue sender, object oldValue, object newValue) - { - var property = sender.Property; - var priority = (BindingPriority)sender.ValuePriority; - - oldValue = (oldValue == PerspexProperty.UnsetValue) ? - GetDefaultValue(property) : - oldValue; - newValue = (newValue == PerspexProperty.UnsetValue) ? - GetDefaultValue(property) : - newValue; - - if (!Equals(oldValue, newValue)) - { - RaisePropertyChanged(property, oldValue, newValue, priority); - - Logger.Verbose( - LogArea.Property, - this, - "{Property} changed from {$Old} to {$Value} with priority {Priority}", - property, - oldValue, - newValue, - priority); - } - } - - /// - void IPriorityValueOwner.DataValidationChanged(PriorityValue sender, ValidationStatus status) - { - var property = sender.Property; - DataValidation(property, status); - } - - /// - /// Called when the validation state on a tracked property is changed. - /// - /// The property whose validation state changed. - /// The new validation state. - protected virtual void DataValidation(PerspexProperty property, ValidationStatus status) - { - - } - - /// - Delegate[] IPerspexObjectDebug.GetPropertyChangedSubscribers() - { - return _propertyChanged?.GetInvocationList(); - } - - /// - /// Gets all priority values set on the object. - /// - /// A collection of property/value tuples. - internal IDictionary GetSetValues() - { - return _values; - } - - /// - /// Forces revalidation of properties when a property value changes. - /// - /// The property to that affects validation. - /// The affected properties. - protected static void AffectsValidation(PerspexProperty property, params PerspexProperty[] affected) - { - property.Changed.Subscribe(e => - { - foreach (var p in affected) - { - e.Sender.Revalidate(p); - } - }); - } - - /// - /// Called when a perspex property changes on the object. - /// - /// The event arguments. - protected virtual void OnPropertyChanged(PerspexPropertyChangedEventArgs e) - { - } - - /// - /// Raises the event. - /// - /// The property that has changed. - /// The old property value. - /// The new property value. - /// The priority of the binding that produced the value. - protected void RaisePropertyChanged( - PerspexProperty property, - object oldValue, - object newValue, - BindingPriority priority = BindingPriority.LocalValue) - { - Contract.Requires(property != null); - VerifyAccess(); - - PerspexPropertyChangedEventArgs e = new PerspexPropertyChangedEventArgs( - this, - property, - oldValue, - newValue, - priority); - - property.Notifying?.Invoke(this, true); - - try - { - OnPropertyChanged(e); - property.NotifyChanged(e); - - _propertyChanged?.Invoke(this, e); - - if (_inpcChanged != null) - { - PropertyChangedEventArgs e2 = new PropertyChangedEventArgs(property.Name); - _inpcChanged(this, e2); - } - } - finally - { - property.Notifying?.Invoke(this, false); - } - } - - /// - /// Sets the backing field for a direct perspex property, raising the - /// event if the value has changed. - /// - /// The type of the property. - /// The property. - /// The backing field. - /// The value. - /// - /// True if the value changed, otherwise false. - /// - protected bool SetAndRaise(PerspexProperty property, ref T field, T value) - { - VerifyAccess(); - if (!object.Equals(field, value)) - { - var old = field; - field = value; - RaisePropertyChanged(property, old, value, BindingPriority.LocalValue); - return true; - } - else - { - return false; - } - } - - /// - /// Tries to cast a value to a type, taking into account that the value may be a - /// . - /// - /// The value. - /// The type. - /// The cast value, or a . - private static object CastOrDefault(object value, Type type) - { - var error = value as BindingError; - - if (error == null) - { - return TypeUtilities.CastOrDefault(value, type); - } - else - { - return error; - } - } - - /// - /// Creates a for a . - /// - /// The property. - /// The . - private PriorityValue CreatePriorityValue(PerspexProperty property) - { - var validate = ((IStyledPropertyAccessor)property).GetValidationFunc(GetType()); - Func validate2 = null; - - if (validate != null) - { - validate2 = v => validate(this, v); - } - - PriorityValue result = new PriorityValue( - this, - property, - property.PropertyType, - validate2); - - return result; - } - - /// - /// Sets a property value for a direct property binding. - /// - /// The property. - /// The value. - /// - private void DirectBindingSet(PerspexProperty property, object value) - { - var error = value as BindingError; - - if (error == null) - { - SetValue(property, value); - } - else - { - if (error.UseFallbackValue) - { - SetValue(property, error.FallbackValue); - } - - Logger.Error( - LogArea.Binding, - this, - "Error binding to {Target}.{Property}: {Message}", - this, - property, - error.Exception.Message); - } - } - - /// - /// Converts an unset value to the default value for a direct property. - /// - /// The value. - /// The property. - /// The value. - private object DirectUnsetToDefault(object value, PerspexProperty property) - { - return value == PerspexProperty.UnsetValue ? - ((IDirectPropertyMetadata)property.GetMetadata(GetType())).UnsetValue : - value; - } - - /// - /// Gets the default value for a property. - /// - /// The property. - /// The default value. - private object GetDefaultValue(PerspexProperty property) - { - if (property.Inherits && _inheritanceParent != null) - { - return _inheritanceParent.GetValue(property); - } - else - { - return ((IStyledPropertyAccessor)property).GetDefaultValue(GetType()); - } - } - - /// - /// Given a returns a registered perspex property that is - /// equal or throws if not found. - /// - /// The property. - /// The registered property. - public PerspexProperty GetRegistered(PerspexProperty property) - { - var result = PerspexPropertyRegistry.Instance.FindRegistered(this, property); - - if (result == null) - { - ThrowNotRegistered(property); - } - - return result; - } - - /// - /// Called when a property is changed on the current . - /// - /// The event sender. - /// The event args. - /// - /// Checks for changes in an inherited property value. - /// - private void ParentPropertyChanged(object sender, PerspexPropertyChangedEventArgs e) - { - Contract.Requires(e != null); - - if (e.Property.Inherits && !IsSet(e.Property)) - { - RaisePropertyChanged(e.Property, e.OldValue, e.NewValue, BindingPriority.LocalValue); - } - } - - /// - /// Gets a description of an observable that van be used in logs. - /// - /// The observable. - /// The description. - private string GetDescription(IObservable o) - { - var description = o as IDescription; - return description?.Description ?? o.ToString(); - } - - /// - /// Logs a property set message. - /// - /// The property. - /// The new value. - /// The priority. - private void LogPropertySet(PerspexProperty property, object value, BindingPriority priority) - { - Logger.Verbose( - LogArea.Property, - this, - "Set {Property} to {$Value} with priority {Priority}", - property, - value, - priority); - } - - /// - /// Throws an exception indicating that the specified property is not registered on this - /// object. - /// - /// The property - private void ThrowNotRegistered(PerspexProperty p) - { - throw new ArgumentException($"Property '{p.Name} not registered on '{this.GetType()}"); - } - } -} diff --git a/src/Perspex.Base/PerspexObjectExtensions.cs b/src/Perspex.Base/PerspexObjectExtensions.cs deleted file mode 100644 index 6e23a470ae..0000000000 --- a/src/Perspex.Base/PerspexObjectExtensions.cs +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using Perspex.Data; -using Perspex.Reactive; - -namespace Perspex -{ - /// - /// Provides extension methods for and related classes. - /// - public static class PerspexObjectExtensions - { - /// - /// Gets an observable for a . - /// - /// The object. - /// The property. - /// - /// An observable which fires immediately with the current value of the property on the - /// object and subsequently each time the property value changes. - /// - public static IObservable GetObservable(this IPerspexObject o, PerspexProperty property) - { - Contract.Requires(o != null); - Contract.Requires(property != null); - - return new PerspexObservable( - observer => - { - EventHandler handler = (s, e) => - { - if (e.Property == property) - { - observer.OnNext(e.NewValue); - } - }; - - observer.OnNext(o.GetValue(property)); - - o.PropertyChanged += handler; - - return Disposable.Create(() => - { - o.PropertyChanged -= handler; - }); - }, - GetDescription(o, property)); - } - - /// - /// Gets an observable for a . - /// - /// The object. - /// The property type. - /// The property. - /// - /// An observable which fires immediately with the current value of the property on the - /// object and subsequently each time the property value changes. - /// - public static IObservable GetObservable(this IPerspexObject o, PerspexProperty property) - { - Contract.Requires(o != null); - Contract.Requires(property != null); - - return o.GetObservable((PerspexProperty)property).Cast(); - } - - /// - /// Gets an observable for a . - /// - /// The object. - /// The type of the property. - /// The property. - /// - /// An observable which when subscribed pushes the old and new values of the property each - /// time it is changed. Note that the observable returned from this method does not fire - /// with the current value of the property immediately. - /// - public static IObservable> GetObservableWithHistory( - this IPerspexObject o, - PerspexProperty property) - { - Contract.Requires(o != null); - Contract.Requires(property != null); - - return new PerspexObservable>( - observer => - { - EventHandler handler = (s, e) => - { - if (e.Property == property) - { - observer.OnNext(Tuple.Create((T)e.OldValue, (T)e.NewValue)); - } - }; - - o.PropertyChanged += handler; - - return Disposable.Create(() => - { - o.PropertyChanged -= handler; - }); - }, - GetDescription(o, property)); - } - - /// - /// Gets a subject for a . - /// - /// The object. - /// The property. - /// - /// The priority with which binding values are written to the object. - /// - /// - /// An which can be used for two-way binding to/from the - /// property. - /// - public static ISubject GetSubject( - this IPerspexObject o, - PerspexProperty property, - BindingPriority priority = BindingPriority.LocalValue) - { - // TODO: Subject.Create is not yet in stable Rx : once it is, remove the - // AnonymousSubject classes and use Subject.Create. - var output = new Subject(); - var result = new AnonymousSubject( - Observer.Create( - x => output.OnNext(x), - e => output.OnError(e), - () => output.OnCompleted()), - o.GetObservable(property)); - o.Bind(property, output, priority); - return result; - } - - /// - /// Gets a subject for a . - /// - /// The property type. - /// The object. - /// The property. - /// - /// The priority with which binding values are written to the object. - /// - /// - /// An which can be used for two-way binding to/from the - /// property. - /// - public static ISubject GetSubject( - this IPerspexObject o, - PerspexProperty property, - BindingPriority priority = BindingPriority.LocalValue) - { - // TODO: Subject.Create is not yet in stable Rx : once it is, remove the - // AnonymousSubject classes from this file and use Subject.Create. - var output = new Subject(); - var result = new AnonymousSubject( - Observer.Create( - x => output.OnNext(x), - e => output.OnError(e), - () => output.OnCompleted()), - o.GetObservable(property)); - o.Bind(property, output, priority); - return result; - } - - /// - /// Gets a weak observable for a . - /// - /// The object. - /// The property. - /// An observable. - public static IObservable GetWeakObservable(this IPerspexObject o, PerspexProperty property) - { - Contract.Requires(o != null); - Contract.Requires(property != null); - - return new WeakPropertyChangedObservable( - new WeakReference(o), - property, - GetDescription(o, property)); - } - - /// - /// Binds a property on an to an . - /// - /// The object. - /// The property to bind. - /// The binding. - /// - /// An optional anchor from which to locate required context. When binding to objects that - /// are not in the logical tree, certain types of binding need an anchor into the tree in - /// order to locate named controls or resources. The parameter - /// can be used to provice this context. - /// - /// An which can be used to cancel the binding. - public static IDisposable Bind( - this IPerspexObject target, - PerspexProperty property, - IBinding binding, - object anchor = null) - { - Contract.Requires(target != null); - Contract.Requires(property != null); - Contract.Requires(binding != null); - - var result = binding.Initiate(target, property, anchor); - - if (result != null) - { - return BindingOperations.Apply(target, property, result, anchor); - } - else - { - return Disposable.Empty; - } - } - - /// - /// Subscribes to a property changed notifications for changes that originate from a - /// . - /// - /// The type of the property change sender. - /// The property changed observable. - /// - /// The method to call. The parameters are the sender and the event args. - /// - /// A disposable that can be used to terminate the subscription. - public static IDisposable AddClassHandler( - this IObservable observable, - Action action) - where TTarget : PerspexObject - { - return observable.Subscribe(e => - { - if (e.Sender is TTarget) - { - action((TTarget)e.Sender, e); - } - }); - } - - /// - /// Subscribes to a property changed notifications for changes that originate from a - /// . - /// - /// The type of the property change sender. - /// The property changed observable. - /// Given a TTarget, returns the handler. - /// A disposable that can be used to terminate the subscription. - public static IDisposable AddClassHandler( - this IObservable observable, - Func> handler) - where TTarget : class - { - return observable.Subscribe(e => SubscribeAdapter(e, handler)); - } - - /// - /// Gets a description of a property that van be used in observables. - /// - /// The object. - /// The property - /// The description. - private static string GetDescription(IPerspexObject o, PerspexProperty property) - { - return $"{o.GetType().Name}.{property.Name}"; - } - - /// - /// Observer method for . - /// - /// The sender type to accept. - /// The event args. - /// Given a TTarget, returns the handler. - private static void SubscribeAdapter( - PerspexPropertyChangedEventArgs e, - Func> handler) - where TTarget : class - { - var target = e.Sender as TTarget; - - if (target != null) - { - handler(target)(e); - } - } - } -} diff --git a/src/Perspex.Base/PerspexProperty.cs b/src/Perspex.Base/PerspexProperty.cs deleted file mode 100644 index 36c534266e..0000000000 --- a/src/Perspex.Base/PerspexProperty.cs +++ /dev/null @@ -1,554 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reactive.Subjects; -using System.Reflection; -using Perspex.Data; -using Perspex.Utilities; - -namespace Perspex -{ - /// - /// Base class for perspex properties. - /// - public class PerspexProperty : IEquatable - { - /// - /// Represents an unset property value. - /// - public static readonly object UnsetValue = new Unset(); - - private static int s_nextId = 1; - private readonly Subject _initialized; - private readonly Subject _changed; - private readonly PropertyMetadata _defaultMetadata; - private readonly Dictionary _metadata; - - /// - /// Initializes a new instance of the class. - /// - /// The name of the property. - /// The type of the property's value. - /// The type of the class that registers the property. - /// The property metadata. - /// A callback. - protected PerspexProperty( - string name, - Type valueType, - Type ownerType, - PropertyMetadata metadata, - Action notifying = null) - { - Contract.Requires(name != null); - Contract.Requires(valueType != null); - Contract.Requires(ownerType != null); - Contract.Requires(metadata != null); - - if (name.Contains(".")) - { - throw new ArgumentException("'name' may not contain periods."); - } - - _initialized = new Subject(); - _changed = new Subject(); - _metadata = new Dictionary(); - - Name = name; - PropertyType = valueType; - OwnerType = ownerType; - Notifying = notifying; - Id = s_nextId++; - - _metadata.Add(ownerType, metadata); - _defaultMetadata = metadata; - } - - /// - /// Initializes a new instance of the class. - /// - /// The direct property to copy. - /// The new owner type. - /// Optional overridden metadata. - protected PerspexProperty( - PerspexProperty source, - Type ownerType, - PropertyMetadata metadata) - { - Contract.Requires(source != null); - Contract.Requires(ownerType != null); - - _initialized = source._initialized; - _changed = source._changed; - _metadata = new Dictionary(); - - Name = source.Name; - PropertyType = source.PropertyType; - OwnerType = ownerType; - Notifying = source.Notifying; - Id = source.Id; - _defaultMetadata = source._defaultMetadata; - - if (metadata != null) - { - _metadata.Add(ownerType, metadata); - } - } - - /// - /// Gets the name of the property. - /// - public string Name { get; } - - /// - /// Gets the type of the property's value. - /// - public Type PropertyType { get; } - - /// - /// Gets the type of the class that registered the property. - /// - public Type OwnerType { get; } - - /// - /// Gets a value indicating whether the property inherits its value. - /// - public virtual bool Inherits => false; - - /// - /// Gets a value indicating whether this is an attached property. - /// - public virtual bool IsAttached => false; - - /// - /// Gets a value indicating whether this is a direct property. - /// - public virtual bool IsDirect => false; - - /// - /// Gets a value indicating whether this is a readonly property. - /// - public virtual bool IsReadOnly => false; - - /// - /// Gets an observable that is fired when this property is initialized on a - /// new instance. - /// - /// - /// This observable is fired each time a new is constructed - /// for all properties registered on the object's type. The default value of the property - /// for the object is passed in the args' NewValue (OldValue will always be - /// . - /// - /// - /// An observable that is fired when this property is initialized on a new - /// instance. - /// - public IObservable Initialized => _initialized; - - /// - /// Gets an observable that is fired when this property changes on any - /// instance. - /// - /// - /// An observable that is fired when this property changes on any - /// instance. - /// - public IObservable Changed => _changed; - - /// - /// Gets a method that gets called before and after the property starts being notified on an - /// object. - /// - /// - /// When a property changes, change notifications are sent to all property subscribers; - /// for example via the observable and and the - /// event. If this callback is set for a property, - /// then it will be called before and after these notifications take place. The bool argument - /// will be true before the property change notifications are sent and false afterwards. This - /// callback is intended to support Control.IsDataContextChanging. - /// - public Action Notifying { get; } - - /// - /// Gets the integer ID that represents this property. - /// - internal int Id { get; } - - /// - /// Provides access to a property's binding via the - /// indexer. - /// - /// The property. - /// A describing the binding. - public static IndexerDescriptor operator !(PerspexProperty property) - { - return new IndexerDescriptor - { - Priority = BindingPriority.LocalValue, - Property = property, - }; - } - - /// - /// Provides access to a property's template binding via the - /// indexer. - /// - /// The property. - /// A describing the binding. - public static IndexerDescriptor operator ~(PerspexProperty property) - { - return new IndexerDescriptor - { - Priority = BindingPriority.TemplatedParent, - Property = property, - }; - } - - /// - /// Tests two s for equality. - /// - /// The first property. - /// The second property. - /// True if the properties are equal, otherwise false. - public static bool operator ==(PerspexProperty a, PerspexProperty b) - { - if (object.ReferenceEquals(a, b)) - { - return true; - } - else if (((object)a == null) || ((object)b == null)) - { - return false; - } - else - { - return a.Equals(b); - } - } - - /// - /// Tests two s for unequality. - /// - /// The first property. - /// The second property. - /// True if the properties are equal, otherwise false. - public static bool operator !=(PerspexProperty a, PerspexProperty b) - { - return !(a == b); - } - - /// - /// Registers a . - /// - /// The type of the class that is registering the property. - /// The type of the property's value. - /// The name of the property. - /// The default value of the property. - /// Whether the property inherits its value. - /// The default binding mode for the property. - /// A validation function. - /// - /// A method that gets called before and after the property starts being notified on an - /// object; the bool argument will be true before and false afterwards. This callback is - /// intended to support IsDataContextChanging. - /// - /// A - public static StyledProperty Register( - string name, - TValue defaultValue = default(TValue), - bool inherits = false, - BindingMode defaultBindingMode = BindingMode.OneWay, - Func validate = null, - Action notifying = null) - where TOwner : IPerspexObject - { - Contract.Requires(name != null); - - var metadata = new StyledPropertyMetadata( - defaultValue, - validate: Cast(validate), - defaultBindingMode: defaultBindingMode); - - var result = new StyledProperty( - name, - typeof(TOwner), - metadata, - inherits, - notifying); - PerspexPropertyRegistry.Instance.Register(typeof(TOwner), result); - return result; - } - - /// - /// Registers an attached . - /// - /// The type of the class that is registering the property. - /// The type of the class that the property is to be registered on. - /// The type of the property's value. - /// The name of the property. - /// The default value of the property. - /// Whether the property inherits its value. - /// The default binding mode for the property. - /// A validation function. - /// A - public static AttachedProperty RegisterAttached( - string name, - TValue defaultValue = default(TValue), - bool inherits = false, - BindingMode defaultBindingMode = BindingMode.OneWay, - Func validate = null) - where THost : IPerspexObject - { - Contract.Requires(name != null); - - var metadata = new StyledPropertyMetadata( - defaultValue, - validate: Cast(validate), - defaultBindingMode: defaultBindingMode); - - var result = new AttachedProperty(name, typeof(TOwner), metadata, inherits); - PerspexPropertyRegistry.Instance.Register(typeof(THost), result); - return result; - } - - /// - /// Registers an attached . - /// - /// The type of the class that the property is to be registered on. - /// The type of the property's value. - /// The name of the property. - /// The type of the class that is registering the property. - /// The default value of the property. - /// Whether the property inherits its value. - /// The default binding mode for the property. - /// A validation function. - /// A - public static AttachedProperty RegisterAttached( - string name, - Type ownerType, - TValue defaultValue = default(TValue), - bool inherits = false, - BindingMode defaultBindingMode = BindingMode.OneWay, - Func validate = null) - where THost : IPerspexObject - { - Contract.Requires(name != null); - - var metadata = new StyledPropertyMetadata( - defaultValue, - validate: Cast(validate), - defaultBindingMode: defaultBindingMode); - - var result = new AttachedProperty(name, ownerType, metadata, inherits); - PerspexPropertyRegistry.Instance.Register(typeof(THost), result); - return result; - } - - /// - /// Registers a direct . - /// - /// The type of the class that is registering the property. - /// The type of the property's value. - /// The name of the property. - /// Gets the current value of the property. - /// Sets the value of the property. - /// - /// The value to use when the property is set to - /// - /// The default binding mode for the property. - /// A - public static DirectProperty RegisterDirect( - string name, - Func getter, - Action setter = null, - TValue unsetValue = default(TValue), - BindingMode defaultBindingMode = BindingMode.OneWay) - where TOwner : IPerspexObject - { - Contract.Requires(name != null); - - var metadata = new DirectPropertyMetadata( - unsetValue: unsetValue, - defaultBindingMode: defaultBindingMode); - - var result = new DirectProperty(name, getter, setter, metadata); - PerspexPropertyRegistry.Instance.Register(typeof(TOwner), result); - return result; - } - - /// - /// Returns a binding accessor that can be passed to 's [] - /// operator to initiate a binding. - /// - /// A . - /// - /// The ! and ~ operators are short forms of this. - /// - public IndexerDescriptor Bind() - { - return new IndexerDescriptor - { - Property = this, - }; - } - - /// - public override bool Equals(object obj) - { - var p = obj as PerspexProperty; - return p != null && Equals(p); - } - - /// - public bool Equals(PerspexProperty other) - { - return other != null && Id == other.Id; - } - - /// - public override int GetHashCode() - { - return Id; - } - - /// - /// Gets the property metadata for the specified type. - /// - /// The type. - /// - /// The property metadata. - /// - public PropertyMetadata GetMetadata() where T : IPerspexObject - { - var type = typeof(T); - - while (type != null) - { - PropertyMetadata result; - - if (_metadata.TryGetValue(type, out result)) - { - return result; - } - - type = type.GetTypeInfo().BaseType; - } - - return _defaultMetadata; - } - - - /// - /// Gets the property metadata for the specified type. - /// - /// The type. - /// - /// The property metadata. - /// - public PropertyMetadata GetMetadata(Type type) - { - Contract.Requires(type != null); - - while (type != null) - { - PropertyMetadata result; - - if (_metadata.TryGetValue(type, out result)) - { - return result; - } - - type = type.GetTypeInfo().BaseType; - } - - return _defaultMetadata; - } - - /// - /// Checks whether the is valid for the property. - /// - /// The value. - /// True if the value is valid, otherwise false. - public bool IsValidValue(object value) - { - return TypeUtilities.TryCast(PropertyType, value, out value); - } - - /// - /// Gets the string representation of the property. - /// - /// The property's string representation. - public override string ToString() - { - return Name; - } - - /// - /// Notifies the observable. - /// - /// The observable arguments. - internal void NotifyInitialized(PerspexPropertyChangedEventArgs e) - { - _initialized.OnNext(e); - } - - /// - /// Notifies the observable. - /// - /// The observable arguments. - internal void NotifyChanged(PerspexPropertyChangedEventArgs e) - { - _changed.OnNext(e); - } - - /// - /// Overrides the metadata for the property on the specified type. - /// - /// The type. - /// The metadata. - protected void OverrideMetadata(Type type, PropertyMetadata metadata) - { - Contract.Requires(type != null); - Contract.Requires(metadata != null); - - if (_metadata.ContainsKey(type)) - { - throw new InvalidOperationException( - $"Metadata is already set for {Name} on {type}."); - } - - var baseMetadata = GetMetadata(type); - metadata.Merge(baseMetadata, this); - _metadata.Add(type, metadata); - } - - [DebuggerHidden] - private static Func Cast(Func f) - where TOwner : IPerspexObject - { - if (f != null) - { - return (o, v) => (o is TOwner) ? f((TOwner)o, v) : v; - } - else - { - return null; - } - } - - /// - /// Class representing the . - /// - private class Unset - { - /// - /// Returns the string representation of the . - /// - /// The string "(unset)". - public override string ToString() => "(unset)"; - } - } -} diff --git a/src/Perspex.Base/PerspexPropertyChangedEventArgs.cs b/src/Perspex.Base/PerspexPropertyChangedEventArgs.cs deleted file mode 100644 index 4563278acc..0000000000 --- a/src/Perspex.Base/PerspexPropertyChangedEventArgs.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Data; - -namespace Perspex -{ - /// - /// Provides information for a perspex property change. - /// - public class PerspexPropertyChangedEventArgs : EventArgs - { - /// - /// Initializes a new instance of the class. - /// - /// The object that the property changed on. - /// The property that changed. - /// The old value of the property. - /// The new value of the property. - /// The priority of the binding that produced the value. - public PerspexPropertyChangedEventArgs( - PerspexObject sender, - PerspexProperty property, - object oldValue, - object newValue, - BindingPriority priority) - { - Sender = sender; - Property = property; - OldValue = oldValue; - NewValue = newValue; - Priority = priority; - } - - /// - /// Gets the that the property changed on. - /// - /// The sender object. - public PerspexObject Sender { get; private set; } - - /// - /// Gets the property that changed. - /// - /// - /// The property that changed. - /// - public PerspexProperty Property { get; private set; } - - /// - /// Gets the old value of the property. - /// - /// - /// The old value of the property. - /// - public object OldValue { get; private set; } - - /// - /// Gets the new value of the property. - /// - /// - /// The new value of the property. - /// - public object NewValue { get; private set; } - - /// - /// Gets the priority of the binding that produced the value. - /// - /// - /// The priority of the binding that produced the value. - /// - public BindingPriority Priority { get; private set; } - } -} diff --git a/src/Perspex.Base/PerspexPropertyRegistry.cs b/src/Perspex.Base/PerspexPropertyRegistry.cs deleted file mode 100644 index 25a1013abb..0000000000 --- a/src/Perspex.Base/PerspexPropertyRegistry.cs +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Perspex -{ - /// - /// Tracks registered instances. - /// - public class PerspexPropertyRegistry - { - /// - /// The registered properties by type. - /// - private readonly Dictionary> _registered = - new Dictionary>(); - - /// - /// The registered attached properties by owner type. - /// - private readonly Dictionary> _attached = - new Dictionary>(); - - /// - /// Gets the instance - /// - public static PerspexPropertyRegistry Instance { get; } - = new PerspexPropertyRegistry(); - - /// - /// Gets all attached s registered by an owner. - /// - /// The owner type. - /// A collection of definitions. - public IEnumerable GetAttached(Type ownerType) - { - Dictionary inner; - - if (_attached.TryGetValue(ownerType, out inner)) - { - return inner.Values; - } - - return Enumerable.Empty(); - } - - /// - /// Gets all s registered on a type. - /// - /// The type. - /// A collection of definitions. - public IEnumerable GetRegistered(Type type) - { - Contract.Requires(type != null); - - var i = type.GetTypeInfo(); - - while (type != null) - { - // Ensure the type's static ctor has been run. - RuntimeHelpers.RunClassConstructor(type.TypeHandle); - - Dictionary inner; - - if (_registered.TryGetValue(type, out inner)) - { - foreach (var p in inner) - { - yield return p.Value; - } - } - - type = type.GetTypeInfo().BaseType; - } - } - - /// - /// Gets all s registered on a object. - /// - /// The object. - /// A collection of definitions. - public IEnumerable GetRegistered(PerspexObject o) - { - Contract.Requires(o != null); - - return GetRegistered(o.GetType()); - } - - /// - /// Finds a registered on a type. - /// - /// The type. - /// The property. - /// The registered property or null if not found. - /// - /// Calling AddOwner on a PerspexProperty creates a new PerspexProperty that is a - /// different object but is equal according to . - /// - public PerspexProperty FindRegistered(Type type, PerspexProperty property) - { - while (type != null) - { - Dictionary inner; - - if (_registered.TryGetValue(type, out inner)) - { - PerspexProperty result; - - if (inner.TryGetValue(property.Id, out result)) - { - return result; - } - } - - type = type.GetTypeInfo().BaseType; - } - - return null; - } - - /// - /// Finds registered on an object. - /// - /// The object. - /// The property. - /// The registered property or null if not found. - /// - /// Calling AddOwner on a PerspexProperty creates a new PerspexProperty that is a - /// different object but is equal according to . - /// - public PerspexProperty FindRegistered(object o, PerspexProperty property) - { - return FindRegistered(o.GetType(), property); - } - - /// - /// Finds a registered property on a type by name. - /// - /// The type. - /// - /// The property name. If an attached property it should be in the form - /// "OwnerType.PropertyName". - /// - /// - /// The registered property or null if no matching property found. - /// - public PerspexProperty FindRegistered(Type type, string name) - { - Contract.Requires(type != null); - Contract.Requires(name != null); - - var parts = name.Split('.'); - var types = GetImplementedTypes(type).ToList(); - - if (parts.Length < 1 || parts.Length > 2) - { - throw new ArgumentException("Invalid property name."); - } - - string propertyName; - var results = GetRegistered(type); - - if (parts.Length == 1) - { - propertyName = parts[0]; - results = results.Where(x => !x.IsAttached || types.Contains(x.OwnerType.Name)); - } - else - { - if (!types.Contains(parts[0])) - { - results = results.Where(x => x.OwnerType.Name == parts[0]); - } - - propertyName = parts[1]; - } - - return results.FirstOrDefault(x => x.Name == propertyName); - } - - - /// - /// Finds a registered property on an object by name. - /// - /// The object. - /// - /// The property name. If an attached property it should be in the form - /// "OwnerType.PropertyName". - /// - /// - /// The registered property or null if no matching property found. - /// - public PerspexProperty FindRegistered(PerspexObject o, string name) - { - return FindRegistered(o.GetType(), name); - } - - /// - /// Returns a type and all its base types. - /// - /// The type. - /// The type and all its base types. - private IEnumerable GetImplementedTypes(Type type) - { - while (type != null) - { - yield return type.Name; - type = type.GetTypeInfo().BaseType; - } - } - - /// - /// Checks whether a is registered on a type. - /// - /// The type. - /// The property. - /// True if the property is registered, otherwise false. - public bool IsRegistered(Type type, PerspexProperty property) - { - return FindRegistered(type, property) != null; - } - - /// - /// Checks whether a is registered on a object. - /// - /// The object. - /// The property. - /// True if the property is registered, otherwise false. - public bool IsRegistered(object o, PerspexProperty property) - { - return IsRegistered(o.GetType(), property); - } - - /// - /// Registers a on a type. - /// - /// The type. - /// The property. - /// - /// You won't usually want to call this method directly, instead use the - /// method. - /// - public void Register(Type type, PerspexProperty property) - { - Contract.Requires(type != null); - Contract.Requires(property != null); - - Dictionary inner; - - if (!_registered.TryGetValue(type, out inner)) - { - inner = new Dictionary(); - _registered.Add(type, inner); - } - - if (!inner.ContainsKey(property.Id)) - { - inner.Add(property.Id, property); - } - - if (property.IsAttached) - { - if (!_attached.TryGetValue(property.OwnerType, out inner)) - { - inner = new Dictionary(); - _attached.Add(property.OwnerType, inner); - } - - if (!inner.ContainsKey(property.Id)) - { - inner.Add(property.Id, property); - } - } - } - } -} diff --git a/src/Perspex.Base/PerspexProperty`1.cs b/src/Perspex.Base/PerspexProperty`1.cs deleted file mode 100644 index 1ad1cef2e1..0000000000 --- a/src/Perspex.Base/PerspexProperty`1.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex -{ - /// - /// A typed perspex property. - /// - /// The value type of the property. - public class PerspexProperty : PerspexProperty - { - /// - /// Initializes a new instance of the class. - /// - /// The name of the property. - /// The type of the class that registers the property. - /// The property metadata. - /// A callback. - protected PerspexProperty( - string name, - Type ownerType, - PropertyMetadata metadata, - Action notifying = null) - : base(name, typeof(TValue), ownerType, metadata, notifying) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The property to copy. - /// The new owner type. - /// Optional overridden metadata. - protected PerspexProperty( - PerspexProperty source, - Type ownerType, - PropertyMetadata metadata) - : base(source, ownerType, metadata) - { - } - } -} diff --git a/src/Perspex.Base/Platform/IAssetLoader.cs b/src/Perspex.Base/Platform/IAssetLoader.cs deleted file mode 100644 index cd32d7bd3d..0000000000 --- a/src/Perspex.Base/Platform/IAssetLoader.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.IO; -using System.Reflection; - -namespace Perspex.Platform -{ - /// - /// Loads assets compiled into the application binary. - /// - public interface IAssetLoader - { - /// - /// We need a way to override the default assembly selected by the host platform - /// because right now it is selecting the wrong one for PCL based Apps. The - /// AssetLoader needs a refactor cause right now it lives in 3+ platforms which - /// can all be loaded on Windows. - /// - /// - void SetDefaultAssembly(Assembly asm); - - /// - /// Checks if an asset with the specified URI exists. - /// - /// The URI. - /// - /// A base URI to use if is relative. - /// - /// True if the asset could be found; otherwise false. - bool Exists(Uri uri, Uri baseUri = null); - - /// - /// Opens the resource with the requested URI. - /// - /// The URI. - /// - /// A base URI to use if is relative. - /// - /// A stream containing the resource contents. - /// - /// The resource was not found. - /// - Stream Open(Uri uri, Uri baseUri = null); - } -} diff --git a/src/Perspex.Base/Platform/IPclPlatformWrapper.cs b/src/Perspex.Base/Platform/IPclPlatformWrapper.cs deleted file mode 100644 index 68a2a379bf..0000000000 --- a/src/Perspex.Base/Platform/IPclPlatformWrapper.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Perspex.Platform -{ - public interface IPclPlatformWrapper - { - Assembly[] GetLoadedAssemblies(); - void PostThreadPoolItem(Action cb); - IDisposable StartSystemTimer(TimeSpan interval, Action tick); - string GetStackTrace(); - } -} diff --git a/src/Perspex.Base/Platform/IPlatformHandle.cs b/src/Perspex.Base/Platform/IPlatformHandle.cs deleted file mode 100644 index 234e4598a4..0000000000 --- a/src/Perspex.Base/Platform/IPlatformHandle.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Platform -{ - /// - /// Represents a platform-specific handle. - /// - public interface IPlatformHandle - { - /// - /// Gets the handle. - /// - IntPtr Handle { get; } - - /// - /// Gets an optional string that describes what represents. - /// - string HandleDescriptor { get; } - } -} diff --git a/src/Perspex.Base/Platform/IPlatformThreadingInterface.cs b/src/Perspex.Base/Platform/IPlatformThreadingInterface.cs deleted file mode 100644 index 7acbc30fec..0000000000 --- a/src/Perspex.Base/Platform/IPlatformThreadingInterface.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Threading; - -namespace Perspex.Platform -{ - /// - /// Provides platform-specific services relating to threading. - /// - public interface IPlatformThreadingInterface - { - void RunLoop(CancellationToken cancellationToken); - - /// - /// Starts a timer. - /// - /// The interval. - /// The action to call on each tick. - /// An used to stop the timer. - IDisposable StartTimer(TimeSpan interval, Action tick); - - /// - /// Sends a message that causes to exit. - /// - void Signal(); - - bool CurrentThreadIsLoopThread { get; } - - event Action Signaled; - - } -} diff --git a/src/Perspex.Base/Platform/PlatformHandle.cs b/src/Perspex.Base/Platform/PlatformHandle.cs deleted file mode 100644 index 77aca1b334..0000000000 --- a/src/Perspex.Base/Platform/PlatformHandle.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Platform -{ - /// - /// Represents a platform-specific handle. - /// - public class PlatformHandle : IPlatformHandle - { - /// - /// Initializes a new instance of the class. - /// - /// The handle. - /// - /// An optional string that describes what represents. - /// - public PlatformHandle(IntPtr handle, string descriptor) - { - Handle = handle; - HandleDescriptor = descriptor; - } - - /// - /// Gets the handle. - /// - public IntPtr Handle { get; } - - /// - /// Gets an optional string that describes what represents. - /// - public string HandleDescriptor { get; } - } -} diff --git a/src/Perspex.Base/PriorityBindingEntry.cs b/src/Perspex.Base/PriorityBindingEntry.cs deleted file mode 100644 index cc5cd66c2e..0000000000 --- a/src/Perspex.Base/PriorityBindingEntry.cs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Data; - -namespace Perspex -{ - /// - /// A registered binding in a . - /// - internal class PriorityBindingEntry : IDisposable - { - private PriorityLevel _owner; - private IDisposable _subscription; - - /// - /// Initializes a new instance of the class. - /// - /// The owner. - /// - /// The binding index. Later bindings should have higher indexes. - /// - /// The validation settings for the binding. - public PriorityBindingEntry(PriorityLevel owner, int index) - { - _owner = owner; - Index = index; - } - - /// - /// Gets the observable associated with the entry. - /// - public IObservable Observable { get; private set; } - - /// - /// Gets a description of the binding. - /// - public string Description - { - get; - private set; - } - - /// - /// Gets the binding entry index. Later bindings will have higher indexes. - /// - public int Index - { - get; - } - - /// - /// The current value of the binding. - /// - public object Value - { - get; - private set; - } - - /// - /// Starts listening to the binding. - /// - /// The binding. - public void Start(IObservable binding) - { - Contract.Requires(binding != null); - - if (_subscription != null) - { - throw new Exception("PriorityValue.Entry.Start() called more than once."); - } - - Observable = binding; - Value = PerspexProperty.UnsetValue; - - if (binding is IDescription) - { - Description = ((IDescription)binding).Description; - } - - _subscription = binding.Subscribe(ValueChanged, Completed); - } - - /// - /// Ends the binding subscription. - /// - public void Dispose() - { - _subscription?.Dispose(); - } - - private void ValueChanged(object value) - { - var bindingError = value as BindingError; - - if (bindingError != null) - { - _owner.Error(this, bindingError); - } - - var validationStatus = value as ValidationStatus; - - if (validationStatus != null) - { - _owner.Validation(this, validationStatus); - } - else if (bindingError == null || bindingError.UseFallbackValue) - { - Value = bindingError == null ? value : bindingError.FallbackValue; - _owner.Changed(this); - } - } - - private void Completed() - { - _owner.Completed(this); - } - } -} diff --git a/src/Perspex.Base/PriorityLevel.cs b/src/Perspex.Base/PriorityLevel.cs deleted file mode 100644 index 2ab957f645..0000000000 --- a/src/Perspex.Base/PriorityLevel.cs +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Reactive.Disposables; -using Perspex.Data; -using Perspex.Logging; - -namespace Perspex -{ - /// - /// Stores bindings for a priority level in a . - /// - /// - /// - /// Each priority level in a has a current , - /// a list of and a . When there are no - /// bindings present, or all bindings return then - /// Value will equal DirectValue. - /// - /// - /// When there are bindings present, then the latest added binding that doesn't return - /// UnsetValue will take precedence. The active binding is returned by the - /// property (which refers to the active binding's - /// property rather than the index in - /// Bindings). - /// - /// - /// If DirectValue is set while a binding is active, then it will replace the - /// current value until the active binding fires again. - /// - /// - internal class PriorityLevel - { - private PriorityValue _owner; - private object _directValue; - private int _nextIndex; - - /// - /// Initializes a new instance of the class. - /// - /// The owner. - /// The priority. - public PriorityLevel( - PriorityValue owner, - int priority) - { - Contract.Requires(owner != null); - - _owner = owner; - Priority = priority; - Value = _directValue = PerspexProperty.UnsetValue; - ActiveBindingIndex = -1; - Bindings = new LinkedList(); - } - - /// - /// Gets the priority of this level. - /// - public int Priority { get; } - - /// - /// Gets or sets the direct value for this priority level. - /// - public object DirectValue - { - get - { - return _directValue; - } - - set - { - Value = _directValue = value; - _owner.LevelValueChanged(this); - } - } - - /// - /// Gets the current binding for the priority level. - /// - public object Value { get; private set; } - - /// - /// Gets the value of the active binding, or -1 - /// if no binding is active. - /// - public int ActiveBindingIndex { get; private set; } - - /// - /// Gets the bindings for the priority level. - /// - public LinkedList Bindings { get; } - - /// - /// Adds a binding. - /// - /// The binding to add. - /// Validation settings for the binding. - /// A disposable used to remove the binding. - public IDisposable Add(IObservable binding) - { - Contract.Requires(binding != null); - - var entry = new PriorityBindingEntry(this, _nextIndex++); - var node = Bindings.AddFirst(entry); - - entry.Start(binding); - - return Disposable.Create(() => - { - Bindings.Remove(node); - entry.Dispose(); - - if (entry.Index >= ActiveBindingIndex) - { - ActivateFirstBinding(); - } - }); - } - - /// - /// Invoked when an entry in changes value. - /// - /// The entry that changed. - public void Changed(PriorityBindingEntry entry) - { - if (entry.Index >= ActiveBindingIndex) - { - if (entry.Value != PerspexProperty.UnsetValue) - { - Value = entry.Value; - ActiveBindingIndex = entry.Index; - _owner.LevelValueChanged(this); - } - else - { - ActivateFirstBinding(); - } - } - } - - /// - /// Invoked when an entry in completes. - /// - /// The entry that completed. - public void Completed(PriorityBindingEntry entry) - { - Bindings.Remove(entry); - - if (entry.Index >= ActiveBindingIndex) - { - ActivateFirstBinding(); - } - } - - /// - /// Invoked when an entry in encounters a recoverable error. - /// - /// The entry that completed. - /// The error. - public void Error(PriorityBindingEntry entry, BindingError error) - { - _owner.LevelError(this, error); - } - - /// - /// Invoked when an entry in reports validation status. - /// - /// The entry that completed. - /// The validation status. - public void Validation(PriorityBindingEntry entry, ValidationStatus validationStatus) - { - _owner.LevelValidation(this, validationStatus); - } - - - /// - /// Activates the first binding that has a value. - /// - private void ActivateFirstBinding() - { - foreach (var binding in Bindings) - { - if (binding.Value != PerspexProperty.UnsetValue) - { - Value = binding.Value; - ActiveBindingIndex = binding.Index; - _owner.LevelValueChanged(this); - return; - } - } - - Value = DirectValue; - ActiveBindingIndex = -1; - _owner.LevelValueChanged(this); - } - } -} diff --git a/src/Perspex.Base/PriorityValue.cs b/src/Perspex.Base/PriorityValue.cs deleted file mode 100644 index c0e855654c..0000000000 --- a/src/Perspex.Base/PriorityValue.cs +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Perspex.Data; -using Perspex.Logging; -using Perspex.Utilities; - -namespace Perspex -{ - /// - /// Maintains a list of prioritised bindings together with a current value. - /// - /// - /// Bindings, in the form of s are added to the object using - /// the method. With the observable is passed a priority, where lower values - /// represent higher priorites. The current is selected from the highest - /// priority binding that doesn't return . Where there - /// are multiple bindings registered with the same priority, the most recently added binding - /// has a higher priority. Each time the value changes, the - /// method on the - /// owner object is fired with the old and new values. - /// - internal class PriorityValue - { - private readonly IPriorityValueOwner _owner; - private readonly Type _valueType; - private readonly Dictionary _levels = new Dictionary(); - private object _value; - private readonly Func _validate; - - /// - /// Initializes a new instance of the class. - /// - /// The owner of the object. - /// The property that the value represents. - /// The value type. - /// An optional validation function. - public PriorityValue( - IPriorityValueOwner owner, - PerspexProperty property, - Type valueType, - Func validate = null) - { - _owner = owner; - Property = property; - _valueType = valueType; - _value = PerspexProperty.UnsetValue; - ValuePriority = int.MaxValue; - _validate = validate; - } - - /// - /// Gets the property that the value represents. - /// - public PerspexProperty Property { get; } - - /// - /// Gets the current value. - /// - public object Value => _value; - - /// - /// Gets the priority of the binding that is currently active. - /// - public int ValuePriority - { - get; - private set; - } - - /// - /// Adds a new binding. - /// - /// The binding. - /// The binding priority. - /// Validation settings for the binding. - /// - /// A disposable that will remove the binding. - /// - public IDisposable Add(IObservable binding, int priority) - { - return GetLevel(priority).Add(binding); - } - - /// - /// Sets the value for a specified priority. - /// - /// The value. - /// The priority - public void SetValue(object value, int priority) - { - GetLevel(priority).DirectValue = value; - } - - /// - /// Gets the currently active bindings on this object. - /// - /// An enumerable collection of bindings. - public IEnumerable GetBindings() - { - foreach (var level in _levels) - { - foreach (var binding in level.Value.Bindings) - { - yield return binding; - } - } - } - - /// - /// Returns diagnostic string that can help the user debug the bindings in effect on - /// this object. - /// - /// A diagnostic string. - public string GetDiagnostic() - { - var b = new StringBuilder(); - var first = true; - - foreach (var level in _levels) - { - if (!first) - { - b.AppendLine(); - } - - b.Append(ValuePriority == level.Key ? "*" : string.Empty); - b.Append("Priority "); - b.Append(level.Key); - b.Append(": "); - b.AppendLine(level.Value.Value?.ToString() ?? "(null)"); - b.AppendLine("--------"); - b.Append("Direct: "); - b.AppendLine(level.Value.DirectValue?.ToString() ?? "(null)"); - - foreach (var binding in level.Value.Bindings) - { - b.Append(level.Value.ActiveBindingIndex == binding.Index ? "*" : string.Empty); - b.Append(binding.Description ?? binding.Observable.GetType().Name); - b.Append(": "); - b.AppendLine(binding.Value?.ToString() ?? "(null)"); - } - - first = false; - } - - return b.ToString(); - } - - /// - /// Called when the value for a priority level changes. - /// - /// The priority level of the changed entry. - public void LevelValueChanged(PriorityLevel level) - { - if (level.Priority <= ValuePriority) - { - if (level.Value != PerspexProperty.UnsetValue) - { - UpdateValue(level.Value, level.Priority); - } - else - { - foreach (var i in _levels.Values.OrderBy(x => x.Priority)) - { - if (i.Value != PerspexProperty.UnsetValue) - { - UpdateValue(i.Value, i.Priority); - return; - } - } - - UpdateValue(PerspexProperty.UnsetValue, int.MaxValue); - } - } - } - - /// - /// Called whenever a priority level validation state changes. - /// - /// The priority level of the changed entry. - /// The validation status. - public void LevelValidation(PriorityLevel priorityLevel, ValidationStatus validationStatus) - { - _owner.DataValidationChanged(this, validationStatus); - } - - /// - /// Called when a priority level encounters an error. - /// - /// The priority level of the changed entry. - /// The binding error. - public void LevelError(PriorityLevel level, BindingError error) - { - Logger.Log( - LogEventLevel.Error, - LogArea.Binding, - _owner, - "Error binding to {Target}.{Property}: {Message}", - _owner, - Property, - error.Exception.Message); - } - - /// - /// Causes a revalidation of the value. - /// - public void Revalidate() - { - if (_validate != null) - { - PriorityLevel level; - - if (_levels.TryGetValue(ValuePriority, out level)) - { - UpdateValue(level.Value, level.Priority); - } - } - } - - /// - /// Gets the with the specified priority, creating it if it - /// doesn't already exist. - /// - /// The priority. - /// The priority level. - private PriorityLevel GetLevel(int priority) - { - PriorityLevel result; - - if (!_levels.TryGetValue(priority, out result)) - { - result = new PriorityLevel(this, priority); - _levels.Add(priority, result); - } - - return result; - } - - /// - /// Updates the current and notifies all subscibers. - /// - /// The value to set. - /// The priority level that the value came from. - private void UpdateValue(object value, int priority) - { - object castValue; - - if (TypeUtilities.TryCast(_valueType, value, out castValue)) - { - var old = _value; - - if (_validate != null && castValue != PerspexProperty.UnsetValue) - { - castValue = _validate(castValue); - } - - ValuePriority = priority; - _value = castValue; - _owner?.Changed(this, old, _value); - } - else - { - Logger.Error( - LogArea.Binding, - _owner, - "Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})", - Property.Name, - _valueType, - value, - value.GetType()); - } - } - } -} diff --git a/src/Perspex.Base/Properties/AssemblyInfo.cs b/src/Perspex.Base/Properties/AssemblyInfo.cs deleted file mode 100644 index f3c46631b7..0000000000 --- a/src/Perspex.Base/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Reflection; -using System.Runtime.CompilerServices; - -[assembly: AssemblyTitle("Perspex.Base")] -[assembly: InternalsVisibleTo("Perspex.Base.UnitTests")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] \ No newline at end of file diff --git a/src/Perspex.Base/PropertyMetadata.cs b/src/Perspex.Base/PropertyMetadata.cs deleted file mode 100644 index 256c818f81..0000000000 --- a/src/Perspex.Base/PropertyMetadata.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using Perspex.Data; - -namespace Perspex -{ - /// - /// Base class for perspex property metadata. - /// - public class PropertyMetadata - { - private BindingMode _defaultBindingMode; - - /// - /// Initializes a new instance of the class. - /// - /// The default binding mode. - public PropertyMetadata(BindingMode defaultBindingMode = BindingMode.Default) - { - _defaultBindingMode = defaultBindingMode; - } - - /// - /// Gets the default binding mode for the property. - /// - public BindingMode DefaultBindingMode - { - get - { - return _defaultBindingMode == BindingMode.Default ? - BindingMode.OneWay : _defaultBindingMode; - } - } - - /// - /// Merges the metadata with the base metadata. - /// - /// The base metadata to merge. - /// The property to which the metadata is being applied. - public virtual void Merge( - PropertyMetadata baseMetadata, - PerspexProperty property) - { - if (_defaultBindingMode == BindingMode.Default) - { - _defaultBindingMode = baseMetadata.DefaultBindingMode; - } - } - } -} diff --git a/src/Perspex.Base/Reactive/AnonymousSubject`1.cs b/src/Perspex.Base/Reactive/AnonymousSubject`1.cs deleted file mode 100644 index 3bbf2295ff..0000000000 --- a/src/Perspex.Base/Reactive/AnonymousSubject`1.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Subjects; - -namespace Perspex.Reactive -{ - public class AnonymousSubject : AnonymousSubject, ISubject - { - public AnonymousSubject(IObserver observer, IObservable observable) - : base(observer, observable) - { - } - } -} diff --git a/src/Perspex.Base/Reactive/AnonymousSubject`2.cs b/src/Perspex.Base/Reactive/AnonymousSubject`2.cs deleted file mode 100644 index 04e58585b3..0000000000 --- a/src/Perspex.Base/Reactive/AnonymousSubject`2.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Subjects; - -namespace Perspex.Reactive -{ - public class AnonymousSubject : ISubject - { - private readonly IObserver _observer; - private readonly IObservable _observable; - - public AnonymousSubject(IObserver observer, IObservable observable) - { - _observer = observer; - _observable = observable; - } - - public void OnCompleted() - { - _observer.OnCompleted(); - } - - public void OnError(Exception error) - { - if (error == null) - throw new ArgumentNullException("error"); - - _observer.OnError(error); - } - - public void OnNext(T value) - { - _observer.OnNext(value); - } - - public IDisposable Subscribe(IObserver observer) - { - if (observer == null) - throw new ArgumentNullException("observer"); - - // - // [OK] Use of unsafe Subscribe: non-pretentious wrapping of an observable sequence. - // - return _observable.Subscribe/*Unsafe*/(observer); - } - } -} diff --git a/src/Perspex.Base/Reactive/ObservableEx.cs b/src/Perspex.Base/Reactive/ObservableEx.cs deleted file mode 100644 index b808543904..0000000000 --- a/src/Perspex.Base/Reactive/ObservableEx.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Disposables; - -namespace Perspex.Reactive -{ - /// - /// Provides common observable methods not found in standard Rx framework. - /// - public static class ObservableEx - { - /// - /// Returns an observable that fires once with the specified value and never completes. - /// - /// The type of the value. - /// The value. - /// The observable. - public static IObservable SingleValue(T value) - { - return new SingleValueImpl(value); - } - - private class SingleValueImpl : IObservable - { - private T _value; - - public SingleValueImpl(T value) - { - _value = value; - } - - public IDisposable Subscribe(IObserver observer) - { - observer.OnNext(_value); - return Disposable.Empty; - } - } - } -} diff --git a/src/Perspex.Base/Reactive/PerspexObservable.cs b/src/Perspex.Base/Reactive/PerspexObservable.cs deleted file mode 100644 index a939bf33b5..0000000000 --- a/src/Perspex.Base/Reactive/PerspexObservable.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive; -using System.Reactive.Disposables; - -namespace Perspex.Reactive -{ - /// - /// An with an additional description. - /// - /// The type of the elements in the sequence. - public class PerspexObservable : ObservableBase, IDescription - { - private readonly Func, IDisposable> _subscribe; - - /// - /// Initializes a new instance of the class. - /// - /// The subscribe function. - /// The description of the observable. - public PerspexObservable(Func, IDisposable> subscribe, string description) - { - Contract.Requires(subscribe != null); - - _subscribe = subscribe; - Description = description; - } - - /// - /// Gets the description of the observable. - /// - public string Description { get; } - - /// - protected override IDisposable SubscribeCore(IObserver observer) - { - return _subscribe(observer) ?? Disposable.Empty; - } - } -} \ No newline at end of file diff --git a/src/Perspex.Base/Reactive/WeakPropertyChangedObservable.cs b/src/Perspex.Base/Reactive/WeakPropertyChangedObservable.cs deleted file mode 100644 index 63b1df5fb2..0000000000 --- a/src/Perspex.Base/Reactive/WeakPropertyChangedObservable.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive; -using System.Reactive.Disposables; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using Perspex.Utilities; - -namespace Perspex.Reactive -{ - internal class WeakPropertyChangedObservable : ObservableBase, - IWeakSubscriber, IDescription - { - private WeakReference _sourceReference; - private readonly PerspexProperty _property; - private readonly Subject _changed = new Subject(); - - private int _count; - - public WeakPropertyChangedObservable( - WeakReference source, - PerspexProperty property, - string description) - { - _sourceReference = source; - _property = property; - Description = description; - } - - public string Description { get; } - - public void OnEvent(object sender, PerspexPropertyChangedEventArgs e) - { - if (e.Property == _property) - { - _changed.OnNext(e.NewValue); - } - } - - protected override IDisposable SubscribeCore(IObserver observer) - { - IPerspexObject instance; - - if (_sourceReference.TryGetTarget(out instance)) - { - if (_count++ == 0) - { - WeakSubscriptionManager.Subscribe( - instance, - nameof(instance.PropertyChanged), - this); - } - - observer.OnNext(instance.GetValue(_property)); - - return Observable.Using(() => Disposable.Create(DecrementCount), _ => _changed) - .Subscribe(observer); - } - else - { - _changed.OnCompleted(); - observer.OnCompleted(); - return Disposable.Empty; - } - } - - private void DecrementCount() - { - if (--_count == 0) - { - IPerspexObject instance; - - if (_sourceReference.TryGetTarget(out instance)) - { - WeakSubscriptionManager.Unsubscribe( - instance, - nameof(instance.PropertyChanged), - this); - } - } - } - } -} diff --git a/src/Perspex.Base/StyledProperty.cs b/src/Perspex.Base/StyledProperty.cs deleted file mode 100644 index af9c348195..0000000000 --- a/src/Perspex.Base/StyledProperty.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex -{ - /// - /// A styled perspex property. - /// - public class StyledProperty : StyledPropertyBase - { - /// - /// Initializes a new instance of the class. - /// - /// The name of the property. - /// The type of the class that registers the property. - /// The property metadata. - /// Whether the property inherits its value. - /// A callback. - public StyledProperty( - string name, - Type ownerType, - StyledPropertyMetadata metadata, - bool inherits = false, - Action notifying = null) - : base(name, ownerType, metadata, inherits, notifying) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The property to add the owner to. - /// The type of the class that registers the property. - internal StyledProperty(StyledPropertyBase source, Type ownerType) - : base(source, ownerType) - { - } - - /// - /// Registers the property on another type. - /// - /// The type of the additional owner. - /// The property. - public StyledProperty AddOwner() where TOwner : IPerspexObject - { - PerspexPropertyRegistry.Instance.Register(typeof(TOwner), this); - return this; - } - } -} diff --git a/src/Perspex.Base/StyledPropertyBase.cs b/src/Perspex.Base/StyledPropertyBase.cs deleted file mode 100644 index e77c5704eb..0000000000 --- a/src/Perspex.Base/StyledPropertyBase.cs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Diagnostics; - -namespace Perspex -{ - /// - /// Base class for styled properties. - /// - public class StyledPropertyBase : PerspexProperty, IStyledPropertyAccessor - { - private bool _inherits; - - /// - /// Initializes a new instance of the class. - /// - /// The name of the property. - /// The type of the class that registers the property. - /// The property metadata. - /// Whether the property inherits its value. - /// A callback. - protected StyledPropertyBase( - string name, - Type ownerType, - StyledPropertyMetadata metadata, - bool inherits = false, - Action notifying = null) - : base(name, ownerType, metadata, notifying) - { - Contract.Requires(name != null); - Contract.Requires(ownerType != null); - - if (name.Contains(".")) - { - throw new ArgumentException("'name' may not contain periods."); - } - - _inherits = inherits; - } - - /// - /// Initializes a new instance of the class. - /// - /// The property to add the owner to. - /// The type of the class that registers the property. - protected StyledPropertyBase(StyledPropertyBase source, Type ownerType) - : base(source, ownerType, null) - { - _inherits = source.Inherits; - } - - /// - /// Gets a value indicating whether the property inherits its value. - /// - /// - /// A value indicating whether the property inherits its value. - /// - public override bool Inherits => _inherits; - - /// - /// Gets the default value for the property on the specified type. - /// - /// The type. - /// The default value. - public TValue GetDefaultValue(Type type) - { - Contract.Requires(type != null); - - return GetMetadata(type).DefaultValue; - } - - /// - /// Gets the property metadata for the specified type. - /// - /// The type. - /// - /// The property metadata. - /// - public new StyledPropertyMetadata GetMetadata(Type type) - { - return (StyledPropertyMetadata)base.GetMetadata(type); - } - - /// - /// Overrides the default value for the property on the specified type. - /// - /// The type. - /// The default value. - public void OverrideDefaultValue(TValue defaultValue) where T : IPerspexObject - { - OverrideDefaultValue(typeof(T), defaultValue); - } - - /// - /// Overrides the default value for the property on the specified type. - /// - /// The type. - /// The default value. - public void OverrideDefaultValue(Type type, TValue defaultValue) - { - OverrideMetadata(type, new StyledPropertyMetadata(defaultValue)); - } - - /// - /// Overrides the metadata for the property on the specified type. - /// - /// The type. - /// The metadata. - public void OverrideMetadata(StyledPropertyMetadata metadata) where T : IPerspexObject - { - base.OverrideMetadata(typeof(T), metadata); - } - - /// - /// Overrides the metadata for the property on the specified type. - /// - /// The type. - /// The metadata. - public void OverrideMetadata(Type type, StyledPropertyMetadata metadata) - { - base.OverrideMetadata(type, metadata); - } - - /// - /// Overrides the validation function for the specified type. - /// - /// The type. - /// The validation function. - public void OverrideValidation(Func validate) - where THost : IPerspexObject - { - Func f; - - if (validate != null) - { - f = Cast(validate); - } - else - { - // Passing null to the validation function means that the property metadata merge - // will take the base validation function, so instead use an empty validation. - f = (o, v) => v; - } - - base.OverrideMetadata(typeof(THost), new StyledPropertyMetadata(validate: f)); - } - - /// - /// Gets the string representation of the property. - /// - /// The property's string representation. - public override string ToString() - { - return Name; - } - - /// - Func IStyledPropertyAccessor.GetValidationFunc(Type type) - { - Contract.Requires(type != null); - return ((IStyledPropertyMetadata)base.GetMetadata(type)).Validate; - } - - /// - object IStyledPropertyAccessor.GetDefaultValue(Type type) => GetDefaultValue(type); - - [DebuggerHidden] - private Func Cast(Func validate) - { - return (o, v) => validate((THost)o, v); - } - } -} diff --git a/src/Perspex.Base/StyledPropertyMetadata`1.cs b/src/Perspex.Base/StyledPropertyMetadata`1.cs deleted file mode 100644 index 8d1cb28fd9..0000000000 --- a/src/Perspex.Base/StyledPropertyMetadata`1.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Diagnostics; -using Perspex.Data; - -namespace Perspex -{ - /// - /// Metadata for styled perspex properties. - /// - public class StyledPropertyMetadata : PropertyMetadata, IStyledPropertyMetadata - { - /// - /// Initializes a new instance of the class. - /// - /// The default value of the property. - /// A validation function. - /// The default binding mode. - public StyledPropertyMetadata( - TValue defaultValue = default(TValue), - Func validate = null, - BindingMode defaultBindingMode = BindingMode.Default) - : base(defaultBindingMode) - { - DefaultValue = defaultValue; - Validate = validate; - } - - /// - /// Gets the default value for the property. - /// - public TValue DefaultValue { get; private set; } - - /// - /// Gets the validation callback. - /// - public Func Validate { get; private set; } - - object IStyledPropertyMetadata.DefaultValue => DefaultValue; - - Func IStyledPropertyMetadata.Validate => Cast(Validate); - - /// - public override void Merge(PropertyMetadata baseMetadata, PerspexProperty property) - { - base.Merge(baseMetadata, property); - - var src = baseMetadata as StyledPropertyMetadata; - - if (src != null) - { - if (DefaultValue == null) - { - DefaultValue = src.DefaultValue; - } - - if (Validate == null) - { - Validate = src.Validate; - } - } - } - - [DebuggerHidden] - private static Func Cast(Func f) - { - if (f == null) - { - return null; - } - else - { - return (o, v) => f(o, (TValue)v); - } - } - } -} diff --git a/src/Perspex.Base/Threading/Dispatcher.cs b/src/Perspex.Base/Threading/Dispatcher.cs deleted file mode 100644 index 3c2480c103..0000000000 --- a/src/Perspex.Base/Threading/Dispatcher.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Perspex.Platform; - -namespace Perspex.Threading -{ - /// - /// Provides services for managing work items on a thread. - /// - /// - /// In Perspex, there is usually only a single in the application - - /// the one for the UI thread, retrieved via the property. - /// - public class Dispatcher - { - private readonly IPlatformThreadingInterface _platform; - private readonly JobRunner _jobRunner; - - public static Dispatcher UIThread { get; } = - new Dispatcher(PerspexLocator.Current.GetService()); - - public Dispatcher(IPlatformThreadingInterface platform) - { - _platform = platform; - if(_platform == null) - //TODO: Unit test mode, fix that somehow - return; - _jobRunner = new JobRunner(platform); - _platform.Signaled += _jobRunner.RunJobs; - } - - public bool CheckAccess() => _platform?.CurrentThreadIsLoopThread ?? true; - - public void VerifyAccess() - { - if (!CheckAccess()) - throw new InvalidOperationException("Call from invalid thread"); - } - - - /// - /// Runs the dispatcher's main loop. - /// - /// - /// A cancellation token used to exit the main loop. - /// - public void MainLoop(CancellationToken cancellationToken) - { - var platform = PerspexLocator.Current.GetService(); - cancellationToken.Register(platform.Signal); - platform.RunLoop(cancellationToken); - } - - /// - /// Runs continuations pushed on the loop. - /// - public void RunJobs() - { - _jobRunner?.RunJobs(); - } - - /// - /// Invokes a method on the dispatcher thread. - /// - /// The method. - /// The priority with which to invoke the method. - /// A task that can be used to track the method's execution. - public Task InvokeTaskAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) - { - return _jobRunner?.InvokeAsync(action, priority); - } - - /// - /// Post action that will be invoked on main thread - /// - /// The method. - /// The priority with which to invoke the method. - public void InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) - { - _jobRunner?.Post(action, priority); - } - } -} \ No newline at end of file diff --git a/src/Perspex.Base/Threading/DispatcherPriority.cs b/src/Perspex.Base/Threading/DispatcherPriority.cs deleted file mode 100644 index a53d25b4f0..0000000000 --- a/src/Perspex.Base/Threading/DispatcherPriority.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -namespace Perspex.Threading -{ - /// - /// Defines the priorities with which jobs can be invoked on a . - /// - // TODO: These are copied from WPF - many won't apply to Perspex. - public enum DispatcherPriority - { - /// - /// The job will not be processed. - /// - Inactive = 0, - - /// - /// The job will be processed when the system is idle. - /// - SystemIdle = 1, - - /// - /// The job will be processed when the application sis idle. - /// - ApplicationIdle = 2, - - /// - /// The job will be processed after background operations have completed. - /// - ContextIdle = 3, - - /// - /// The job will be processed after other non-idle operations have completed. - /// - Background = 4, - - /// - /// The job will be processed with the same priority as input. - /// - Input = 5, - - /// - /// The job will be processed after layout and render but before input. - /// - Loaded = 6, - - /// - /// The job will be processed with the same priority as render. - /// - Render = 7, - - /// - /// The job will be processed with the same priority as data binding. - /// - DataBind = 8, - - /// - /// The job will be processed with normal priority. - /// - Normal = 9, - - /// - /// The job will be processed before other asynchronous operations. - /// - Send = 10, - } -} diff --git a/src/Perspex.Base/Threading/DispatcherTimer.cs b/src/Perspex.Base/Threading/DispatcherTimer.cs deleted file mode 100644 index 287ce1c124..0000000000 --- a/src/Perspex.Base/Threading/DispatcherTimer.cs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Disposables; -using Perspex.Platform; - -namespace Perspex.Threading -{ - /// - /// A timer that uses a to fire at a specified interval. - /// - public class DispatcherTimer - { - private IDisposable _timer; - - private readonly DispatcherPriority _priority; - - private TimeSpan _interval; - - private readonly Action _raiseTickAction; - - /// - /// Initializes a new instance of the class. - /// - public DispatcherTimer() : this(DispatcherPriority.Normal) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The priority to use. - public DispatcherTimer(DispatcherPriority priority) - { - _priority = priority; - _raiseTickAction = RaiseTick; - } - - /// - /// Initializes a new instance of the class. - /// - /// The interval at which to tick. - /// The priority to use. - /// The event to call when the timer ticks. - public DispatcherTimer(TimeSpan interval, DispatcherPriority priority, EventHandler callback) : this(priority) - { - _priority = priority; - Interval = interval; - Tick += callback; - } - - /// - /// Finalizes an instance of the class. - /// - ~DispatcherTimer() - { - if (_timer != null) - { - Stop(); - } - } - - /// - /// Raised when the timer ticks. - /// - public event EventHandler Tick; - - /// - /// Gets or sets the interval at which the timer ticks. - /// - public TimeSpan Interval - { - get - { - return _interval; - } - - set - { - bool enabled = IsEnabled; - Stop(); - _interval = value; - IsEnabled = enabled; - } - } - - /// - /// Gets or sets a value indicating whether the timer is running. - /// - public bool IsEnabled - { - get - { - return _timer != null; - } - - set - { - if (IsEnabled != value) - { - if (value) - { - Start(); - } - else - { - Stop(); - } - } - } - } - - /// - /// Gets or sets user-defined data associated with the timer. - /// - public object Tag - { - get; - set; - } - - /// - /// Starts a new timer. - /// - /// - /// The method to call on timer tick. If the method returns false, the timer will stop. - /// - /// The interval at which to tick. - /// The priority to use. - /// An used to cancel the timer. - public static IDisposable Run(Func action, TimeSpan interval, DispatcherPriority priority = DispatcherPriority.Normal) - { - var timer = new DispatcherTimer(priority) { Interval = interval }; - - timer.Tick += (s, e) => - { - if (!action()) - { - timer.Stop(); - } - }; - - timer.Start(); - - return Disposable.Create(() => timer.Stop()); - } - - /// - /// Runs a method once, after the specified interval. - /// - /// - /// The method to call after the interval has elapsed. - /// - /// The interval after which to call the method. - /// The priority to use. - /// An used to cancel the timer. - public static IDisposable RunOnce( - Action action, - TimeSpan interval, - DispatcherPriority priority = DispatcherPriority.Normal) - { - var timer = new DispatcherTimer(priority) { Interval = interval }; - - timer.Tick += (s, e) => - { - action(); - timer.Stop(); - }; - - timer.Start(); - - return Disposable.Create(() => timer.Stop()); - } - - /// - /// Starts the timer. - /// - public void Start() - { - if (!IsEnabled) - { - IPlatformThreadingInterface threading = PerspexLocator.Current.GetService(); - - if (threading == null) - { - throw new Exception("Could not start timer: IPlatformThreadingInterface is not registered."); - } - - _timer = threading.StartTimer(Interval, InternalTick); - } - } - - /// - /// Stops the timer. - /// - public void Stop() - { - if (IsEnabled) - { - _timer.Dispose(); - _timer = null; - } - } - - - - /// - /// Raises the event on the dispatcher thread. - /// - private void InternalTick() - { - Dispatcher.UIThread.InvokeAsync(_raiseTickAction, _priority); - } - - /// - /// Raises the event. - /// - private void RaiseTick() - { - Tick?.Invoke(this, EventArgs.Empty); - } - } -} \ No newline at end of file diff --git a/src/Perspex.Base/Threading/JobRunner.cs b/src/Perspex.Base/Threading/JobRunner.cs deleted file mode 100644 index 67d5301224..0000000000 --- a/src/Perspex.Base/Threading/JobRunner.cs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Perspex.Platform; - -namespace Perspex.Threading -{ - /// - /// A main loop in a . - /// - internal class JobRunner - { - private readonly IPlatformThreadingInterface _platform; - private readonly Queue _queue = new Queue(); - - public JobRunner(IPlatformThreadingInterface platform) - { - _platform = platform; - } - - /// - /// Runs continuations pushed on the loop. - /// - public void RunJobs() - { - while (true) - { - Job job; - - lock (_queue) - { - if (_queue.Count == 0) - return; - job = _queue.Dequeue(); - } - - if (job.TaskCompletionSource == null) - { - job.Action(); - } - else - { - try - { - job.Action(); - job.TaskCompletionSource.SetResult(null); - } - catch (Exception e) - { - job.TaskCompletionSource.SetException(e); - } - } - } - } - - /// - /// Invokes a method on the main loop. - /// - /// The method. - /// The priority with which to invoke the method. - /// A task that can be used to track the method's execution. - public Task InvokeAsync(Action action, DispatcherPriority priority) - { - var job = new Job(action, priority, false); - AddJob(job); - return job.TaskCompletionSource.Task; - } - - /// - /// Post action that will be invoked on main thread - /// - /// The method. - /// - /// The priority with which to invoke the method. - internal void Post(Action action, DispatcherPriority priority) - { - // TODO: Respect priority. - AddJob(new Job(action, priority, true)); - } - - private void AddJob(Job job) - { - var needWake = false; - lock (_queue) - { - needWake = _queue.Count == 0; - _queue.Enqueue(job); - } - if (needWake) - _platform.Signal(); - } - - /// - /// A job to run. - /// - private class Job - { - /// - /// Initializes a new instance of the class. - /// - /// The method to call. - /// The job priority. - /// Do not wrap excepption in TaskCompletionSource - public Job(Action action, DispatcherPriority priority, bool throwOnUiThread) - { - Action = action; - Priority = priority; - TaskCompletionSource = throwOnUiThread ? null : new TaskCompletionSource(); - } - - /// - /// Gets the method to call. - /// - public Action Action { get; } - - /// - /// Gets the job priority. - /// - public DispatcherPriority Priority { get; } - - /// - /// Gets the task completion source. - /// - public TaskCompletionSource TaskCompletionSource { get; } - } - } -} diff --git a/src/Perspex.Base/Threading/PerspexScheduler.cs b/src/Perspex.Base/Threading/PerspexScheduler.cs deleted file mode 100644 index 4861600c53..0000000000 --- a/src/Perspex.Base/Threading/PerspexScheduler.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reactive.Concurrency; - -namespace Perspex.Threading -{ - /// - /// A reactive scheduler that uses Perspex's . - /// - public class PerspexScheduler : LocalScheduler - { - /// - /// The instance of the . - /// - public static readonly PerspexScheduler Instance = new PerspexScheduler(); - - /// - /// Initializes a new instance of the class. - /// - private PerspexScheduler() - { - } - - /// - public override IDisposable Schedule(TState state, TimeSpan dueTime, Func action) - { - return DispatcherTimer.Run( - () => - { - action(this, state); - return false; - }, - dueTime); - } - } -} diff --git a/src/Perspex.Base/Threading/PerspexSynchronizationContext.cs b/src/Perspex.Base/Threading/PerspexSynchronizationContext.cs deleted file mode 100644 index cd81496927..0000000000 --- a/src/Perspex.Base/Threading/PerspexSynchronizationContext.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Threading; - -namespace Perspex.Threading -{ - /// - /// SynchronizationContext to be used on main thread - /// - public class PerspexSynchronizationContext : SynchronizationContext - { - /// - /// Controls if SynchronizationContext should be installed in InstallIfNeeded. Used by Designer. - /// - public static bool AutoInstall { get; set; } = true; - - /// - /// Installs synchronization context in current thread - /// - public static void InstallIfNeeded() - { - if (!AutoInstall || Current is PerspexSynchronizationContext) - { - return; - } - - SetSynchronizationContext(new PerspexSynchronizationContext()); - } - - /// - public override void Post(SendOrPostCallback d, object state) - { - Dispatcher.UIThread.InvokeAsync(() => d(state)); - } - - /// - public override void Send(SendOrPostCallback d, object state) - { - if (Dispatcher.UIThread.CheckAccess()) - d(state); - else - Dispatcher.UIThread.InvokeTaskAsync(() => d(state)).Wait(); - } - } -} \ No newline at end of file diff --git a/src/Perspex.Base/Threading/SingleThreadDispatcher.cs b/src/Perspex.Base/Threading/SingleThreadDispatcher.cs deleted file mode 100644 index bcf858db3a..0000000000 --- a/src/Perspex.Base/Threading/SingleThreadDispatcher.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Perspex.Platform; - -namespace Perspex.Threading -{ - public class SingleThreadDispatcher : Dispatcher - { - class ThreadingInterface : IPlatformThreadingInterface - { - private readonly AutoResetEvent _evnt = new AutoResetEvent(false); - private readonly JobRunner _timerJobRunner; - - public ThreadingInterface() - { - _timerJobRunner = new JobRunner(this); - } - - public void RunLoop(CancellationToken cancellationToken) - { - while (!cancellationToken.IsCancellationRequested) - { - _evnt.WaitOne(); - if (cancellationToken.IsCancellationRequested) - return; - Signaled?.Invoke(); - _timerJobRunner.RunJobs(); - } - } - - public IDisposable StartTimer(TimeSpan interval, Action tick) - => PerspexLocator.Current.GetService().StartSystemTimer(interval, - () => _timerJobRunner.Post(tick, DispatcherPriority.Normal)); - - public void Signal() => _evnt.Set(); - //TODO: Actually perform a check - public bool CurrentThreadIsLoopThread => true; - - public event Action Signaled; - } - - public SingleThreadDispatcher() : base(new ThreadingInterface()) - { - } - - public static Dispatcher StartNew(CancellationToken token) - { - var dispatcher = new SingleThreadDispatcher(); - PerspexLocator.Current.GetService().PostThreadPoolItem(() => - { - dispatcher.MainLoop(token); - }); - return dispatcher; - } - } -} diff --git a/src/Perspex.Base/Utilities/IWeakSubscriber.cs b/src/Perspex.Base/Utilities/IWeakSubscriber.cs deleted file mode 100644 index 454c43c17f..0000000000 --- a/src/Perspex.Base/Utilities/IWeakSubscriber.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; - -namespace Perspex.Utilities -{ - /// - /// Defines a listener to a event subscribed vis the . - /// - /// The type of the event arguments. - public interface IWeakSubscriber where T : EventArgs - { - /// - /// Invoked when the subscribed event is raised. - /// - /// The event sender. - /// The event arguments. - void OnEvent(object sender, T e); - } -} diff --git a/src/Perspex.Base/Utilities/MathUtilities.cs b/src/Perspex.Base/Utilities/MathUtilities.cs deleted file mode 100644 index 81837e5de1..0000000000 --- a/src/Perspex.Base/Utilities/MathUtilities.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace Perspex.Utilities -{ - /// - /// Provides math utilities not provided in System.Math. - /// - public static class MathUtilities - { - /// - /// Clamps a value between a minimum and maximum value. - /// - /// The value. - /// The minimum value. - /// The maximum value. - /// The clamped value. - public static double Clamp(double val, double min, double max) - { - if (val < min) - { - return min; - } - else if (val > max) - { - return max; - } - else - { - return val; - } - } - } -} diff --git a/src/Perspex.Base/Utilities/TypeUtilities.cs b/src/Perspex.Base/Utilities/TypeUtilities.cs deleted file mode 100644 index c6d16d56b2..0000000000 --- a/src/Perspex.Base/Utilities/TypeUtilities.cs +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Reflection; - -namespace Perspex.Utilities -{ - /// - /// Provides utilities for working with types at runtime. - /// - public static class TypeUtilities - { - private static readonly Dictionary> Conversions = new Dictionary>() - { - { typeof(decimal), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char) } }, - { typeof(double), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } }, - { typeof(float), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } }, - { typeof(ulong), new List { typeof(byte), typeof(ushort), typeof(uint), typeof(char) } }, - { typeof(long), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(char) } }, - { typeof(uint), new List { typeof(byte), typeof(ushort), typeof(char) } }, - { typeof(int), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(char) } }, - { typeof(ushort), new List { typeof(byte), typeof(char) } }, - { typeof(short), new List { typeof(byte) } } - }; - - /// - /// Returns a value indicating whether null can be assigned to the specified type. - /// - /// The type. - /// True if the type accepts null values; otherwise false. - public static bool AcceptsNull(Type type) - { - var t = type.GetTypeInfo(); - return !t.IsValueType || (t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(Nullable<>))); - } - - /// - /// Try to cast a value to a type, using implicit conversions if possible. - /// - /// The type to cast to. - /// The value to cast. - /// If sucessful, contains the cast value. - /// True if the cast was sucessful, otherwise false. - public static bool TryCast(Type to, object value, out object result) - { - Contract.Requires(to != null); - - if (value == null) - { - result = null; - return AcceptsNull(to); - } - - var from = value.GetType(); - - if (value == PerspexProperty.UnsetValue) - { - result = value; - return true; - } - else if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo())) - { - result = value; - return true; - } - else if (Conversions.ContainsKey(to) && Conversions[to].Contains(from)) - { - result = Convert.ChangeType(value, to); - return true; - } - else - { - var cast = from.GetRuntimeMethods() - .FirstOrDefault(m => m.Name == "op_Implicit" && m.ReturnType == to); - - if (cast != null) - { - result = cast.Invoke(null, new[] { value }); - return true; - } - } - - result = null; - return false; - } - - /// - /// Try to convert a value to a type, using if possible, - /// otherwise using . - /// - /// The type to cast to. - /// The value to cast. - /// The culture to use. - /// If sucessful, contains the cast value. - /// True if the cast was sucessful, otherwise false. - public static bool TryConvert(Type to, object value, CultureInfo culture, out object result) - { - if (value == null) - { - result = null; - return AcceptsNull(to); - } - - var from = value.GetType(); - - if (value == PerspexProperty.UnsetValue) - { - result = value; - return true; - } - - if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo())) - { - result = value; - return true; - } - - if (to == typeof(string)) - { - result = Convert.ToString(value); - return true; - } - - if (to.GetTypeInfo().IsEnum && from == typeof(string)) - { - if (Enum.IsDefined(to, (string)value)) - { - result = Enum.Parse(to, (string)value); - return true; - } - } - - bool containsFrom = Conversions.ContainsKey(from); - bool containsTo = Conversions.ContainsKey(to); - - if ((containsFrom && containsTo) || (from == typeof(string) && containsTo)) - { - try - { - result = Convert.ChangeType(value, to, culture); - return true; - } - catch - { - result = null; - return false; - } - } - - var cast = from.GetRuntimeMethods() - .FirstOrDefault(m => (m.Name == "op_Implicit" || m.Name == "op_Explicit") && m.ReturnType == to); - - if (cast != null) - { - result = cast.Invoke(null, new[] { value }); - return true; - } - - result = null; - return false; - } - - /// - /// Casts a value to a type, returning the default for that type if the value could not be - /// cast. - /// - /// The value to cast. - /// The type to cast to.. - /// A value of . - public static object CastOrDefault(object value, Type type) - { - var typeInfo = type.GetTypeInfo(); - object result; - - if (TypeUtilities.TryCast(type, value, out result)) - { - return result; - } - else if (typeInfo.IsValueType) - { - return Activator.CreateInstance(type); - } - else - { - return null; - } - } - - /// - /// Gets the default value for the specified type. - /// - /// The type. - /// The default value. - public static object Default(Type type) - { - var typeInfo = type.GetTypeInfo(); - - if (typeInfo.IsValueType) - { - return Activator.CreateInstance(type); - } - else - { - return null; - } - } - } -} diff --git a/src/Perspex.Base/Utilities/WeakSubscriptionManager.cs b/src/Perspex.Base/Utilities/WeakSubscriptionManager.cs deleted file mode 100644 index cb4cc061f1..0000000000 --- a/src/Perspex.Base/Utilities/WeakSubscriptionManager.cs +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Perspex.Utilities -{ - /// - /// Manages subscriptions to events using weak listeners. - /// - public static class WeakSubscriptionManager - { - /// - /// Subscribes to an event on an object using a weak subscription. - /// - /// The type of the event arguments. - /// The event source. - /// The name of the event. - /// The subscriber. - public static void Subscribe(object target, string eventName, IWeakSubscriber subscriber) - where T : EventArgs - { - var dic = SubscriptionTypeStorage.Subscribers.GetOrCreateValue(target); - Subscription sub; - - if (!dic.TryGetValue(eventName, out sub)) - { - dic[eventName] = sub = new Subscription(dic, target, eventName); - } - - sub.Add(new WeakReference>(subscriber)); - } - - /// - /// Unsubscribes from an event. - /// - /// The type of the event arguments. - /// The event source. - /// The name of the event. - /// The subscriber. - public static void Unsubscribe(object target, string eventName, IWeakSubscriber subscriber) - where T : EventArgs - { - SubscriptionDic dic; - - if (SubscriptionTypeStorage.Subscribers.TryGetValue(target, out dic)) - { - Subscription sub; - - if (dic.TryGetValue(eventName, out sub)) - { - sub.Remove(subscriber); - } - } - } - - private static class SubscriptionTypeStorage - where T : EventArgs - { - public static readonly ConditionalWeakTable> Subscribers - = new ConditionalWeakTable>(); - } - - private class SubscriptionDic : Dictionary> - where T : EventArgs - { - } - - private static readonly Dictionary> Accessors - = new Dictionary>(); - - private class Subscription where T : EventArgs - { - private readonly EventInfo _info; - private readonly SubscriptionDic _sdic; - private readonly object _target; - private readonly string _eventName; - private readonly Delegate _delegate; - - private WeakReference>[] _data = new WeakReference>[16]; - private int _count = 0; - - public Subscription(SubscriptionDic sdic, object target, string eventName) - { - _sdic = sdic; - _target = target; - _eventName = eventName; - var t = target.GetType(); - Dictionary evDic; - if (!Accessors.TryGetValue(t, out evDic)) - Accessors[t] = evDic = new Dictionary(); - - if (!evDic.TryGetValue(eventName, out _info)) - { - var ev = t.GetRuntimeEvents().FirstOrDefault(x => x.Name == eventName); - - if (ev == null) - { - throw new ArgumentException( - $"The event {eventName} was not found on {target.GetType()}."); - } - - evDic[eventName] = _info = ev; - } - - var del = new Action(OnEvent); - _delegate = del.GetMethodInfo().CreateDelegate(_info.EventHandlerType, del.Target); - _info.AddMethod.Invoke(target, new[] { _delegate }); - } - - void Destroy() - { - _info.RemoveMethod.Invoke(_target, new[] { _delegate }); - _sdic.Remove(_eventName); - } - - public void Add(WeakReference> s) - { - if (_count == _data.Length) - { - //Extend capacity - var ndata = new WeakReference>[_data.Length*2]; - Array.Copy(_data, ndata, _data.Length); - _data = ndata; - } - _data[_count] = s; - _count++; - } - - public void Remove(IWeakSubscriber s) - { - var removed = false; - - for (int c = 0; c < _count; ++c) - { - var reference = _data[c]; - IWeakSubscriber instance; - - if (reference != null && reference.TryGetTarget(out instance) && instance == s) - { - _data[c] = null; - removed = true; - } - } - - if (removed) - { - Compact(); - } - } - - void Compact() - { - int empty = -1; - for (int c = 0; c < _count; c++) - { - var r = _data[c]; - //Mark current index as first empty - if (r == null && empty == -1) - empty = c; - //If current element isn't null and we have an empty one - if (r != null && empty != -1) - { - _data[c] = null; - _data[empty] = r; - empty++; - } - } - if (empty != -1) - _count = empty; - if (_count == 0) - Destroy(); - } - - void OnEvent(object sender, T eventArgs) - { - var needCompact = false; - for(var c=0; c<_count; c++) - { - var r = _data[c]; - IWeakSubscriber sub; - if (r.TryGetTarget(out sub)) - sub.OnEvent(sender, eventArgs); - else - needCompact = true; - } - if (needCompact) - Compact(); - } - } - } -} diff --git a/src/Perspex.Base/Utilities/WeakTimer.cs b/src/Perspex.Base/Utilities/WeakTimer.cs deleted file mode 100644 index f8901a1d74..0000000000 --- a/src/Perspex.Base/Utilities/WeakTimer.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Perspex.Threading; - -namespace Perspex.Utilities -{ - public class WeakTimer - { - public interface IWeakTimerSubscriber - { - bool Tick(); - } - - private readonly WeakReference _subscriber; - private DispatcherTimer _timer; - - public WeakTimer(IWeakTimerSubscriber subscriber) - { - _subscriber = new WeakReference(subscriber); - _timer = new DispatcherTimer(); - - _timer.Tick += delegate { OnTick(); }; - _timer.Start(); - } - - private void OnTick() - { - IWeakTimerSubscriber subscriber; - if (!_subscriber.TryGetTarget(out subscriber) || !subscriber.Tick()) - Stop(); - } - - public TimeSpan Interval - { - get { return _timer.Interval; } - set { _timer.Interval = value; } - } - - public void Start() => _timer.Start(); - - public void Stop() => _timer.Stop(); - - - public static WeakTimer StartWeakTimer(IWeakTimerSubscriber subscriber, TimeSpan interval) - { - var timer = new WeakTimer(subscriber) {Interval = interval}; - timer.Start(); - return timer; - } - - } -} diff --git a/src/Perspex.Controls/Application.cs b/src/Perspex.Controls/Application.cs deleted file mode 100644 index 06f0b6ddeb..0000000000 --- a/src/Perspex.Controls/Application.cs +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Reflection; -using System.Threading; -using Perspex.Controls; -using Perspex.Controls.Platform; -using Perspex.Controls.Templates; -using Perspex.Input; -using Perspex.Input.Platform; -using Perspex.Layout; -using Perspex.Rendering; -using Perspex.Styling; -using Perspex.Threading; - -namespace Perspex -{ - /// - /// Encapsulates a Perspex application. - /// - /// - /// The class encapsulates Perspex application-specific - /// functionality, including: - /// - A global set of . - /// - A global set of . - /// - A . - /// - An . - /// - Loads and initializes rendering and windowing subsystems with - /// and . - /// - Registers services needed by the rest of Perspex in the - /// method. - /// - Tracks the lifetime of the application. - /// - public class Application : IGlobalDataTemplates, IGlobalStyles, IStyleRoot, IApplicationLifecycle - { - static Action _platformInitializationCallback; - - /// - /// The application-global data templates. - /// - private DataTemplates _dataTemplates; - - private readonly Lazy _clipboard = - new Lazy(() => (IClipboard)PerspexLocator.Current.GetService(typeof(IClipboard))); - private readonly Styler _styler = new Styler(); - - /// - /// Initializes a new instance of the class. - /// - public Application() - { - if (Current != null) - { - throw new InvalidOperationException("Cannot create more than one Application instance."); - } - - PerspexLocator.CurrentMutable.BindToSelf(this); - OnExit += OnExiting; - } - - /// - /// Gets the current instance of the class. - /// - /// - /// The current instance of the class. - /// - public static Application Current - { - get { return PerspexLocator.Current.GetService(); } - } - - /// - /// Gets or sets the application's global data templates. - /// - /// - /// The application's global data templates. - /// - public DataTemplates DataTemplates - { - get { return _dataTemplates ?? (_dataTemplates = new DataTemplates()); } - set { _dataTemplates = value; } - } - - /// - /// Gets the application's focus manager. - /// - /// - /// The application's focus manager. - /// - public IFocusManager FocusManager - { - get; - private set; - } - - /// - /// Gets the application's input manager. - /// - /// - /// The application's input manager. - /// - public InputManager InputManager - { - get; - private set; - } - - /// - /// Gets the application clipboard. - /// - public IClipboard Clipboard => _clipboard.Value; - - /// - /// Gets the application's global styles. - /// - /// - /// The application's global styles. - /// - /// - /// Global styles apply to all windows in the application. - /// - public Styles Styles { get; } = new Styles(); - - /// - /// Gets the styling parent of the application, which is null. - /// - IStyleHost IStyleHost.StylingParent => null; - - public static void RegisterPlatformCallback(Action cb) - { - _platformInitializationCallback = cb; - } - - /// - /// Runs the application's main loop until the is closed. - /// - /// The closable to track - public void Run(ICloseable closable) - { - var source = new CancellationTokenSource(); - closable.Closed += OnExiting; - closable.Closed += (s, e) => source.Cancel(); - Dispatcher.UIThread.MainLoop(source.Token); - } - - /// - /// Exits the application - /// - public void Exit() - { - OnExit?.Invoke(this, EventArgs.Empty); - } - - /// - /// Sent when the application is exiting. - /// - public event EventHandler OnExit; - - - /// - /// Called when the application is exiting. - /// - /// - /// - protected virtual void OnExiting(object sender, EventArgs e) - { - - } - - /// - /// Register's the services needed by Perspex. - /// - protected virtual void RegisterServices() - { - PerspexSynchronizationContext.InstallIfNeeded(); - FocusManager = new FocusManager(); - InputManager = new InputManager(); - - PerspexLocator.CurrentMutable - .Bind().ToTransient() - .Bind().ToConstant(this) - .Bind().ToConstant(this) - .Bind().ToConstant(FocusManager) - .Bind().ToConstant(InputManager) - .Bind().ToTransient() - .Bind().ToConstant(_styler) - .Bind().ToSingleton() - .Bind().ToTransient() - .Bind().ToConstant(this); - } - - /// - /// Initializes the rendering and windowing subsystems according to platform. - /// - /// The value of Environment.OSVersion.Platform. - protected void InitializeSubsystems(int platformID) - { - if (_platformInitializationCallback != null) - { - _platformInitializationCallback(); - } - else if (platformID == 4 || platformID == 6) - { - InitializeSubsystem("Perspex.Cairo"); - InitializeSubsystem("Perspex.Gtk"); - } - else - { - InitializeSubsystem("Perspex.Direct2D1"); - InitializeSubsystem("Perspex.Win32"); - } - } - - /// - /// Initializes the rendering or windowing subsystem defined by the specified assemblt. - /// - /// The name of the assembly. - protected static void InitializeSubsystem(string assemblyName) - { - var assembly = Assembly.Load(new AssemblyName(assemblyName)); - var platformClassName = assemblyName.Replace("Perspex.", string.Empty) + "Platform"; - var platformClassFullName = assemblyName + "." + platformClassName; - var platformClass = assembly.GetType(platformClassFullName); - var init = platformClass.GetRuntimeMethod("Initialize", new Type[0]); - init.Invoke(null, null); - } - - internal static void InitializeWin32Subsystem() - { - InitializeSubsystem("Perspex.Direct2D1"); - InitializeSubsystem("Perspex.Win32"); - } - } -} diff --git a/src/Perspex.Controls/Border.cs b/src/Perspex.Controls/Border.cs deleted file mode 100644 index 6c3da91681..0000000000 --- a/src/Perspex.Controls/Border.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using Perspex.Media; - -namespace Perspex.Controls -{ - /// - /// A control which decorates a child with a border and background. - /// - public class Border : Decorator - { - /// - /// Defines the property. - /// - public static readonly StyledProperty BackgroundProperty = - PerspexProperty.Register(nameof(Background)); - - /// - /// Defines the property. - /// - public static readonly StyledProperty BorderBrushProperty = - PerspexProperty.Register(nameof(BorderBrush)); - - /// - /// Defines the property. - /// - public static readonly StyledProperty BorderThicknessProperty = - PerspexProperty.Register(nameof(BorderThickness)); - - /// - /// Defines the property. - /// - public static readonly StyledProperty CornerRadiusProperty = - PerspexProperty.Register(nameof(CornerRadius)); - - /// - /// Initializes static members of the class. - /// - static Border() - { - AffectsRender(BackgroundProperty, BorderBrushProperty); - } - - /// - /// Gets or sets a brush with which to paint the background. - /// - public IBrush Background - { - get { return GetValue(BackgroundProperty); } - set { SetValue(BackgroundProperty, value); } - } - - /// - /// Gets or sets a brush with which to paint the border. - /// - public IBrush BorderBrush - { - get { return GetValue(BorderBrushProperty); } - set { SetValue(BorderBrushProperty, value); } - } - - /// - /// Gets or sets the thickness of the border. - /// - public double BorderThickness - { - get { return GetValue(BorderThicknessProperty); } - set { SetValue(BorderThicknessProperty, value); } - } - - /// - /// Gets or sets the radius of the border rounded corners. - /// - public float CornerRadius - { - get { return GetValue(CornerRadiusProperty); } - set { SetValue(CornerRadiusProperty, value); } - } - - /// - /// Renders the control. - /// - /// The drawing context. - public override void Render(DrawingContext context) - { - var background = Background; - var borderBrush = BorderBrush; - var borderThickness = BorderThickness; - var cornerRadius = CornerRadius; - var rect = new Rect(Bounds.Size).Deflate(BorderThickness); - - if (background != null) - { - context.FillRectangle(background, rect, cornerRadius); - } - - if (borderBrush != null && borderThickness > 0) - { - context.DrawRectangle(new Pen(borderBrush, borderThickness), rect, cornerRadius); - } - } - - /// - /// Measures the control. - /// - /// The available size. - /// The desired size of the control. - protected override Size MeasureOverride(Size availableSize) - { - var child = Child; - var padding = Padding + new Thickness(BorderThickness); - - if (child != null) - { - child.Measure(availableSize.Deflate(padding)); - return child.DesiredSize.Inflate(padding); - } - else - { - return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top); - } - } - - /// - /// Arranges the control's child. - /// - /// The size allocated to the control. - /// The space taken. - protected override Size ArrangeOverride(Size finalSize) - { - var child = Child; - - if (child != null) - { - var padding = Padding + new Thickness(BorderThickness); - child.Arrange(new Rect(finalSize).Deflate(padding)); - } - - return finalSize; - } - } -} \ No newline at end of file diff --git a/src/Perspex.Controls/Button.cs b/src/Perspex.Controls/Button.cs deleted file mode 100644 index 2ced7c4be8..0000000000 --- a/src/Perspex.Controls/Button.cs +++ /dev/null @@ -1,349 +0,0 @@ -// Copyright (c) The Perspex Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Linq; -using System.Windows.Input; -using Perspex.Input; -using Perspex.Interactivity; -using Perspex.Rendering; -using Perspex.VisualTree; - -namespace Perspex.Controls -{ - /// - /// Defines how a reacts to clicks. - /// - public enum ClickMode - { - /// - /// The event is raised when the pointer is released. - /// - Release, - - /// - /// The event is raised when the pointer is pressed. - /// - Press, - } - - /// - /// A button control. - /// - public class Button : ContentControl - { - /// - /// Defines the property. - /// - public static readonly StyledProperty ClickModeProperty = - PerspexProperty.Register(nameof(ClickMode)); - - /// - /// Defines the property. - /// - public static readonly StyledProperty CommandProperty = - PerspexProperty.Register(nameof(Command)); - - /// - /// Defines the property. - /// - public static readonly StyledProperty HotKeyProperty = - HotKeyManager.HotKeyProperty.AddOwner