зеркало из https://github.com/jsuarezruiz/HotUI.git
Skia works on iOS and Mac.
This commit is contained in:
Родитель
5633dbddda
Коммит
05c7d082dc
|
@ -1,6 +0,0 @@
|
||||||
namespace HotUI.Skia.iOS
|
|
||||||
{
|
|
||||||
public class Class1
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
22
HotUI.sln
22
HotUI.sln
|
@ -49,6 +49,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HotUI.Skia", "src\HotUI.Ski
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotUI.WPF", "src\HotUI.WPF\HotUI.WPF.csproj", "{F8BA5DE0-AEC0-4423-B036-5F9157E939D0}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotUI.WPF", "src\HotUI.WPF\HotUI.WPF.csproj", "{F8BA5DE0-AEC0-4423-B036-5F9157E939D0}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Skia", "Skia", "{BDB6346D-E97A-49F4-81D6-664390944360}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotUI.Skia.iOS", "src\HotUI.Skia.iOS\HotUI.Skia.iOS.csproj", "{9ACC68A5-5A5C-409D-A379-D62220A9F49F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HotUI.Skia.Mac", "src\HotUI.Skia.Mac\HotUI.Skia.Mac.csproj", "{00B248D0-382A-4504-A126-76B9C892583E}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -333,6 +339,18 @@ Global
|
||||||
{F8BA5DE0-AEC0-4423-B036-5F9157E939D0}.Release|iPhone.Build.0 = Release|Any CPU
|
{F8BA5DE0-AEC0-4423-B036-5F9157E939D0}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{F8BA5DE0-AEC0-4423-B036-5F9157E939D0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{F8BA5DE0-AEC0-4423-B036-5F9157E939D0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{F8BA5DE0-AEC0-4423-B036-5F9157E939D0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
{F8BA5DE0-AEC0-4423-B036-5F9157E939D0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -355,8 +373,10 @@ Global
|
||||||
{0FC87DE5-B5E5-4846-894B-824497118143} = {C3FDCDB7-0C29-472D-A406-E2F21A4B0EAE}
|
{0FC87DE5-B5E5-4846-894B-824497118143} = {C3FDCDB7-0C29-472D-A406-E2F21A4B0EAE}
|
||||||
{2D337300-B3E9-4A36-8387-76A9A1100C5B} = {AB9AD206-4B1E-4B0C-88A2-5C769314E8A4}
|
{2D337300-B3E9-4A36-8387-76A9A1100C5B} = {AB9AD206-4B1E-4B0C-88A2-5C769314E8A4}
|
||||||
{EDC997D0-2358-416F-A628-5DFD85728060} = {586C3CCB-82A5-47F0-A099-B9A31BB4EA88}
|
{EDC997D0-2358-416F-A628-5DFD85728060} = {586C3CCB-82A5-47F0-A099-B9A31BB4EA88}
|
||||||
{9ACC68A5-5A5C-409D-A379-D62220A9F49F} = {D83B3108-A837-4D1C-B66D-C4B15037BBFB}
|
{9ACC68A5-5A5C-409D-A379-D62220A9F49F} = {BDB6346D-E97A-49F4-81D6-664390944360}
|
||||||
{F8BA5DE0-AEC0-4423-B036-5F9157E939D0} = {AB9AD206-4B1E-4B0C-88A2-5C769314E8A4}
|
{F8BA5DE0-AEC0-4423-B036-5F9157E939D0} = {AB9AD206-4B1E-4B0C-88A2-5C769314E8A4}
|
||||||
|
{BF15264B-D7C7-4F09-B13B-487D60D649BD} = {BDB6346D-E97A-49F4-81D6-664390944360}
|
||||||
|
{00B248D0-382A-4504-A126-76B9C892583E} = {BDB6346D-E97A-49F4-81D6-664390944360}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {0653DB4A-5BBE-4D78-99B2-DB1C82663246}
|
SolutionGuid = {0653DB4A-5BBE-4D78-99B2-DB1C82663246}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HUI/@EntryIndexedValue">HUI</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HUI/@EntryIndexedValue">HUI</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IUI/@EntryIndexedValue">IUI</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IUI/@EntryIndexedValue">IUI</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OS/@EntryIndexedValue">OS</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UWP/@EntryIndexedValue">UWP</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UWP/@EntryIndexedValue">UWP</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=WPF/@EntryIndexedValue">WPF</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=WPF/@EntryIndexedValue">WPF</s:String>
|
||||||
|
@ -8,6 +9,7 @@
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=maxx/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=maxx/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=midx/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=midx/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=midy/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=midy/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Skia/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|
||||||
|
|
||||||
</wpf:ResourceDictionary>
|
</wpf:ResourceDictionary>
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
@ -53,6 +53,7 @@
|
||||||
<Reference Include="System.Numerics.Vectors" />
|
<Reference Include="System.Numerics.Vectors" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SkiaSharp.Views.Forms" Version="1.68.0" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.1" />
|
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.1" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.1" />
|
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0.1" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" />
|
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0.1" />
|
||||||
|
@ -106,5 +107,5 @@
|
||||||
<Name>HotUI.Forms.Sample</Name>
|
<Name>HotUI.Forms.Sample</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -61,8 +61,10 @@
|
||||||
<MtouchArch>ARM64</MtouchArch>
|
<MtouchArch>ARM64</MtouchArch>
|
||||||
<CodesignKey>iPhone Developer</CodesignKey>
|
<CodesignKey>iPhone Developer</CodesignKey>
|
||||||
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
|
||||||
<MtouchNoSymbolStrip></MtouchNoSymbolStrip>
|
<MtouchNoSymbolStrip>
|
||||||
<IOSDebugOverWiFi></IOSDebugOverWiFi>
|
</MtouchNoSymbolStrip>
|
||||||
|
<IOSDebugOverWiFi>
|
||||||
|
</IOSDebugOverWiFi>
|
||||||
<LangVersion>7.2</LangVersion>
|
<LangVersion>7.2</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -126,6 +128,7 @@
|
||||||
<Reference Include="System.Numerics.Vectors" />
|
<Reference Include="System.Numerics.Vectors" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SkiaSharp.Views.Forms" Version="1.68.0" />
|
||||||
<PackageReference Include="Xamarin.Essentials" Version="1.2.0" />
|
<PackageReference Include="Xamarin.Essentials" Version="1.2.0" />
|
||||||
<PackageReference Include="Xamarin.Forms">
|
<PackageReference Include="Xamarin.Forms">
|
||||||
<Version>4.1.0.581479</Version>
|
<Version>4.1.0.581479</Version>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
@ -15,6 +15,7 @@
|
||||||
<LangVersion>7.2</LangVersion>
|
<LangVersion>7.2</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SkiaSharp.Views.Forms" Version="1.68.0" />
|
||||||
<PackageReference Include="Xamarin.Forms" Version="4.1.0.581479" />
|
<PackageReference Include="Xamarin.Forms" Version="4.1.0.581479" />
|
||||||
<PackageReference Include="Xamarin.Essentials" Version="1.2.0" />
|
<PackageReference Include="Xamarin.Essentials" Version="1.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -74,7 +74,7 @@
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</AndroidResource>
|
</AndroidResource>
|
||||||
<AndroidResource Include="Resources\layout\content_main.axml">
|
<AndroidResource Include="Resources\layout\content_main.axml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</AndroidResource>
|
</AndroidResource>
|
||||||
<AndroidResource Include="Resources\values\colors.xml" />
|
<AndroidResource Include="Resources\values\colors.xml" />
|
||||||
<AndroidResource Include="Resources\values\dimens.xml" />
|
<AndroidResource Include="Resources\values\dimens.xml" />
|
||||||
|
@ -101,6 +101,8 @@
|
||||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
||||||
|
<PackageReference Include="SkiaSharp.Views" Version="1.68.0" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.1" />
|
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.1" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="28.0.0.1" />
|
<PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="28.0.0.1" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.1" />
|
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.1" />
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace HotUI.Mac.Sample
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
HotUI.Reload.Init();
|
HotUI.Reload.Init();
|
||||||
#endif
|
#endif
|
||||||
|
HotUI.Skia.Mac.UI.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WillTerminate(NSNotification notification)
|
public override void WillTerminate(NSNotification notification)
|
||||||
|
|
|
@ -109,11 +109,21 @@
|
||||||
<Project>{BCAF5569-30DB-4D44-BF46-DFFE93DDCBD0}</Project>
|
<Project>{BCAF5569-30DB-4D44-BF46-DFFE93DDCBD0}</Project>
|
||||||
<Name>HotUI.Mac</Name>
|
<Name>HotUI.Mac</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\src\HotUI.Skia\HotUI.Skia.csproj">
|
||||||
|
<Project>{BF15264B-D7C7-4F09-B13B-487D60D649BD}</Project>
|
||||||
|
<Name>HotUI.Skia</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\src\HotUI.Skia.Mac\HotUI.Skia.Mac.csproj">
|
||||||
|
<Project>{00B248D0-382A-4504-A126-76B9C892583E}</Project>
|
||||||
|
<Name>HotUI.Skia.Mac</Name>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<BundleResource Include="Resources\turtlerock.jpg" />
|
<BundleResource Include="Resources\turtlerock.jpg" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
||||||
|
<PackageReference Include="SkiaSharp.Views" Version="1.68.0" />
|
||||||
<PackageReference Include="Xamarin.FFImageLoading" Version="2.4.11.982" />
|
<PackageReference Include="Xamarin.FFImageLoading" Version="2.4.11.982" />
|
||||||
<PackageReference Include="HotUI.Reload">
|
<PackageReference Include="HotUI.Reload">
|
||||||
<Version>0.0.6-alpha</Version>
|
<Version>0.0.6-alpha</Version>
|
||||||
|
|
|
@ -11,10 +11,14 @@
|
||||||
<LangVersion>7.2</LangVersion>
|
<LangVersion>7.2</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\HotUI.Skia\HotUI.Skia.csproj" />
|
||||||
<ProjectReference Include="..\..\src\HotUI\HotUI.csproj" />
|
<ProjectReference Include="..\..\src\HotUI\HotUI.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Models\" />
|
<Folder Include="Models\" />
|
||||||
<Folder Include="ApiAudit\" />
|
<Folder Include="ApiAudit\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using HotUI.Samples.Comparisons;
|
using HotUI.Samples.Comparisons;
|
||||||
|
using HotUI.Samples.Skia;
|
||||||
|
|
||||||
namespace HotUI.Samples {
|
namespace HotUI.Samples {
|
||||||
public class MainPage : View {
|
public class MainPage : View {
|
||||||
|
@ -26,6 +27,10 @@ namespace HotUI.Samples {
|
||||||
new MenuItem("TextFieldSample2", ()=> new TextFieldSample2()),
|
new MenuItem("TextFieldSample2", ()=> new TextFieldSample2()),
|
||||||
new MenuItem("TextFieldSample3", ()=> new TextFieldSample3()),
|
new MenuItem("TextFieldSample3", ()=> new TextFieldSample3()),
|
||||||
new MenuItem("TextFieldSample4", ()=> new TextFieldSample4()),
|
new MenuItem("TextFieldSample4", ()=> new TextFieldSample4()),
|
||||||
|
new MenuItem("SkiaSample1 (FingerPaint)", ()=> new SkiaSample1()),
|
||||||
|
new MenuItem("SkiaSample2 (FingerPaint)", ()=> new SkiaSample2()),
|
||||||
|
new MenuItem("SkiaSample3 (BindableFingerPaint)", ()=> new SkiaSample3()),
|
||||||
|
new MenuItem("SkiaSample4 (BindableFingerPaint)", ()=> new SkiaSample4()),
|
||||||
new MenuItem("SwiftUI Tutorial Section 1", ()=> new Section1()),
|
new MenuItem("SwiftUI Tutorial Section 1", ()=> new Section1()),
|
||||||
new MenuItem("SwiftUI Tutorial Section 2", ()=> new Section2()),
|
new MenuItem("SwiftUI Tutorial Section 2", ()=> new Section2()),
|
||||||
new MenuItem("SwiftUI Tutorial Section 3", ()=> new Section3()),
|
new MenuItem("SwiftUI Tutorial Section 3", ()=> new Section3()),
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using HotUI.Skia;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace HotUI.Samples.Skia
|
||||||
|
{
|
||||||
|
public class BindableFingerPaint : SimpleFingerPaint
|
||||||
|
{
|
||||||
|
private readonly List<List<PointF>> _pointsLists = new List<List<PointF>>();
|
||||||
|
private float _strokeWidth = 2;
|
||||||
|
private string _strokeColor = "#00FF00";
|
||||||
|
|
||||||
|
public BindableFingerPaint (
|
||||||
|
Binding<float> strokeSize = null,
|
||||||
|
Binding<string> strokeColor = null)
|
||||||
|
{
|
||||||
|
Bind(strokeSize, nameof(StrokeWidth), value => StrokeWidth = value);
|
||||||
|
Bind(strokeColor, nameof(StrokeColor), value => StrokeColor = value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float StrokeWidth
|
||||||
|
{
|
||||||
|
get => _strokeWidth;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
SetValue(ref _strokeWidth, value);
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StrokeColor
|
||||||
|
{
|
||||||
|
get => _strokeColor;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
SetValue(ref _strokeColor, value);
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw(SKCanvas canvas, RectangleF dirtyRect)
|
||||||
|
{
|
||||||
|
canvas.Clear(SKColors.White);
|
||||||
|
|
||||||
|
var color = new Color(_strokeColor);
|
||||||
|
|
||||||
|
var paint = new SKPaint()
|
||||||
|
{
|
||||||
|
Color = color.ToSKColor(),
|
||||||
|
StrokeWidth = StrokeWidth,
|
||||||
|
Style = SKPaintStyle.Stroke
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var pointsList in _pointsLists)
|
||||||
|
{
|
||||||
|
var path = new SKPath();
|
||||||
|
for (var i = 0; i < pointsList.Count; i++)
|
||||||
|
{
|
||||||
|
var point = pointsList[i];
|
||||||
|
if (i == 0)
|
||||||
|
path.MoveTo(point.X, point.Y);
|
||||||
|
else
|
||||||
|
path.LineTo(point.X, point.Y);
|
||||||
|
}
|
||||||
|
canvas.DrawPath(path, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool StartInteraction(PointF[] points)
|
||||||
|
{
|
||||||
|
var pointsList = new List<PointF> {points[0]};
|
||||||
|
_pointsLists.Add(pointsList);
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DragInteraction(PointF[] points)
|
||||||
|
{
|
||||||
|
var pointsList = _pointsLists[_pointsLists.Count - 1];
|
||||||
|
pointsList.Add(points[0]);
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void EndInteraction(PointF[] points)
|
||||||
|
{
|
||||||
|
var pointsList = _pointsLists[_pointsLists.Count - 1];
|
||||||
|
pointsList.Add(points[0]);
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_pointsLists.Clear();
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using HotUI.Skia;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace HotUI.Samples.Skia
|
||||||
|
{
|
||||||
|
public class SimpleFingerPaint : AbstractControlDelegate
|
||||||
|
{
|
||||||
|
private readonly List<List<PointF>> _pointsLists = new List<List<PointF>>();
|
||||||
|
|
||||||
|
public override void Draw(SKCanvas canvas, RectangleF dirtyRect)
|
||||||
|
{
|
||||||
|
canvas.Clear(SKColors.White);
|
||||||
|
|
||||||
|
var paint = new SKPaint()
|
||||||
|
{
|
||||||
|
Color = SKColors.Blue,
|
||||||
|
StrokeWidth = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var pointsList in _pointsLists)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < pointsList.Count; i++)
|
||||||
|
{
|
||||||
|
var point = pointsList[i];
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
var lastPoint = pointsList[i - 1];
|
||||||
|
canvas.DrawLine(lastPoint.X, lastPoint.Y, point.X, point.Y, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool StartInteraction(PointF[] points)
|
||||||
|
{
|
||||||
|
var pointsList = new List<PointF> {points[0]};
|
||||||
|
_pointsLists.Add(pointsList);
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DragInteraction(PointF[] points)
|
||||||
|
{
|
||||||
|
var pointsList = _pointsLists[_pointsLists.Count - 1];
|
||||||
|
pointsList.Add(points[0]);
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void EndInteraction(PointF[] points)
|
||||||
|
{
|
||||||
|
var pointsList = _pointsLists[_pointsLists.Count - 1];
|
||||||
|
pointsList.Add(points[0]);
|
||||||
|
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_pointsLists.Clear();
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace HotUI.Samples.Skia
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This example how to use use a DrawableControl directly: you give it a control delegate
|
||||||
|
/// in it's constructor.
|
||||||
|
/// </summary>
|
||||||
|
public class SkiaSample1 : View
|
||||||
|
{
|
||||||
|
[Body]
|
||||||
|
View body() => new DrawableControl(new SimpleFingerPaint());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using HotUI.Skia;
|
||||||
|
|
||||||
|
namespace HotUI.Samples.Skia
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This example shows the cleaner way to use a drawable control. A control delegate can be
|
||||||
|
/// implicitly converted into a drawable control, so there is no need to wrap it like in
|
||||||
|
/// SkiaSample1.
|
||||||
|
/// </summary>
|
||||||
|
public class SkiaSample2 : View
|
||||||
|
{
|
||||||
|
[Body]
|
||||||
|
View body() => new SimpleFingerPaint();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using HotUI.Skia;
|
||||||
|
|
||||||
|
namespace HotUI.Samples.Skia
|
||||||
|
{
|
||||||
|
public class SkiaSample3 : View
|
||||||
|
{
|
||||||
|
readonly State<float> _strokeSize = 2;
|
||||||
|
readonly State<string> _strokeColor = "#000000";
|
||||||
|
|
||||||
|
[Body]
|
||||||
|
View body() => new VStack()
|
||||||
|
{
|
||||||
|
new VStack()
|
||||||
|
{
|
||||||
|
new HStack()
|
||||||
|
{
|
||||||
|
new Text("Stroke Width:"),
|
||||||
|
new Slider(_strokeSize, 1, 10, 1)
|
||||||
|
},
|
||||||
|
new HStack()
|
||||||
|
{
|
||||||
|
new Text("Stroke Color:"),
|
||||||
|
new TextField(_strokeColor)
|
||||||
|
},
|
||||||
|
new BindableFingerPaint(
|
||||||
|
strokeSize:_strokeSize,
|
||||||
|
strokeColor:_strokeColor).ToView().Frame(height:400)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using HotUI.Skia;
|
||||||
|
|
||||||
|
namespace HotUI.Samples.Skia
|
||||||
|
{
|
||||||
|
public class SkiaSample4 : View
|
||||||
|
{
|
||||||
|
readonly State<float> _strokeSize = 2;
|
||||||
|
readonly State<string> _strokeColor = "#000000";
|
||||||
|
|
||||||
|
[Body]
|
||||||
|
View body()
|
||||||
|
{
|
||||||
|
var fingerPaint = new BindableFingerPaint(
|
||||||
|
strokeSize: _strokeSize,
|
||||||
|
strokeColor: _strokeColor);
|
||||||
|
|
||||||
|
return new VStack()
|
||||||
|
{
|
||||||
|
new VStack()
|
||||||
|
{
|
||||||
|
new HStack()
|
||||||
|
{
|
||||||
|
new Text("Stroke Width:"),
|
||||||
|
new Slider(_strokeSize, 1, 10, 1)
|
||||||
|
},
|
||||||
|
new HStack()
|
||||||
|
{
|
||||||
|
new Text("Stroke Color:"),
|
||||||
|
new TextField(_strokeColor)
|
||||||
|
},
|
||||||
|
new Button("Reset", () => fingerPaint.Reset()),
|
||||||
|
fingerPaint.ToView().Frame(height: 400)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using CoreLocation;
|
using CoreLocation;
|
||||||
using Foundation;
|
using Foundation;
|
||||||
using HotUI.Samples;
|
using HotUI.Samples;
|
||||||
|
@ -30,7 +29,9 @@ namespace HotUI.iOS.Sample {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
HotUI.Reload.Init();
|
HotUI.Reload.Init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
HotUI.Skia.iOS.UI.Init();
|
||||||
|
|
||||||
"turtlerock.jpg".LoadImage();
|
"turtlerock.jpg".LoadImage();
|
||||||
|
|
||||||
window = new UIWindow {
|
window = new UIWindow {
|
||||||
|
|
|
@ -74,6 +74,12 @@
|
||||||
<Reference Include="System.Numerics.Vectors" />
|
<Reference Include="System.Numerics.Vectors" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SkiaSharp">
|
||||||
|
<Version>1.68.0</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="SkiaSharp.Views">
|
||||||
|
<Version>1.68.0</Version>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Essentials" Version="1.2.0" />
|
<PackageReference Include="Xamarin.Essentials" Version="1.2.0" />
|
||||||
<PackageReference Include="Xamarin.FFImageLoading">
|
<PackageReference Include="Xamarin.FFImageLoading">
|
||||||
<Version>2.4.11.982</Version>
|
<Version>2.4.11.982</Version>
|
||||||
|
@ -141,6 +147,14 @@
|
||||||
<Compile Include="AppDelegate.cs" />
|
<Compile Include="AppDelegate.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\HotUI.Skia.iOS\HotUI.Skia.iOS.csproj">
|
||||||
|
<Project>{9acc68a5-5a5c-409d-a379-d62220a9f49f}</Project>
|
||||||
|
<Name>HotUI.Skia.iOS</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\src\HotUI.Skia\HotUI.Skia.csproj">
|
||||||
|
<Project>{bf15264b-d7c7-4f09-b13b-487d60d649bd}</Project>
|
||||||
|
<Name>HotUI.Skia</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\..\src\HotUI\HotUI.csproj">
|
<ProjectReference Include="..\..\src\HotUI\HotUI.csproj">
|
||||||
<Project>{1817646E-E71E-48CF-80A4-3030EF870D61}</Project>
|
<Project>{1817646E-E71E-48CF-80A4-3030EF870D61}</Project>
|
||||||
<Name>HotUI</Name>
|
<Name>HotUI</Name>
|
||||||
|
|
|
@ -6,6 +6,11 @@ namespace HotUI.Mac
|
||||||
{
|
{
|
||||||
public static class CoreGraphicsExtensions
|
public static class CoreGraphicsExtensions
|
||||||
{
|
{
|
||||||
|
public static PointF ToPointF(this CGPoint size)
|
||||||
|
{
|
||||||
|
return new PointF((float)size.X, (float)size.Y);
|
||||||
|
}
|
||||||
|
|
||||||
public static SizeF ToSizeF(this CGSize size)
|
public static SizeF ToSizeF(this CGSize size)
|
||||||
{
|
{
|
||||||
return new SizeF((float)size.Width, (float)size.Height);
|
return new SizeF((float)size.Width, (float)size.Height);
|
||||||
|
|
|
@ -8,18 +8,27 @@ namespace HotUI.Mac.Handlers
|
||||||
where TVirtualView : View
|
where TVirtualView : View
|
||||||
where TNativeView: NSView
|
where TNativeView: NSView
|
||||||
{
|
{
|
||||||
private readonly PropertyMapper<TVirtualView> _mapper;
|
private PropertyMapper<TVirtualView> _mapper;
|
||||||
private TVirtualView _virtualView;
|
private TVirtualView _virtualView;
|
||||||
private TNativeView _nativeView;
|
private TNativeView _nativeView;
|
||||||
private HUIContainerView _containerView;
|
private HUIContainerView _containerView;
|
||||||
|
|
||||||
public event EventHandler<ViewChangedEventArgs> NativeViewChanged;
|
public event EventHandler<ViewChangedEventArgs> NativeViewChanged;
|
||||||
|
|
||||||
|
protected AbstractControlHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected AbstractControlHandler(PropertyMapper<TVirtualView> mapper)
|
protected AbstractControlHandler(PropertyMapper<TVirtualView> mapper)
|
||||||
{
|
{
|
||||||
_mapper = mapper;
|
_mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void SetMapper(PropertyMapper<TVirtualView> mapper)
|
||||||
|
{
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract TNativeView CreateView();
|
protected abstract TNativeView CreateView();
|
||||||
|
|
||||||
protected abstract void DisposeView(TNativeView nativeView);
|
protected abstract void DisposeView(TNativeView nativeView);
|
||||||
|
@ -60,7 +69,7 @@ namespace HotUI.Mac.Handlers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SizeF Measure(SizeF availableSize)
|
public virtual SizeF Measure(SizeF availableSize)
|
||||||
{
|
{
|
||||||
if (_nativeView is NSControl control)
|
if (_nativeView is NSControl control)
|
||||||
return control.SizeThatFits(availableSize.ToCGSize()).ToSizeF();
|
return control.SizeThatFits(availableSize.ToCGSize()).ToSizeF();
|
||||||
|
@ -90,12 +99,12 @@ namespace HotUI.Mac.Handlers
|
||||||
_virtualView = view as TVirtualView;
|
_virtualView = view as TVirtualView;
|
||||||
if (_nativeView == null)
|
if (_nativeView == null)
|
||||||
_nativeView = CreateView();
|
_nativeView = CreateView();
|
||||||
_mapper.UpdateProperties(this, _virtualView);
|
_mapper?.UpdateProperties(this, _virtualView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void UpdateValue(string property, object value)
|
public virtual void UpdateValue(string property, object value)
|
||||||
{
|
{
|
||||||
_mapper.UpdateProperty(this, _virtualView, property);
|
_mapper?.UpdateProperty(this, _virtualView, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
using HotUI.Mac.Handlers;
|
||||||
|
|
||||||
|
// ReSharper disable ClassNeverInstantiated.Global
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
namespace HotUI.Skia.Mac
|
||||||
|
{
|
||||||
|
public class DrawableControlHandler : AbstractControlHandler<DrawableControl, MacDrawableControl>
|
||||||
|
{
|
||||||
|
protected override MacDrawableControl CreateView()
|
||||||
|
{
|
||||||
|
return new MacDrawableControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DisposeView(MacDrawableControl nativeView)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetView(View view)
|
||||||
|
{
|
||||||
|
base.SetView(view);
|
||||||
|
|
||||||
|
SetMapper(VirtualView.ControlDelegate.Mapper);
|
||||||
|
TypedNativeView.ControlDelegate = VirtualView.ControlDelegate;
|
||||||
|
VirtualView.ControlDelegate.Mapper?.UpdateProperties(this, VirtualView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Remove(View view)
|
||||||
|
{
|
||||||
|
TypedNativeView.ControlDelegate = null;
|
||||||
|
SetMapper(null);
|
||||||
|
|
||||||
|
base.Remove(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SizeF Measure(SizeF availableSize)
|
||||||
|
{
|
||||||
|
return VirtualView?.ControlDelegate?.Measure(availableSize) ?? availableSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{00B248D0-382A-4504-A126-76B9C892583E}</ProjectGuid>
|
||||||
|
<ProjectTypeGuids>{A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<RootNamespace>HotUI.Skia.Mac</RootNamespace>
|
||||||
|
<AssemblyName>HotUI.Skia.Mac</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||||
|
<TargetFrameworkIdentifier>Xamarin.Mac</TargetFrameworkIdentifier>
|
||||||
|
<MonoMacResourcePrefix>Resources</MonoMacResourcePrefix>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<EnableCodeSigning>false</EnableCodeSigning>
|
||||||
|
<CreatePackage>false</CreatePackage>
|
||||||
|
<EnablePackageSigning>false</EnablePackageSigning>
|
||||||
|
<IncludeMonoRuntime>false</IncludeMonoRuntime>
|
||||||
|
<UseSGen>false</UseSGen>
|
||||||
|
<HttpClientHandler>
|
||||||
|
</HttpClientHandler>
|
||||||
|
<LinkMode>
|
||||||
|
</LinkMode>
|
||||||
|
<XamMacArch>
|
||||||
|
</XamMacArch>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release</OutputPath>
|
||||||
|
<DefineConstants>
|
||||||
|
</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<EnableCodeSigning>false</EnableCodeSigning>
|
||||||
|
<CreatePackage>false</CreatePackage>
|
||||||
|
<EnablePackageSigning>false</EnablePackageSigning>
|
||||||
|
<IncludeMonoRuntime>false</IncludeMonoRuntime>
|
||||||
|
<UseSGen>false</UseSGen>
|
||||||
|
<HttpClientHandler>
|
||||||
|
</HttpClientHandler>
|
||||||
|
<LinkMode>
|
||||||
|
</LinkMode>
|
||||||
|
<XamMacArch>
|
||||||
|
</XamMacArch>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="Xamarin.Mac" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="DrawableControlHandler.cs" />
|
||||||
|
<Compile Include="MacDrawableControl.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="UI.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
||||||
|
<PackageReference Include="SkiaSharp.Views" Version="1.68.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\HotUI.Mac\HotUI.Mac.csproj">
|
||||||
|
<Project>{bcaf5569-30db-4d44-bf46-dffe93ddcbd0}</Project>
|
||||||
|
<Name>HotUI.Mac</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\HotUI\HotUI.csproj">
|
||||||
|
<Project>{1817646E-E71E-48CF-80A4-3030EF870D61}</Project>
|
||||||
|
<Name>HotUI</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\HotUI.Skia\HotUI.Skia.csproj">
|
||||||
|
<Project>{BF15264B-D7C7-4F09-B13B-487D60D649BD}</Project>
|
||||||
|
<Name>HotUI.Skia</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Mac\Xamarin.Mac.CSharp.targets" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,124 @@
|
||||||
|
using System;
|
||||||
|
using CoreGraphics;
|
||||||
|
using SkiaSharp.Views.Mac;
|
||||||
|
using HotUI.Mac;
|
||||||
|
using AppKit;
|
||||||
|
|
||||||
|
namespace HotUI.Skia.Mac
|
||||||
|
{
|
||||||
|
public class MacDrawableControl : SKCanvasView, IDrawableControl
|
||||||
|
{
|
||||||
|
private IControlDelegate _controlDelegate;
|
||||||
|
|
||||||
|
public MacDrawableControl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public MacDrawableControl(CGRect frame) : base(frame)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsFlipped => true;
|
||||||
|
|
||||||
|
public IControlDelegate ControlDelegate
|
||||||
|
{
|
||||||
|
get => _controlDelegate;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_controlDelegate != null)
|
||||||
|
{
|
||||||
|
_controlDelegate.Invalidated -= HandleInvalidated;
|
||||||
|
_controlDelegate.RemovedFromView(this);
|
||||||
|
_controlDelegate.NativeDrawableControl = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_controlDelegate = value;
|
||||||
|
|
||||||
|
if (_controlDelegate != null)
|
||||||
|
{
|
||||||
|
_controlDelegate.AddedToView(this, Bounds.ToRectangleF());
|
||||||
|
_controlDelegate.Invalidated += HandleInvalidated;
|
||||||
|
_controlDelegate.NativeDrawableControl = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleInvalidated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleInvalidated()
|
||||||
|
{
|
||||||
|
if (Handle == IntPtr.Zero)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NeedsDisplay = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
|
||||||
|
{
|
||||||
|
if (_controlDelegate == null) return;
|
||||||
|
var canvas = e.Surface.Canvas;
|
||||||
|
|
||||||
|
canvas.Save();
|
||||||
|
var scale = CanvasSize.Width / (float)Bounds.Width;
|
||||||
|
canvas.Scale(scale,-scale);
|
||||||
|
canvas.Translate(0, -(float)Bounds.Height);
|
||||||
|
_controlDelegate.Draw(canvas, Bounds.ToRectangleF());
|
||||||
|
canvas.Restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CGRect Frame
|
||||||
|
{
|
||||||
|
get => base.Frame;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.Frame = value;
|
||||||
|
_controlDelegate?.Resized(Bounds.ToRectangleF());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void MouseDown(NSEvent theEvent)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var windowPoint = theEvent.LocationInWindow;
|
||||||
|
var pointInView = ConvertPointFromView(windowPoint, Window.ContentView);
|
||||||
|
var points = new PointF[] { pointInView.ToPointF() };
|
||||||
|
_controlDelegate?.StartInteraction(points);
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
Logger.Error("An unexpected error occured handling a mouse event within the control.", exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void MouseDragged(NSEvent theEvent)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var windowPoint = theEvent.LocationInWindow;
|
||||||
|
var pointInView = ConvertPointFromView(windowPoint, Window.ContentView);
|
||||||
|
var points = new PointF[] { pointInView.ToPointF() };
|
||||||
|
_controlDelegate?.DragInteraction(points);
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
Logger.Error("An unexpected error occured handling a mouse moved event within the control.", exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void MouseUp(NSEvent theEvent)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var windowPoint = theEvent.LocationInWindow;
|
||||||
|
var pointInView = ConvertPointFromView(windowPoint, Window.ContentView);
|
||||||
|
var points = new PointF[] { pointInView.ToPointF() };
|
||||||
|
_controlDelegate?.EndInteraction(points);
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
Logger.Error("An unexpected error occured handling a mouse up event within the control.", exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
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("HotUI.Skia.Mac")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("")]
|
||||||
|
[assembly: AssemblyCopyright("")]
|
||||||
|
[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.*")]
|
||||||
|
|
||||||
|
// The following attributes are used to specify the signing key for the assembly,
|
||||||
|
// if desired. See the Mono documentation for more information about signing.
|
||||||
|
|
||||||
|
//[assembly: AssemblyDelaySign(false)]
|
||||||
|
//[assembly: AssemblyKeyFile("")]
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace HotUI.Skia.Mac
|
||||||
|
{
|
||||||
|
public static class UI
|
||||||
|
{
|
||||||
|
static bool _hasInitialized;
|
||||||
|
|
||||||
|
public static void Init ()
|
||||||
|
{
|
||||||
|
if (_hasInitialized) return;
|
||||||
|
_hasInitialized = true;
|
||||||
|
|
||||||
|
// Controls
|
||||||
|
Registrar.Handlers.Register<DrawableControl, DrawableControlHandler> ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
using HotUI.iOS.Handlers;
|
||||||
|
|
||||||
|
// ReSharper disable ClassNeverInstantiated.Global
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
namespace HotUI.Skia.iOS
|
||||||
|
{
|
||||||
|
public class DrawableControlHandler : AbstractControlHandler<DrawableControl, iOSDrawableControl>
|
||||||
|
{
|
||||||
|
protected override iOSDrawableControl CreateView()
|
||||||
|
{
|
||||||
|
return new iOSDrawableControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DisposeView(iOSDrawableControl nativeView)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetView(View view)
|
||||||
|
{
|
||||||
|
base.SetView(view);
|
||||||
|
|
||||||
|
SetMapper(VirtualView.ControlDelegate.Mapper);
|
||||||
|
TypedNativeView.ControlDelegate = VirtualView.ControlDelegate;
|
||||||
|
VirtualView.ControlDelegate.Mapper?.UpdateProperties(this, VirtualView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Remove(View view)
|
||||||
|
{
|
||||||
|
TypedNativeView.ControlDelegate = null;
|
||||||
|
SetMapper(null);
|
||||||
|
|
||||||
|
base.Remove(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SizeF Measure(SizeF availableSize)
|
||||||
|
{
|
||||||
|
return VirtualView?.ControlDelegate?.Measure(availableSize) ?? availableSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,12 +40,28 @@
|
||||||
<Folder Include="Resources\" />
|
<Folder Include="Resources\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Class1.cs" />
|
<Compile Include="DrawableControlHandler.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="iOSDrawableControl.cs" />
|
||||||
|
<Compile Include="UI.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
<PackageReference Include="SkiaSharp" Version="1.68.0" />
|
||||||
<PackageReference Include="SkiaSharp.Views" Version="1.68.0" />
|
<PackageReference Include="SkiaSharp.Views" Version="1.68.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\HotUI.iOS\HotUI.iOS.csproj">
|
||||||
|
<Project>{9df36dbf-afe6-438d-b7a6-1b5fb3d1d6d1}</Project>
|
||||||
|
<Name>HotUI.iOS</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\HotUI.Skia\HotUI.Skia.csproj">
|
||||||
|
<Project>{bf15264b-d7c7-4f09-b13b-487d60d649bd}</Project>
|
||||||
|
<Name>HotUI.Skia</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\HotUI\HotUI.csproj">
|
||||||
|
<Project>{1817646e-e71e-48cf-80a4-3030ef870d61}</Project>
|
||||||
|
<Name>HotUI</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace HotUI.Skia.iOS
|
||||||
|
{
|
||||||
|
public static class UI
|
||||||
|
{
|
||||||
|
static bool _hasInitialized;
|
||||||
|
|
||||||
|
public static void Init ()
|
||||||
|
{
|
||||||
|
if (_hasInitialized) return;
|
||||||
|
_hasInitialized = true;
|
||||||
|
|
||||||
|
// Controls
|
||||||
|
Registrar.Handlers.Register<DrawableControl, DrawableControlHandler> ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
using System;
|
||||||
|
using CoreGraphics;
|
||||||
|
using Foundation;
|
||||||
|
using SkiaSharp.Views.iOS;
|
||||||
|
using HotUI.iOS;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace HotUI.Skia.iOS
|
||||||
|
{
|
||||||
|
public class iOSDrawableControl : SKCanvasView, IDrawableControl
|
||||||
|
{
|
||||||
|
private IControlDelegate _controlDelegate;
|
||||||
|
|
||||||
|
public iOSDrawableControl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public iOSDrawableControl(CGRect frame) : base(frame)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public IControlDelegate ControlDelegate
|
||||||
|
{
|
||||||
|
get => _controlDelegate;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_controlDelegate != null)
|
||||||
|
{
|
||||||
|
_controlDelegate.Invalidated -= HandleInvalidated;
|
||||||
|
_controlDelegate.RemovedFromView(this);
|
||||||
|
_controlDelegate.NativeDrawableControl = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_controlDelegate = value;
|
||||||
|
|
||||||
|
if (_controlDelegate != null)
|
||||||
|
{
|
||||||
|
_controlDelegate.AddedToView(this, Bounds.ToRectangleF());
|
||||||
|
_controlDelegate.Invalidated += HandleInvalidated;
|
||||||
|
_controlDelegate.NativeDrawableControl = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleInvalidated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleInvalidated()
|
||||||
|
{
|
||||||
|
if (Handle == IntPtr.Zero)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetNeedsDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
|
||||||
|
{
|
||||||
|
if (_controlDelegate == null) return;
|
||||||
|
var canvas = e.Surface.Canvas;
|
||||||
|
|
||||||
|
canvas.Save();
|
||||||
|
var scale = CanvasSize.Width / (float)Bounds.Width;
|
||||||
|
canvas.Scale(scale,scale);
|
||||||
|
_controlDelegate.Draw(canvas, Bounds.ToRectangleF());
|
||||||
|
canvas.Restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override CGRect Frame
|
||||||
|
{
|
||||||
|
get => base.Frame;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base.Frame = value;
|
||||||
|
_controlDelegate?.Resized(Bounds.ToRectangleF());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TouchesBegan(NSSet touches, UIEvent evt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var viewPoints = this.GetPointsInView(evt);
|
||||||
|
_controlDelegate?.StartInteraction(viewPoints);
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
Logger.Warn("An unexpected error occured handling a touch event within the control.", exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TouchesMoved(NSSet touches, UIEvent evt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var viewPoints = this.GetPointsInView(evt);
|
||||||
|
_controlDelegate?.DragInteraction(viewPoints);
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
Logger.Warn("An unexpected error occured handling a touch moved event within the control.", exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TouchesEnded(NSSet touches, UIEvent evt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var viewPoints = this.GetPointsInView(evt);
|
||||||
|
_controlDelegate?.EndInteraction(viewPoints);
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
Logger.Warn("An unexpected error occured handling a touch ended event within the control.", exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void TouchesCancelled(NSSet touches, UIEvent evt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_controlDelegate?.CancelInteraction();
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
Logger.Warn("An unexpected error occured cancelling the touches within the control.", exc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace HotUI.Skia
|
||||||
|
{
|
||||||
|
public abstract class AbstractControlDelegate : IControlDelegate
|
||||||
|
{
|
||||||
|
public event Action Invalidated;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, BindingDefinition> _bindings = new Dictionary<string, BindingDefinition>();
|
||||||
|
|
||||||
|
protected AbstractControlDelegate()
|
||||||
|
{
|
||||||
|
Mapper = new PropertyMapper<DrawableControl>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractControlDelegate(PropertyMapper<DrawableControl> mapper)
|
||||||
|
{
|
||||||
|
Mapper = mapper ?? new PropertyMapper<DrawableControl>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<string, BindingDefinition> Bindings => _bindings;
|
||||||
|
|
||||||
|
protected void Bind<T>(
|
||||||
|
Binding<T> binding,
|
||||||
|
string propertyName,
|
||||||
|
Action<T> updater)
|
||||||
|
{
|
||||||
|
if (binding == null) return;
|
||||||
|
_bindings[propertyName] = new BindingDefinition(binding, propertyName, v => updater.Invoke((T)v));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyMapper<DrawableControl> Mapper { get; }
|
||||||
|
|
||||||
|
public RectangleF Bounds { get; private set; }
|
||||||
|
|
||||||
|
public void Invalidate()
|
||||||
|
{
|
||||||
|
Invalidated?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void Draw(SKCanvas canvas, RectangleF dirtyRect);
|
||||||
|
|
||||||
|
public virtual bool StartInteraction(PointF[] points)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void DragInteraction(PointF[] points)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void EndInteraction(PointF[] points)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void CancelInteraction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Resized(RectangleF bounds)
|
||||||
|
{
|
||||||
|
Bounds = bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void AddedToView(object view, RectangleF bounds)
|
||||||
|
{
|
||||||
|
Bounds = bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemovedFromView(object view)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawableControl VirtualDrawableControl { get; set; }
|
||||||
|
|
||||||
|
public IDrawableControl NativeDrawableControl { get; set; }
|
||||||
|
|
||||||
|
public virtual SizeF Measure(SizeF availableSize)
|
||||||
|
{
|
||||||
|
return availableSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator View(AbstractControlDelegate controlDelegate)
|
||||||
|
{
|
||||||
|
return new DrawableControl(controlDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SetValue<T> (ref T currentValue, T newValue, [CallerMemberName] string propertyName = "")
|
||||||
|
{
|
||||||
|
VirtualDrawableControl.SetStateValue (ref currentValue, newValue , propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace HotUI.Skia
|
|
||||||
{
|
|
||||||
public class Class1
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace HotUI.Skia
|
||||||
|
{
|
||||||
|
public static class ControlDelegateExtensions
|
||||||
|
{
|
||||||
|
public static HotUI.View ToView(this IControlDelegate controlDelegate)
|
||||||
|
{
|
||||||
|
return new DrawableControl(controlDelegate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using HotUI.Skia;
|
||||||
|
|
||||||
|
namespace HotUI
|
||||||
|
{
|
||||||
|
public class DrawableControl : BoundControl, IDrawableControl
|
||||||
|
{
|
||||||
|
public IControlDelegate ControlDelegate { get; set; }
|
||||||
|
|
||||||
|
public DrawableControl(IControlDelegate controlDelegate)
|
||||||
|
{
|
||||||
|
ControlDelegate = controlDelegate;
|
||||||
|
controlDelegate.VirtualDrawableControl = this;
|
||||||
|
|
||||||
|
if (controlDelegate is AbstractControlDelegate abstractControlDelegate)
|
||||||
|
AddBindings(abstractControlDelegate.Bindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStateValue<T> (ref T currentValue, T newValue, [CallerMemberName] string propertyName = "")
|
||||||
|
{
|
||||||
|
State.SetValue (ref currentValue, newValue, this , propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace HotUI.Skia
|
||||||
|
{
|
||||||
|
public interface IControlDelegate
|
||||||
|
{
|
||||||
|
event Action Invalidated;
|
||||||
|
PropertyMapper<DrawableControl> Mapper { get; }
|
||||||
|
RectangleF Bounds { get; }
|
||||||
|
DrawableControl VirtualDrawableControl { get; set; }
|
||||||
|
IDrawableControl NativeDrawableControl { get; set; }
|
||||||
|
void Invalidate();
|
||||||
|
void Draw(SKCanvas canvas, RectangleF dirtyRect);
|
||||||
|
bool StartInteraction(PointF[] points);
|
||||||
|
void DragInteraction(PointF[] points);
|
||||||
|
void EndInteraction(PointF[] points);
|
||||||
|
void CancelInteraction();
|
||||||
|
void Resized(RectangleF bounds);
|
||||||
|
void AddedToView(object view, RectangleF bounds);
|
||||||
|
void RemovedFromView(object view);
|
||||||
|
SizeF Measure(SizeF availableSize);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
using System;
|
||||||
|
namespace HotUI.Skia
|
||||||
|
{
|
||||||
|
public interface IDrawableControl
|
||||||
|
{
|
||||||
|
IControlDelegate ControlDelegate { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace HotUI.Skia
|
||||||
|
{
|
||||||
|
public static class SkiaGraphicsExtensions
|
||||||
|
{
|
||||||
|
public static SKColor ToSKColor(this Color target)
|
||||||
|
{
|
||||||
|
var r = (byte) (target.R * 255f);
|
||||||
|
var g = (byte) (target.G * 255f);
|
||||||
|
var b = (byte) (target.B * 255f);
|
||||||
|
var a = (byte) (target.A * 255f);
|
||||||
|
return new SKColor(r, g, b, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,11 @@ namespace HotUI.iOS
|
||||||
{
|
{
|
||||||
public static class CoreGraphicsExtensions
|
public static class CoreGraphicsExtensions
|
||||||
{
|
{
|
||||||
|
public static PointF ToPointF(this CGPoint size)
|
||||||
|
{
|
||||||
|
return new PointF((float)size.X, (float)size.Y);
|
||||||
|
}
|
||||||
|
|
||||||
public static SizeF ToSizeF(this CGSize size)
|
public static SizeF ToSizeF(this CGSize size)
|
||||||
{
|
{
|
||||||
return new SizeF((float)size.Width, (float)size.Height);
|
return new SizeF((float)size.Width, (float)size.Height);
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
using CoreGraphics;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace HotUI
|
||||||
|
{
|
||||||
|
public static class UIViewExtensions
|
||||||
|
{
|
||||||
|
public static PointF[] GetPointsInView(this UIView target, UIEvent touchEvent)
|
||||||
|
{
|
||||||
|
var touchSet = touchEvent.TouchesForView(target);
|
||||||
|
if (touchSet == null || touchSet.Count == 0)
|
||||||
|
return new PointF[0];
|
||||||
|
|
||||||
|
var touches = touchSet.ToArray<UITouch>();
|
||||||
|
var points = new PointF[touches.Length];
|
||||||
|
for (int i = 0; i < touches.Length; i++)
|
||||||
|
{
|
||||||
|
var touch = touches[i];
|
||||||
|
var locationInView = touch.LocationInView(target);
|
||||||
|
points[i] = new PointF((float) locationInView.X, (float) locationInView.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,18 +8,28 @@ namespace HotUI.iOS.Handlers
|
||||||
where TVirtualView : View
|
where TVirtualView : View
|
||||||
where TNativeView: UIView
|
where TNativeView: UIView
|
||||||
{
|
{
|
||||||
private readonly PropertyMapper<TVirtualView> _mapper;
|
private PropertyMapper<TVirtualView> _mapper;
|
||||||
private TVirtualView _virtualView;
|
private TVirtualView _virtualView;
|
||||||
private TNativeView _nativeView;
|
private TNativeView _nativeView;
|
||||||
private HUIContainerView _containerView;
|
private HUIContainerView _containerView;
|
||||||
|
|
||||||
public event EventHandler<ViewChangedEventArgs> NativeViewChanged;
|
public event EventHandler<ViewChangedEventArgs> NativeViewChanged;
|
||||||
|
|
||||||
|
protected AbstractControlHandler()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected AbstractControlHandler(PropertyMapper<TVirtualView> mapper)
|
protected AbstractControlHandler(PropertyMapper<TVirtualView> mapper)
|
||||||
{
|
{
|
||||||
_mapper = mapper;
|
_mapper = mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void SetMapper(PropertyMapper<TVirtualView> mapper)
|
||||||
|
{
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract TNativeView CreateView();
|
protected abstract TNativeView CreateView();
|
||||||
|
|
||||||
protected abstract void DisposeView(TNativeView nativeView);
|
protected abstract void DisposeView(TNativeView nativeView);
|
||||||
|
@ -62,7 +72,7 @@ namespace HotUI.iOS.Handlers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SizeF Measure(SizeF availableSize)
|
public virtual SizeF Measure(SizeF availableSize)
|
||||||
{
|
{
|
||||||
return _nativeView.SizeThatFits(availableSize.ToCGSize()).ToSizeF();
|
return _nativeView.SizeThatFits(availableSize.ToCGSize()).ToSizeF();
|
||||||
}
|
}
|
||||||
|
@ -91,12 +101,13 @@ namespace HotUI.iOS.Handlers
|
||||||
_virtualView = view as TVirtualView;
|
_virtualView = view as TVirtualView;
|
||||||
if (_nativeView == null)
|
if (_nativeView == null)
|
||||||
_nativeView = CreateView();
|
_nativeView = CreateView();
|
||||||
_mapper.UpdateProperties(this, _virtualView);
|
|
||||||
|
_mapper?.UpdateProperties(this, _virtualView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void UpdateValue(string property, object value)
|
public virtual void UpdateValue(string property, object value)
|
||||||
{
|
{
|
||||||
_mapper.UpdateProperty(this, _virtualView, property);
|
_mapper?.UpdateProperty(this, _virtualView, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IDisposable Support
|
#region IDisposable Support
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
<Compile Include="Controls\HUITableViewCell.cs" />
|
<Compile Include="Controls\HUITableViewCell.cs" />
|
||||||
<Compile Include="Controls\SizeChangedEventArgs.cs" />
|
<Compile Include="Controls\SizeChangedEventArgs.cs" />
|
||||||
<Compile Include="Extensions\GraphicsExtensions.cs" />
|
<Compile Include="Extensions\GraphicsExtensions.cs" />
|
||||||
|
<Compile Include="Extensions\UIViewExtensions.cs" />
|
||||||
<Compile Include="Handlers\AbstractHandler.cs" />
|
<Compile Include="Handlers\AbstractHandler.cs" />
|
||||||
<Compile Include="Handlers\AbstractLayoutHandler.cs" />
|
<Compile Include="Handlers\AbstractLayoutHandler.cs" />
|
||||||
<Compile Include="Handlers\HStackHandler.cs" />
|
<Compile Include="Handlers\HStackHandler.cs" />
|
||||||
|
|
|
@ -3,25 +3,38 @@ using System.Linq.Expressions;
|
||||||
|
|
||||||
namespace HotUI
|
namespace HotUI
|
||||||
{
|
{
|
||||||
public class Binding<T>
|
public class Binding
|
||||||
{
|
{
|
||||||
public Binding(Func<T> getValue, Action<T> setValue)
|
public Binding(Func<object> getValue, Action<object> setValue)
|
||||||
|
{
|
||||||
|
GetValue = getValue;
|
||||||
|
SetValue = setValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<object> GetValue { get; }
|
||||||
|
public Action<object> SetValue { get; }
|
||||||
|
|
||||||
|
public bool IsValue { get; internal set; }
|
||||||
|
public bool IsFunc { get; internal set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Binding<T> : Binding
|
||||||
|
{
|
||||||
|
public Binding(Func<T> getValue, Action<T> setValue)
|
||||||
|
: base(ToGenericGetter(getValue),ToGenericSetter(setValue))
|
||||||
{
|
{
|
||||||
Get = getValue;
|
Get = getValue;
|
||||||
Set = setValue;
|
Set = setValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Func<T> Get { get; }
|
public Func<T> Get { get; }
|
||||||
public Action<T> Set { get; }
|
public Action<T> Set { get; }
|
||||||
|
|
||||||
public bool IsValue { get; private set; }
|
|
||||||
public bool IsFunc { get; internal set; }
|
|
||||||
|
|
||||||
public static implicit operator Binding<T>(T value)
|
public static implicit operator Binding<T>(T value)
|
||||||
{
|
{
|
||||||
return new Binding<T>(
|
return new Binding<T>(
|
||||||
getValue: () => value,
|
getValue: () => value,
|
||||||
setValue: null) {IsValue = true};
|
setValue: null) { IsValue = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator Binding<T>(Func<T> value)
|
public static implicit operator Binding<T>(Func<T> value)
|
||||||
|
@ -30,6 +43,22 @@ namespace HotUI
|
||||||
getValue: value,
|
getValue: value,
|
||||||
setValue: null) {IsFunc = true};
|
setValue: null) {IsFunc = true};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Func<object> ToGenericGetter(Func<T> getValue)
|
||||||
|
{
|
||||||
|
if (getValue != null)
|
||||||
|
return () => getValue.Invoke();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Action<object> ToGenericSetter(Action<T> setValue)
|
||||||
|
{
|
||||||
|
if (setValue != null)
|
||||||
|
return (v) => setValue.Invoke((T)v);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class BindingExtensions
|
public static class BindingExtensions
|
||||||
|
|
|
@ -199,6 +199,7 @@ namespace HotUI
|
||||||
isBuilding = false;
|
isBuilding = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal void StartProperty()
|
internal void StartProperty()
|
||||||
{
|
{
|
||||||
isBuilding = true;
|
isBuilding = true;
|
||||||
|
|
|
@ -1,58 +1,87 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace HotUI
|
namespace HotUI
|
||||||
{
|
{
|
||||||
public abstract class BoundControl<T> : Control
|
public abstract class BoundControl : Control
|
||||||
{
|
{
|
||||||
private readonly Binding<T> _binding;
|
private readonly Dictionary<string, BindingDefinition> _bindings = new Dictionary<string, BindingDefinition>();
|
||||||
private readonly string _propertyName;
|
|
||||||
|
|
||||||
protected BoundControl (Binding<T> binding, string propertyName) : base(binding?.IsValue ?? false)
|
protected BoundControl (params Binding[] bindings) : base(HasValueBinding(bindings))
|
||||||
{
|
{
|
||||||
_binding = binding;
|
|
||||||
_propertyName = propertyName;
|
|
||||||
|
|
||||||
if (binding?.IsValue ?? false)
|
|
||||||
BoundValue = binding.Get.Invoke();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
T _boundValue;
|
protected void Bind<T>(
|
||||||
protected T BoundValue
|
Binding<T> binding,
|
||||||
|
string propertyName,
|
||||||
|
Action<object> updater)
|
||||||
{
|
{
|
||||||
get => _boundValue;
|
if (binding == null) return;
|
||||||
set => SetValue (ref _boundValue, value, _propertyName);
|
_bindings[propertyName] = new BindingDefinition(binding, propertyName, updater);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AddBindings(IReadOnlyDictionary<string, BindingDefinition> bindings)
|
||||||
|
{
|
||||||
|
if (bindings == null) return;
|
||||||
|
foreach (var entry in bindings)
|
||||||
|
_bindings[entry.Key] = entry.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetValue<T> (ref T currentValue, T newValue, [CallerMemberName] string propertyName = "")
|
protected void SetValue<T> (ref T currentValue, T newValue, [CallerMemberName] string propertyName = "")
|
||||||
{
|
{
|
||||||
State.SetValue<T> (ref currentValue, newValue, this , propertyName);
|
State.SetValue (ref currentValue, newValue, this , propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void WillUpdateView ()
|
protected override void WillUpdateView ()
|
||||||
{
|
{
|
||||||
base.WillUpdateView ();
|
base.WillUpdateView ();
|
||||||
|
|
||||||
if (_binding?.Get != null)
|
|
||||||
{
|
|
||||||
State.StartProperty ();
|
|
||||||
var value = _binding.Get.Invoke ();
|
|
||||||
var props = State.EndProperty ();
|
|
||||||
var propCount = props.Length;
|
|
||||||
if (propCount > 0)
|
|
||||||
State.BindingState.AddViewProperty(props,this,nameof(BoundValue)) ;
|
|
||||||
|
|
||||||
BoundValue = value;
|
if (_bindings.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var entry in _bindings)
|
||||||
|
{
|
||||||
|
var propertyName = entry.Key;
|
||||||
|
var definition = entry.Value;
|
||||||
|
State.StartProperty ();
|
||||||
|
var value = definition.Binding.GetValue.Invoke ();
|
||||||
|
definition.Updater(value);
|
||||||
|
var props = State.EndProperty ();
|
||||||
|
var propCount = props.Length;
|
||||||
|
if (propCount > 0)
|
||||||
|
State.BindingState.AddViewProperty(props, this, propertyName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ViewPropertyChanged(string property, object value)
|
protected override void ViewPropertyChanged(string property, object value)
|
||||||
{
|
{
|
||||||
if(property == nameof(BoundValue))
|
if (_bindings.TryGetValue(property, out var definition))
|
||||||
{
|
definition.Updater(value);
|
||||||
BoundValue = _binding.Get.Invoke();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
base.ViewPropertyChanged(property, value);
|
base.ViewPropertyChanged(property, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool HasValueBinding(Binding[] bindings)
|
||||||
|
{
|
||||||
|
return bindings != null && bindings.Any(b => b.IsValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class BindingDefinition
|
||||||
|
{
|
||||||
|
public BindingDefinition(Binding binding, string propertyName, Action<object> updater)
|
||||||
|
{
|
||||||
|
Binding = binding;
|
||||||
|
PropertyName = propertyName;
|
||||||
|
Updater = updater;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Binding Binding { get; }
|
||||||
|
public string PropertyName { get; }
|
||||||
|
public Action<object> Updater { get; }
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace HotUI
|
||||||
|
{
|
||||||
|
public abstract class BoundControl<T> : Control
|
||||||
|
{
|
||||||
|
private readonly Binding<T> _binding;
|
||||||
|
private readonly string _propertyName;
|
||||||
|
|
||||||
|
protected BoundControl (Binding<T> binding, string propertyName) : base(binding?.IsValue ?? false)
|
||||||
|
{
|
||||||
|
_binding = binding;
|
||||||
|
_propertyName = propertyName;
|
||||||
|
|
||||||
|
if (binding?.IsValue ?? false)
|
||||||
|
BoundValue = binding.Get.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
T _boundValue;
|
||||||
|
protected T BoundValue
|
||||||
|
{
|
||||||
|
get => _boundValue;
|
||||||
|
set => SetValue (ref _boundValue, value, _propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SetValue<T> (ref T currentValue, T newValue, [CallerMemberName] string propertyName = "")
|
||||||
|
{
|
||||||
|
State.SetValue (ref currentValue, newValue, this , propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void WillUpdateView ()
|
||||||
|
{
|
||||||
|
base.WillUpdateView ();
|
||||||
|
|
||||||
|
if (_binding?.Get != null)
|
||||||
|
{
|
||||||
|
State.StartProperty ();
|
||||||
|
var value = _binding.Get.Invoke ();
|
||||||
|
var props = State.EndProperty ();
|
||||||
|
var propCount = props.Length;
|
||||||
|
if (propCount > 0)
|
||||||
|
State.BindingState.AddViewProperty(props,this,nameof(BoundValue)) ;
|
||||||
|
|
||||||
|
BoundValue = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected override void ViewPropertyChanged(string property, object value)
|
||||||
|
{
|
||||||
|
if(property == nameof(BoundValue))
|
||||||
|
{
|
||||||
|
BoundValue = _binding.Get.Invoke();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
base.ViewPropertyChanged(property, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
using System;
|
||||||
|
using HotUI.Services;
|
||||||
|
|
||||||
|
namespace HotUI
|
||||||
|
{
|
||||||
|
public static class Logger
|
||||||
|
{
|
||||||
|
private static ILoggingService _registeredService;
|
||||||
|
|
||||||
|
public static ILoggingService RegisteredService
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_registeredService == null)
|
||||||
|
{
|
||||||
|
_registeredService = ServiceContainer.Resolve<ILoggingService>(true);
|
||||||
|
if (_registeredService == null)
|
||||||
|
{
|
||||||
|
_registeredService = new ConsoleLoggingService();
|
||||||
|
_registeredService.Log(LogType.Warning, "No logging service was registered. Falling back to console logging.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _registeredService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterService(ILoggingService service)
|
||||||
|
{
|
||||||
|
ServiceContainer.Register(service);
|
||||||
|
_registeredService = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Debug(params object[] parameters)
|
||||||
|
{
|
||||||
|
Log(LogType.Debug, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Warn(params object[] parameters)
|
||||||
|
{
|
||||||
|
Log(LogType.Warning, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Error(params object[] parameters)
|
||||||
|
{
|
||||||
|
Log(LogType.Error, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fatal(params object[] parameters)
|
||||||
|
{
|
||||||
|
Log(LogType.Fatal, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Info(params object[] parameters)
|
||||||
|
{
|
||||||
|
Log(LogType.Info, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Log(LogType logType, params object[] parameters)
|
||||||
|
{
|
||||||
|
if (parameters == null || parameters.Length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parameters.Length == 1)
|
||||||
|
{
|
||||||
|
if (parameters[0] is Exception exception)
|
||||||
|
{
|
||||||
|
RegisteredService.Log(logType, exception.Message, exception);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = parameters[0];
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
RegisteredService.Log(logType, value.ToString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var format = parameters[0] != null ? parameters[0].ToString() : "";
|
||||||
|
var message = format;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var args = new object[parameters.Length - 1];
|
||||||
|
Array.Copy(parameters, 1, args, 0, parameters.Length - 1);
|
||||||
|
|
||||||
|
message = string.Format(format, args);
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
RegisteredService.Log(LogType.Info, $"An error occured formatting the logging message: [{format}]", exc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters[parameters.Length - 1] is Exception ex)
|
||||||
|
{
|
||||||
|
RegisteredService.Log(logType, message, ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RegisteredService.Log(logType, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace HotUI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A simple service container implementation, singleton only
|
||||||
|
/// </summary>
|
||||||
|
public static class ServiceContainer
|
||||||
|
{
|
||||||
|
static readonly ConcurrentDictionary<Type, Lazy<object>> services = new ConcurrentDictionary<Type, Lazy<object>>();
|
||||||
|
static readonly Stack<Dictionary<Type, object>> scopedServices = new Stack<Dictionary<Type, object>>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register the specified service with an instance
|
||||||
|
/// </summary>
|
||||||
|
public static void Register<T>(T service)
|
||||||
|
{
|
||||||
|
services[typeof(T)] = new Lazy<object>(() => service);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register the specified service for a class with a default constructor
|
||||||
|
/// </summary>
|
||||||
|
public static void Register<T>() where T : new()
|
||||||
|
{
|
||||||
|
services[typeof(T)] = new Lazy<object>(() => new T(), LazyThreadSafetyMode.ExecutionAndPublication);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register the specified service with a callback to be invoked when requested
|
||||||
|
/// </summary>
|
||||||
|
public static void Register<T>(Func<T> function)
|
||||||
|
{
|
||||||
|
services[typeof(T)] = new Lazy<object>(() => function());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register the specified service with an instance
|
||||||
|
/// </summary>
|
||||||
|
public static void Register(Type type, object service)
|
||||||
|
{
|
||||||
|
services[type] = new Lazy<object>(() => service);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register the specified service with a callback to be invoked when requested
|
||||||
|
/// </summary>
|
||||||
|
public static void Register(Type type, Func<object> function)
|
||||||
|
{
|
||||||
|
services[type] = new Lazy<object>(function, LazyThreadSafetyMode.ExecutionAndPublication);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register the specified service with an instance that is scoped
|
||||||
|
/// </summary>
|
||||||
|
public static void RegisterScoped<T>(T service)
|
||||||
|
{
|
||||||
|
Dictionary<Type, object> scope;
|
||||||
|
if (scopedServices.Count == 0)
|
||||||
|
{
|
||||||
|
scope = new Dictionary<Type, object>();
|
||||||
|
scopedServices.Push(scope);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scope = scopedServices.Peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
scope[typeof(T)] = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resolves the type, throwing an exception if not found
|
||||||
|
/// </summary>
|
||||||
|
public static T Resolve<T>(bool nullIsAcceptable = false)
|
||||||
|
{
|
||||||
|
return (T) Resolve(typeof(T), nullIsAcceptable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resolves the type, throwing an exception if not found
|
||||||
|
/// </summary>
|
||||||
|
public static object Resolve(Type type, bool nullIsAcceptable = false)
|
||||||
|
{
|
||||||
|
//Scoped services
|
||||||
|
if (scopedServices.Count > 0)
|
||||||
|
{
|
||||||
|
var scope = scopedServices.Peek();
|
||||||
|
|
||||||
|
object service;
|
||||||
|
if (scope.TryGetValue(type, out service))
|
||||||
|
{
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Non-scoped services
|
||||||
|
{
|
||||||
|
Lazy<object> service;
|
||||||
|
if (services.TryGetValue(type, out service))
|
||||||
|
{
|
||||||
|
return service.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nullIsAcceptable) return null;
|
||||||
|
|
||||||
|
throw new KeyNotFoundException(string.Format("Service not found for type '{0}'", type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a "scope" which is a way to register a service on a stack to be popped off at a later time
|
||||||
|
/// </summary>
|
||||||
|
public static void AddScope()
|
||||||
|
{
|
||||||
|
scopedServices.Push(new Dictionary<Type, object>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the current "scope" which pops off some local services
|
||||||
|
/// </summary>
|
||||||
|
public static void RemoveScope()
|
||||||
|
{
|
||||||
|
if (scopedServices.Count > 0)
|
||||||
|
scopedServices.Pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mainly for testing, clears the entire container
|
||||||
|
/// </summary>
|
||||||
|
public static void Clear()
|
||||||
|
{
|
||||||
|
services.Clear();
|
||||||
|
scopedServices.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace HotUI.Services
|
||||||
|
{
|
||||||
|
public class ConsoleLoggingService : ILoggingService
|
||||||
|
{
|
||||||
|
public virtual void Log(LogType type, string message)
|
||||||
|
{
|
||||||
|
WriteToConsole(type, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Log(LogType type, string message, Exception exception)
|
||||||
|
{
|
||||||
|
WriteToConsole(type, message + "\n" + GetExceptionDetails(exception));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void WriteToConsole(LogType type, string message)
|
||||||
|
{
|
||||||
|
Console.WriteLine("[{0}] {1}", type, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string GetExceptionDetails(Exception exception)
|
||||||
|
{
|
||||||
|
var writer = new StringWriter();
|
||||||
|
|
||||||
|
writer.Write("Exception: ");
|
||||||
|
writer.WriteLine(exception.GetType());
|
||||||
|
writer.Write("Message: ");
|
||||||
|
writer.WriteLine(exception.Message);
|
||||||
|
if (exception.InnerException != null)
|
||||||
|
{
|
||||||
|
writer.Write("InnerException: ");
|
||||||
|
writer.WriteLine(exception.InnerException);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Write("StackTrace: ");
|
||||||
|
writer.WriteLine(exception.StackTrace);
|
||||||
|
|
||||||
|
return writer.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace HotUI.Services
|
||||||
|
{
|
||||||
|
public enum LogType
|
||||||
|
{
|
||||||
|
Debug,
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
Fatal
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ILoggingService
|
||||||
|
{
|
||||||
|
void Log(LogType logType, string message);
|
||||||
|
void Log(LogType logType, string message, Exception exception);
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче