C# Control factory / Registry 38/101938/19
authorNick Holland <nick.holland@partner.samsung.com>
Wed, 7 Dec 2016 15:41:53 +0000 (15:41 +0000)
committerNick Holland <nick.holland@partner.samsung.com>
Thu, 12 Jan 2017 14:33:33 +0000 (14:33 +0000)
Allows controls to register themselves
with DALi type registry along with their
properties.

Once registered this allows DALi to load a
JSON file which can create C# controls and fill
in properties for that control.

See json-loader
and data-picker-using-json

Change-Id: I7f57722a5a7e30b7c85a732dc2077da7cf5809c7

18 files changed:
plugins/dali-swig/.gitignore
plugins/dali-swig/Makefile.am
plugins/dali-swig/SWIG/dali-core.i
plugins/dali-swig/SWIG/dali.i
plugins/dali-swig/SWIG/events/application-event.i
plugins/dali-swig/SWIG/events/builder-event.i
plugins/dali-swig/SWIG/property-value.i [new file with mode: 0644]
plugins/dali-swig/examples/date-picker-using-json.cs [new file with mode: 0644]
plugins/dali-swig/examples/date-picker.cs [new file with mode: 0644]
plugins/dali-swig/examples/json-loader.cs [new file with mode: 0644]
plugins/dali-swig/examples/json/date-picker-template.json [new file with mode: 0644]
plugins/dali-swig/examples/json/date-picker.json [new file with mode: 0644]
plugins/dali-swig/examples/json/spin.json [new file with mode: 0644]
plugins/dali-swig/examples/spin-control.cs [deleted file]
plugins/dali-swig/manual/csharp/PropertyRangeManager.cs [new file with mode: 0644]
plugins/dali-swig/manual/csharp/ViewRegistry.cs [new file with mode: 0644]
plugins/dali-swig/manual/csharp/ViewRegistryHelper.cs [new file with mode: 0644]
plugins/dali-swig/views/spin.cs [new file with mode: 0644]

index 43660d7..2263391 100644 (file)
@@ -4,6 +4,5 @@ autom4te.cache/
 aclocal.m4
 config/
 config.*
-cpp/dali_wrap.cpp
-cpp/dali_wrap.h
+automatic/*
 configure
index 991c0ee..e1520bf 100755 (executable)
@@ -39,14 +39,16 @@ manual/cpp/callbackbase_wrap.o: $(BUILT_SOURCES)
        g++ -c -fpic $(CXXFLAGS) $(DALICORE_CFLAGS) $(DALIADAPTOR_CFLAGS) $(DALITOOLKIT_CFLAGS) manual/cpp/callbackbase_wrap.cpp -o manual/cpp/callbackbase_wrap.o
 
 NDali.dll: $(BUILT_SOURCES)
-       $(MCS) -nologo -target:library -out:NDali.dll automatic/csharp/*.cs manual/csharp/*.cs
+       $(MCS) -nologo -target:library -out:NDali.dll automatic/csharp/*.cs manual/csharp/*.cs views/*.cs
 
 check-local: examples/dali-test.exe \
              examples/hello-world.exe \
              examples/scroll-view.exe \
              examples/custom-control.exe \
-             examples/spin-control.exe \
+             examples/date-picker.exe \
              examples/control-dashboard.exe \
+             examples/date-picker-using-json.exe \
+             examples/json-loader.exe \
              examples/user-alphafunction.exe \
              examples/image-view.exe \
              examples/libNDalic.so examples/NDali.dll
index 5535ee9..73ce8cc 100755 (executable)
@@ -84,6 +84,7 @@
 %ignore *::AnchorPoint::DEFAULT;
 %ignore *::SetPositionInheritanceMode(PositionInheritanceMode);
 %ignore *::GetKeyValue(SizeType) const;
+%ignore *::TypeInfo::GetCreator() const;
 
 %rename(ParentOriginTop) Dali::ParentOrigin::TOP;
 %rename(ParentOriginBottom) Dali::ParentOrigin::BOTTOM;
@@ -209,6 +210,8 @@ typedef std::pair< Dali::Radian, Dali::Radian > AngleThresholdPair;
 %include <dali/public-api/object/handle.h>
 %include <dali/public-api/object/type-info.h>
 %include <dali/public-api/object/type-registry.h>
+%include <dali/devel-api/object/csharp-type-info.h>
+%include <dali/devel-api/object/csharp-type-registry.h>
 
 %include <dali/public-api/common/constants.h>
 %include <dali/public-api/actors/actor-enumerations.h>
index 1f5149b..e4da86b 100755 (executable)
@@ -53,6 +53,8 @@
 #include <dali/public-api/math/matrix3.h>
 #include <dali/public-api/math/viewport.h>
 #include <dali/public-api/object/property-key.h>
+#include <dali/devel-api/object/csharp-type-info.h>
+#include <dali/devel-api/object/csharp-type-registry.h>
 
 #include <dali/public-api/adaptor-framework/timer.h>
 #include <dali/public-api/adaptor-framework/window.h>
   return $null;
 %}
 
+
+
+
+// Type registry type maps
+%typemap(cstype) Dali::TypeInfo::CreateFunction "System.Delegate"
+%typemap(csin, pre ="System.IntPtr ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate($csinput); ")
+  Dali::TypeInfo::CreateFunction "new System.Runtime.InteropServices.HandleRef(null, ip)" // null was this
+
+%typemap(cstype) Dali::CSharpTypeInfo::CreateFunction "System.Delegate"
+%typemap(csin, pre ="System.IntPtr ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate($csinput); ")
+   Dali::CSharpTypeInfo::CreateFunction "new System.Runtime.InteropServices.HandleRef(null, ip)" // null was this
+
+
+
+%typemap(cstype) Dali::CSharpTypeInfo::SetPropertyFunction "System.Delegate"
+%typemap(csin, pre ="System.IntPtr ip = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate($csinput); ")
+   Dali::CSharpTypeInfo::SetPropertyFunction "new System.Runtime.InteropServices.HandleRef(null, ip)" // null was this
+
+
+
+%typemap(cstype) Dali::CSharpTypeInfo::GetPropertyFunction "System.Delegate"
+%typemap(csin, pre ="System.IntPtr ip2 = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate($csinput); ")
+   Dali::CSharpTypeInfo::GetPropertyFunction "new System.Runtime.InteropServices.HandleRef(null, ip2)" // null was this
+
+
+
+
+
+
+
 #endif
 
+
+
+/**
+ * Extend the type registry to allow for registering of C# controls and custom properties
+ */
+%extend Dali::TypeRegistration {
+
+
+   static void RegisterControl( const std::string& controlName, Dali::CSharpTypeInfo::CreateFunction createFunc )
+   {
+     Dali::CSharpTypeRegistry::RegisterType( controlName, typeid( Dali::Toolkit::Control), createFunc );
+   };
+
+
+   static void RegisterProperty( const std::string& controlName,
+                    const std::string& propertyName,
+                    int index,
+                    Property::Type type,
+                    Dali::CSharpTypeInfo::SetPropertyFunction setFunc,
+                    Dali::CSharpTypeInfo::GetPropertyFunction getFunc )
+   {
+     Dali::CSharpTypeRegistry::RegisterProperty( controlName, propertyName, index, type, setFunc, getFunc );
+   };
+
+};
+
+
+
+
 %ignore operator<<;
 %ignore *::GetImplementation();
 %ignore *::GetImplementation(Dali::BaseHandle&);
@@ -219,7 +280,7 @@ using namespace Dali::Toolkit;
 
 %include alphafunction.i
 %include name-changed.i
-
+%include property-value.i
 %include dali-operator.i
 %include dali-core.i
 %include dali-adaptor.i
index bc81dec..3db23f4 100644 (file)
 
     public static Application NewApplication(string stylesheet, Application.WINDOW_MODE windowMode) {
 
+      // register all Views with the type registry, so that can be created / styled via JSON
+      ViewRegistryHelper.Initialize();
+
       Application ret = New(1, stylesheet, windowMode);
       if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
 
index db58063..268b7d7 100644 (file)
       }
     }
 
+    ///
+  public void LoadFromFile( string fileName )
+  {
+    try
+    {
+      string json = System.IO.File.ReadAllText( fileName );
+      if( json.Length > 0 )
+      {
+        LoadFromString( json );
+      }
+      else
+      {
+        throw new global::System.InvalidOperationException("Failed to load file " +fileName);
+
+      }
+    }
+    catch ( System.Exception e)
+    {
+      throw new global::System.InvalidOperationException("Failed to parse " +fileName);
+    }
+  }
+
+
     %}
     %enddef
 
diff --git a/plugins/dali-swig/SWIG/property-value.i b/plugins/dali-swig/SWIG/property-value.i
new file mode 100644 (file)
index 0000000..290b4a1
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#if defined(SWIGCSHARP)
+
+
+ %typemap(cscode) Dali::Property::Value %{
+
+    // Extension to property value class that allows us to create a
+    // PropertyValue from a C# object, e.g. int, float, string
+    static public Property.Value CreateFromObject( System.Object obj)
+    {
+      System.Type type = obj.GetType ();
+
+        Property.Value value;
+
+        if ( type.Equals (typeof(int)) )
+        {
+          System.Console.WriteLine (" got an int property value ");
+          value = new Property.Value ((int) obj );
+        }
+        if ( type.Equals (typeof(System.Int32)) )
+        {
+          System.Console.WriteLine (" got an int property value ");
+          value = new Property.Value ((int) obj );
+        }
+        else if ( type.Equals (typeof(bool)) )
+        {
+          System.Console.WriteLine (" got an bool property value ");
+          value = new Property.Value ((bool) obj );
+        }
+        else if ( type.Equals (typeof(float)) )
+        {
+          System.Console.WriteLine (" got an float property value ");
+          value = new Property.Value ((float) obj );
+        }
+        else if ( type.Equals (typeof(string)) )
+        {
+          System.Console.WriteLine (" got a string property value ");
+          value = new Property.Value ((string) obj );
+        }
+        else if ( type.Equals (typeof(Vector2)) )
+        {
+          System.Console.WriteLine (" got an Vector2 property value ");
+          value = new Property.Value ((Vector2) obj );
+        }
+        else if ( type.Equals (typeof(Vector3)) )
+        {
+          System.Console.WriteLine (" got an Vector3 property value ");
+          value = new Property.Value ((Vector3) obj );
+        }
+        else if ( type.Equals (typeof(Vector4)) )
+        {
+          System.Console.WriteLine (" got an Vector4 property value ");
+
+          value = new Property.Value ((Vector4) obj );
+        }
+        else if ( type.Equals (typeof(Position)) )
+        {
+          System.Console.WriteLine (" got an Position property value ");
+          value = new Property.Value ((Position) obj );
+        }
+        else if ( type.Equals (typeof(Size)) )
+        {
+          System.Console.WriteLine (" got an Size property value ");
+          value = new Property.Value ((Size) obj );
+        }
+        else if ( type.Equals (typeof(Color)) )
+        {
+          System.Console.WriteLine (" got an Color property value ");
+          value = new Property.Value ((Color) obj );
+        }
+        else
+        {
+           throw new global::System.InvalidOperationException("Unimplemented type for Property Value");
+        }
+        return  value;
+    }
+
+
+ %}
+
+
+
+
+#endif
\ No newline at end of file
diff --git a/plugins/dali-swig/examples/date-picker-using-json.cs b/plugins/dali-swig/examples/date-picker-using-json.cs
new file mode 100644 (file)
index 0000000..dbc388c
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using Dali;
+
+namespace MyCSharpExample
+{
+    // A spin control (for continously changing values when users can easily predict a set of values)
+
+    class Example
+    {
+        private Dali.Application _application;
+        private Spin _spinYear;  // spin control for year
+        private Spin _spinMonth; // spin control for month
+        private Spin _spinDay;   // spin control for day
+        private Builder _builder; // DALi Builder
+
+        public Example(Dali.Application application)
+        {
+            _application = application;
+            _application.Initialized += Initialize;
+        }
+
+        public void Initialize(object source, NUIApplicationInitEventArgs e)
+        {
+
+            Stage stage = Stage.GetCurrent();
+            stage.BackgroundColor = Color.White;
+
+            // load date JSON template...
+
+            _builder = new Builder ();
+
+            // Optional constant to see logging information coming out
+            // of DALi JSON parser (builder)
+            Property.Map constants = new  Property.Map();
+            constants.Insert( "CONFIG_SCRIPT_LOG_LEVEL",  new Property.Value( "Verbose") );
+            _builder.AddConstants( constants );
+
+            _builder.LoadFromFile( "./json/date-picker.json" );
+
+            // create the date-picker from the template in the json file
+            BaseHandle handle =  _builder.Create( "date-picker");
+
+            Actor actorTree =  Actor.DownCast( handle );
+
+            stage.Add( actorTree );
+
+            Actor year  = actorTree.FindChildByName("Year");
+            Actor month  =  actorTree.FindChildByName("Month" );
+            Actor day  = actorTree.FindChildByName("Day");
+
+            // need to get the actual C# View associated with the actor,
+            _spinYear = (Spin ) ViewRegistry.GetCustomViewFromActor( year );
+            _spinMonth = (Spin ) ViewRegistry.GetCustomViewFromActor( month );
+            _spinDay = (Spin ) ViewRegistry.GetCustomViewFromActor( day );
+
+            _spinYear.Value = 2099;
+            _spinMonth.Value = 5;
+            _spinDay.Value = 23;
+
+
+            _spinYear.SetKeyboardFocusable(true);
+            _spinMonth.SetKeyboardFocusable(true);
+            _spinDay.SetKeyboardFocusable(true);
+
+
+            FocusManager keyboardFocusManager = FocusManager.Instance;
+            keyboardFocusManager.PreFocusChange += OnKeyboardPreFocusChange;
+            keyboardFocusManager.FocusedActorEnterKeyPressed += OnFocusedActorEnterKeyPressed;
+
+        }
+
+        private Actor OnKeyboardPreFocusChange(object source, FocusManager.PreFocusChangeEventArgs e)
+        {
+            Actor nextFocusActor = e.Proposed;
+
+            // When nothing has been focused initially, focus the text field in the first spin
+            if (!e.Current && !e.Proposed)
+            {
+                nextFocusActor = _spinYear.SpinText;
+            }
+            else if(e.Direction == View.KeyboardFocus.Direction.LEFT)
+            {
+                // Move the focus to the spin in the left of the current focused spin
+                if(e.Current == _spinMonth.SpinText)
+                {
+                    nextFocusActor = _spinYear.SpinText;
+                }
+                else if(e.Current == _spinDay.SpinText)
+                {
+                    nextFocusActor = _spinMonth.SpinText;
+                }
+            }
+            else if(e.Direction == View.KeyboardFocus.Direction.RIGHT)
+            {
+                // Move the focus to the spin in the right of the current focused spin
+                if(e.Current == _spinYear.SpinText)
+                {
+                    nextFocusActor = _spinMonth.SpinText;
+                }
+                else if(e.Current == _spinMonth.SpinText)
+                {
+                    nextFocusActor = _spinDay.SpinText;
+                }
+            }
+
+            return nextFocusActor;
+        }
+
+        private void OnFocusedActorEnterKeyPressed(object source, FocusManager.FocusedActorEnterKeyEventArgs e)
+        {
+            // Make the text field in the current focused spin to take the key input
+            KeyInputFocusManager manager = KeyInputFocusManager.Get();
+
+            if (e.Actor == _spinYear.SpinText)
+            {
+                if (manager.GetCurrentFocusControl() != _spinYear.SpinText)
+                {
+                    manager.SetFocus(_spinYear.SpinText);
+                }
+            }
+            else if (e.Actor == _spinMonth.SpinText)
+            {
+                if (manager.GetCurrentFocusControl() != _spinMonth.SpinText)
+                {
+                    manager.SetFocus(_spinMonth.SpinText);
+                }
+            }
+            else if (e.Actor == _spinDay.SpinText)
+            {
+                if (manager.GetCurrentFocusControl() != _spinDay.SpinText)
+                {
+                    manager.SetFocus(_spinDay.SpinText);
+                }
+            }
+        }
+
+        public void MainLoop()
+        {
+            _application.MainLoop ();
+        }
+
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        [STAThread]
+        static void Main(string[] args)
+        {
+            Example example = new Example(Application.NewApplication());
+            example.MainLoop ();
+        }
+    }
+}
diff --git a/plugins/dali-swig/examples/date-picker.cs b/plugins/dali-swig/examples/date-picker.cs
new file mode 100644 (file)
index 0000000..c9701cf
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using Dali;
+
+namespace MyCSharpExample
+{
+    // A spin control (for continously changing values when users can easily predict a set of values)
+
+    class Example
+    {
+        private Dali.Application _application;
+        private FlexContainer _container;   // Flex container to hold spin controls
+        private Spin _spinYear;  // spin control for year
+        private Spin _spinMonth; // spin control for month
+        private Spin _spinDay;   // spin control for day
+
+        public Example(Dali.Application application)
+        {
+            _application = application;
+            _application.Initialized += Initialize;
+        }
+
+        public void Initialize(object source, NUIApplicationInitEventArgs e)
+        {
+
+            Stage stage = Stage.GetCurrent();
+            stage.BackgroundColor = Color.White;
+
+            // Create a container for the spins
+            _container = new FlexContainer();
+
+            _container.ParentOrigin = NDalic.ParentOriginCenter;
+            _container.AnchorPoint = NDalic.AnchorPointCenter;
+            _container.FlexDirection = (int)FlexContainer.FlexDirectionType.ROW;
+            _container.Size = new Vector3(480.0f, 150.0f, 0.0f);
+
+            stage.Add(_container);
+
+            // Create a Spin control for year
+            _spinYear = new Spin();
+            _spinYear.ParentOrigin = NDalic.ParentOriginCenter;
+            _spinYear.AnchorPoint = NDalic.AnchorPointCenter;
+            _spinYear.Flex = 0.3f;
+            _spinYear.FlexMargin = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
+            _container.Add(_spinYear);
+
+            _spinYear.MinValue = 1900;
+            _spinYear.MaxValue = 2100;
+            _spinYear.Value = 2016;
+            _spinYear.Step = 1;
+            _spinYear.MaxTextLength = 4;
+            _spinYear.TextPointSize = 26;
+            _spinYear.TextColor = Color.White;
+            _spinYear.SetKeyboardFocusable(true);
+            _spinYear.Name = "_spinYear";
+
+            // Create a Spin control for month
+            _spinMonth = new Spin();
+            _spinMonth.ParentOrigin = NDalic.ParentOriginCenter;
+            _spinMonth.AnchorPoint = NDalic.AnchorPointCenter;
+            _spinMonth.Flex = 0.3f;
+            _spinMonth.FlexMargin = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
+            _container.Add(_spinMonth);
+
+            _spinMonth.MinValue = 1;
+            _spinMonth.MaxValue = 12;
+            _spinMonth.Value = 10;
+            _spinMonth.Step = 1;
+            _spinMonth.MaxTextLength = 2;
+            _spinMonth.TextPointSize = 26;
+            _spinMonth.TextColor = Color.White;
+            _spinMonth.SetKeyboardFocusable(true);
+            _spinMonth.Name = "_spinMonth";
+
+            // Create a Spin control for day
+            _spinDay = new Spin();
+            _spinDay.ParentOrigin = NDalic.ParentOriginCenter;
+            _spinDay.AnchorPoint = NDalic.AnchorPointCenter;
+            _spinDay.Flex = 0.3f;
+            _spinDay.FlexMargin = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
+            _container.Add(_spinDay);
+
+            _spinDay.MinValue = 1;
+            _spinDay.MaxValue = 31;
+            _spinDay.Value = 26;
+            _spinDay.Step = 1;
+            _spinDay.MaxTextLength = 2;
+            _spinDay.TextPointSize = 26;
+            _spinDay.TextColor = Color.White;
+            _spinDay.SetKeyboardFocusable(true);
+            _spinDay.Name = "_spinDay";
+
+            FocusManager keyboardFocusManager = FocusManager.Instance;
+            keyboardFocusManager.PreFocusChange += OnKeyboardPreFocusChange;
+            keyboardFocusManager.FocusedActorEnterKeyPressed += OnFocusedActorEnterKeyPressed;
+
+        }
+
+        private Actor OnKeyboardPreFocusChange(object source, FocusManager.PreFocusChangeEventArgs e)
+        {
+            Actor nextFocusActor = e.Proposed;
+
+            // When nothing has been focused initially, focus the text field in the first spin
+            if (!e.Current && !e.Proposed)
+            {
+                nextFocusActor = _spinYear.SpinText;
+            }
+            else if(e.Direction == View.KeyboardFocus.Direction.LEFT)
+            {
+                // Move the focus to the spin in the left of the current focused spin
+                if(e.Current == _spinMonth.SpinText)
+                {
+                    nextFocusActor = _spinYear.SpinText;
+                }
+                else if(e.Current == _spinDay.SpinText)
+                {
+                    nextFocusActor = _spinMonth.SpinText;
+                }
+            }
+            else if(e.Direction == View.KeyboardFocus.Direction.RIGHT)
+            {
+                // Move the focus to the spin in the right of the current focused spin
+                if(e.Current == _spinYear.SpinText)
+                {
+                    nextFocusActor = _spinMonth.SpinText;
+                }
+                else if(e.Current == _spinMonth.SpinText)
+                {
+                    nextFocusActor = _spinDay.SpinText;
+                }
+            }
+
+            return nextFocusActor;
+        }
+
+        private void OnFocusedActorEnterKeyPressed(object source, FocusManager.FocusedActorEnterKeyEventArgs e)
+        {
+            // Make the text field in the current focused spin to take the key input
+            KeyInputFocusManager manager = KeyInputFocusManager.Get();
+
+            if (e.Actor == _spinYear.SpinText)
+            {
+                if (manager.GetCurrentFocusControl() != _spinYear.SpinText)
+                {
+                    manager.SetFocus(_spinYear.SpinText);
+                }
+            }
+            else if (e.Actor == _spinMonth.SpinText)
+            {
+                if (manager.GetCurrentFocusControl() != _spinMonth.SpinText)
+                {
+                    manager.SetFocus(_spinMonth.SpinText);
+                }
+            }
+            else if (e.Actor == _spinDay.SpinText)
+            {
+                if (manager.GetCurrentFocusControl() != _spinDay.SpinText)
+                {
+                    manager.SetFocus(_spinDay.SpinText);
+                }
+            }
+        }
+
+        public void MainLoop()
+        {
+            _application.MainLoop ();
+        }
+
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        [STAThread]
+        static void Main(string[] args)
+        {
+            Example example = new Example(Application.NewApplication());
+            example.MainLoop ();
+        }
+    }
+}
diff --git a/plugins/dali-swig/examples/json-loader.cs b/plugins/dali-swig/examples/json-loader.cs
new file mode 100644 (file)
index 0000000..388b077
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using Dali;
+
+namespace MyExampleApp
+{
+  class Example
+  {
+    private Dali.Application _application;
+    private Builder _builder;
+    private string _jsonFileName;
+
+    public Example(Dali.Application application, string fileName)
+    {
+      _application = application;
+      _jsonFileName = fileName;
+      _application.Initialized += Initialize;
+    }
+
+    public void Initialize(object source, NUIApplicationInitEventArgs e)
+    {
+        if( _jsonFileName.Length == 0)
+        {
+          Console.WriteLine("Please specify JSON file to load");
+          return;
+        }
+
+        _builder = new Builder ();
+
+        Property.Map constants = new  Property.Map();
+
+        //  In dali-demo we have some JSON files that can be loaded, but they need 3 different macros defining.
+        // The JSON folder is typically installed into dali-env/opt/share/com.samsung.dali-demo/res:
+        //
+        //string demoDirectory = ".../dali-env/opt/share/com.samsung.dali-demo/res";
+        //constants.Insert( "DEMO_IMAGE_DIR" ,  new Property.Value( demoDirectory+"/images") );
+        //constants.Insert( "DEMO_MODEL_DIR" ,  new Property.Value( demoDirectory+"/models") );
+        //constants.Insert( "DEMO_SCRIPT_DIR",  new Property.Value( demoDirectory+"/scripts") );
+        constants.Insert( "CONFIG_SCRIPT_LOG_LEVEL",  new Property.Value( "Verbose") );
+
+         _builder.AddConstants( constants );
+
+
+        Stage stage = Stage.GetCurrent();
+        stage.BackgroundColor = Color.White;
+
+        _builder.LoadFromFile( _jsonFileName );
+
+        _builder.AddActors( stage.GetRootLayer() );
+
+    }
+
+
+    public void MainLoop()
+    {
+      _application.MainLoop ();
+    }
+
+    /// <summary>
+    /// The main entry point for the application.
+    /// </summary>
+    [STAThread]
+    static void Main(string[] args)
+    {
+      string fileName= "";
+
+      if( args.Length > 0)
+      {
+          fileName = args[0];
+      }
+
+      Console.WriteLine("arguments = " + args.Length);
+      Example example = new Example(Application.NewApplication(), fileName);
+      example.MainLoop ();
+    }
+  }
+}
diff --git a/plugins/dali-swig/examples/json/date-picker-template.json b/plugins/dali-swig/examples/json/date-picker-template.json
new file mode 100644 (file)
index 0000000..dd01d8f
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+{
+  // Data picker loaded directly on to the stage
+  //
+  "templates": {
+    "date-picker":
+    {
+      "type":"FlexContainer",
+      "name":"exampleDatePicker",
+      "parentOrigin": "CENTER",
+      "anchorPoint": "CENTER",
+      "flexDirection":"ROW",
+      "size":[480.0, 150, 0 ],
+      "actors": [
+      {
+
+        "type": "Spin",
+        "name": "Year",
+        "parentOrigin": "CENTER",
+        "anchorPoint": "CENTER",
+        "Value":2017,
+        "MinValue":1900,
+        "MaxValue":2100,
+        "Step":1,
+        "TextColor":[0.0,0.0,1.0,1.0],
+        "properties": { // properties registered dynamically
+            "flex":0.3,
+            "flexMargin": [5.0,0.0,5.0,0.0]
+        }
+      },
+      {
+
+        "type": "Spin",
+        "name": "Month",
+        "parentOrigin": "CENTER",
+        "anchorPoint": "CENTER",
+        "parentOrigin": "CENTER",
+        "Value":10,
+        "Step":1,
+        "MinValue":1,
+        "MaxValue":12,
+        "TextColor":[1.0,1.0,1.0,1.0],
+        "properties": { // properties registered dynamically
+            "flex":0.3,
+            "flexMargin": [5.0,0.0,5.0,0.0]
+        }
+
+      },
+      {
+
+        "type": "Spin",
+        "name": "Day",
+        "parentOrigin": "CENTER",
+        "anchorPoint": "CENTER",
+        "Value":1,
+        "MinValue":1,
+        "MaxValue":31,
+        "TextColor":[1.0,0.0,0.0,1.0],
+         "properties": { // properties registered dynamically
+            "flex":0.3,
+            "flexMargin": [5.0,0.0,5.0,0.0]
+        }
+      }]
+
+    }
+}
+
+}
+
diff --git a/plugins/dali-swig/examples/json/date-picker.json b/plugins/dali-swig/examples/json/date-picker.json
new file mode 100644 (file)
index 0000000..3126aa3
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+{
+  // Data picker loaded directly on to the stage
+  //
+  "stage": [{
+
+      "type":"FlexContainer",
+      "name":"exampleDatePicker",
+      "parentOrigin": "CENTER",
+      "anchorPoint": "CENTER",
+      "flexDirection":"ROW",
+      "size":[480.0, 150, 0 ],
+      "actors": [
+      {
+
+        "type": "Spin",
+        "name": "Year",
+        "parentOrigin": "CENTER",
+        "anchorPoint": "CENTER",
+        "MinValue":1900,
+        "MaxValue":2100,
+        "Value":2017,
+        "Step":1,
+        "TextColor":[0.0,0.0,1.0,1.0],
+        "properties": { // properties registered dynamically
+            "flex":0.3,
+            "flexMargin": [5.0,0.0,5.0,0.0]
+        }
+      },
+      {
+
+        "type": "Spin",
+        "name": "Month",
+        "parentOrigin": "CENTER",
+        "anchorPoint": "CENTER",
+        "parentOrigin": "CENTER",
+        "Step":1,
+        "MinValue":1,
+        "MaxValue":12,
+        "Value":10,
+        "TextColor":[1.0,1.0,1.0,1.0],
+        "properties": { // properties registered dynamically
+            "flex":0.3,
+            "flexMargin": [5.0,0.0,5.0,0.0]
+        }
+
+      },
+      {
+
+        "type": "Spin",
+        "name": "Day",
+        "parentOrigin": "CENTER",
+        "anchorPoint": "CENTER",
+        "MinValue":1,
+        "MaxValue":31,
+        "Value":1,
+        "TextColor":[1.0,0.0,0.0,1.0],
+         "properties": { // properties registered dynamically
+            "flex":0.3,
+            "flexMargin": [5.0,0.0,5.0,0.0]
+        }
+      }]
+
+}]
+
+}
+
diff --git a/plugins/dali-swig/examples/json/spin.json b/plugins/dali-swig/examples/json/spin.json
new file mode 100644 (file)
index 0000000..df9b10c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+{
+  // a tree of actors
+  "stage": [
+    // You can add an array of  Actors / Views here
+    // Lets add a spin to the stage
+    {
+      "type":"Spin",
+      "parentOrigin":"CENTER",
+      "size":[120,120,0]
+      // now lets use the C# app json-loader.exe to load it
+    }
+
+  ]
+}
diff --git a/plugins/dali-swig/examples/spin-control.cs b/plugins/dali-swig/examples/spin-control.cs
deleted file mode 100755 (executable)
index f385852..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-using System;
-using System.Runtime.InteropServices;
-using Dali;
-
-namespace MyCSharpExample
-{
-    // A spin control (for continously changing values when users can easily predict a set of values)
-    class Spin : CustomView
-    {
-        private VisualBase _arrowVisual;
-        private TextField _textField;
-        private int _arrowVisualPropertyIndex;
-        private string _arrowImage;
-        private int _currentValue;
-        private int _minValue;
-        private int _maxValue;
-        private int _singleStep;
-        private bool _wrappingEnabled;
-        private string _fontFamily;
-        private string _fontStyle;
-        private int _pointSize;
-        private Color _textColor;
-        private Color _textBackgroundColor;
-        private int _maxTextLength;
-
-        public Spin() : base(ViewWrapperImpl.CustomViewBehaviour.REQUIRES_KEYBOARD_NAVIGATION_SUPPORT | ViewWrapperImpl.CustomViewBehaviour.DISABLE_STYLE_CHANGE_SIGNALS)
-        {
-        }
-
-        public override void OnInitialize()
-        {
-            // Initialize the properties
-            _arrowImage = "./images/arrow.png";
-            _textBackgroundColor = new Color(0.6f, 0.6f, 0.6f, 1.0f);
-            _currentValue = 0;
-            _minValue = 0;
-            _maxValue = 0;
-            _singleStep = 1;
-            _maxTextLength = 0;
-
-            // Create image visual for the arrow keys
-            _arrowVisualPropertyIndex = RegisterProperty("ArrowImage", new Dali.Property.Value(_arrowImage), Dali.Property.AccessMode.READ_WRITE);
-            _arrowVisual =  VisualFactory.Get().CreateVisual( _arrowImage, new Uint16Pair(150, 150) );
-            RegisterVisual( _arrowVisualPropertyIndex, _arrowVisual );
-
-            // Create a text field
-            _textField = new TextField();
-            _textField.ParentOrigin = NDalic.ParentOriginCenter;
-            _textField.AnchorPoint = NDalic.AnchorPointCenter;
-            _textField.WidthResizePolicy = "SIZE_RELATIVE_TO_PARENT";
-            _textField.HeightResizePolicy = "SIZE_RELATIVE_TO_PARENT";
-            _textField.SizeModeFactor = new Vector3( 1.0f, 0.45f, 1.0f );
-            _textField.PlaceholderText = "----";
-            _textField.BackgroundColor = _textBackgroundColor;
-            _textField.HorizontalAlignment = "Center";
-            _textField.VerticalAlignment = "Center";
-            _textField.SetKeyboardFocusable(true);
-            _textField.Name = "_textField";
-
-            this.Add(_textField);
-
-            _textField.KeyInputFocusGained += TextFieldKeyInputFocusGained;
-            _textField.KeyInputFocusLost += TextFieldKeyInputFocusLost;
-        }
-
-        public override Vector3 GetNaturalSize()
-        {
-            return new Vector3(150.0f, 150.0f, 0.0f);
-        }
-
-        public void TextFieldKeyInputFocusGained(object source, KeyInputFocusGainedEventArgs e)
-        {
-            // Make sure when the current spin that takes input focus also takes the keyboard focus
-            // For example, when you tap the spin directly
-            FocusManager.Instance.SetCurrentFocusActor(_textField);
-        }
-
-        public void TextFieldKeyInputFocusLost(object source, KeyInputFocusLostEventArgs e)
-        {
-            int previousValue = _currentValue;
-
-            // If the input value is invalid, change it back to the previous valid value
-            if(int.TryParse(_textField.Text, out _currentValue))
-            {
-                if (_currentValue < _minValue || _currentValue > _maxValue)
-                {
-                    _currentValue = previousValue;
-                }
-            }
-            else
-            {
-                _currentValue = previousValue;
-            }
-
-            // Otherwise take the new value
-            this.Value = _currentValue;
-        }
-
-        public override Actor GetNextKeyboardFocusableActor(Actor currentFocusedActor, View.KeyboardFocus.Direction direction, bool loopEnabled)
-        {
-            // Respond to Up/Down keys to change the value while keeping the current spin focused
-            Actor nextFocusedActor = currentFocusedActor;
-            if (direction == View.KeyboardFocus.Direction.UP)
-            {
-                this.Value += this.Step;
-                nextFocusedActor = _textField;
-            }
-            else if (direction == View.KeyboardFocus.Direction.DOWN)
-            {
-                this.Value -= this.Step;
-                nextFocusedActor = _textField;
-            }
-            else
-            {
-                // Return a native empty handle as nothing can be focused in the left or right
-                nextFocusedActor = new Actor();
-                nextFocusedActor.Reset();
-            }
-
-            return nextFocusedActor;
-        }
-
-        // Value property of type int:
-        public int Value
-        {
-            get
-            {
-                return _currentValue;
-            }
-            set
-            {
-                _currentValue = value;
-
-                // Make sure no invalid value is accepted
-                if (_currentValue < _minValue)
-                {
-                    _currentValue = _minValue;
-                }
-
-                if (_currentValue > _maxValue)
-                {
-                    _currentValue = _maxValue;
-                }
-
-                _textField.Text = _currentValue.ToString();
-            }
-        }
-
-        // MinValue property of type int:
-        public int MinValue
-        {
-            get
-            {
-                return _minValue;
-            }
-            set
-            {
-              _minValue = value;
-            }
-        }
-
-        // MaxValue property of type int:
-        public int MaxValue
-        {
-            get
-            {
-                return _maxValue;
-            }
-            set
-            {
-              _maxValue = value;
-            }
-        }
-
-        // Step property of type int:
-        public int Step
-        {
-            get
-            {
-                return _singleStep;
-            }
-            set
-            {
-              _singleStep = value;
-            }
-        }
-
-        // WrappingEnabled property of type bool:
-        public bool WrappingEnabled
-        {
-            get
-            {
-                return _wrappingEnabled;
-            }
-            set
-            {
-              _wrappingEnabled = value;
-            }
-        }
-
-        // TextPointSize property of type int:
-        public int TextPointSize
-        {
-            get
-            {
-                return _pointSize;
-            }
-            set
-            {
-              _pointSize = value;
-              _textField.PointSize = _pointSize;
-            }
-        }
-
-        // TextColor property of type Color:
-        public Color TextColor
-        {
-            get
-            {
-                return _textColor;
-            }
-            set
-            {
-              _textColor = value;
-              _textField.TextColor = _textColor;
-            }
-        }
-
-        // MaxTextLength property of type int:
-        public int MaxTextLength
-        {
-            get
-            {
-                return _maxTextLength;
-            }
-            set
-            {
-                _maxTextLength = value;
-                _textField.MaxLength = _maxTextLength;
-            }
-        }
-
-        public TextField SpinText
-        {
-            get
-            {
-                return _textField;
-            }
-            set
-            {
-                _textField = value;
-            }
-        }
-
-        // Indicator property of type string:
-        public string IndicatorImage
-        {
-            get
-            {
-                return _arrowImage;
-            }
-            set
-            {
-              _arrowImage = value;
-              _arrowVisual =  VisualFactory.Get().CreateVisual( _arrowImage, new Uint16Pair(150, 150) );
-              RegisterVisual( _arrowVisualPropertyIndex, _arrowVisual );
-            }
-        }
-    }
-
-    class Example
-    {
-        private Dali.Application _application;
-        private FlexContainer _container;
-        private Spin _spinYear;
-        private Spin _spinMonth;
-        private Spin _spinDay;
-
-        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
-        delegate void CallbackDelegate();
-
-        public Example(Dali.Application application)
-        {
-            _application = application;
-            _application.Initialized += Initialize;
-        }
-
-        public void Initialize(object source, NUIApplicationInitEventArgs e)
-        {
-            Stage stage = Stage.GetCurrent();
-            stage.BackgroundColor = Color.White;
-
-            // Create a container for the spins
-            _container = new FlexContainer();
-
-            _container.ParentOrigin = NDalic.ParentOriginCenter;
-            _container.AnchorPoint = NDalic.AnchorPointCenter;
-            _container.FlexDirection = (int)FlexContainer.FlexDirectionType.ROW;
-            _container.Size = new Vector3(480.0f, 150.0f, 0.0f);
-
-            stage.Add(_container);
-
-            // Create a Spin control for year
-            _spinYear = new Spin();
-            _spinYear.ParentOrigin = NDalic.ParentOriginCenter;
-            _spinYear.AnchorPoint = NDalic.AnchorPointCenter;
-            _spinYear.Flex = 0.3f;
-            _spinYear.FlexMargin = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
-            _container.Add(_spinYear);
-
-            _spinYear.MinValue = 1900;
-            _spinYear.MaxValue = 2100;
-            _spinYear.Value = 2016;
-            _spinYear.Step = 1;
-            _spinYear.MaxTextLength = 4;
-            _spinYear.TextPointSize = 26;
-            _spinYear.TextColor = Color.White;
-            _spinYear.SetKeyboardFocusable(true);
-            _spinYear.Name = "_spinYear";
-
-            // Create a Spin control for month
-            _spinMonth = new Spin();
-            _spinMonth.ParentOrigin = NDalic.ParentOriginCenter;
-            _spinMonth.AnchorPoint = NDalic.AnchorPointCenter;
-            _spinMonth.Flex = 0.3f;
-            _spinMonth.FlexMargin = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
-            _container.Add(_spinMonth);
-
-            _spinMonth.MinValue = 1;
-            _spinMonth.MaxValue = 12;
-            _spinMonth.Value = 10;
-            _spinMonth.Step = 1;
-            _spinMonth.MaxTextLength = 2;
-            _spinMonth.TextPointSize = 26;
-            _spinMonth.TextColor = Color.White;
-            _spinMonth.SetKeyboardFocusable(true);
-            _spinMonth.Name = "_spinMonth";
-
-            // Create a Spin control for day
-            _spinDay = new Spin();
-            _spinDay.ParentOrigin = NDalic.ParentOriginCenter;
-            _spinDay.AnchorPoint = NDalic.AnchorPointCenter;
-            _spinDay.Flex = 0.3f;
-            _spinDay.FlexMargin = new Vector4(5.0f, 0.0f, 5.0f, 0.0f);
-            _container.Add(_spinDay);
-
-            _spinDay.MinValue = 1;
-            _spinDay.MaxValue = 31;
-            _spinDay.Value = 26;
-            _spinDay.Step = 1;
-            _spinDay.MaxTextLength = 2;
-            _spinDay.TextPointSize = 26;
-            _spinDay.TextColor = Color.White;
-            _spinDay.SetKeyboardFocusable(true);
-            _spinDay.Name = "_spinDay";
-
-            FocusManager keyboardFocusManager = FocusManager.Instance;
-            keyboardFocusManager.PreFocusChange += OnKeyboardPreFocusChange;
-            keyboardFocusManager.FocusedActorEnterKeyPressed += OnFocusedActorEnterKeyPressed;
-
-        }
-
-        private Actor OnKeyboardPreFocusChange(object source, FocusManager.PreFocusChangeEventArgs e)
-        {
-            Actor nextFocusActor = e.Proposed;
-
-            // When nothing has been focused initially, focus the text field in the first spin
-            if (!e.Current && !e.Proposed)
-            {
-                nextFocusActor = _spinYear.SpinText;
-            }
-            else if(e.Direction == View.KeyboardFocus.Direction.LEFT)
-            {
-                // Move the focus to the spin in the left of the current focused spin
-                if(e.Current == _spinMonth.SpinText)
-                {
-                    nextFocusActor = _spinYear.SpinText;
-                }
-                else if(e.Current == _spinDay.SpinText)
-                {
-                    nextFocusActor = _spinMonth.SpinText;
-                }
-            }
-            else if(e.Direction == View.KeyboardFocus.Direction.RIGHT)
-            {
-                // Move the focus to the spin in the right of the current focused spin
-                if(e.Current == _spinYear.SpinText)
-                {
-                    nextFocusActor = _spinMonth.SpinText;
-                }
-                else if(e.Current == _spinMonth.SpinText)
-                {
-                    nextFocusActor = _spinDay.SpinText;
-                }
-            }
-
-            return nextFocusActor;
-        }
-
-        private void OnFocusedActorEnterKeyPressed(object source, FocusManager.FocusedActorEnterKeyEventArgs e)
-        {
-            // Make the text field in the current focused spin to take the key input
-            KeyInputFocusManager manager = KeyInputFocusManager.Get();
-
-            if (e.Actor == _spinYear.SpinText)
-            {
-                if (manager.GetCurrentFocusControl() != _spinYear.SpinText)
-                {
-                    manager.SetFocus(_spinYear.SpinText);
-                }
-            }
-            else if (e.Actor == _spinMonth.SpinText)
-            {
-                if (manager.GetCurrentFocusControl() != _spinMonth.SpinText)
-                {
-                    manager.SetFocus(_spinMonth.SpinText);
-                }
-            }
-            else if (e.Actor == _spinDay.SpinText)
-            {
-                if (manager.GetCurrentFocusControl() != _spinDay.SpinText)
-                {
-                    manager.SetFocus(_spinDay.SpinText);
-                }
-            }
-        }
-
-        public void MainLoop()
-        {
-            _application.MainLoop ();
-        }
-
-        /// <summary>
-        /// The main entry point for the application.
-        /// </summary>
-        [STAThread]
-        static void Main(string[] args)
-        {
-            Example example = new Example(Application.NewApplication());
-            example.MainLoop ();
-        }
-    }
-}
diff --git a/plugins/dali-swig/manual/csharp/PropertyRangeManager.cs b/plugins/dali-swig/manual/csharp/PropertyRangeManager.cs
new file mode 100644 (file)
index 0000000..7e6c4d4
--- /dev/null
@@ -0,0 +1,138 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+
+namespace Dali
+{
+  /// <summary>
+  /// Helper class for calculating what property indexes should be assigned to C# View (view) classes.
+  /// </summary>
+  public class PropertyRangeManager
+  {
+    private Dictionary<String, PropertyRange > _propertyRange;
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="Dali.PropertyRangeManager"/> class.
+    /// </summary>
+    public PropertyRangeManager ()
+    {
+      _propertyRange = new Dictionary<String, PropertyRange > ();
+    }
+
+    /// <summary>
+    /// Only called if a View has scriptable properties
+    /// </summary>
+    private PropertyRange RegisterView( string viewName, System.Type viewType )
+    {
+      PropertyRange range;
+
+      if ( _propertyRange.TryGetValue (viewName, out range) )
+      {
+        // already registered
+        return range;
+      }
+
+      // Find out the event and animatable start indexes for the type
+      range = new PropertyRange();
+
+      GetPropertyStartRange( viewType, ref range);
+
+      // add it to our dictionary
+      _propertyRange.Add( viewName, range );
+
+      return range;
+
+     }
+
+    /// <summary>
+    /// Gets the index of the property.
+    /// Each property has to have unique index for this view type
+    /// </summary>
+    /// <returns>The property index.</returns>
+    /// <param name="viewName">View name</param>
+    /// <param name="viewType">View type</param>
+    /// <param name="type">Type.</param>
+    public int GetPropertyIndex( string viewName, System.Type viewType, ScriptableProperty.ScriptableType type )
+    {
+
+      PropertyRange range;
+
+      if (!  _propertyRange.TryGetValue (viewName, out range) )
+      {
+         // view not found, register it now
+          range = RegisterView( viewName, viewType);
+      }
+
+      int index =  range.GetNextFreePropertyIndex ( type );
+
+      // update the dictionary
+      _propertyRange[viewName]=range;
+
+      return index;
+
+    }
+
+    ///<summary>
+    /// We calculate the start property indices, based on the type and it's class  heirachy, e.g. DateView (70,000)- > Spin (60,000) -> View (50,000)
+    /// </summary>
+    private void GetPropertyStartRange( System.Type viewType, ref PropertyRange range )
+    {
+      const int maxCountPerDerivation = 1000; // For child and animtable properties we use a gap of 1000 between each
+      // views property range in the heirachy
+
+      // custom views start there property index, at view_PROPERTY_END_INDEX
+      // we add 1000, just incase View class (our C# custom view base) starts using scriptable properties
+      int startEventPropertyIndex = (int)View.PropertyRange.CONTROL_PROPERTY_END_INDEX+maxCountPerDerivation;
+
+      // for animatable properties current range starts at ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,
+      // we add 1000, just incase View class starts using animatable properties
+      int startAnimatablePropertyIndex = (int)Dali.PropertyRanges.ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX +maxCountPerDerivation;
+
+      while ( viewType.BaseType.Name != "CustomView" )   // custom view is our C# view base class. we don't go any deeper.
+      {
+        // for every base class increase property start index
+        startEventPropertyIndex += (int)Dali.PropertyRanges.DEFAULT_PROPERTY_MAX_COUNT_PER_DERIVATION; // DALi uses 10,000
+        startAnimatablePropertyIndex += maxCountPerDerivation;
+
+        //Console.WriteLine ("getStartPropertyIndex =  " + viewType.Name +"current index " + startEventPropertyIndex);
+        viewType = viewType.BaseType;
+      }
+
+      range.startEventIndex = startEventPropertyIndex;
+      range.lastUsedEventIndex = startEventPropertyIndex;
+
+      range.startAnimationIndex = startAnimatablePropertyIndex;
+      range.lastUsedAnimationIndex = startAnimatablePropertyIndex;
+
+    }
+
+
+    public struct PropertyRange
+    {
+
+      public int GetNextFreePropertyIndex( ScriptableProperty.ScriptableType type)
+      {
+        if ( type == ScriptableProperty.ScriptableType.Default )
+        {
+           lastUsedEventIndex++;
+           return lastUsedEventIndex;
+        }
+        else
+        {
+          lastUsedAnimationIndex++;
+          return lastUsedAnimationIndex ;
+        }
+      }
+
+
+      public int startEventIndex;    /// start of the property range
+      public int lastUsedEventIndex;    /// last used of the property index
+
+      public int startAnimationIndex;  /// start of the property range
+      public int lastUsedAnimationIndex; /// last used of the property index
+    };
+
+
+
+}
+}
diff --git a/plugins/dali-swig/manual/csharp/ViewRegistry.cs b/plugins/dali-swig/manual/csharp/ViewRegistry.cs
new file mode 100644 (file)
index 0000000..29ece3a
--- /dev/null
@@ -0,0 +1,507 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+
+namespace Dali
+{
+  /// <summary>
+  /// Add this attribute to any property belonging to a View (control) you want to be scriptable from JSON
+  /// </summary>
+  /// <remarks>
+  /// Example:
+  ///
+  /// class MyView : public CustomView
+  /// {
+  ///  [ScriptableProperty()]
+  ///  public int MyProperty
+  ///  {
+  ///   get
+  ///   {
+  ///     return _myProperty;
+  ///   }
+  ///   set
+  ///   {
+  ///    _myProperty = value;
+  ///   }
+  ///  }
+  /// }
+  ///
+  /// Internally the following occurs for property registration ( this only occurs once per Type, not per Instance):
+  ///
+  /// - The controls static constructor should call ViewRegistry.Register()  (only called once for the lifecycle of the app)
+  /// - Within Register() the code will introspect the Controls properties, looking for the ScriptableProperty() attribute
+  /// - For every property with the ScriptableProperty() attribute, TypeRegistration.RegisterProperty is called.
+  /// - TypeRegistration.RegisterProperty calls in to DALi C++ Code Dali::CSharpTypeRegistry::RegisterProperty()
+  /// - DALi C++ now knows the existance of the property and will try calling SetProperty, if it finds the property in a JSON file (loaded using builder).
+  ///
+  ///  The DALi C# example
+  ///
+  ///  class MyView : public CustomView
+  ///  {
+  ///
+  ///    [ScriptableProperty()]
+  ///    public double Hours
+  ///    {
+  ///     get { return seconds / 3600; }
+  ///     set { seconds = value * 3600; }
+  ///    }
+  ///  }
+  ///
+  ///  Equivalent code in DALi C++:
+  ///  in MyControl.h
+  ///  class MyControl : public Control
+  ///  {
+  ///      struct Property
+  ///      {
+  ///         enum
+  ///        {
+  ///              HOURS =  Control::CONTROL_PROPERTY_END_INDEX + 1
+  ///        }
+  ///     }
+  ///
+  ///
+  /// in MyControl-impl.cpp
+  ///
+  /// DALI_TYPE_REGISTRATION_BEGIN( Toolkit::MyControl, Toolkit::Control, Create );
+  /// DALI_PROPERTY_REGISTRATION( Toolkit, MyControl, "Hours",  INTEGER, DISABLED                     )
+  /// DALI_TYPE_REGISTRATION_END()
+  /// </remarks>
+  ///
+  ///
+  public class ScriptableProperty : System.Attribute
+  {
+    public enum ScriptableType
+    {
+      Default,    // Read Writable, non-animatable property, event thread only
+    //  Animatable // Animatable property, Currently disabled, UK
+    }
+    public readonly ScriptableType type;
+
+    public ScriptableProperty(ScriptableType type = ScriptableType.Default )
+    {
+      this.type = type;
+    }
+  }
+
+  /// <summary>
+  /// View Registry singleton.
+  /// Used for registering controls and any scriptable properties they have ( see ScriptableProperty )
+  ///
+  /// Internal Design from C# to C++
+  ///
+  /// - Each custom C# view should have it's static constructor called before any JSON file is loaded.
+  /// Static constructors for a class will only run once ( they are run per control type, not per instance).
+  /// Example of running a static constructor:
+  ///      System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (typeof(Spin).TypeHandle);
+  /// Inside the static constructor the control should register it's type with the ViewRegistry
+  /// e.g.
+  ///
+  ///  static Spin()
+  ///  {
+  ///     ViewRegistry.Instance.RegisterControl("Spin", CreateInstance, typeof(Spin) );
+  ///  }
+  ///
+  ///  The control should also provide a CreateInstance function, which gets passed to the ViewRegistry
+  ///  // Eventually it will be called if DALi Builderfinds a Spin control in a JSON file
+  ///  static CustomView CreateInstance()
+  ///  {
+  ///    return new Spin();
+  ///  }
+  ///
+  ///
+  ///
+  /// The DALi C++ equivalent of this is
+  ///
+  ///  TypeRegistration mType( typeid(Toolkit::Spin), typeid(Toolkit::Control), CreateInstance );
+  ///
+  ///
+  ///
+  /// </summary>
+  public sealed class ViewRegistry
+  {
+    /// <summary>
+    /// ViewRegistry is a singleton
+    /// </summary>
+    private static ViewRegistry instance = null;
+
+    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+    delegate IntPtr CreateControlDelegate( IntPtr cPtrControlName );
+
+    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+    delegate IntPtr GetPropertyDelegate( IntPtr controlPtr, IntPtr propertyName );
+
+    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+    delegate void SetPropertyDelegate( IntPtr controlPtr, IntPtr propertyName, IntPtr propertyValue );
+
+    private CreateControlDelegate _createCallback;
+    private SetPropertyDelegate _setPropertyCallback;
+    private GetPropertyDelegate _getPropertyCallback;
+    private PropertyRangeManager _propertyRangeManager;
+
+    /// <summary>
+    /// Given a C++ custom control the dictionary allows us to find what CustomView it belongs to
+    /// </summary>
+    private Dictionary<IntPtr, Dali.CustomView> _controlMap;
+
+    ///<summary>
+    // Maps the name of a custom view to a create instance function
+    /// E.g. given a string "Spin", we can get a function used to create the Spin View.
+    ///</summary>
+    private Dictionary<String, Func< CustomView > > _constructorMap;
+
+    /// <summary>
+    /// Lookup table to match C# types to DALi types, used for the automatic property registration
+    /// </summary>
+    private static readonly Dictionary<string, Dali.Property.Type> _daliPropertyTypeLookup
+    = new Dictionary< string, Dali.Property.Type  >
+    {
+      { "float",   Property.Type.FLOAT },
+      { "int",     Property.Type.INTEGER },
+      { "Int32",   Property.Type.INTEGER },
+      { "Boolean", Property.Type.BOOLEAN },
+      { "string",  Property.Type.STRING },
+      { "Vector2", Property.Type.VECTOR2 },
+      { "Vector3", Property.Type.VECTOR3 },
+      { "Vector4", Property.Type.VECTOR4 },
+      { "Size",    Property.Type.VECTOR2 },
+      { "Position",Property.Type.VECTOR3 },
+      { "Color",   Property.Type.VECTOR4 },
+    //  { "Matrix3", Property.Type.MATRIX3 }, commented out until we need to use Matrices from JSON
+    //  { "Matrix",  Property.Type.MATRIX },
+    };
+
+
+    public ViewRegistry()
+    {
+      _createCallback = new CreateControlDelegate( CreateControl );
+      _getPropertyCallback = new GetPropertyDelegate (GetProperty);
+      _setPropertyCallback  = new SetPropertyDelegate (SetProperty);
+
+      _controlMap = new Dictionary<IntPtr, CustomView>();
+      _constructorMap = new Dictionary<string, Func<CustomView>>();
+      _propertyRangeManager = new PropertyRangeManager();
+
+    }
+
+    private Dali.Property.Type GetDaliPropertyType( string cSharpTypeName )
+    {
+      Dali.Property.Type daliType;
+      if ( _daliPropertyTypeLookup.TryGetValue (cSharpTypeName, out daliType) )
+      {
+        //Console.WriteLine("mapped "+ cSharpTypeName + " to dAli type " +daliType );
+        return daliType;
+      }
+      else
+      {
+       // Console.WriteLine("Failed to find a mapping between C# property" + cSharpTypeName +" and DALi type");
+        return Property.Type.NONE;
+      }
+    }
+
+    /// <summary>
+    /// Called directly from DALi C++ type registry to create a control (View)  uses no marshalling.
+    /// </summary>
+    /// <returns>Pointer to the Control (Views) handle </returns>
+    /// <param name="cPtrControlName"> C pointer to the Control (View) name</param>
+    private static IntPtr CreateControl( IntPtr cPtrControlName )
+    {
+      string controlName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (cPtrControlName);
+      // Console.WriteLine ("Create controlled called from C++ create a " + controlName);
+
+      Func< CustomView > controlConstructor;
+
+      // find the control constructor
+      if ( Instance._constructorMap.TryGetValue (controlName, out controlConstructor) )
+      {
+        // Create the control
+        CustomView newControl = controlConstructor ();
+
+        // Store the mapping between this instance of the custom control and native part
+        // We store a pointer to the RefObject for the control
+        IntPtr cPtr = newControl.GetPtrfromActor();
+        RefObject refObj = newControl.GetObjectPtr ();
+        IntPtr refCptr = (IntPtr) RefObject.getCPtr(refObj);
+
+        //Console.WriteLine ("________Storing ref object cptr in control map Hex: {0:X}", refCptr);
+        Instance._controlMap.Add (refCptr , newControl );
+
+        return cPtr;  // return pointer to handle
+      }
+      else
+      {
+        throw new global::System.InvalidOperationException("C# View not registererd with ViewRegistry"+ controlName );
+        return IntPtr.Zero;
+      }
+    }
+
+    private static IntPtr GetProperty( IntPtr controlPtr, IntPtr propertyName )
+    {
+      string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (propertyName);
+      return Instance.GetPropertyValue ( controlPtr, name);
+    }
+
+    private static void SetProperty(  IntPtr controlPtr, IntPtr propertyName, IntPtr propertyValue )
+    {
+      string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (propertyName);
+      //Console.WriteLine ( SetControlProperty  called for:" + name );
+      Instance.SetPropertyValue ( controlPtr, name, propertyValue);
+
+    }
+
+    public static ViewRegistry Instance
+    {
+      get
+      {
+        if (instance==null)
+        {
+          instance = new ViewRegistry();
+        }
+        return instance;
+      }
+    }
+
+    public static CustomView GetCustomViewFromActor( Actor actor )
+    {
+      // we store a dictionary of ref-obects (C++ land) to custom views (C# land)
+      Dali.CustomView view;
+
+      RefObject refObj = actor.GetObjectPtr ();
+      IntPtr refObjectPtr = (IntPtr) RefObject.getCPtr(refObj);
+
+      if ( Instance._controlMap.TryGetValue ( refObjectPtr, out view) )
+      {
+
+        // call the get property function
+
+        return view;
+      }
+      else
+      {
+        return null;
+      }
+    }
+
+
+    /// <summary>
+    /// Function which registers a view and all it's scriptable properties with DALi's type registry.
+    /// Means the View can be created / configured from a JSON script.
+    ///
+    /// The function uses introspection to scan a Views C# properties, then selects the ones with
+    ///[ScriptableProperty] attribute to be registered.
+    /// Example of a Spin view registering itself
+    ///   static Spin()
+    /// {
+    ///   ViewRegistry registers control type with DALi type registery
+    ///   also uses introspection to find any properties that need to be registered with type registry
+    ///   ViewRegistry.Instance.Register("Spin", CreateInstance, typeof(Spin) );
+    /// }
+    ///
+    /// </summary>
+    public void Register(string viewName, Func< CustomView > createFunction, System.Type viewType )
+    {
+      // add the mapping between the view name and it's create function
+      _constructorMap.Add (viewName, createFunction);
+
+      // Call into DALi C++ to register the control with the type registry
+      TypeRegistration.RegisterControl( viewName, _createCallback );
+
+      // Cycle through each property in the class
+      foreach (System.Reflection.PropertyInfo propertyInfo in viewType.GetProperties())
+      {
+
+        if ( propertyInfo.CanRead )
+        {
+
+          System.Attribute[] attrs = System.Attribute.GetCustomAttributes(propertyInfo);
+          foreach (System.Attribute attr in attrs)
+          {
+            // If the Scriptable attribute exists, then register it with the type registry.
+            if (attr is ScriptableProperty)
+            {
+              //Console.WriteLine ("Got a DALi JSON scriptable property = " + propertyInfo.Name +", of type " + propertyInfo.PropertyType.Name);
+
+              // first get the attribute type, ( default, or animatable)
+              ScriptableProperty scriptableProp = attr as ScriptableProperty;
+
+              // we get the start property index, based on the type and it's heirachy, e.g. DateView (70,000)-> Spin (60,000) -> View (50,000)
+              int propertyIndex =  _propertyRangeManager.GetPropertyIndex( viewName, viewType, scriptableProp.type );
+
+              // get the enum for the property type... E.g. registering a string property returns Dali.PropertyType.String
+              Dali.Property.Type propertyType = GetDaliPropertyType( propertyInfo.PropertyType.Name );
+
+              // Example   RegisterProperty("spin","maxValue", 50001, FLOAT, set, get );
+              // Native call to register the property
+              TypeRegistration.RegisterProperty (viewName, propertyInfo.Name , propertyIndex, propertyType, _setPropertyCallback, _getPropertyCallback);
+            }
+          }
+          // Console.WriteLine ("property name = " + propertyInfo.Name);
+        }
+      }
+    }
+
+    /// <summary>
+    /// Get a property value from a View
+    ///
+    /// </summary>
+    private IntPtr GetPropertyValue ( IntPtr controlPtr, string propertyName)
+    {
+      // Get the C# control that maps to the C++ control
+      Dali.CustomView view;
+
+      BaseHandle baseHandle = new BaseHandle (controlPtr, false);
+
+      RefObject refObj = baseHandle.GetObjectPtr ();
+
+      IntPtr refObjectPtr = (IntPtr) RefObject.getCPtr(refObj);
+
+      if ( _controlMap.TryGetValue ( refObjectPtr, out view) )
+      {
+
+        // call the get property function
+        System.Object val = view.GetType ().GetProperty (propertyName).GetAccessors () [0].Invoke (view, null);
+
+        Property.Value value = Property.Value.CreateFromObject (val);
+
+        return (IntPtr)Property.Value.getCPtr (value);
+      }
+      else
+      {
+        return IntPtr.Zero;
+      }
+    }
+
+    /// <summary>
+    /// Set a property value on a View
+    ///
+    /// </summary>
+    private void SetPropertyValue ( IntPtr controlPtr, string propertyName, IntPtr propertyValuePtr)
+    {
+      // Get the C# control that maps to the C++ control
+      Dali.CustomView view;
+
+      //Console.WriteLine ("SetPropertyValue   refObjectPtr = {0:X}", controlPtr);
+
+      Property.Value propValue = new Property.Value (propertyValuePtr, false);
+
+      if ( _controlMap.TryGetValue ( controlPtr, out view) )
+      {
+
+        System.Reflection.PropertyInfo propertyInfo = view.GetType().GetProperty(propertyName);
+
+        // We know the property name, we know it's type, we just need to convert from a DALi property value to native C# type
+        System.Type type = propertyInfo.PropertyType;
+        bool ok = false;
+
+        if ( type.Equals (typeof(Int32)) )
+        {
+          int value = 0;
+          ok = propValue.Get( ref value );
+          if ( ok )
+          {
+            propertyInfo.SetValue (view, value);
+          }
+        }
+        else if ( type.Equals (typeof(bool)) )
+        {
+          bool value = false;
+          ok = propValue.Get( ref value );
+          if ( ok )
+          {
+            propertyInfo.SetValue (view, value);
+          }
+        }
+        else if ( type.Equals (typeof(float)) )
+        {
+          float value = 0;
+          ok = propValue.Get( ref value );
+          if ( ok )
+          {
+            propertyInfo.SetValue (view, value);
+          }
+        }
+        else if ( type.Equals (typeof(string)) )
+        {
+          string value = "";
+          ok = propValue.Get( out value );
+          if ( ok )
+          {
+            propertyInfo.SetValue (view, value);
+          }
+        }
+        else if ( type.Equals (typeof(Vector2)) )
+        {
+          Vector2 value = new Vector2 ();
+          ok = propValue.Get( value );
+          if ( ok )
+          {
+            propertyInfo.SetValue (view, value);
+          }
+        }
+        else if ( type.Equals (typeof(Vector3)) )
+        {
+          Vector3 value = new Vector3 ();
+          ok = propValue.Get( value );
+          if ( ok )
+          {
+            propertyInfo.SetValue (view, value);
+          }
+        }
+        else if ( type.Equals (typeof(Vector4)) )
+        {
+          Vector4 value = new Vector4 ();
+          ok = propValue.Get( value );
+
+          if ( ok )
+          {
+           propertyInfo.SetValue (view, value);
+          }
+        }
+        else if ( type.Equals (typeof(Position)) )
+        {
+          Position value = new Position ();
+          ok = propValue.Get( value );
+          if ( ok )
+          {
+            propertyInfo.SetValue (view, value);
+          }
+        }
+        else if ( type.Equals (typeof(Size)) )
+        {
+          // DALi sizes are Vector3
+          Vector3 value = new Vector3();
+          ok = propValue.Get( value );
+          if ( ok )
+          {
+            propertyInfo.SetValue(view, new Size(value.X,value.Y));
+          };
+        }
+        else if ( type.Equals (typeof(Color)) )
+        {
+          // Colors are stored as Vector4's in DALi
+          Vector4 value = new Vector4();
+          ok = propValue.Get( value );
+          if ( ok )
+          {
+            propertyInfo.SetValue (view, (Color)value);
+          };
+        }
+        else
+        {
+          throw new global::System.InvalidOperationException("SetPropertyValue Unimplemented type for Property Value");
+        }
+        if ( !ok )
+        {
+          throw new global::System.InvalidOperationException("SetPropertyValue propValue.Get failed");
+        }
+      }
+      else
+      {
+        throw new global::System.InvalidOperationException("failed to find the control to write a property to: cptr = " + controlPtr);
+      }
+
+    }
+
+  }
+
+
+}
\ No newline at end of file
diff --git a/plugins/dali-swig/manual/csharp/ViewRegistryHelper.cs b/plugins/dali-swig/manual/csharp/ViewRegistryHelper.cs
new file mode 100644 (file)
index 0000000..8e9e19a
--- /dev/null
@@ -0,0 +1,15 @@
+using System;
+
+// include all custom views here which will be
+namespace Dali
+{
+  public class ViewRegistryHelper
+  {
+    static public void Initialize()
+    {
+       // Register all views with the type registry
+       System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (typeof(Dali.Spin).TypeHandle);
+    }
+  }
+}
+
diff --git a/plugins/dali-swig/views/spin.cs b/plugins/dali-swig/views/spin.cs
new file mode 100644 (file)
index 0000000..06a0210
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using Dali;
+
+// A spin control (for continously changing values when users can easily predict a set of values)
+
+namespace Dali
+{
+public class Spin : CustomView
+  {
+    private VisualBase _arrowVisual;
+    private TextField _textField;
+    private int _arrowVisualPropertyIndex;
+    private string _arrowImage;
+    private int _currentValue;
+    private int _minValue;
+    private int _maxValue;
+    private int _singleStep;
+    private bool _wrappingEnabled;
+    private string _fontFamily;
+    private string _fontStyle;
+    private int _pointSize;
+    private Color _textColor;
+    private Color _textBackgroundColor;
+    private int _maxTextLength;
+
+    // Called by DALi Builder if it finds a Spin control in a JSON file
+    static CustomView CreateInstance()
+    {
+      return new Spin();
+    }
+
+    // static constructor registers the control type (only runs once)
+    static Spin()
+    {
+      // ViewRegistry registers control type with DALi type registery
+      // also uses introspection to find any properties that need to be registered with type registry
+      ViewRegistry.Instance.Register("Spin", CreateInstance, typeof(Spin) );
+    }
+    public Spin() : base(ViewWrapperImpl.CustomViewBehaviour.REQUIRES_KEYBOARD_NAVIGATION_SUPPORT | ViewWrapperImpl.CustomViewBehaviour.DISABLE_STYLE_CHANGE_SIGNALS)
+    {
+
+    }
+
+    public override void OnInitialize()
+    {
+      // Initialize the propertiesControl
+      _arrowImage = "./images/arrow.png";
+      _textBackgroundColor = new Color(0.6f, 0.6f, 0.6f, 1.0f);
+      _currentValue = 0;
+      _minValue = 0;
+      _maxValue = 0;
+      _singleStep = 1;
+      _maxTextLength = 0;
+
+      // Create image visual for the arrow keys
+      _arrowVisualPropertyIndex = RegisterProperty("ArrowImage", new Dali.Property.Value(_arrowImage), Dali.Property.AccessMode.READ_WRITE);
+      _arrowVisual =  VisualFactory.Get().CreateVisual( _arrowImage, new Uint16Pair(150, 150) );
+      RegisterVisual( _arrowVisualPropertyIndex, _arrowVisual );
+
+      // Create a text field
+      _textField = new TextField();
+      _textField.ParentOrigin = NDalic.ParentOriginCenter;
+      _textField.AnchorPoint = NDalic.AnchorPointCenter;
+      _textField.WidthResizePolicy = "SIZE_RELATIVE_TO_PARENT";
+      _textField.HeightResizePolicy = "SIZE_RELATIVE_TO_PARENT";
+      _textField.SizeModeFactor = new Vector3( 1.0f, 0.45f, 1.0f );
+      _textField.PlaceholderText = "----";
+      _textField.BackgroundColor = _textBackgroundColor;
+      _textField.HorizontalAlignment = "Center";
+      _textField.VerticalAlignment = "Center";
+      _textField.SetKeyboardFocusable(true);
+      _textField.Name = "_textField";
+
+      this.Add(_textField);
+
+      _textField.KeyInputFocusGained += TextFieldKeyInputFocusGained;
+      _textField.KeyInputFocusLost += TextFieldKeyInputFocusLost;
+    }
+
+    public override Vector3 GetNaturalSize()
+    {
+      return new Vector3(150.0f, 150.0f, 0.0f);
+    }
+
+    public void TextFieldKeyInputFocusGained(object source, KeyInputFocusGainedEventArgs e)
+    {
+      // Make sure when the current spin that takes input focus also takes the keyboard focus
+      // For example, when you tap the spin directly
+      FocusManager.Instance.SetCurrentFocusActor(_textField);
+    }
+
+    public void TextFieldKeyInputFocusLost(object source, KeyInputFocusLostEventArgs e)
+    {
+      int previousValue = _currentValue;
+
+      // If the input value is invalid, change it back to the previous valid value
+      if(int.TryParse(_textField.Text, out _currentValue))
+      {
+        if (_currentValue < _minValue || _currentValue > _maxValue)
+        {
+          _currentValue = previousValue;
+        }
+      }
+      else
+      {
+        _currentValue = previousValue;
+      }
+
+      // Otherwise take the new value
+      this.Value = _currentValue;
+    }
+
+    public override Actor GetNextKeyboardFocusableActor(Actor currentFocusedActor, View.KeyboardFocus.Direction direction, bool loopEnabled)
+    {
+      // Respond to Up/Down keys to change the value while keeping the current spin focused
+      Actor nextFocusedActor = currentFocusedActor;
+      if (direction == View.KeyboardFocus.Direction.UP)
+      {
+        this.Value += this.Step;
+        nextFocusedActor = _textField;
+      }
+      else if (direction == View.KeyboardFocus.Direction.DOWN)
+      {
+        this.Value -= this.Step;
+        nextFocusedActor = _textField;
+      }
+      else
+      {
+        // Return a native empty handle as nothing can be focused in the left or right
+        nextFocusedActor = new Actor();
+        nextFocusedActor.Reset();
+      }
+
+      return nextFocusedActor;
+    }
+
+
+    [ScriptableProperty()]
+    public int Value
+    {
+      get
+      {
+        return _currentValue;
+      }
+      set
+      {
+
+        Console.WriteLine ("Value set to "  + value );
+        _currentValue = value;
+
+        // Make sure no invalid value is accepted
+        if (_currentValue < _minValue)
+        {
+          _currentValue = _minValue;
+        }
+
+        if (_currentValue > _maxValue)
+        {
+          _currentValue = _maxValue;
+        }
+
+        _textField.Text = _currentValue.ToString();
+      }
+    }
+    // MinValue property of type int:
+    [ScriptableProperty()]
+    public int MinValue
+    {
+      get
+      {
+        return _minValue;
+      }
+      set
+      {
+        _minValue = value;
+      }
+    }
+
+    // MaxValue property of type int:
+    [ScriptableProperty()]
+    public int MaxValue
+    {
+      get
+      {
+        return _maxValue;
+      }
+      set
+      {
+        _maxValue = value;
+      }
+    }
+
+    // Step property of type int:
+    [ScriptableProperty()]
+    public int Step
+    {
+      get
+      {
+        return _singleStep;
+      }
+      set
+      {
+        _singleStep = value;
+      }
+    }
+
+    // WrappingEnabled property of type bool:
+    [ScriptableProperty()]
+    public bool WrappingEnabled
+    {
+      get
+      {
+        return _wrappingEnabled;
+      }
+      set
+      {
+        _wrappingEnabled = value;
+      }
+    }
+
+    // TextPointSize property of type int:
+    [ScriptableProperty()]
+    public int TextPointSize
+    {
+      get
+      {
+        return _pointSize;
+      }
+      set
+      {
+        _pointSize = value;
+        _textField.PointSize = _pointSize;
+      }
+    }
+
+    // TextColor property of type Color:
+    [ScriptableProperty()]
+    public Color TextColor
+    {
+      get
+      {
+        return _textColor;
+      }
+      set
+      {
+          Console.WriteLine ("TextColor set to "  + value.R + "," + value.G + ","+ value.B);
+
+        _textColor = value;
+        _textField.TextColor = _textColor;
+      }
+    }
+
+    // MaxTextLength property of type int:
+    [ScriptableProperty()]
+    public int MaxTextLength
+    {
+      get
+      {
+        return _maxTextLength;
+      }
+      set
+      {
+        _maxTextLength = value;
+        _textField.MaxLength = _maxTextLength;
+      }
+    }
+
+    public TextField SpinText
+    {
+      get
+      {
+        return _textField;
+      }
+      set
+      {
+        _textField = value;
+      }
+    }
+
+    // Indicator property of type string:
+    public string IndicatorImage
+    {
+      get
+      {
+        return _arrowImage;
+      }
+      set
+      {
+        _arrowImage = value;
+        _arrowVisual =  VisualFactory.Get().CreateVisual( _arrowImage, new Uint16Pair(150, 150) );
+        RegisterVisual( _arrowVisualPropertyIndex, _arrowVisual );
+      }
+  }
+}
+}
\ No newline at end of file