Add Tizen backend renderer
authorKangho Hur <kangho.hur@samsung.com>
Fri, 16 Dec 2016 02:00:07 +0000 (11:00 +0900)
committerKangho Hur <kangho.hur@samsung.com>
Fri, 24 Mar 2017 04:18:57 +0000 (13:18 +0900)
- Xamarin.Forms.Platform.Tizen has been added
- Xamarin.Forms.Maps.Tizen has been added
- RPM build spec has been added

Change-Id: I0021e0f040d97345affc87512ee0f6ce437f4e6d

111 files changed:
.nuspec/Xamarin.Forms.Maps.Tizen.nuspec [new file with mode: 0644]
.nuspec/Xamarin.Forms.Platform.Tizen.nuspec [new file with mode: 0644]
Xamarin.Forms.Core/Properties/AssemblyInfo.cs
Xamarin.Forms.Maps.Tizen/FormsMaps.cs [new file with mode: 0755]
Xamarin.Forms.Maps.Tizen/GeocoderBackend.cs [new file with mode: 0644]
Xamarin.Forms.Maps.Tizen/MapControl.cs [new file with mode: 0755]
Xamarin.Forms.Maps.Tizen/MapRenderer.cs [new file with mode: 0755]
Xamarin.Forms.Maps.Tizen/Properties/AssemblyInfo.cs [new file with mode: 0644]
Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.csproj [new file with mode: 0644]
Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.project.json [new file with mode: 0755]
Xamarin.Forms.Maps.Tizen/packages.config [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Cells/CellRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Cells/EntryCellRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Cells/ImageCellRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Cells/SwitchCellRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Cells/TextCellRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Cells/ViewCellRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Deserializer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/ElementChangedEventArgs.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/EvasObjectWrapper.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/ExportCellAttribute.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/ExportImageSourceHandlerAttribute.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/ExportRendererAttribute.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Extensions/ColorExtensions.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Extensions/KeyboardExtensions.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Extensions/LayoutExtensions.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Extensions/ScrollToPositionExtensions.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Extensions/TextAlignmentExtensions.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Forms.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/FormsApplication.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/GestureHandler.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Log/ConsoleLogger.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Log/DlogLogger.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Log/ILogger.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Log/Log.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Log/XamarinLogListener.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/Box.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/Button.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/Canvas.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/ContentPage.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/DateChangedEventArgs.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/DatePicker.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/DateTimePickerDialog.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/Dialog.cs [new file with mode: 0755]
Xamarin.Forms.Platform.Tizen/Native/DisplayOrientations.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/Entry.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/FormattedString.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/IContainable.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/IMeasurable.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/ITextable.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/Image.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/Keyboard.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/Label.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/LayoutEventArgs.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/LineBreakMode.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/ListView.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/MasterDetailPage.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/ObservableCollection.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/SearchBar.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/Span.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/TableView.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/TextAlignment.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/TextHelper.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/TimePicker.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/Window.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Platform.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/PlatformEffect.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/ActivityIndicatorRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/BoxViewRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/ButtonRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/CarouselPageRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/ContentPageRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/DatePickerRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/EditorRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/EntryRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/EvasObjectWrapperRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/FrameRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/IVisualElementRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/ImageRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/LabelRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/LayoutRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/ListViewRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailPageRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/NavigationPageRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/PickerRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/ProgressBarRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/ScrollViewRenderer.cs [new file with mode: 0755]
Xamarin.Forms.Platform.Tizen/Renderers/SearchBarRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/SliderRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/StepperRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/SwitchRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/TableViewRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/TimePickerRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/ViewRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Renderers/VisualElementRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/ResourcePath.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/ResourcesProvider.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/TizenIsolatedStorageFile.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/TizenPlatformServices.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/TizenTitleBarVisibility.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/ViewInitializedEventArgs.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/VisualElementChangedEventArgs.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/VisualElementRendererFlags.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Xamarin.Forms.Platform.Tizen.csproj [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Xamarin.Forms.Platform.Tizen.project.json [new file with mode: 0644]
Xamarin.Forms.Tizen.sln [new file with mode: 0644]
packaging/custom-find-requires [new file with mode: 0755]
packaging/xamarin-forms-tizen.manifest [new file with mode: 0755]
packaging/xamarin-forms-tizen.spec [new file with mode: 0644]

diff --git a/.nuspec/Xamarin.Forms.Maps.Tizen.nuspec b/.nuspec/Xamarin.Forms.Maps.Tizen.nuspec
new file mode 100644 (file)
index 0000000..b951d4a
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<package>
+  <metadata>
+    <id>Xamarin.Forms.Maps.Tizen</id>
+    <version>$version$</version>
+    <authors>Tizen Developers</authors>
+    <description>Xamarin.Forms.Maps Renderer for Tizen.Net</description>
+    <dependencies>
+      <dependency id="Xamarin.Forms.Maps" version="2.3.3.0" />
+    </dependencies>
+  </metadata>
+  <files>
+    <file src="../Xamarin.Forms.Maps.Tizen/bin/$Configuration$/Xamarin.Forms.Maps.Tizen.dll" target="lib/netcoreapp1.0"/>
+    <file src="../Xamarin.Forms.Maps.Tizen/bin/$Configuration$/Xamarin.Forms.Maps.Tizen.*pdb" target="lib/netcoreapp1.0"/>
+  </files>
+</package>
diff --git a/.nuspec/Xamarin.Forms.Platform.Tizen.nuspec b/.nuspec/Xamarin.Forms.Platform.Tizen.nuspec
new file mode 100644 (file)
index 0000000..3bcf80b
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<package>
+       <metadata>
+               <id>Xamarin.Forms.Platform.Tizen</id>
+               <version>$version$</version>
+               <authors>tizen</authors>
+               <tags>xamarin forms xamarin.forms tizen</tags>
+               <projectUrl>https://www.tizen.org/</projectUrl>
+               <iconUrl>https://developer.tizen.org/sites/default/files/images/tizen-pinwheel-on-light-rgb_64_64.png</iconUrl>
+               <requireLicenseAcceptance>false</requireLicenseAcceptance>
+               <description>Xamarin Forms Renderer to build native UIs for Tizen.Net</description>
+               <copyright>Copyright 2016</copyright>
+               <dependencies>
+                       <dependency id="Xamarin.Forms" version="2.3.3.175" />
+               </dependencies>
+       </metadata>
+       <files>
+               <file src="../Xamarin.Forms.Platform.Tizen/bin/$Configuration$/Xamarin.Forms.Platform.Tizen.dll" target="lib/netcoreapp1.0"/>
+               <file src="../Xamarin.Forms.Platform.Tizen/bin/$Configuration$/Xamarin.Forms.Platform.Tizen.*pdb" target="lib/netcoreapp1.0"/>
+       </files>
+</package>
index 8f50765..7ba35cd 100644 (file)
@@ -29,6 +29,7 @@ using Xamarin.Forms.Internals;
 [assembly: InternalsVisibleTo("Xamarin.Forms.Platform.WinRT.Phone")]
 [assembly: InternalsVisibleTo("Xamarin.Forms.Platform.WP8")]
 [assembly: InternalsVisibleTo("Xamarin.Forms.Platform.macOS")]
+[assembly: InternalsVisibleTo("Xamarin.Forms.Platform.Tizen")]
 [assembly: InternalsVisibleTo("iOSUnitTests")]
 [assembly: InternalsVisibleTo("Xamarin.Forms.Controls")]
 [assembly: InternalsVisibleTo("Xamarin.Forms.Core.Design")]
@@ -40,6 +41,7 @@ using Xamarin.Forms.Internals;
 [assembly: InternalsVisibleTo("Xamarin.Forms.Maps.iOS")]
 [assembly: InternalsVisibleTo("Xamarin.Forms.Maps.iOS.Classic")]
 [assembly: InternalsVisibleTo("Xamarin.Forms.Maps.Android")]
+[assembly: InternalsVisibleTo("Xamarin.Forms.Maps.Tizen")]
 [assembly: InternalsVisibleTo("Xamarin.Forms.Xaml.UnitTests")]
 [assembly: InternalsVisibleTo("Xamarin.Forms.UITests")]
 //[assembly:InternalsVisibleTo("Xamarin.Forms.Core.UITests")]
@@ -59,4 +61,4 @@ using Xamarin.Forms.Internals;
 [assembly: InternalsVisibleTo("Xamarin.Forms.CarouselView")]
 [assembly: Preserve]
 
-[assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms", "Xamarin.Forms")]
\ No newline at end of file
+[assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms", "Xamarin.Forms")]
diff --git a/Xamarin.Forms.Maps.Tizen/FormsMaps.cs b/Xamarin.Forms.Maps.Tizen/FormsMaps.cs
new file mode 100755 (executable)
index 0000000..b41b50d
--- /dev/null
@@ -0,0 +1,19 @@
+using Xamarin.Forms.Maps.Tizen;
+
+namespace Xamarin
+{
+    public static class FormsMaps
+    {
+        public static bool IsInitialized { get; private set; }
+
+        public static void Init()
+        {
+            if (IsInitialized)
+                return;
+
+            IsInitialized = true;
+
+            GeocoderBackend.Register();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Maps.Tizen/GeocoderBackend.cs b/Xamarin.Forms.Maps.Tizen/GeocoderBackend.cs
new file mode 100644 (file)
index 0000000..a18990d
--- /dev/null
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using System;
+
+namespace Xamarin.Forms.Maps.Tizen
+{
+    public class Position {};
+
+    internal class GeocoderBackend
+    {
+        public static void Register()
+        {
+        }
+
+        public static async Task<IEnumerable<Position>> GetPositionsForAddressAsync(string address)
+        {
+            return new Position[]{};
+        }
+
+        public static async Task<IEnumerable<string>> GetAddressesForPositionAsync(Position position)
+        {
+            return new String[]{"Not supported"};
+        }
+    }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Maps.Tizen/MapControl.cs b/Xamarin.Forms.Maps.Tizen/MapControl.cs
new file mode 100755 (executable)
index 0000000..a10bb80
--- /dev/null
@@ -0,0 +1,14 @@
+using TLabel = Xamarin.Forms.Platform.Tizen.Native.Label;
+
+namespace Xamarin.Forms.Maps.Tizen
+{
+    public class MapControl : TLabel
+    {
+        public MapControl(ElmSharp.EvasObject parent) : base(parent)
+        {
+            Text = "Can not supported Maps";
+            TextColor = ElmSharp.Color.Red;
+        }
+    }
+}
+
diff --git a/Xamarin.Forms.Maps.Tizen/MapRenderer.cs b/Xamarin.Forms.Maps.Tizen/MapRenderer.cs
new file mode 100755 (executable)
index 0000000..b7278dc
--- /dev/null
@@ -0,0 +1,47 @@
+using Xamarin.Forms.Platform.Tizen;
+using TForms = Xamarin.Forms.Platform.Tizen.Forms;
+
+namespace Xamarin.Forms.Maps.Tizen
+{
+    public class MapRenderer : ViewRenderer<Map, MapControl>
+    {
+        public MapRenderer()
+        {
+            RegisterPropertyHandler(Map.MapTypeProperty, UpdateMapType);
+            RegisterPropertyHandler(Map.IsShowingUserProperty, UpdateIsShowingUser);
+            RegisterPropertyHandler(Map.HasScrollEnabledProperty, UpdateHasScrollEnabled);
+            RegisterPropertyHandler(Map.HasZoomEnabledProperty, UpdateHasZoomEnabled);
+        }
+
+        protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
+        {
+            base.OnElementChanged(e);
+
+            if (Control == null)
+            {
+                var mapControl = new MapControl(TForms.Context.MainWindow);
+                SetNativeControl(mapControl);
+            }
+        }
+
+        void UpdateMapType()
+        {
+            // TODO
+        }
+
+        void UpdateIsShowingUser()
+        {
+            // TODO
+        }
+
+        void UpdateHasScrollEnabled()
+        {
+            // TODO
+        }
+
+        void UpdateHasZoomEnabled()
+        {
+            // TODO
+        }
+    }
+}
diff --git a/Xamarin.Forms.Maps.Tizen/Properties/AssemblyInfo.cs b/Xamarin.Forms.Maps.Tizen/Properties/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..ec69a71
--- /dev/null
@@ -0,0 +1,32 @@
+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.
+using Xamarin.Forms;
+using Xamarin.Forms.Maps;
+using Xamarin.Forms.Maps.Tizen;
+using Xamarin.Forms.Platform.Tizen;
+
+[assembly: AssemblyTitle("Xamarin.Forms.Maps.Tizen")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("k.lipner")]
+[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.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: ExportRenderer(typeof (Map), typeof (MapRenderer))]
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.csproj b/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.csproj
new file mode 100644 (file)
index 0000000..9b16376
--- /dev/null
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{D29D5750-9A39-4E92-A19E-62567D660B7D}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Xamarin.Forms.Maps.Tizen</RootNamespace>
+    <AssemblyName>Xamarin.Forms.Maps.Tizen</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup>
+    <TargetFrameworkIdentifier>.NETStandard</TargetFrameworkIdentifier>
+    <TargetFrameworkVersion>v1.6</TargetFrameworkVersion>
+    <NuGetTargetMoniker>.NETStandard,Version=v1.6</NuGetTargetMoniker>
+    <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
+    <NoStdLib>true</NoStdLib>
+    <NoWarn>$(NoWarn);1701;1702</NoWarn>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="FormsMaps.cs" />
+    <Compile Include="GeocoderBackend.cs" />
+    <Compile Include="MapRenderer.cs" />
+    <Compile Include="MapControl.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Xamarin.Forms.Maps.Tizen.project.json" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <ItemGroup>
+    <ProjectReference Include="..\Xamarin.Forms.Maps\Xamarin.Forms.Maps.csproj">
+      <Project>{7D13BAC2-C6A4-416A-B07E-C169B199E52B}</Project>
+      <Name>Xamarin.Forms.Maps</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Xamarin.Forms.Core\Xamarin.Forms.Core.csproj">
+      <Project>{57B8B73D-C3B5-4C42-869E-7B2F17D354AC}</Project>
+      <Name>Xamarin.Forms.Core</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Xamarin.Forms.Platform.Tizen\Xamarin.Forms.Platform.Tizen.csproj">
+      <Project>{227D2CC5-26A1-4CE7-AE25-1B18AF625B9C}</Project>
+      <Name>Xamarin.Forms.Platform.Tizen</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <PropertyGroup>
+    <!-- https://github.com/dotnet/corefxlab/tree/master/samples/NetCoreSample and
+       https://docs.microsoft.com/en-us/dotnet/articles/core/tutorials/target-dotnetcore-with-msbuild
+    -->
+    <!-- We don't use any of MSBuild's resolution logic for resolving the framework, so just set these two
+       properties to any folder that exists to skip the GetReferenceAssemblyPaths task (not target) and
+       to prevent it from outputting a warning (MSB3644).
+    -->
+    <_TargetFrameworkDirectories>$(MSBuildThisFileDirectory)</_TargetFrameworkDirectories>
+    <_FullFrameworkReferenceAssemblyPaths>$(MSBuildThisFileDirectory)</_FullFrameworkReferenceAssemblyPaths>
+    <AutoUnifyAssemblyReferences>true</AutoUnifyAssemblyReferences>
+  </PropertyGroup>
+</Project>
\ No newline at end of file
diff --git a/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.project.json b/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.project.json
new file mode 100755 (executable)
index 0000000..f4511fe
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "dependencies": {
+    "ElmSharp": "1.1.0-*",
+    "NETStandard.Library": "1.6.0",
+    "Tizen.Applications": "1.0.2"
+  },
+  "frameworks": {
+    "netstandard1.6": {
+      "imports": "portable-net45+win8+wpa81+wp8"
+    }
+  }
+}
diff --git a/Xamarin.Forms.Maps.Tizen/packages.config b/Xamarin.Forms.Maps.Tizen/packages.config
new file mode 100644 (file)
index 0000000..433f1b9
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="ElmSharp" version="1.0.3" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Tizen/Cells/CellRenderer.cs b/Xamarin.Forms.Platform.Tizen/Cells/CellRenderer.cs
new file mode 100644 (file)
index 0000000..1cda74c
--- /dev/null
@@ -0,0 +1,142 @@
+using ElmSharp;
+using System.Collections.Generic;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public abstract class CellRenderer : IRegisterable
+       {
+               const string _heightProperty = "Height";
+               protected static readonly EColor s_defaultTextColor = EColor.Black;
+               protected static readonly EColor s_defaultBackgroundColor = EColor.White;
+               readonly Dictionary<Cell, Dictionary<string, EvasObject>> _realizedNativeViews = new Dictionary<Cell, Dictionary<string, EvasObject>>();
+
+               protected CellRenderer(string style)
+               {
+                       Class = new GenItemClass(style)
+                       {
+                               GetTextHandler = GetText,
+                               GetContentHandler = GetContent,
+                               DeleteHandler = ItemDeleted,
+                       };
+               }
+
+               public GenItemClass Class
+               {
+                       get;
+                       private set;
+               }
+
+               protected virtual bool OnCellPropertyChanged(Cell cell, string property, Dictionary<string, EvasObject> realizedView)
+               {
+                       if (property == _heightProperty)
+                       {
+                               return true;
+                       }
+                       return false;
+               }
+
+               protected virtual Span OnGetText(Cell cell, string part)
+               {
+                       return null;
+               }
+               protected virtual EvasObject OnGetContent(Cell cell, string part)
+               {
+                       return null;
+               }
+               protected virtual void OnDeleted(Cell cell)
+               {
+               }
+
+               protected virtual void OnUnrealizedCell(Cell cell)
+               {
+               }
+
+               protected int FindCellContentHeight(Cell cell)
+               {
+                       ViewCell viewCell = cell as ViewCell;
+                       if (viewCell != null)
+                       {
+                               var parentWidth = (cell.Parent as VisualElement).Width;
+                               var view = viewCell.View;
+                               return (int)view.Measure(parentWidth, double.PositiveInfinity).Request.Height;
+                       }
+                       else
+                               return -1;
+               }
+
+               static Native.Span ToNative(Span span)
+               {
+                       var nativeSpan = new Native.Span();
+                       nativeSpan.Text = span.Text;
+                       nativeSpan.ForegroundColor = span.ForegroundColor.IsDefault ? s_defaultTextColor : span.ForegroundColor.ToNative();
+                       nativeSpan.FontAttributes = span.FontAttributes;
+                       nativeSpan.BackgroundColor = span.BackgroundColor.IsDefault ? s_defaultBackgroundColor : span.BackgroundColor.ToNative();
+                       nativeSpan.FontSize = span.FontSize;
+                       nativeSpan.FontFamily = span.FontFamily;
+                       return nativeSpan;
+               }
+
+               internal void SendCellPropertyChanged(Cell cell, GenListItem item, string property)
+               {
+                       Dictionary<string, EvasObject> realizedView = null;
+                       _realizedNativeViews.TryGetValue(cell, out realizedView);
+
+                       // just to prevent null reference exception in OnCellPropertyChanged
+                       realizedView = realizedView ?? new Dictionary<string, EvasObject>();
+
+                       if (property == Cell.IsEnabledProperty.PropertyName)
+                       {
+                               item.IsEnabled = cell.IsEnabled;
+                       }
+                       // if true was returned, item was updated
+                       // if it's possible to update the cell property without Update(), return false
+                       else if (OnCellPropertyChanged(cell, property, realizedView))
+                       {
+                               item.Update();
+                       }
+               }
+
+               internal void SendUnrealizedCell(Cell cell)
+               {
+                       _realizedNativeViews.Remove(cell);
+                       OnUnrealizedCell(cell);
+               }
+
+               string GetText(object data, string part)
+               {
+                       var span = OnGetText((data as Native.ListView.ItemContext).Cell, part);
+                       return span != null ? ToNative(span).GetDecoratedText() : null;
+               }
+
+               EvasObject GetContent(object data, string part)
+               {
+                       var cell = (data as Native.ListView.ItemContext).Cell;
+                       EvasObject nativeView = OnGetContent(cell, part);
+                       if (part != null && nativeView != null)
+                       {
+                               Dictionary<string, EvasObject> realizedView = null;
+                               _realizedNativeViews.TryGetValue(cell, out realizedView);
+                               if (realizedView == null)
+                               {
+                                       realizedView = new Dictionary<string, EvasObject>();
+                                       _realizedNativeViews[cell] = realizedView;
+                               }
+                               realizedView[part] = nativeView;
+
+                               nativeView.Deleted += (sender, e) =>
+                               {
+                                       realizedView.Remove(part);
+                               };
+                       }
+                       return nativeView;
+               }
+
+               void ItemDeleted(object data)
+               {
+                       var cell = (data as Native.ListView.ItemContext).Cell;
+                       _realizedNativeViews.Remove(cell);
+                       OnDeleted(cell);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Cells/EntryCellRenderer.cs b/Xamarin.Forms.Platform.Tizen/Cells/EntryCellRenderer.cs
new file mode 100644 (file)
index 0000000..c07985f
--- /dev/null
@@ -0,0 +1,163 @@
+using ElmSharp;
+using EColor = ElmSharp.Color;
+using EBox = ElmSharp.Box;
+using System.Collections.Generic;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class EntryCellRenderer : ViewCellRenderer
+       {
+               const int _defaultHeight = 120;
+               readonly Dictionary<EvasObject, NativeEntryComponent> _realizedComponent = new Dictionary<EvasObject, NativeEntryComponent>();
+
+               public EntryCellRenderer()
+               {
+               }
+
+               protected override EvasObject OnGetContent(Cell cell, string part)
+               {
+                       if (part == MainContentPart)
+                       {
+                               var entryCell = cell as EntryCell;
+                               int height = (int)entryCell.RenderHeight;
+                               height = height <= 0 ? FindCellContentHeight(entryCell) : height;
+                               height = height <= 0 ? _defaultHeight : height;
+
+                               // TODO
+                               // Need to use Forms.Core element instead of using Elmsharp.
+                               // if we use Forms element, easily binding data to view elements
+                               var box = new EBox(Forms.Context.MainWindow)
+                               {
+                                       IsHorizontal = true,
+                                       MinimumHeight = height,
+                               };
+                               box.SetAlignment(-1.0, -1.0);  // fill
+                               box.SetWeight(1.0, 1.0);  // expand
+
+                               var label = new Native.Label(box)
+                               {
+                                       Text = entryCell.Label,
+                                       TextColor = GetLabelColor(entryCell),
+                               };
+                               label.SetAlignment(0.0, 0.5);
+                               label.SetWeight(0.0, 1.0);
+
+                               var entry = new Native.Entry(box)
+                               {
+                                       IsSingleLine = true,
+                                       Text = entryCell.Text,
+                                       TextColor = s_defaultTextColor,
+                                       Placeholder = entryCell.Placeholder,
+                                       PlaceholderColor = s_defaultTextColor,
+                                       Keyboard = entryCell.Keyboard.ToNative(),
+                                       HorizontalTextAlignment = entryCell.HorizontalTextAlignment.ToNative(),
+                               };
+                               entry.SetAlignment(-1.0, 0.5);
+                               entry.SetWeight(1.0, 1.0);
+
+                               box.PackEnd(label);
+                               box.PackEnd(entry);
+
+                               label.Show();
+                               entry.Show();
+
+                               entry.TextChanged += (sender, e) =>
+                               {
+                                       entryCell.Text = e.NewTextValue;
+                               };
+                               entry.Activated += (sender, e) =>
+                               {
+                                       (cell as IEntryCellController).SendCompleted();
+                               };
+                               NativeEntryComponent component = new NativeEntryComponent()
+                               {
+                                       Entry = entry,
+                                       Label = label,
+                               };
+                               _realizedComponent[box] = component;
+                               box.Deleted += (sender, e) =>
+                               {
+                                       _realizedComponent.Remove(box);
+                               };
+                               return box;
+                       }
+                       return null;
+               }
+
+               protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary<string, EvasObject> realizedView)
+               {
+                       if (!realizedView.ContainsKey(MainContentPart) || !_realizedComponent.ContainsKey(realizedView[MainContentPart]))
+                       {
+                               return base.OnCellPropertyChanged(cell, property, realizedView);
+                       }
+
+                       NativeEntryComponent realizedCompoenet = _realizedComponent[realizedView[MainContentPart]];
+                       EntryCell entryCell = (EntryCell)cell;
+
+                       if (property == EntryCell.HorizontalTextAlignmentProperty.PropertyName)
+                       {
+                               var entry = realizedCompoenet.Entry;
+                               if (entry != null)
+                               {
+                                       entry.HorizontalTextAlignment = entryCell.HorizontalTextAlignment.ToNative();
+                               }
+                       }
+                       else if (property == EntryCell.KeyboardProperty.PropertyName)
+                       {
+                               var entry = realizedCompoenet.Entry;
+                               if (entry != null)
+                               {
+                                       entry.Keyboard = entryCell.Keyboard.ToNative();
+                               }
+                       }
+                       else if (property == EntryCell.PlaceholderProperty.PropertyName)
+                       {
+                               var entry = realizedCompoenet.Entry;
+                               if (entry != null)
+                               {
+                                       entry.Placeholder = entryCell.Placeholder;
+                               }
+                       }
+                       else if (property == EntryCell.TextProperty.PropertyName)
+                       {
+                               var entry = realizedCompoenet.Entry;
+                               if (entry != null)
+                               {
+                                       entry.Text = entryCell.Text;
+                               }
+                       }
+                       else if (property == EntryCell.LabelProperty.PropertyName)
+                       {
+                               var label = realizedCompoenet.Label;
+                               if (label != null)
+                               {
+                                       label.Text = entryCell.Label;
+                               }
+                       }
+                       else if (property == EntryCell.LabelColorProperty.PropertyName)
+                       {
+                               var label = realizedCompoenet.Label;
+                               if (label != null)
+                               {
+                                       label.TextColor = GetLabelColor(entryCell);
+                               }
+                       }
+                       else
+                       {
+                               return base.OnCellPropertyChanged(cell, property, realizedView);
+                       }
+                       return false;
+               }
+
+               EColor GetLabelColor(EntryCell cell)
+               {
+                       return cell.LabelColor.IsDefault ? s_defaultTextColor : cell.LabelColor.ToNative();
+               }
+
+               class NativeEntryComponent
+               {
+                       public Native.Entry Entry { get; set; }
+                       public Native.Label Label { get; set; }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Cells/ImageCellRenderer.cs b/Xamarin.Forms.Platform.Tizen/Cells/ImageCellRenderer.cs
new file mode 100644 (file)
index 0000000..9492e7c
--- /dev/null
@@ -0,0 +1,60 @@
+using ElmSharp;
+using System.Collections.Generic;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class ImageCellRenderer : TextCellRenderer
+       {
+               const int _defaultHeight = 100;
+               Dictionary<EvasObject, Native.Image> _realizedViews = new Dictionary<EvasObject, Native.Image>();
+
+               public ImageCellRenderer() : this("type1")
+               {
+                       ImagePart = "elm.swallow.icon";
+               }
+               protected ImageCellRenderer(string style) : base(style) { }
+
+               protected string ImagePart { get; set; }
+
+               protected override EvasObject OnGetContent(Cell cell, string part)
+               {
+                       if (part == ImagePart)
+                       {
+                               var imgCell = cell as ImageCell;
+                               var size = imgCell.RenderHeight;
+                               if (size <= 0)
+                               {
+                                       size = _defaultHeight;
+                               }
+
+                               var image = new Native.Image(Forms.Context.MainWindow)
+                               {
+                                       MinimumWidth = (int)size,
+                                       MinimumHeight = (int)size
+                               };
+                               image.SetAlignment(-1.0, -1.0); // fill
+                               image.SetWeight(1.0, 1.0); // expand
+
+                               image.LoadFromImageSourceAsync(imgCell.ImageSource);
+                               return image;
+                       }
+                       else
+                       {
+                               return null;
+                       }
+               }
+
+               protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary<string, EvasObject> realizedView)
+               {
+                       if (property == ImageCell.ImageSourceProperty.PropertyName)
+                       {
+                               EvasObject image;
+                               realizedView.TryGetValue(ImagePart, out image);
+                               (image as Native.Image)?.LoadFromImageSourceAsync((cell as ImageCell)?.ImageSource);
+                               return false;
+                       }
+                       return base.OnCellPropertyChanged(cell, property, realizedView);
+               }
+
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Cells/SwitchCellRenderer.cs b/Xamarin.Forms.Platform.Tizen/Cells/SwitchCellRenderer.cs
new file mode 100644 (file)
index 0000000..6c5a038
--- /dev/null
@@ -0,0 +1,74 @@
+using System.Collections.Generic;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class SwitchCellRenderer : CellRenderer
+       {
+               protected SwitchCellRenderer(string style) : base(style)
+               {
+               }
+               public SwitchCellRenderer() : this("end_icon")
+               {
+                       MainPart = "elm.text";
+                       SwitchPart = "elm.swallow.end";
+               }
+
+               protected string MainPart { get; set; }
+               protected string SwitchPart { get; set; }
+
+               protected override Span OnGetText(Cell cell, string part)
+               {
+                       if (part == MainPart)
+                       {
+                               return new Span()
+                               {
+                                       Text = (cell as SwitchCell).Text
+                               };
+                       }
+                       return null;
+               }
+
+               protected override EvasObject OnGetContent(Cell cell, string part)
+               {
+                       if (part == SwitchPart)
+                       {
+                               var switchCell = cell as SwitchCell;
+                               var checkbox = new Check(Forms.Context.MainWindow)
+                               {
+                                       Style = "on&off",
+                                       IsChecked = switchCell.On,
+                               };
+
+                               checkbox.StateChanged += (sender, e) =>
+                               {
+                                       switchCell.On = e.NewState;
+                               };
+
+                               checkbox.SetAlignment(-1.0, -1.0);  // fill
+                               checkbox.SetWeight(1.0, 1.0);  // expand
+                               return checkbox;
+                       }
+                       return null;
+               }
+
+               protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary<string, EvasObject> realizedView)
+               {
+                       if (property == SwitchCell.OnProperty.PropertyName && realizedView.ContainsKey(SwitchPart))
+                       {
+                               var checkbox = realizedView[SwitchPart] as Check;
+                               if (checkbox != null)
+                               {
+                                       checkbox.IsChecked = (cell as SwitchCell).On;
+                               }
+                               return false;
+                       }
+                       else if (property == SwitchCell.TextProperty.PropertyName)
+                       {
+                               return true;
+                       }
+
+                       return base.OnCellPropertyChanged(cell, property, realizedView);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Cells/TextCellRenderer.cs b/Xamarin.Forms.Platform.Tizen/Cells/TextCellRenderer.cs
new file mode 100644 (file)
index 0000000..2bea384
--- /dev/null
@@ -0,0 +1,72 @@
+using ElmSharp;
+using System.Collections.Generic;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class TextCellRenderer : CellRenderer
+       {
+               public TextCellRenderer() : this("double_label") { }
+               protected TextCellRenderer(string style) : base(style)
+               {
+                       MainPart = "elm.text";
+                       DetailPart = "elm.text.sub";
+               }
+
+               protected string MainPart { get; set; }
+               protected string DetailPart { get; set; }
+
+               protected override Span OnGetText(Cell cell, string part)
+               {
+                       var textCell = (TextCell)cell;
+                       if (part == MainPart)
+                       {
+                               return OnMainText(textCell);
+                       }
+                       if (part == DetailPart)
+                       {
+                               return OnDetailText(textCell);
+                       }
+                       return null;
+               }
+
+               protected virtual Span OnMainText(TextCell cell)
+               {
+                       return new Span()
+                       {
+                               Text = cell.Text,
+                               ForegroundColor = cell.TextColor
+                       };
+               }
+
+               protected virtual Span OnDetailText(TextCell cell)
+               {
+                       return new Span()
+                       {
+                               Text = cell.Detail,
+                               ForegroundColor = cell.DetailColor
+                       };
+               }
+
+               protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary<string, EvasObject> realizedView)
+               {
+                       if (property == TextCell.TextProperty.PropertyName ||
+                               property == TextCell.TextColorProperty.PropertyName ||
+                               property == TextCell.DetailProperty.PropertyName ||
+                               property == TextCell.DetailColorProperty.PropertyName)
+                       {
+                               return true;
+                       }
+                       return base.OnCellPropertyChanged(cell, property, realizedView);
+               }
+       }
+
+       internal class GroupCellTextRenderer : TextCellRenderer
+       {
+
+               public GroupCellTextRenderer() : this("group_index")
+               {
+                       DetailPart = "elm.text.end";
+               }
+               protected GroupCellTextRenderer(string style) : base(style) { }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Cells/ViewCellRenderer.cs b/Xamarin.Forms.Platform.Tizen/Cells/ViewCellRenderer.cs
new file mode 100644 (file)
index 0000000..69065c8
--- /dev/null
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class ViewCellRenderer : CellRenderer
+       {
+               public ViewCellRenderer() : base("full")
+               {
+                       MainContentPart = "elm.swallow.content";
+               }
+
+               protected string MainContentPart { get; set; }
+
+               protected override EvasObject OnGetContent(Cell cell, string part)
+               {
+                       if (part == MainContentPart)
+                       {
+                               var viewCell = cell as ViewCell;
+                               if (viewCell != null)
+                               {
+                                       var renderer = Platform.GetOrCreateRenderer(viewCell.View);
+                                       int height = (int)viewCell.RenderHeight;
+                                       height = height <= 0 ? FindCellContentHeight(viewCell) : height;
+
+                                       renderer.NativeView.MinimumHeight = height;
+                                       return renderer.NativeView;
+                               }
+                               return null;
+                       }
+                       return null;
+               }
+
+               protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary<string, EvasObject> realizedView)
+               {
+                       if (property == "View")
+                       {
+                               return true;
+                       }
+                       return base.OnCellPropertyChanged(cell, property, realizedView);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Deserializer.cs b/Xamarin.Forms.Platform.Tizen/Deserializer.cs
new file mode 100644 (file)
index 0000000..8335840
--- /dev/null
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using System.Runtime.Serialization;
+using System.Xml;
+using System.Diagnostics;
+using System.IO;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       internal class Deserializer : IDeserializer
+       {
+               const string PropertyStoreFile = "PropertyStore.forms";
+
+               public Task<IDictionary<string, object>> DeserializePropertiesAsync()
+               {
+                       // Deserialize property dictionary to local storage
+                       // Make sure to use Internal
+                       return Task.Run(() =>
+                       {
+                               var store = new TizenIsolatedStorageFile();
+                               Stream stream = null;
+                               try
+                               {
+                                       stream = store.OpenFile(PropertyStoreFile, System.IO.FileMode.OpenOrCreate);
+                                       if (stream.Length == 0)
+                                       {
+                                               return null;
+                                       }
+                                       using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
+                                       {
+                                               stream = null;
+                                               var dcs = new DataContractSerializer(typeof(Dictionary<string, object>));
+                                               return (IDictionary<string, object>)dcs.ReadObject(reader);
+                                       }
+                               }
+                               catch (Exception e)
+                               {
+                                       Debug.WriteLine("Could not deserialize properties: " + e.Message);
+                                       Xamarin.Forms.Log.Warning("Xamarin.Forms PropertyStore", $"Exception while reading Application properties: {e}");
+                               }
+                               finally
+                               {
+                                       if (stream != null)
+                                       {
+                                               stream.Dispose();
+                                       }
+                               }
+
+                               return null;
+                       });
+               }
+
+               public Task SerializePropertiesAsync(IDictionary<string, object> properties)
+               {
+                       properties = new Dictionary<string, object>(properties);
+                       // Serialize property dictionary to local storage
+                       // Make sure to use Internal
+                       return Task.Run(() =>
+                       {
+                               var success = false;
+                               var store = new TizenIsolatedStorageFile();
+                               Stream stream = null;
+                               try
+                               {
+                                       stream = store.OpenFile(PropertyStoreFile + ".tmp", System.IO.FileMode.OpenOrCreate);
+                                       using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream))
+                                       {
+                                               stream = null;
+                                               var dcs = new DataContractSerializer(typeof(Dictionary<string, object>));
+                                               dcs.WriteObject(writer, properties);
+                                               writer.Flush();
+                                               success = true;
+                                       }
+                               }
+                               catch (Exception e)
+                               {
+                                       Debug.WriteLine("Could not serialize properties: " + e.Message);
+                                       Xamarin.Forms.Log.Warning("Xamarin.Forms PropertyStore", $"Exception while writing Application properties: {e}");
+                               }
+                               finally
+                               {
+                                       if (stream != null)
+                                       {
+                                               stream.Dispose();
+                                       }
+                               }
+
+                               if (!success)
+                                       return;
+
+                               try
+                               {
+                                       if (store.FileExists(PropertyStoreFile))
+                                               store.DeleteFile(PropertyStoreFile);
+                                       store.MoveFile(PropertyStoreFile + ".tmp", PropertyStoreFile);
+                               }
+                               catch (Exception e)
+                               {
+                                       Debug.WriteLine("Could not move new serialized property file over old: " + e.Message);
+                                       Xamarin.Forms.Log.Warning("Xamarin.Forms PropertyStore", $"Exception while writing Application properties: {e}");
+                               }
+                       });
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/ElementChangedEventArgs.cs b/Xamarin.Forms.Platform.Tizen/ElementChangedEventArgs.cs
new file mode 100644 (file)
index 0000000..844752e
--- /dev/null
@@ -0,0 +1,38 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class ElementChangedEventArgs<TElement> : EventArgs where TElement : Element
+       {
+               /// <summary>
+               /// Holds the old element which is about to be replaced by a new element
+               /// </summary>
+               /// <value>An TElement instance representing the old element just being replaced</value>
+               public TElement OldElement
+               {
+                       get;
+                       private set;
+               }
+
+               /// <summary>
+               /// Holds the new element which will replace the old element
+               /// </summary>
+               /// <value>An TElement instance representing the new element to be used from now on</value>
+               public TElement NewElement
+               {
+                       get;
+                       private set;
+               }
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.ElementChangedEventArgs`1"/> class.
+               /// </summary>
+               /// <param name="oldElement">The old element which will be replaced by a newElement momentarily.</param>
+               /// <param name="newElement">The new element, taking place of an old element.</param>
+               public ElementChangedEventArgs(TElement oldElement, TElement newElement)
+               {
+                       this.OldElement = oldElement;
+                       this.NewElement = newElement;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/EvasObjectWrapper.cs b/Xamarin.Forms.Platform.Tizen/EvasObjectWrapper.cs
new file mode 100644 (file)
index 0000000..97cf77f
--- /dev/null
@@ -0,0 +1,24 @@
+using ElmSharp;
+using ESize = ElmSharp.Size;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public delegate ESize? MeasureDelegate(EvasObjectWrapperRenderer renderer, int availableWidth, int availableHeight);
+
+       public class EvasObjectWrapper : View
+       {
+               public EvasObjectWrapper(EvasObject obj, MeasureDelegate measureDelegate = null)
+               {
+                       EvasObject = obj;
+                       MeasureDelegate = measureDelegate;
+               }
+
+               public EvasObject EvasObject
+               {
+                       get;
+                       private set;
+               }
+
+               public MeasureDelegate MeasureDelegate { get; }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/ExportCellAttribute.cs b/Xamarin.Forms.Platform.Tizen/ExportCellAttribute.cs
new file mode 100644 (file)
index 0000000..e0435ad
--- /dev/null
@@ -0,0 +1,12 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+       public sealed class ExportCellAttribute : HandlerAttribute
+       {
+               public ExportCellAttribute(Type handler, Type target) : base(handler, target)
+               {
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/ExportImageSourceHandlerAttribute.cs b/Xamarin.Forms.Platform.Tizen/ExportImageSourceHandlerAttribute.cs
new file mode 100644 (file)
index 0000000..4463db8
--- /dev/null
@@ -0,0 +1,12 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+       public sealed class ExportImageSourceHandlerAttribute : HandlerAttribute
+       {
+               public ExportImageSourceHandlerAttribute(Type handler, Type target) : base(handler, target)
+               {
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/ExportRendererAttribute.cs b/Xamarin.Forms.Platform.Tizen/ExportRendererAttribute.cs
new file mode 100644 (file)
index 0000000..9af8019
--- /dev/null
@@ -0,0 +1,12 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
+       public sealed class ExportRendererAttribute : HandlerAttribute
+       {
+               public ExportRendererAttribute(Type handler, Type target) : base(handler, target)
+               {
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Extensions/ColorExtensions.cs b/Xamarin.Forms.Platform.Tizen/Extensions/ColorExtensions.cs
new file mode 100644 (file)
index 0000000..553c2cb
--- /dev/null
@@ -0,0 +1,39 @@
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public static class ColorExtensions
+       {
+               /// <summary>
+               /// Creates an instance of ElmSharp.Color class based on provided Xamarin.Forms.Color instance
+               /// </summary>
+               /// <returns>ElmSharp.Color instance representing a color which corresponds to the provided Xamarin.Forms.Color</returns>
+               /// <param name="c">The Xamarin.Forms.Color instance which will be converted to a ElmSharp.Color</param>
+               public static EColor ToNative(this Color c)
+               {
+                       if (c.IsDefault)
+                       {
+                               Log.Warn("Trying to convert the default color, this may result in black color.");
+                               return EColor.Default;
+                       }
+                       else
+                       {
+                               return new EColor((int)(255.0 * c.R), (int)(255.0 * c.G), (int)(255.0 * c.B), (int)(255.0 * c.A));
+                       }
+               }
+
+               /// <summary>
+               /// Returns a string representing the provided ElmSharp.Color instance in a hexagonal notation
+               /// </summary>
+               /// <returns>string value containing the encoded color</returns>
+               /// <param name="c">The ElmSharp.Color class instance which will be serialized</param>
+               internal static string ToHex(this EColor c)
+               {
+                       if (c.IsDefault)
+                       {
+                               Log.Warn("Trying to convert the default color to hexagonal notation, it does not works as expected.");
+                       }
+                       return string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", c.R, c.G, c.B, c.A);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Extensions/KeyboardExtensions.cs b/Xamarin.Forms.Platform.Tizen/Extensions/KeyboardExtensions.cs
new file mode 100644 (file)
index 0000000..000b6bb
--- /dev/null
@@ -0,0 +1,42 @@
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public static class KeyboardExtensions
+       {
+               /// <summary>
+               /// Creates an instance of ElmSharp.Keyboard reflecting the provided Xamarin.Forms.Keyboard instance
+               /// </summary>
+               /// <returns>Keyboard type corresponding to the provided Xamarin.Forms.Keyboard</returns>
+               /// <param name="keyboard">The Xamarin.Forms.Keyboard class instance to be converted to ElmSharp.Keyboard.</param>
+               public static Native.Keyboard ToNative(this Keyboard keyboard)
+               {
+                       if (keyboard is TextKeyboard)
+                       {
+                               return Native.Keyboard.Normal;
+                       }
+                       else if (keyboard is NumericKeyboard)
+                       {
+                               return Native.Keyboard.Number;
+                       }
+                       else if (keyboard is TelephoneKeyboard)
+                       {
+                               return Native.Keyboard.PhoneNumber;
+                       }
+                       else if (keyboard is EmailKeyboard)
+                       {
+                               return Native.Keyboard.Email;
+                       }
+                       else if (keyboard is UrlKeyboard)
+                       {
+                               return Native.Keyboard.Url;
+                       }
+                       else if (keyboard is ChatKeyboard)
+                       {
+                               return Native.Keyboard.Emoticon;
+                       }
+                       else
+                       {
+                               return Native.Keyboard.Normal;
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Extensions/LayoutExtensions.cs b/Xamarin.Forms.Platform.Tizen/Extensions/LayoutExtensions.cs
new file mode 100644 (file)
index 0000000..4880beb
--- /dev/null
@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Extension class, provides native embedding functionalities:
+       /// https://developer.xamarin.com/guides/xamarin-forms/user-interface/layouts/add-platform-controls/
+       /// </summary>
+       /// <remarks>
+       /// This code is not used in the Xamarin.Forms.Platform.Tizen implementation, however it should not
+       /// be removed as it allows developers to use native controls directly.
+       /// </remarks>
+       public static class LayoutExtensions
+       {
+               /// <summary>
+               /// Add the specified evas object to the list of children views.
+               /// </summary>
+               /// <param name="children">The extended class.</param>
+               /// <param name="obj">Object to be added.</param>
+               /// <param name="measureDelegate">Optional delegate which provides measurements for the added object.</param>
+               public static void Add(this IList<View> children, EvasObject obj, MeasureDelegate measureDelegate = null)
+               {
+                       children.Add(obj.ToView(measureDelegate));
+               }
+
+               /// <summary>
+               /// Wraps the evas object into a view which can be used by Xamarin.
+               /// </summary>
+               /// <returns>The Xamarin view which wraps the evas object.</returns>
+               /// <param name="obj">The extended class.</param>
+               /// <param name="measureDelegate">Optional delegate which provides measurements for the evas object.</param>
+               public static View ToView(this EvasObject obj, MeasureDelegate measureDelegate = null)
+               {
+                       return new EvasObjectWrapper(obj, measureDelegate);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Extensions/ScrollToPositionExtensions.cs b/Xamarin.Forms.Platform.Tizen/Extensions/ScrollToPositionExtensions.cs
new file mode 100644 (file)
index 0000000..9d1dc25
--- /dev/null
@@ -0,0 +1,28 @@
+using EScrollToPosition = ElmSharp.ScrollToPosition;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public static class ScrollToPositionExtensions
+       {
+               public static EScrollToPosition ToNative(this ScrollToPosition position)
+               {
+                       switch (position)
+                       {
+                               case ScrollToPosition.Center:
+                                       return EScrollToPosition.Middle;
+
+                               case ScrollToPosition.End:
+                                       return EScrollToPosition.Bottom;
+
+                               case ScrollToPosition.MakeVisible:
+                                       return EScrollToPosition.In;
+
+                               case ScrollToPosition.Start:
+                                       return EScrollToPosition.Top;
+
+                               default:
+                                       return EScrollToPosition.Top;
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Extensions/TextAlignmentExtensions.cs b/Xamarin.Forms.Platform.Tizen/Extensions/TextAlignmentExtensions.cs
new file mode 100644 (file)
index 0000000..cf662c4
--- /dev/null
@@ -0,0 +1,26 @@
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public static class TextAlignmentExtensions
+       {
+               public static Native.TextAlignment ToNative(this TextAlignment alignment)
+               {
+                       switch (alignment)
+                       {
+                               case TextAlignment.Center:
+                                       return Native.TextAlignment.Center;
+
+                               case TextAlignment.Start:
+                                       return Native.TextAlignment.Start;
+
+                               case TextAlignment.End:
+                                       return Native.TextAlignment.End;
+
+                               default:
+                                       Log.Warn("Warning: unrecognized HorizontalTextAlignment value {0}. " +
+                                               "Expected: {Start|Center|End}.", alignment);
+                                       Log.Debug("Falling back to platform's default settings.");
+                                       return Native.TextAlignment.Auto;
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Forms.cs b/Xamarin.Forms.Platform.Tizen/Forms.cs
new file mode 100644 (file)
index 0000000..6aa0e62
--- /dev/null
@@ -0,0 +1,173 @@
+using System;
+using System.Reflection;
+using Tizen.Applications;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public static class Forms
+       {
+               class TizenDeviceInfo : DeviceInfo
+               {
+                       readonly Size pixelScreenSize;
+
+                       readonly Size scaledScreenSize;
+
+                       readonly double scalingFactor;
+
+                       public override Size PixelScreenSize
+                       {
+                               get
+                               {
+                                       return this.pixelScreenSize;
+                               }
+                       }
+
+                       public override Size ScaledScreenSize
+                       {
+                               get
+                               {
+                                       return this.scaledScreenSize;
+                               }
+                       }
+
+                       public override double ScalingFactor
+                       {
+                               get
+                               {
+                                       return this.scalingFactor;
+                               }
+                       }
+
+                       public TizenDeviceInfo(FormsApplication formsApplication)
+                       {
+                               // TODO: obtain screen data from device
+                               pixelScreenSize = new Size();
+                               scaledScreenSize = new Size();
+                               scalingFactor = 0.0;
+                       }
+               }
+
+               public static event EventHandler<ViewInitializedEventArgs> ViewInitialized;
+
+               public static FormsApplication Context
+               {
+                       get;
+                       internal set;
+               }
+
+               public static bool IsInitialized
+               {
+                       get;
+                       private set;
+               }
+
+               internal static TizenTitleBarVisibility TitleBarVisibility
+               {
+                       get;
+                       private set;
+               }
+
+               internal static void SendViewInitialized(this VisualElement self, EvasObject nativeView)
+               {
+                       EventHandler<ViewInitializedEventArgs> viewInitialized = Forms.ViewInitialized;
+                       if (viewInitialized != null)
+                       {
+                               viewInitialized.Invoke(self, new ViewInitializedEventArgs
+                               {
+                                       View = self,
+                                       NativeView = nativeView
+                               });
+                       }
+               }
+
+               public static void SetTitleBarVisibility(TizenTitleBarVisibility visibility)
+               {
+                       TitleBarVisibility = visibility;
+               }
+
+               public static void Init(FormsApplication application)
+               {
+                       SetupInit(application);
+               }
+
+               static void SetupInit(FormsApplication application)
+               {
+                       Color.Accent = GetAccentColor();
+
+                       Context = application;
+
+                       if (!IsInitialized)
+                       {
+                               Xamarin.Forms.Log.Listeners.Add(new XamarinLogListener());
+                               if (System.Threading.SynchronizationContext.Current == null)
+                               {
+                                       TizenSynchronizationContext.Initialize();
+                               }
+                               Elementary.Initialize();
+                               Elementary.ThemeOverlay();
+                       }
+
+                       //TO-DO: Need to change to Tizen.
+                       Device.OS = TargetPlatform.Other;
+
+#if !NET45
+                       // In .NETCore, AppDomain feature is not supported.
+                       // The list of assemblies returned by AppDomain.GetAssemblies() method should be registered manually.
+                       // The assembly of the executing application and referenced assemblies of it are added into the list here.
+                       Assembly asm = application.GetType().GetTypeInfo().Assembly;
+                       TizenPlatformServices.AppDomain.CurrentDomain.RegisterAssembly(asm);
+                       foreach (var refName in asm.GetReferencedAssemblies())
+                       {
+                               if (!refName.Name.StartsWith("System.") && !refName.Name.StartsWith("Microsoft."))
+                               {
+                                       try
+                                       {
+                                               Assembly refAsm = Assembly.Load(refName);
+                                               TizenPlatformServices.AppDomain.CurrentDomain.RegisterAssembly(refAsm);
+                                       }
+                                       catch
+                                       {
+                                               Log.Warn("Reference Assembly can not be loaded. {0}", refName.FullName);
+                                       }
+                               }
+                       }
+#endif
+
+                       Device.PlatformServices = new TizenPlatformServices(); ;
+                       if (Device.info != null)
+                       {
+                               ((TizenDeviceInfo)Device.info).Dispose();
+                               Device.info = null;
+                       }
+
+                       Device.Info = new Forms.TizenDeviceInfo(application);
+
+                       if (!Forms.IsInitialized)
+                       {
+                               Registrar.RegisterAll(new Type[]
+                               {
+                                       typeof(ExportRendererAttribute),
+                                       typeof(ExportImageSourceHandlerAttribute),
+                                       typeof(ExportCellAttribute),
+                               });
+                       }
+
+                       // FIXME: We should consider TV and Common (Desktop) profiles also.
+                       Device.Idiom = TargetIdiom.Phone;
+
+                       IsInitialized = true;
+               }
+
+               static Color GetAccentColor()
+               {
+                       // On Windows Phone, this is the complementary color chosen by the user.
+                       // Good Windows Phone applications use this as part of their styling to provide a native look and feel.
+                       // On iOS and Android this instance is set to a contrasting color that is visible on the default
+                       // background but is not the same as the default text color.
+
+                       // TODO: implement me
+                       return Color.Black;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/FormsApplication.cs b/Xamarin.Forms.Platform.Tizen/FormsApplication.cs
new file mode 100644 (file)
index 0000000..32ef3c3
--- /dev/null
@@ -0,0 +1,344 @@
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using Tizen.Applications;
+using ElmSharp;
+using EProgressBar = ElmSharp.ProgressBar;
+using EColor = ElmSharp.Color;
+using ELabel = ElmSharp.Label;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class FormsApplication : CoreUIApplication
+       {
+               Platform _platform;
+               Application _application;
+               bool _isInitialStart;
+               int _pageBusyCount;
+               Native.Dialog _pageBusyDialog;
+               Native.Window _window;
+
+               protected FormsApplication()
+               {
+                       _isInitialStart = true;
+                       _pageBusyCount = 0;
+               }
+
+               /// <summary>
+               /// Gets the main window or <c>null</c> if it's not set.
+               /// </summary>
+               /// <value>The main window or <c>null</c>.</value>
+               public Native.Window MainWindow
+               {
+                       get
+                       {
+                               return _window;
+                       }
+
+                       private set
+                       {
+                               _window = value;
+                       }
+               }
+
+               protected override void OnCreate()
+               {
+                       base.OnCreate();
+                       Application.ClearCurrent();
+                       CreateWindow();
+               }
+
+               protected override void OnTerminate()
+               {
+                       base.OnTerminate();
+                       MessagingCenter.Unsubscribe<Page, AlertArguments>(this, "Xamarin.SendAlert");
+                       MessagingCenter.Unsubscribe<Page, bool>(this, "Xamarin.BusySet");
+                       MessagingCenter.Unsubscribe<Page, ActionSheetArguments>(this, "Xamarin.ShowActionSheet");
+                       if (_platform != null)
+                       {
+                               _platform.Dispose();
+                       }
+               }
+
+               protected override void OnAppControlReceived(AppControlReceivedEventArgs e)
+               {
+                       base.OnAppControlReceived(e);
+
+                       if (!_isInitialStart && _application != null)
+                       {
+                               _application.SendResume();
+                       }
+                       _isInitialStart = false;
+               }
+
+               protected override void OnPause()
+               {
+                       base.OnPause();
+                       if (_application != null)
+                       {
+                               _application.SendSleepAsync();
+                       }
+               }
+
+               protected override void OnResume()
+               {
+                       base.OnResume();
+                       if (_application != null)
+                       {
+                               _application.SendResume();
+                       }
+               }
+
+               public void LoadApplication(Application application)
+               {
+                       if (null == MainWindow)
+                       {
+                               throw new NullReferenceException("Call base OnCreate() method before loading the application.");
+                       }
+                       if (null == application)
+                       {
+                               throw new ArgumentNullException("application");
+                       }
+                       _application = application;
+                       Application.Current = application;
+                       application.SendStart();
+                       application.PropertyChanged += new PropertyChangedEventHandler(this.AppOnPropertyChanged);
+                       SetPage(_application.MainPage);
+               }
+
+               void AppOnPropertyChanged(object sender, PropertyChangedEventArgs args)
+               {
+                       if ("MainPage" == args.PropertyName)
+                       {
+                               SetPage(_application.MainPage);
+                       }
+               }
+
+               void ShowActivityIndicatorDialog(bool enabled)
+               {
+                       if (null == _pageBusyDialog)
+                       {
+                               _pageBusyDialog = new Native.Dialog(Forms.Context.MainWindow)
+                               {
+                                       Orientation = PopupOrientation.Top,
+                               };
+
+                               var activity = new EProgressBar(_pageBusyDialog)
+                               {
+                                       Style = "process_large",
+                                       IsPulseMode = true,
+                               };
+                               activity.PlayPulse();
+                               activity.Show();
+
+                               _pageBusyDialog.Content = activity;
+
+                       }
+                       _pageBusyCount = Math.Max(0, enabled ? _pageBusyCount + 1 : _pageBusyCount - 1);
+                       if (_pageBusyCount > 0)
+                       {
+                               _pageBusyDialog.Show();
+                       }
+                       else
+                       {
+                               _pageBusyDialog.Dismiss();
+                               _pageBusyDialog = null;
+                       }
+               }
+
+               void SetPage(Page page)
+               {
+                       if (!Forms.IsInitialized)
+                       {
+                               throw new InvalidOperationException("Call Forms.Init (UIApplication) before this");
+                       }
+                       if (_platform != null)
+                       {
+                               _platform.SetPage(page);
+                               return;
+                       }
+                       MessagingCenter.Subscribe<Page, bool>(this, Page.BusySetSignalName, delegate (Page sender, bool enabled)
+                               {
+                                       ShowActivityIndicatorDialog(enabled);
+                               }, null);
+
+                       MessagingCenter.Subscribe<Page, AlertArguments>(this, Page.AlertSignalName, delegate (Page sender, AlertArguments arguments)
+                               {
+                                       Native.Dialog alert = new Native.Dialog(Forms.Context.MainWindow);
+
+                                       alert.Title = arguments.Title;
+                                       var label = new ELabel(alert)
+                                       {
+                                               Text = "<span font_size=30 >" + arguments.Message + "<\\span>",
+                                       };
+                                       label.Show();
+
+                                       var box = new Box(alert);
+                                       box.PackEnd(label);
+                                       box.Show();
+                                       alert.Content = box;
+
+                                       Native.Button cancel = new Native.Button(alert) { Text = arguments.Cancel };
+                                       alert.NegativeButton = cancel;
+                                       cancel.Clicked += (s, evt) =>
+                                       {
+                                               arguments.SetResult(false);
+                                               alert.Dismiss();
+                                       };
+
+                                       if (arguments.Accept != null)
+                                       {
+                                               Native.Button ok = new Native.Button(alert) { Text = arguments.Accept };
+                                               alert.PositiveButton = ok;
+                                               ok.Clicked += (s, evt) =>
+                                               {
+                                                       arguments.SetResult(true);
+                                                       alert.Dismiss();
+                                               };
+                                       }
+
+                                       alert.BackButtonPressed += (s, evt) =>
+                                       {
+                                               arguments.SetResult(false);
+                                               alert.Dismiss();
+                                       };
+
+                                       alert.Show();
+                               }, null);
+
+                       MessagingCenter.Subscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName, delegate (Page sender, ActionSheetArguments arguments)
+                       {
+                               Native.Dialog alert = new Native.Dialog(Forms.Context.MainWindow);
+
+                               alert.Title = arguments.Title;
+                               Box box = new Box(alert);
+
+                               if (null != arguments.Destruction)
+                               {
+                                       Native.Button destruction = new Native.Button(alert)
+                                       {
+                                               Text = arguments.Destruction,
+                                               TextColor = EColor.Red,
+                                               AlignmentX = -1
+                                       };
+                                       destruction.Clicked += (s, evt) =>
+                                       {
+                                               arguments.SetResult(arguments.Destruction);
+                                               alert.Dismiss();
+                                       };
+                                       destruction.Show();
+                                       box.PackEnd(destruction);
+                               }
+
+                               foreach (string buttonName in arguments.Buttons)
+                               {
+                                       Native.Button button = new Native.Button(alert)
+                                       {
+                                               Text = buttonName,
+                                               AlignmentX = -1
+                                       };
+                                       button.Clicked += (s, evt) =>
+                                       {
+                                               arguments.SetResult(buttonName);
+                                               alert.Dismiss();
+                                       };
+                                       button.Show();
+                                       box.PackEnd(button);
+                               }
+
+                               box.Show();
+                               alert.Content = box;
+
+                               if (null != arguments.Cancel)
+                               {
+                                       Native.Button cancel = new Native.Button(Forms.Context.MainWindow) { Text = arguments.Cancel };
+                                       alert.NegativeButton = cancel;
+                                       cancel.Clicked += (s, evt) =>
+                                       {
+                                               alert.Dismiss();
+                                       };
+                               }
+
+                               alert.BackButtonPressed += (s, evt) =>
+                               {
+                                       alert.Dismiss();
+                               };
+
+                               alert.Show();
+                       }, null);
+
+                       _platform = new Platform(this);
+                       if (_application != null)
+                       {
+                               _application.Platform = _platform;
+                       }
+                       _platform.SetPage(page);
+               }
+
+               void CreateWindow()
+               {
+                       Debug.Assert(null == MainWindow);
+
+                       var window = new Native.Window();
+                       window.Closed += (s, e) =>
+                       {
+                               Exit();
+                       };
+                       window.RotationChanged += (sender, e) =>
+                       {
+                               switch (_window.CurrentOrientation)
+                               {
+                                       case Native.DisplayOrientations.None:
+                                               Device.Info.CurrentOrientation = DeviceOrientation.Other;
+                                               break;
+
+                                       case Native.DisplayOrientations.Portrait:
+                                               Device.Info.CurrentOrientation = DeviceOrientation.PortraitUp;
+                                               break;
+
+                                       case Native.DisplayOrientations.Landscape:
+                                               Device.Info.CurrentOrientation = DeviceOrientation.LandscapeLeft;
+                                               break;
+
+                                       case Native.DisplayOrientations.PortraitFlipped:
+                                               Device.Info.CurrentOrientation = DeviceOrientation.PortraitDown;
+                                               break;
+
+                                       case Native.DisplayOrientations.LandscapeFlipped:
+                                               Device.Info.CurrentOrientation = DeviceOrientation.LandscapeRight;
+                                               break;
+                               }
+                       };
+
+                       MainWindow = window;
+               }
+               public void Run()
+               {
+                       Run(System.Environment.GetCommandLineArgs());
+               }
+
+               /// <summary>
+               /// Exits the application's main loop, which initiates the process of its termination
+               /// </summary>
+               public override void Exit()
+               {
+                       if (_platform == null)
+                       {
+                               Log.Warn("Exit was already called or FormsApplication is not initialized yet.");
+                               return;
+                       }
+                       // before everything is closed, inform the MainPage that it is disappearing
+                       try
+                       {
+                               (_platform?.Page as IPageController)?.SendDisappearing();
+                               _platform = null;
+                       }
+                       catch (Exception e)
+                       {
+                               Log.Error("Exception thrown from SendDisappearing: {0}", e.Message);
+                       }
+
+                       base.Exit();
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/GestureHandler.cs b/Xamarin.Forms.Platform.Tizen/GestureHandler.cs
new file mode 100644 (file)
index 0000000..209da3e
--- /dev/null
@@ -0,0 +1,299 @@
+using System.Linq;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.Collections.Generic;
+using ElmSharp;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       internal class GestureHandler
+       {
+               internal readonly IVisualElementRenderer _renderer;
+               internal GestureLayer _gestureLayer;
+               View _view => _renderer.Element as View;
+               IPanGestureController _currentPanGestureController;
+               int _currentPanGestureId;
+               IPinchGestureController _currentPinchGestureController;
+               Point _currentScalePoint;
+               int _previousPinchRadius;
+               double _originalPinchScale;
+               Polygon _hitBox;
+
+               public GestureHandler(IVisualElementRenderer renderer)
+               {
+                       _renderer = renderer;
+                       // Whenever a GestureRecognizer is added to the View, it will be connected to GestureLayer
+                       (_view.GestureRecognizers as ObservableCollection<IGestureRecognizer>).CollectionChanged += OnGestureRecognizersChanged;
+                       // handle GestureRecognizers which were already set by the time we got here
+                       if (_view.GestureRecognizers.Count > 0)
+                       {
+                               CreateGestureLayer();
+                               foreach (var item in _view.GestureRecognizers)
+                                       ToggleRecognizer(item, true);
+                       }
+               }
+
+               public void Clear()
+               {
+                       // this will clear all callbacks in ElmSharp GestureLayer
+                       _gestureLayer.Unrealize();
+                       (_view.GestureRecognizers as ObservableCollection<IGestureRecognizer>).CollectionChanged -= OnGestureRecognizersChanged;
+                       if (_hitBox != null)
+                       {
+                               _hitBox.Unrealize();
+                               _hitBox = null;
+                       }
+               }
+
+               public void UpdateHitBox()
+               {
+                       if (_hitBox == null)
+                               return;
+                       // _hitBox has to be used because gestures do not work well with transformations (EvasMap)
+                       // so we create additional object which has the same shape as tranformed target, but does not have EvasMap on it
+                       EvasObject target = _renderer.NativeView;
+                       _hitBox.ClearPoints();
+                       if (target.IsMapEnabled)
+                       {
+                               var map = target.EvasMap;
+                               Point3D point;
+                               for (var i = 0; i < 4; i++)
+                               {
+                                       point = map.GetPointCoordinate(i);
+                                       _hitBox.AddPoint(point.X, point.Y);
+                               }
+                       }
+                       else
+                       {
+                               var geometry = target.Geometry;
+                               if (geometry.Width == 0 || geometry.Height == 0)
+                                       return;
+                               _hitBox.AddPoint(geometry.Left, geometry.Top);
+                               _hitBox.AddPoint(geometry.Right, geometry.Top);
+                               _hitBox.AddPoint(geometry.Right, geometry.Bottom);
+                               _hitBox.AddPoint(geometry.Left, geometry.Bottom);
+                       }
+               }
+
+               protected void ToggleRecognizer(IGestureRecognizer recognizer, bool enable)
+               {
+                       TapGestureRecognizer tapRecognizer;
+                       PanGestureRecognizer panRecognizer;
+                       PinchGestureRecognizer pinchRecognizer;
+
+                       if ((tapRecognizer = recognizer as TapGestureRecognizer) != null)
+                       {
+                               ToggleTapRecognizer(tapRecognizer, enable);
+                       }
+                       else if ((panRecognizer = recognizer as PanGestureRecognizer) != null)
+                       {
+                               if (enable)
+                                       AddPanRecognizer(panRecognizer);
+                               else
+                                       RemovePanRecognizer(panRecognizer);
+                       }
+                       else if ((pinchRecognizer = recognizer as PinchGestureRecognizer) != null)
+                       {
+                               if (enable)
+                                       AddPinchRecognizer(pinchRecognizer);
+                               else
+                                       RemovePinchRecognizer(pinchRecognizer);
+                       }
+                       else
+                       {
+                               Log.Error("Unknown GestureRecognizer will be ignored: {0}", recognizer);
+                       }
+               }
+
+               void ToggleTapRecognizer(TapGestureRecognizer recognizer, bool enable)
+               {
+                       GestureLayer.GestureType type;
+                       switch (recognizer.NumberOfTapsRequired)
+                       {
+                               case 1:
+                                       type = GestureLayer.GestureType.Tap;
+                                       break;
+                               case 2:
+                                       type = GestureLayer.GestureType.DoubleTap;
+                                       break;
+                               default:
+                                       type = GestureLayer.GestureType.TripleTap;
+                                       break;
+                       }
+                       if (enable)
+                               _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.End, (data) => recognizer.SendTapped(_view));
+                       else
+                               _gestureLayer.SetTapCallback(type, GestureLayer.GestureState.End, null);
+               }
+
+               void AddPanRecognizer(PanGestureRecognizer recognizer)
+               {
+                       if (_currentPanGestureController != null)
+                               Log.Warn("More than one PanGestureRecognizer on {0}. Only the last one will work.", _view);
+                       EnsureHitBoxExists();
+                       _currentPanGestureController = recognizer;
+                       _gestureLayer.SetLineCallback(GestureLayer.GestureState.Start, OnPanStarted);
+                       _gestureLayer.SetLineCallback(GestureLayer.GestureState.Move, OnPanMoved);
+                       _gestureLayer.SetLineCallback(GestureLayer.GestureState.End, OnPanCompleted);
+                       _gestureLayer.SetLineCallback(GestureLayer.GestureState.Abort, OnPanCancelled);
+               }
+
+               void RemovePanRecognizer(PanGestureRecognizer recognizer)
+               {
+                       _gestureLayer.SetLineCallback(GestureLayer.GestureState.Start, null);
+                       _gestureLayer.SetLineCallback(GestureLayer.GestureState.Move, null);
+                       _gestureLayer.SetLineCallback(GestureLayer.GestureState.End, null);
+                       _gestureLayer.SetLineCallback(GestureLayer.GestureState.Abort, null);
+                       _currentPanGestureController = null;
+               }
+
+               void AddPinchRecognizer(PinchGestureRecognizer recognizer)
+               {
+                       if (_currentPinchGestureController != null)
+                               Log.Warn("More than one PinchGestureRecognizer on {0}. Only the last one will work.", _view);
+                       EnsureHitBoxExists();
+                       _currentPinchGestureController = recognizer;
+                       _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Start, OnPinchStarted);
+                       _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Move, OnPinchMoved);
+                       _gestureLayer.SetZoomCallback(GestureLayer.GestureState.End, OnPinchCompleted);
+                       _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Abort, OnPinchCancelled);
+               }
+
+               void RemovePinchRecognizer(PinchGestureRecognizer recognizer)
+               {
+                       _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Start, null);
+                       _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Move, null);
+                       _gestureLayer.SetZoomCallback(GestureLayer.GestureState.End, null);
+                       _gestureLayer.SetZoomCallback(GestureLayer.GestureState.Abort, null);
+                       _currentPinchGestureController = null;
+               }
+
+               void CreateGestureLayer()
+               {
+                       _gestureLayer = new GestureLayer(_renderer.NativeView);
+                       _gestureLayer.Attach(_renderer.NativeView);
+               }
+
+               void EnsureHitBoxExists()
+               {
+                       if (_hitBox == null)
+                       {
+                               Box parent = (Platform.GetRenderer(_renderer.Element.RealParent) as LayoutRenderer).Control;
+                               _hitBox = new Polygon(parent)
+                               {
+                                       Color = EColor.Transparent
+                               };
+                               _hitBox.Show();
+                               UpdateHitBox();
+                               parent.PackAfter(_hitBox, _renderer.NativeView);
+                               _gestureLayer.Attach(_hitBox);
+                       }
+               }
+
+               void AddAndRemoveRecognizers(IEnumerable<IGestureRecognizer> removed, IEnumerable<IGestureRecognizer> added)
+               {
+                       if (_hitBox == null &&
+                               added != null &&
+                               added.Any(item => (item is IPanGestureController || item is IPinchGestureController)))
+                       {
+                               // at least one of the added recognizers requires _hitBot, which is not ready
+                               _gestureLayer.ClearCallbacks();
+                               EnsureHitBoxExists();
+                               // as _gestureLayer was reattached, register all callbacks, not only new ones
+                               removed = null;
+                               added = _view.GestureRecognizers;
+                       }
+
+                       if (removed != null)
+                       {
+                               foreach (var item in removed)
+                                       ToggleRecognizer(item, false);
+                       }
+                       if (added != null)
+                       {
+                               foreach (var item in added)
+                                       ToggleRecognizer(item, true);
+                       }
+               }
+
+               void OnGestureRecognizersChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
+               {
+                       // Gestures will be registered/unregistered according to changes in the GestureRecognizers list
+                       switch (e.Action)
+                       {
+                               case NotifyCollectionChangedAction.Add:
+                                       if (_gestureLayer == null)
+                                               CreateGestureLayer();
+                                       AddAndRemoveRecognizers(null, e.NewItems.OfType<IGestureRecognizer>());
+                                       break;
+
+                               case NotifyCollectionChangedAction.Replace:
+                                       AddAndRemoveRecognizers(e.OldItems.OfType<IGestureRecognizer>(), e.NewItems.OfType<IGestureRecognizer>());
+                                       break;
+
+                               case NotifyCollectionChangedAction.Remove:
+                                       AddAndRemoveRecognizers(e.OldItems.OfType<IGestureRecognizer>(), null);
+                                       break;
+
+                               case NotifyCollectionChangedAction.Reset:
+                                       AddAndRemoveRecognizers(_view.GestureRecognizers, null);
+                                       break;
+                       }
+               }
+
+               void OnPanStarted(GestureLayer.LineData data)
+               {
+                       _currentPanGestureId++;
+                       _currentPanGestureController.SendPanStarted(_view, _currentPanGestureId);
+               }
+
+               void OnPanMoved(GestureLayer.LineData data)
+               {
+                       _currentPanGestureController.SendPan(_view, data.X2 - data.X1, data.Y2 - data.Y1, _currentPanGestureId);
+               }
+
+               void OnPanCompleted(GestureLayer.LineData data)
+               {
+                       _currentPanGestureController.SendPanCompleted(_view, _currentPanGestureId);
+               }
+
+               void OnPanCancelled(GestureLayer.LineData data)
+               {
+                       // don't trust ElmSharp that the gesture has been aborted, report that it is completed
+                       _currentPanGestureController.SendPanCompleted(_view, _currentPanGestureId);
+               }
+
+               void OnPinchStarted(GestureLayer.ZoomData data)
+               {
+                       var geometry = _renderer.NativeView.Geometry;
+                       _currentScalePoint = new Point((data.X - geometry.X) / (double)geometry.Width, (data.Y - geometry.Y) / (double)geometry.Height);
+                       _originalPinchScale = _view.Scale;
+                       _previousPinchRadius = data.Radius;
+                       _currentPinchGestureController.SendPinchStarted(_view, _currentScalePoint);
+               }
+
+               void OnPinchMoved(GestureLayer.ZoomData data)
+               {
+                       if (_previousPinchRadius <= 0)
+                               _previousPinchRadius = 1;
+                       // functionality limitation: _currentScalePoint is not updated
+                       _currentPinchGestureController.SendPinch(_view,
+                               1 + _originalPinchScale * (data.Radius - _previousPinchRadius) / _previousPinchRadius,
+                               _currentScalePoint
+                       );
+                       _previousPinchRadius = data.Radius;
+               }
+
+               void OnPinchCompleted(GestureLayer.ZoomData data)
+               {
+                       _currentPinchGestureController.SendPinchEnded(_view);
+               }
+
+               void OnPinchCancelled(GestureLayer.ZoomData data)
+               {
+                       // ElmSharp says the gesture has been aborted really too often, report completion instead
+                       _currentPinchGestureController.SendPinchEnded(_view);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Log/ConsoleLogger.cs b/Xamarin.Forms.Platform.Tizen/Log/ConsoleLogger.cs
new file mode 100644 (file)
index 0000000..19e46e9
--- /dev/null
@@ -0,0 +1,68 @@
+using System;
+using System.IO;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Logs a message to the console.
+       /// </summary>
+       internal class ConsoleLogger : ILogger
+       {
+               public void Debug(string tag, string message, string file, string func, int line)
+               {
+                       Print("D", tag, message, file, func, line);
+               }
+
+               public void Verbose(string tag, string message, string file, string func, int line)
+               {
+                       Print("V", tag, message, file, func, line);
+               }
+
+               public void Info(string tag, string message, string file, string func, int line)
+               {
+                       Print("I", tag, message, file, func, line);
+               }
+
+               public void Warn(string tag, string message, string file, string func, int line)
+               {
+                       Print("W", tag, message, file, func, line);
+               }
+
+               public void Error(string tag, string message, string file, string func, int line)
+               {
+                       Print("E", tag, message, file, func, line);
+               }
+
+               public void Fatal(string tag, string message, string file, string func, int line)
+               {
+                       Print("F", tag, message, file, func, line);
+               }
+
+               /// <summary>
+               /// Formats and prints the log information.
+               /// </summary>
+               /// <param name="level">Log level</param>
+               /// <param name="tag">Log tag</param>
+               /// <param name="message">Log message</param>
+               /// <param name="file">Full path to the file</param>
+               /// <param name="func">Function name</param>
+               /// <param name="line">Line number</param>
+               void Print(string level, string tag, string message, string file, string func, int line)
+               {
+                       Uri f = new Uri(file);
+                       Console.WriteLine(
+                               String.Format(
+                                       "\n[{6:yyyy-MM-dd HH:mm:ss.ffff} {0}/{1}]\n{2}: {3}({4}) > {5}",
+                                       level,  // 0
+                                       tag,  // 1
+                                       Path.GetFileName(f.AbsolutePath),  // 2
+                                       func,  // 3
+                                       line,  // 4
+                                       message,  // 5
+                                       DateTime.Now  // 6
+                               )
+                       );
+               }
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Log/DlogLogger.cs b/Xamarin.Forms.Platform.Tizen/Log/DlogLogger.cs
new file mode 100644 (file)
index 0000000..987a000
--- /dev/null
@@ -0,0 +1,41 @@
+using T = Tizen;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Logs a message to the dlog.
+       /// </summary>
+       internal class DlogLogger : ILogger
+       {
+               public void Debug(string tag, string message, string file, string func, int line)
+               {
+                       T.Log.Debug(tag, message, file, func, line);
+               }
+
+               public void Verbose(string tag, string message, string file, string func, int line)
+               {
+                       T.Log.Verbose(tag, message, file, func, line);
+               }
+
+               public void Info(string tag, string message, string file, string func, int line)
+               {
+                       T.Log.Info(tag, message, file, func, line);
+               }
+
+               public void Warn(string tag, string message, string file, string func, int line)
+               {
+                       T.Log.Warn(tag, message, file, func, line);
+               }
+
+               public void Error(string tag, string message, string file, string func, int line)
+               {
+                       T.Log.Error(tag, message, file, func, line);
+               }
+
+               public void Fatal(string tag, string message, string file, string func, int line)
+               {
+                       T.Log.Fatal(tag, message, file, func, line);
+               }
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Log/ILogger.cs b/Xamarin.Forms.Platform.Tizen/Log/ILogger.cs
new file mode 100644 (file)
index 0000000..6874641
--- /dev/null
@@ -0,0 +1,71 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Reports log messages with various log levels.
+       /// </summary>
+       internal interface ILogger
+       {
+               /// <summary>
+               /// Reports a debug log message.
+               /// </summary>
+               /// <param name="tag">Log tag</param>
+               /// <param name="message">Log message</param>
+               /// <param name="file">Full path to the file</param>
+               /// <param name="func">Function name</param>
+               /// <param name="line">Line number</param>
+               void Debug(string tag, string message, string file, string func, int line);
+
+               /// <summary>
+               /// Reports a verbose log message.
+               /// </summary>
+               /// <param name="tag">Log tag</param>
+               /// <param name="message">Log message</param>
+               /// <param name="file">Full path to the file</param>
+               /// <param name="func">Function name</param>
+               /// <param name="line">Line number</param>
+               void Verbose(string tag, string message, string file, string func, int line);
+
+               /// <summary>
+               /// Reports an information log message.
+               /// </summary>
+               /// <param name="tag">Log tag</param>
+               /// <param name="message">Log message</param>
+               /// <param name="file">Full path to the file</param>
+               /// <param name="func">Function name</param>
+               /// <param name="line">Line number</param>
+               void Info(string tag, string message, string file, string func, int line);
+
+               /// <summary>
+               /// Reports a warning log message.
+               /// </summary>
+               /// <param name="tag">Log tag</param>
+               /// <param name="message">Log message</param>
+               /// <param name="file">Full path to the file</param>
+               /// <param name="func">Function name</param>
+               /// <param name="line">Line number</param>
+               void Warn(string tag, string message, string file, string func, int line);
+
+               /// <summary>
+               /// Reports an error log message.
+               /// </summary>
+               /// <param name="tag">Log tag</param>
+               /// <param name="message">Log message</param>
+               /// <param name="file">Full path to the file</param>
+               /// <param name="func">Function name</param>
+               /// <param name="line">Line number</param>
+               void Error(string tag, string message, string file, string func, int line);
+
+               /// <summary>
+               /// Reports a fatal error log message.
+               /// </summary>
+               /// <param name="tag">Log tag</param>
+               /// <param name="message">Log message</param>
+               /// <param name="file">Full path to the file</param>
+               /// <param name="func">Function name</param>
+               /// <param name="line">Line number</param>
+               void Fatal(string tag, string message, string file, string func, int line);
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Log/Log.cs b/Xamarin.Forms.Platform.Tizen/Log/Log.cs
new file mode 100644 (file)
index 0000000..3ebeb11
--- /dev/null
@@ -0,0 +1,989 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Provides logging functionality.
+       /// </summary>
+       internal static class Log
+       {
+               static String _tag = "Xamarin";
+
+               static ILogger _logger = IsTizen() ? (ILogger)new DlogLogger() : (ILogger)new ConsoleLogger();
+
+               /// <summary>
+               /// Gets or sets the log tag.
+               /// </summary>
+               public static String Tag
+               {
+                       get
+                       {
+                               return _tag;
+                       }
+                       set
+                       {
+                               _tag = value;
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the logger used to report messages.
+               /// It's DlogLogger on a Tizen platform, ConsoleLogger on any other.
+               /// </summary>
+               public static ILogger Logger
+               {
+                       get
+                       {
+                               return _logger;
+                       }
+                       set
+                       {
+                               _logger = value;
+                       }
+               }
+
+               public static void Debug(string message,
+                                                                Guardian _ = default(Guardian),
+                                                                [CallerFilePath] string file = "",
+                                                                [CallerMemberName] string func = "",
+                                                                [CallerLineNumber] int line = 0)
+               {
+                       _logger.Debug(_tag, message, file, func, line);
+               }
+
+               public static void Debug<T0>(string message,
+                                                                        T0 arg0,
+                                                                        Guardian _ = default(Guardian),
+                                                                        [CallerFilePath] string file = "",
+                                                                        [CallerMemberName] string func = "",
+                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Debug(String.Format(message, arg0), _, file, func, line);
+               }
+
+               public static void Debug<T0, T1>(string message,
+                                                                                T0 arg0,
+                                                                                T1 arg1,
+                                                                                Guardian _ = default(Guardian),
+                                                                                [CallerFilePath] string file = "",
+                                                                                [CallerMemberName] string func = "",
+                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Debug(String.Format(message, arg0, arg1), _, file, func, line);
+               }
+
+               public static void Debug<T0, T1, T2>(string message,
+                                                                                        T0 arg0,
+                                                                                        T1 arg1,
+                                                                                        T2 arg2,
+                                                                                        Guardian _ = default(Guardian),
+                                                                                        [CallerFilePath] string file = "",
+                                                                                        [CallerMemberName] string func = "",
+                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Debug(String.Format(message, arg0, arg1, arg2), _, file, func, line);
+               }
+
+               public static void Debug<T0, T1, T2, T3>(string message,
+                                                                                                T0 arg0,
+                                                                                                T1 arg1,
+                                                                                                T2 arg2,
+                                                                                                T3 arg3,
+                                                                                                Guardian _ = default(Guardian),
+                                                                                                [CallerFilePath] string file = "",
+                                                                                                [CallerMemberName] string func = "",
+                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Debug(String.Format(message, arg0, arg1, arg2, arg3), _, file, func, line);
+               }
+
+               public static void Debug<T0, T1, T2, T3, T4>(string message,
+                                                                                                        T0 arg0,
+                                                                                                        T1 arg1,
+                                                                                                        T2 arg2,
+                                                                                                        T3 arg3,
+                                                                                                        T4 arg4,
+                                                                                                        Guardian _ = default(Guardian),
+                                                                                                        [CallerFilePath] string file = "",
+                                                                                                        [CallerMemberName] string func = "",
+                                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Debug(String.Format(message, arg0, arg1, arg2, arg3, arg4), _, file, func, line);
+               }
+
+               public static void Debug<T0, T1, T2, T3, T4, T5>(string message,
+                                                                                                                T0 arg0,
+                                                                                                                T1 arg1,
+                                                                                                                T2 arg2,
+                                                                                                                T3 arg3,
+                                                                                                                T4 arg4,
+                                                                                                                T5 arg5,
+                                                                                                                Guardian _ = default(Guardian),
+                                                                                                                [CallerFilePath] string file = "",
+                                                                                                                [CallerMemberName] string func = "",
+                                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Debug(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5), _, file, func, line);
+               }
+
+               public static void Debug<T0, T1, T2, T3, T4, T5, T6>(string message,
+                                                                                                                        T0 arg0,
+                                                                                                                        T1 arg1,
+                                                                                                                        T2 arg2,
+                                                                                                                        T3 arg3,
+                                                                                                                        T4 arg4,
+                                                                                                                        T5 arg5,
+                                                                                                                        T6 arg6,
+                                                                                                                        Guardian _ = default(Guardian),
+                                                                                                                        [CallerFilePath] string file = "",
+                                                                                                                        [CallerMemberName] string func = "",
+                                                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Debug(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6), _, file, func, line);
+               }
+
+               public static void Debug<T0, T1, T2, T3, T4, T5, T6, T7>(string message,
+                                                                                                                                T0 arg0,
+                                                                                                                                T1 arg1,
+                                                                                                                                T2 arg2,
+                                                                                                                                T3 arg3,
+                                                                                                                                T4 arg4,
+                                                                                                                                T5 arg5,
+                                                                                                                                T6 arg6,
+                                                                                                                                T7 arg7,
+                                                                                                                                Guardian _ = default(Guardian),
+                                                                                                                                [CallerFilePath] string file = "",
+                                                                                                                                [CallerMemberName] string func = "",
+                                                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Debug(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7), _, file, func, line);
+               }
+
+               public static void Debug<T0, T1, T2, T3, T4, T5, T6, T7, T8>(string message,
+                                                                                                                                        T0 arg0,
+                                                                                                                                        T1 arg1,
+                                                                                                                                        T2 arg2,
+                                                                                                                                        T3 arg3,
+                                                                                                                                        T4 arg4,
+                                                                                                                                        T5 arg5,
+                                                                                                                                        T6 arg6,
+                                                                                                                                        T7 arg7,
+                                                                                                                                        T8 arg8,
+                                                                                                                                        Guardian _ = default(Guardian),
+                                                                                                                                        [CallerFilePath] string file = "",
+                                                                                                                                        [CallerMemberName] string func = "",
+                                                                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Debug(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), _, file, func, line);
+               }
+
+               public static void Debug<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(string message,
+                                                                                                                                                T0 arg0,
+                                                                                                                                                T1 arg1,
+                                                                                                                                                T2 arg2,
+                                                                                                                                                T3 arg3,
+                                                                                                                                                T4 arg4,
+                                                                                                                                                T5 arg5,
+                                                                                                                                                T6 arg6,
+                                                                                                                                                T7 arg7,
+                                                                                                                                                T8 arg8,
+                                                                                                                                                T9 arg9,
+                                                                                                                                                Guardian _ = default(Guardian),
+                                                                                                                                                [CallerFilePath] string file = "",
+                                                                                                                                                [CallerMemberName] string func = "",
+                                                                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Debug(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), _, file, func, line);
+               }
+
+               public static void Verbose(string message,
+                                                                  Guardian _ = default(Guardian),
+                                                                  [CallerFilePath] string file = "",
+                                                                  [CallerMemberName] string func = "",
+                                                                  [CallerLineNumber] int line = 0)
+               {
+                       _logger.Verbose(_tag, message, file, func, line);
+               }
+
+               public static void Verbose<T0>(string message,
+                                                                          T0 arg0,
+                                                                          Guardian _ = default(Guardian),
+                                                                          [CallerFilePath] string file = "",
+                                                                          [CallerMemberName] string func = "",
+                                                                          [CallerLineNumber] int line = 0)
+               {
+                       Verbose(String.Format(message, arg0), _, file, func, line);
+               }
+
+               public static void Verbose<T0, T1>(string message,
+                                                                                  T0 arg0,
+                                                                                  T1 arg1,
+                                                                                  Guardian _ = default(Guardian),
+                                                                                  [CallerFilePath] string file = "",
+                                                                                  [CallerMemberName] string func = "",
+                                                                                  [CallerLineNumber] int line = 0)
+               {
+                       Verbose(String.Format(message, arg0, arg1), _, file, func, line);
+               }
+
+               public static void Verbose<T0, T1, T2>(string message,
+                                                                                          T0 arg0,
+                                                                                          T1 arg1,
+                                                                                          T2 arg2,
+                                                                                          Guardian _ = default(Guardian),
+                                                                                          [CallerFilePath] string file = "",
+                                                                                          [CallerMemberName] string func = "",
+                                                                                          [CallerLineNumber] int line = 0)
+               {
+                       Verbose(String.Format(message, arg0, arg1, arg2), _, file, func, line);
+               }
+
+               public static void Verbose<T0, T1, T2, T3>(string message,
+                                                                                                  T0 arg0,
+                                                                                                  T1 arg1,
+                                                                                                  T2 arg2,
+                                                                                                  T3 arg3,
+                                                                                                  Guardian _ = default(Guardian),
+                                                                                                  [CallerFilePath] string file = "",
+                                                                                                  [CallerMemberName] string func = "",
+                                                                                                  [CallerLineNumber] int line = 0)
+               {
+                       Verbose(String.Format(message, arg0, arg1, arg2, arg3), _, file, func, line);
+               }
+
+               public static void Verbose<T0, T1, T2, T3, T4>(string message,
+                                                                                                          T0 arg0,
+                                                                                                          T1 arg1,
+                                                                                                          T2 arg2,
+                                                                                                          T3 arg3,
+                                                                                                          T4 arg4,
+                                                                                                          Guardian _ = default(Guardian),
+                                                                                                          [CallerFilePath] string file = "",
+                                                                                                          [CallerMemberName] string func = "",
+                                                                                                          [CallerLineNumber] int line = 0)
+               {
+                       Verbose(String.Format(message, arg0, arg1, arg2, arg3, arg4), _, file, func, line);
+               }
+
+               public static void Verbose<T0, T1, T2, T3, T4, T5>(string message,
+                                                                                                                  T0 arg0,
+                                                                                                                  T1 arg1,
+                                                                                                                  T2 arg2,
+                                                                                                                  T3 arg3,
+                                                                                                                  T4 arg4,
+                                                                                                                  T5 arg5,
+                                                                                                                  Guardian _ = default(Guardian),
+                                                                                                                  [CallerFilePath] string file = "",
+                                                                                                                  [CallerMemberName] string func = "",
+                                                                                                                  [CallerLineNumber] int line = 0)
+               {
+                       Verbose(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5), _, file, func, line);
+               }
+
+               public static void Verbose<T0, T1, T2, T3, T4, T5, T6>(string message,
+                                                                                                                          T0 arg0,
+                                                                                                                          T1 arg1,
+                                                                                                                          T2 arg2,
+                                                                                                                          T3 arg3,
+                                                                                                                          T4 arg4,
+                                                                                                                          T5 arg5,
+                                                                                                                          T6 arg6,
+                                                                                                                          Guardian _ = default(Guardian),
+                                                                                                                          [CallerFilePath] string file = "",
+                                                                                                                          [CallerMemberName] string func = "",
+                                                                                                                          [CallerLineNumber] int line = 0)
+               {
+                       Verbose(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6), _, file, func, line);
+               }
+
+               public static void Verbose<T0, T1, T2, T3, T4, T5, T6, T7>(string message,
+                                                                                                                                  T0 arg0,
+                                                                                                                                  T1 arg1,
+                                                                                                                                  T2 arg2,
+                                                                                                                                  T3 arg3,
+                                                                                                                                  T4 arg4,
+                                                                                                                                  T5 arg5,
+                                                                                                                                  T6 arg6,
+                                                                                                                                  T7 arg7,
+                                                                                                                                  Guardian _ = default(Guardian),
+                                                                                                                                  [CallerFilePath] string file = "",
+                                                                                                                                  [CallerMemberName] string func = "",
+                                                                                                                                  [CallerLineNumber] int line = 0)
+               {
+                       Verbose(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7), _, file, func, line);
+               }
+
+               public static void Verbose<T0, T1, T2, T3, T4, T5, T6, T7, T8>(string message,
+                                                                                                                                          T0 arg0,
+                                                                                                                                          T1 arg1,
+                                                                                                                                          T2 arg2,
+                                                                                                                                          T3 arg3,
+                                                                                                                                          T4 arg4,
+                                                                                                                                          T5 arg5,
+                                                                                                                                          T6 arg6,
+                                                                                                                                          T7 arg7,
+                                                                                                                                          T8 arg8,
+                                                                                                                                          Guardian _ = default(Guardian),
+                                                                                                                                          [CallerFilePath] string file = "",
+                                                                                                                                          [CallerMemberName] string func = "",
+                                                                                                                                          [CallerLineNumber] int line = 0)
+               {
+                       Verbose(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), _, file, func, line);
+               }
+
+               public static void Verbose<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(string message,
+                                                                                                                                                  T0 arg0,
+                                                                                                                                                  T1 arg1,
+                                                                                                                                                  T2 arg2,
+                                                                                                                                                  T3 arg3,
+                                                                                                                                                  T4 arg4,
+                                                                                                                                                  T5 arg5,
+                                                                                                                                                  T6 arg6,
+                                                                                                                                                  T7 arg7,
+                                                                                                                                                  T8 arg8,
+                                                                                                                                                  T9 arg9,
+                                                                                                                                                  Guardian _ = default(Guardian),
+                                                                                                                                                  [CallerFilePath] string file = "",
+                                                                                                                                                  [CallerMemberName] string func = "",
+                                                                                                                                                  [CallerLineNumber] int line = 0)
+               {
+                       Verbose(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), _, file, func, line);
+               }
+
+               public static void Info(string message,
+                                                               Guardian _ = default(Guardian),
+                                                               [CallerFilePath] string file = "",
+                                                               [CallerMemberName] string func = "",
+                                                               [CallerLineNumber] int line = 0)
+               {
+                       _logger.Info(_tag, message, file, func, line);
+               }
+
+               public static void Info<T0>(string message,
+                                                                       T0 arg0,
+                                                                       Guardian _ = default(Guardian),
+                                                                       [CallerFilePath] string file = "",
+                                                                       [CallerMemberName] string func = "",
+                                                                       [CallerLineNumber] int line = 0)
+               {
+                       Info(String.Format(message, arg0), _, file, func, line);
+               }
+
+               public static void Info<T0, T1>(string message,
+                                                                               T0 arg0,
+                                                                               T1 arg1,
+                                                                               Guardian _ = default(Guardian),
+                                                                               [CallerFilePath] string file = "",
+                                                                               [CallerMemberName] string func = "",
+                                                                               [CallerLineNumber] int line = 0)
+               {
+                       Info(String.Format(message, arg0, arg1), _, file, func, line);
+               }
+
+               public static void Info<T0, T1, T2>(string message,
+                                                                                       T0 arg0,
+                                                                                       T1 arg1,
+                                                                                       T2 arg2,
+                                                                                       Guardian _ = default(Guardian),
+                                                                                       [CallerFilePath] string file = "",
+                                                                                       [CallerMemberName] string func = "",
+                                                                                       [CallerLineNumber] int line = 0)
+               {
+                       Info(String.Format(message, arg0, arg1, arg2), _, file, func, line);
+               }
+
+               public static void Info<T0, T1, T2, T3>(string message,
+                                                                                               T0 arg0,
+                                                                                               T1 arg1,
+                                                                                               T2 arg2,
+                                                                                               T3 arg3,
+                                                                                               Guardian _ = default(Guardian),
+                                                                                               [CallerFilePath] string file = "",
+                                                                                               [CallerMemberName] string func = "",
+                                                                                               [CallerLineNumber] int line = 0)
+               {
+                       Info(String.Format(message, arg0, arg1, arg2, arg3), _, file, func, line);
+               }
+
+               public static void Info<T0, T1, T2, T3, T4>(string message,
+                                                                                                       T0 arg0,
+                                                                                                       T1 arg1,
+                                                                                                       T2 arg2,
+                                                                                                       T3 arg3,
+                                                                                                       T4 arg4,
+                                                                                                       Guardian _ = default(Guardian),
+                                                                                                       [CallerFilePath] string file = "",
+                                                                                                       [CallerMemberName] string func = "",
+                                                                                                       [CallerLineNumber] int line = 0)
+               {
+                       Info(String.Format(message, arg0, arg1, arg2, arg3, arg4), _, file, func, line);
+               }
+
+               public static void Info<T0, T1, T2, T3, T4, T5>(string message,
+                                                                                                               T0 arg0,
+                                                                                                               T1 arg1,
+                                                                                                               T2 arg2,
+                                                                                                               T3 arg3,
+                                                                                                               T4 arg4,
+                                                                                                               T5 arg5,
+                                                                                                               Guardian _ = default(Guardian),
+                                                                                                               [CallerFilePath] string file = "",
+                                                                                                               [CallerMemberName] string func = "",
+                                                                                                               [CallerLineNumber] int line = 0)
+               {
+                       Info(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5), _, file, func, line);
+               }
+
+               public static void Info<T0, T1, T2, T3, T4, T5, T6>(string message,
+                                                                                                                       T0 arg0,
+                                                                                                                       T1 arg1,
+                                                                                                                       T2 arg2,
+                                                                                                                       T3 arg3,
+                                                                                                                       T4 arg4,
+                                                                                                                       T5 arg5,
+                                                                                                                       T6 arg6,
+                                                                                                                       Guardian _ = default(Guardian),
+                                                                                                                       [CallerFilePath] string file = "",
+                                                                                                                       [CallerMemberName] string func = "",
+                                                                                                                       [CallerLineNumber] int line = 0)
+               {
+                       Info(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6), _, file, func, line);
+               }
+
+               public static void Info<T0, T1, T2, T3, T4, T5, T6, T7>(string message,
+                                                                                                                               T0 arg0,
+                                                                                                                               T1 arg1,
+                                                                                                                               T2 arg2,
+                                                                                                                               T3 arg3,
+                                                                                                                               T4 arg4,
+                                                                                                                               T5 arg5,
+                                                                                                                               T6 arg6,
+                                                                                                                               T7 arg7,
+                                                                                                                               Guardian _ = default(Guardian),
+                                                                                                                               [CallerFilePath] string file = "",
+                                                                                                                               [CallerMemberName] string func = "",
+                                                                                                                               [CallerLineNumber] int line = 0)
+               {
+                       Info(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7), _, file, func, line);
+               }
+
+               public static void Info<T0, T1, T2, T3, T4, T5, T6, T7, T8>(string message,
+                                                                                                                                       T0 arg0,
+                                                                                                                                       T1 arg1,
+                                                                                                                                       T2 arg2,
+                                                                                                                                       T3 arg3,
+                                                                                                                                       T4 arg4,
+                                                                                                                                       T5 arg5,
+                                                                                                                                       T6 arg6,
+                                                                                                                                       T7 arg7,
+                                                                                                                                       T8 arg8,
+                                                                                                                                       Guardian _ = default(Guardian),
+                                                                                                                                       [CallerFilePath] string file = "",
+                                                                                                                                       [CallerMemberName] string func = "",
+                                                                                                                                       [CallerLineNumber] int line = 0)
+               {
+                       Info(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), _, file, func, line);
+               }
+
+               public static void Info<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(string message,
+                                                                                                                                               T0 arg0,
+                                                                                                                                               T1 arg1,
+                                                                                                                                               T2 arg2,
+                                                                                                                                               T3 arg3,
+                                                                                                                                               T4 arg4,
+                                                                                                                                               T5 arg5,
+                                                                                                                                               T6 arg6,
+                                                                                                                                               T7 arg7,
+                                                                                                                                               T8 arg8,
+                                                                                                                                               T9 arg9,
+                                                                                                                                               Guardian _ = default(Guardian),
+                                                                                                                                               [CallerFilePath] string file = "",
+                                                                                                                                               [CallerMemberName] string func = "",
+                                                                                                                                               [CallerLineNumber] int line = 0)
+               {
+                       Info(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), _, file, func, line);
+               }
+
+               public static void Warn(string message,
+                                                               Guardian _ = default(Guardian),
+                                                               [CallerFilePath] string file = "",
+                                                               [CallerMemberName] string func = "",
+                                                               [CallerLineNumber] int line = 0)
+               {
+                       _logger.Warn(_tag, message, file, func, line);
+               }
+
+               public static void Warn<T0>(string message,
+                                                                       T0 arg0,
+                                                                       Guardian _ = default(Guardian),
+                                                                       [CallerFilePath] string file = "",
+                                                                       [CallerMemberName] string func = "",
+                                                                       [CallerLineNumber] int line = 0)
+               {
+                       Warn(String.Format(message, arg0), _, file, func, line);
+               }
+
+               public static void Warn<T0, T1>(string message,
+                                                                               T0 arg0,
+                                                                               T1 arg1,
+                                                                               Guardian _ = default(Guardian),
+                                                                               [CallerFilePath] string file = "",
+                                                                               [CallerMemberName] string func = "",
+                                                                               [CallerLineNumber] int line = 0)
+               {
+                       Warn(String.Format(message, arg0, arg1), _, file, func, line);
+               }
+
+               public static void Warn<T0, T1, T2>(string message,
+                                                                                       T0 arg0,
+                                                                                       T1 arg1,
+                                                                                       T2 arg2,
+                                                                                       Guardian _ = default(Guardian),
+                                                                                       [CallerFilePath] string file = "",
+                                                                                       [CallerMemberName] string func = "",
+                                                                                       [CallerLineNumber] int line = 0)
+               {
+                       Warn(String.Format(message, arg0, arg1, arg2), _, file, func, line);
+               }
+
+               public static void Warn<T0, T1, T2, T3>(string message,
+                                                                                               T0 arg0,
+                                                                                               T1 arg1,
+                                                                                               T2 arg2,
+                                                                                               T3 arg3,
+                                                                                               Guardian _ = default(Guardian),
+                                                                                               [CallerFilePath] string file = "",
+                                                                                               [CallerMemberName] string func = "",
+                                                                                               [CallerLineNumber] int line = 0)
+               {
+                       Warn(String.Format(message, arg0, arg1, arg2, arg3), _, file, func, line);
+               }
+
+               public static void Warn<T0, T1, T2, T3, T4>(string message,
+                                                                                                       T0 arg0,
+                                                                                                       T1 arg1,
+                                                                                                       T2 arg2,
+                                                                                                       T3 arg3,
+                                                                                                       T4 arg4,
+                                                                                                       Guardian _ = default(Guardian),
+                                                                                                       [CallerFilePath] string file = "",
+                                                                                                       [CallerMemberName] string func = "",
+                                                                                                       [CallerLineNumber] int line = 0)
+               {
+                       Warn(String.Format(message, arg0, arg1, arg2, arg3, arg4), _, file, func, line);
+               }
+
+               public static void Warn<T0, T1, T2, T3, T4, T5>(string message,
+                                                                                                               T0 arg0,
+                                                                                                               T1 arg1,
+                                                                                                               T2 arg2,
+                                                                                                               T3 arg3,
+                                                                                                               T4 arg4,
+                                                                                                               T5 arg5,
+                                                                                                               Guardian _ = default(Guardian),
+                                                                                                               [CallerFilePath] string file = "",
+                                                                                                               [CallerMemberName] string func = "",
+                                                                                                               [CallerLineNumber] int line = 0)
+               {
+                       Warn(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5), _, file, func, line);
+               }
+
+               public static void Warn<T0, T1, T2, T3, T4, T5, T6>(string message,
+                                                                                                                       T0 arg0,
+                                                                                                                       T1 arg1,
+                                                                                                                       T2 arg2,
+                                                                                                                       T3 arg3,
+                                                                                                                       T4 arg4,
+                                                                                                                       T5 arg5,
+                                                                                                                       T6 arg6,
+                                                                                                                       Guardian _ = default(Guardian),
+                                                                                                                       [CallerFilePath] string file = "",
+                                                                                                                       [CallerMemberName] string func = "",
+                                                                                                                       [CallerLineNumber] int line = 0)
+               {
+                       Warn(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6), _, file, func, line);
+               }
+
+               public static void Warn<T0, T1, T2, T3, T4, T5, T6, T7>(string message,
+                                                                                                                               T0 arg0,
+                                                                                                                               T1 arg1,
+                                                                                                                               T2 arg2,
+                                                                                                                               T3 arg3,
+                                                                                                                               T4 arg4,
+                                                                                                                               T5 arg5,
+                                                                                                                               T6 arg6,
+                                                                                                                               T7 arg7,
+                                                                                                                               Guardian _ = default(Guardian),
+                                                                                                                               [CallerFilePath] string file = "",
+                                                                                                                               [CallerMemberName] string func = "",
+                                                                                                                               [CallerLineNumber] int line = 0)
+               {
+                       Warn(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7), _, file, func, line);
+               }
+
+               public static void Warn<T0, T1, T2, T3, T4, T5, T6, T7, T8>(string message,
+                                                                                                                                       T0 arg0,
+                                                                                                                                       T1 arg1,
+                                                                                                                                       T2 arg2,
+                                                                                                                                       T3 arg3,
+                                                                                                                                       T4 arg4,
+                                                                                                                                       T5 arg5,
+                                                                                                                                       T6 arg6,
+                                                                                                                                       T7 arg7,
+                                                                                                                                       T8 arg8,
+                                                                                                                                       Guardian _ = default(Guardian),
+                                                                                                                                       [CallerFilePath] string file = "",
+                                                                                                                                       [CallerMemberName] string func = "",
+                                                                                                                                       [CallerLineNumber] int line = 0)
+               {
+                       Warn(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), _, file, func, line);
+               }
+
+               public static void Warn<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(string message,
+                                                                                                                                               T0 arg0,
+                                                                                                                                               T1 arg1,
+                                                                                                                                               T2 arg2,
+                                                                                                                                               T3 arg3,
+                                                                                                                                               T4 arg4,
+                                                                                                                                               T5 arg5,
+                                                                                                                                               T6 arg6,
+                                                                                                                                               T7 arg7,
+                                                                                                                                               T8 arg8,
+                                                                                                                                               T9 arg9,
+                                                                                                                                               Guardian _ = default(Guardian),
+                                                                                                                                               [CallerFilePath] string file = "",
+                                                                                                                                               [CallerMemberName] string func = "",
+                                                                                                                                               [CallerLineNumber] int line = 0)
+               {
+                       Warn(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), _, file, func, line);
+               }
+
+               public static void Error(string message,
+                                                                Guardian _ = default(Guardian),
+                                                                [CallerFilePath] string file = "",
+                                                                [CallerMemberName] string func = "",
+                                                                [CallerLineNumber] int line = 0)
+               {
+                       _logger.Error(_tag, message, file, func, line);
+               }
+
+               public static void Error<T0>(string message,
+                                                                        T0 arg0,
+                                                                        Guardian _ = default(Guardian),
+                                                                        [CallerFilePath] string file = "",
+                                                                        [CallerMemberName] string func = "",
+                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Error(String.Format(message, arg0), _, file, func, line);
+               }
+
+               public static void Error<T0, T1>(string message,
+                                                                                T0 arg0,
+                                                                                T1 arg1,
+                                                                                Guardian _ = default(Guardian),
+                                                                                [CallerFilePath] string file = "",
+                                                                                [CallerMemberName] string func = "",
+                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Error(String.Format(message, arg0, arg1), _, file, func, line);
+               }
+
+               public static void Error<T0, T1, T2>(string message,
+                                                                                        T0 arg0,
+                                                                                        T1 arg1,
+                                                                                        T2 arg2,
+                                                                                        Guardian _ = default(Guardian),
+                                                                                        [CallerFilePath] string file = "",
+                                                                                        [CallerMemberName] string func = "",
+                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Error(String.Format(message, arg0, arg1, arg2), _, file, func, line);
+               }
+
+               public static void Error<T0, T1, T2, T3>(string message,
+                                                                                                T0 arg0,
+                                                                                                T1 arg1,
+                                                                                                T2 arg2,
+                                                                                                T3 arg3,
+                                                                                                Guardian _ = default(Guardian),
+                                                                                                [CallerFilePath] string file = "",
+                                                                                                [CallerMemberName] string func = "",
+                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Error(String.Format(message, arg0, arg1, arg2, arg3), _, file, func, line);
+               }
+
+               public static void Error<T0, T1, T2, T3, T4>(string message,
+                                                                                                        T0 arg0,
+                                                                                                        T1 arg1,
+                                                                                                        T2 arg2,
+                                                                                                        T3 arg3,
+                                                                                                        T4 arg4,
+                                                                                                        Guardian _ = default(Guardian),
+                                                                                                        [CallerFilePath] string file = "",
+                                                                                                        [CallerMemberName] string func = "",
+                                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Error(String.Format(message, arg0, arg1, arg2, arg3, arg4), _, file, func, line);
+               }
+
+               public static void Error<T0, T1, T2, T3, T4, T5>(string message,
+                                                                                                                T0 arg0,
+                                                                                                                T1 arg1,
+                                                                                                                T2 arg2,
+                                                                                                                T3 arg3,
+                                                                                                                T4 arg4,
+                                                                                                                T5 arg5,
+                                                                                                                Guardian _ = default(Guardian),
+                                                                                                                [CallerFilePath] string file = "",
+                                                                                                                [CallerMemberName] string func = "",
+                                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Error(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5), _, file, func, line);
+               }
+
+               public static void Error<T0, T1, T2, T3, T4, T5, T6>(string message,
+                                                                                                                        T0 arg0,
+                                                                                                                        T1 arg1,
+                                                                                                                        T2 arg2,
+                                                                                                                        T3 arg3,
+                                                                                                                        T4 arg4,
+                                                                                                                        T5 arg5,
+                                                                                                                        T6 arg6,
+                                                                                                                        Guardian _ = default(Guardian),
+                                                                                                                        [CallerFilePath] string file = "",
+                                                                                                                        [CallerMemberName] string func = "",
+                                                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Error(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6), _, file, func, line);
+               }
+
+               public static void Error<T0, T1, T2, T3, T4, T5, T6, T7>(string message,
+                                                                                                                                T0 arg0,
+                                                                                                                                T1 arg1,
+                                                                                                                                T2 arg2,
+                                                                                                                                T3 arg3,
+                                                                                                                                T4 arg4,
+                                                                                                                                T5 arg5,
+                                                                                                                                T6 arg6,
+                                                                                                                                T7 arg7,
+                                                                                                                                Guardian _ = default(Guardian),
+                                                                                                                                [CallerFilePath] string file = "",
+                                                                                                                                [CallerMemberName] string func = "",
+                                                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Error(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7), _, file, func, line);
+               }
+
+               public static void Error<T0, T1, T2, T3, T4, T5, T6, T7, T8>(string message,
+                                                                                                                                        T0 arg0,
+                                                                                                                                        T1 arg1,
+                                                                                                                                        T2 arg2,
+                                                                                                                                        T3 arg3,
+                                                                                                                                        T4 arg4,
+                                                                                                                                        T5 arg5,
+                                                                                                                                        T6 arg6,
+                                                                                                                                        T7 arg7,
+                                                                                                                                        T8 arg8,
+                                                                                                                                        Guardian _ = default(Guardian),
+                                                                                                                                        [CallerFilePath] string file = "",
+                                                                                                                                        [CallerMemberName] string func = "",
+                                                                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Error(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), _, file, func, line);
+               }
+
+               public static void Error<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(string message,
+                                                                                                                                                T0 arg0,
+                                                                                                                                                T1 arg1,
+                                                                                                                                                T2 arg2,
+                                                                                                                                                T3 arg3,
+                                                                                                                                                T4 arg4,
+                                                                                                                                                T5 arg5,
+                                                                                                                                                T6 arg6,
+                                                                                                                                                T7 arg7,
+                                                                                                                                                T8 arg8,
+                                                                                                                                                T9 arg9,
+                                                                                                                                                Guardian _ = default(Guardian),
+                                                                                                                                                [CallerFilePath] string file = "",
+                                                                                                                                                [CallerMemberName] string func = "",
+                                                                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Error(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), _, file, func, line);
+               }
+
+               public static void Fatal(string message,
+                                                                Guardian _ = default(Guardian),
+                                                                [CallerFilePath] string file = "",
+                                                                [CallerMemberName] string func = "",
+                                                                [CallerLineNumber] int line = 0)
+               {
+                       _logger.Fatal(_tag, message, file, func, line);
+               }
+
+               public static void Fatal<T0>(string message,
+                                                                        T0 arg0,
+                                                                        Guardian _ = default(Guardian),
+                                                                        [CallerFilePath] string file = "",
+                                                                        [CallerMemberName] string func = "",
+                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Fatal(String.Format(message, arg0), _, file, func, line);
+               }
+
+               public static void Fatal<T0, T1>(string message,
+                                                                                T0 arg0,
+                                                                                T1 arg1,
+                                                                                Guardian _ = default(Guardian),
+                                                                                [CallerFilePath] string file = "",
+                                                                                [CallerMemberName] string func = "",
+                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Fatal(String.Format(message, arg0, arg1), _, file, func, line);
+               }
+
+               public static void Fatal<T0, T1, T2>(string message,
+                                                                                        T0 arg0,
+                                                                                        T1 arg1,
+                                                                                        T2 arg2,
+                                                                                        Guardian _ = default(Guardian),
+                                                                                        [CallerFilePath] string file = "",
+                                                                                        [CallerMemberName] string func = "",
+                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Fatal(String.Format(message, arg0, arg1, arg2), _, file, func, line);
+               }
+
+               public static void Fatal<T0, T1, T2, T3>(string message,
+                                                                                                T0 arg0,
+                                                                                                T1 arg1,
+                                                                                                T2 arg2,
+                                                                                                T3 arg3,
+                                                                                                Guardian _ = default(Guardian),
+                                                                                                [CallerFilePath] string file = "",
+                                                                                                [CallerMemberName] string func = "",
+                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Fatal(String.Format(message, arg0, arg1, arg2, arg3), _, file, func, line);
+               }
+
+               public static void Fatal<T0, T1, T2, T3, T4>(string message,
+                                                                                                        T0 arg0,
+                                                                                                        T1 arg1,
+                                                                                                        T2 arg2,
+                                                                                                        T3 arg3,
+                                                                                                        T4 arg4,
+                                                                                                        Guardian _ = default(Guardian),
+                                                                                                        [CallerFilePath] string file = "",
+                                                                                                        [CallerMemberName] string func = "",
+                                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Fatal(String.Format(message, arg0, arg1, arg2, arg3, arg4), _, file, func, line);
+               }
+
+               public static void Fatal<T0, T1, T2, T3, T4, T5>(string message,
+                                                                                                                T0 arg0,
+                                                                                                                T1 arg1,
+                                                                                                                T2 arg2,
+                                                                                                                T3 arg3,
+                                                                                                                T4 arg4,
+                                                                                                                T5 arg5,
+                                                                                                                Guardian _ = default(Guardian),
+                                                                                                                [CallerFilePath] string file = "",
+                                                                                                                [CallerMemberName] string func = "",
+                                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Fatal(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5), _, file, func, line);
+               }
+
+               public static void Fatal<T0, T1, T2, T3, T4, T5, T6>(string message,
+                                                                                                                        T0 arg0,
+                                                                                                                        T1 arg1,
+                                                                                                                        T2 arg2,
+                                                                                                                        T3 arg3,
+                                                                                                                        T4 arg4,
+                                                                                                                        T5 arg5,
+                                                                                                                        T6 arg6,
+                                                                                                                        Guardian _ = default(Guardian),
+                                                                                                                        [CallerFilePath] string file = "",
+                                                                                                                        [CallerMemberName] string func = "",
+                                                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Fatal(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6), _, file, func, line);
+               }
+
+               public static void Fatal<T0, T1, T2, T3, T4, T5, T6, T7>(string message,
+                                                                                                                                T0 arg0,
+                                                                                                                                T1 arg1,
+                                                                                                                                T2 arg2,
+                                                                                                                                T3 arg3,
+                                                                                                                                T4 arg4,
+                                                                                                                                T5 arg5,
+                                                                                                                                T6 arg6,
+                                                                                                                                T7 arg7,
+                                                                                                                                Guardian _ = default(Guardian),
+                                                                                                                                [CallerFilePath] string file = "",
+                                                                                                                                [CallerMemberName] string func = "",
+                                                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Fatal(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7), _, file, func, line);
+               }
+
+               public static void Fatal<T0, T1, T2, T3, T4, T5, T6, T7, T8>(string message,
+                                                                                                                                        T0 arg0,
+                                                                                                                                        T1 arg1,
+                                                                                                                                        T2 arg2,
+                                                                                                                                        T3 arg3,
+                                                                                                                                        T4 arg4,
+                                                                                                                                        T5 arg5,
+                                                                                                                                        T6 arg6,
+                                                                                                                                        T7 arg7,
+                                                                                                                                        T8 arg8,
+                                                                                                                                        Guardian _ = default(Guardian),
+                                                                                                                                        [CallerFilePath] string file = "",
+                                                                                                                                        [CallerMemberName] string func = "",
+                                                                                                                                        [CallerLineNumber] int line = 0)
+               {
+                       Fatal(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), _, file, func, line);
+               }
+
+               public static void Fatal<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(string message,
+                                                                                                                                                T0 arg0,
+                                                                                                                                                T1 arg1,
+                                                                                                                                                T2 arg2,
+                                                                                                                                                T3 arg3,
+                                                                                                                                                T4 arg4,
+                                                                                                                                                T5 arg5,
+                                                                                                                                                T6 arg6,
+                                                                                                                                                T7 arg7,
+                                                                                                                                                T8 arg8,
+                                                                                                                                                T9 arg9,
+                                                                                                                                                Guardian _ = default(Guardian),
+                                                                                                                                                [CallerFilePath] string file = "",
+                                                                                                                                                [CallerMemberName] string func = "",
+                                                                                                                                                [CallerLineNumber] int line = 0)
+               {
+                       Fatal(String.Format(message, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), _, file, func, line);
+               }
+
+               /// <summary>
+               /// Determines if Xamarin is running in a Tizen environment.
+               /// </summary>
+               /// <returns><c>true</c> if application is running on Tizen; otherwise, <c>false</c>.</returns>
+               static bool IsTizen()
+               {
+                       return System.IO.File.Exists("/etc/tizen-release");
+               }
+
+               /// <summary>
+               /// A helper class, it allows to separate optional parameters from non-optional ones.
+               /// In case of any compilation errors, please make sure you're not using
+               /// explicit <c>null</c> value as one of the parameters.
+               /// </summary>
+               internal struct Guardian
+               {
+               }
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Log/XamarinLogListener.cs b/Xamarin.Forms.Platform.Tizen/Log/XamarinLogListener.cs
new file mode 100644 (file)
index 0000000..02bdb0f
--- /dev/null
@@ -0,0 +1,20 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       internal class XamarinLogListener : LogListener
+       {
+               public XamarinLogListener()
+               {
+               }
+
+               #region implemented abstract members of LogListener
+
+               public override void Warning(string category, string message)
+               {
+                       Log.Warn("[{0}] {1}", category, message);
+               }
+
+               #endregion
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/Box.cs b/Xamarin.Forms.Platform.Tizen/Native/Box.cs
new file mode 100644 (file)
index 0000000..f22d27b
--- /dev/null
@@ -0,0 +1,67 @@
+using System;
+using ElmSharp;
+using EBox = ElmSharp.Box;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Extends the ElmSharp.Box class with functionality useful to Xamarin.Forms renderer.
+       /// </summary>
+       /// <remarks>
+       /// This class overrides the layout mechanism. Instead of using the native layout,
+       /// <c>LayoutUpdated</c> event is sent.
+       /// </remarks>
+       public class Box : EBox
+       {
+               /// <summary>
+               /// The last processed geometry of the Box which was reported from the native layer.
+               /// </summary>
+               Rect _previousGeometry;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.Box"/> class.
+               /// </summary>
+               /// <param name="parent">The parent EvasObject.</param>
+               public Box(EvasObject parent) : base(parent)
+               {
+                       Resized += (sender, e) => { NotifyOnLayout(); };
+                       SetLayoutCallback(() => { NotifyOnLayout(); });
+               }
+
+               /// <summary>
+               /// Notifies that the layout has been updated.
+               /// </summary>
+               public event EventHandler<LayoutEventArgs> LayoutUpdated;
+
+               /// <summary>
+               /// Triggers the <c>LayoutUpdated</c> event.
+               /// </summary>
+               /// <remarks>
+               /// This method is called whenever there is a possibility that the size and/or position has been changed.
+               /// </remarks>
+               void NotifyOnLayout()
+               {
+                       var g = Geometry;
+
+                       if (0 == g.Width || 0 == g.Height)
+                       {
+                               // ignore irrelevant dimensions
+                               return;
+                       }
+                       if (null != LayoutUpdated)
+                       {
+                               LayoutUpdated(this, new LayoutEventArgs()
+                                       {
+                                               HasChanged = g != _previousGeometry,
+                                               X = g.X,
+                                               Y = g.Y,
+                                               Width = g.Width,
+                                               Height = g.Height,
+                                       }
+                               );
+                       }
+
+                       _previousGeometry = g;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/Button.cs b/Xamarin.Forms.Platform.Tizen/Native/Button.cs
new file mode 100644 (file)
index 0000000..8f85da6
--- /dev/null
@@ -0,0 +1,303 @@
+using System;
+using ElmSharp;
+using EButton = ElmSharp.Button;
+using ESize = ElmSharp.Size;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Extends the EButton control, providing basic formatting features,
+       /// i.e. font color, size, additional image.
+       /// </summary>
+       public class Button : EButton, IMeasurable
+       {
+               /// <summary>
+               /// Holds the formatted text of the button.
+               /// </summary>
+               readonly Span _span = new Span();
+
+               /// <summary>
+               /// The internal padding of the button, helps to determine the size.
+               /// </summary>
+               readonly ESize _internalPadding;
+
+               /// <summary>
+               /// Optional image, if set will be drawn on the button.
+               /// </summary>
+               Image _image;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.Button"/> class.
+               /// </summary>
+               /// <param name="parent">Parent evas object.</param>
+               public Button(EvasObject parent) : base(parent)
+               {
+                       _internalPadding = GetInternalPadding();
+               }
+
+               /// <summary>
+               /// Gets or sets the button's text.
+               /// </summary>
+               /// <value>The text.</value>
+               public override string Text
+               {
+                       get
+                       {
+                               return _span.Text;
+                       }
+
+                       set
+                       {
+                               if (value != _span.Text)
+                               {
+                                       _span.Text = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the color of the text.
+               /// </summary>
+               /// <value>The color of the text.</value>
+               public EColor TextColor
+               {
+                       get
+                       {
+                               return _span.ForegroundColor;
+                       }
+
+                       set
+                       {
+                               if (!_span.ForegroundColor.Equals(value))
+                               {
+                                       _span.ForegroundColor = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the color of the text background.
+               /// </summary>
+               /// <value>The color of the text background.</value>
+               public EColor TextBackgroundColor
+               {
+                       get
+                       {
+                               return _span.BackgroundColor;
+                       }
+
+                       set
+                       {
+                               if (!_span.BackgroundColor.Equals(value))
+                               {
+                                       _span.BackgroundColor = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the font family.
+               /// </summary>
+               /// <value>The font family.</value>
+               public string FontFamily
+               {
+                       get
+                       {
+                               return _span.FontFamily;
+                       }
+
+                       set
+                       {
+                               if (value != _span.FontFamily)
+                               {
+                                       _span.FontFamily = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the font attributes.
+               /// </summary>
+               /// <value>The font attributes.</value>
+               public FontAttributes FontAttributes
+               {
+                       get
+                       {
+                               return _span.FontAttributes;
+                       }
+
+                       set
+                       {
+                               if (value != _span.FontAttributes)
+                               {
+                                       _span.FontAttributes = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the size of the font.
+               /// </summary>
+               /// <value>The size of the font.</value>
+               public double FontSize
+               {
+                       get
+                       {
+                               return _span.FontSize;
+                       }
+
+                       set
+                       {
+                               if (value != _span.FontSize)
+                               {
+                                       _span.FontSize = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the image to be displayed next to the button's text.
+               /// </summary>
+               /// <value>The image displayed on the button.</value>
+               public Image Image
+               {
+                       get
+                       {
+                               return _image;
+                       }
+
+                       set
+                       {
+                               if (value != _image)
+                               {
+                                       ApplyImage(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Implementation of the IMeasurable.Measure() method.
+               /// </summary>
+               public ESize Measure(int availableWidth, int availableHeight)
+               {
+                       var size = Geometry;
+
+                       // resize the control using the whole available width
+                       Resize(availableWidth, size.Height);
+
+                       // measure the button's text, use it as a hint for the size
+                       var rawSize = Native.TextHelper.GetRawTextBlockSize(this);
+                       var formattedSize = Native.TextHelper.GetFormattedTextBlockSize(this);
+
+                       // restore the original size
+                       Resize(size.Width, size.Height);
+
+                       var padding = _internalPadding;
+
+                       if (rawSize.Width > availableWidth)
+                       {
+                               // if the raw text width is larger than the available width, use
+                               // either formatted size or internal padding, whichever is bigger
+                               return new ESize()
+                               {
+                                       Width = Math.Max(padding.Width, formattedSize.Width),
+                                       Height = Math.Max(padding.Height, Math.Min(formattedSize.Height, Math.Max(rawSize.Height, availableHeight))),
+                               };
+                       }
+                       else
+                       {
+                               // otherwise use the formatted size along with padding
+                               return new ESize()
+                               {
+                                       Width = padding.Width + formattedSize.Width,
+                                       Height = Math.Max(padding.Height, formattedSize.Height),
+                               };
+                       }
+               }
+
+               /// <summary>
+               /// Applies the button's text and its style.
+               /// </summary>
+               void ApplyTextAndStyle()
+               {
+                       SetInternalTextAndStyle(_span.GetDecoratedText(), _span.GetStyle());
+               }
+
+               /// <summary>
+               /// Sets the button's internal text and its style.
+               /// </summary>
+               /// <param name="formattedText">Formatted text, supports HTML tags.</param>
+               /// <param name="textStyle">Style applied to the formattedText.</param>
+               void SetInternalTextAndStyle(string formattedText, string textStyle)
+               {
+                       string emission = "elm,state,text,visible";
+
+                       if (string.IsNullOrEmpty(formattedText))
+                       {
+                               formattedText = null;
+                               textStyle = null;
+                               emission = "elm,state,text,hidden";
+                       }
+
+                       base.Text = formattedText;
+
+                       var textblock = EdjeObject["elm.text"];
+
+                       if (textblock != null)
+                       {
+                               textblock.TextStyle = textStyle;
+                       }
+
+                       EdjeObject.EmitSignal(emission, "elm");
+               }
+
+               /// <summary>
+               /// Gets the internal padding of the button.
+               /// </summary>
+               /// <returns>The internal padding.</returns>
+               ESize GetInternalPadding()
+               {
+                       var edje = EdjeObject;
+
+                       return new ESize
+                       {
+                               Width = (edje["padding_top_left"]?.Geometry.Width ?? 64) + (edje["padding_bottom_right"]?.Geometry.Width ?? 64),
+                               Height = edje["bg"]?.Geometry.Height ?? 64
+                       };
+               }
+
+               /// <summary>
+               /// Applies the image to be displayed on the button. If value is <c>null</c>,
+               /// image will be removed.
+               /// </summary>
+               /// <param name="image">Image to be displayed or null.</param>
+               void ApplyImage(Image image)
+               {
+                       _image = image;
+
+                       SetInternalImage();
+               }
+
+               /// <summary>
+               /// Sets the internal image. If value is <c>null</c>, image will be removed.
+               /// </summary>
+               void SetInternalImage()
+               {
+                       if (_image == null)
+                       {
+                               SetPartContent("icon", null);
+                       }
+                       else
+                       {
+                               SetPartContent("icon", _image);
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/Canvas.cs b/Xamarin.Forms.Platform.Tizen/Native/Canvas.cs
new file mode 100644 (file)
index 0000000..c345abf
--- /dev/null
@@ -0,0 +1,109 @@
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// A Canvas provides a class which can be a container for other controls.
+       /// </summary>
+       /// <remarks>
+       /// This class is used as a container view for Layouts from Xamarin.Forms.Platform.Tizen framework.
+       /// It is used for implementing xamarin pages and layouts.
+       /// </remarks>
+       public class Canvas : Box, IContainable<EvasObject>
+       {
+               /// <summary>
+               /// The list of Views.
+               /// </summary>
+               readonly ObservableCollection<EvasObject> _children = new ObservableCollection<EvasObject>();
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.Canvas"/> class.
+               /// </summary>
+               /// <remarks>Canvas doesn't support replacing its children, this will be ignored.</remarks>
+               /// <param name="parent">Parent of this instance.</param>
+               public Canvas(EvasObject parent) : base(parent)
+               {
+                       _children.CollectionChanged += (o, e) =>
+                       {
+                               if (e.Action == NotifyCollectionChangedAction.Add)
+                               {
+                                       foreach (var v in e.NewItems)
+                                       {
+                                               var view = v as EvasObject;
+                                               if (null != view)
+                                               {
+                                                       OnAdd(view);
+                                               }
+                                       }
+                               }
+                               else if (e.Action == NotifyCollectionChangedAction.Remove)
+                               {
+                                       foreach (var v in e.OldItems)
+                                       {
+                                               var view = v as EvasObject;
+                                               if (null != view)
+                                               {
+                                                       OnRemove(view);
+                                               }
+                                       }
+                               }
+                               else if (e.Action == NotifyCollectionChangedAction.Reset)
+                               {
+                                       OnRemoveAll();
+                               }
+                       };
+               }
+
+               /// <summary>
+               /// Gets list of native elements that are placed in the canvas.
+               /// </summary>
+               public IList<EvasObject> Children
+               {
+                       get
+                       {
+                               return _children;
+                       }
+               }
+
+               /// <summary>
+               /// Provides destruction for native element and contained elements.
+               /// </summary>
+               protected override void OnUnrealize()
+               {
+                       foreach (var child in _children)
+                       {
+                               child.Unrealize();
+                       }
+
+                       base.OnUnrealize();
+               }
+
+               /// <summary>
+               /// Adds a new child to a container.
+               /// </summary>
+               /// <param name="view">Native element which will be added</param>
+               void OnAdd(EvasObject view)
+               {
+                       PackEnd(view);
+               }
+
+               /// <summary>
+               /// Removes a child from a container.
+               /// </summary>
+               /// <param name="view">Child element to be removed from canvas</param>
+               void OnRemove(EvasObject view)
+               {
+                       UnPack(view);
+               }
+
+               /// <summary>
+               /// Removes all children from a canvas.
+               /// </summary>
+               void OnRemoveAll()
+               {
+                       UnPackAll();
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/ContentPage.cs b/Xamarin.Forms.Platform.Tizen/Native/ContentPage.cs
new file mode 100644 (file)
index 0000000..32f24a0
--- /dev/null
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// A basic page which can hold a single view.
+       /// </summary>
+       public class ContentPage : Background, IContainable<EvasObject>
+       {
+               /// <summary>
+               /// The name of the part to be used when setting content.
+               /// </summary>
+               public const string ContentPartName = "overlay";
+
+               /// <summary>
+               /// Exposes the Children property, mapping it to the _canvas' Children property.
+               /// </summary>
+               public IList<EvasObject> Children => _canvas.Children;
+
+               /// <summary>
+               /// The canvas, used as a container for other objects.
+               /// </summary>
+               /// <remarks>
+               /// The canvas holds all the Views that the ContentPage is composed of.
+               /// </remarks>
+               internal Canvas _canvas;
+
+               /// <summary>
+               /// Initializes a new instance of the ContentPage class.
+               /// </summary>
+               public ContentPage(EvasObject parent) : base(parent)
+               {
+                       _canvas = new Canvas(this);
+                       SetPartContent(ContentPartName, _canvas);
+               }
+
+               /// <summary>
+               /// Gets or sets the title.
+               /// </summary>
+               /// <value>The current title.p</value>
+               public string Title
+               {
+                       get;
+                       set;
+               }
+
+               /// <summary>
+               /// Allows custom handling of events emitted when the layout has been updated.
+               /// </summary>
+               public event EventHandler<LayoutEventArgs> LayoutUpdated
+               {
+                       add
+                       {
+                               _canvas.LayoutUpdated += value;
+                       }
+                       remove
+                       {
+                               _canvas.LayoutUpdated -= value;
+                       }
+               }
+
+               /// <summary>
+               /// Handles the disposing of a ContentPage
+               /// </summary>
+               /// <remarks>
+               /// Takes the proper care of discarding the canvas, then calls the base method.
+               /// </remarks>
+               protected override void OnUnrealize()
+               {
+                       _canvas.Unrealize();
+                       base.OnUnrealize();
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/DateChangedEventArgs.cs b/Xamarin.Forms.Platform.Tizen/Native/DateChangedEventArgs.cs
new file mode 100644 (file)
index 0000000..c238e9e
--- /dev/null
@@ -0,0 +1,31 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Event arguments for <see cref="DatePicker.DateChanged"/> event.
+       /// </summary>
+       public class DateChangedEventArgs : EventArgs
+       {
+               /// <summary>
+               /// The date that was on the element at the time that the user selected it.
+               /// </summary>
+               public DateTime OldDate { get; private set; }
+
+               /// <summary>
+               /// The date that the user entered.
+               /// </summary>
+               public DateTime NewDate { get; private set; }
+
+               /// <summary>
+               /// Creates a new <see cref="DateChangedEventArgs"/> object that represents a change from <paramref name="oldDate"/> to <paramref name="newDate"/>.
+               /// </summary>
+               /// <param name="oldDate">Old date of <see cref="DatePicker"/>.</param>
+               /// <param name="newDate">Current date of <see cref="DatePicker"/>.</param>
+               public DateChangedEventArgs(DateTime oldDate, DateTime newDate)
+               {
+                       this.OldDate = oldDate;
+                       this.NewDate = newDate;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/DatePicker.cs b/Xamarin.Forms.Platform.Tizen/Native/DatePicker.cs
new file mode 100644 (file)
index 0000000..fabd526
--- /dev/null
@@ -0,0 +1,130 @@
+using System;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Extends the ElmSharp.DateTimeSelector class with functionality useful to renderer.
+       /// </summary>
+       public class DatePicker : DateTimeSelector
+       {
+               const string DateLayoutStyle = "date_layout";
+               const string DefaultEFLFormat = "%d/%b/%Y";
+               static readonly DateTime s_defaultMaximumDate = new DateTime(2037, 12, 31);
+               static readonly DateTime s_defaultMinimumDate = new DateTime(1970, 1, 1);
+               DateTime _date;
+               DateTime _maxDate;
+               DateTime _minDate;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="DatePicker"/> class.
+               /// </summary>
+               /// <param name="parent">The parent EvasObject.</param>
+               public DatePicker(EvasObject parent) : base(parent)
+               {
+                       SetFieldVisible(DateTimeFieldType.Hour, false);
+                       Style = DateLayoutStyle;
+                       ApplyDate(Date);
+                       ApplyMinDate(s_defaultMinimumDate);
+                       ApplyMaxDate(s_defaultMaximumDate);
+                       //TODO use date format currently set on the platform
+                       Format = DefaultEFLFormat;
+
+                       DateTimeChanged += (sender, e) =>
+                       {
+                               Date = e.NewDate;
+                       };
+               }
+
+               /// <summary>
+               /// Gets or sets the displayed date.
+               /// </summary>
+               public DateTime Date
+               {
+                       get
+                       {
+                               return _date;
+                       }
+                       set
+                       {
+                               if (_date != value)
+                               {
+                                       ApplyDate(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets of sets the highest date selectable for this <see cref="DatePicker"/>.
+               /// </summary>
+               /// <remarks>
+               /// Default value is 31st Dec, 2037.
+               /// </remarks>
+               public DateTime MaximumDate
+               {
+                       get
+                       {
+                               return _maxDate;
+                       }
+                       set
+                       {
+                               if (_maxDate != value)
+                               {
+                                       ApplyMaxDate(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets of sets the lowest date selectable for this <see cref="DatePicker"/>.
+               /// </summary>
+               /// <remarks>
+               /// Default value is 1st Jan, 1970.
+               /// </remarks>
+               public DateTime MinimumDate
+               {
+                       get
+                       {
+                               return _minDate;
+                       }
+                       set
+                       {
+                               if (_minDate != value)
+                               {
+                                       ApplyMinDate(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Sets the <c>DateTime</c> property according to the given <paramref name="date"/>.
+               /// </summary>
+               /// <param name="date">The date value to be applied to the date picker.</param>
+               void ApplyDate(DateTime date)
+               {
+                       _date = date;
+                       DateTime = date;
+               }
+
+               /// <summary>
+               /// Sets the <c>MaximumDateTime</c> property according to the given <paramref name="maxDate"/>.
+               /// </summary>
+               /// <param name="maxDate">The maximum date value to be applied to the date picker.</param>
+               void ApplyMaxDate(DateTime maxDate)
+               {
+                       _maxDate = maxDate;
+                       MaximumDateTime = maxDate;
+               }
+
+               /// <summary>
+               /// Sets the <c>MinimumDateTime</c> property according to the given <paramref name="minDate"/>.
+               /// </summary>
+               /// <param name="minDate">The minimum date value to be applied to the date picker.</param>
+               void ApplyMinDate(DateTime minDate)
+               {
+                       _minDate = minDate;
+                       MinimumDateTime = minDate;
+               }
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Native/DateTimePickerDialog.cs b/Xamarin.Forms.Platform.Tizen/Native/DateTimePickerDialog.cs
new file mode 100644 (file)
index 0000000..64b1b3b
--- /dev/null
@@ -0,0 +1,100 @@
+using System;
+using ElmSharp;
+using EButton = ElmSharp.Button;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       public class DateTimePickerDialog : Dialog
+       {
+               DateTimeSelector _dateTimePicker;
+               EvasObject _parent;
+
+               /// <summary>
+               /// Creates a dialog window.
+               /// </summary>
+               public DateTimePickerDialog(EvasObject parent) : base(parent)
+               {
+                       _parent = parent;
+                       Initialize();
+               }
+
+               /// <summary>
+               /// Occurs when the date of this dialog has changed.
+               /// </summary>
+               public event EventHandler<DateChangedEventArgs> DateTimeChanged;
+
+               /// <summary>
+               /// Gets the <see cref="DateTimePicker"/> contained in this dialog.
+               /// </summary>
+               public DateTimeSelector DateTimePicker
+               {
+                       get
+                       {
+                               return _dateTimePicker;
+                       }
+                       private set
+                       {
+                               if (_dateTimePicker != value)
+                               {
+                                       ApplyDateTimePicker(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Creates date picker in dialog window.
+               /// </summary>
+               public void InitializeDatePicker(DateTime date, DateTime minimumDate, DateTime maximumDate)
+               {
+                       var datePicker = new DatePicker(this)
+                       {
+                               Date = date,
+                               MinimumDate = minimumDate,
+                               MaximumDate = maximumDate
+                       };
+                       Content = DateTimePicker = datePicker;
+               }
+
+               /// <summary>
+               /// Creates time picker in dialog window.
+               /// </summary>
+               public void InitializeTimePicker(TimeSpan time, string format)
+               {
+                       var timePicker = new TimePicker(this)
+                       {
+                               Time = time,
+                               DateTimeFormat = format
+                       };
+                       Content = DateTimePicker = timePicker;
+               }
+
+               void ApplyDateTimePicker(DateTimeSelector dateTimePicker)
+               {
+                       _dateTimePicker = dateTimePicker;
+                       Content = _dateTimePicker;
+               }
+
+               void Initialize()
+               {
+                       //TODO need to add internationalization support
+                       PositiveButton = new EButton(_parent) { Text = "Set" };
+                       PositiveButton.Clicked += (s, e) =>
+                       {
+                               DateTime oldDate = DateTimePicker.DateTime;
+                               DateTimeChanged?.Invoke(this, new DateChangedEventArgs(oldDate, DateTimePicker.DateTime));
+                               Hide();
+                       };
+
+                       //TODO need to add internationalization support
+                       NegativeButton = new EButton(_parent) { Text = "Cancel" };
+                       NegativeButton.Clicked += (s, e) =>
+                       {
+                               Hide();
+                       };
+                       BackButtonPressed += (object s, EventArgs e) =>
+                       {
+                               Hide();
+                       };
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/Dialog.cs b/Xamarin.Forms.Platform.Tizen/Native/Dialog.cs
new file mode 100755 (executable)
index 0000000..e616ff5
--- /dev/null
@@ -0,0 +1,276 @@
+using System;
+using ElmSharp;
+using EButton = ElmSharp.Button;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Base class for Dialogs. 
+       /// A dialog is a small window that prompts the user to make a decision or enter additional information.
+       /// </summary>
+       public class Dialog : Popup
+       {
+               EButton _positiveButton;
+               EButton _neutralButton;
+               EButton _negativeButton;
+               EvasObject _content;
+               string _title;
+
+               /// <summary>
+               /// Creates a dialog window that uses the default dialog theme.
+               /// </summary>
+               public Dialog(EvasObject parent) : base(parent)
+               {
+                       Initialize();
+               }
+
+               /// <summary>
+               /// Occurs when the hardware Back button is pressed.
+               /// </summary>
+               public event EventHandler BackButtonPressed;
+
+               /// <summary>
+               /// Occurs whenever the dialog is first displayed.
+               /// </summary>
+               public event EventHandler Shown;
+
+               /// <summary>
+               /// Enumerates the three valid positions of a dialog button.
+               /// </summary>
+               enum ButtonPosition
+               {
+                       Positive,
+                       Neutral,
+                       Negative
+               }
+
+               /// <summary>
+               /// Gets or sets the title of the dialog
+               /// </summary>
+               public string Title
+               {
+                       get
+                       {
+                               return _title;
+                       }
+                       set
+                       {
+                               if (_title != value)
+                               {
+                                       ApplyTitle(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the content to display in that dialog.
+               /// </summary>
+               public EvasObject Content
+               {
+                       get
+                       {
+                               return _content;
+                       }
+                       set
+                       {
+                               if (_content != value)
+                               {
+                                       ApplyContent(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the positive button used in the dialog
+               /// </summary>
+               public EButton PositiveButton
+               {
+                       get
+                       {
+                               return _positiveButton;
+                       }
+                       set
+                       {
+                               if (_positiveButton != value)
+                               {
+                                       ApplyButton(ButtonPosition.Positive, value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the neutral button used in the dialog
+               /// </summary>
+               public EButton NeutralButton
+               {
+                       get
+                       {
+                               return _neutralButton;
+                       }
+                       set
+                       {
+                               if (_neutralButton != value)
+                               {
+                                       ApplyButton(ButtonPosition.Neutral, value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the negative button used in the dialog
+               /// </summary>
+               public EButton NegativeButton
+               {
+                       get
+                       {
+                               return _negativeButton;
+                       }
+                       set
+                       {
+                               if (_negativeButton != value)
+                               {
+                                       ApplyButton(ButtonPosition.Negative, value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Starts the dialog and displays it on screen.
+               /// </summary>
+               public new void Show()
+               {
+                       base.Show();
+                       Shown?.Invoke(this, EventArgs.Empty);
+               }
+
+               /// <summary>
+               /// Handles the disposing of a dialog widget.
+               /// </summary>
+               protected override void OnUnrealize()
+               {
+                       _content?.Unrealize();
+
+                       ApplyButton(ButtonPosition.Positive, null);
+                       ApplyButton(ButtonPosition.Neutral, null);
+                       ApplyButton(ButtonPosition.Negative, null);
+                       ApplyContent(null);
+
+                       UngrabBackKey();
+
+                       base.OnUnrealize();
+               }
+
+               /// <summary>
+               /// Called when the dialog is shown.
+               /// </summary>
+               /// <remarks>When shown, the dialog will register itself for the back key press event handling.</remarks>
+               protected virtual void OnShown()
+               {
+                       GrabBackKey();
+               }
+
+               /// <summary>
+               /// Called when the dialog is dismissed.
+               /// </summary>
+               /// <remarks>When dismissed, the dialog will unregister itself from the back key press event handling.</remarks>
+               protected virtual void OnDismissed()
+               {
+                       UngrabBackKey();
+               }
+
+               /// <summary>
+               /// Handles the initialization process.
+               /// </summary>
+               /// <remarks>Creates handlers for vital events</remarks>
+               void Initialize()
+               {
+                       // Adds a handler for the Dismissed event.
+                       // In effect, unregisters this instance from being affected by the hardware back key presses.
+                       Dismissed += (s, e) =>
+                       {
+                               OnDismissed();
+                       };
+
+                       // Adds a handler for the Shown event.
+                       // In effect, registers this instance to be affected by the hardware back key presses.
+                       Shown += (s, e) =>
+                       {
+                               OnShown();
+                       };
+
+                       // Adds a handler for the KeyUp event.
+                       // The handler checks whether the key just pressed is a back key
+                       // and if that is the case, invokes the back button press handler of this instance.
+                       KeyUp += (s, e) =>
+                       {
+                               if (e.KeyName == EvasKeyEventArgs.PlatformBackButtonName)
+                                       BackButtonPressed?.Invoke(this, EventArgs.Empty);
+                       };
+               }
+
+               /// <summary>
+               /// Changes the dialog title.
+               /// </summary>
+               /// <param name="title">New dialog title.</param>
+               void ApplyTitle(string title)
+               {
+                       _title = title;
+
+                       SetPartText("title,text", _title);
+               }
+
+               /// <summary>
+               /// Puts the button in one of the three available slots.
+               /// </summary>
+               /// <param name="position">The slot to be occupied by the button expressed as a <see cref="ButtonPosition"/></param>
+               /// <param name="button">The new button.</param>
+               void ApplyButton(ButtonPosition position, EButton button)
+               {
+                       switch (position)
+                       {
+                               case ButtonPosition.Positive:
+                                       _positiveButton = button;
+                                       SetPartContent("button3", _positiveButton, true);
+                                       break;
+
+                               case ButtonPosition.Neutral:
+                                       _neutralButton = button;
+                                       SetPartContent("button2", _neutralButton, true);
+                                       break;
+
+                               case ButtonPosition.Negative:
+                                       _negativeButton = button;
+                                       SetPartContent("button1", _negativeButton, true);
+                                       break;
+                       }
+               }
+
+               /// <summary>
+               /// Updates the content of the dialog.
+               /// </summary>
+               /// <param name="content">New dialog content.</param>
+               void ApplyContent(EvasObject content)
+               {
+                       _content = content;
+
+                       SetPartContent("default", _content, true);
+               }
+
+               /// <summary>
+               /// Registers this instance to be affected by pressing the hardware back key.
+               /// </summary>
+               void GrabBackKey()
+               {
+                       KeyGrab(EvasKeyEventArgs.PlatformBackButtonName, true);
+               }
+
+               /// <summary>
+               /// Unregisters this instance from being affected by pressing the hardware back key.
+               /// </summary>
+               void UngrabBackKey()
+               {
+                       KeyUngrab(EvasKeyEventArgs.PlatformBackButtonName);
+               }
+
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/DisplayOrientations.cs b/Xamarin.Forms.Platform.Tizen/Native/DisplayOrientations.cs
new file mode 100644 (file)
index 0000000..efb0952
--- /dev/null
@@ -0,0 +1,36 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Enumeration for the orientation of a rectangular screen.
+       /// </summary>
+       [Flags]
+       public enum DisplayOrientations
+       {
+               /// <summary>
+               /// No display orientation is specified.
+               /// </summary>
+               None = 0,
+
+               /// <summary>
+               /// The display is oriented in a natural position.
+               /// </summary>
+               Portrait = 1,
+
+               /// <summary>
+               /// The display's left side is at the top.
+               /// </summary>
+               Landscape = 2,
+
+               /// <summary>
+               /// The display is upside down.
+               /// </summary>
+               PortraitFlipped = 4,
+
+               /// <summary>
+               /// The display's right side is at the top.
+               /// </summary>
+               LandscapeFlipped = 8
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/Entry.cs b/Xamarin.Forms.Platform.Tizen/Native/Entry.cs
new file mode 100644 (file)
index 0000000..808155c
--- /dev/null
@@ -0,0 +1,396 @@
+using System;
+using ElmSharp;
+using EEntry = ElmSharp.Entry;
+using EColor = ElmSharp.Color;
+using ESize = ElmSharp.Size;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Extends the Entry control, providing basic formatting features,
+       /// i.e. font color, size, placeholder.
+       /// </summary>
+       public class Entry : EEntry, IMeasurable
+       {
+               /// <summary>
+               /// Holds the formatted text of the entry.
+               /// </summary>
+               readonly Span _span = new Span();
+
+               /// <summary>
+               /// Holds the formatted text of the placeholder.
+               /// </summary>
+               readonly Span _placeholderSpan = new Span();
+
+               /// <summary>
+               /// Helps to detect whether the text change was initiated by the user
+               /// or via the Text property.
+               /// </summary>
+               int _changedByUserCallbackDepth;
+
+               /// <summary>
+               /// The type of the keyboard used by the entry.
+               /// </summary>
+               Keyboard _keyboard;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.Entry"/> class.
+               /// </summary>
+               /// <param name="parent">Parent evas object.</param>
+               public Entry(EvasObject parent) : base(parent)
+               {
+                       Scrollable = true;
+
+                       ChangedByUser += (s, e) =>
+                       {
+                               _changedByUserCallbackDepth++;
+
+                               Text = GetInternalText();
+
+                               _changedByUserCallbackDepth--;
+                       };
+
+                       ApplyKeyboard(Keyboard.Normal);
+               }
+
+               /// <summary>
+               /// Occurs when the text has changed.
+               /// </summary>
+               public event EventHandler<TextChangedEventArgs> TextChanged;
+
+               /// <summary>
+               /// Gets or sets the text.
+               /// </summary>
+               /// <value>The text.</value>
+               public override string Text
+               {
+                       get
+                       {
+                               return _span.Text;
+                       }
+
+                       set
+                       {
+                               if (value != _span.Text)
+                               {
+                                       var old = _span.Text;
+                                       _span.Text = value;
+                                       ApplyTextAndStyle();
+                                       Device.StartTimer(TimeSpan.FromTicks(1), () =>
+                                               {
+                                                       TextChanged?.Invoke(this, new TextChangedEventArgs(old, value));
+                                                       return false;
+                                               });
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the color of the text.
+               /// </summary>
+               /// <value>The color of the text.</value>
+               public EColor TextColor
+               {
+                       get
+                       {
+                               return _span.ForegroundColor;
+                       }
+
+                       set
+                       {
+                               if (!_span.ForegroundColor.Equals(value))
+                               {
+                                       _span.ForegroundColor = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the font family of the text and the placeholder.
+               /// </summary>
+               /// <value>The font family of the text and the placeholder.</value>
+               public string FontFamily
+               {
+                       get
+                       {
+                               return _span.FontFamily;
+                       }
+
+                       set
+                       {
+                               if (value != _span.FontFamily)
+                               {
+                                       _span.FontFamily = value;
+                                       ApplyTextAndStyle();
+
+                                       _placeholderSpan.FontFamily = value;
+                                       ApplyPlaceholderAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the font attributes of the text and the placeholder.
+               /// </summary>
+               /// <value>The font attributes of the text and the placeholder.</value>
+               public FontAttributes FontAttributes
+               {
+                       get
+                       {
+                               return _span.FontAttributes;
+                       }
+
+                       set
+                       {
+                               if (value != _span.FontAttributes)
+                               {
+                                       _span.FontAttributes = value;
+                                       ApplyTextAndStyle();
+
+                                       _placeholderSpan.FontAttributes = value;
+                                       ApplyPlaceholderAndStyle();
+                               }
+                       }
+               }
+
+
+               /// <summary>
+               /// Gets or sets the size of the font of both text and placeholder.
+               /// </summary>
+               /// <value>The size of the font of both text and placeholder.</value>
+               public double FontSize
+               {
+                       get
+                       {
+                               return _span.FontSize;
+                       }
+
+                       set
+                       {
+                               if (value != _span.FontSize)
+                               {
+                                       _span.FontSize = value;
+                                       ApplyTextAndStyle();
+
+                                       _placeholderSpan.FontSize = value;
+                                       ApplyPlaceholderAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the horizontal text alignment of both text and placeholder.
+               /// </summary>
+               /// <value>The horizontal text alignment of both text and placeholder.</value>
+               public TextAlignment HorizontalTextAlignment
+               {
+                       get
+                       {
+                               return _span.HorizontalTextAlignment;
+                       }
+
+                       set
+                       {
+                               if (value != _span.HorizontalTextAlignment)
+                               {
+                                       _span.HorizontalTextAlignment = value;
+                                       ApplyTextAndStyle();
+
+                                       _placeholderSpan.HorizontalTextAlignment = value;
+                                       ApplyPlaceholderAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the keyboard type used by the entry.
+               /// </summary>
+               /// <value>The keyboard type.</value>
+               public Keyboard Keyboard
+               {
+                       get
+                       {
+                               return _keyboard;
+                       }
+
+                       set
+                       {
+                               if (value != _keyboard)
+                               {
+                                       ApplyKeyboard(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the placeholder's text.
+               /// </summary>
+               /// <value>The placeholder's text.</value>
+               public string Placeholder
+               {
+                       get
+                       {
+                               return _placeholderSpan.Text;
+                       }
+
+                       set
+                       {
+                               if (value != _placeholderSpan.Text)
+                               {
+                                       _placeholderSpan.Text = value;
+                                       ApplyPlaceholderAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the color of the placeholder's text.
+               /// </summary>
+               /// <value>The color of the placeholder's text.</value>
+               public EColor PlaceholderColor
+               {
+                       get
+                       {
+                               return _placeholderSpan.ForegroundColor;
+                       }
+
+                       set
+                       {
+                               if (!_placeholderSpan.ForegroundColor.Equals(value))
+                               {
+                                       _placeholderSpan.ForegroundColor = value;
+                                       ApplyPlaceholderAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Implementation of the IMeasurable.Measure() method.
+               /// </summary>
+               public ESize Measure(int availableWidth, int availableHeight)
+               {
+                       var originalSize = Geometry;
+                       // resize the control using the whole available width
+                       Resize(availableWidth, originalSize.Height);
+
+                       ESize rawSize;
+                       ESize formattedSize;
+                       var edjeTextBlock = EdjeObject["elm.guide"];
+
+                       // if there's no text, but there's a placeholder, use it for measurements
+                       if (string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Placeholder) && edjeTextBlock != null)
+                       {
+                               rawSize = edjeTextBlock.TextBlockNativeSize;
+                               formattedSize = edjeTextBlock.TextBlockFormattedSize;
+                       }
+                       else
+                       {
+                               // there's text in the entry, use it instead
+                               rawSize = Native.TextHelper.GetRawTextBlockSize(this);
+                               formattedSize = Native.TextHelper.GetFormattedTextBlockSize(this);
+                       }
+
+                       // restore the original size
+                       Resize(originalSize.Width, originalSize.Height);
+
+                       // Set bottom padding for lower case letters that have segments below the bottom line of text (g, j, p, q, y).
+                       var verticalPadding = (int)Math.Ceiling(0.05 * FontSize);
+                       var horizontalPadding = (int)Math.Ceiling(0.2 * FontSize);
+                       rawSize.Height += verticalPadding;
+                       formattedSize.Height += verticalPadding;
+                       formattedSize.Width += horizontalPadding;
+
+                       // if the raw text width is larger than available width, we use the available width,
+                       // while height is set to the smallest height value
+                       if (rawSize.Width > availableWidth)
+                       {
+                               return new ESize
+                               {
+                                       Width = availableWidth,
+                                       Height = Math.Min(formattedSize.Height, Math.Max(rawSize.Height, availableHeight)),
+                               };
+                       }
+                       else
+                       {
+                               // width is fine, return the formatted text size
+                               return formattedSize;
+                       }
+               }
+
+               /// <summary>
+               /// Applies entry's text and its style.
+               /// </summary>
+               void ApplyTextAndStyle()
+               {
+                       SetInternalTextAndStyle(_span.GetDecoratedText(), _span.GetStyle());
+               }
+
+               /// <summary>
+               /// Sets entry's internal text and its style.
+               /// </summary>
+               /// <param name="formattedText">Formatted text, supports HTML tags.</param>
+               /// <param name="textStyle">Style applied to the formattedText.</param>
+               void SetInternalTextAndStyle(string formattedText, string textStyle)
+               {
+                       if (_changedByUserCallbackDepth == 0)
+                       {
+                               base.Text = formattedText;
+                               base.TextStyle = textStyle;
+                       }
+               }
+
+               /// <summary>
+               /// Gets the internal text representation of the entry.
+               /// </summary>
+               /// <returns>The internal text representation.</returns>
+               string GetInternalText()
+               {
+                       return Entry.ConvertMarkupToUtf8(base.Text);
+               }
+
+               /// <summary>
+               /// Applies the keyboard type to be used by the entry.
+               /// </summary>
+               /// <param name="keyboard">Keyboard type to be used.</param>
+               void ApplyKeyboard(Keyboard keyboard)
+               {
+                       SetInternalKeyboard(_keyboard = keyboard);
+               }
+
+               /// <summary>
+               /// Configures the ElmSharp.Entry with specified keyboard type and displays
+               /// the keyboard automatically unless the provided type is Keyboard.None.
+               /// </summary>
+               /// <param name="keyboard">Keyboard type to be used.</param>
+               void SetInternalKeyboard(Keyboard keyboard)
+               {
+                       if (keyboard == Keyboard.None)
+                       {
+                               SetInputPanelEnabled(false);
+                       }
+                       else
+                       {
+                               SetInputPanelEnabled(true);
+                               SetInputPanelLayout((InputPanelLayout)keyboard);
+                       }
+               }
+
+               /// <summary>
+               /// Applies placeholders's text and its style.
+               /// </summary>
+               void ApplyPlaceholderAndStyle()
+               {
+                       SetInternalPlaceholderAndStyle(_placeholderSpan.GetMarkupText());
+               }
+
+               /// <summary>
+               /// Sets placeholder's internal text and style.
+               /// </summary>
+               /// <param name="markupText">Markup text to be used as a placeholder.</param>
+               void SetInternalPlaceholderAndStyle(string markupText)
+               {
+                       SetPartText("guide", markupText ?? "");
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/FormattedString.cs b/Xamarin.Forms.Platform.Tizen/Native/FormattedString.cs
new file mode 100644 (file)
index 0000000..f782efd
--- /dev/null
@@ -0,0 +1,128 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Represents a text with attributes applied to some parts.
+       /// </summary>
+       /// <remarks>
+       /// Formatted string consists of spans that represent text segments with various attributes applied.
+       /// </remarks>
+       public class FormattedString
+       {
+               /// <summary>
+               /// A flag indicating whether the instance contains just a plain string without any formatting.
+               /// </summary>
+               /// <remarks>
+               /// <c>true</c> if the instance contains an unformatted string.
+               /// </remarks>
+               readonly bool _just_string;
+
+               /// <summary>
+               /// Holds the unformatted string.
+               /// </summary>
+               /// <remarks>
+               /// The contents of this field are accurate if and only if the _just_string flag is set.
+               /// </remarks>
+               readonly string _string;
+
+               /// <summary>
+               /// Holds the collection of span elements.
+               /// </summary>
+               /// <remarks>
+               /// Span elements are basically chunks of text with uniform formatting.
+               /// </remarks>
+               readonly ObservableCollection<Span> _spans;
+
+               /// <summary>
+               /// Returns the collection of span elements.
+               /// </summary>
+               public IList<Span> Spans { get { return _spans; } }
+
+               /// <summary>
+               /// Creates a new FormattedString instance with an empty string.
+               /// </summary>
+               public FormattedString()
+               {
+                       _just_string = false;
+                       _spans = new ObservableCollection<Span>();
+               }
+
+               /// <summary>
+               /// Creates a new FormattedString instance based on given <c>str</c>.
+               /// </summary>
+               /// <param name="str">
+               /// A string used to make a new FormattedString instance.
+               /// </param>
+               public FormattedString(string str)
+               {
+                       _just_string = true;
+                       _string = str;
+               }
+
+               /// <summary>
+               /// Returns the plain text of the FormattedString as an unformatted string.
+               /// </summary>
+               /// <returns>
+               /// The text content of the FormattedString without any format applied.
+               /// </returns>
+               public override string ToString()
+               {
+                       if (_just_string)
+                       {
+                               return _string;
+                       }
+                       else
+                       {
+                               return string.Concat(from span in this.Spans select span.Text);
+                       }
+               }
+
+               /// <summary>
+               /// Returns the markup text representation of the FormattedString instance.
+               /// </summary>
+               /// <returns>The string containing a markup text.</returns>
+               internal string ToMarkupString()
+               {
+                       if (_just_string)
+                       {
+                               return _string;
+                       }
+                       else
+                       {
+                               return string.Concat(from span in this.Spans select span.GetMarkupText());
+                       }
+               }
+
+               /// <summary>
+               /// Casts the FormattedString to a string.
+               /// </summary>
+               /// <param name="formatted">The FormattedString instance which will be used for the conversion.</param>
+               public static explicit operator string (FormattedString formatted)
+               {
+                       return formatted.ToString();
+               }
+
+               /// <summary>
+               /// Casts the string to a FormattedString.
+               /// </summary>
+               /// <param name="text">The text which will be put in a new FormattedString instance.</param>
+               public static implicit operator FormattedString(string text)
+               {
+                       return new FormattedString(text);
+               }
+
+               /// <summary>
+               /// Casts the Span to a FormattedString.
+               /// </summary>
+               /// <param name="span">The span which will be used for the conversion.</param>
+               public static implicit operator FormattedString(Span span)
+               {
+                       return new FormattedString()
+                       {
+                               Spans = { span }
+                       };
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/IContainable.cs b/Xamarin.Forms.Platform.Tizen/Native/IContainable.cs
new file mode 100644 (file)
index 0000000..dfee0cb
--- /dev/null
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Interface defining methods for managing elements of the container.
+       /// </summary>
+       /// <typeparam name="T">The type of element that can be added to the container.</typeparam>
+       public interface IContainable<T>
+       {
+               /// <summary>
+               /// The children collection of an element.
+               /// </summary>
+               IList<T> Children { get; }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/IMeasurable.cs b/Xamarin.Forms.Platform.Tizen/Native/IMeasurable.cs
new file mode 100644 (file)
index 0000000..13ee1c1
--- /dev/null
@@ -0,0 +1,20 @@
+using ESize = ElmSharp.Size;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Interface of the controls which can measure their size taking into
+       /// account the available area.
+       /// </summary>
+       public interface IMeasurable
+       {
+               /// <summary>
+               /// Measures the size of the control in order to fit it into the
+               /// available area.
+               /// </summary>
+               /// <param name="availableWidth">Available width.</param>
+               /// <param name="availableHeight">Available height.</param>
+               /// <returns>Size of the control that fits the available area.</returns>
+               ESize Measure(int availableWidth, int availableHeight);
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/ITextable.cs b/Xamarin.Forms.Platform.Tizen/Native/ITextable.cs
new file mode 100644 (file)
index 0000000..876646e
--- /dev/null
@@ -0,0 +1,68 @@
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Interface defining properties of formattable text.
+       /// </summary>
+       public interface ITextable
+       {
+               /// <summary>
+               /// Get or sets the formatted text.
+               /// </summary>
+               FormattedString FormattedText { get; set; }
+
+               /// <summary>
+               /// Gets or sets the text.
+               /// </summary>
+               string Text { get; set; }
+
+               /// <summary>
+               /// Gets or sets the color for the text.
+               /// </summary>
+               EColor TextColor { get; set; }
+
+               /// <summary>
+               /// Gets or sets the background color for the text.
+               /// </summary>
+               EColor TextBackgroundColor { get; set; }
+
+               /// <summary>
+               /// Gets or sets the font family for the text.
+               /// </summary>
+               string FontFamily { get; set; }
+
+               /// <summary>
+               /// Gets or sets the font attributes for the text.
+               /// See <see cref="FontAttributes"/> for information about FontAttributes.
+               /// </summary>
+               FontAttributes FontAttributes { get; set; }
+
+               /// <summary>
+               /// Gets or sets the font size for the text.
+               /// </summary>
+               double FontSize { get; set; }
+
+               /// <summary>
+               /// Gets or sets the horizontal alignment mode for the text.
+               /// See <see cref="TextAlignment"/> for information about TextAlignment.
+               /// </summary>
+               TextAlignment HorizontalTextAlignment { get; set; }
+
+               /// <summary>
+               /// Gets or sets the vertical alignment mode for the text.
+               /// See <see cref="TextAlignment"/> for information about TextAlignment.
+               /// </summary>
+               TextAlignment VerticalTextAlignment { get; set; }
+
+               /// <summary>
+               /// Gets or sets the value that indicates whether the text has underline.
+               /// </summary>
+               bool Underline { get; set; }
+
+               /// <summary>
+               /// Gets or sets the value that indicates whether the text has strike line though it.
+               /// </summary>
+               bool Strikethrough { get; set; }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/Image.cs b/Xamarin.Forms.Platform.Tizen/Native/Image.cs
new file mode 100644 (file)
index 0000000..7321c5b
--- /dev/null
@@ -0,0 +1,124 @@
+using System.Threading.Tasks;
+using ElmSharp;
+using EImage = ElmSharp.Image;
+using ESize = ElmSharp.Size;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Extends the ElmSharp.Image class with functionality useful to renderer.
+       /// </summary>
+       public class Image : EImage, IMeasurable
+       {
+               Aspect _aspect;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.Image"/> class.
+               /// </summary>
+               /// <param name="parent">The parent EvasObject.</param>
+               public Image(EvasObject parent) : base(parent)
+               {
+                       IsScaling = true;
+                       CanScaleUp = true;
+                       CanScaleDown = true;
+
+                       ApplyAspect(Aspect.AspectFit);
+               }
+
+               /// <summary>
+               /// Gets or sets the image aspect ratio preserving option.
+               /// </summary>
+               /// <value>The aspect option.</value>
+               public Aspect Aspect
+               {
+                       get
+                       {
+                               return _aspect;
+                       }
+
+                       set
+                       {
+                               if (_aspect != value)
+                               {
+                                       ApplyAspect(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Loads image data from the given <see cref="Xamarin.Forms.ImageSource"/> asynchronously.
+               /// </summary>
+               /// <returns>A task which will be completed when image data is loaded.</returns>
+               /// <param name="source">Image source specifying from where the image data has to be loaded.</param>
+               public Task<bool> LoadFromImageSourceAsync(ImageSource source)
+               {
+                       IImageSourceHandler handler;
+                       if (source != null && (handler = Registrar.Registered.GetHandler<IImageSourceHandler>(source.GetType())) != null)
+                       {
+                               return handler.LoadImageAsync(this, source);
+                       }
+                       return Task.FromResult<bool>(false);
+               }
+
+               /// <summary>
+               /// Implements the <see cref="Xamarin.Forms.Platform.Tizen.Native.IMeasurable"/> interface.
+               /// </summary>
+               /// <param name="availableWidth">Available width.</param>
+               /// <param name="availableHeight">Available height.</param>
+               public ESize Measure(int availableWidth, int availableHeight)
+               {
+                       var imageSize = ObjectSize;
+
+                       var size = new ESize()
+                       {
+                               Width = imageSize.Width,
+                               Height = imageSize.Height,
+                       };
+
+                       if (0 != availableWidth && 0 != availableHeight
+                               && (imageSize.Width > availableWidth || imageSize.Height > availableHeight))
+                       {
+                               // when available size is limited and insufficient for the image ...
+                               double imageRatio = (double)imageSize.Width / (double)imageSize.Height;
+                               double availableRatio = (double)availableWidth / (double)availableHeight;
+                               // depending on the relation between availableRatio and imageRatio, copy the availableWidth or availableHeight
+                               // and calculate the size which preserves the image ratio, but does not exceed the available size
+                               size.Width = availableRatio > imageRatio ? imageSize.Width * availableHeight / imageSize.Height : availableWidth;
+                               size.Height = availableRatio > imageRatio ? availableHeight : imageSize.Height * availableWidth / imageSize.Width;
+                       }
+
+                       return size;
+               }
+
+               /// <summary>
+               /// Sets the <c>IsFixedAspect</c> and <c>CanFillOutside</c> properties according to the given <paramref name="aspect"/>.
+               /// </summary>
+               /// <param name="aspect">The aspect setting to be applied to the image.</param>
+               void ApplyAspect(Aspect aspect)
+               {
+                       _aspect = aspect;
+
+                       switch (_aspect)
+                       {
+                               case Aspect.AspectFit:
+                                       IsFixedAspect = true;
+                                       CanFillOutside = false;
+                                       break;
+
+                               case Aspect.AspectFill:
+                                       IsFixedAspect = true;
+                                       CanFillOutside = true;
+                                       break;
+
+                               case Aspect.Fill:
+                                       IsFixedAspect = false;
+                                       CanFillOutside = false;
+                                       break;
+
+                               default:
+                                       Log.Warn("Invalid Aspect value: {0}", _aspect);
+                                       break;
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/Keyboard.cs b/Xamarin.Forms.Platform.Tizen/Native/Keyboard.cs
new file mode 100644 (file)
index 0000000..4223ca0
--- /dev/null
@@ -0,0 +1,84 @@
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Keyboard layout type on entry control.
+       /// </summary>
+       public enum Keyboard
+       {
+               /// <summary>
+               /// Disable Keyboard
+               /// </summary>
+               None = -1,
+
+               /// <summary>
+               /// Keyboard layout type default.
+               /// </summary>
+               Normal,
+
+               /// <summary>
+               /// Keyboard layout type number.
+               /// </summary>
+               Number,
+
+               /// <summary>
+               /// Keyboard layout type email.
+               /// </summary>
+               Email,
+
+               /// <summary>
+               /// Keyboard layout type url.
+               /// </summary>
+               Url,
+
+               /// <summary>
+               /// Keyboard layout type phone.
+               /// </summary>
+               PhoneNumber,
+
+               /// <summary>
+               /// Keyboard layout type ip.
+               /// </summary>
+               Ip,
+
+               /// <summary>
+               /// Keyboard layout type month.
+               /// </summary>
+               Month,
+
+               /// <summary>
+               /// Keyboard layout type number.
+               /// </summary>
+               NumberOnly,
+
+               /// <summary>
+               /// Keyboard layout type error type. Do not use it directly!
+               /// </summary>
+               Invalid,
+
+               /// <summary>
+               /// Keyboard layout type hexadecimal.
+               /// </summary>
+               Hex,
+
+               /// <summary>
+               /// Keyboard layout type terminal type, esc, alt, ctrl, etc.
+               /// </summary>
+               Terminal,
+
+               /// <summary>
+               /// Keyboard layout type password.
+               /// </summary>
+               Password,
+
+               /// <summary>
+               /// Keyboard layout type date and time.
+               /// </summary>
+               DateTime,
+
+               /// <summary>
+               /// Keyboard layout type emoticons.
+               /// </summary>
+               Emoticon
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Native/Label.cs b/Xamarin.Forms.Platform.Tizen/Native/Label.cs
new file mode 100644 (file)
index 0000000..cba2ba2
--- /dev/null
@@ -0,0 +1,347 @@
+using System;
+using ElmSharp;
+using ELabel = ElmSharp.Label;
+using EColor = ElmSharp.Color;
+using ESize = ElmSharp.Size;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// The Label class extends <c>ElmSharp.Label</c> to be better suited for Xamarin renderers.
+       /// Mainly the formatted text support.
+       /// </summary>
+       public class Label : ELabel, ITextable, IMeasurable
+       {
+               /// <summary>
+               /// The _span holds the content of the label.
+               /// </summary>
+               readonly Span _span = new Span();
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.Label"/> class.
+               /// </summary>
+               /// <param name="parent">Parent evas object.</param>
+               public Label(EvasObject parent) : base(parent)
+               {
+               }
+
+               /// <summary>
+               /// Get or sets the formatted text.
+               /// </summary>
+               /// <remarks>Setting <c>FormattedText</c> changes the value of the <c>Text</c> property.</remarks>
+               /// <value>The formatted text.</value>
+               public FormattedString FormattedText
+               {
+                       get
+                       {
+                               return _span.FormattedText;
+                       }
+
+                       set
+                       {
+                               if (value != _span.FormattedText)
+                               {
+                                       _span.FormattedText = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the text.
+               /// </summary>
+               /// <remarks>Setting <c>Text</c> overwrites the value of the <c>FormattedText</c> property too.</remarks>
+               /// <value>The content of the label.</value>
+               public override string Text
+               {
+                       get
+                       {
+                               return _span.Text;
+                       }
+
+                       set
+                       {
+                               if (value != _span.Text)
+                               {
+                                       _span.Text = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the color of the formatted text.
+               /// </summary>
+               /// <value>The color of the text.</value>
+               public EColor TextColor
+               {
+                       get
+                       {
+                               return _span.ForegroundColor;
+                       }
+
+                       set
+                       {
+                               if (!_span.ForegroundColor.Equals(value))
+                               {
+                                       _span.ForegroundColor = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the background color for the text.
+               /// </summary>
+               /// <value>The color of the label's background.</value>
+               public EColor TextBackgroundColor
+               {
+                       get
+                       {
+                               return _span.BackgroundColor;
+                       }
+
+                       set
+                       {
+                               if (!_span.BackgroundColor.Equals(value))
+                               {
+                                       _span.BackgroundColor = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the font family for the text.
+               /// </summary>
+               /// <value>The font family.</value>
+               public string FontFamily
+               {
+                       get
+                       {
+                               return _span.FontFamily;
+                       }
+
+                       set
+                       {
+                               if (value != _span.FontFamily)
+                               {
+                                       _span.FontFamily = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the font attributes.
+               /// </summary>
+               /// <value>The font attributes.</value>
+               public FontAttributes FontAttributes
+               {
+                       get
+                       {
+                               return _span.FontAttributes;
+                       }
+
+                       set
+                       {
+                               if (value != _span.FontAttributes)
+                               {
+                                       _span.FontAttributes = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the font size for the text.
+               /// </summary>
+               /// <value>The size of the font.</value>
+               public double FontSize
+               {
+                       get
+                       {
+                               return _span.FontSize;
+                       }
+
+                       set
+                       {
+                               if (value != _span.FontSize)
+                               {
+                                       _span.FontSize = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the line wrap option.
+               /// </summary>
+               /// <value>The line break mode.</value>
+               public LineBreakMode LineBreakMode
+               {
+                       get
+                       {
+                               return _span.LineBreakMode;
+                       }
+
+                       set
+                       {
+                               if (value != _span.LineBreakMode)
+                               {
+                                       _span.LineBreakMode = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the horizontal text alignment.
+               /// </summary>
+               /// <value>The horizontal text alignment.</value>
+               public TextAlignment HorizontalTextAlignment
+               {
+                       get
+                       {
+                               return _span.HorizontalTextAlignment;
+                       }
+
+                       set
+                       {
+                               if (value != _span.HorizontalTextAlignment)
+                               {
+                                       _span.HorizontalTextAlignment = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the vertical text alignment.
+               /// </summary>
+               /// <value>The vertical text alignment.</value>
+               public TextAlignment VerticalTextAlignment
+               {
+                       get
+                       {
+                               return _span.VerticalTextAlignment;
+                       }
+
+                       set
+                       {
+                               if (value != _span.VerticalTextAlignment)
+                               {
+                                       _span.VerticalTextAlignment = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the value that indicates whether the text is underlined.
+               /// </summary>
+               /// <value><c>true</c> if the text is underlined.</value>
+               public bool Underline
+               {
+                       get
+                       {
+                               return _span.Underline;
+                       }
+
+                       set
+                       {
+                               if (value != _span.Underline)
+                               {
+                                       _span.Underline = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the value that indicates whether the text is striked out.
+               /// </summary>
+               /// <value><c>true</c> if the text is striked out.</value>
+               public bool Strikethrough
+               {
+                       get
+                       {
+                               return _span.Strikethrough;
+                       }
+
+                       set
+                       {
+                               if (value != _span.Strikethrough)
+                               {
+                                       _span.Strikethrough = value;
+                                       ApplyTextAndStyle();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Implements <see cref="Xamarin.Forms.Platform.Tizen.Native.IMeasurable"/> to provide a desired size of the label.
+               /// </summary>
+               /// <param name="availableWidth">Available width.</param>
+               /// <param name="availableHeight">Available height.</param>
+               /// <returns>Size of the control that fits the available area.</returns>
+               public ESize Measure(int availableWidth, int availableHeight)
+               {
+                       var size = Geometry;
+
+                       Resize(availableWidth, size.Height);
+
+                       var rawSize = Native.TextHelper.GetRawTextBlockSize(this);
+                       var formattedSize = Native.TextHelper.GetFormattedTextBlockSize(this);
+                       Resize(size.Width, size.Height);
+
+                       // Set bottom padding for lower case letters that have segments below the bottom line of text (g, j, p, q, y).
+                       var verticalPadding = (int)Math.Ceiling(0.05 * FontSize);
+                       var horizontalPadding = (int)Math.Ceiling(0.2 * FontSize);
+                       rawSize.Height += verticalPadding;
+                       formattedSize.Height += verticalPadding;
+                       formattedSize.Width += horizontalPadding;
+
+                       if (rawSize.Width > availableWidth)
+                       {
+                               return new ESize()
+                               {
+                                       Width = formattedSize.Width,
+                                       Height = Math.Min(formattedSize.Height, Math.Max(rawSize.Height, availableHeight)),
+                               };
+                       }
+                       else
+                       {
+                               return formattedSize;
+                       }
+               }
+
+               void ApplyTextAndStyle()
+               {
+                       SetInternalTextAndStyle(_span.GetDecoratedText(), _span.GetStyle());
+               }
+
+               void SetInternalTextAndStyle(string formattedText, string textStyle)
+               {
+                       string emission = "elm,state,text,visible";
+
+                       if (string.IsNullOrEmpty(formattedText))
+                       {
+                               formattedText = null;
+                               textStyle = null;
+                               emission = "elm,state,text,hidden";
+                       }
+
+                       base.Text = formattedText;
+
+                       var textblock = EdjeObject["elm.text"];
+
+                       if (textblock != null)
+                       {
+                               textblock.TextStyle = textStyle;
+                       }
+
+                       EdjeObject.EmitSignal(emission, "elm");
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/LayoutEventArgs.cs b/Xamarin.Forms.Platform.Tizen/Native/LayoutEventArgs.cs
new file mode 100644 (file)
index 0000000..6668f8d
--- /dev/null
@@ -0,0 +1,55 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Holds information about size of the area which can be used for layout.
+       /// </summary>
+       public class LayoutEventArgs : EventArgs
+       {
+               /// <summary>
+               /// Whether or not the dimensions have changed.
+               /// </summary>
+               public bool HasChanged
+               {
+                       get;
+                       internal set;
+               }
+
+               /// <summary>
+               /// X coordinate of the layout area, relative to the main window.
+               /// </summary>
+               public int X
+               {
+                       get;
+                       internal set;
+               }
+
+               /// <summary>
+               /// Y coordinate of the layout area, relative to the main window.
+               /// </summary>
+               public int Y
+               {
+                       get;
+                       internal set;
+               }
+
+               /// <summary>
+               /// Width of the layout area.
+               /// </summary>
+               public int Width
+               {
+                       get;
+                       internal set;
+               }
+
+               /// <summary>
+               /// Height of the layout area.
+               /// </summary>
+               public int Height
+               {
+                       get;
+                       internal set;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/LineBreakMode.cs b/Xamarin.Forms.Platform.Tizen/Native/LineBreakMode.cs
new file mode 100644 (file)
index 0000000..27253ad
--- /dev/null
@@ -0,0 +1,43 @@
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Enumerates values that describe options for line braking.
+       /// </summary>
+       public enum LineBreakMode
+       {
+               /// <summary>
+               /// Do not wrap text.
+               /// </summary>
+               NoWrap,
+
+               /// <summary>
+               /// Wrap at character boundaries.
+               /// </summary>
+               CharacterWrap,
+
+               /// <summary>
+               /// Wrap at word boundaries.
+               /// </summary>
+               WordWrap,
+
+               /// <summary>
+               /// Tries to wrap at word boundaries, and then wrap at a character boundary if the word is too long.
+               /// </summary>
+               MixedWrap,
+
+               /// <summary>
+               /// Truncate the head of text.
+               /// </summary>
+               HeadTruncation,
+
+               /// <summary>
+               /// Truncate the middle of text. This may be done, for example, by replacing it with an ellipsis.
+               /// </summary>
+               MiddleTruncation,
+
+               /// <summary>
+               /// Truncate the tail of text.
+               /// </summary>
+               TailTruncation
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/ListView.cs b/Xamarin.Forms.Platform.Tizen/Native/ListView.cs
new file mode 100644 (file)
index 0000000..d5531dc
--- /dev/null
@@ -0,0 +1,601 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Type alias which identifies list of cells whose data model was transformed by Xamarin.
+       /// </summary>
+       using GroupList = TemplatedItemsList<ItemsView<Cell>, Cell>;
+
+       /// <summary>
+       /// Native ListView implementation for Xamarin renderer
+       /// </summary>
+       /// <remarks> 
+       /// This internally uses GenList class.
+       /// One should note that it is optimized for displaying many elements which may be
+       /// unavailable at first. This means that only currently visible elements will be constructed.
+       /// Whenever element disappears from visible space its content is destroyed for time being.
+       /// This is carried out by so called Cell Handlers.
+       /// </remarks>
+       public class ListView : GenList
+       {
+               /// <summary>
+               /// ItemContext helper class. This represents the association between Xamarin.Forms.Cell and
+               /// native elements. It also stores useful context for them.
+               /// </summary>
+               public class ItemContext
+               {
+                       public ItemContext()
+                       {
+                               Item = null;
+                               Cell = null;
+                               Renderer = null;
+                               ListOfSubItems = null;
+                       }
+
+                       public GenListItem Item;
+                       public Cell Cell;
+                       public bool IsGroupItem;
+                       public CellRenderer Renderer;
+                       internal TemplatedItemsList<ItemsView<Cell>, Cell> ListOfSubItems;
+               }
+
+               /// <summary>
+               /// The item context list for each added element.
+               /// </summary>
+               readonly List<ItemContext> _itemContextList = new List<ItemContext>();
+
+               /// <summary>
+               /// Registered cell handlers.
+               /// </summary>
+               protected readonly IDictionary<Type, CellRenderer> _cellRendererCache = new Dictionary<Type, CellRenderer>();
+
+               /// <summary>
+               /// Registered group handlers.
+               /// </summary>
+               protected readonly IDictionary<Type, CellRenderer> _groupCellRendererCache = new Dictionary<Type, CellRenderer>();
+
+               /// <summary>
+               /// The header context.
+               /// </summary>
+               ItemContext _headerContext;
+
+               /// <summary>
+               /// The header element.
+               /// </summary>
+               VisualElement _headerElement;
+
+               /// <summary>
+               /// The footer context.
+               /// </summary>
+               ItemContext _footerContext;
+
+               /// <summary>
+               /// The footer element.
+               /// </summary>
+               VisualElement _footerElement;
+
+               /// <summary>
+               /// The item class for header and footer.
+               /// </summary>
+               GenItemClass _headerFooterItemClass = null;
+
+               /// <summary>
+               /// Gets or sets a value indicating whether this instance has grouping enabled.
+               /// </summary>
+               /// <value><c>true</c> if this instance has grouping enabled.</value>
+               public bool IsGroupingEnabled { get; set; }
+
+               /// <summary>
+               /// Constructor of ListView native control.
+               /// </summary>
+               /// <param name="parent">ElmSharp object which is parent of particular list view</param>
+               public ListView(EvasObject parent)
+                       : base(parent)
+               {
+                       ItemRealized += OnItemAppear;
+                       ItemUnrealized += OnItemDisappear;
+               }
+
+               /// <summary>
+               /// Gets the item context based on Cell item.
+               /// </summary>
+               /// <returns>The item context.</returns>
+               /// <param name="cell">Cell for which context should be found.</param>
+               internal ItemContext GetItemContext(Cell cell)
+               {
+                       if (cell == null)
+                       {
+                               return null;
+                       }
+                       else
+                       {
+                               return _itemContextList.Find(X => X.Cell == cell);
+                       }
+               }
+
+               /// <summary>
+               /// Sets the HasUnevenRows property.
+               /// </summary>
+               /// <param name="hasUnevenRows">If <c>true</c>, the list will allow uneven sizes for its rows.</param>
+               public void SetHasUnevenRows(bool hasUnevenRows)
+               {
+                       Homogeneous = !hasUnevenRows;
+                       UpdateRealizedItems();
+               }
+
+               /// <summary>
+               /// Adds elements to the list and defines its presentation based on Cell type.
+               /// </summary>
+               /// <param name="_source">IEnumerable on Cell collection.</param>
+               /// <param name="beforeCell">Cell before which new items will be placed. 
+               /// Null value may also be passed as this parameter, which results in appending new items to the end.
+               /// </param>
+               public void AddSource(IEnumerable _source, Cell beforeCell = null)
+               {
+                       foreach (var data in _source)
+                       {
+                               GroupList groupList = data as GroupList;
+                               if (groupList != null)
+                               {
+                                       AddGroupItem(groupList, beforeCell);
+                                       foreach (var item in groupList)
+                                       {
+                                               AddItem(item as Cell, groupList.HeaderContent);
+                                       }
+                               }
+                               else
+                               {
+                                       AddItem(data as Cell, null, beforeCell);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Deletes all items from a given group.
+               /// </summary>
+               /// <param name="group">Group of items to be deleted.</param>
+               internal void ResetGroup(GroupList group)
+               {
+                       var items = _itemContextList.FindAll(x => x.ListOfSubItems == group && x.Cell != group.HeaderContent);
+                       foreach (var item in items)
+                       {
+                               item.Item?.Delete();
+                       }
+               }
+
+               /// <summary>
+               /// Adds items to the group.
+               /// </summary>
+               /// <param name="itemGroup">Group to which elements will be added.</param>
+               /// <param name="newItems">New list items to be added.</param>
+               /// <param name="cellBefore">A reference to the Cell already existing in a ListView.
+               ///  Newly added cells will be put just before this cell.</param>
+               public void AddItemsToGroup(IEnumerable itemGroup, IEnumerable newItems, Cell cellBefore = null)
+               {
+                       ItemContext groupCtx = GetItemContext((itemGroup as GroupList)?.HeaderContent);
+                       if (groupCtx != null)
+                       {
+                               foreach (var item in newItems)
+                               {
+                                       AddItem(item as Cell, groupCtx.Cell, cellBefore);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Removes the specified cells.
+               /// </summary>
+               /// <param name="cells">Cells to be removed.</param>
+               public void Remove(IEnumerable cells)
+               {
+                       foreach (var data in cells)
+                       {
+                               var group = data as GroupList;
+                               if (group != null)
+                               {
+                                       ItemContext groupCtx = GetItemContext(group.HeaderContent);
+                                       Remove(groupCtx.ListOfSubItems);
+                                       groupCtx.Item.Delete();
+                               }
+                               else
+                               {
+                                       ItemContext itemCtx = GetItemContext(data as Cell);
+                                       itemCtx?.Item?.Delete();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Scrolls the list to a specified cell.
+               /// </summary>
+               /// <remarks>
+               /// Different scrolling behaviors are also possible. The element may be positioned in the center,
+               /// top or bottom of the visible part of the list depending on the value of the <c>position</c> parameter.
+               /// </remarks>
+               /// <param name="cell">Cell which will be displayed after scrolling .</param>
+               /// <param name="position">This will defines scroll to behavior based on ScrollToPosition values.</param>
+               /// <param name="animated">If <c>true</c>, scrolling will be animated. Otherwise the cell will be moved instantaneously.</param>
+               public void ApplyScrollTo(Cell cell, ScrollToPosition position, bool animated)
+               {
+                       GenListItem item = GetItemContext(cell)?.Item;
+                       if (item != null)
+                               this.ScrollTo(item, position.ToNative(), animated);
+               }
+
+               /// <summary>
+               /// Selects the specified cell.
+               /// </summary>
+               /// <param name="cell">Cell to be selected.</param>
+               public void ApplySelectedItem(Cell cell)
+               {
+                       GenListItem item = GetItemContext(cell)?.Item;
+                       if (item != null)
+                               item.IsSelected = true;
+               }
+
+               /// <summary>
+               /// Sets the header.
+               /// </summary>
+               /// <param name="header">Header of the list.</param>
+               public void SetHeader(VisualElement header)
+               {
+                       if (header == null)
+                       {
+                               if (HasHeader())
+                               {
+                                       RemoveHeader();
+                               }
+
+                               return;
+                       }
+
+                       GenItemClass headerTemplate = GetHeaderFooterItemClass();
+
+                       _headerElement = header;
+                       if (HasHeader())
+                       {
+                               FirstItem.UpdateItemClass(headerTemplate, header);
+                       }
+                       else
+                       {
+                               _headerContext = new ItemContext();
+                               _headerContext.Item = _itemContextList.Count > 0 ? InsertBefore(headerTemplate, header, FirstItem) : Append(headerTemplate, header);
+                               _headerContext.Item.SelectionMode = GenListSelectionMode.None;
+                               _headerContext.Item.Deleted += HeaderDeletedHandler;
+                               _itemContextList.Insert(0, _headerContext);
+                       }
+               }
+
+               /// <summary>
+               /// Sets the footer.
+               /// </summary>
+               /// <param name="footer">Footer of the list.</param>
+               public void SetFooter(VisualElement footer)
+               {
+                       if (footer == null)
+                       {
+                               if (HasFooter())
+                               {
+                                       RemoveFooter();
+                               }
+                               return;
+                       }
+
+                       GenItemClass footerTemplate = GetHeaderFooterItemClass();
+
+                       _footerElement = footer;
+                       if (HasFooter())
+                       {
+                               _footerContext.Item.UpdateItemClass(footerTemplate, footer);
+                       }
+                       else
+                       {
+                               _footerContext = new ItemContext();
+                               _footerContext.Item = Append(footerTemplate, footer);
+                               _footerContext.Item.SelectionMode = GenListSelectionMode.None;
+                               _footerContext.Item.Deleted += FooterDeletedHandler;
+                               _itemContextList.Add(_footerContext);
+                       }
+               }
+
+               /// <summary>
+               /// Removes the header.
+               /// </summary>
+               public void RemoveHeader()
+               {
+                       _itemContextList.Remove(_headerContext);
+                       _headerContext?.Item?.Delete();
+                       _headerContext = null;
+                       _headerElement = null;
+               }
+
+               /// <summary>
+               /// Removes the footer.
+               /// </summary>
+               public void RemoveFooter()
+               {
+                       _itemContextList.Remove(_footerContext);
+                       _footerContext?.Item?.Delete();
+                       _footerContext = null;
+                       _footerElement = null;
+               }
+
+               /// <summary>
+               /// Determines whether this instance has a header.
+               /// </summary>
+               /// <returns><c>true</c> if the header is present.</returns>
+               public bool HasHeader()
+               {
+                       return _headerContext != null;
+               }
+
+               /// <summary>
+               /// Determines whether this instance has a footer.
+               /// </summary>
+               /// <returns><c>true</c> if the footer is present.</returns>
+               public bool HasFooter()
+               {
+                       return _footerContext != null;
+               }
+
+               /// <summary>
+               /// Gets the header.
+               /// </summary>
+               /// <returns>The header.</returns>
+               public VisualElement GetHeader()
+               {
+                       return _headerElement;
+               }
+
+               /// <summary>
+               /// Gets the footer.
+               /// </summary>
+               /// <returns>The footer.</returns>
+               public VisualElement GetFooter()
+               {
+                       return _footerElement;
+               }
+
+               /// <summary>
+               /// Handles the header deleted event.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="e">Empty argument.</param>
+               void HeaderDeletedHandler(object sender, EventArgs e)
+               {
+                       _itemContextList.Remove(_headerContext);
+                       _headerContext = null;
+               }
+
+               /// <summary>
+               /// Handles the footer deleted event.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="e">Empty argument.</param>
+               void FooterDeletedHandler(object sender, EventArgs e)
+               {
+                       _itemContextList.Remove(_footerContext);
+                       _footerContext = null;
+               }
+
+               /// <summary>
+               /// Called every time an object gets realized.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="evt">GenListItemEventArgs.</param>
+               void OnItemAppear(object sender, GenListItemEventArgs evt)
+               {
+                       ItemContext itemContext = (evt.Item.Data as ItemContext);
+
+                       if (itemContext != null && itemContext.Cell != null)
+                       {
+                               (itemContext.Cell as ICellController).SendAppearing();
+                       }
+               }
+
+               /// <summary>
+               /// Called every time an object gets unrealized.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="evt">GenListItemEventArgs.</param>
+               void OnItemDisappear(object sender, GenListItemEventArgs evt)
+               {
+                       ItemContext itemContext = (evt.Item.Data as ItemContext);
+                       if (itemContext != null && itemContext.Cell != null)
+                       {
+                               (itemContext.Cell as ICellController).SendDisappearing();
+                               itemContext.Renderer?.SendUnrealizedCell(itemContext.Cell);
+                       }
+               }
+
+
+               /// <summary>
+               /// A convenience shorthand method for derivate classes.
+               /// </summary>
+               /// <param name="cell">Cell to be added.</param>
+               protected void AddCell(Cell cell)
+               {
+                       AddItem(cell);
+               }
+
+               /// <summary>
+               /// Gets the cell renderer for given cell type.
+               /// </summary>
+               /// <returns>The cell handler.</returns>
+               /// <param name="cell">Cell to be added.</param>
+               /// <param name="isGroup">If <c>true</c>, then group handlers will be included in the lookup as well.</param>
+               protected virtual CellRenderer GetCellRenderer(Cell cell, bool isGroup = false)
+               {
+                       Type type = cell.GetType();
+                       var cache = isGroup ? _groupCellRendererCache : _cellRendererCache;
+                       if (cache.ContainsKey(type))
+                               return cache[type];
+
+                       CellRenderer renderer = null;
+
+                       if (isGroup && type == typeof(TextCell))
+                       {
+                               renderer = new GroupCellTextRenderer();
+                       }
+                       renderer = renderer ?? Registrar.Registered.GetHandler<CellRenderer>(type);
+
+                       if (renderer == null)
+                       {
+                               Log.Error("Cell type is not handled: {0}", cell.GetType());
+                               throw new ArgumentNullException("Unsupported cell type");
+                       }
+                       return cache[type] = renderer;
+               }
+
+               /// <summary>
+               /// Adds the group item. Group item is actually of class GroupList because
+               /// group item has sub items (can be zero) which needs to be added.
+               /// If beforeCell is not null, new group will be added just before it.
+               /// </summary>
+               /// <param name="groupList">Group to be added.</param>
+               /// <param name="beforeCell">Before cell.</param>
+               void AddGroupItem(GroupList groupList, Cell beforeCell = null)
+               {
+                       Cell groupCell = groupList.HeaderContent;
+                       CellRenderer groupRenderer = GetCellRenderer(groupCell, true);
+                       ItemContext groupItemContext = new ItemContext();
+                       groupItemContext.Cell = groupCell;
+                       groupItemContext.Renderer = groupRenderer;
+
+                       if (beforeCell != null)
+                       {
+                               GenListItem beforeItem = GetItemContext(beforeCell)?.Item;
+                               groupItemContext.Item = InsertBefore(groupRenderer.Class, groupItemContext, beforeItem, GenListItemType.Group);
+                       }
+                       else
+                       {
+                               groupItemContext.Item = Append(groupRenderer.Class, groupItemContext, GenListItemType.Group);
+                       }
+
+                       groupItemContext.Item.SelectionMode = GenListSelectionMode.None;
+                       groupItemContext.IsGroupItem = true;
+
+                       groupItemContext.ListOfSubItems = groupList;
+                       groupItemContext.Item.Deleted += ItemDeletedHandler;
+                       _itemContextList.Add(groupItemContext);
+               }
+
+               /// <summary>
+               /// Adds the item.
+               /// </summary>
+               /// <param name="cell">Cell to be added.</param>
+               /// <param name="groupCell">Group to which the new item should belong.</param>
+               /// <remark>If the value of <c>groupCell</c> is not null, the new item will be put into the requested group. </remark>
+               /// <param name="beforeCell">The cell before which the new item should be placed.</param>
+               /// <remarks> If the value of <c>beforeCell</c> is not null, the new item will be placed just before the requested cell. </remarks>
+               void AddItem(Cell cell, Cell groupCell = null, Cell beforeCell = null)
+               {
+                       CellRenderer renderer = GetCellRenderer(cell);
+                       GenListItem parentItem = null;
+
+                       ItemContext itemContext = new ItemContext();
+                       itemContext.Cell = cell;
+                       itemContext.Renderer = renderer;
+
+                       if (IsGroupingEnabled && groupCell != null)
+                       {
+                               var groupContext = GetItemContext(groupCell);
+                               itemContext.ListOfSubItems = groupContext.ListOfSubItems;
+                               parentItem = groupContext.Item;
+                       }
+
+                       if (beforeCell != null)
+                       {
+                               GenListItem beforeItem = GetItemContext(beforeCell)?.Item;
+                               itemContext.Item = InsertBefore(renderer.Class, itemContext, beforeItem, GenListItemType.Normal, parentItem);
+                       }
+                       else
+                       {
+                               itemContext.Item = Append(renderer.Class, itemContext, GenListItemType.Normal, parentItem);
+                       }
+
+                       itemContext.Item.SelectionMode = GenListSelectionMode.Always;
+
+                       cell.PropertyChanged += OnCellPropertyChanged;
+                       (cell as ICellController).ForceUpdateSizeRequested += OnForceUpdateSizeRequested;
+                       itemContext.Item.Deleted += ItemDeletedHandler;
+                       _itemContextList.Add(itemContext);
+               }
+
+               /// <summary>
+               /// Handles item deleted event.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="e">Empty argument.</param>
+               void ItemDeletedHandler(object sender, EventArgs e)
+               {
+                       ItemContext itemContext = (sender as GenListItem).Data as ItemContext;
+                       if (itemContext.Cell != null)
+                       {
+                               itemContext.Cell.PropertyChanged -= OnCellPropertyChanged;
+                               (itemContext.Cell as ICellController).ForceUpdateSizeRequested -= OnForceUpdateSizeRequested;
+                       }
+                       _itemContextList.Remove(itemContext);
+               }
+
+               /// <summary>
+               /// Invoked whenever the properties of data model change.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="e">PropertyChangedEventArgs.</param>
+               /// <remarks>
+               /// The purpose of this method is to propagate these changes to the presentation layer.
+               /// </remarks>
+               void OnCellPropertyChanged(object sender, PropertyChangedEventArgs e)
+               {
+                       var cell = sender as Cell;
+                       var context = GetItemContext(cell);
+                       context.Renderer.SendCellPropertyChanged(cell, context.Item, e.PropertyName);
+               }
+
+               void OnForceUpdateSizeRequested(object sender, EventArgs e)
+               {
+                       var cell = sender as Cell;
+                       var itemContext = GetItemContext(cell);
+                       if (itemContext.Item != null)
+                               itemContext.Item.Update();
+               }
+
+               /// <summary>
+               /// Gets the item class used for header and footer cells.
+               /// </summary>
+               /// <returns>The header and footer item class.</returns>
+               GenItemClass GetHeaderFooterItemClass()
+               {
+                       if (_headerFooterItemClass == null)
+                       {
+                               _headerFooterItemClass = new GenItemClass("full")
+                               {
+                                       GetContentHandler = (data, part) =>
+                                       {
+                                               VisualElement element = data as VisualElement;
+                                               var renderer = Platform.GetOrCreateRenderer(element);
+
+                                               if (element.MinimumHeightRequest == -1)
+                                               {
+                                                       SizeRequest request = element.Measure(double.PositiveInfinity, double.PositiveInfinity);
+                                                       renderer.NativeView.MinimumHeight = (int)request.Request.Height;
+                                               }
+                                               else
+                                               {
+                                                       renderer.NativeView.MinimumHeight = (int)element.MinimumHeightRequest;
+                                               }
+
+                                               return renderer.NativeView;
+                                       }
+                               };
+                       }
+                       return _headerFooterItemClass;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/MasterDetailPage.cs b/Xamarin.Forms.Platform.Tizen/Native/MasterDetailPage.cs
new file mode 100644 (file)
index 0000000..5751aaf
--- /dev/null
@@ -0,0 +1,364 @@
+using System;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// The native widget which provides Xamarin.MasterDetailPage features.
+       /// </summary>
+       public class MasterDetailPage : Box
+       {
+               /// <summary>
+               /// The portion of the screen that the MasterPage takes in Split mode.
+               /// </summary>
+               static readonly double s_splitRatio = 0.35;
+
+               /// <summary>
+               /// The portion of the screen that the MasterPage takes in Popover mode.
+               /// </summary>
+               static readonly double s_popoverRatio = 0.8;
+
+               /// <summary>
+               /// The default master behavior (a.k.a mode).
+               /// </summary>
+               static readonly MasterBehavior s_defaultMasterBehavior = (Device.Idiom == TargetIdiom.Phone) ? MasterBehavior.Popover : MasterBehavior.SplitOnLandscape;
+
+               /// <summary>
+               /// The MasterPage native container.
+               /// </summary>
+               readonly Canvas _masterCanvas;
+
+               /// <summary>
+               /// The DetailPage native container.
+               /// </summary>
+               readonly Canvas _detailCanvas;
+
+               /// <summary>
+               /// The container for <c>_masterCanvas</c> and <c>_detailCanvas</c> used in split mode.
+               /// </summary>
+               readonly Panes _splitPane;
+
+               /// <summary>
+               /// The container for <c>_masterCanvas</c> used in popover mode.
+               /// </summary>
+               readonly Panel _drawer;
+
+               /// <summary>
+               /// The <see cref="MasterBehavior"/> property value.
+               /// </summary>
+               MasterBehavior _masterBehavior = s_defaultMasterBehavior;
+
+               /// <summary>
+               /// The actual MasterDetailPage mode - either split or popover. It depends on <c>_masterBehavior</c> and screen orientation.
+               /// </summary>
+               MasterBehavior _internalMasterBehavior = MasterBehavior.Popover;
+
+               /// <summary>
+               /// The <see cref="Master"/> property value.
+               /// </summary>
+               EvasObject _master;
+
+               /// <summary>
+               /// The <see cref="Detail"/> property value.
+               /// </summary>
+               EvasObject _detail;
+
+               /// <summary>
+               /// The main widget - either <see cref="_splitPlane"/> or <see cref="_detailPage"/>, depending on the mode.
+               /// </summary>
+               EvasObject _mainWidget;
+
+               /// <summary>
+               /// The <see cref="IsPresented"/> property value.
+               /// </summary>
+               bool _isPresented;
+
+               /// <summary>
+               /// The <see cref="IsGestureEnabled"/> property value.
+               /// </summary>
+               bool _isGestureEnabled;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.MasterDetailPage"/> class.
+               /// </summary>
+               /// <param name="parent">Parent evas object.</param>
+               public MasterDetailPage(EvasObject parent) : base(parent)
+               {
+                       // we control the layout ourselves
+                       Resized += (sender, e) =>
+                       {
+                               var g = Geometry;
+
+                               // main widget should fill the area of the MasterDetailPage
+                               if (_mainWidget != null)
+                               {
+                                       _mainWidget.Geometry = g;
+                               }
+
+                               g.Width = (int)((s_popoverRatio * (double)g.Width));
+                               _drawer.Geometry = g;
+                       };
+
+                       // create the controls which will hold the master and detail pages
+                       _masterCanvas = new Canvas(this);
+                       _masterCanvas.SetAlignment(-1.0, -1.0);  // fill
+                       _masterCanvas.SetWeight(1.0, 1.0);  // expand
+                       _masterCanvas.Resized += (sender, e) =>
+                       {
+                               UpdatePageGeometry(_master);
+                       };
+
+                       _detailCanvas = new Canvas(this);
+                       _detailCanvas.SetAlignment(-1.0, -1.0);  // fill
+                       _detailCanvas.SetWeight(1.0, 1.0);  // expand
+                       _detailCanvas.Resized += (sender, e) =>
+                       {
+                               UpdatePageGeometry(_detail);
+                       };
+
+                       _splitPane = new Panes(this)
+                       {
+                               IsFixed = true,
+                               IsHorizontal = false,
+                               Proportion = s_splitRatio,
+                       };
+
+                       _drawer = new Panel(this)
+                       {
+                               Direction = PanelDirection.Left,
+                       };
+                       _drawer.SetScrollable(_isGestureEnabled);
+                       _drawer.SetScrollableArea(1.0);
+                       _drawer.Toggled += (object sender, EventArgs e) =>
+                       {
+                               IsPresented = _drawer.IsOpen;
+                       };
+
+                       IsPresentedChanged += (sender, e) =>
+                       {
+                               _drawer.IsOpen = IsPresented;
+                       };
+
+                       ConfigureLayout();
+
+                       // in case of the screen rotation we may need to update the choice between split
+                       // and popover behaviors and reconfigure the layout
+                       Forms.Context.MainWindow.RotationChanged += (sender, e) =>
+                       {
+                               UpdateMasterBehavior();
+                       };
+               }
+
+               /// <summary>
+               /// Occurs when the MasterPage is shown or hidden.
+               /// </summary>
+               public event EventHandler IsPresentedChanged;
+
+               /// <summary>
+               /// Gets or sets the MasterDetailPage behavior.
+               /// </summary>
+               /// <value>The behavior of the <c>MasterDetailPage</c> requested by the user.</value>
+               public MasterBehavior MasterBehavior
+               {
+                       get
+                       {
+                               return _masterBehavior;
+                       }
+
+                       set
+                       {
+                               if (_masterBehavior != value)
+                               {
+                                       _masterBehavior = value;
+
+                                       UpdateMasterBehavior();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the content of the MasterPage.
+               /// </summary>
+               /// <value>The MasterPage.</value>
+               public EvasObject Master
+               {
+                       get
+                       {
+                               return _master;
+                       }
+
+                       set
+                       {
+                               if (_master != value)
+                               {
+                                       _master = value;
+                                       UpdatePageGeometry(_master);
+                                       _masterCanvas.Children.Clear();
+                                       _masterCanvas.Children.Add(_master);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the content of the DetailPage.
+               /// </summary>
+               /// <value>The DetailPage.</value>
+               public EvasObject Detail
+               {
+                       get
+                       {
+                               return _detail;
+                       }
+
+                       set
+                       {
+                               if (_detail != value)
+                               {
+                                       _detail = value;
+                                       UpdatePageGeometry(_detail);
+                                       _detailCanvas.Children.Clear();
+                                       _detailCanvas.Children.Add(_detail);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets a value indicating whether the MasterPage is shown.
+               /// </summary>
+               /// <value><c>true</c> if the MasterPage is presented.</value>
+               public bool IsPresented
+               {
+                       get
+                       {
+                               return _isPresented;
+                       }
+
+                       set
+                       {
+                               if (_isPresented != value)
+                               {
+                                       _isPresented = value;
+                                       IsPresentedChanged?.Invoke(this, EventArgs.Empty);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets a value indicating whether a MasterDetailPage allows showing MasterPage with swipe gesture.
+               /// </summary>
+               /// <value><c>true</c> if the MasterPage can be revealed with a gesture.</value>
+               public bool IsGestureEnabled
+               {
+                       get
+                       {
+                               return _isGestureEnabled;
+                       }
+
+                       set
+                       {
+                               if (_isGestureEnabled != value)
+                               {
+                                       _isGestureEnabled = value;
+                                       _drawer.SetScrollable(_isGestureEnabled);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Updates the geometry of the selected page.
+               /// </summary>
+               /// <param name="page">Master or Detail page to be updated.</param>
+               void UpdatePageGeometry(EvasObject page)
+               {
+                       if (page != null)
+                       {
+                               if (_master == page)
+                               {
+                                       // update the geometry of the master page
+                                       page.Geometry = _masterCanvas.Geometry;
+                               }
+                               else if (_detail == page)
+                               {
+                                       // update the geometry of the detail page
+                                       page.Geometry = _detailCanvas.Geometry;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Updates <see cref="_internalMasterBehavior"/> according to <see cref="MasterDetailBehavior"/> set by the user and current screen orientation.
+               /// </summary>
+               void UpdateMasterBehavior()
+               {
+                       var behavior = (_masterBehavior == MasterBehavior.Default) ? s_defaultMasterBehavior : _masterBehavior;
+
+                       // Screen orientation affects those 2 behaviors
+                       if (behavior == MasterBehavior.SplitOnLandscape ||
+                               behavior == MasterBehavior.SplitOnPortrait)
+                       {
+                               var orientation = Forms.Context.MainWindow.CurrentOrientation;
+
+                               if (((orientation == DisplayOrientations.Landscape || orientation == DisplayOrientations.LandscapeFlipped) && behavior == MasterBehavior.SplitOnLandscape) ||
+                                       ((orientation == DisplayOrientations.Portrait || orientation == DisplayOrientations.PortraitFlipped) && behavior == MasterBehavior.SplitOnPortrait))
+                               {
+                                       behavior = MasterBehavior.Split;
+                               }
+                               else
+                               {
+                                       behavior = MasterBehavior.Popover;
+                               }
+                       }
+
+                       if (behavior != _internalMasterBehavior)
+                       {
+                               _internalMasterBehavior = behavior;
+
+                               ConfigureLayout();
+                       }
+               }
+
+               /// <summary>
+               /// Composes the structure of all the necessary widgets.
+               /// </summary>
+               void ConfigureLayout()
+               {
+                       _drawer.SetContent(null, true);
+                       _drawer.Hide();
+
+                       _splitPane.SetPartContent("left", null, true);
+                       _splitPane.SetPartContent("right", null, true);
+                       _splitPane.Hide();
+
+                       UnPackAll();
+
+                       // the structure for split mode and for popover mode looks differently
+                       if (_internalMasterBehavior == MasterBehavior.Split)
+                       {
+                               _splitPane.SetPartContent("left", _masterCanvas, true);
+                               _splitPane.SetPartContent("right", _detailCanvas, true);
+                               PackEnd(_splitPane);
+
+                               _splitPane.Show();
+
+                               _mainWidget = _splitPane;
+
+                               IsPresented = true;
+                       }
+                       else
+                       {
+                               _drawer.SetContent(_masterCanvas, true);
+                               PackEnd(_detailCanvas);
+                               PackEnd(_drawer);
+
+                               _drawer.Show();
+
+                               _mainWidget = _detailCanvas;
+
+                               _drawer.IsOpen = IsPresented;
+                       }
+
+                       _masterCanvas.Show();
+                       _detailCanvas.Show();
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/ObservableCollection.cs b/Xamarin.Forms.Platform.Tizen/Native/ObservableCollection.cs
new file mode 100644 (file)
index 0000000..d33407c
--- /dev/null
@@ -0,0 +1,30 @@
+using System.Collections.Specialized;
+using System.Linq;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
+       /// </summary>
+       /// <typeparam name="T">The type of elements in the collection.</typeparam>
+       internal class ObservableCollection<T> : System.Collections.ObjectModel.ObservableCollection<T>
+       {
+               /// <summary>
+               /// Removes all items from the collection.
+               /// </summary>
+               /// <remarks>
+               /// Fisrt remove all items, send CollectionChanged event with Remove Action
+               /// Second call ClearItems of base
+               /// </remarks>
+               protected override void ClearItems()
+               {
+                       var oldItems = Items.ToList();
+                       Items.Clear();
+                       using (BlockReentrancy())
+                       {
+                               OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItems));
+                       }
+                       base.ClearItems();
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/SearchBar.cs b/Xamarin.Forms.Platform.Tizen/Native/SearchBar.cs
new file mode 100644 (file)
index 0000000..db597ed
--- /dev/null
@@ -0,0 +1,423 @@
+using System;
+using ElmSharp;
+using EColor = ElmSharp.Color;
+using ESize = ElmSharp.Size;
+using ERect = ElmSharp.Rect;
+using ERectangle = ElmSharp.Rectangle;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Provides implementation of the search bar widget.
+       /// </summary>
+       public class SearchBar : Canvas, IMeasurable
+       {
+               /// <summary>
+               /// The height of the background of the search bar.
+               /// </summary>
+               const int BackgroundHeight = 120;
+
+               /// <summary>
+               /// The style of the cancel button.
+               /// </summary>
+               const string CancelButtonLayoutStyle = "editfield_clear";
+
+               /// <summary>
+               /// The horizontal padding of the cancel button.
+               /// </summary>
+               const int CancelButtonPaddingHorizontal = 17;
+
+               /// <summary>
+               /// The size of the cancel button.
+               /// </summary>
+               const int CancelButtonSize = 80;
+
+               /// <summary>
+               /// The height of the entry.
+               /// </summary>
+               const int EntryHeight = 54;
+
+               /// <summary>
+               /// The horizontal padding of the entry.
+               /// </summary>
+               const int EntryPaddingHorizontal = 42;
+
+               /// <summary>
+               /// The vertical padding of the entry.
+               /// </summary>
+               const int EntryPaddingVertical = 33;
+
+               /// <summary>
+               /// The height of the rectangle used to draw underline effect.
+               /// </summary>
+               const int RectangleHeight = 2;
+
+               /// <summary>
+               /// The bottom padding of the rectangle used to draw underline effect.
+               /// </summary>
+               const int RectanglePaddingBottom = 20;
+
+               /// <summary>
+               /// The horizontal padding of the rectangle used to draw underline effect.
+               /// </summary>
+               const int RectanglePaddingHorizontal = 32;
+
+               /// <summary>
+               /// The top padding of the rectangle used to draw underline effect.
+               /// </summary>
+               const int RectanglePaddingTop = 11;
+
+               //TODO: read default platform color
+
+               /// <summary>
+               /// The color of the underline rectangle.
+               /// </summary>
+               static readonly EColor s_underlineColor = EColor.Aqua;
+
+               /// <summary>
+               /// The dimmed color of the underline rectangle.
+               /// </summary>
+               static readonly EColor s_underlineDimColor = EColor.Gray;
+
+               /// <summary>
+               /// The cancel button.
+               /// </summary>
+               Button _cancelButton;
+
+               /// <summary>
+               /// The text entry.
+               /// </summary>
+               Entry _entry;
+
+               /// <summary>
+               /// The underline rectangle.
+               /// </summary>
+               ERectangle _underlineRectangle;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.SearchBar"/> class.
+               /// </summary>
+               /// <param name="parent">Parent evas object.</param>
+               public SearchBar(EvasObject parent) : base(parent)
+               {
+                       _entry = new Entry(parent)
+                       {
+                               IsSingleLine = true,
+                       };
+                       _entry.SetInputPanelReturnKeyType(InputPanelReturnKeyType.Search);
+                       _entry.TextChanged += EntryTextChanged;
+                       _entry.Activated += EntryActivated;
+                       _entry.Focused += EntryFocused;
+                       _entry.Unfocused += EntryUnfocused;
+                       _entry.Show();
+
+                       _cancelButton = new Button(parent);
+                       _cancelButton.Style = CancelButtonLayoutStyle;
+                       _cancelButton.Clicked += CancelButtonClicked;
+
+                       _underlineRectangle = new ERectangle(parent)
+                       {
+                               Color = IsEnabled ? s_underlineColor : s_underlineDimColor,
+                       };
+                       _underlineRectangle.Show();
+
+                       Children.Add(_entry);
+                       Children.Add(_cancelButton);
+                       Children.Add(_underlineRectangle);
+
+                       Show();
+
+                       this.LayoutUpdated += SearchBarLayoutUpdated;
+               }
+
+               /// <summary>
+               /// Occurs when the search button on the keyboard is pressed.
+               /// </summary>
+               public event EventHandler SearchButtonPressed;
+
+               /// <summary>
+               /// Occurs when the entry's text has changed.
+               /// </summary>
+               public event EventHandler<TextChangedEventArgs> TextChanged;
+
+               /// <summary>
+               /// Gets or sets the color of the cancel button.
+               /// </summary>
+               /// <value>Color of the cancel button.</value>
+               public EColor CancelButtonColor
+               {
+                       get
+                       {
+                               return _cancelButton.Color;
+                       }
+
+                       set
+                       {
+                               if (!_cancelButton.Color.Equals(value))
+                               {
+                                       _cancelButton.Color = value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the font attributes of the search bar's entry.
+               /// </summary>
+               /// <value>The font attributes.</value>
+               public FontAttributes FontAttributes
+               {
+                       get
+                       {
+                               return _entry.FontAttributes;
+                       }
+
+                       set
+                       {
+                               if (value != _entry.FontAttributes)
+                               {
+                                       _entry.FontAttributes = value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the font family of the search bar's entry.
+               /// </summary>
+               /// <value>The font family.</value>
+               public string FontFamily
+               {
+                       get
+                       {
+                               return _entry.FontFamily;
+                       }
+
+                       set
+                       {
+                               if (value != _entry.FontFamily)
+                               {
+                                       _entry.FontFamily = value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the size of the font of the search bar's entry.
+               /// </summary>
+               /// <value>The size of the font.</value>
+               public double FontSize
+               {
+                       get
+                       {
+                               return _entry.FontSize;
+                       }
+
+                       set
+                       {
+                               if (value != _entry.FontSize)
+                               {
+                                       _entry.FontSize = value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the horizontal text alignment of the search bar's entry.
+               /// </summary>
+               /// <value>The horizontal text alignment.</value>
+               public TextAlignment HorizontalTextAlignment
+               {
+                       get
+                       {
+                               return _entry.HorizontalTextAlignment;
+                       }
+
+                       set
+                       {
+                               if (value != _entry.HorizontalTextAlignment)
+                               {
+                                       _entry.HorizontalTextAlignment = value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the placeholder of the search bar's entry.
+               /// </summary>
+               /// <value>The placeholder.</value>
+               public string Placeholder
+               {
+                       get
+                       {
+                               return _entry.Placeholder;
+                       }
+
+                       set
+                       {
+                               if (value != _entry.Placeholder)
+                               {
+                                       _entry.Placeholder = value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the color of the placeholder.
+               /// </summary>
+               /// <value>The color of the placeholder.</value>
+               public EColor PlaceholderColor
+               {
+                       get
+                       {
+                               return _entry.PlaceholderColor;
+                       }
+
+                       set
+                       {
+                               if (!_entry.PlaceholderColor.Equals(value))
+                               {
+                                       _entry.PlaceholderColor = value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the text of the search bar's entry.
+               /// </summary>
+               /// <value>The text.</value>
+               public override string Text
+               {
+                       get
+                       {
+                               return _entry.Text;
+                       }
+
+                       set
+                       {
+                               if (value != _entry.Text)
+                               {
+                                       _entry.Text = value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the color of the text.
+               /// </summary>
+               /// <value>The color of the text.</value>
+               public EColor TextColor
+               {
+                       get
+                       {
+                               return _entry.TextColor;
+                       }
+
+                       set
+                       {
+                               if (!_entry.TextColor.Equals(value))
+                               {
+                                       _entry.TextColor = value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Implementation of the IMeasurable.Measure() method.
+               /// </summary>
+               public ESize Measure(int availableWidth, int availableHeight)
+               {
+                       ESize entrySize = _entry.Measure(availableWidth, availableHeight);
+                       int width = entrySize.Width + (CancelButtonPaddingHorizontal * 2) + CancelButtonSize;
+                       return new ESize(width, BackgroundHeight);
+               }
+
+               /// <summary>
+               /// Handles the event triggered by the cancel button being clicked.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="e">Event arguments, ignored.</param>
+               void CancelButtonClicked(object sender, EventArgs e)
+               {
+                       _entry.Text = string.Empty;
+                       _cancelButton.Hide();
+               }
+
+               /// <summary>
+               /// Handles the event triggered by clicking the search button on the keyboard.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="e">Event arguments, ignored.</param>
+               void EntryActivated(object sender, EventArgs e)
+               {
+                       SearchButtonPressed?.Invoke(this, EventArgs.Empty);
+               }
+
+               /// <summary>
+               /// Handles the event triggered by entry gaining the focus.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="e">Event arguments, ignored.</param>
+               void EntryFocused(object sender, EventArgs e)
+               {
+                       _underlineRectangle.Color = s_underlineColor;
+               }
+
+               /// <summary>
+               /// Handles the event triggered by entry's text being changed.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="e">Event arguments.</param>
+               void EntryTextChanged(object sender, TextChangedEventArgs e)
+               {
+                       if (string.IsNullOrEmpty(e.NewTextValue))
+                       {
+                               _cancelButton.Hide();
+                       }
+                       else if (!_cancelButton.IsVisible)
+                       {
+                               _cancelButton.Show();
+                       }
+                       TextChanged?.Invoke(this, e);
+               }
+
+               /// <summary>
+               /// Handles the event triggered by entry losing the focus.
+               /// </summary>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="e">Event arguments, ignored.</param>
+               void EntryUnfocused(object sender, EventArgs e)
+               {
+                       _underlineRectangle.Color = s_underlineDimColor;
+               }
+
+               /// <summary>
+               /// Handles the event triggered by search bar's layout being changed.
+               /// </summary>
+               /// <remarks>
+               /// Updates the geometry of the widgets comprising the search bar.
+               /// </remarks>
+               /// <param name="sender">Sender of the event.</param>
+               /// <param name="e">Event arguments.</param>
+               void SearchBarLayoutUpdated(object sender, LayoutEventArgs e)
+               {
+                       if (!e.HasChanged)
+                       {
+                               return;
+                       }
+
+                       _underlineRectangle.Geometry = new ERect(Geometry.Left + RectanglePaddingHorizontal,
+                                                                                                                        Geometry.Top + EntryPaddingVertical + EntryHeight + RectanglePaddingTop,
+                                                                                                                        Geometry.Width - (RectanglePaddingHorizontal * 2),
+                                                                                                                        RectangleHeight);
+
+                       _entry.Geometry = new ERect(Geometry.Left + EntryPaddingHorizontal,
+                                                                                               Geometry.Top + EntryPaddingVertical,
+                                                                                               Geometry.Width - (EntryPaddingHorizontal + (CancelButtonPaddingHorizontal * 2) + CancelButtonSize),
+                                                                                               EntryHeight);
+
+                       _cancelButton.Geometry = new ERect(Geometry.Right - CancelButtonSize - CancelButtonPaddingHorizontal,
+                                                                                                          Geometry.Top + RectanglePaddingBottom,
+                                                                                                          CancelButtonSize,
+                                                                                                          CancelButtonSize);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/Span.cs b/Xamarin.Forms.Platform.Tizen/Native/Span.cs
new file mode 100644 (file)
index 0000000..6c479e3
--- /dev/null
@@ -0,0 +1,294 @@
+using System.Text;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Represent a text with attributes applied.
+       /// </summary>
+       public class Span
+       {
+               string _text;
+
+               /// <summary>
+               /// Gets or sets the formatted text.
+               /// </summary>
+               public FormattedString FormattedText { get; set; }
+
+               /// <summary>
+               /// Gets or sets the text.
+               /// </summary>
+               /// <remarks>
+               /// Setting Text to a non-null value will set the FormattedText property to null.
+               /// </remarks>
+               public string Text
+               {
+                       get
+                       {
+                               if (FormattedText != null)
+                               {
+                                       return FormattedText.ToString();
+                               }
+                               else
+                               {
+                                       return _text;
+                               }
+                       }
+                       set
+                       {
+                               if (value == null)
+                               {
+                                       value = "";
+                               }
+                               else
+                               {
+                                       FormattedText = null;
+                               }
+                               _text = value;
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the color for the text.
+               /// </summary>
+               public EColor ForegroundColor { get; set; }
+
+               /// <summary>
+               /// Gets or sets the background color for the text.
+               /// </summary>
+               public EColor BackgroundColor { get; set; }
+
+               /// <summary>
+               /// Gets or sets the font family for the text.
+               /// </summary>
+               public string FontFamily { get; set; }
+
+               /// <summary>
+               /// Gets or sets the font attributes for the text.
+               /// See <see cref="FontAttributes"/> for information about FontAttributes.
+               /// </summary>
+               public FontAttributes FontAttributes { get; set; }
+
+               /// <summary>
+               /// Gets or sets the font size for the text.
+               /// </summary>
+               public double FontSize { get; set; }
+
+               /// <summary>
+               /// Gets or sets the line break mode for the text.
+               /// See <see cref="LineBreakMode"/> for information about LineBreakMode.
+               /// </summary>
+               public LineBreakMode LineBreakMode { get; set; }
+
+               /// <summary>
+               /// Gets or sets the horizontal alignment mode for the text.
+               /// See <see cref="TextAlignment"/> for information about TextAlignment.
+               /// </summary>
+               public TextAlignment HorizontalTextAlignment { get; set; }
+
+               /// <summary>
+               /// Gets or sets the vertical alignment mode for the text.
+               /// See <see cref="TextAlignment"/> for information about TextAlignment.
+               /// </summary>
+               public TextAlignment VerticalTextAlignment { get; set; }
+
+               /// <summary>
+               /// Gets or sets the value that indicates whether the text has underline.
+               /// </summary>
+               public bool Underline { get; set; }
+
+               /// <summary>
+               /// Gets or sets the value that indicates whether the text has strike line though it.
+               /// </summary>
+               public bool Strikethrough { get; set; }
+
+               /// <summary>
+               /// Create a new Span instance with default attributes.
+               /// </summary>
+               public Span()
+               {
+                       Text = "";
+                       FontFamily = "";
+                       FontSize = -1;
+                       FontAttributes = FontAttributes.None;
+                       ForegroundColor = EColor.White;
+                       BackgroundColor = EColor.Transparent;
+                       HorizontalTextAlignment = TextAlignment.Auto;
+                       VerticalTextAlignment = TextAlignment.Auto;
+                       LineBreakMode = LineBreakMode.MixedWrap;
+                       Underline = false;
+                       Strikethrough = false;
+               }
+
+               /// <summary>
+               /// This method return marked up text
+               /// </summary>
+               internal string GetMarkupText()
+               {
+                       StringBuilder sb = new StringBuilder();
+
+                       sb.AppendFormat("<span ");
+
+                       sb = PrepareFormattingString(sb);
+
+                       sb.Append(">");
+
+                       sb.Append(GetDecoratedText());
+
+                       sb.Append("</>");
+
+                       return sb.ToString();
+               }
+
+               /// <summary>
+               /// This method return text decorated with markup if FormattedText is set or plain text otherwise.
+               /// </summary>
+               internal string GetDecoratedText()
+               {
+                       if (FormattedText != null)
+                       {
+                               return FormattedText.ToMarkupString();
+                       }
+                       else
+                       {
+                               return ConvertTags(Text);
+                       }
+               }
+
+               StringBuilder PrepareFormattingString(StringBuilder _formattingString)
+               {
+                       var foregroundColor = ForegroundColor.ToHex();
+
+                       _formattingString.AppendFormat("color={0} ", foregroundColor);
+
+                       _formattingString.AppendFormat("backing_color={0} ", BackgroundColor.ToHex());
+                       _formattingString.Append("backing=on ");
+
+                       if (!string.IsNullOrEmpty(FontFamily))
+                       {
+                               _formattingString.AppendFormat("font={0} ", FontFamily);
+                       }
+
+                       if (FontSize != -1)
+                       {
+                               _formattingString.AppendFormat("font_size={0} ", FontSize);
+                       }
+
+                       if ((FontAttributes & FontAttributes.Bold) != 0)
+                       {
+                               _formattingString.Append("font_weight=Bold ");
+                       }
+                       if ((FontAttributes & FontAttributes.Italic) != 0)
+                       {
+                               _formattingString.Append("font_style=italic ");
+                       }
+
+                       if (Underline)
+                       {
+                               _formattingString.AppendFormat("underline=on underline_color={0} ", foregroundColor);
+                       }
+
+                       if (Strikethrough)
+                       {
+                               _formattingString.AppendFormat("strikethrough=on strikethrough_color={0} ", foregroundColor);
+                       }
+
+                       switch (HorizontalTextAlignment)
+                       {
+                               case TextAlignment.Auto:
+                                       _formattingString.Append("align=auto ");
+                                       break;
+
+                               case TextAlignment.Start:
+                                       _formattingString.Append("align=left ");
+                                       break;
+
+                               case TextAlignment.End:
+                                       _formattingString.Append("align=right ");
+                                       break;
+
+                               case TextAlignment.Center:
+                                       _formattingString.Append("align=center ");
+                                       break;
+                       }
+
+                       switch (VerticalTextAlignment)
+                       {
+                               case TextAlignment.Auto:
+                               case TextAlignment.Start:
+                                       _formattingString.Append("valign=top ");
+                                       break;
+
+                               case TextAlignment.End:
+                                       _formattingString.Append("valign=bottom ");
+                                       break;
+
+                               case TextAlignment.Center:
+                                       _formattingString.Append("valign=middle ");
+                                       break;
+                       }
+
+                       switch (LineBreakMode)
+                       {
+                               case LineBreakMode.NoWrap:
+                                       _formattingString.Append("wrap=none");
+                                       break;
+
+                               case LineBreakMode.CharacterWrap:
+                                       _formattingString.Append("wrap=char");
+                                       break;
+
+                               case LineBreakMode.WordWrap:
+                                       _formattingString.Append("wrap=word");
+                                       break;
+
+                               case LineBreakMode.MixedWrap:
+                                       _formattingString.Append("wrap=mixed");
+                                       break;
+
+                               case LineBreakMode.HeadTruncation:
+                                       _formattingString.Append("ellipsis=0.0");
+                                       break;
+
+                               case LineBreakMode.MiddleTruncation:
+                                       _formattingString.Append("ellipsis=0.5");
+                                       break;
+
+                               case LineBreakMode.TailTruncation:
+                                       _formattingString.Append("ellipsis=1.0");
+                                       break;
+                       }
+
+                       return _formattingString;
+               }
+
+               string ConvertTags(string text)
+               {
+                       return text.Replace("<", "&lt;")
+                                          .Replace(">", "&gt;")
+                                          .Replace("\n", "<br>");
+               }
+
+               internal string GetStyle()
+               {
+                       StringBuilder sb = new StringBuilder();
+
+                       sb.Append("DEFAULT='");
+
+                       PrepareFormattingString(sb);
+
+                       sb.Append("'");
+
+                       return sb.ToString();
+               }
+
+               /// <summary>
+               /// Converts string value to Span.
+               /// </summary>
+               /// <param name="text">The string text</param>
+               public static implicit operator Span(string text)
+               {
+                       return new Span { Text = text };
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/TableView.cs b/Xamarin.Forms.Platform.Tizen/Native/TableView.cs
new file mode 100644 (file)
index 0000000..73388a8
--- /dev/null
@@ -0,0 +1,67 @@
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Extends the ListView class to provide TableView class implementation.
+       /// </summary>
+       public class TableView : ListView
+       {
+
+               static readonly SectionCellRenderer _sectionCellRenderer = new SectionCellRenderer();
+               /// <summary>
+               /// Initializes a new instance of the TableView class.
+               /// </summary>
+               public TableView(EvasObject parent)
+                       : base(parent) {
+               }
+
+               /// <summary>
+               /// Sets the root of the table.
+               /// </summary>
+               /// <param name="root">TableRoot, which is parent to one or more TableSections.</param>
+               public void ApplyTableRoot(TableRoot root)
+               {
+                       Clear();
+                       foreach (TableSection ts in root)
+                       {
+                               AddSectionTitle(ts.Title);
+                               AddSource(ts);
+                       }
+               }
+
+               protected override CellRenderer GetCellRenderer(Cell cell, bool isGroup = false)
+               {
+                       if (cell.GetType() == typeof(SectionCell))
+                       {
+                               return _sectionCellRenderer;
+                       }
+                       return base.GetCellRenderer(cell, isGroup);
+               }
+
+               /// <summary>
+               /// Sets the section title.
+               /// </summary>
+               void AddSectionTitle(string title)
+               {
+                       Cell cell = new SectionCell()
+                       {
+                               Text = title
+                       };
+                       AddCell(cell);
+               }
+
+               internal class SectionCellRenderer : GroupCellTextRenderer
+               {
+                       public SectionCellRenderer()
+                       {
+                               DetailPart = "null";
+                       }
+                       protected SectionCellRenderer(string style) : base(style) { }
+               }
+               class SectionCell : TextCell
+               {
+               }
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Native/TextAlignment.cs b/Xamarin.Forms.Platform.Tizen/Native/TextAlignment.cs
new file mode 100644 (file)
index 0000000..c7e934b
--- /dev/null
@@ -0,0 +1,25 @@
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Enumerates values that describe alignemnt of text.
+       /// </summary>
+       public enum TextAlignment
+       {
+               /// <summary>
+               /// Aligns horizontal text according to language. Top aligned for vertical text.
+               /// </summary>
+               Auto,
+               /// <summary>
+               /// Left and top aligned for horizontal and vertical text, respectively.
+               /// </summary>
+               Start,
+               /// <summary>
+               /// Right and bottom aligned for horizontal and  vertical text, respectively.
+               /// </summary>
+               End,
+               /// <summary>
+               /// Center-aligned text.
+               /// </summary>
+               Center,
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/TextHelper.cs b/Xamarin.Forms.Platform.Tizen/Native/TextHelper.cs
new file mode 100644 (file)
index 0000000..5109dad
--- /dev/null
@@ -0,0 +1,54 @@
+using System;
+using ElmSharp;
+using ESize = ElmSharp.Size;
+using ELayout = ElmSharp.Layout;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// The Text Helper contains functions that assist in working with text-able objects.
+       /// </summary>
+       internal static class TextHelper
+       {
+               /// <summary>
+               /// Gets the size of raw text block.
+               /// </summary>
+               /// <param name="textable">The <see cref="EvasObject"/> with text part.</param>
+               /// <returns>Returns the size of raw text block.</returns>
+               public static ESize GetRawTextBlockSize(EvasObject textable)
+               {
+                       return GetElmTextPart(textable).TextBlockNativeSize;
+               }
+
+               /// <summary>
+               /// Gets the size of formatted text block.
+               /// </summary>
+               /// <param name="textable">The <see cref="ElmSharp.EvasObject"/> with text part.</param>
+               /// <returns>Returns the size of formatted text block.</returns>
+               public static ESize GetFormattedTextBlockSize(EvasObject textable)
+               {
+                       return GetElmTextPart(textable).TextBlockFormattedSize;
+               }
+
+               /// <summary>
+               /// Gets the ELM text part of evas object.
+               /// </summary>
+               /// <param name="textable">The <see cref="ElmSharp.EvasObject"/> with text part.</param>
+               /// <exception cref="ArgumentException">Throws exception when parameter <param name="textable"> isn't text-able object or doesn't have ELM text part.</exception>
+               /// <returns>Requested <see cref="ElmSharp.EdjeTextPartObject"/> instance.</returns>
+               static EdjeTextPartObject GetElmTextPart(EvasObject textable)
+               {
+                       ELayout widget = textable as ELayout;
+                       if (widget == null)
+                       {
+                               throw new ArgumentException("textable should be ElmSharp.Layout", "textable");
+                       }
+                       EdjeTextPartObject textPart = widget.EdjeObject["elm.text"];
+                       if (textPart == null)
+                       {
+                               throw new ArgumentException("There is no elm.text part", "textable");
+                       }
+                       return textPart;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/TimePicker.cs b/Xamarin.Forms.Platform.Tizen/Native/TimePicker.cs
new file mode 100644 (file)
index 0000000..6ee49ce
--- /dev/null
@@ -0,0 +1,185 @@
+using System;
+using System.Linq;
+using System.Text.RegularExpressions;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       /// <summary>
+       /// Extends the ElmSharp.DateTimeSelector class with functionality useful to renderer.
+       /// </summary>
+       public class TimePicker : DateTimeSelector
+       {
+               const string DefaultEFLFormat = "%I:%M %p";
+               //TODO need to add internationalization support
+               const string FormatExceptionMessage = "Input string was not in a correct format.";
+               const string RegexValidTimePattern = "^([h]{1,2}|[H]{1,2})[.:-]([m]{1,2})(([.:-][s]{1,2})?)(([.:-][fF]{1,7})?)(([K])?)(([z]{1,3})?)(([ ][t]{1,2})?)$";
+               const string TimeLayoutStyle = "time_layout";
+               string _dateTimeFormat;
+               TimeSpan _time;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="TimePicker"/> class.
+               /// </summary>
+               /// <param name="parent">The parent EvasObject.</param>
+               public TimePicker(EvasObject parent) : base(parent)
+               {
+                       Style = TimeLayoutStyle;
+                       ApplyTime(Time);
+                       ApplyFormat(DateTimeFormat);
+
+                       DateTimeChanged += (sender, e) =>
+                       {
+                               Time = e.NewDate.TimeOfDay;
+                       };
+               }
+
+               /// <summary>
+               /// Gets or sets the displayed date time format.
+               /// </summary>
+               public string DateTimeFormat
+               {
+                       get
+                       {
+                               return _dateTimeFormat;
+                       }
+                       set
+                       {
+                               if (_dateTimeFormat != value)
+                               {
+                                       ApplyFormat(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the displayed time.
+               /// </summary>
+               public TimeSpan Time
+               {
+                       get
+                       {
+                               return _time;
+                       }
+                       set
+                       {
+                               if (_time != value)
+                               {
+                                       ApplyTime(value);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Sets the <c>Format</c> property according to the given <paramref name="format"/>.
+               /// </summary>
+               /// <param name="format">The format value to be applied to the time picker.</param>
+               void ApplyFormat(string format)
+               {
+                       _dateTimeFormat = format;
+                       Format = ConvertToEFLFormat(_dateTimeFormat);
+               }
+
+               /// <summary>
+               /// Sets the <c>DateTime</c> property according to the given <paramref name="time"/>.
+               /// </summary>
+               /// <param name="time">The time value to be applied to the time picker.</param>
+               void ApplyTime(TimeSpan time)
+               {
+                       _time = time;
+                       DateTime = ConvertToDateTime(time);
+               }
+
+               /// <summary>
+               /// Converts parameter <paramref name="timeSpan"/> to <see cref="DateTime"/>.
+               /// </summary>
+               /// <param name="timeSpan">The time value to be converted to <see cref="DateTime"/>.</param>
+               /// <returns>An object representing the date 1st Jan, 1970 (minimum date of ElmSharp.DateTimeSelector) with added <paramref name="timeSpan"/>.</returns>
+               DateTime ConvertToDateTime(TimeSpan timeSpan)
+               {
+                       return new DateTime(1970, 1, 1) + timeSpan;
+               }
+
+               /// <summary>
+               /// Converts standard or custom <see cref="DateTime"/> format to EFL format.
+               /// </summary>
+               /// <param name="dateTimeFormat">The <see cref="DateTime"/> format to be converted to EFL format.</param>
+               /// <exception cref="FormatException"><param name="dateTimeFormat"> does not contain a valid string representation of a date and time.</exception>
+               /// <returns>An object representing the EFL time format string.
+               /// Example:
+               /// "t" or "T" returns default EFL format "%I:%M %p"
+               /// "HH:mm tt" returns "%H:%M %p"
+               /// "h:mm" returns "%l:%M"
+               /// </returns>
+               string ConvertToEFLFormat(string dateTimeFormat)
+               {
+                       if (string.IsNullOrWhiteSpace(dateTimeFormat))
+                       {
+                               return DefaultEFLFormat;
+                       }
+
+                       if (dateTimeFormat.Length == 1)
+                       {
+                               //Standard Time Format (DateTime)
+                               if (dateTimeFormat[0] == 't' || dateTimeFormat[0] == 'T')
+                               {
+                                       return DefaultEFLFormat;
+                               }
+                               else
+                               {
+                                       throw new FormatException(FormatExceptionMessage);
+                               }
+                       }
+                       else
+                       {
+                               //Custom Time Format (DateTime)
+                               Regex regex = new Regex(RegexValidTimePattern);
+                               if (!regex.IsMatch(dateTimeFormat))
+                               {
+                                       throw new FormatException(FormatExceptionMessage);
+                               }
+
+                               string format = string.Empty;
+                               int count_h = dateTimeFormat.Count(m => m == 'h'); //12h
+                               int count_H = dateTimeFormat.Count(m => m == 'H'); //24h
+
+                               if (count_h == 1)
+                               {
+                                       format += "%l";
+                               }
+                               else if (count_h == 2)
+                               {
+                                       format += "%I";
+                               }
+                               else if (count_H == 1)
+                               {
+                                       format += "%k";
+                               }
+                               else if (count_H == 2)
+                               {
+                                       format += "%H";
+                               }
+
+                               format += ":%M";
+                               int count_t = dateTimeFormat.Count(m => m == 't');
+
+                               if ((count_H > 0 && count_t > 0) ||
+                                       (count_h > 0 && count_t == 0))
+                               {
+                                       throw new FormatException(FormatExceptionMessage);
+                               }
+
+                               if (count_t == 1)
+                               {
+                                       format += " %P";
+                               }
+                               else if (count_t == 2)
+                               {
+                                       format += " %p";
+                               }
+
+                               return format;
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Native/Window.cs b/Xamarin.Forms.Platform.Tizen/Native/Window.cs
new file mode 100644 (file)
index 0000000..87a54cd
--- /dev/null
@@ -0,0 +1,138 @@
+using System;
+using ElmSharp;
+using EWindow = ElmSharp.Window;
+
+namespace Xamarin.Forms.Platform.Tizen.Native
+{
+       public class Window : EWindow
+       {
+               Conformant _conformant;
+
+               /// <summary>
+               /// Initializes a new instance of the Window class.
+               /// </summary>
+               public Window() : base("FormsWindow")
+               {
+                       Initialize();
+               }
+
+               /// <summary>
+               /// Notifies that the window has been closed.
+               /// </summary>
+               public event EventHandler Closed;
+
+               /// <summary>
+               /// Notifies that the back button has been pressed.
+               /// </summary>
+               public event EventHandler BackButtonPressed;
+
+               /// <summary>
+               /// Gets the current orientation.
+               /// </summary>
+               public DisplayOrientations CurrentOrientation
+               {
+                       get
+                       {
+                               if (IsRotationSupported)
+                               {
+                                       return GetDisplayOrientation();
+                               }
+                               else
+                               {
+                                       return DisplayOrientations.None;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Gets or sets the orientation of a rectangular screen.
+               /// </summary>
+               public DisplayOrientations AvailableOrientations
+               {
+                       get
+                       {
+                               if (IsRotationSupported)
+                               {
+                                       return (DisplayOrientations)AvailableRotations;
+                               }
+                               else
+                               {
+                                       return DisplayOrientations.None;
+                               }
+                       }
+                       set
+                       {
+                               if (IsRotationSupported)
+                               {
+                                       AvailableRotations = (DisplayRotation)value;
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Sets the main page of Window.
+               /// </summary>
+               /// <param name="content">ElmSharp.EvasObject type page to be set.</param>
+               public void SetMainPage(EvasObject content)
+               {
+                       _conformant.SetContent(content);
+               }
+
+               void Initialize()
+               {
+                       // size
+                       var size = ScreenSize;
+                       Resize(size.Width, size.Height);
+
+                       // events
+                       Deleted += (sender, e) =>
+                       {
+                               Closed?.Invoke(this, EventArgs.Empty);
+                       };
+                       CloseRequested += (sender, e) =>
+                       {
+                               Unrealize();
+                       };
+
+                       KeyGrab(EvasKeyEventArgs.PlatformBackButtonName, false);
+                       KeyUp += (s, e) =>
+                       {
+                               if (e.KeyName == EvasKeyEventArgs.PlatformBackButtonName)
+                               {
+                                       BackButtonPressed?.Invoke(this, EventArgs.Empty);
+                               }
+                       };
+
+                       Active();
+                       AutoDeletion = false;
+                       Show();
+
+                       _conformant = new Conformant(this);
+                       _conformant.SetAlignment(-1.0, -1.0);  // fill
+                       _conformant.SetWeight(1.0, 1.0);  // expand
+                       _conformant.Show();
+
+                       AvailableOrientations = DisplayOrientations.Portrait | DisplayOrientations.Landscape | DisplayOrientations.PortraitFlipped | DisplayOrientations.LandscapeFlipped;
+               }
+               DisplayOrientations GetDisplayOrientation()
+               {
+                       switch (Rotation)
+                       {
+                               case 0:
+                               return Native.DisplayOrientations.Portrait;
+
+                               case 90:
+                               return Native.DisplayOrientations.Landscape;
+
+                               case 180:
+                               return Native.DisplayOrientations.PortraitFlipped;
+
+                               case 270:
+                               return Native.DisplayOrientations.LandscapeFlipped;
+
+                               default:
+                               return Native.DisplayOrientations.None;
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Platform.cs b/Xamarin.Forms.Platform.Tizen/Platform.cs
new file mode 100644 (file)
index 0000000..ab07300
--- /dev/null
@@ -0,0 +1,345 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       internal class Platform : BindableObject, IPlatform, INavigation, IDisposable
+       {
+               internal static readonly BindableProperty RendererProperty = BindableProperty.CreateAttached("Renderer", typeof(IVisualElementRenderer), typeof(Platform), default(IVisualElementRenderer),
+                       propertyChanged: (bindable, oldvalue, newvalue) =>
+                       {
+                               var ve = bindable as VisualElement;
+                               if (ve != null)
+                                       ve.IsPlatformEnabled = newvalue != null;
+                       });
+               internal static readonly BindableProperty PageContextProperty = BindableProperty.CreateAttached("PageContext", typeof(FormsApplication), typeof(Platform), null);
+
+               Naviframe _naviframe;
+               NavigationModel _navModel = new NavigationModel();
+               bool _disposed;
+
+               internal Platform(FormsApplication context)
+               {
+                       Forms.Context.MainWindow.BackButtonPressed += (o, e) =>
+                       {
+                               bool handled = false;
+                               if (_navModel.CurrentPage != null)
+                               {
+                                       if (CurrentModalNavigationTask != null && !CurrentModalNavigationTask.IsCompleted)
+                                       {
+                                               handled = true;
+                                       }
+                                       else
+                                       {
+                                               handled = _navModel.CurrentPage.SendBackButtonPressed();
+                                       }
+                               }
+                               if (!handled)
+                                       context.Exit();
+                       };
+                       _naviframe = new Naviframe(Forms.Context.MainWindow)
+                       {
+                               PreserveContentOnPop = true,
+                               DefaultBackButtonEnabled = false,
+                       };
+                       _naviframe.SetAlignment(-1, -1);
+                       _naviframe.SetWeight(1.0, 1.0);
+                       _naviframe.Show();
+                       _naviframe.AnimationFinished += NaviAnimationFinished;
+                       Forms.Context.MainWindow.SetMainPage(_naviframe);
+               }
+
+               ~Platform()
+               {
+                       Dispose(false);
+               }
+
+               public Page Page
+               {
+                       get;
+                       private set;
+               }
+
+               Task CurrentModalNavigationTask { get; set; }
+               TaskCompletionSource<bool> CurrentTaskCompletionSource { get; set; }
+               IPageController CurrentPageController => _navModel.CurrentPage as IPageController;
+               IReadOnlyList<Page> INavigation.ModalStack => _navModel.Modals.ToList();
+               IReadOnlyList<Page> INavigation.NavigationStack => new List<Page>();
+
+               public static FormsApplication GetPageContext(BindableObject bindable)
+               {
+                       return (FormsApplication)bindable.GetValue(Platform.PageContextProperty);
+               }
+
+               public static void SetPageContext(BindableObject bindable, FormsApplication context)
+               {
+                       bindable.SetValue(Platform.PageContextProperty, context);
+               }
+
+               public static IVisualElementRenderer GetRenderer(BindableObject bindable)
+               {
+                       return (IVisualElementRenderer)bindable.GetValue(Platform.RendererProperty);
+               }
+
+               public static void SetRenderer(BindableObject bindable, IVisualElementRenderer value)
+               {
+                       bindable.SetValue(Platform.RendererProperty, value);
+               }
+
+               /// <summary>
+               /// Gets the renderer associated with the <c>view</c>. If it doesn't exist, creates a new one.
+               /// </summary>
+               /// <returns>Renderer associated with the <c>view</c>.</returns>
+               /// <param name="view">View for which the renderer is going to be returned.</param>
+               public static IVisualElementRenderer GetOrCreateRenderer(VisualElement view)
+               {
+                       return GetRenderer(view) ?? AttachRenderer(view);
+               }
+
+               public void Dispose()
+               {
+                       Dispose(true);
+                       GC.SuppressFinalize(this);
+               }
+
+               public void SetPage(Page newRoot)
+               {
+                       if (Page != null)
+                       {
+                               var copyOfStack = new List<NaviItem>(_naviframe.NavigationStack);
+                               for (var i = 0; i < copyOfStack.Count; i++)
+                               {
+                                       copyOfStack[i].Delete();
+                               }
+                               foreach (Page page in _navModel.Roots)
+                               {
+                                       var renderer = GetRenderer(page);
+                                       (page as IPageController)?.SendDisappearing();
+                                       renderer?.Dispose();
+                               }
+                               _navModel = new NavigationModel();
+                       }
+
+                       if (newRoot == null)
+                               return;
+
+                       _navModel.Push(newRoot, null);
+
+                       Page = newRoot;
+                       Page.Platform = this;
+
+                       Platform.SetPageContext(Page, Forms.Context);
+                       IVisualElementRenderer pageRenderer = AttachRenderer(Page);
+                       var naviItem = _naviframe.Push(pageRenderer.NativeView);
+                       naviItem.TitleBarVisible = false;
+                       ((Application)Page.RealParent).NavigationProxy.Inner = this;
+
+                       CurrentPageController?.SendAppearing();
+               }
+
+               public SizeRequest GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint)
+               {
+                       widthConstraint = widthConstraint <= -1 ? double.PositiveInfinity : widthConstraint;
+                       heightConstraint = heightConstraint <= -1 ? double.PositiveInfinity : heightConstraint;
+
+                       double width = !double.IsPositiveInfinity(widthConstraint) ? widthConstraint : Int32.MaxValue;
+                       double height = !double.IsPositiveInfinity(heightConstraint) ? heightConstraint : Int32.MaxValue;
+
+                       return GetRenderer(view).GetDesiredSize(width, height);
+               }
+
+               protected virtual void Dispose(bool disposing)
+               {
+                       if (_disposed) return;
+                       if (disposing)
+                       {
+                               SetPage(null);
+                               _naviframe.Unrealize();
+                       }
+                       _disposed = true;
+               }
+
+               protected override void OnBindingContextChanged()
+               {
+                       BindableObject.SetInheritedBindingContext(Page, base.BindingContext);
+                       base.OnBindingContextChanged();
+               }
+
+               static IVisualElementRenderer AttachRenderer(VisualElement view)
+               {
+                       IVisualElementRenderer visualElementRenderer = Registrar.Registered.GetHandler<IVisualElementRenderer>(view.GetType());
+
+                       if (null == visualElementRenderer)
+                       {
+                               throw new ArgumentException(String.Format("{0} doesn't have assigned renderer!", view.GetType()));
+                       }
+
+                       visualElementRenderer.SetElement(view);
+
+                       return visualElementRenderer;
+               }
+
+               void INavigation.InsertPageBefore(Page page, Page before)
+               {
+                       throw new InvalidOperationException("InsertPageBefore is not supported globally on Tizen, please use a NavigationPage.");
+               }
+
+               Task<Page> INavigation.PopAsync()
+               {
+                       return ((INavigation)this).PopAsync(true);
+               }
+
+               Task<Page> INavigation.PopAsync(bool animated)
+               {
+                       throw new InvalidOperationException("PopAsync is not supported globally on Tizen, please use a NavigationPage.");
+               }
+
+               Task INavigation.PopToRootAsync()
+               {
+                       return ((INavigation)this).PopToRootAsync(true);
+               }
+
+               Task INavigation.PopToRootAsync(bool animated)
+               {
+                       throw new InvalidOperationException("PopToRootAsync is not supported globally on Tizen, please use a NavigationPage.");
+               }
+
+               Task INavigation.PushAsync(Page root)
+               {
+                       return ((INavigation)this).PushAsync(root, true);
+               }
+
+               Task INavigation.PushAsync(Page root, bool animated)
+               {
+                       throw new InvalidOperationException("PushAsync is not supported globally on Tizen, please use a NavigationPage.");
+               }
+
+               void INavigation.RemovePage(Page page)
+               {
+                       throw new InvalidOperationException("RemovePage is not supported globally on Tizen, please use a NavigationPage.");
+               }
+
+               Task INavigation.PushModalAsync(Page modal)
+               {
+                       return ((INavigation)this).PushModalAsync(modal, true);
+               }
+
+               async Task INavigation.PushModalAsync(Page modal, bool animated)
+               {
+                       CurrentPageController?.SendDisappearing();
+
+                       _navModel.PushModal(modal);
+
+                       modal.Platform = this;
+
+                       await PushModalInternal(modal, animated);
+
+                       // Verify that the modal is still on the stack
+                       if (_navModel.CurrentPage == modal)
+                               CurrentPageController.SendAppearing();
+               }
+
+               Task<Page> INavigation.PopModalAsync()
+               {
+                       return ((INavigation)this).PopModalAsync(true);
+               }
+
+               async Task<Page> INavigation.PopModalAsync(bool animated)
+               {
+                       Page modal = _navModel.PopModal();
+
+                       ((IPageController)modal).SendDisappearing();
+
+                       IVisualElementRenderer modalRenderer = GetRenderer(modal);
+                       if (modalRenderer != null)
+                       {
+                               await PopModalInternal(animated);
+                       }
+                       Platform.GetRenderer(modal).Dispose();
+
+                       CurrentPageController?.SendAppearing();
+                       return modal;
+               }
+
+               async Task PushModalInternal(Page modal, bool animated)
+               {
+                       TaskCompletionSource<bool> tcs = null;
+                       if (CurrentModalNavigationTask != null && !CurrentModalNavigationTask.IsCompleted)
+                       {
+                               var previousTask = CurrentModalNavigationTask;
+                               tcs = new TaskCompletionSource<bool>();
+                               CurrentModalNavigationTask = tcs.Task;
+                               await previousTask;
+                       }
+
+                       var after = _naviframe.NavigationStack.LastOrDefault();
+                       NaviItem pushed = null;
+                       if (animated || after == null)
+                       {
+                               pushed = _naviframe.Push(Platform.GetOrCreateRenderer(modal).NativeView, modal.Title);
+                       }
+                       else
+                       {
+                               pushed = _naviframe.InsertAfter(after, Platform.GetOrCreateRenderer(modal).NativeView, modal.Title);
+                       }
+                       pushed.TitleBarVisible = false;
+
+                       bool shouldWait = animated && after != null;
+                       await WaitForCompletion(shouldWait, tcs);
+               }
+
+               async Task PopModalInternal(bool animated)
+               {
+                       TaskCompletionSource<bool> tcs = null;
+                       if (CurrentModalNavigationTask != null && !CurrentModalNavigationTask.IsCompleted)
+                       {
+                               var previousTask = CurrentModalNavigationTask;
+                               tcs = new TaskCompletionSource<bool>();
+                               CurrentModalNavigationTask = tcs.Task;
+                               await previousTask;
+                       }
+
+                       if (animated)
+                       {
+                               _naviframe.Pop();
+                       }
+                       else
+                       {
+                               _naviframe.NavigationStack.LastOrDefault()?.Delete();
+                       }
+
+                       bool shouldWait = animated && (_naviframe.NavigationStack.Count != 0);
+                       await WaitForCompletion(shouldWait, tcs);
+               }
+
+               async Task WaitForCompletion(bool shouldWait, TaskCompletionSource<bool> tcs)
+               {
+                       if (shouldWait)
+                       {
+                               tcs = tcs ?? new TaskCompletionSource<bool>();
+                               CurrentTaskCompletionSource = tcs;
+                               if (CurrentModalNavigationTask == null || CurrentModalNavigationTask.IsCompleted)
+                               {
+                                       CurrentModalNavigationTask = CurrentTaskCompletionSource.Task;
+                               }
+                       }
+                       else
+                       {
+                               tcs?.SetResult(true);
+                       }
+
+                       if (tcs != null)
+                               await tcs.Task;
+               }
+
+               void NaviAnimationFinished(object sender, EventArgs e)
+               {
+                       var tcs = CurrentTaskCompletionSource;
+                       CurrentTaskCompletionSource = null;
+                       tcs?.SetResult(true);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/PlatformEffect.cs b/Xamarin.Forms.Platform.Tizen/PlatformEffect.cs
new file mode 100644 (file)
index 0000000..97dec49
--- /dev/null
@@ -0,0 +1,11 @@
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Base class for platform-specific effect classes.
+       /// </summary>
+       public abstract class PlatformEffect : PlatformEffect<EvasObject, EvasObject>
+       {
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs b/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..37e0221
--- /dev/null
@@ -0,0 +1,59 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+
+[assembly: AssemblyVersion("0.0.1")]
+[assembly: AssemblyCompany("Samsung Electronics")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCopyright("Copyright © Samsung Electronics 2016")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyProduct("Xamarin.Forms")]
+[assembly: AssemblyTitle("Xamarin.Forms.Platform.Tizen")]
+[assembly: AssemblyTrademark("")]
+[assembly: CompilationRelaxations(8)]
+[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
+[assembly: InternalsVisibleTo("Xamarin.Forms.Platform.Tizen.Tests")]
+[assembly: ComVisible(false)]
+
+[assembly: Xamarin.Forms.Dependency(typeof(ResourcesProvider))]
+[assembly: Xamarin.Forms.Dependency(typeof(Deserializer))]
+
+[assembly: ExportRenderer(typeof(Layout), typeof(LayoutRenderer))]
+[assembly: ExportRenderer(typeof(ScrollView), typeof(ScrollViewRenderer))]
+[assembly: ExportRenderer(typeof(CarouselPage), typeof(CarouselPageRenderer))]
+[assembly: ExportRenderer(typeof(ContentPage), typeof(ContentPageRenderer))]
+[assembly: ExportRenderer(typeof(NavigationPage), typeof(NavigationPageRenderer))]
+[assembly: ExportRenderer(typeof(MasterDetailPage), typeof(MasterDetailPageRenderer))]
+[assembly: ExportRenderer(typeof(TabbedPage), typeof(TabbedPageRenderer))]
+
+[assembly: ExportRenderer(typeof(Label), typeof(LabelRenderer))]
+[assembly: ExportRenderer(typeof(Button), typeof(ButtonRenderer))]
+[assembly: ExportRenderer(typeof(Image), typeof(ImageRenderer))]
+[assembly: ExportRenderer(typeof(Slider), typeof(SliderRenderer))]
+[assembly: ExportRenderer(typeof(Picker), typeof(PickerRenderer))]
+[assembly: ExportRenderer(typeof(Frame), typeof(FrameRenderer))]
+[assembly: ExportRenderer(typeof(Stepper), typeof(StepperRenderer))]
+[assembly: ExportRenderer(typeof(DatePicker), typeof(DatePickerRenderer))]
+[assembly: ExportRenderer(typeof(TimePicker), typeof(TimePickerRenderer))]
+[assembly: ExportRenderer(typeof(ProgressBar), typeof(ProgressBarRenderer))]
+[assembly: ExportRenderer(typeof(Switch), typeof(SwitchRenderer))]
+[assembly: ExportRenderer(typeof(ListView), typeof(ListViewRenderer))]
+[assembly: ExportRenderer(typeof(BoxView), typeof(BoxViewRenderer))]
+[assembly: ExportRenderer(typeof(ActivityIndicator), typeof(ActivityIndicatorRenderer))]
+[assembly: ExportRenderer(typeof(SearchBar), typeof(SearchBarRenderer))]
+[assembly: ExportRenderer(typeof(Entry), typeof(EntryRenderer))]
+[assembly: ExportRenderer(typeof(Editor), typeof(EditorRenderer))]
+[assembly: ExportRenderer(typeof(TableView), typeof(TableViewRenderer))]
+[assembly: ExportRenderer(typeof(EvasObjectWrapper), typeof(EvasObjectWrapperRenderer))]
+
+[assembly: ExportImageSourceHandler(typeof(FileImageSource), typeof(FileImageSourceHandler))]
+[assembly: ExportImageSourceHandler(typeof(StreamImageSource), typeof(StreamImageSourceHandler))]
+[assembly: ExportImageSourceHandler(typeof(UriImageSource), typeof(UriImageSourceHandler))]
+
+[assembly: ExportCell(typeof(TextCell), typeof(TextCellRenderer))]
+[assembly: ExportCell(typeof(ImageCell), typeof(ImageCellRenderer))]
+[assembly: ExportCell(typeof(SwitchCell), typeof(SwitchCellRenderer))]
+[assembly: ExportCell(typeof(EntryCell), typeof(EntryCellRenderer))]
+[assembly: ExportCell(typeof(ViewCell), typeof(ViewCellRenderer))]
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ActivityIndicatorRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ActivityIndicatorRenderer.cs
new file mode 100644 (file)
index 0000000..04a69c6
--- /dev/null
@@ -0,0 +1,57 @@
+using EProgressBar = ElmSharp.ProgressBar;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class ActivityIndicatorRenderer : ViewRenderer<ActivityIndicator, EProgressBar>
+       {
+               static readonly EColor s_defaultColor = EColor.Black;
+
+               public ActivityIndicatorRenderer()
+               {
+                       RegisterPropertyHandler(ActivityIndicator.ColorProperty, UpdateColor);
+                       RegisterPropertyHandler(ActivityIndicator.IsRunningProperty, UpdateIsRunning);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<ActivityIndicator> e)
+               {
+                       if (Control == null)
+                       {
+                               var ac = new EProgressBar(Forms.Context.MainWindow)
+                               {
+                                       Style = "process_medium",
+                                       IsPulseMode = true,
+                               };
+                               SetNativeControl(ac);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               void UpdateColor()
+               {
+                       Control.Color = (Element.Color == Color.Default) ? s_defaultColor : Element.Color.ToNative();
+               }
+
+               void UpdateIsRunning()
+               {
+                       if (Element.IsRunning)
+                       {
+                               Control.PlayPulse();
+                       }
+                       else
+                       {
+                               Control.StopPulse();
+                       }
+               }
+
+       };
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/BoxViewRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/BoxViewRenderer.cs
new file mode 100644 (file)
index 0000000..7a9f756
--- /dev/null
@@ -0,0 +1,61 @@
+using System.ComponentModel;
+using EColor = ElmSharp.Color;
+using ERectangle = ElmSharp.Rectangle;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class BoxViewRenderer :
+       VisualElementRenderer<BoxView>
+       {
+               static readonly EColor s_defaultColor = EColor.Transparent;
+
+               ERectangle _control;
+
+               public BoxViewRenderer()
+               {
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
+               {
+                       if (_control == null)
+                       {
+                               _control = new ERectangle(Forms.Context.MainWindow);
+                               SetNativeControl(_control);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               UpdateColor();
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               void UpdateColor()
+               {
+                       Color colorToSet = Element.Color;
+
+                       if (colorToSet == Color.Default)
+                       {
+                               colorToSet = Element.BackgroundColor;
+                       }
+
+                       _control.Color = (colorToSet == Color.Default) ? s_defaultColor : colorToSet.ToNative();
+               }
+
+               protected override void OnElementPropertyChanged(object sender,
+                       PropertyChangedEventArgs e)
+               {
+                       if (e.PropertyName == BoxView.ColorProperty.PropertyName ||
+                               e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
+                       {
+                               UpdateColor();
+                       }
+                       base.OnElementPropertyChanged(sender, e);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ButtonRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ButtonRenderer.cs
new file mode 100644 (file)
index 0000000..a34df54
--- /dev/null
@@ -0,0 +1,95 @@
+using System;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class ButtonRenderer : ViewRenderer<Button, Native.Button>
+       {
+               static readonly EColor s_defaultTextColor = EColor.White;
+
+               public ButtonRenderer()
+               {
+                       RegisterPropertyHandler(Button.TextProperty, UpdateText);
+                       RegisterPropertyHandler(Button.FontFamilyProperty, UpdateText);
+                       RegisterPropertyHandler(Button.FontSizeProperty, UpdateText);
+                       RegisterPropertyHandler(Button.FontAttributesProperty, UpdateText);
+                       RegisterPropertyHandler(Button.TextColorProperty, UpdateTextColor);
+                       RegisterPropertyHandler(Button.ImageProperty, UpdateBitmap);
+                       RegisterPropertyHandler(Button.BorderColorProperty, UpdateBorder);
+                       RegisterPropertyHandler(Button.BorderRadiusProperty, UpdateBorder);
+                       RegisterPropertyHandler(Button.BorderWidthProperty, UpdateBorder);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
+               {
+                       if (Control == null)
+                       {
+                               var button = new Native.Button(Forms.Context.MainWindow)
+                               {
+                                       PropagateEvents = false,
+                               };
+                               SetNativeControl(button);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.Clicked -= ButtonClickedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Control.Clicked += ButtonClickedHandler;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override Size MinimumSize()
+               {
+                       return new Size(Control.MinimumWidth, Control.MinimumHeight);
+               }
+
+               void ButtonClickedHandler(object sender, EventArgs e)
+               {
+                       IButtonController btn = Element as IButtonController;
+                       if (btn != null)
+                       {
+                               btn.SendClicked();
+                       }
+               }
+
+               void UpdateText()
+               {
+                       Control.Text = Element.Text ?? "";
+                       Control.FontSize = Element.FontSize;
+                       Control.FontAttributes = Element.FontAttributes;
+                       Control.FontFamily = Element.FontFamily;
+               }
+
+               void UpdateTextColor()
+               {
+                       Control.TextColor = Element.TextColor.IsDefault ? s_defaultTextColor : Element.TextColor.ToNative();
+               }
+
+               void UpdateBitmap()
+               {
+                       if (!string.IsNullOrEmpty(Element.Image))
+                       {
+                               Control.Image = new Native.Image(Control);
+                               Control.Image.LoadFromImageSourceAsync(Element.Image);
+                       }
+                       else
+                       {
+                               Control.Image = null;
+                       }
+               }
+
+               void UpdateBorder()
+               {
+                       /* The simpler way is to create some specialized theme for button in
+                        * tizen-theme
+                        */
+                       // TODO: implement border handling
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/CarouselPageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/CarouselPageRenderer.cs
new file mode 100644 (file)
index 0000000..812b8ab
--- /dev/null
@@ -0,0 +1,259 @@
+using System;
+using ElmSharp;
+using EColor = ElmSharp.Color;
+using ERectangle = ElmSharp.Rectangle;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Renderer of a CarouselPage widget.
+       /// </summary>
+       public class CarouselPageRenderer : VisualElementRenderer<CarouselPage>, IVisualElementRenderer
+       {
+               /// <summary>
+               /// The minimum length of a swipe to be recognized as a page switching command, in screen pixels unit.
+               /// </summary>
+               public static readonly double s_minimumSwipeLengthX = 200.0;
+
+               // Different levels of "difficulty" in making a valid swipe gesture, determined by a maximum absolute value
+               // of an angle between a line formed by the swipe gesture and the horizontal axis, in arc degrees:
+               public static readonly double s_challengeEasyArcDegrees = 25.0;
+               public static readonly double s_challengeComfortableArcDegrees = 20.0;
+               public static readonly double s_challengeStandardArcDegrees = 15.0;
+               public static readonly double s_challengeHardArcDegrees = 10.0;
+
+               /// <summary>
+               /// The maximum allowed angle between a line formed by the swipe gesture and the horizontal axis, in arc degrees.
+               /// The gesture will be recognized as a page switching command if its angle does not exceed this value.
+               /// </summary>
+               public static readonly double s_thresholdSwipeArcDegrees = s_challengeComfortableArcDegrees;
+
+               /// <summary>
+               /// The tangent of a maximum allowed angle between the swipe line and the horizontal axis.
+               /// </summary>
+               public static readonly double s_thresholdSwipeTangent = Math.Tan(s_thresholdSwipeArcDegrees * (Math.PI / 180.0));
+
+               // A master container for the entire widget:
+               protected Box _box;
+
+               // Used for grabbing gestures over the entire screen, even if Page is smaller than it:
+               protected ERectangle _filler;
+
+               protected GestureLayer _gestureLayer;
+               protected EvasObject _page;
+
+               /// <summary>
+               /// The default constructor.
+               /// </summary>
+               public CarouselPageRenderer()
+               {
+               }
+
+               /// <summary>
+               /// Invoked whenever the CarouselPage element has been changed in Xamarin.
+               /// </summary>
+               /// <param name="e">Event parameters.</param>
+               protected override void OnElementChanged(ElementChangedEventArgs<CarouselPage> e)
+               {
+                       if (NativeView == null)
+                       {
+                               // Creates an overlaying box which serves as a container
+                               // for both page and a gesture handling layer:
+                               _box = new Box(Forms.Context.MainWindow)
+                               {
+                                       IsHorizontal = false,
+                               };
+                               _box.SetAlignment(-1, -1);
+                               _box.SetWeight(1, 1);
+                               _box.Show();
+
+                               // Disallows the Box to lay out its contents. They will be laid out manually,
+                               // because the page has to overlay the conformant rectangle. By default
+                               // Box will lay its contents in a stack. Applying an empty method disables it:
+                               _box.SetLayoutCallback(() => {
+                                       ResizeContentsToFullScreen();
+                               });
+
+                               // Creates a Rectangle used for ensuring that the gestures will get recognized:
+                               _filler = new ERectangle(Forms.Context.MainWindow)
+                               {
+                                       Color = EColor.Transparent,
+                               };
+                               _filler.SetAlignment(-1, -1);
+                               _filler.SetWeight(1, 1);
+                               _filler.Show();
+                               _box.PackEnd(_filler);
+
+                               // Creates a GestureLayer used for swipe gestures recognition and attaches it to the Box:
+                               _gestureLayer = new GestureLayer(_box);
+                               _gestureLayer.Attach(_box);
+                               AddLineGestureHandler();
+
+                               SetNativeControl(_box);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Element.CurrentPageChanged -= OnCurrentPageChanged;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Element.CurrentPageChanged += OnCurrentPageChanged;
+                       }
+
+                       // If pages have been added to the Xamarin widget and the user has not explicitly
+                       // marked one of them to be displayed, displays the first one:
+                       if (_page == null && Element.Children.Count > 0)
+                       {
+                               DisplayPage(Element.Children[0]);
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               /// <summary>
+               /// Called just before the associated element is deleted.
+               /// </summary>
+               /// <param name="disposing">True if the memory release was requested on demand.</param>
+               protected override void Dispose(bool disposing)
+               {
+                       if (_box != null)
+                       {
+                               Element.CurrentPageChanged -= OnCurrentPageChanged;
+
+                               // Unpacks the page from the box to prevent it from being disposed of prematurely:
+                               _box.UnPack(_page);
+
+                               _box.Unrealize();
+                               _box = null;
+                       }
+
+                       base.Dispose(disposing);
+               }
+
+               /// <summary>
+               /// Handles the process of switching between the displayed pages.
+               /// </summary>
+               /// <param name="sender">An object originating the request</param>
+               /// <param name="ea">Additional arguments to the event handler</param>
+               void OnCurrentPageChanged(object sender, EventArgs ea)
+               {
+                       if (_page != null)
+                       {
+                               _page.Hide();
+                               _box.UnPack(_page);
+                       }
+
+                       DisplayPage(Element.CurrentPage);
+                       ResizeContentsToFullScreen();
+               }
+
+               /// <summary>
+               /// Gets the index of the currently displayed page in Element.Children collection.
+               /// </summary>
+               /// <returns>An int value representing the index of the page currently displayed,
+               /// or -1 if no page is being displayed currently.</returns>
+               int GetCurrentPageIndex()
+               {
+                       int index = -1;
+                       for (int k = 0; k < Element.Children.Count; ++k)
+                       {
+                               if (Element.Children[k] == Element.CurrentPage)
+                               {
+                                       index = k;
+                                       break;
+                               }
+                       }
+
+                       return index;
+               }
+
+               /// <summary>
+               /// Resizes the widget's contents to utilize all the available screen space.
+               /// </summary>
+               void ResizeContentsToFullScreen()
+               {
+                       // Box's geometry should match Forms.Context.MainWindow's geometry
+                       // minus the space occupied by the top toolbar.
+                       // Applies Box's geometry to both displayed page and conformant rectangle:
+                       _filler.Geometry = _page.Geometry = _box.Geometry;
+               }
+
+               /// <summary>
+               /// Adds the feature of recognizing swipes to the GestureLayer.
+               /// </summary>
+               void AddLineGestureHandler()
+               {
+                       _gestureLayer.SetLineCallback(GestureLayer.GestureState.End, (line) => {
+                               double horizontalDistance = line.X2 - line.X1;
+                               double verticalDistance = line.Y2 - line.Y1;
+
+                               // Determines whether the movement is long enough to be considered a swipe:
+                               bool isLongEnough = (Math.Abs(horizontalDistance) >= s_minimumSwipeLengthX);
+
+                               // Determines whether the movement is horizontal enough to be considered as a swipe:
+                               // The swipe arc's tangent value (v/h) needs to be lesser than or equal to the threshold value.
+                               // This approach allows for getting rid of computationally heavier atan2() function.
+                               double angleTangent = Math.Abs(verticalDistance) / horizontalDistance;
+                               bool isDirectionForward = (angleTangent < 0);
+
+                               // Determines whether the movement has been recognized as a valid swipe:
+                               bool isSwipeMatching = (isLongEnough && (Math.Abs(angleTangent) <= s_thresholdSwipeTangent));
+
+                               if (isSwipeMatching)
+                               {
+                                       // TODO: Unsure whether changes made via ItemsSource/ItemTemplate properties will be handled correctly this way.
+                                       // If not, it should be implemented in another method.
+                                       if (isDirectionForward)
+                                       {
+                                               // Tries to switch the page to the next one:
+                                               int currentPageIndex = GetCurrentPageIndex();
+                                               if (currentPageIndex < Element.Children.Count - 1)
+                                               {
+                                                       // Sets the current page to the next one:
+                                                       Element.CurrentPage = Element.Children[currentPageIndex + 1];
+                                               }
+                                               else
+                                               {
+                                                       // Reacts to the case of forward-swiping when the last page is already being displayed:
+                                                       Log.Debug("CarouselPage: Displaying the last page already - can not revolve further.");
+
+                                                       // Note (TODO): Once we have a more sophisticated renderer able to e.g. display the animation
+                                                       // of revolving Pages or at least indicate current overall position, some visual feedback
+                                                       // should be provided here for the user who has haplessly tried to access a nonexistent page.
+                                               }
+                                       }
+                                       else
+                                       {
+                                               // Tries to switch the page to the previous one:
+                                               int currentPageIndex = GetCurrentPageIndex();
+                                               if (currentPageIndex > 0)
+                                               {
+                                                       // Sets the current page to the previous one:
+                                                       Element.CurrentPage = Element.Children[currentPageIndex - 1];
+                                               }
+                                               else
+                                               {
+                                                       // Reacts to the case of backward-swiping when the first page is already being displayed:
+                                                       Log.Debug("CarouselPage: The first page is already being displayed - can not revolve further.");
+
+                                                       // Note (TODO): (The same as in case of scrolling forwards)
+                                               }
+                                       }
+                               }
+                       });
+               }
+
+               void DisplayPage(ContentPage p)
+               {
+                       _page = Platform.GetOrCreateRenderer(p).NativeView;
+                       _page.SetAlignment(-1, -1);
+                       _page.SetWeight(1, 1);
+                       _page.Show();
+                       _box.PackEnd(_page);
+               }
+
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ContentPageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ContentPageRenderer.cs
new file mode 100644 (file)
index 0000000..c4f7965
--- /dev/null
@@ -0,0 +1,65 @@
+using System;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Renderer of ContentPage.
+       /// </summary>
+       public class ContentPageRenderer : VisualElementRenderer<ContentPage>
+       {
+               /// <summary>
+               /// Native control which holds the contents.
+               /// </summary>
+               Native.ContentPage _page;
+
+               /// <summary>
+               /// Default constructor.
+               /// </summary>
+               public ContentPageRenderer()
+               {
+                       RegisterPropertyHandler(Page.BackgroundImageProperty, UpdateBackgroundImage);
+                       RegisterPropertyHandler(Page.TitleProperty, UpdateTitle);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<ContentPage> e)
+               {
+                       if (null == _page)
+                       {
+                               _page = new Native.ContentPage(Forms.Context.MainWindow);
+                               _page.LayoutUpdated += new EventHandler<Native.LayoutEventArgs>(OnLayoutUpdated);
+                               SetNativeControl(_page);
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override void UpdateBackgroundColor()
+               {
+                       // base.UpdateBackgroundColor() is not called on purpose, we don't want the regular background setting
+                       if (Element.BackgroundColor.IsDefault || Element.BackgroundColor.A == 0)
+                               _page.Color = EColor.Transparent;
+                       else
+                               _page.Color = Element.BackgroundColor.ToNative();
+               }
+
+               void UpdateBackgroundImage()
+               {
+                       if (string.IsNullOrWhiteSpace(Element.BackgroundImage))
+                               _page.File = null;
+                       else
+                               _page.File = ResourcePath.GetPath(Element.BackgroundImage);
+               }
+
+               void UpdateTitle()
+               {
+                       _page.Title = Element.Title;
+               }
+
+               void OnLayoutUpdated(object sender, Native.LayoutEventArgs e)
+               {
+                       DoLayout(e);
+               }
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/DatePickerRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/DatePickerRenderer.cs
new file mode 100644 (file)
index 0000000..aed7b9d
--- /dev/null
@@ -0,0 +1,77 @@
+using System;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class DatePickerRenderer : ViewRenderer<DatePicker, Native.Button>
+       {
+               //TODO need to add internationalization support
+               const string DialogTitle = "Choose Date";
+               static readonly EColor s_defaultTextColor = EColor.White;
+
+               public DatePickerRenderer()
+               {
+                       RegisterPropertyHandler(DatePicker.DateProperty, UpdateDate);
+                       RegisterPropertyHandler(DatePicker.FormatProperty, UpdateDate);
+                       RegisterPropertyHandler(DatePicker.TextColorProperty, UpdateTextColor);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
+               {
+                       if (Control == null)
+                       {
+                               var button = new Native.Button(Forms.Context.MainWindow);
+                               SetNativeControl(button);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.Clicked -= ButtonClickedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Control.Clicked += ButtonClickedHandler;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               void ButtonClickedHandler(object sender, EventArgs e)
+               {
+                       Native.DateTimePickerDialog dialog = new Native.DateTimePickerDialog(Forms.Context.MainWindow)
+                       {
+                               Title = DialogTitle
+                       };
+
+                       dialog.InitializeDatePicker(Element.Date, Element.MinimumDate, Element.MaximumDate);
+                       dialog.DateTimeChanged += DialogDateTimeChangedHandler;
+                       dialog.Dismissed += DialogDismissedHandler;
+                       dialog.Show();
+               }
+
+               void DialogDateTimeChangedHandler(object sender, Native.DateChangedEventArgs dcea)
+               {
+                       Element.Date = dcea.NewDate;
+                       Control.Text = dcea.NewDate.ToString(Element.Format);
+               }
+
+               void DialogDismissedHandler(object sender, EventArgs e)
+               {
+                       var dialog = sender as Native.DateTimePickerDialog;
+                       dialog.DateTimeChanged -= DialogDateTimeChangedHandler;
+                       dialog.Dismissed -= DialogDismissedHandler;
+               }
+
+               void UpdateDate()
+               {
+                       Control.Text = Element.Date.ToString(Element.Format);
+               }
+
+               void UpdateTextColor()
+               {
+                       Control.TextColor = Element.TextColor.IsDefault ? s_defaultTextColor : Element.TextColor.ToNative();
+               }
+
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/EditorRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/EditorRenderer.cs
new file mode 100644 (file)
index 0000000..0f21463
--- /dev/null
@@ -0,0 +1,88 @@
+using System;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class EditorRenderer : ViewRenderer<Editor, Native.Entry>
+       {
+               static readonly EColor s_defaultTextColor = EColor.Black;
+
+               public EditorRenderer()
+               {
+                       RegisterPropertyHandler(Editor.TextProperty, UpdateText);
+                       RegisterPropertyHandler(Editor.TextColorProperty, UpdateTextColor);
+                       RegisterPropertyHandler(Editor.FontSizeProperty, UpdateFontSize);
+                       RegisterPropertyHandler(Editor.FontFamilyProperty, UpdateFontFamily);
+                       RegisterPropertyHandler(Editor.FontAttributesProperty, UpdateFontAttributes);
+                       RegisterPropertyHandler(Editor.KeyboardProperty, UpdateKeyboard);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
+               {
+                       if (Control == null)
+                       {
+                               var entry = new Native.Entry(Forms.Context.MainWindow)
+                               {
+                                       IsSingleLine = false,
+                                       PropagateEvents = false,
+                               };
+                               SetNativeControl(entry);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.TextChanged -= TextChanged;
+                               Control.Unfocused -= Completed;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Control.TextChanged += TextChanged;
+                               Control.Unfocused += Completed;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               void TextChanged(object sender, EventArgs e)
+               {
+                       Element.Text = ((Native.Entry)sender).Text;
+               }
+
+               void Completed(object sender, EventArgs e)
+               {
+                       Element.SendCompleted();
+               }
+
+               void UpdateText()
+               {
+                       Control.Text = Element.Text;
+               }
+
+               void UpdateTextColor()
+               {
+                       Control.TextColor = Element.TextColor.IsDefault ? s_defaultTextColor : Element.TextColor.ToNative();
+               }
+
+               void UpdateFontSize()
+               {
+                       Control.FontSize = Element.FontSize;
+               }
+
+               void UpdateFontFamily()
+               {
+                       Control.FontFamily = Element.FontFamily;
+               }
+
+               void UpdateFontAttributes()
+               {
+                       Control.FontAttributes = Element.FontAttributes;
+               }
+
+               void UpdateKeyboard()
+               {
+                       Control.Keyboard = Element.Keyboard.ToNative();
+               }
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/EntryRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/EntryRenderer.cs
new file mode 100644 (file)
index 0000000..95828c0
--- /dev/null
@@ -0,0 +1,127 @@
+using System;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class EntryRenderer : ViewRenderer<Entry, Native.Entry>, IDisposable
+       {
+               static readonly EColor s_defaultTextColor = EColor.Black;
+
+               static readonly EColor s_defaultPlaceholderColor = EColor.Gray;
+
+               public EntryRenderer()
+               {
+                       RegisterPropertyHandler(Entry.IsPasswordProperty, UpdateIsPassword);
+                       RegisterPropertyHandler(Entry.TextProperty, UpdateText);
+                       RegisterPropertyHandler(Entry.TextColorProperty, UpdateTextColor);
+                       RegisterPropertyHandler(Entry.FontSizeProperty, UpdateFontSize);
+                       RegisterPropertyHandler(Entry.FontFamilyProperty, UpdateFontFamily);
+                       RegisterPropertyHandler(Entry.FontAttributesProperty, UpdateFontAttributes);
+                       RegisterPropertyHandler(Entry.HorizontalTextAlignmentProperty, UpdateHorizontalTextAlignment);
+                       RegisterPropertyHandler(Entry.KeyboardProperty, UpdateKeyboard);
+                       RegisterPropertyHandler(Entry.PlaceholderProperty, UpdatePlaceholder);
+                       RegisterPropertyHandler(Entry.PlaceholderColorProperty, UpdatePlaceholderColor);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
+               {
+                       if (Control == null)
+                       {
+                               var entry = new Native.Entry(Forms.Context.MainWindow)
+                               {
+                                       IsSingleLine = true,
+                                       PropagateEvents = false,
+                               };
+                               SetNativeControl(entry);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.TextChanged -= EntryChangedHandler;
+                               Control.Activated -= EntryCompletedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Control.TextChanged += EntryChangedHandler;
+                               Control.Activated += EntryCompletedHandler;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (null != Control)
+                       {
+                               Control.TextChanged -= EntryChangedHandler;
+                               Control.Activated -= EntryCompletedHandler;
+                       }
+
+                       base.Dispose(disposing);
+               }
+
+               void EntryChangedHandler(object sender, EventArgs e)
+               {
+                       Element.Text = Control.Text;
+               }
+
+               void EntryCompletedHandler(object sender, EventArgs e)
+               {
+                       //TODO Consider if any other object should overtake focus
+                       Control.SetFocus(false);
+
+                       ((IEntryController)Element).SendCompleted();
+               }
+
+               void UpdateIsPassword()
+               {
+                       Control.IsPassword = Element.IsPassword;
+               }
+
+               void UpdateText()
+               {
+                       Control.Text = Element.Text;
+               }
+
+               void UpdateTextColor()
+               {
+                       Control.TextColor = Element.TextColor.IsDefault ? s_defaultTextColor : Element.TextColor.ToNative();
+               }
+
+               void UpdateFontSize()
+               {
+                       Control.FontSize = Element.FontSize;
+               }
+
+               void UpdateFontFamily()
+               {
+                       Control.FontFamily = Element.FontFamily;
+               }
+
+               void UpdateFontAttributes()
+               {
+                       Control.FontAttributes = Element.FontAttributes;
+               }
+
+               void UpdateHorizontalTextAlignment()
+               {
+                       Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToNative();
+               }
+
+               void UpdateKeyboard()
+               {
+                       Control.Keyboard = Element.Keyboard.ToNative();
+               }
+
+               void UpdatePlaceholder()
+               {
+                       Control.Placeholder = Element.Placeholder;
+               }
+
+               void UpdatePlaceholderColor()
+               {
+                       Control.PlaceholderColor = Element.PlaceholderColor.IsDefault ? s_defaultPlaceholderColor : Element.PlaceholderColor.ToNative();
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/EvasObjectWrapperRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/EvasObjectWrapperRenderer.cs
new file mode 100644 (file)
index 0000000..4e11c27
--- /dev/null
@@ -0,0 +1,32 @@
+using ESize = ElmSharp.Size;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class EvasObjectWrapperRenderer : VisualElementRenderer<EvasObjectWrapper>
+       {
+               protected override void OnElementChanged(ElementChangedEventArgs<EvasObjectWrapper> e)
+               {
+                       if (NativeView == null)
+                       {
+                               SetNativeControl(Element.EvasObject);
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override ESize Measure(int availableWidth, int availableHeight)
+               {
+                       if (Element?.MeasureDelegate == null)
+                       {
+                               return base.Measure(availableWidth, availableHeight);
+                       }
+
+                       // The user has specified a different implementation of MeasureDelegate
+                       ESize? result = Element.MeasureDelegate(this, availableWidth, availableHeight);
+
+                       // If the delegate returns a ElmSharp.Size, we use it; if it returns null,
+                       // fall back to the default implementation
+                       return result ?? base.Measure(availableWidth, availableHeight);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/FrameRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/FrameRenderer.cs
new file mode 100644 (file)
index 0000000..0684c4a
--- /dev/null
@@ -0,0 +1,124 @@
+using ElmSharp;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class FrameRenderer : ViewRenderer<Frame, Native.Canvas>
+       {
+               const int _thickness = 2;
+               const int _shadow_shift = 2;
+               const int _shadow_thickness = _thickness + 2;
+
+               static readonly EColor s_DefaultColor = EColor.Black;
+               static readonly EColor s_ShadowColor = EColor.FromRgba(80, 80, 80, 50);
+
+               Polygon _shadow = null;
+               Polygon _frame = null;
+
+               public FrameRenderer()
+               {
+                       RegisterPropertyHandler(Frame.OutlineColorProperty, UpdateColor);
+                       RegisterPropertyHandler(Frame.HasShadowProperty, UpdateShadowVisibility);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
+               {
+                       if (Control == null)
+                       {
+                               SetNativeControl(new Native.Canvas(Forms.Context.MainWindow));
+
+                               _shadow = new Polygon(NativeView);
+                               _shadow.Color = s_ShadowColor;
+                               Control.Children.Add(_shadow);
+
+                               _frame = new Polygon(NativeView);
+                               _frame.Show();
+                               Control.Children.Add(_frame);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.LayoutUpdated -= OnLayoutUpdated;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Control.LayoutUpdated += OnLayoutUpdated;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               void OnLayoutUpdated(object sender, Native.LayoutEventArgs e)
+               {
+                       UpdateGeometry();
+                       // TODO: why is this DoLayout() required?
+                       if (Element.Content != null)
+                               base.DoLayout(e);
+               }
+
+               void UpdateGeometry()
+               {
+                       var geometry = NativeView.Geometry;
+                       DrawFrame(_frame,
+                               geometry.X,
+                               geometry.Y,
+                               geometry.Right,
+                               geometry.Bottom,
+                               _thickness
+                       );
+                       DrawFrame(_shadow,
+                               geometry.X + _shadow_shift,
+                               geometry.Y + _shadow_shift,
+                               geometry.Right - _thickness + _shadow_shift + _shadow_thickness,
+                               geometry.Bottom - _thickness + _shadow_shift + _shadow_thickness,
+                               _shadow_thickness
+                       );
+               }
+
+               void DrawFrame(Polygon frame, int left, int top, int right, int bottom, int thickness)
+               {
+                       frame.ClearPoints();
+                       if (left + thickness >= right || top + thickness >= bottom)
+                       {
+                               if (left >= right || top >= bottom)
+                                       return;
+                               // shape reduces to a rectangle
+                               frame.AddPoint(left, top);
+                               frame.AddPoint(right, top);
+                               frame.AddPoint(right, bottom);
+                               frame.AddPoint(left, bottom);
+                               return;
+                       }
+                       // outside edge
+                       frame.AddPoint(left, top);
+                       frame.AddPoint(right, top);
+                       frame.AddPoint(right, bottom);
+                       frame.AddPoint(left, bottom);
+                       frame.AddPoint(left, top + thickness);
+                       // and inside edge
+                       frame.AddPoint(left + thickness, top + thickness);
+                       frame.AddPoint(left + thickness, bottom - thickness);
+                       frame.AddPoint(right - thickness, bottom - thickness);
+                       frame.AddPoint(right - thickness, top + thickness);
+                       frame.AddPoint(left, top + thickness);
+               }
+
+               void UpdateColor()
+               {
+                       if (Element.OutlineColor.IsDefault)
+                               _frame.Color = s_DefaultColor;
+                       else
+                               _frame.Color = Element.OutlineColor.ToNative();
+               }
+
+               void UpdateShadowVisibility()
+               {
+                       if (Element.HasShadow)
+                               _shadow.Show();
+                       else
+                               _shadow.Hide();
+               }
+
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/IVisualElementRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/IVisualElementRenderer.cs
new file mode 100644 (file)
index 0000000..4702fd3
--- /dev/null
@@ -0,0 +1,39 @@
+using System;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Base interface for VisualElement renderer.
+       /// </summary>
+       public interface IVisualElementRenderer : IRegisterable, IDisposable
+       {
+               /// <summary>
+               /// Gets the VisualElement associated with this renderer.
+               /// </summary>
+               /// <value>The VisualElement.</value>
+               VisualElement Element
+               {
+                       get;
+               }
+
+               /// <summary>
+               /// Gets the native view associated with this renderer.
+               /// </summary>
+               /// <value>The native view.</value>
+               EvasObject NativeView
+               {
+                       get;
+               }
+
+               /// <summary>
+               /// Sets the VisualElement associated with this renderer.
+               /// </summary>
+               /// <param name="element">New element.</param>
+               void SetElement(VisualElement element);
+
+               SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint);
+
+               void UpdateNativeGeometry();
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ImageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ImageRenderer.cs
new file mode 100644 (file)
index 0000000..ca06a66
--- /dev/null
@@ -0,0 +1,105 @@
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class ImageRenderer : ViewRenderer<Image, Native.Image>
+       {
+               public ImageRenderer()
+               {
+                       RegisterPropertyHandler(Image.SourceProperty, UpdateSource);
+                       RegisterPropertyHandler(Image.AspectProperty, UpdateAspect);
+                       RegisterPropertyHandler(Image.IsOpaqueProperty, UpdateIsOpaque);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
+               {
+                       if (Control == null)
+                       {
+                               var image = new Native.Image(Forms.Context.MainWindow);
+                               SetNativeControl(image);
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               async void UpdateSource()
+               {
+                       ImageSource source = Element.Source;
+
+                       ((IImageController)Element).SetIsLoading(true);
+
+                       if (Control != null)
+                       {
+                               bool success = await Control.LoadFromImageSourceAsync(source);
+                               if (!IsDisposed && success)
+                                       ((IVisualElementController)Element).NativeSizeChanged();
+                       }
+
+                       if (!IsDisposed)
+                               ((IImageController)Element).SetIsLoading(false);
+               }
+
+               void UpdateAspect()
+               {
+                       Control.Aspect = Element.Aspect;
+               }
+
+               void UpdateIsOpaque()
+               {
+                       Control.IsOpaque = Element.IsOpaque;
+               }
+       }
+
+       public interface IImageSourceHandler : IRegisterable
+       {
+               Task<bool> LoadImageAsync(Native.Image image, ImageSource imageSource, CancellationToken cancelationToken = default(CancellationToken));
+       }
+
+       public sealed class FileImageSourceHandler : IImageSourceHandler
+       {
+               public Task<bool> LoadImageAsync(Native.Image image, ImageSource imageSource, CancellationToken cancelationToken = default(CancellationToken))
+               {
+                       var filesource = imageSource as FileImageSource;
+                       if (filesource != null)
+                       {
+                               string file = filesource.File;
+                               if (!string.IsNullOrEmpty(file))
+                                       return image.LoadAsync(ResourcePath.GetPath(file), cancelationToken);
+                       }
+                       return Task.FromResult<bool>(false);
+               }
+       }
+
+       public sealed class StreamImageSourceHandler : IImageSourceHandler
+       {
+               public async Task<bool> LoadImageAsync(Native.Image image, ImageSource imageSource, CancellationToken cancelationToken = default(CancellationToken))
+               {
+                       var streamsource = imageSource as StreamImageSource;
+                       if (streamsource != null && streamsource.Stream != null)
+                       {
+                               using (var streamImage = await ((IStreamImageSource)streamsource).GetStreamAsync(cancelationToken))
+                               {
+                                       if (streamImage != null)
+                                               return await image.LoadAsync(streamImage, cancelationToken);
+                               }
+                       }
+                       return false;
+               }
+       }
+
+       public sealed class UriImageSourceHandler : IImageSourceHandler
+       {
+               public Task<bool> LoadImageAsync(Native.Image image, ImageSource imageSource, CancellationToken cancelationToken = default(CancellationToken))
+               {
+                       var urisource = imageSource as UriImageSource;
+                       if (urisource != null && urisource.Uri != null)
+                       {
+                               return image.LoadAsync(urisource.Uri, cancelationToken);
+                       }
+
+                       return Task.FromResult<bool>(false);
+               }
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/LabelRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/LabelRenderer.cs
new file mode 100644 (file)
index 0000000..5a4744f
--- /dev/null
@@ -0,0 +1,103 @@
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+
+       public class LabelRenderer : ViewRenderer<Label, Native.Label>
+       {
+               static readonly EColor s_defaultBackgroundColor = EColor.Transparent;
+               static readonly EColor s_defaultForegroundColor = EColor.Black;
+               static readonly EColor s_defaultTextColor = s_defaultForegroundColor;
+
+               public LabelRenderer()
+               {
+                       RegisterPropertyHandler(Label.TextProperty, () => Control.Text = Element.Text);
+                       RegisterPropertyHandler(Label.TextColorProperty, UpdateTextColor);
+                       // FontProperty change is called also for FontSizeProperty, FontFamilyProperty and FontAttributesProperty change
+                       RegisterPropertyHandler(Label.FontProperty, UpdateFontProperties);
+                       RegisterPropertyHandler(Label.LineBreakModeProperty, UpdateLineBreakMode);
+                       RegisterPropertyHandler(Label.HorizontalTextAlignmentProperty, UpdateTextAlignment);
+                       RegisterPropertyHandler(Label.VerticalTextAlignmentProperty, UpdateTextAlignment);
+                       RegisterPropertyHandler(Label.FormattedTextProperty, () => Control.FormattedText = ConvertFormattedText(Element.FormattedText));
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
+               {
+                       if (Control == null)
+                       {
+                               var label = new Native.Label(Forms.Context.MainWindow);
+                               base.SetNativeControl(label);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override Size MinimumSize()
+               {
+                       return new Size(Control.MinimumWidth, Control.MinimumHeight);
+               }
+
+               Native.FormattedString ConvertFormattedText(FormattedString formattedString)
+               {
+                       if (formattedString == null)
+                       {
+                               return null;
+                       }
+
+                       Native.FormattedString nativeString = new Native.FormattedString();
+
+                       foreach (var element in formattedString.Spans)
+                       {
+                               Native.Span span = new Native.Span();
+                               span.FormattedText = element.Text;
+                               span.FontAttributes = element.FontAttributes;
+                               span.FontFamily = element.FontFamily;
+                               span.FontSize = element.FontSize;
+                               span.ForegroundColor = element.ForegroundColor.IsDefault ? s_defaultForegroundColor : element.ForegroundColor.ToNative();
+                               span.BackgroundColor = element.BackgroundColor.IsDefault ? s_defaultBackgroundColor : element.BackgroundColor.ToNative();
+
+                               nativeString.Spans.Add(span);
+                       }
+
+                       return nativeString;
+               }
+
+               void UpdateTextColor()
+               {
+                       Control.TextColor = Element.TextColor.IsDefault ? s_defaultTextColor : Element.TextColor.ToNative();
+               }
+
+               void UpdateTextAlignment()
+               {
+                       Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToNative();
+                       Control.VerticalTextAlignment = Element.VerticalTextAlignment.ToNative();
+               }
+
+               void UpdateFontProperties()
+               {
+                       Control.FontSize = Element.FontSize;
+                       Control.FontAttributes = Element.FontAttributes;
+                       Control.FontFamily = Element.FontFamily;
+               }
+
+               void UpdateLineBreakMode()
+               {
+                       if (Element.LineBreakMode == LineBreakMode.CharacterWrap)
+                               Control.LineBreakMode = Native.LineBreakMode.CharacterWrap;
+                       else if (Element.LineBreakMode == LineBreakMode.WordWrap)
+                               Control.LineBreakMode = Native.LineBreakMode.WordWrap;
+                       else if (Element.LineBreakMode == LineBreakMode.NoWrap)
+                               Control.LineBreakMode = Native.LineBreakMode.NoWrap;
+                       else
+                               Control.LineBreakMode = Native.LineBreakMode.MixedWrap;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/LayoutRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/LayoutRenderer.cs
new file mode 100644 (file)
index 0000000..61421c7
--- /dev/null
@@ -0,0 +1,57 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Renderer of a Layout.
+       /// </summary>
+       public class LayoutRenderer : ViewRenderer<Layout, Native.Canvas>
+       {
+               /// <summary>
+               /// Default constructor.
+               /// </summary>
+               public LayoutRenderer()
+               {
+               }
+
+               protected override void UpdateLayout()
+               {
+                       // in case of layouts we need to make sure that the minimum size of the native control is updated
+                       // this is important in case of ScrollView, when it's content is likely to be wider/higher than the window
+                       // EFL does not allow control to be larger than the window if it's minimum size is smaller than window dimensions
+                       ScrollView scrollView = Element.Parent as ScrollView;
+                       if (scrollView != null)
+                       {
+                               Size size = scrollView.ContentSize;
+                               Control.MinimumWidth = ToNativeDimension(Math.Max(size.Width, scrollView.Content.Width));
+                               Control.MinimumHeight = ToNativeDimension(Math.Max(size.Height, scrollView.Content.Height));
+                       }
+
+                       base.UpdateLayout();
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Layout> e)
+               {
+                       if (null == Control)
+                       {
+                               var canvas = new Native.Canvas(Forms.Context.MainWindow);
+                               canvas.LayoutUpdated += OnLayoutUpdated;
+                               SetNativeControl(canvas);
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       Control.LayoutUpdated -= OnLayoutUpdated;
+
+                       base.Dispose(disposing);
+               }
+
+               void OnLayoutUpdated(object sender, Native.LayoutEventArgs e)
+               {
+                       DoLayout(e);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ListViewRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ListViewRenderer.cs
new file mode 100644 (file)
index 0000000..5179d7e
--- /dev/null
@@ -0,0 +1,437 @@
+using System;
+using System.Collections.Specialized;
+using ElmSharp;
+using EProgressBar = ElmSharp.ProgressBar;
+using ERect = ElmSharp.Rect;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Renderer class for Xamarin ListView class. This provides necessary logic translating
+       /// Xamarin API to Tizen Native API. This is a derivate of a ViewRenderer base class.
+       /// This is a template class with two template parameters. First one is restricted to
+       /// Xamarin.Forms.View and can be accessed via property Element. This represent actual
+       /// xamarin view which represents control logic. Second one is restricted to ElmSharp.Widget
+       /// types, and can be accessed with Control property. This represents actual native control
+       /// which is used to draw control and realize xamarin forms api.
+       /// </summary>
+       public class ListViewRenderer : ViewRenderer<ListView, Native.ListView>, IDisposable
+       {
+               /// <summary>
+               /// Event handler for ScrollToRequested.
+               /// </summary>
+               readonly EventHandler<ScrollToRequestedEventArgs> _scrollToRequested;
+
+               /// <summary>
+               /// Event handler for collection changed.
+               /// </summary>
+               readonly NotifyCollectionChangedEventHandler _collectionChanged;
+
+               /// <summary>
+               /// Event handler for grouped collection changed.
+               /// </summary>
+               readonly NotifyCollectionChangedEventHandler _groupedCollectionChanged;
+
+               /// <summary>
+               /// The _lastSelectedItem and _selectedItemChanging are used for realizing ItemTapped event. Since Xamarin
+               /// needs information only when an item has been taped, native handlers need to be agreagated
+               /// and NotifyRowTapped has to be realized with this.
+               /// </summary>
+
+               GenListItem _lastSelectedItem = null;
+               int _selectedItemChanging = 0;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.ListViewRenderer"/> class.
+               /// Note that at this stage of construction renderer dose not have required native element. This should
+               /// only be used with xamarin engine.
+               /// </summary>
+               public ListViewRenderer()
+               {
+                       _scrollToRequested = OnScrollToRequested;
+                       _collectionChanged = OnCollectionChanged;
+                       _groupedCollectionChanged = OnGroupedCollectionChanged;
+
+                       RegisterPropertyHandler(ListView.IsGroupingEnabledProperty, UpdateIsGroupingEnabled);
+                       RegisterPropertyHandler(ListView.HasUnevenRowsProperty, UpdateHasUnevenRows);
+                       RegisterPropertyHandler(ListView.RowHeightProperty, UpdateRowHeight);
+                       RegisterPropertyHandler(ListView.HeaderProperty, UpdateHeader);
+                       RegisterPropertyHandler(ListView.SelectedItemProperty, UpdateSelectedItem);
+                       RegisterPropertyHandler(ListView.FooterProperty, UpdateFooter);
+                       RegisterPropertyHandler(ListView.ItemsSourceProperty, UpdateSource);
+                       RegisterPropertyHandler(ListView.FooterTemplateProperty, UpdateFooter);
+                       RegisterPropertyHandler(ListView.HeaderTemplateProperty, UpdateHeader);
+               }
+
+               /// <summary>
+               /// Invoked on creation of new ListView renderer. Handles the creation of a native
+               /// element and initialization of the renderer.
+               /// </summary>
+               /// <param name="e"><see cref="Xamarin.Forms.Platform.Tizen.ElementChangedEventArgs"/>.</param>
+               protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
+               {
+                       if (Control == null)
+                       {
+                               SetNativeControl(new Native.ListView(Forms.Context.MainWindow));
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               e.OldElement.ScrollToRequested -= _scrollToRequested;
+                               if (Element.IsGroupingEnabled)
+                               {
+                                       e.OldElement.TemplatedItems.GroupedCollectionChanged -= _groupedCollectionChanged;
+                               }
+                               e.OldElement.TemplatedItems.CollectionChanged -= _collectionChanged;
+                               Control.ItemSelected -= ListViewItemSelectedHandler;
+                               Control.ItemUnselected -= ListViewItemUnselectedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               e.NewElement.ScrollToRequested += _scrollToRequested;
+                               Element.TemplatedItems.CollectionChanged += _collectionChanged;
+                               Control.ItemSelected += ListViewItemSelectedHandler;
+                               Control.ItemUnselected += ListViewItemUnselectedHandler;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               /// <summary>
+               /// Handles the disposing of an existing renderer instance. Results in event handlers
+               /// being detached and a Dispose() method from base class (VisualElementRenderer) being invoked.
+               /// </summary>
+               /// <param name="disposing">A boolean flag passed to the invocation of base class' Dispose() method.
+               ///  <c>True</c> if the memory release was requested on demand.</param>
+               protected override void Dispose(bool disposing)
+               {
+                       Element.ScrollToRequested -= _scrollToRequested;
+                       Element.TemplatedItems.CollectionChanged -= _collectionChanged;
+                       Element.TemplatedItems.GroupedCollectionChanged -= _groupedCollectionChanged;
+
+                       base.Dispose(disposing);
+               }
+
+               /// <summary>
+               /// Handles item selected event. Note that it has to handle selection also for grouping mode as well.
+               /// As a result of this method, ItemTapped event should be invoked in Xamarin.
+               /// </summary>
+               /// <param name="sender">A native list instance from which the event has originated.</param>
+               /// <param name="e">Argument associated with handler, it holds native item for which event was raised</param>
+               void ListViewItemSelectedHandler(object sender, GenListItemEventArgs e)
+               {
+                       GenListItem item = e.Item;
+
+                       _lastSelectedItem = item;
+
+                       if (_selectedItemChanging == 0)
+                       {
+                               if (item != null)
+                               {
+                                       int index = -1;
+                                       if (Element.IsGroupingEnabled)
+                                       {
+                                               Native.ListView.ItemContext itemContext = item.Data as Native.ListView.ItemContext;
+                                               if (itemContext.IsGroupItem)
+                                               {
+                                                       return;
+                                               }
+                                               else
+                                               {
+                                                       int groupIndex = (Element.TemplatedItems as System.Collections.IList).IndexOf(itemContext.ListOfSubItems);
+                                                       int inGroupIndex = itemContext.ListOfSubItems.IndexOf(itemContext.Cell);
+
+                                                       ++_selectedItemChanging;
+                                                       Element.NotifyRowTapped(groupIndex, inGroupIndex);
+                                                       --_selectedItemChanging;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               index = Element.TemplatedItems.IndexOf((item.Data as Native.ListView.ItemContext).Cell);
+
+                                               ++_selectedItemChanging;
+                                               Element.NotifyRowTapped(index);
+                                               --_selectedItemChanging;
+                                       }
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Handles item unselected event.
+               /// </summary>
+               /// <param name="sender">A native list instance from which the event has originated.</param>
+               /// <param name="e">Argument associated with handler, it holds native item for which event was raised</param>
+               void ListViewItemUnselectedHandler(object sender, GenListItemEventArgs e)
+               {
+                       if (_selectedItemChanging == 0)
+                       {
+                               _lastSelectedItem = null;
+                       }
+               }
+
+               /// <summary>
+               /// This is method handles "scroll to" requests from xamarin events.
+               /// It allows for scrolling to specified item on list view.
+               /// </summary>
+               /// <param name="sender">A native list instance from which the event has originated.</param>
+               /// <param name="e">ScrollToRequestedEventArgs.</param>
+               void OnScrollToRequested(object sender, ScrollToRequestedEventArgs e)
+               {
+                       Cell cell;
+                       int position;
+                       var scrollArgs = (ITemplatedItemsListScrollToRequestedEventArgs)e;
+
+                       var templatedItems = Element.TemplatedItems;
+                       if (Element.IsGroupingEnabled)
+                       {
+                               var results = templatedItems.GetGroupAndIndexOfItem(scrollArgs.Group, scrollArgs.Item);
+                               if (results.Item1 == -1 || results.Item2 == -1)
+                                       return;
+
+                               var group = templatedItems.GetGroup(results.Item1);
+                               cell = group[results.Item2];
+                       }
+                       else
+                       {
+                               position = templatedItems.GetGlobalIndexOfItem(scrollArgs.Item);
+                               cell = templatedItems[position];
+                       }
+
+                       Control.ApplyScrollTo(cell, e.Position, e.ShouldAnimate);
+               }
+
+               /// <summary>
+               /// Helper class for managing proper postion of Header and Footer element.
+               /// Since both elements need to be implemented with ordinary list elements,
+               /// both header and footer are removed at first, then the list is being modified
+               /// and finally header and footer are prepended and appended to the list, respectively.
+               /// </summary>
+               class HeaderAndFooterHandler : IDisposable
+               {
+                       VisualElement headerElement;
+                       VisualElement footerElement;
+
+                       Native.ListView Control;
+
+                       public HeaderAndFooterHandler(Widget control)
+                       {
+                               Control = control as Native.ListView;
+
+                               if (Control.HasHeader())
+                               {
+                                       headerElement = Control.GetHeader();
+                                       Control.RemoveHeader();
+                               }
+                               if (Control.HasFooter())
+                               {
+                                       footerElement = Control.GetFooter();
+                                       Control.RemoveFooter();
+                               }
+                       }
+
+                       public void Dispose()
+                       {
+                               if (headerElement != null)
+                               {
+                                       Control.SetHeader(headerElement);
+                               }
+                               if (footerElement != null)
+                               {
+                                       Control.SetFooter(footerElement);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// This method is called whenever something changes in list view data model.
+               /// Method will not be invoked for grouping mode, but for example event with
+               /// action reset will be handled here when switching between group and no-group mode.
+               /// </summary>
+               /// <param name="sender">TemplatedItemsList<ItemsView<Cell>, Cell>.</param>
+               /// <param name="e">NotifyCollectionChangedEventArgs.</param>
+               void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+               {
+                       using (new HeaderAndFooterHandler(Control))
+                       {
+                               if (e.Action == NotifyCollectionChangedAction.Add)
+                               {
+                                       Cell before = null;
+                                       if(e.NewStartingIndex + e.NewItems.Count < Element.TemplatedItems.Count)
+                                       {
+                                               before = Element.TemplatedItems[e.NewStartingIndex + e.NewItems.Count];
+                                       }
+                                       Control.AddSource(e.NewItems, before);
+                               }
+                               else if (e.Action == NotifyCollectionChangedAction.Remove)
+                               {
+                                       Control.Remove(e.OldItems);
+                               }
+                               else if (e.Action == NotifyCollectionChangedAction.Reset)
+                               {
+                                       UpdateSource();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// This method is called whenever something changes in list view data model.
+               /// Method will be invoked for grouping mode, but some action can be also handled
+               /// by OnCollectionChanged handler.
+               /// </summary>
+               /// <param name="sender">TemplatedItemsList<ItemsView<Cell>, Cell>.</param>
+               /// <param name="e">NotifyCollectionChangedEventArgs.</param>
+               void OnGroupedCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+               {
+                       using (new HeaderAndFooterHandler(Control))
+                       {
+                               if (e.Action == NotifyCollectionChangedAction.Add)
+                               {
+                                       TemplatedItemsList<ItemsView<Cell>,Cell> itemsGroup = sender as TemplatedItemsList<ItemsView<Cell>,Cell>;
+                                       Cell before = null;
+                                       if (e.NewStartingIndex + e.NewItems.Count < itemsGroup.Count)
+                                       {
+                                               before = itemsGroup[e.NewStartingIndex + e.NewItems.Count];
+                                       }
+                                       Control.AddItemsToGroup(itemsGroup, e.NewItems, before);
+                               }
+                               else if (e.Action == NotifyCollectionChangedAction.Remove)
+                               {
+                                       Control.Remove(e.OldItems);
+                               }
+                               else if (e.Action == NotifyCollectionChangedAction.Reset)
+                               {
+                                       Control.ResetGroup(sender as TemplatedItemsList<ItemsView<Cell>, Cell>);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Updates the source.
+               /// </summary>
+               void UpdateSource()
+               {
+                       Control.Clear();
+                       Control.AddSource(Element.TemplatedItems);
+               }
+
+               /// <summary>
+               /// Updates the header.
+               /// </summary>
+               void UpdateHeader()
+               {
+                       if (Element.Header == null)
+                       {
+                               Control.SetHeader(null);
+                               return;
+                       }
+
+                       if (((IListViewController)Element).HeaderElement == null)
+                       {
+                               Device.StartTimer(new TimeSpan(0), () =>
+                               {
+                                       Control.SetHeader(((IListViewController)Element).HeaderElement as VisualElement);
+                                       return false;
+                               });
+                       }
+                       else
+                       {
+                               Control.SetHeader(((IListViewController)Element).HeaderElement as VisualElement);
+                       }
+               }
+
+               /// <summary>
+               /// Updates the footer.
+               /// </summary>
+               void UpdateFooter()
+               {
+                       if (Element.Footer == null)
+                       {
+                               Control.SetFooter(null);
+                               return;
+                       }
+
+
+                       if (((IListViewController)Element).FooterElement == null)
+                       {
+                               Device.StartTimer(new TimeSpan(0), () =>
+                               {
+                                       Control.SetFooter(((IListViewController)Element).FooterElement as VisualElement);
+                                       return false;
+                               });
+                       }
+                       else
+                       {
+                               Control.SetFooter(((IListViewController)Element).FooterElement as VisualElement);
+                       }
+               }
+
+               /// <summary>
+               /// Updates the has uneven rows.
+               /// </summary>
+               void UpdateHasUnevenRows()
+               {
+                       Control.SetHasUnevenRows(Element.HasUnevenRows);
+               }
+
+               /// <summary>
+               /// Updates the height of the row.
+               /// </summary>
+               void UpdateRowHeight()
+               {
+                       Control.UpdateRealizedItems();
+               }
+
+               /// <summary>
+               /// Updates the is grouping enabled.
+               /// </summary>
+               /// <param name="initialize">If set to <c>true</c>, this method is invoked during initialization
+               /// (otherwise it will be invoked only after property changes).</param>
+               void UpdateIsGroupingEnabled(bool initialize)
+               {
+                       Control.IsGroupingEnabled = Element.IsGroupingEnabled;
+                       if (Element.IsGroupingEnabled)
+                       {
+                               Element.TemplatedItems.GroupedCollectionChanged += _groupedCollectionChanged;
+                       }
+                       else
+                       {
+                               Element.TemplatedItems.GroupedCollectionChanged -= _groupedCollectionChanged;
+                       }
+               }
+
+               /// <summary>
+               /// Method is used for programaticaly selecting choosen item.
+               /// </summary>
+               void UpdateSelectedItem()
+               {
+                       if (_selectedItemChanging == 0)
+                       {
+                               if (Element.SelectedItem == null)
+                               {
+                                       if (_lastSelectedItem != null)
+                                       {
+                                               _lastSelectedItem.IsSelected = false;
+                                               _lastSelectedItem = null;
+                                       }
+                               }
+                               else
+                               {
+                                       var templatedItems = Element.TemplatedItems;
+                                       var results = templatedItems.GetGroupAndIndexOfItem(Element.SelectedItem);
+                                       if (results.Item1 != -1 && results.Item2 != -1)
+                                       {
+                                               var itemGroup = templatedItems.GetGroup(results.Item1);
+                                               var cell = itemGroup[results.Item2];
+
+                                               ++_selectedItemChanging;
+                                               Control.ApplySelectedItem(cell);
+                                               --_selectedItemChanging;
+                                       }
+                               }
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailPageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailPageRenderer.cs
new file mode 100644 (file)
index 0000000..9da812e
--- /dev/null
@@ -0,0 +1,96 @@
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class MasterDetailPageRenderer : VisualElementRenderer<MasterDetailPage>
+       {
+               Native.MasterDetailPage _mdpage;
+
+               /// <summary>
+               /// Default constructor.
+               /// </summary>
+               public MasterDetailPageRenderer()
+               {
+                       RegisterPropertyHandler("Master", UpdateMasterPage);
+                       RegisterPropertyHandler("Detail", UpdateDetailPage);
+                       RegisterPropertyHandler(MasterDetailPage.IsPresentedProperty,
+                               UpdateIsPresented);
+                       RegisterPropertyHandler(MasterDetailPage.MasterBehaviorProperty,
+                               UpdateMasterBehavior);
+                       RegisterPropertyHandler(MasterDetailPage.IsGestureEnabledProperty,
+                               UpdateIsGestureEnabled);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<MasterDetailPage> e)
+               {
+                       if (_mdpage == null)
+                       {
+                               _mdpage = new Native.MasterDetailPage(Forms.Context.MainWindow)
+                               {
+                                       Master = GetNativePage(e.NewElement.Master),
+                                       Detail = GetNativePage(e.NewElement.Detail),
+                                       IsPresented = e.NewElement.IsPresented,
+                               };
+
+                               _mdpage.IsPresentedChanged += (sender, ev) =>
+                               {
+                                       Element.IsPresented = _mdpage.IsPresented;
+                               };
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               (e.OldElement as IMasterDetailPageController).BackButtonPressed -= BackButtonPressedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               (e.NewElement as IMasterDetailPageController).BackButtonPressed += BackButtonPressedHandler;
+                       }
+
+                       UpdateMasterBehavior();
+                       SetNativeControl(_mdpage);
+
+                       base.OnElementChanged(e);
+               }
+
+               void BackButtonPressedHandler(object sender, BackButtonPressedEventArgs e)
+               {
+                       if ((Element != null) && !Element.IsPresented)
+                       {
+                               Element.IsPresented = true;
+                               e.Handled = true;
+                       }
+               }
+
+               EvasObject GetNativePage(Page page)
+               {
+                       var pageRenderer = Platform.GetOrCreateRenderer(page);
+                       return pageRenderer.NativeView;
+               }
+
+               void UpdateMasterBehavior() {
+                       _mdpage.MasterBehavior = Element.MasterBehavior;
+               }
+
+               void UpdateMasterPage()
+               {
+                       _mdpage.Master = GetNativePage(Element.Master);
+               }
+
+               void UpdateDetailPage()
+               {
+                       _mdpage.Detail = GetNativePage(Element.Detail);
+               }
+
+               void UpdateIsPresented()
+               {
+                       _mdpage.IsPresented = Element.IsPresented;
+               }
+
+               void UpdateIsGestureEnabled()
+               {
+                       _mdpage.IsGestureEnabled = Element.IsGestureEnabled;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/NavigationPageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/NavigationPageRenderer.cs
new file mode 100644 (file)
index 0000000..0d2ee2e
--- /dev/null
@@ -0,0 +1,390 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using Xamarin.Forms.Internals;
+using ElmSharp;
+using EButton = ElmSharp.Button;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class NavigationPageRenderer : VisualElementRenderer<NavigationPage>, IDisposable, IVisualElementRenderer
+       {
+               Naviframe _naviFrame = null;
+               Page _previousPage = null;
+               TaskCompletionSource<bool> _currentTaskSource = null;
+               const string _partBackButton = "elm.swallow.prev_btn";
+               const string _leftToolbar = "title_left_btn";
+               const string _rightToolbar = "title_right_btn";
+               const string _defaultToolbarIcon = "naviframe/drawers";
+               const string _partTitle = "default";
+               const string _styleBackButton = "naviframe/back_btn/default";
+               readonly List<Widget> _naviItemContentPartList = new List<Widget>();
+               ToolbarTracker _toolbarTracker = null;
+
+               public NavigationPageRenderer()
+               {
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       _naviFrame.AnimationFinished -= AnimationFinishedHandler;
+                       base.Dispose(disposing);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e)
+               {
+                       if (_naviFrame == null)
+                       {
+                               _naviFrame = new Naviframe(Forms.Context.MainWindow);
+                               _naviFrame.PreserveContentOnPop = true;
+                               _naviFrame.DefaultBackButtonEnabled = true;
+                               _naviFrame.AnimationFinished += AnimationFinishedHandler;
+
+                               SetNativeControl(_naviFrame);
+                       }
+
+                       if (_toolbarTracker == null)
+                       {
+                               _toolbarTracker = new ToolbarTracker();
+                               _toolbarTracker.CollectionChanged += ToolbarTrackerOnCollectionChanged;
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               var navigation = e.OldElement as INavigationPageController;
+                               navigation.PopRequested -= PopRequestedHandler;
+                               navigation.PopToRootRequested -= PopToRootRequestedHandler;
+                               navigation.PushRequested -= PushRequestedHandler;
+                               navigation.RemovePageRequested -= RemovePageRequestedHandler;
+                               navigation.InsertPageBeforeRequested -= InsertPageBeforeRequestedHandler;
+
+                               var pageController = e.OldElement as IPageController;
+                               pageController.InternalChildren.CollectionChanged -= PageCollectionChangedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               var navigation = e.NewElement as INavigationPageController;
+                               navigation.PopRequested += PopRequestedHandler;
+                               navigation.PopToRootRequested += PopToRootRequestedHandler;
+                               navigation.PushRequested += PushRequestedHandler;
+                               navigation.RemovePageRequested += RemovePageRequestedHandler;
+                               navigation.InsertPageBeforeRequested += InsertPageBeforeRequestedHandler;
+
+                               var pageController = e.NewElement as IPageController;
+                               pageController.InternalChildren.CollectionChanged += PageCollectionChangedHandler;
+
+                               foreach (Page page in pageController.InternalChildren)
+                               {
+                                       _naviFrame.Push(Platform.GetOrCreateRenderer(page).NativeView, SpanTitle(page.Title));
+                                       page.PropertyChanged += NavigationBarPropertyChangedHandler;
+
+                                       UpdateHasNavigationBar(page);
+                               }
+
+                               _toolbarTracker.Target = e.NewElement;
+                               _previousPage = e.NewElement.CurrentPage;
+                       }
+                       base.OnElementChanged(e);
+               }
+
+               protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+               {
+                       base.OnElementPropertyChanged(sender, e);
+
+                       if (e.PropertyName == NavigationPage.CurrentPageProperty.PropertyName)
+                       {
+                               (_previousPage as IPageController)?.SendDisappearing();
+                               _previousPage = Element.CurrentPage;
+                               (_previousPage as IPageController)?.SendAppearing();
+                       }
+               }
+
+               void PageCollectionChangedHandler(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
+               {
+                       if (e.OldItems != null)
+                               foreach (Page page in e.OldItems)
+                                       page.PropertyChanged -= NavigationBarPropertyChangedHandler;
+                       if (e.NewItems != null)
+                               foreach (Page page in e.NewItems)
+                                       page.PropertyChanged += NavigationBarPropertyChangedHandler;
+               }
+
+               void ToolbarTrackerOnCollectionChanged(object sender, EventArgs eventArgs)
+               {
+                       UpdateToolbarItem(Element.CurrentPage);
+               }
+
+               void NavigationBarPropertyChangedHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+               {
+                       // this handler is invoked only for child pages (contained on a navigation stack)
+                       if (e.PropertyName == NavigationPage.HasNavigationBarProperty.PropertyName)
+                               UpdateHasNavigationBar(sender as Page);
+                       else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName ||
+                               e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName)
+                               UpdateHasBackButton(sender as Page);
+                       else if (e.PropertyName == Page.TitleProperty.PropertyName ||
+                               e.PropertyName == NavigationPage.BarBackgroundColorProperty.PropertyName ||
+                               e.PropertyName == NavigationPage.BarTextColorProperty.PropertyName ||
+                               e.PropertyName == NavigationPage.TintProperty.PropertyName)
+                               UpdateTitle(sender as Page);
+               }
+
+               void UpdateHasNavigationBar(Page page)
+               {
+                       NaviItem item = GetNaviItemForPage(page);
+                       item.TitleBarVisible = (bool)page.GetValue(NavigationPage.HasNavigationBarProperty);
+                       UpdateToolbarItem(page, item);
+               }
+
+               void UpdateToolbarItem(Page page, NaviItem item = null)
+               {
+                       if (item == null)
+                               item = GetNaviItemForPage(page);
+
+                       if (_naviFrame.NavigationStack.Count == 0 || item == null || item != _naviFrame.NavigationStack.Last())
+                               return;
+
+                       item.SetPartContent(_leftToolbar, null, false);
+                       item.SetPartContent(_rightToolbar, null, false);
+
+                       Native.Button rightButton = GetToolbarButtonIfExists(ToolbarItemOrder.Primary);
+                       item.SetPartContent(_rightToolbar, rightButton);
+
+                       Native.Button leftButton = GetToolbarButtonIfExists(ToolbarItemOrder.Secondary);
+                       if (leftButton == null)
+                               UpdateHasBackButton(page, item);
+                       else
+                               item.SetPartContent(_leftToolbar, leftButton);
+               }
+
+               void UpdateHasBackButton(Page page, NaviItem item = null)
+               {
+                       if (item == null)
+                               item = GetNaviItemForPage(page);
+
+                       EButton button = null;
+
+                       if ((bool)page.GetValue(NavigationPage.HasBackButtonProperty))
+                               button = CreateNavigationButton((string)page.GetValue(NavigationPage.BackButtonTitleProperty));
+                       item.SetPartContent(_partBackButton, button);
+               }
+
+               void UpdateTitle(Page page)
+               {
+                       NaviItem item = GetNaviItemForPage(page);
+                       item.SetPartText(_partTitle, SpanTitle(page.Title));
+               }
+
+               string SpanTitle(string Title)
+               {
+                       Native.Span span = new Native.Span { Text = Title };
+                       if (Element.BarTextColor != Color.Default)
+                       {
+                               span.ForegroundColor = Element.BarTextColor.ToNative();
+                       }
+                       //TODO: changes only background of title not all bar
+                       if (Element.BarBackgroundColor != Color.Default)
+                       {
+                               span.BackgroundColor = Element.BarBackgroundColor.ToNative();
+                       }
+                       else if (Element.Tint != Color.Default)
+                       {
+                               //TODO: This is only for backward compatibility
+                               //- remove when Tint is no longer in Xamarin API
+                               span.BackgroundColor = Element.Tint.ToNative();
+                       }
+                       return span.GetMarkupText();
+               }
+
+               EButton CreateNavigationButton(string text)
+               {
+                       EButton button = new EButton(Forms.Context.MainWindow);
+                       button.Clicked += (sender, e) =>
+                       {
+                               if (!Element.SendBackButtonPressed())
+                                       Forms.Context.Exit();
+                       };
+
+                       button.Style = _styleBackButton;
+                       button.Text = text;
+
+                       _naviItemContentPartList.Add(button);
+                       button.Deleted += NaviItemPartContentDeletedHandler;
+
+                       return button;
+               }
+
+               void NaviItemPartContentDeletedHandler(object sender, EventArgs e)
+               {
+                       _naviItemContentPartList.Remove(sender as Widget);
+               }
+
+               NaviItem GetNaviItemForPage(Page page)
+               {
+                       NaviItem item = null;
+
+                       if (page != null)
+                       {
+                               IVisualElementRenderer renderer = Platform.GetRenderer(page);
+                               if (renderer != null)
+                               {
+                                       EvasObject content = renderer.NativeView;
+
+                                       for (int i = _naviFrame.NavigationStack.Count - 1; i >= 0; --i)
+                                               if (_naviFrame.NavigationStack[i].Content == content)
+                                               {
+                                                       item = _naviFrame.NavigationStack[i];
+                                                       break;
+                                               }
+                               }
+                       }
+                       return item;
+               }
+
+               Native.Button GetToolbarButtonIfExists(ToolbarItemOrder order)
+               {
+                       ToolbarItem item = _toolbarTracker.ToolbarItems.Where(
+                               (i => i.Order == order ||
+                               (order == ToolbarItemOrder.Primary && i.Order == ToolbarItemOrder.Default)))
+                               .OrderBy(i => i.Priority)
+                               .FirstOrDefault();
+
+                       if (item != default(ToolbarItem))
+                       {
+                               return GetToolbarButton(item);
+                       }
+                       return null;
+               }
+
+               Native.Button GetToolbarButton(ToolbarItem item)
+               {
+                       Native.Button button = new Native.Button(Forms.Context.MainWindow);
+                       button.Clicked += (s, e) =>
+                       {
+                               IMenuItemController control = item;
+                               control.Activate();
+                       };
+                       button.Text = item.Text;
+                       button.BackgroundColor = Xamarin.Forms.Color.Transparent.ToNative();
+
+                       if (String.IsNullOrEmpty(item.Icon) && String.IsNullOrEmpty(item.Text))
+                       {
+                               button.Style = _defaultToolbarIcon;
+                       }
+                       else
+                       {
+                               Native.Image iconImage = new Native.Image(Forms.Context.MainWindow);
+                               iconImage.LoadFromImageSourceAsync(item.Icon);
+                               button.Image = iconImage;
+                       }
+
+                       return button;
+               }
+
+               void PopRequestedHandler(object sender, NavigationRequestedEventArgs nre)
+               {
+                       if ((Element as IPageController).InternalChildren.Count == _naviFrame.NavigationStack.Count)
+                       {
+                               if (nre.Animated)
+                               {
+                                       _naviFrame.Pop();
+
+                                       _currentTaskSource = new TaskCompletionSource<bool>();
+                                       nre.Task = _currentTaskSource.Task;
+
+                                       // There is no TransitionFinished (AnimationFinished) event after Pop the last page
+                                       if (_naviFrame.NavigationStack.Count == 0)
+                                               CompleteCurrentNavigationTask();
+                               }
+                               else
+                                       _naviFrame.NavigationStack.Last().Delete();
+                       }
+               }
+
+               void PopToRootRequestedHandler(object sender, NavigationRequestedEventArgs nre)
+               {
+                       List<NaviItem> copyOfStack = new List<NaviItem>(_naviFrame.NavigationStack);
+                       copyOfStack.Reverse();
+                       NaviItem topItem = copyOfStack.FirstOrDefault();
+                       NaviItem rootItem = copyOfStack.LastOrDefault();
+
+                       foreach (NaviItem naviItem in copyOfStack)
+                               if (naviItem != rootItem && naviItem != topItem)
+                                       naviItem.Delete();
+
+                       if (topItem != rootItem)
+                       {
+                               if (nre.Animated)
+                               {
+                                       _naviFrame.Pop();
+
+                                       _currentTaskSource = new TaskCompletionSource<bool>();
+                                       nre.Task = _currentTaskSource.Task;
+                               }
+                               else
+                                       topItem.Delete();
+                       }
+               }
+
+               void PushRequestedHandler(object sender, NavigationRequestedEventArgs nre)
+               {
+                       if (nre.Animated || _naviFrame.NavigationStack.Count == 0)
+                       {
+                               _naviFrame.Push(Platform.GetOrCreateRenderer(nre.Page).NativeView, SpanTitle(nre.Page.Title));
+                               _currentTaskSource = new TaskCompletionSource<bool>();
+                               nre.Task = _currentTaskSource.Task;
+
+                               // There is no TransitionFinished (AnimationFinished) event after the first Push
+                               if (_naviFrame.NavigationStack.Count == 1)
+                                       CompleteCurrentNavigationTask();
+                       }
+                       else
+                               _naviFrame.InsertAfter(_naviFrame.NavigationStack.Last(), Platform.GetOrCreateRenderer(nre.Page).NativeView, SpanTitle(nre.Page.Title));
+
+                       UpdateHasNavigationBar(nre.Page);
+               }
+
+               void RemovePageRequestedHandler(object sender, NavigationRequestedEventArgs nre)
+               {
+                       GetNaviItemForPage(nre.Page).Delete();
+               }
+
+               async void InsertPageBeforeRequestedHandler(object sender, NavigationRequestedEventArgs nre)
+               {
+                       TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
+                       if (Element.CurrentNavigationTask != null && !Element.CurrentNavigationTask.IsCompleted)
+                       {
+                               await Element.CurrentNavigationTask;
+                       }
+                       Element.CurrentNavigationTask = tcs.Task;
+
+                       Device.StartTimer(TimeSpan.FromMilliseconds(0), () =>
+                       {
+                               EvasObject page = Platform.GetOrCreateRenderer(nre.Page).NativeView;
+                               _naviFrame.InsertBefore(GetNaviItemForPage(nre.BeforePage), page, SpanTitle(nre.Page.Title));
+                               tcs.SetResult(true);
+
+                               UpdateHasNavigationBar(nre.Page);
+
+                               return false;
+                       });
+               }
+
+               void AnimationFinishedHandler(object sender, EventArgs e)
+               {
+                       CompleteCurrentNavigationTask();
+               }
+
+               void CompleteCurrentNavigationTask()
+               {
+                       if (_currentTaskSource != null)
+                       {
+                               var tmp = _currentTaskSource;
+                               _currentTaskSource = null;
+                               tmp.SetResult(true);
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/PickerRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/PickerRenderer.cs
new file mode 100644 (file)
index 0000000..9abd507
--- /dev/null
@@ -0,0 +1,119 @@
+using System;
+using System.ComponentModel;
+using System.Collections.Generic;
+using ElmSharp;
+using EButton = ElmSharp.Button;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class PickerRenderer : ViewRenderer<Picker, EButton>
+       {
+               internal List _list;
+               internal Native.Dialog _dialog;
+               Dictionary<ListItem, int> _itemToItemNumber = new Dictionary<ListItem, int>();
+
+               public PickerRenderer()
+               {
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
+               {
+                       if (Control == null)
+                       {
+                               var button = new EButton(Forms.Context.MainWindow);
+                               SetNativeControl (button);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.Clicked -= OnClick;
+                               ((ObservableList<String>)e.OldElement.Items).CollectionChanged -= RowsCollectionChanged;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               UpdateSelectedIndex();
+
+                               Control.Clicked += OnClick;
+                               ((ObservableList<String>)e.NewElement.Items).CollectionChanged += RowsCollectionChanged;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+               {
+                       base.OnElementPropertyChanged(sender, e);
+
+                       if (e.PropertyName == Picker.SelectedIndexProperty.PropertyName)
+                       {
+                               UpdateSelectedIndex();
+                       }
+               }
+
+               void UpdateSelectedIndex()
+               {
+                       Control.Text = (Element.SelectedIndex == -1 || Element.Items == null ?
+                               "" : Element.Items[Element.SelectedIndex]);
+               }
+
+               void RowsCollectionChanged(object sender, EventArgs e)
+               {
+                       UpdateSelectedIndex();
+               }
+
+               void OnClick(object sender, EventArgs e)
+               {
+                       int i = 0;
+                       _dialog = new Native.Dialog(Forms.Context.MainWindow);
+                       _list = new List(_dialog);
+                       _dialog.AlignmentX = -1;
+                       _dialog.AlignmentY = -1;
+
+                       _dialog.Title = Element.Title;
+                       _dialog.Dismissed += DialogDismissed;
+                       _dialog.BackButtonPressed += (object senders, EventArgs es) =>
+                       {
+                               _dialog.Dismiss();
+                       };
+
+                       foreach (var s in Element.Items)
+                       {
+                               ListItem item = _list.Append(s);
+                               _itemToItemNumber[item] = i;
+                               i++;
+                       }
+                       _list.ItemSelected += ItemSelected;
+                       _dialog.Content = _list;
+
+                       _dialog.Show();
+                       _list.Show();
+               }
+
+               void ItemSelected(object senderObject, EventArgs ev)
+               {
+                       Element.SelectedIndex = _itemToItemNumber[(senderObject as List).SelectedItem];
+                       _dialog.Dismiss();
+               }
+
+               void DialogDismissed(object sender, EventArgs e)
+               {
+                       CleanView();
+               }
+
+               void CleanView()
+               {
+                       if (null != _list)
+                       {
+                               _list.Unrealize();
+                               _itemToItemNumber.Clear();
+                               _list = null;
+                       }
+                       if (null != _dialog)
+                       {
+                               _dialog.Unrealize();
+                               _dialog = null;
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ProgressBarRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ProgressBarRenderer.cs
new file mode 100644 (file)
index 0000000..3aacd3f
--- /dev/null
@@ -0,0 +1,60 @@
+using System.ComponentModel;
+using EProgressBar = ElmSharp.ProgressBar;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class ProgressBarRenderer : ViewRenderer<ProgressBar, EProgressBar>
+       {
+               public ProgressBarRenderer()
+               {
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<ProgressBar> e)
+               {
+                       if (base.Control == null)
+                       {
+                               var progressBar = new EProgressBar(Forms.Context.MainWindow);
+                               SetNativeControl(progressBar);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               if (e.NewElement.MinimumWidthRequest == -1 &&
+                               e.NewElement.MinimumHeightRequest == -1 &&
+                               e.NewElement.WidthRequest == -1 &&
+                               e.NewElement.HeightRequest == -1)
+                               {
+                                       Log.Warn("Need to size request");
+                               }
+
+                               UpdateAll();
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               void UpdateAll()
+               {
+                       UpdateProgress();
+               }
+
+               void UpdateProgress()
+               {
+                       Control.Value = Element.Progress;
+               }
+
+               protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+               {
+                       base.OnElementPropertyChanged(sender, e);
+                       if (e.PropertyName == ProgressBar.ProgressProperty.PropertyName)
+                       {
+                               UpdateProgress();
+                       }
+               }
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ScrollViewRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ScrollViewRenderer.cs
new file mode 100755 (executable)
index 0000000..29f15fb
--- /dev/null
@@ -0,0 +1,130 @@
+using System;
+using System.ComponentModel;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// This class provides a Renderer for a ScrollView widget.
+       /// </summary>
+       public class ScrollViewRenderer : ViewRenderer<ScrollView, Scroller>
+       {
+               EvasObject _content;
+
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.ScrollViewRenderer"/> class.
+               /// </summary>
+               public ScrollViewRenderer()
+               {
+                       RegisterPropertyHandler("Content", FillContent);
+               }
+
+               /// <summary>
+               /// Handles the element change event.
+               /// </summary>
+               /// <param name="e">Event arguments.</param>
+               protected override void OnElementChanged(ElementChangedEventArgs<ScrollView> e)
+               {
+                       if (Control == null)
+                       {
+                               var scrollView = new Scroller(Forms.Context.MainWindow);
+                               SetNativeControl(scrollView);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.Scrolled -= ScrollViewScrolledHandler;
+                               (e.OldElement as IScrollViewController).ScrollToRequested -= ScrollRequestHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Control.Scrolled += ScrollViewScrolledHandler;
+                               (e.NewElement as IScrollViewController).ScrollToRequested += ScrollRequestHandler;
+                       }
+
+                       UpdateAll();
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (null != Control)
+                       {
+                               (Control as IScrollViewController).ScrollToRequested -= ScrollRequestHandler;
+                       }
+
+                       base.Dispose(disposing);
+               }
+
+               void FillContent()
+               {
+                       if (_content != null)
+                       {
+                               Control.SetContent(null, true);
+                       }
+
+                       _content = Platform.GetOrCreateRenderer(Element.Content).NativeView;
+
+                       if (_content != null)
+                       {
+                               Control.SetContent(_content, true);
+                       }
+               }
+
+               void UpdateAll()
+               {
+                       UpdateOrientation();
+               }
+
+               void UpdateOrientation()
+               {
+                       switch (Element.Orientation)
+                       {
+                               case ScrollOrientation.Horizontal:
+                                       Control.ScrollBlock = ScrollBlock.Vertical;
+                                       Control.HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Visible;
+                                       Control.VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible;
+                                       break;
+                               case ScrollOrientation.Vertical:
+                                       Control.ScrollBlock = ScrollBlock.Horizontal;
+                                       Control.HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible;
+                                       Control.VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Visible;
+                                       break;
+                               default:
+                                       Control.ScrollBlock = ScrollBlock.None;
+                                       Control.HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Visible;
+                                       Control.VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Visible;
+                                       break;
+                       }
+               }
+
+               /// <summary>
+               /// An event raised on element's property change.
+               /// </summary>
+               /// <param name="sender">Sender.</param>
+               /// <param name="e">Event arguments</param>
+               protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+               {
+                       if (ScrollView.OrientationProperty.PropertyName == e.PropertyName)
+                       {
+                               UpdateOrientation();
+                       }
+
+                       base.OnElementPropertyChanged(sender, e);
+               }
+
+               void ScrollViewScrolledHandler(object sender, EventArgs e)
+               {
+                       var region = Control.CurrentRegion;
+                       ((IScrollViewController)Element).SetScrolledPosition(region.X, region.Y);
+               }
+
+               void ScrollRequestHandler(object sender, ScrollToRequestedEventArgs e)
+               {
+                       Rect region = new Rect(ToNativeDimension(e.ScrollX), ToNativeDimension(e.ScrollY), ToNativeDimension(Element.Width), ToNativeDimension(Element.Height));
+                       Control.ScrollTo(region, e.ShouldAnimate);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/SearchBarRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/SearchBarRenderer.cs
new file mode 100644 (file)
index 0000000..798a049
--- /dev/null
@@ -0,0 +1,167 @@
+using System;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class SearchBarRenderer : ViewRenderer<SearchBar, Native.SearchBar>
+       {
+               //TODO need to add internationalization support
+               const string DefaultPlaceholderText = "Search";
+
+               static readonly EColor s_defaultCancelButtonColor = EColor.Aqua;
+
+               //TODO: read default platform color
+               static readonly EColor s_defaultPlaceholderColor = EColor.Gray;
+               static readonly EColor s_defaultTextColor = EColor.Black;
+               /// <summary>
+               /// Creates a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.SearchBarRenderer"/> class.
+               /// Registers handlers for various properties of the SearchBar widget.
+               /// </summary>
+               public SearchBarRenderer()
+               {
+                       RegisterPropertyHandler(SearchBar.CancelButtonColorProperty, CancelButtonColorPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.FontAttributesProperty, FontAttributesPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.FontFamilyProperty, FontFamilyPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.FontSizeProperty, FontSizePropertyHandler);
+                       RegisterPropertyHandler(SearchBar.HorizontalTextAlignmentProperty, HorizontalTextAlignmentPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.PlaceholderProperty, PlaceholderPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.PlaceholderColorProperty, PlaceholderColorPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.TextProperty, TextPropertyHandler);
+                       RegisterPropertyHandler(SearchBar.TextColorProperty, TextColorPropertyHandler);
+               }
+
+               /// <summary>
+               /// A method called whenever the associated element has changed.
+               /// </summary>
+               protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
+               {
+                       if (Control == null)
+                       {
+                               var searchBar = new Native.SearchBar(Forms.Context.MainWindow);
+                               SetNativeControl(searchBar);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.TextChanged -= SearchBarTextChangedHandler;
+                               Control.SearchButtonPressed -= SearchButtonPressedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Control.TextChanged += SearchBarTextChangedHandler;
+                               Control.SearchButtonPressed += SearchButtonPressedHandler;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override Size MinimumSize()
+               {
+                       return new Size(250, 120);
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's cancel button color property.
+               /// Converts current Color to ElmSharp.Color instance and sets it in the underlying Xamarin.Forms.Platform.Tizen.Native widget.
+               /// </summary>
+               void CancelButtonColorPropertyHandler()
+               {
+                       Control.CancelButtonColor = Element.CancelButtonColor.IsDefault ? s_defaultCancelButtonColor : Element.CancelButtonColor.ToNative();
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's font attributes property.
+               /// Converts current FontAttributes to ElmSharp.FontAttributes instance
+               /// and sets it in the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void FontAttributesPropertyHandler()
+               {
+                       Control.FontAttributes = Element.FontAttributes;
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's font family property.
+               /// Sets current value of FontFamily property to the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void FontFamilyPropertyHandler()
+               {
+                       Control.FontFamily = Element.FontFamily;
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's font size property.
+               /// Sets current value of FontSize property to the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void FontSizePropertyHandler()
+               {
+                       Control.FontSize = Element.FontSize;
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's horizontal text alignment property.
+               /// Converts current HorizontalTextAlignment property's value to Xamarin.Forms.Platform.Tizen.Native.TextAlignment instance
+               /// and sets it in the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void HorizontalTextAlignmentPropertyHandler()
+               {
+                       Control.HorizontalTextAlignment = Element.HorizontalTextAlignment.ToNative();
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's placeholder color property.
+               /// Converts current PlaceholderColor property value to ElmSharp.Color instance
+               /// and sets it in the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void PlaceholderColorPropertyHandler()
+               {
+                       Control.PlaceholderColor = Element.PlaceholderColor.IsDefault ? s_defaultPlaceholderColor : Element.PlaceholderColor.ToNative();
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's placeholder text property.
+               /// </summary>
+               void PlaceholderPropertyHandler()
+               {
+                       Control.Placeholder = Element.Placeholder == null ? DefaultPlaceholderText : Element.Placeholder;
+               }
+
+               /// <summary>
+               /// Called on every change of underlying SearchBar's Text property.
+               /// Rewrites current underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar's Text contents to its Xamarin counterpart.
+               /// </summary>
+               /// <param name="sender">Sender.</param>
+               void SearchBarTextChangedHandler(object sender, EventArgs e)
+               {
+                       Element.Text = Control.Text;
+               }
+
+               /// <summary>
+               /// Called when the user clicks the Search button.
+               /// </summary>
+               /// <param name="sender">Sender.</param>
+               /// <param name="e">Event arguments.</param>
+               void SearchButtonPressedHandler(object sender, EventArgs e)
+               {
+                       (Element as ISearchBarController).OnSearchButtonPressed();
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's text color property.
+               /// Converts current TextColor property value to ElmSharp.Color instance
+               /// and sets it in the underlying Xamarin.Forms.Platform.Tizen.Native.SearchBar widget.
+               /// </summary>
+               void TextColorPropertyHandler()
+               {
+                       Control.TextColor = Element.TextColor.IsDefault ? s_defaultTextColor : Element.TextColor.ToNative();
+               }
+
+               /// <summary>
+               /// Called upon changing of Xamarin widget's text property.
+               /// </summary>
+               void TextPropertyHandler()
+               {
+                       Control.Text = Element.Text;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/SliderRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/SliderRenderer.cs
new file mode 100644 (file)
index 0000000..93cc6e8
--- /dev/null
@@ -0,0 +1,63 @@
+using System;
+using ESlider = ElmSharp.Slider;
+using ESize = ElmSharp.Size;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class SliderRenderer : ViewRenderer<Slider, ESlider>
+       {
+
+               public SliderRenderer()
+               {
+                       RegisterPropertyHandler(Slider.ValueProperty, UpdateValue);
+                       RegisterPropertyHandler(Slider.MinimumProperty, UpdateMinMax);
+                       RegisterPropertyHandler(Slider.MaximumProperty, UpdateMinMax);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
+               {
+                       if (Control == null)
+                       {
+                               var slider = new ESlider(Forms.Context.MainWindow)
+                               {
+                                       PropagateEvents = false,
+                               };
+                               SetNativeControl(slider);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.ValueChanged -= SliderValueChangedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Control.ValueChanged += SliderValueChangedHandler;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override ESize Measure(int availableWidth, int availableHeight)
+               {
+                       return new ESize(Math.Min(200, availableWidth), 50);
+               }
+
+               void SliderValueChangedHandler(object sender, EventArgs e)
+               {
+                       Element.Value = Control.Value;
+               }
+
+               protected void UpdateValue()
+               {
+                       Control.Value = Element.Value;
+               }
+
+               protected void UpdateMinMax()
+               {
+                       Control.Minimum = Element.Minimum;
+                       Control.Maximum = Element.Maximum;
+                       UpdateValue();
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/StepperRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/StepperRenderer.cs
new file mode 100644 (file)
index 0000000..09d1bf6
--- /dev/null
@@ -0,0 +1,86 @@
+using System;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class StepperRenderer : ViewRenderer<Stepper, Spinner>
+       {
+
+               public StepperRenderer()
+               {
+                       RegisterPropertyHandler(Stepper.ValueProperty, UpdateValue);
+                       RegisterPropertyHandler(Stepper.MinimumProperty, UpdateMinMax);
+                       RegisterPropertyHandler(Stepper.MaximumProperty, UpdateMinMax);
+                       RegisterPropertyHandler(Stepper.IncrementProperty, UpdateStep);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
+               {
+                       if (Control == null)
+                       {
+                               var stepper = new Spinner(Forms.Context.MainWindow)
+                               {
+                                       IsEditable = false,
+                               };
+
+                               SetNativeControl(stepper);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.ValueChanged -= StepperValueChangedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Control.ValueChanged += StepperValueChangedHandler;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               void StepperValueChangedHandler(object sender, EventArgs e)
+               {
+                       double newValue = Control.Value;
+                       ((IElementController)Element).SetValueFromRenderer(Stepper.ValueProperty, newValue);
+
+                       // Determines how many decimal places are there in current Stepper's value.
+                       // The 15 pound characters below correspond to the maximum precision of Double type.
+                       var decimalValue = Decimal.Parse(newValue.ToString("0.###############"));
+
+                       // GetBits() method returns an array of four 32-bit integer values.
+                       // The third (0-indexing) element of an array contains the following information:
+                       //     bits 00-15: unused, required to be 0
+                       //     bits 16-23: an exponent between 0 and 28 indicating the power of 10 to divide the integer number passed as a parameter.
+                       //                 Conversely this is the number of decimal digits in the number as well.
+                       //     bits 24-30: unused, required to be 0
+                       //     bit     31: indicates the sign. 0 means positive number, 1 is for negative numbers.
+                       //
+                       // The precision information needs to be extracted from bits 16-23 of third element of an array
+                       // returned by GetBits() call. Right-shifting by 16 bits followed by zeroing anything else results
+                       // in a nice conversion of this data to integer variable.
+                       var precision = (Decimal.GetBits(decimalValue)[3] >> 16) & 0x000000FF;
+
+                       // Sets Stepper's inner label decimal format to use exactly as many decimal places as needed:
+                       Control.LabelFormat = string.Format("%.{0}f", precision);
+               }
+
+               protected void UpdateValue()
+               {
+                       Control.Value = Element.Value;
+               }
+
+               protected void UpdateMinMax()
+               {
+                       Control.Minimum = Element.Minimum;
+                       Control.Maximum = Element.Maximum;
+                       UpdateValue();
+               }
+
+               void UpdateStep()
+               {
+                       Control.Step = Element.Increment;
+               }
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/SwitchRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/SwitchRenderer.cs
new file mode 100644 (file)
index 0000000..b3539e6
--- /dev/null
@@ -0,0 +1,50 @@
+using System;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class SwitchRenderer : ViewRenderer<Switch, Check>
+       {
+               public SwitchRenderer()
+               {
+                       RegisterPropertyHandler(Switch.IsToggledProperty, HandleToggled);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
+               {
+                       if (Control == null)
+                       {
+                               var _switch = new Check(Forms.Context.MainWindow)
+                               {
+                                       PropagateEvents = false,
+                               };
+                               SetNativeControl(_switch);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.StateChanged -= CheckChangedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               Control.Style = "toggle";
+
+                               Control.StateChanged += CheckChangedHandler;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               void CheckChangedHandler(object sender, EventArgs e)
+               {
+                       Element.SetValue(Switch.IsToggledProperty, Control.IsChecked);
+               }
+
+               void HandleToggled()
+               {
+                       Control.IsChecked = Element.IsToggled;
+               }
+
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs
new file mode 100644 (file)
index 0000000..db97b33
--- /dev/null
@@ -0,0 +1,190 @@
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using ElmSharp;
+using EToolbarItem = ElmSharp.ToolbarItem;
+using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class TabbedPageRenderer : VisualElementRenderer<TabbedPage>, IVisualElementRenderer
+       {
+               Box _box;
+               Toolbar _tpage;
+               EvasObject _tcontent;
+               Dictionary<EToolbarItem, Page> _itemToItemPage = new Dictionary<EToolbarItem, Page>();
+
+               public TabbedPageRenderer ()
+               {
+                       //Register for title change property
+                       RegisterPropertyHandler(TabbedPage.TitleProperty, UpdateTitle);
+                       //Register for current page change property
+                       RegisterPropertyHandler("CurrentPage", CurrentPageChanged);
+                       //TODO renderer should add item on EFL toolbar when new Page is added to TabbedPage
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
+               {
+                       if (_tpage == null)
+                       {
+                               //Create box that holds toolbar and selected content
+                               _box = new Box(Forms.Context.MainWindow)
+                               {
+                                       AlignmentX = -1,
+                                       AlignmentY = -1,
+                                       WeightX = 1,
+                                       WeightY = 1,
+                                       IsHorizontal = false,
+                               };
+                               _box.Show();
+
+                               //Create toolbar that is placed inside the _box
+                               _tpage = new Toolbar(Forms.Context.MainWindow)
+                               {
+                                       AlignmentX = -1,
+                                       WeightX = 1,
+                                       ShrinkMode = ToolbarShrinkMode.Expand,
+                                       SelectionMode = ToolbarSelectionMode.Always,
+                               };
+                               _tpage.Show();
+                               //Add callback for item selection
+                               _tpage.Selected += OnCurrentPageChanged;
+                               _box.PackEnd(_tpage);
+
+                               SetNativeControl(_box);
+                               UpdateTitle();
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       if (_box != null)
+                       {
+                               _box.Unrealize();
+                               _box = null;
+                       }
+                       if (_tpage != null)
+                       {
+                               _tpage.Selected -= OnCurrentPageChanged;
+
+                               _tpage.Unrealize();
+                               _tpage = null;
+                       }
+                       base.Dispose(disposing);
+               }
+
+               protected override void OnElementReady()
+               {
+                       FillToolbar();
+                       base.OnElementReady();
+               }
+
+               void UpdateTitle()
+               {
+                       _tpage.Text = Element.Title;
+               }
+
+               void UpdateTitle(Page page)
+               {
+                       if (_itemToItemPage.ContainsValue(page))
+                       {
+                               var pair = _itemToItemPage.FirstOrDefault(x => x.Value == page);
+                               pair.Key.SetPartText(null, pair.Value.Title);
+                       }
+               }
+
+               void OnPageTitleChanged(object sender, PropertyChangedEventArgs e)
+               {
+                       if (e.PropertyName == Page.TitleProperty.PropertyName)
+                       {
+                               UpdateTitle(sender as Page);
+                       }
+               }
+
+               void FillToolbar()
+               {
+                       var logicalChildren = (Element as IElementController).LogicalChildren;
+                       bool hasIcon = false;
+
+                       //add items to toolbar
+                       foreach (Page child in logicalChildren)
+                       {
+                               var childRenderer = Platform.GetRenderer(child);
+                               if (childRenderer != null)
+                               {
+                                       childRenderer.NativeView.Hide();
+                               }
+
+                               EToolbarItem toolbarItem;
+                               if (string.IsNullOrEmpty(child.Icon))
+                               {
+                                       toolbarItem = _tpage.Append(child.Title);
+                               }
+                               else
+                               {
+                                       //elm_toobar style and size hint must be changed at least once before adding the toolbar item having icon.
+                                       if (!hasIcon)
+                                       {
+                                               int windowHeight = Forms.Context.MainWindow.Geometry.Height;
+                                               //This value is from efl-theme-tizen-mobile theme. (NAVIFRAME_TABBAR_HEIGHT_WITH_TITLE_INC 80)
+                                               double requiredToolbarHeight = 80.0;
+                                               double toolBarWeight = requiredToolbarHeight/windowHeight;
+                                               _tpage.Style="tabbar";
+                                               _tpage.TransverseExpansion = true;
+                                               _tpage.SetAlignment(-1,-1);
+                                               _tpage.SetWeight(1, toolBarWeight);
+                                               _box.SetAlignment(-1,-1);
+                                               _box.SetWeight(1, 1- toolBarWeight);
+                                               hasIcon = true;
+                                       }
+                                       toolbarItem = _tpage.Append(child.Title, ResourcePath.GetPath(child.Icon));
+                               }
+                               _itemToItemPage.Add(toolbarItem, child);
+                               if (Element.CurrentPage == child)
+                               {
+                                       //select item on the toolbar and fill content
+                                       toolbarItem.IsSelected = true;
+                                       OnCurrentPageChanged(null, null);
+                               }
+                               child.PropertyChanged += OnPageTitleChanged;
+                       }
+               }
+
+               void OnCurrentPageChanged(object sender, EToolbarItemEventArgs e)
+               {
+                       if (_tpage.SelectedItem == null)
+                               return;
+                       Element.CurrentPage = _itemToItemPage[_tpage.SelectedItem];
+
+                       //detach content from view without EvasObject changes
+                       if (_tcontent != null)
+                       {
+                               //hide content that should not be visible
+                               _tcontent.Hide();
+                               //unpack content that is hiden an prepare for new content
+                               _box.UnPack(_tcontent);
+                       }
+                       //create EvasObject using renderer and remember to not destroy
+                       //it for better performance (creat once)
+                       _tcontent = Platform.GetOrCreateRenderer(Element.CurrentPage).NativeView;
+                       _tcontent.SetAlignment(-1, -1);
+                       _tcontent.SetWeight(1, 1);
+                       _tcontent.Show();
+                       _box.PackEnd(_tcontent);
+               }
+
+               void CurrentPageChanged()
+               {
+                       foreach (KeyValuePair<EToolbarItem, Page> pair in _itemToItemPage)
+                       {
+                               if (pair.Value == Element.CurrentPage)
+                               {
+                                       pair.Key.IsSelected = true;
+                                       return;
+                               }
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/TableViewRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/TableViewRenderer.cs
new file mode 100644 (file)
index 0000000..5912354
--- /dev/null
@@ -0,0 +1,79 @@
+using System;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class TableViewRenderer : ViewRenderer<TableView, Native.TableView>, IVisualElementRenderer
+       {
+               internal static BindableProperty PresentationProperty = BindableProperty.Create("Presentation", typeof(View), typeof(TableSectionBase), null, BindingMode.OneWay, null, null, null, null, null as BindableProperty.CreateDefaultValueDelegate);
+
+               public TableViewRenderer()
+               {
+                       RegisterPropertyHandler(TableView.HasUnevenRowsProperty, UpdateHasUnevenRows);
+                       RegisterPropertyHandler(TableView.RowHeightProperty, UpdateRowHeight);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<TableView> e)
+               {
+                       if (Control == null)
+                       {
+                               var _tableView = new Native.TableView(Forms.Context.MainWindow);
+                               SetNativeControl(_tableView);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.ItemSelected -= ListViewItemSelectedHandler;
+                               e.OldElement.ModelChanged -= OnRootPropertyChanged;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               e.NewElement.ModelChanged += OnRootPropertyChanged;
+                               Control.ItemSelected += ListViewItemSelectedHandler;
+                               Control.ApplyTableRoot(e.NewElement.Root);
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               protected override void Dispose(bool disposing)
+               {
+                       Element.ModelChanged -= OnRootPropertyChanged;
+                       base.Dispose(disposing);
+               }
+
+               void ListViewItemSelectedHandler(object sender, GenListItemEventArgs e)
+               {
+                       var item = e.Item as GenListItem;
+
+                       if (item != null)
+                       {
+                               var clickedCell = item.Data as Native.ListView.ItemContext;
+                               if (null != clickedCell)
+                               {
+                                       Element.Model.RowSelected(clickedCell.Cell);
+                               }
+                       }
+               }
+
+               void OnRootPropertyChanged(object sender, EventArgs e)
+               {
+                       if (Element != null)
+                       {
+                               Control.ApplyTableRoot(Element.Root);
+                       }
+               }
+
+               void UpdateHasUnevenRows()
+               {
+                       //TODO Implement UnevenRows in ListView
+               }
+
+               void UpdateRowHeight()
+               {
+                       Control.UpdateRealizedItems();
+               }
+
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/TimePickerRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/TimePickerRenderer.cs
new file mode 100644 (file)
index 0000000..9f964c1
--- /dev/null
@@ -0,0 +1,101 @@
+using System;
+using System.Globalization;
+using EColor = ElmSharp.Color;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class TimePickerRenderer : ViewRenderer<TimePicker, Native.Button>
+       {
+               //TODO need to add internationalization support
+               const string DialogTitle = "Choose Time";
+
+               static readonly string s_defaultFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;
+
+               static readonly EColor s_defaultTextColor = EColor.White;
+
+               string _format;
+
+               TimeSpan _time;
+
+               public TimePickerRenderer()
+               {
+                       RegisterPropertyHandler(TimePicker.FormatProperty, UpdateFormat);
+                       RegisterPropertyHandler(TimePicker.TimeProperty, UpdateTime);
+                       RegisterPropertyHandler(TimePicker.TextColorProperty, UpdateTextColor);
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
+               {
+                       if (Control == null)
+                       {
+                               var button = new Native.Button(Forms.Context.MainWindow);
+                               SetNativeControl(button);
+                       }
+
+                       if (e.OldElement != null)
+                       {
+                               Control.Clicked -= ButtonClickedHandler;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               _time = DateTime.Now.TimeOfDay;
+                               _format = s_defaultFormat;
+                               UpdateTimeAndFormat();
+
+                               Control.Clicked += ButtonClickedHandler;
+                       }
+
+                       base.OnElementChanged(e);
+               }
+
+               void ButtonClickedHandler(object o, EventArgs e)
+               {
+                       Native.DateTimePickerDialog dialog = new Native.DateTimePickerDialog(Forms.Context.MainWindow)
+                       {
+                               Title = DialogTitle
+                       };
+
+                       dialog.InitializeTimePicker(_time, _format);
+                       dialog.DateTimeChanged += DialogDateTimeChangedHandler;
+                       dialog.Dismissed += DialogDismissedHandler;
+                       dialog.Show();
+               }
+
+               void DialogDateTimeChangedHandler(object sender, Native.DateChangedEventArgs dcea)
+               {
+                       Element.Time = dcea.NewDate.TimeOfDay;
+                       UpdateTime();
+               }
+
+               void DialogDismissedHandler(object sender, EventArgs e)
+               {
+                       var dialog = sender as Native.DateTimePickerDialog;
+                       dialog.DateTimeChanged -= DialogDateTimeChangedHandler;
+                       dialog.Dismissed -= DialogDismissedHandler;
+               }
+
+               void UpdateFormat()
+               {
+                       _format = Element.Format ?? s_defaultFormat;
+                       UpdateTimeAndFormat();
+               }
+
+               void UpdateTextColor()
+               {
+                       Control.TextColor = Element.TextColor.IsDefault ? s_defaultTextColor : Element.TextColor.ToNative();
+               }
+
+               void UpdateTime()
+               {
+                       _time = Element.Time;
+                       UpdateTimeAndFormat();
+               }
+
+               void UpdateTimeAndFormat()
+               {
+                       // Xamarin using DateTime formatting (https://developer.xamarin.com/api/property/Xamarin.Forms.TimePicker.Format/)
+                       Control.Text = new DateTime(_time.Ticks).ToString(_format);
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/ViewRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/ViewRenderer.cs
new file mode 100644 (file)
index 0000000..24debc8
--- /dev/null
@@ -0,0 +1,46 @@
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Base class for view renderers.
+       /// </summary>
+       public abstract class ViewRenderer<TView, TNativeView> : VisualElementRenderer<TView>
+               where TView : View
+               where TNativeView : Widget
+       {
+               /// <summary>
+               /// Default constructor.
+               /// </summary>
+               protected ViewRenderer()
+               {
+               }
+
+               protected override void OnElementChanged(ElementChangedEventArgs<TView> e)
+               {
+                       base.OnElementChanged(e);
+
+                       if (e.OldElement != null)
+                       {
+                               _gestureHandler.Clear();
+                               _gestureHandler = null;
+                       }
+
+                       if (e.NewElement != null)
+                       {
+                               _gestureHandler = new GestureHandler(this);
+                       }
+               }
+
+               /// <summary>
+               /// Native control associated with this renderer.
+               /// </summary>
+               public TNativeView Control
+               {
+                       get
+                       {
+                               return (TNativeView)NativeView;
+                       }
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/VisualElementRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/VisualElementRenderer.cs
new file mode 100644 (file)
index 0000000..8c5c0be
--- /dev/null
@@ -0,0 +1,946 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.ComponentModel;
+using ElmSharp;
+using ELayout = ElmSharp.Layout;
+using EColor = ElmSharp.Color;
+using ESize = ElmSharp.Size;
+using ERect = ElmSharp.Rect;
+using ERectangle = ElmSharp.Rectangle;
+using EBox = ElmSharp.Box;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Base class for rendering of a Xamarin element.
+       /// </summary>
+       public abstract class VisualElementRenderer<TElement> : IVisualElementRenderer, IEffectControlProvider where TElement : VisualElement
+       {
+               /// <summary>
+               /// Holds registered element changed handlers.
+               /// </summary>
+               readonly List<EventHandler<VisualElementChangedEventArgs>> _elementChangedHandlers = new List<EventHandler<VisualElementChangedEventArgs>>();
+
+               /// <summary>
+               /// Handler for property changed events.
+               /// </summary>
+               PropertyChangedEventHandler _propertyChangedHandler;
+
+               EventHandler<EventArg<VisualElement>> _batchCommittedHandler;
+
+               /// <summary>
+               /// Flags which control status of renderer.
+               /// </summary>
+               VisualElementRendererFlags _flags = VisualElementRendererFlags.None;
+
+               /// <summary>
+               /// Holds the native view.
+               /// </summary>
+               EvasObject _view;
+
+               Dictionary<string, Action<bool>> _propertyHandlersWithInit = new Dictionary<string, Action<bool>>();
+
+               Dictionary<string, Action> _propertyHandlers = new Dictionary<string, Action>();
+
+               HashSet<string> _batchedProperties = new HashSet<string>();
+
+               ERectangle _opacityLayer;
+
+               internal GestureHandler _gestureHandler;
+
+               /// <summary>
+               /// Default constructor.
+               /// </summary>
+               protected VisualElementRenderer()
+               {
+                       RegisterPropertyHandler(VisualElement.IsVisibleProperty, UpdateIsVisible);
+                       RegisterPropertyHandler(VisualElement.OpacityProperty, UpdateOpacity);
+                       RegisterPropertyHandler(VisualElement.IsEnabledProperty, UpdateIsEnabled);
+                       RegisterPropertyHandler(VisualElement.InputTransparentProperty, UpdateInputTransparent);
+                       RegisterPropertyHandler(VisualElement.BackgroundColorProperty, UpdateBackgroundColor);
+
+                       RegisterPropertyHandler(VisualElement.AnchorXProperty, ApplyTransformation);
+                       RegisterPropertyHandler(VisualElement.AnchorYProperty, ApplyTransformation);
+                       RegisterPropertyHandler(VisualElement.ScaleProperty, ApplyTransformation);
+                       RegisterPropertyHandler(VisualElement.RotationProperty, ApplyTransformation);
+                       RegisterPropertyHandler(VisualElement.RotationXProperty, ApplyTransformation);
+                       RegisterPropertyHandler(VisualElement.RotationYProperty, ApplyTransformation);
+                       RegisterPropertyHandler(VisualElement.TranslationXProperty, ApplyTransformation);
+                       RegisterPropertyHandler(VisualElement.TranslationYProperty, ApplyTransformation);
+               }
+
+               ~VisualElementRenderer()
+               {
+                       Dispose(false);
+               }
+
+               event EventHandler<VisualElementChangedEventArgs> ElementChanged
+               {
+                       add
+                       {
+                               _elementChangedHandlers.Add(value);
+                       }
+                       remove
+                       {
+                               _elementChangedHandlers.Remove(value);
+                       }
+               }
+
+               /// <summary>
+               /// Gets the Xamarin element associated with this renderer.
+               /// </summary>
+               public TElement Element
+               {
+                       get;
+                       private set;
+               }
+
+               VisualElement IVisualElementRenderer.Element
+               {
+                       get
+                       {
+                               return this.Element;
+                       }
+               }
+
+               public EvasObject NativeView
+               {
+                       get
+                       {
+                               return _view;
+                       }
+               }
+
+               protected bool IsDisposed => (_flags == VisualElementRendererFlags.Disposed);
+
+               /// <summary>
+               /// Releases all resource used by the <see cref="Xamarin.Forms.Platform.Tizen.VisualElementRenderer"/> object.
+               /// </summary>
+               /// <remarks>Call <see cref="Dispose"/> when you are finished using the
+               /// <see cref="Xamarin.Forms.Platform.Tizen.VisualElementRenderer"/>. The <see cref="Dispose"/> method
+               /// leaves the <see cref="Xamarin.Forms.Platform.Tizen.VisualElementRenderer"/> in an unusable state.
+               /// After calling <see cref="Dispose"/>, you must release all references to the
+               /// <see cref="Xamarin.Forms.Platform.Tizen.VisualElementRenderer"/> so the garbage collector can reclaim
+               /// the memory that the <see cref="Xamarin.Forms.Platform.Tizen.VisualElementRenderer"/> was occupying.</remarks>
+               public void Dispose()
+               {
+                       Dispose(true);
+                       GC.SuppressFinalize(this);
+               }
+
+               public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
+               {
+                       if (null == NativeView)
+                       {
+                               return new SizeRequest(new Size(0, 0));
+                       }
+                       else
+                       {
+                               int availableWidth = ToNativeDimension(widthConstraint);
+                               int availableHeight = ToNativeDimension(heightConstraint);
+                               ESize measured;
+
+                               var nativeViewMeasurable = NativeView as Native.IMeasurable;
+                               if (nativeViewMeasurable != null)
+                               {
+                                       measured = nativeViewMeasurable.Measure(availableWidth, availableHeight);
+                               }
+                               else
+                               {
+                                       measured = Measure(availableWidth, availableHeight);
+                               }
+
+                               return new SizeRequest(new Size(measured.Width, measured.Height), MinimumSize());
+                       }
+               }
+
+               /// <summary>
+               /// Sets the element associated with this renderer.
+               /// </summary>
+               public void SetElement(TElement newElement)
+               {
+                       if (newElement == null)
+                       {
+                               throw new ArgumentNullException("newElement");
+                       }
+
+                       TElement oldElement = Element;
+                       if (oldElement != null)
+                       {
+                               throw new InvalidOperationException("oldElement");
+                       }
+
+                       Element = newElement;
+                       if (_propertyChangedHandler == null)
+                       {
+                               _propertyChangedHandler = new PropertyChangedEventHandler(OnElementPropertyChanged);
+                       }
+
+                       if (_batchCommittedHandler == null)
+                       {
+                               _batchCommittedHandler = OnBatchCommitted;
+                       }
+
+                       // send notification
+                       OnElementChanged(new ElementChangedEventArgs<TElement>(oldElement, newElement));
+
+                       // store renderer for the new element
+                       Platform.SetRenderer(newElement, this);
+
+                       // add children
+                       var logicalChildren = (newElement as IElementController).LogicalChildren;
+                       foreach (Element child in logicalChildren)
+                       {
+                               AddChild(child);
+                       }
+
+                       OnElementReady();
+               }
+
+               public void UpdateNativeGeometry()
+               {
+                       var x = ComputeAbsoluteX(Element);
+                       var y = ComputeAbsoluteY(Element);
+                       NativeView.Geometry = new ERect(ToNativeDimension(x), ToNativeDimension(y), ToNativeDimension(Element.Width), ToNativeDimension(Element.Height));
+                       ApplyTransformation();
+                       UpdateOpacityLayer();
+               }
+
+               void IVisualElementRenderer.SetElement(VisualElement element)
+               {
+                       TElement tElement = element as TElement;
+                       if (tElement == null)
+                       {
+                               throw new ArgumentException("Element is not of type " + typeof(TElement), "Element");
+                       }
+                       SetElement(tElement);
+               }
+
+               /// <summary>
+               /// Registers the effect with the element by establishing the parent-child relations needed for rendering on the specific platform.
+               /// </summary>
+               /// <param name="effect">The effect to register.</param>
+               void IEffectControlProvider.RegisterEffect(Effect effect)
+               {
+                       RegisterEffect(effect);
+               }
+
+               /// <summary>
+               /// Registers the effect with the element by establishing the parent-child relations needed for rendering on the specific platform.
+               /// </summary>
+               /// <param name="effect">The effect to register.</param>
+               protected void RegisterEffect(Effect effect)
+               {
+                       var platformEffect = effect as PlatformEffect;
+                       if (platformEffect != null)
+                       {
+                               OnRegisterEffect(platformEffect);
+                       }
+               }
+
+
+               protected virtual void UpdateLayout()
+               {
+                       // we're updating the coordinates of native control only if they were modified
+                       // via Xamarin (Settings.IgnoreBatchCommitted is set to false);
+                       // otherwise native control is already in the right place
+                       if (!Settings.IgnoreBatchCommitted && null != NativeView)
+                       {
+                               UpdateNativeGeometry();
+                       }
+
+                       // we're updating just immediate children
+                       var logicalChildren = (Element as IElementController).LogicalChildren;
+                       foreach (var child in logicalChildren)
+                       {
+                               Platform.GetRenderer(child)?.UpdateNativeGeometry();
+                       }
+               }
+
+               /// <summary>
+               /// Disposes of underlying resources.
+               /// </summary>
+               /// <param name="disposing">True if the memory release was requested on demand.</param>
+               protected virtual void Dispose(bool disposing)
+               {
+                       if ((_flags & VisualElementRendererFlags.Disposed) != 0)
+                       {
+                               return;
+                       }
+
+                       _flags |= VisualElementRendererFlags.Disposed;
+
+                       if (disposing)
+                       {
+                               if (Element != null)
+                               {
+                                       Element.PropertyChanged -= _propertyChangedHandler;
+                                       Element.BatchCommitted -= _batchCommittedHandler;
+
+                                       Element.ChildAdded -= OnChildAdded;
+                                       Element.ChildRemoved -= OnChildRemoved;
+                                       Element.ChildrenReordered -= OnChildrenReordered;
+
+                                       Element.FocusChangeRequested -= OnFocusChangeRequested;
+
+                                       Settings.StartIgnoringBatchCommitted();
+                                       Element.Layout(new Rectangle(0, 0, -1, -1));
+                                       Settings.StopIgnoringBatchCommitted();
+
+                                       var logicalChildren = (Element as IElementController).LogicalChildren;
+                                       foreach (var child in logicalChildren)
+                                       {
+                                               Platform.GetRenderer(child)?.Dispose();
+                                       }
+
+                                       if (Platform.GetRenderer(Element) == this)
+                                       {
+                                               Platform.SetRenderer(Element, (IVisualElementRenderer)null);
+                                       }
+                                       Element = default(TElement);
+                               }
+
+                               if (NativeView != null)
+                               {
+                                       NativeView.Deleted -= NativeViewDeleted;
+                                       EnsureOpacityLayerIsDestroyed();
+                                       NativeView.Unrealize();
+                                       SetNativeView(null);
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Notification that the associated element has changed.
+               /// </summary>
+               /// <param name="e">Event parameters.</param>
+               protected virtual void OnElementChanged(ElementChangedEventArgs<TElement> e)
+               {
+                       if (null != e.OldElement)
+                       {
+                               e.OldElement.PropertyChanged -= _propertyChangedHandler;
+                               e.OldElement.BatchCommitted -= _batchCommittedHandler;
+
+                               e.OldElement.ChildAdded -= OnChildAdded;
+                               e.OldElement.ChildRemoved -= OnChildRemoved;
+                               e.OldElement.ChildrenReordered -= OnChildrenReordered;
+
+                               e.OldElement.FocusChangeRequested -= OnFocusChangeRequested;
+
+                               Settings.StartIgnoringBatchCommitted();
+                               Element.Layout(new Rectangle(0, 0, -1, -1));
+                               Settings.StopIgnoringBatchCommitted();
+
+                               var controller = e.OldElement as IElementController;
+                               if (controller != null && controller.EffectControlProvider == this)
+                               {
+                                       controller.EffectControlProvider = null;
+                               }
+                       }
+
+                       if (null != e.NewElement)
+                       {
+                               e.NewElement.PropertyChanged += _propertyChangedHandler;
+                               e.NewElement.BatchCommitted += _batchCommittedHandler;
+
+                               e.NewElement.ChildAdded += OnChildAdded;
+                               e.NewElement.ChildRemoved += OnChildRemoved;
+                               e.NewElement.ChildrenReordered += OnChildrenReordered;
+
+                               e.NewElement.FocusChangeRequested += OnFocusChangeRequested;
+
+                               UpdateAllProperties(true);
+
+                               var controller = e.NewElement as IElementController;
+                               if (controller != null)
+                               {
+                                       controller.EffectControlProvider = this;
+                               }
+                       }
+
+                       // TODO: handle the event
+               }
+
+               /// <summary>
+               /// Notification that the property of the associated element has changed.
+               /// </summary>
+               /// <param name="sender">Object which sent the notification.</param>
+               /// <param name="e">Event parameters.</param>
+               protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+               {
+                       if (Element.Batched)
+                       {
+                               if (e.PropertyName == VisualElement.XProperty.PropertyName ||
+                                       e.PropertyName == VisualElement.YProperty.PropertyName ||
+                                       e.PropertyName == VisualElement.WidthProperty.PropertyName ||
+                                       e.PropertyName == VisualElement.HeightProperty.PropertyName)
+                               {
+                                       _flags |= VisualElementRendererFlags.NeedsLayout;
+                               }
+                               else if (e.PropertyName == VisualElement.TranslationXProperty.PropertyName ||
+                                               e.PropertyName == VisualElement.TranslationYProperty.PropertyName ||
+                                               e.PropertyName == VisualElement.RotationProperty.PropertyName ||
+                                               e.PropertyName == VisualElement.RotationXProperty.PropertyName ||
+                                               e.PropertyName == VisualElement.RotationYProperty.PropertyName ||
+                                               e.PropertyName == VisualElement.ScaleProperty.PropertyName ||
+                                               e.PropertyName == VisualElement.AnchorXProperty.PropertyName ||
+                                               e.PropertyName == VisualElement.AnchorYProperty.PropertyName)
+                               {
+                                       _flags |= VisualElementRendererFlags.NeedsTransformation;
+                               }
+                               else
+                               {
+                                       _batchedProperties.Add(e.PropertyName);
+                               }
+                               return;
+                       }
+
+                       Action<bool> init;
+                       if (_propertyHandlersWithInit.TryGetValue(e.PropertyName, out init))
+                       {
+                               init(false);
+                       }
+                       else
+                       {
+                               Action handler;
+                               if (_propertyHandlers.TryGetValue(e.PropertyName, out handler))
+                               {
+                                       handler();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Updates the attached event handlers, sets the native control.
+               /// </summary>
+               protected void SetNativeControl(EvasObject control)
+               {
+                       if (NativeView != null)
+                       {
+                               NativeView.Moved -= OnMoved;
+                               NativeView.Deleted -= NativeViewDeleted;
+                               EnsureOpacityLayerIsDestroyed();
+                       }
+
+                       Widget widget = NativeView as Widget;
+                       if (widget != null)
+                       {
+                               widget.Focused -= OnFocused;
+                               widget.Unfocused -= OnUnfocused;
+                       }
+
+                       SetNativeView(control);
+
+                       if (NativeView != null)
+                       {
+                               NativeView.Deleted += NativeViewDeleted;
+                               NativeView.Moved += OnMoved;
+                       }
+
+                       widget = NativeView as Widget;
+                       if (widget != null)
+                       {
+                               widget.Focused += OnFocused;
+                               widget.Unfocused += OnUnfocused;
+                       }
+               }
+
+               void NativeViewDeleted(object sender, EventArgs e)
+               {
+                       Dispose();
+               }
+
+               void OnBatchCommitted(object sender, EventArg<VisualElement> e)
+               {
+                       if (_flags.HasFlag(VisualElementRendererFlags.NeedsLayout))
+                       {
+                               if (!Settings.IgnoreBatchCommitted)
+                               {
+                                       UpdateLayout();
+                                       // UpdateLayout already updates transformation, clear NeedsTranformation flag then
+                                       _flags &= ~VisualElementRendererFlags.NeedsTransformation;
+                               }
+                               _flags ^= VisualElementRendererFlags.NeedsLayout;
+                       }
+                       if (_flags.HasFlag(VisualElementRendererFlags.NeedsTransformation))
+                       {
+                               ApplyTransformation();
+                               _flags ^= VisualElementRendererFlags.NeedsTransformation;
+                       }
+
+                       foreach (string property in _batchedProperties)
+                       {
+                               OnElementPropertyChanged(this, new PropertyChangedEventArgs(property));
+                       }
+                       _batchedProperties.Clear();
+               }
+
+               /// <summary>
+               /// Registers a handler which is executed when specified property changes.
+               /// </summary>
+               /// <param name="property">Handled property.</param>
+               /// <param name="handler">Action to be executed when property changes.</param>
+               protected void RegisterPropertyHandler(BindableProperty property, Action<bool> handler)
+               {
+                       RegisterPropertyHandler(property.PropertyName, handler);
+               }
+
+               /// <summary>
+               /// Registers a handler which is executed when specified property changes.
+               /// </summary>
+               /// <param name="name">Name of the handled property.</param>
+               /// <param name="handler">Action to be executed when property changes.</param>
+               protected void RegisterPropertyHandler(string name, Action<bool> handler)
+               {
+                       _propertyHandlersWithInit.Add(name, handler);
+               }
+
+               /// <summary>
+               /// Registers a handler which is executed when specified property changes.
+               /// </summary>
+               /// <param name="property">Handled property.</param>
+               /// <param name="handler">Action to be executed when property changes.</param>
+               protected void RegisterPropertyHandler(BindableProperty property, Action handler)
+               {
+                       RegisterPropertyHandler(property.PropertyName, handler);
+               }
+
+               /// <summary>
+               /// Registers a handler which is executed when specified property changes.
+               /// </summary>
+               /// <param name="name">Name of the handled property.</param>
+               /// <param name="handler">Action to be executed when property changes.</param>
+               protected void RegisterPropertyHandler(string name, Action handler)
+               {
+                       _propertyHandlers.Add(name, handler);
+               }
+
+               /// <summary>
+               /// Updates all registered properties.
+               /// </summary>
+               /// <param name="initialization">If set to <c>true</c> the method is called for an uninitialized object.</param>
+               protected void UpdateAllProperties(bool initialization)
+               {
+                       foreach (KeyValuePair<string, Action<bool>> kvp in _propertyHandlersWithInit)
+                       {
+                               kvp.Value(initialization);
+                       }
+
+                       foreach (KeyValuePair<string, Action> kvp in _propertyHandlers)
+                       {
+                               kvp.Value();
+                       }
+               }
+
+               /// <summary>
+               /// Called when Element has been set and its native counterpart
+               /// is properly initialized.
+               /// </summary>
+               protected virtual void OnElementReady()
+               {
+               }
+
+               protected void DoLayout(Native.LayoutEventArgs e)
+               {
+                       Settings.StartIgnoringBatchCommitted();
+                       Element.Layout(new Rectangle(Element.X, Element.Y, e.Width, e.Height));
+                       if (e.HasChanged)
+                       {
+                               UpdateLayout();
+                       }
+                       Settings.StopIgnoringBatchCommitted();
+               }
+
+               protected virtual Size MinimumSize()
+               {
+                       return new Size();
+               }
+
+               /// <summary>
+               /// Calculates how much space this element should take, given how much room there is.
+               /// </summary>
+               /// <returns>a desired dimensions of the element</returns>
+               protected virtual ESize Measure(int availableWidth, int availableHeight)
+               {
+                       return new ESize(NativeView.MinimumWidth, NativeView.MinimumHeight);
+               }
+
+               protected virtual void UpdateBackgroundColor()
+               {
+                       if (NativeView is Widget)
+                       {
+                               (NativeView as Widget).BackgroundColor = Element.BackgroundColor.ToNative();
+                       }
+                       else
+                       {
+                               Log.Warn("{0} uses {1} which does not support background color", this, NativeView);
+                       }
+               }
+
+               /// <summary>
+               /// Converts provided value to native dimension.
+               /// </summary>
+               /// <param name="v">value to be converted.</param>
+               /// <returns>converted value</returns>
+               protected static int ToNativeDimension(double v)
+               {
+                       return (int)Math.Round(v);
+               }
+
+               static double ComputeAbsoluteX(VisualElement e)
+               {
+                       return e.X + (e.RealParent is VisualElement ? Platform.GetRenderer(e.RealParent).NativeView.Geometry.X : 0.0);
+               }
+
+               static double ComputeAbsoluteY(VisualElement e)
+               {
+                       return e.Y + (e.RealParent is VisualElement ? Platform.GetRenderer(e.RealParent).NativeView.Geometry.Y : 0.0);
+               }
+
+               /// <summary>
+               /// Handles focus events.
+               /// </summary>
+               void OnFocused(object sender, EventArgs e)
+               {
+                       if (null != Element)
+                       {
+                               Element.SetValue(VisualElement.IsFocusedPropertyKey, true);
+                       }
+               }
+
+               /// <summary>
+               /// Handles unfocus events.
+               /// </summary>
+               void OnUnfocused(object sender, EventArgs e)
+               {
+                       if (null != Element)
+                       {
+                               Element.SetValue(VisualElement.IsFocusedPropertyKey, false);
+                       }
+               }
+
+               /// <summary>
+               /// Sets the native control, updates the control's properties.
+               /// </summary>
+               void SetNativeView(EvasObject control)
+               {
+                       _view = control;
+               }
+
+               /// <summary>
+               /// Adds a new child if it's derived from the VisualElement class. Otherwise this method does nothing.
+               /// </summary>
+               /// <param name="child">Child to be added.</param>
+               void AddChild(Element child)
+               {
+                       VisualElement vElement = child as VisualElement;
+                       if (vElement != null)
+                       {
+                               var childRenderer = Platform.GetOrCreateRenderer(vElement);
+
+                               // if the native view can have children, attach the new child
+                               if (NativeView is Native.IContainable<EvasObject>)
+                               {
+                                       (NativeView as Native.IContainable<EvasObject>).Children.Add(childRenderer.NativeView);
+                               }
+                       }
+               }
+
+               void RemoveChild(VisualElement view)
+               {
+                       var renderer = Platform.GetRenderer(view);
+                       var containerObject = NativeView as Native.IContainable<EvasObject>;
+                       if (containerObject != null)
+                       {
+                               containerObject.Children.Remove(renderer.NativeView);
+                       }
+
+                       renderer.Dispose();
+               }
+
+               void OnChildAdded(object sender, ElementEventArgs e)
+               {
+                       var view = e.Element as VisualElement;
+                       if (view != null)
+                       {
+                               AddChild(view);
+                       }
+
+                       // changing the order makes sense only in case of Layouts
+                       if (Element is Layout)
+                       {
+                               IElementController controller = Element as IElementController;
+                               if (controller.LogicalChildren[controller.LogicalChildren.Count - 1] != view)
+                               {
+                                       EnsureChildOrder();
+                               }
+                       }
+               }
+
+               void OnChildRemoved(object sender, ElementEventArgs e)
+               {
+                       var view = e.Element as VisualElement;
+                       if (view != null)
+                       {
+                               RemoveChild(view);
+                       }
+               }
+
+               void OnChildrenReordered(object sender, EventArgs e)
+               {
+                       EnsureChildOrder();
+                       Layout layout = Element as Layout;
+                       if (layout != null)
+                       {
+                               layout.InvalidateMeasureInternal(Internals.InvalidationTrigger.MeasureChanged);
+                               layout.ForceLayout();
+                       }
+               }
+
+               void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e)
+               {
+                       Widget widget = NativeView as Widget;
+                       if (widget == null)
+                       {
+                               Log.Warn("{0} is not a widget, it cannot receive focus", NativeView);
+                               return;
+                       }
+
+                       widget.SetFocus(e.Focus);
+                       e.Result = true;
+               }
+
+               /// <summary>
+               /// On register the effect
+               /// </summary>
+               /// <param name="effect">The effect to register.</param>
+               void OnRegisterEffect(PlatformEffect effect)
+               {
+                       effect.Container = Element.Parent == null ? null : Platform.GetRenderer(Element.Parent).NativeView;
+                       effect.Control = NativeView;
+               }
+
+               void OnMoved(object sender, EventArgs e)
+               {
+                       UpdateOpacityLayer();
+                       ApplyTransformation();
+                       _gestureHandler?.UpdateHitBox();
+               }
+
+               void EnsureChildOrder()
+               {
+                       var logicalChildren = (Element as IElementController).LogicalChildren;
+                       for (var i = logicalChildren.Count - 1; i >= 0; --i)
+                       {
+                               var element = logicalChildren[i] as VisualElement;
+                               if (element != null)
+                               {
+                                       Platform.GetRenderer(element).NativeView?.Lower();
+                               }
+                       }
+               }
+
+               void UpdateIsVisible()
+               {
+                       if (null != NativeView)
+                       {
+                               if (Element.IsVisible)
+                               {
+                                       NativeView.Show();
+                               }
+                               else
+                               {
+                                       NativeView.Hide();
+                               }
+                       }
+               }
+
+               void UpdateOpacity()
+               {
+                       if (null != NativeView)
+                       {
+                               if (Element.Opacity < 1.0)
+                               {
+                                       EnsureOpacityLayerExists();
+
+                                       var alpha = (int)(Element.Opacity * 255.0);
+                                       _opacityLayer.Color = new EColor(255, 255, 255, alpha);
+                               }
+                               else
+                               {
+                                       EnsureOpacityLayerIsDestroyed();
+                               }
+                       }
+               }
+
+               /// <summary>
+               /// Updates the IsEnabled property.
+               /// </summary>
+               void UpdateIsEnabled()
+               {
+                       Widget widget = NativeView as Widget;
+                       if (widget != null)
+                       {
+                               widget.IsEnabled = Element.IsEnabled;
+                       }
+               }
+
+               /// <summary>
+               /// Updates the InputTransparent property.
+               /// </summary>
+               void UpdateInputTransparent()
+               {
+                       NativeView.PassEvents = Element.InputTransparent;
+               }
+
+               void ApplyRotation(EvasMap map, ERect geometry, ref bool changed)
+               {
+                       var rotationX = Element.RotationX;
+                       var rotationY = Element.RotationY;
+                       var rotationZ = Element.Rotation;
+                       var anchorX = Element.AnchorX;
+                       var anchorY = Element.AnchorY;
+
+                       // apply rotations
+                       if (rotationX != 0 || rotationY != 0 || rotationZ != 0)
+                       {
+                               map.Rotate3D(rotationX, rotationY, rotationZ, (int)(geometry.X + geometry.Width * anchorX),
+                                                                                                                         (int)(geometry.Y + geometry.Height * anchorY), 0);
+                               changed = true;
+                       }
+               }
+
+               void ApplyScale(EvasMap map, ERect geometry, ref bool changed)
+               {
+                       var scale = Element.Scale;
+
+                       // apply scale factor
+                       if (scale != 1.0)
+                       {
+                               map.Zoom(scale, scale,
+                                       geometry.X + (int)(geometry.Width * Element.AnchorX),
+                                       geometry.Y + (int)(geometry.Height * Element.AnchorY));
+                               changed = true;
+                       }
+               }
+
+               void ApplyTranslation(EvasMap map, ERect geometry, ref bool changed)
+               {
+                       var shiftX = ToNativeDimension(Element.TranslationX);
+                       var shiftY = ToNativeDimension(Element.TranslationY);
+
+                       // apply translation, i.e. move/shift the object a little
+                       if (shiftX != 0 || shiftY != 0)
+                       {
+                               if (changed)
+                               {
+                                       // special care is taken to apply the translation last
+                                       Point3D p;
+                                       for (int i = 0; i < 4; i++)
+                                       {
+                                               p = map.GetPointCoordinate(i);
+                                               p.X += shiftX;
+                                               p.Y += shiftY;
+                                               map.SetPointCoordinate(i, p);
+                                       }
+                               }
+                               else
+                               {
+                                       // in case when we only need translation, then construct the map in a simpler way
+                                       geometry.X += shiftX;
+                                       geometry.Y += shiftY;
+                                       map.PopulatePoints(geometry, 0);
+
+                                       changed = true;
+                               }
+                       }
+               }
+
+               public void ApplyTransformation()
+               {
+                       if (null == NativeView)
+                       {
+                               Log.Error("Trying to apply transformation to the non-existent native control");
+                               return;
+                       }
+
+                       // prepare the EFL effect structure
+                       ERect geometry = NativeView.Geometry;
+                       EvasMap map = new EvasMap(4);
+                       map.PopulatePoints(geometry, 0);
+
+                       bool changed = false;
+                       ApplyRotation(map, geometry, ref changed);
+                       ApplyScale(map, geometry, ref changed);
+                       ApplyTranslation(map, geometry, ref changed);
+
+                       NativeView.IsMapEnabled = changed;
+
+                       if (changed)
+                       {
+                               NativeView.EvasMap = map;
+
+                               if (_opacityLayer != null)
+                               {
+                                       _opacityLayer.IsMapEnabled = true;
+                                       _opacityLayer.EvasMap = map;
+                               }
+                       }
+                       _gestureHandler?.UpdateHitBox();
+               }
+
+               protected virtual void UpdateOpacityLayer()
+               {
+                       if (_opacityLayer != null)
+                       {
+                               _opacityLayer.Geometry = NativeView.Geometry;
+                               NativeView.SetClip(_opacityLayer);
+                       }
+               }
+
+               void EnsureOpacityLayerExists()
+               {
+                       if (_opacityLayer == null)
+                       {
+                               _opacityLayer = new ERectangle(NativeView);
+                               UpdateOpacityLayer();
+                               _opacityLayer.Show();
+                       }
+               }
+
+               void EnsureOpacityLayerIsDestroyed()
+               {
+                       if (_opacityLayer != null)
+                       {
+                               NativeView.SetClip(null);
+                               _opacityLayer.Unrealize();
+                               _opacityLayer = null;
+                       }
+               }
+       }
+
+       internal static class Settings
+       {
+               static int s_ignoreCount = 0;
+
+               public static bool IgnoreBatchCommitted
+               {
+                       get
+                       {
+                               return s_ignoreCount != 0;
+                       }
+               }
+
+               public static void StartIgnoringBatchCommitted()
+               {
+                       ++s_ignoreCount;
+               }
+
+               public static void StopIgnoringBatchCommitted()
+               {
+                       Debug.Assert(s_ignoreCount > 0);
+                       --s_ignoreCount;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/ResourcePath.cs b/Xamarin.Forms.Platform.Tizen/ResourcePath.cs
new file mode 100644 (file)
index 0000000..d238779
--- /dev/null
@@ -0,0 +1,44 @@
+using System.IO;
+#if NET45
+using System.Reflection;
+#endif
+
+using AppFW = Tizen.Applications;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       internal static class ResourcePath
+       {
+               public static string GetPath(string res)
+               {
+                       if (Path.IsPathRooted(res))
+                       {
+                               return res;
+                       }
+
+                       AppFW.Application app = AppFW.Application.Current;
+                       if (app != null)
+                       {
+                               string resPath = app.DirectoryInfo.Resource + res;
+                               if (File.Exists(resPath))
+                               {
+                                       return resPath;
+                               }
+                       }
+
+#if NET45
+                       string exedir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+                       // ind resource in "exepath/../res/"
+                       {
+                               string resPath = exedir + "/../res/" + res;
+                               if (File.Exists(resPath))
+                               {
+                                       return resPath;
+                               }
+                       }
+#endif
+
+                       return res;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/ResourcesProvider.cs b/Xamarin.Forms.Platform.Tizen/ResourcesProvider.cs
new file mode 100644 (file)
index 0000000..15e7485
--- /dev/null
@@ -0,0 +1,72 @@
+namespace Xamarin.Forms.Platform.Tizen
+{
+       internal class ResourcesProvider : ISystemResourcesProvider
+       {
+               ResourceDictionary _dictionary;
+
+               public IResourceDictionary GetSystemResources()
+               {
+                       _dictionary = new ResourceDictionary();
+
+                       UpdateStyles();
+
+                       return _dictionary;
+               }
+
+               void UpdateStyles()
+               {
+                       _dictionary[Device.Styles.BodyStyleKey] = GetStyleByKey(Device.Styles.BodyStyleKey);
+                       _dictionary[Device.Styles.TitleStyleKey] = GetStyleByKey(Device.Styles.TitleStyleKey);
+                       _dictionary[Device.Styles.SubtitleStyleKey] = GetStyleByKey(Device.Styles.SubtitleStyleKey);
+                       _dictionary[Device.Styles.CaptionStyleKey] = GetStyleByKey(Device.Styles.CaptionStyleKey);
+                       _dictionary[Device.Styles.ListItemTextStyleKey] = GetStyleByKey(Device.Styles.ListItemTextStyleKey);
+                       _dictionary[Device.Styles.ListItemDetailTextStyleKey] = GetStyleByKey(Device.Styles.ListItemDetailTextStyleKey);
+               }
+
+               //TODO: need Tizen API to get system values
+               Style GetStyleByKey(string key)
+               {
+                       Style style = null;
+                       if (key == Device.Styles.TitleStyleKey)
+                       {
+                               style = GetStyle(50, Color.FromRgb(250, 250, 250));
+                       }
+                       else if (key == Device.Styles.SubtitleStyleKey)
+                       {
+                               style = GetStyle(24, Color.FromRgb(250, 250, 250));
+                       }
+                       else if (key == Device.Styles.CaptionStyleKey)
+                       {
+                               style = GetStyle(24, Color.FromRgb(115, 115, 115));
+                       }
+                       else if (key == Device.Styles.ListItemTextStyleKey)
+                       {
+                               style = GetStyle(40, Color.FromRgb(0, 0, 0));
+                       }
+                       else if (key == Device.Styles.ListItemDetailTextStyleKey)
+                       {
+                               style = GetStyle(24, Color.FromRgb(0, 0, 0));
+                       }
+                       else
+                       {
+                               style = GetStyle();
+                       }
+
+                       return style;
+               }
+
+               Style GetStyle(int? fontSize = null, Color? textColor = null)
+               {
+                       Style style = new Style(typeof(Label));
+                       if (fontSize.HasValue)
+                       {
+                               style.Setters.Add(new Setter { Property = Label.FontSizeProperty, Value = fontSize });
+                       }
+                       if (textColor.HasValue)
+                       {
+                               style.Setters.Add(new Setter { Property = Label.TextColorProperty, Value = textColor });
+                       }
+                       return style;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/TizenIsolatedStorageFile.cs b/Xamarin.Forms.Platform.Tizen/TizenIsolatedStorageFile.cs
new file mode 100644 (file)
index 0000000..0550d9d
--- /dev/null
@@ -0,0 +1,125 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using TApplication = Tizen.Applications.Application;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       internal class TizenIsolatedStorageFile : IIsolatedStorageFile
+       {
+               string _rootPath;
+
+               internal TizenIsolatedStorageFile()
+               {
+                       _rootPath = TApplication.Current.DirectoryInfo.Data;
+               }
+
+               public void CreateDirectory(string path)
+               {
+                       if (path == null)
+                               throw new ArgumentNullException("path");
+                       Directory.CreateDirectory(Path.Combine(_rootPath, path));
+               }
+
+               public Task CreateDirectoryAsync(string path)
+               {
+                       CreateDirectory(path);
+                       return Task.FromResult(true);
+               }
+
+               public void MoveFile(string source, string dest)
+               {
+                       if (source == null)
+                               throw new ArgumentNullException("source");
+                       if (dest == null)
+                               throw new ArgumentNullException("dest");
+
+                       File.Move(Path.Combine(_rootPath, source), Path.Combine(_rootPath, dest));
+               }
+
+               public void DeleteFile(string path)
+               {
+                       if (path == null)
+                               throw new ArgumentNullException("path");
+                       if (path.Trim().Length == 0)
+                               throw new ArgumentException("An empty path is not valid.");
+
+                       File.Delete(Path.Combine(_rootPath, path));
+               }
+
+               public bool DirectoryExists(string path)
+               {
+                       if (path == null)
+                               throw new ArgumentNullException("path");
+                       return Directory.Exists(Path.Combine(_rootPath, path));
+               }
+
+               public Task<bool> GetDirectoryExistsAsync(string path)
+               {
+                       return Task.FromResult(DirectoryExists(path));
+               }
+
+               public bool FileExists(string path)
+               {
+                       if (path == null)
+                               throw new ArgumentNullException("path");
+                       return File.Exists(Path.Combine(_rootPath, path));
+               }
+
+               public Task<bool> GetFileExistsAsync(string path)
+               {
+                       return Task.FromResult(FileExists(path));
+               }
+
+               public DateTimeOffset GetLastWriteTime(string path)
+               {
+                       if (path == null)
+                               throw new ArgumentNullException("path");
+                       if (path.Trim().Length == 0)
+                               throw new ArgumentException("An empty path is not valid.");
+
+                       string fullPath = Path.Combine(_rootPath, path);
+                       if (File.Exists(fullPath))
+                               return File.GetLastWriteTime(fullPath);
+
+                       return Directory.GetLastWriteTime(fullPath);
+               }
+
+               public Task<DateTimeOffset> GetLastWriteTimeAsync(string path)
+               {
+                       return Task.FromResult(GetLastWriteTime(path));
+               }
+
+               public Stream OpenFile(string path, System.IO.FileMode mode)
+               {
+                       return OpenFile(path, mode, (mode == System.IO.FileMode.Append ? System.IO.FileAccess.Write : System.IO.FileAccess.ReadWrite));
+               }
+
+               public Stream OpenFile(string path, System.IO.FileMode mode, System.IO.FileAccess access)
+               {
+                       return OpenFile(path, mode, access, System.IO.FileShare.Read);
+               }
+
+               public Stream OpenFile(string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share)
+               {
+                       if (path == null)
+                               throw new ArgumentNullException("path");
+                       if (path.Trim().Length == 0)
+                               throw new ArgumentException("An empty path is not valid.");
+
+                       string fullPath = Path.Combine(_rootPath, path);
+                       return new FileStream(fullPath, mode, access, share);
+               }
+
+               public Task<Stream> OpenFileAsync(string path, FileMode mode, FileAccess access)
+               {
+                       return Task.FromResult(OpenFile(path, (System.IO.FileMode)mode, (System.IO.FileAccess)access));
+               }
+
+               public Task<Stream> OpenFileAsync(string path, FileMode mode, FileAccess access, FileShare share)
+               {
+                       return Task.FromResult(OpenFile(path, (System.IO.FileMode)mode, (System.IO.FileAccess)access, (System.IO.FileShare)share));
+               }
+
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/TizenPlatformServices.cs b/Xamarin.Forms.Platform.Tizen/TizenPlatformServices.cs
new file mode 100644 (file)
index 0000000..7d44231
--- /dev/null
@@ -0,0 +1,232 @@
+using System;
+using System.IO;
+using System.Reflection;
+using System.Collections.Generic;
+using System.Security.Cryptography;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Net.Http;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       internal class TizenPlatformServices : IPlatformServices
+       {
+               static MD5 checksum = MD5.Create();
+
+               static SynchronizationContext s_context;
+
+               public TizenPlatformServices()
+               {
+                       s_context = SynchronizationContext.Current;
+               }
+
+               public class _Timer : ITimer
+               {
+                       readonly Timer timer;
+
+                       public _Timer(Timer timer)
+                       {
+                               this.timer = timer;
+                       }
+
+                       #region ITimer implementation
+                       public void Change(int dueTime, int period)
+                       {
+                               timer.Change(dueTime, period);
+                       }
+                       public void Change(long dueTime, long period)
+                       {
+                               timer.Change((int)dueTime, (int)period);
+                       }
+                       public void Change(TimeSpan dueTime, TimeSpan period)
+                       {
+                               timer.Change(dueTime, period);
+                       }
+                       public void Change(uint dueTime, uint period)
+                       {
+                               timer.Change((int)dueTime, (int)period);
+                       }
+                       #endregion
+               }
+
+               public class Ticker : Xamarin.Forms.Internals.Ticker
+               {
+                       readonly ITimer _timer;
+
+                       public Ticker()
+                       {
+                               _timer = new _Timer(new Timer((object o) => HandleElapsed(o), this, Timeout.Infinite, Timeout.Infinite));
+                       }
+
+                       protected override void EnableTimer()
+                       {
+                               _timer.Change(16, 16);
+                       }
+
+                       protected override void DisableTimer()
+                       {
+                               _timer.Change(-1, -1);
+                       }
+
+                       void HandleElapsed(object state)
+                       {
+                               s_context.Post((o) => SendSignals(-1), null);
+                       }
+               }
+
+               #region IPlatformServices implementation
+
+               public double GetNamedSize(NamedSize size, Type targetElementType, bool useOldSizes)
+               {
+                       switch (size)
+                       {
+                               case NamedSize.Micro:
+                                       return 16;
+                               case NamedSize.Small:
+                                       return 20;
+                               case NamedSize.Default:
+                               case NamedSize.Medium:
+                                       return 24;
+                               case NamedSize.Large:
+                                       return 30;
+                               default:
+                                       throw new ArgumentOutOfRangeException();
+                       }
+               }
+
+               public void OpenUriAction(Uri uri)
+               {
+                       throw new NotImplementedException();
+               }
+
+               public void BeginInvokeOnMainThread(Action action)
+               {
+                       if (EcoreMainloop.IsMainThread)
+                       {
+                               action();
+                       }
+                       else
+                       {
+                               s_context.Post((o) => action(), null);
+                       }
+               }
+
+               public Xamarin.Forms.Internals.Ticker CreateTicker()
+               {
+                       return new Ticker();
+               }
+
+               public void StartTimer(TimeSpan interval, Func<bool> callback)
+               {
+                       Timer timer = null;
+                       bool invoking = false;
+                       TimerCallback onTimeout = o =>
+                       {
+                               if (!invoking)
+                               {
+                                       invoking = true;
+                                       BeginInvokeOnMainThread(() =>
+                                               {
+                                                       if (!callback())
+                                                       {
+                                                               timer.Dispose();
+                                                       }
+                                                       invoking = false;
+                                               }
+                                       );
+                               }
+                       };
+                       timer = new Timer(onTimeout, null, Timeout.Infinite, Timeout.Infinite);
+                       // set interval separarately to prevent calling onTimeout before `timer' is assigned
+                       timer.Change(interval, interval);
+               }
+
+               public async Task<Stream> GetStreamAsync(Uri uri, CancellationToken cancellationToken)
+               {
+                       using (var client = new HttpClient())
+                       using (HttpResponseMessage response = await client.GetAsync(uri, cancellationToken))
+                               return await response.Content.ReadAsStreamAsync();
+               }
+
+               public Assembly[] GetAssemblies()
+               {
+                       return AppDomain.CurrentDomain.GetAssemblies();
+               }
+
+               public ITimer CreateTimer(Action<object> callback, object state, int dueTime, int period)
+               {
+                       return new _Timer(new Timer((object o) => callback(o), state, dueTime, period));
+               }
+
+               public ITimer CreateTimer(Action<object> callback, object state, TimeSpan dueTime, TimeSpan period)
+               {
+                       return new _Timer(new Timer((object o) => callback(o), state, dueTime, period));
+               }
+
+               public IIsolatedStorageFile GetUserStoreForApplication()
+               {
+                       return new TizenIsolatedStorageFile();
+               }
+
+               static readonly char[] HexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+               public string GetMD5Hash(string input)
+               {
+                       byte[] bin = checksum.ComputeHash(System.Text.Encoding.UTF8.GetBytes(input));
+                       char[] hex = new char[32];
+                       for (var i = 0; i < 16; ++i)
+                       {
+                               hex[2 * i] = HexDigits[bin[i] >> 4];
+                               hex[2 * i + 1] = HexDigits[bin[i] & 0xf];
+                       }
+                       return new string(hex);
+               }
+
+               public bool IsInvokeRequired
+               {
+                       get
+                       {
+                               return !EcoreMainloop.IsMainThread;
+                       }
+               }
+
+               #endregion
+
+#if !NET45
+               // In .NETCore, AppDomain is not supported. The list of the assemblies should be generated manually.
+               internal class AppDomain
+               {
+                       public static AppDomain CurrentDomain { get; private set; }
+
+                       List<Assembly> _assemblies;
+
+                       static AppDomain()
+                       {
+                               CurrentDomain = new AppDomain();
+                       }
+
+                       AppDomain()
+                       {
+                               _assemblies = new List<Assembly>();
+
+                               // Add this renderer assembly to the list
+                               RegisterAssembly(GetType().GetTypeInfo().Assembly);
+                       }
+
+                       internal void RegisterAssembly(Assembly asm)
+                       {
+                               if (!_assemblies.Contains(asm))
+                               {
+                                       _assemblies.Add(asm);
+                               }
+                       }
+
+                       public Assembly[] GetAssemblies()
+                       {
+                               return _assemblies.ToArray();
+                       }
+               }
+#endif
+       }
+}
+
diff --git a/Xamarin.Forms.Platform.Tizen/TizenTitleBarVisibility.cs b/Xamarin.Forms.Platform.Tizen/TizenTitleBarVisibility.cs
new file mode 100644 (file)
index 0000000..4cd09d8
--- /dev/null
@@ -0,0 +1,8 @@
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public enum TizenTitleBarVisibility
+       {
+               Default,
+               Never
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/ViewInitializedEventArgs.cs b/Xamarin.Forms.Platform.Tizen/ViewInitializedEventArgs.cs
new file mode 100644 (file)
index 0000000..fb05c1a
--- /dev/null
@@ -0,0 +1,20 @@
+using System;
+using ElmSharp;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public class ViewInitializedEventArgs : EventArgs
+       {
+               public EvasObject NativeView
+               {
+                       get;
+                       internal set;
+               }
+
+               public VisualElement View
+               {
+                       get;
+                       internal set;
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/VisualElementChangedEventArgs.cs b/Xamarin.Forms.Platform.Tizen/VisualElementChangedEventArgs.cs
new file mode 100644 (file)
index 0000000..35e2105
--- /dev/null
@@ -0,0 +1,16 @@
+namespace Xamarin.Forms.Platform.Tizen
+{
+       /// <summary>
+       /// Represents the arguments passed to every VisualElement change event.
+       /// </summary>
+       public class VisualElementChangedEventArgs : ElementChangedEventArgs<VisualElement>
+       {
+               /// <summary>
+               /// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.VisualElementChangedEventArgs"/> class.
+               /// </summary>
+               /// <param name="oldElement">Old element.</param>
+               /// <param name="newElement">New element.</param>
+               public VisualElementChangedEventArgs(VisualElement oldElement, VisualElement newElement) : base(oldElement, newElement) {
+               }
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/VisualElementRendererFlags.cs b/Xamarin.Forms.Platform.Tizen/VisualElementRendererFlags.cs
new file mode 100644 (file)
index 0000000..731dd6a
--- /dev/null
@@ -0,0 +1,13 @@
+using System;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       [Flags]
+       public enum VisualElementRendererFlags : byte
+       {
+               None = 0,
+               Disposed = 1,
+               NeedsLayout = 2,
+               NeedsTransformation = 4,
+       }
+}
diff --git a/Xamarin.Forms.Platform.Tizen/Xamarin.Forms.Platform.Tizen.csproj b/Xamarin.Forms.Platform.Tizen/Xamarin.Forms.Platform.Tizen.csproj
new file mode 100644 (file)
index 0000000..818e480
--- /dev/null
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{227D2CC5-26A1-4CE7-AE25-1B18AF625B9C}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Xamarin.Forms.Platform.Tizen</RootNamespace>
+    <AssemblyName>Xamarin.Forms.Platform.Tizen</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup>
+    <TargetFrameworkIdentifier>.NETStandard</TargetFrameworkIdentifier>
+    <TargetFrameworkVersion>v1.6</TargetFrameworkVersion>
+    <NuGetTargetMoniker>.NETStandard,Version=v1.6</NuGetTargetMoniker>
+    <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
+    <NoStdLib>true</NoStdLib>
+    <NoWarn>$(NoWarn);1701;1702</NoWarn>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="Cells\CellRenderer.cs" />
+    <Compile Include="Cells\EntryCellRenderer.cs" />
+    <Compile Include="Cells\ImageCellRenderer.cs" />
+    <Compile Include="Cells\SwitchCellRenderer.cs" />
+    <Compile Include="Cells\TextCellRenderer.cs" />
+    <Compile Include="Cells\ViewCellRenderer.cs" />
+    <Compile Include="Deserializer.cs" />
+    <Compile Include="ElementChangedEventArgs.cs" />
+    <Compile Include="EvasObjectWrapper.cs" />
+    <Compile Include="ExportImageSourceHandlerAttribute.cs" />
+    <Compile Include="ExportCellAttribute.cs" />
+    <Compile Include="ExportRendererAttribute.cs" />
+    <Compile Include="Extensions\ColorExtensions.cs" />
+    <Compile Include="Extensions\KeyboardExtensions.cs" />
+    <Compile Include="Extensions\LayoutExtensions.cs" />
+    <Compile Include="Extensions\ScrollToPositionExtensions.cs" />
+    <Compile Include="Extensions\TextAlignmentExtensions.cs" />
+    <Compile Include="Forms.cs" />
+    <Compile Include="GestureHandler.cs" />
+    <Compile Include="FormsApplication.cs" />
+    <Compile Include="Log\ConsoleLogger.cs" />
+    <Compile Include="Log\DlogLogger.cs" />
+    <Compile Include="Log\ILogger.cs" />
+    <Compile Include="Log\Log.cs" />
+    <Compile Include="Log\XamarinLogListener.cs" />
+    <Compile Include="Native\Box.cs" />
+    <Compile Include="Native\Button.cs" />
+    <Compile Include="Native\Canvas.cs" />
+    <Compile Include="Native\ContentPage.cs" />
+    <Compile Include="Native\DateChangedEventArgs.cs" />
+    <Compile Include="Native\DatePicker.cs" />
+    <Compile Include="Native\DateTimePickerDialog.cs" />
+    <Compile Include="Native\Dialog.cs" />
+    <Compile Include="Native\DisplayOrientations.cs" />
+    <Compile Include="Native\Entry.cs" />
+    <Compile Include="Native\FormattedString.cs" />
+    <Compile Include="Native\IContainable.cs" />
+    <Compile Include="Native\Image.cs" />
+    <Compile Include="Native\IMeasurable.cs" />
+    <Compile Include="Native\ITextable.cs" />
+    <Compile Include="Native\Keyboard.cs" />
+    <Compile Include="Native\Label.cs" />
+    <Compile Include="Native\LayoutEventArgs.cs" />
+    <Compile Include="Native\LineBreakMode.cs" />
+    <Compile Include="Native\ListView.cs" />
+    <Compile Include="Native\MasterDetailPage.cs" />
+    <Compile Include="Native\ObservableCollection.cs" />
+    <Compile Include="Native\SearchBar.cs" />
+    <Compile Include="Native\Span.cs" />
+    <Compile Include="Native\TableView.cs" />
+    <Compile Include="Native\TextAlignment.cs" />
+    <Compile Include="Native\TextHelper.cs" />
+    <Compile Include="Native\TimePicker.cs" />
+    <Compile Include="Native\Window.cs" />
+    <Compile Include="Platform.cs" />
+    <Compile Include="PlatformEffect.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Renderers\ActivityIndicatorRenderer.cs" />
+    <Compile Include="Renderers\BoxViewRenderer.cs" />
+    <Compile Include="Renderers\ButtonRenderer.cs" />
+    <Compile Include="Renderers\CarouselPageRenderer.cs" />
+    <Compile Include="Renderers\ContentPageRenderer.cs" />
+    <Compile Include="Renderers\DatePickerRenderer.cs" />
+    <Compile Include="Renderers\EditorRenderer.cs" />
+    <Compile Include="Renderers\EntryRenderer.cs" />
+    <Compile Include="Renderers\EvasObjectWrapperRenderer.cs" />
+    <Compile Include="Renderers\FrameRenderer.cs" />
+    <Compile Include="Renderers\ImageRenderer.cs" />
+    <Compile Include="Renderers\IVisualElementRenderer.cs" />
+    <Compile Include="Renderers\LabelRenderer.cs" />
+    <Compile Include="Renderers\LayoutRenderer.cs" />
+    <Compile Include="Renderers\ListViewRenderer.cs" />
+    <Compile Include="Renderers\MasterDetailPageRenderer.cs" />
+    <Compile Include="Renderers\NavigationPageRenderer.cs" />
+    <Compile Include="Renderers\PickerRenderer.cs" />
+    <Compile Include="Renderers\ProgressBarRenderer.cs" />
+    <Compile Include="Renderers\ScrollViewRenderer.cs" />
+    <Compile Include="Renderers\SearchBarRenderer.cs" />
+    <Compile Include="Renderers\SliderRenderer.cs" />
+    <Compile Include="Renderers\StepperRenderer.cs" />
+    <Compile Include="Renderers\SwitchRenderer.cs" />
+    <Compile Include="Renderers\TabbedPageRenderer.cs" />
+    <Compile Include="Renderers\TableViewRenderer.cs" />
+    <Compile Include="Renderers\TimePickerRenderer.cs" />
+    <Compile Include="Renderers\ViewRenderer.cs" />
+    <Compile Include="Renderers\VisualElementRenderer.cs" />
+    <Compile Include="ResourcePath.cs" />
+    <Compile Include="ResourcesProvider.cs" />
+    <Compile Include="TizenPlatformServices.cs" />
+    <Compile Include="TizenTitleBarVisibility.cs" />
+    <Compile Include="ViewInitializedEventArgs.cs" />
+    <Compile Include="VisualElementChangedEventArgs.cs" />
+    <Compile Include="VisualElementRendererFlags.cs" />
+    <Compile Include="TizenIsolatedStorageFile.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Xamarin.Forms.Platform.Tizen.project.json" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <ItemGroup>
+    <ProjectReference Include="..\Xamarin.Forms.Core\Xamarin.Forms.Core.csproj">
+      <Project>{57B8B73D-C3B5-4C42-869E-7B2F17D354AC}</Project>
+      <Name>Xamarin.Forms.Core</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <PropertyGroup>
+    <!-- https://github.com/dotnet/corefxlab/tree/master/samples/NetCoreSample and
+       https://docs.microsoft.com/en-us/dotnet/articles/core/tutorials/target-dotnetcore-with-msbuild
+    -->
+    <!-- We don't use any of MSBuild's resolution logic for resolving the framework, so just set these two
+       properties to any folder that exists to skip the GetReferenceAssemblyPaths task (not target) and
+       to prevent it from outputting a warning (MSB3644).
+    -->
+    <_TargetFrameworkDirectories>$(MSBuildThisFileDirectory)</_TargetFrameworkDirectories>
+    <_FullFrameworkReferenceAssemblyPaths>$(MSBuildThisFileDirectory)</_FullFrameworkReferenceAssemblyPaths>
+    <AutoUnifyAssemblyReferences>true</AutoUnifyAssemblyReferences>
+  </PropertyGroup>
+</Project>
diff --git a/Xamarin.Forms.Platform.Tizen/Xamarin.Forms.Platform.Tizen.project.json b/Xamarin.Forms.Platform.Tizen/Xamarin.Forms.Platform.Tizen.project.json
new file mode 100644 (file)
index 0000000..02b62b9
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "dependencies": {
+    "ElmSharp": "1.1.0-*",
+    "NETStandard.Library": "1.6.0",
+    "System.Runtime.Serialization.Xml": "4.1.1",
+    "Tizen.Applications": "1.0.2"
+  },
+  "frameworks": {
+    "netstandard1.6": {
+      "imports": "portable-net45+win8+wpa81+wp8"
+    }
+  }
+}
diff --git a/Xamarin.Forms.Tizen.sln b/Xamarin.Forms.Tizen.sln
new file mode 100644 (file)
index 0000000..ecc5d8f
--- /dev/null
@@ -0,0 +1,65 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Core", "Xamarin.Forms.Core\Xamarin.Forms.Core.csproj", "{57B8B73D-C3B5-4C42-869E-7B2F17D354AC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Platform", "Xamarin.Forms.Platform\Xamarin.Forms.Platform.csproj", "{67F9D3A8-F71E-4428-913F-C37AE82CDB24}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Xaml", "Xamarin.Forms.Xaml\Xamarin.Forms.Xaml.csproj", "{9DB2F292-8034-4E06-89AD-98BBDA4306B9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Platform.Tizen", "Xamarin.Forms.Platform.Tizen\Xamarin.Forms.Platform.Tizen.csproj", "{227D2CC5-26A1-4CE7-AE25-1B18AF625B9C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Maps", "Xamarin.Forms.Maps\Xamarin.Forms.Maps.csproj", "{7D13BAC2-C6A4-416A-B07E-C169B199E52B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Maps.Tizen", "Xamarin.Forms.Maps.Tizen\Xamarin.Forms.Maps.Tizen.csproj", "{D29D5750-9A39-4E92-A19E-62567D660B7D}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+               Turkey|Any CPU = Turkey|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Release|Any CPU.Build.0 = Release|Any CPU
+               {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Turkey|Any CPU.ActiveCfg = Turkey|Any CPU
+               {57B8B73D-C3B5-4C42-869E-7B2F17D354AC}.Turkey|Any CPU.Build.0 = Turkey|Any CPU
+               {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|Any CPU.Build.0 = Release|Any CPU
+               {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Turkey|Any CPU.ActiveCfg = Release|Any CPU
+               {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Turkey|Any CPU.Build.0 = Release|Any CPU
+               {9DB2F292-8034-4E06-89AD-98BBDA4306B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {9DB2F292-8034-4E06-89AD-98BBDA4306B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {9DB2F292-8034-4E06-89AD-98BBDA4306B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {9DB2F292-8034-4E06-89AD-98BBDA4306B9}.Release|Any CPU.Build.0 = Release|Any CPU
+               {9DB2F292-8034-4E06-89AD-98BBDA4306B9}.Turkey|Any CPU.ActiveCfg = Turkey|Any CPU
+               {9DB2F292-8034-4E06-89AD-98BBDA4306B9}.Turkey|Any CPU.Build.0 = Turkey|Any CPU
+               {227D2CC5-26A1-4CE7-AE25-1B18AF625B9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {227D2CC5-26A1-4CE7-AE25-1B18AF625B9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {227D2CC5-26A1-4CE7-AE25-1B18AF625B9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {227D2CC5-26A1-4CE7-AE25-1B18AF625B9C}.Release|Any CPU.Build.0 = Release|Any CPU
+               {227D2CC5-26A1-4CE7-AE25-1B18AF625B9C}.Turkey|Any CPU.ActiveCfg = Release|Any CPU
+               {227D2CC5-26A1-4CE7-AE25-1B18AF625B9C}.Turkey|Any CPU.Build.0 = Release|Any CPU
+               {7D13BAC2-C6A4-416A-B07E-C169B199E52B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {7D13BAC2-C6A4-416A-B07E-C169B199E52B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {7D13BAC2-C6A4-416A-B07E-C169B199E52B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {7D13BAC2-C6A4-416A-B07E-C169B199E52B}.Release|Any CPU.Build.0 = Release|Any CPU
+               {7D13BAC2-C6A4-416A-B07E-C169B199E52B}.Turkey|Any CPU.ActiveCfg = Turkey|Any CPU
+               {7D13BAC2-C6A4-416A-B07E-C169B199E52B}.Turkey|Any CPU.Build.0 = Turkey|Any CPU
+               {D29D5750-9A39-4E92-A19E-62567D660B7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {D29D5750-9A39-4E92-A19E-62567D660B7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {D29D5750-9A39-4E92-A19E-62567D660B7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {D29D5750-9A39-4E92-A19E-62567D660B7D}.Release|Any CPU.Build.0 = Release|Any CPU
+               {D29D5750-9A39-4E92-A19E-62567D660B7D}.Turkey|Any CPU.ActiveCfg = Release|Any CPU
+               {D29D5750-9A39-4E92-A19E-62567D660B7D}.Turkey|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/packaging/custom-find-requires b/packaging/custom-find-requires
new file mode 100755 (executable)
index 0000000..ebd22cb
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+if [ -z "$RPM_BUILD_ROOT" ] ; then
+  echo "The $0 script is not intended to be executed directly." > /dev/stderr
+  exit 1
+fi
+
+# this grep will consume whole list of files from stdin
+if grep -qF /Xamarin.Forms.Platform.Tizen.dll ; then
+  # if it's a X.F.P.Tizen package, then find the version of elm-sharp (or elm-sharp-nuget) in use
+  rpm -qa --queryformat 'elm-sharp >= %{VERSION}\n' 'elm-sharp*' | head -n1
+fi
diff --git a/packaging/xamarin-forms-tizen.manifest b/packaging/xamarin-forms-tizen.manifest
new file mode 100755 (executable)
index 0000000..75b0fa5
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+    <request>
+        <domain name="_"/>
+    </request>
+</manifest>
diff --git a/packaging/xamarin-forms-tizen.spec b/packaging/xamarin-forms-tizen.spec
new file mode 100644 (file)
index 0000000..074629b
--- /dev/null
@@ -0,0 +1,94 @@
+%{!?dotnet_assembly_path: %define dotnet_assembly_path /opt/usr/share/dotnet.tizen/framework}
+
+%if 0%{?tizen_build_devel_mode}
+%define BUILDCONF Debug
+%else
+%define BUILDCONF Release
+%endif
+
+%define XF_VERSION 2.3.3.175
+#%define XF_PRETAG pre3
+
+# Increase this XF_TIZEN_VERSION when any public APIs of Xamarin.Forms.Platform.Tizen are changed.
+%define XF_TIZEN_VERSION b01
+
+Name: xamarin-forms-tizen
+Summary: Xamarin.Forms for Tizen platform
+Version: %{XF_VERSION}
+Release: %{XF_TIZEN_VERSION}
+License: MIT
+Group: Graphics & UI Framework/Libraries
+Source0: %{name}-%{version}.tar.gz
+Source1: %{name}.manifest
+
+%define NUPKG_VERSION %{XF_VERSION}%{?XF_PRETAG:-%{XF_PRETAG}}-%{XF_TIZEN_VERSION}
+
+# Instead of disabling Automatic Dependencies completely with `AutoReqProv: no'
+# let's override Mono provided portion
+%define __mono_requires %{_builddir}/%name-%version/packaging/custom-find-requires
+
+ExcludeArch: aarch64 %ix86
+
+BuildRequires: mono-compiler
+BuildRequires: mono-devel
+BuildRequires: referenceassemblies-pcl
+
+BuildRequires: dotnet-build-tools
+
+# C# API Requires
+BuildRequires: csapi-tizen-nuget
+BuildRequires: csapi-application-nuget
+BuildRequires: elm-sharp-nuget
+
+%description
+Allows one to use portable controls subsets that are mapped to native
+controls of Android, iOS, Windows Phone, and Tizen.
+
+%prep
+%setup -q
+cp %{SOURCE1} .
+
+%build
+# Restore NuGet Dependencies
+find . -name *.Tizen.project.json -print0 | xargs -n1 -0 nuget restore
+
+# Build
+xbuild Xamarin.Forms.Tizen.sln \
+    /p:Configuration=%{BUILDCONF} \
+    /p:PackageSources=/nuget
+
+# Create NuGet Packages
+nuget pack .nuspec/Xamarin.Forms.Platform.Tizen.nuspec \
+    -BasePath ./.nuspec -Version %{NUPKG_VERSION} \
+    -Properties "Configuration=%{BUILDCONF}"
+
+%install
+function install_asm()
+{
+  mkdir -p %{buildroot}%{dotnet_assembly_path}
+  install -p -m 644 $1/bin/%{BUILDCONF}/$1.dll %{buildroot}%{dotnet_assembly_path}
+}
+
+install_asm Xamarin.Forms.Core
+install_asm Xamarin.Forms.Xaml
+install_asm Xamarin.Forms.Platform
+install_asm Xamarin.Forms.Platform.Tizen
+
+mkdir -p %{buildroot}/nuget
+install -p -m 644 *.nupkg %{buildroot}/nuget
+
+%files
+%manifest %{name}.manifest
+%license LICENSE
+%attr(644,root,root) %{dotnet_assembly_path}/*.dll
+
+%package nuget
+Summary:   NuGet package for %{name}
+Group:     Development/Libraries
+Requires:  %{name} = %{version}-%{release}
+
+%description nuget
+NuGet package for %{name}
+
+%files nuget
+/nuget/*.nupkg