2 using System.Runtime.InteropServices;
3 using System.Collections.Generic;
4 using System.Reflection;
\r
10 /// Add this attribute to any property belonging to a View (control) you want to be scriptable from JSON
15 /// class MyView : public CustomView
17 /// [ScriptableProperty()]
18 /// public int MyProperty
22 /// return _myProperty;
26 /// _myProperty = value;
31 /// Internally the following occurs for property registration ( this only occurs once per Type, not per Instance):
33 /// - The controls static constructor should call ViewRegistry.Register() (only called once for the lifecycle of the app)
34 /// - Within Register() the code will introspect the Controls properties, looking for the ScriptableProperty() attribute
35 /// - For every property with the ScriptableProperty() attribute, TypeRegistration.RegisterProperty is called.
36 /// - TypeRegistration.RegisterProperty calls in to DALi C++ Code Dali::CSharpTypeRegistry::RegisterProperty()
37 /// - 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).
39 /// The DALi C# example
41 /// class MyView : public CustomView
44 /// [ScriptableProperty()]
45 /// public double Hours
47 /// get { return seconds / 3600; }
48 /// set { seconds = value * 3600; }
52 /// Equivalent code in DALi C++:
54 /// class MyControl : public Control
60 /// HOURS = Control::CONTROL_PROPERTY_END_INDEX + 1
65 /// in MyControl-impl.cpp
67 /// DALI_TYPE_REGISTRATION_BEGIN( Toolkit::MyControl, Toolkit::Control, Create );
68 /// DALI_PROPERTY_REGISTRATION( Toolkit, MyControl, "Hours", INTEGER, DISABLED )
69 /// DALI_TYPE_REGISTRATION_END()
73 public class ScriptableProperty : System.Attribute
\r
75 public enum ScriptableType
\r
77 Default, // Read Writable, non-animatable property, event thread only
\r
78 // Animatable // Animatable property, Currently disabled, UK
\r
80 public readonly ScriptableType type;
\r
82 public ScriptableProperty(ScriptableType type = ScriptableType.Default)
\r
89 /// View Registry singleton.
90 /// Used for registering controls and any scriptable properties they have ( see ScriptableProperty )
92 /// Internal Design from C# to C++
94 /// - Each custom C# view should have it's static constructor called before any JSON file is loaded.
95 /// Static constructors for a class will only run once ( they are run per control type, not per instance).
96 /// Example of running a static constructor:
97 /// System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (typeof(Spin).TypeHandle);
98 /// Inside the static constructor the control should register it's type with the ViewRegistry
103 /// ViewRegistry.Instance.Register(CreateInstance, typeof(Spin) );
106 /// The control should also provide a CreateInstance function, which gets passed to the ViewRegistry
107 /// // Eventually it will be called if DALi Builderfinds a Spin control in a JSON file
108 /// static CustomView CreateInstance()
110 /// return new Spin();
115 /// The DALi C++ equivalent of this is
117 /// TypeRegistration mType( typeid(Toolkit::Spin), typeid(Toolkit::Control), CreateInstance );
122 public sealed class ViewRegistry
\r
125 /// ViewRegistry is a singleton
127 private static ViewRegistry instance = null;
\r
129 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
\r
130 delegate IntPtr CreateControlDelegate(IntPtr cPtrControlName);
\r
132 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
\r
133 delegate IntPtr GetPropertyDelegate(IntPtr controlPtr, IntPtr propertyName);
\r
135 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
\r
136 delegate void SetPropertyDelegate(IntPtr controlPtr, IntPtr propertyName, IntPtr propertyValue);
\r
138 private CreateControlDelegate _createCallback;
\r
139 private SetPropertyDelegate _setPropertyCallback;
\r
140 private GetPropertyDelegate _getPropertyCallback;
\r
141 private PropertyRangeManager _propertyRangeManager;
\r
144 /// Given a C++ custom control the dictionary allows us to find what CustomView it belongs to
146 private Dictionary<IntPtr, Tizen.NUI.CustomView> _controlMap;
\r
149 // Maps the name of a custom view to a create instance function
\r
150 /// E.g. given a string "Spin", we can get a function used to create the Spin View.
152 private Dictionary<String, Func<CustomView>> _constructorMap;
\r
155 /// Lookup table to match C# types to DALi types, used for the automatic property registration
157 private static readonly Dictionary<string, Tizen.NUI.PropertyType> _daliPropertyTypeLookup
\r
158 = new Dictionary<string, Tizen.NUI.PropertyType>
\r
160 { "float", PropertyType.Float },
161 { "int", PropertyType.Integer },
162 { "Int32", PropertyType.Integer },
163 { "Boolean", PropertyType.Boolean },
164 { "string", PropertyType.String },
165 { "Vector2", PropertyType.Vector2 },
166 { "Vector3", PropertyType.Vector3 },
167 { "Vector4", PropertyType.Vector4 },
168 { "Size", PropertyType.Vector2 },
169 { "Position",PropertyType.Vector3 },
170 { "Color", PropertyType.Vector4 },
\r
171 // { "Matrix3", PropertyType.MATRIX3 }, commented out until we need to use Matrices from JSON
\r
172 // { "Matrix", PropertyType.MATRIX },
\r
176 public ViewRegistry()
\r
178 _createCallback = new CreateControlDelegate(CreateControl);
\r
179 _getPropertyCallback = new GetPropertyDelegate(GetProperty);
\r
180 _setPropertyCallback = new SetPropertyDelegate(SetProperty);
\r
182 _controlMap = new Dictionary<IntPtr, CustomView>();
\r
183 _constructorMap = new Dictionary<string, Func<CustomView>>();
\r
184 _propertyRangeManager = new PropertyRangeManager();
\r
188 private Tizen.NUI.PropertyType GetDaliPropertyType(string cSharpTypeName)
\r
190 Tizen.NUI.PropertyType daliType;
\r
191 if (_daliPropertyTypeLookup.TryGetValue(cSharpTypeName, out daliType))
\r
193 //Console.WriteLine("mapped "+ cSharpTypeName + " to dAli type " +daliType );
\r
198 // Console.WriteLine("Failed to find a mapping between C# property" + cSharpTypeName +" and DALi type");
\r
199 return PropertyType.None;
\r
204 /// Called directly from DALi C++ type registry to create a control (View) uses no marshalling.
206 /// <returns>Pointer to the Control (Views) handle </returns>
207 /// <param name="cPtrControlName"> C pointer to the Control (View) name</param>
208 private static IntPtr CreateControl(IntPtr cPtrControlName)
\r
210 string controlName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(cPtrControlName);
\r
211 // Console.WriteLine ("Create controlled called from C++ create a " + controlName);
\r
213 Func<CustomView> controlConstructor;
\r
215 // find the control constructor
\r
216 if (Instance._constructorMap.TryGetValue(controlName, out controlConstructor))
\r
218 // Create the control
\r
219 CustomView newControl = controlConstructor();
\r
221 // Store the mapping between this instance of the custom control and native part
\r
222 // We store a pointer to the RefObject for the control
\r
223 IntPtr cPtr = newControl.GetPtrfromActor();
\r
224 RefObject refObj = newControl.GetObjectPtr();
\r
225 IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj);
\r
227 //Console.WriteLine ("________Storing ref object cptr in control map Hex: {0:X}", refCptr);
\r
228 Instance._controlMap.Add(refCptr, newControl);
\r
230 return cPtr; // return pointer to handle
\r
234 throw new global::System.InvalidOperationException("C# View not registererd with ViewRegistry" + controlName);
\r
235 return IntPtr.Zero;
\r
239 private static IntPtr GetProperty(IntPtr controlPtr, IntPtr propertyName)
\r
241 string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(propertyName);
\r
242 return Instance.GetPropertyValue(controlPtr, name);
\r
245 private static void SetProperty(IntPtr controlPtr, IntPtr propertyName, IntPtr propertyValue)
\r
247 string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(propertyName);
\r
248 //Console.WriteLine ( SetControlProperty called for:" + name );
\r
249 Instance.SetPropertyValue(controlPtr, name, propertyValue);
\r
253 public static ViewRegistry Instance
\r
257 if (instance == null)
\r
259 instance = new ViewRegistry();
\r
265 public static CustomView GetCustomViewFromActor(Actor actor)
\r
267 // we store a dictionary of ref-obects (C++ land) to custom views (C# land)
\r
268 Tizen.NUI.CustomView view;
\r
270 RefObject refObj = actor.GetObjectPtr();
\r
271 IntPtr refObjectPtr = (IntPtr)RefObject.getCPtr(refObj);
\r
273 if (Instance._controlMap.TryGetValue(refObjectPtr, out view))
\r
276 // call the get property function
\r
288 /// Function which registers a view and all it's scriptable properties with DALi's type registry.
289 /// Means the View can be created / configured from a JSON script.
291 /// The function uses introspection to scan a Views C# properties, then selects the ones with
292 ///[ScriptableProperty] attribute to be registered.
293 /// Example of a Spin view registering itself
296 /// ViewRegistry registers control type with DALi type registery
297 /// also uses introspection to find any properties that need to be registered with type registry
298 /// ViewRegistry.Instance.Register(CreateInstance, typeof(Spin) );
302 public void Register(Func<CustomView> createFunction, System.Type viewType)
\r
304 // add the mapping between the view name and it's create function
\r
305 _constructorMap.Add(viewType.Name, createFunction);
\r
307 // Call into DALi C++ to register the control with the type registry
\r
308 TypeRegistration.RegisterControl(viewType.Name, _createCallback);
\r
310 // Cycle through each property in the class
\r
311 foreach (System.Reflection.PropertyInfo propertyInfo in viewType.GetProperties())
\r
314 if (propertyInfo.CanRead)
\r
317 IEnumerable<Attribute> ie_attrs = propertyInfo.GetCustomAttributes<Attribute>();
\r
318 List<Attribute> li_attrs = new List<Attribute>(ie_attrs);
\r
319 System.Attribute[] attrs = li_attrs.ToArray();
\r
321 foreach (System.Attribute attr in attrs)
\r
323 // If the Scriptable attribute exists, then register it with the type registry.
\r
324 if (attr is ScriptableProperty)
\r
326 //Console.WriteLine ("Got a DALi JSON scriptable property = " + propertyInfo.Name +", of type " + propertyInfo.PropertyType.Name);
\r
328 // first get the attribute type, ( default, or animatable)
\r
329 ScriptableProperty scriptableProp = attr as ScriptableProperty;
\r
331 // 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)
\r
332 int propertyIndex = _propertyRangeManager.GetPropertyIndex(viewType.Name, viewType, scriptableProp.type);
\r
334 // get the enum for the property type... E.g. registering a string property returns Tizen.NUI.PropertyType.String
\r
335 Tizen.NUI.PropertyType propertyType = GetDaliPropertyType(propertyInfo.PropertyType.Name);
\r
337 // Example RegisterProperty("spin","maxValue", 50001, FLOAT, set, get );
\r
338 // Native call to register the property
\r
339 TypeRegistration.RegisterProperty(viewType.Name, propertyInfo.Name, propertyIndex, propertyType, _setPropertyCallback, _getPropertyCallback);
\r
342 // Console.WriteLine ("property name = " + propertyInfo.Name);
\r
348 /// Get a property value from a View
351 private IntPtr GetPropertyValue(IntPtr controlPtr, string propertyName)
\r
353 // Get the C# control that maps to the C++ control
\r
354 Tizen.NUI.CustomView view;
\r
356 BaseHandle baseHandle = new BaseHandle(controlPtr, false);
\r
358 RefObject refObj = baseHandle.GetObjectPtr();
\r
360 IntPtr refObjectPtr = (IntPtr)RefObject.getCPtr(refObj);
\r
362 if (_controlMap.TryGetValue(refObjectPtr, out view))
\r
365 // call the get property function
\r
366 System.Object val = view.GetType().GetProperty(propertyName).GetAccessors()[0].Invoke(view, null);
\r
368 PropertyValue value = PropertyValue.CreateFromObject(val);
\r
370 return (IntPtr)PropertyValue.getCPtr(value);
\r
374 return IntPtr.Zero;
\r
379 /// Set a property value on a View
382 private void SetPropertyValue(IntPtr controlPtr, string propertyName, IntPtr propertyValuePtr)
\r
384 // Get the C# control that maps to the C++ control
\r
385 Tizen.NUI.CustomView view;
\r
387 //Console.WriteLine ("SetPropertyValue refObjectPtr = {0:X}", controlPtr);
\r
389 PropertyValue propValue = new PropertyValue(propertyValuePtr, false);
\r
391 if (_controlMap.TryGetValue(controlPtr, out view))
\r
394 System.Reflection.PropertyInfo propertyInfo = view.GetType().GetProperty(propertyName);
\r
396 // We know the property name, we know it's type, we just need to convert from a DALi property value to native C# type
\r
397 System.Type type = propertyInfo.PropertyType;
\r
400 if (type.Equals(typeof(Int32)))
\r
403 ok = propValue.Get(ref value);
\r
406 propertyInfo.SetValue(view, value);
\r
409 else if (type.Equals(typeof(bool)))
\r
411 bool value = false;
\r
412 ok = propValue.Get(ref value);
\r
415 propertyInfo.SetValue(view, value);
\r
418 else if (type.Equals(typeof(float)))
\r
421 ok = propValue.Get(ref value);
\r
424 propertyInfo.SetValue(view, value);
\r
427 else if (type.Equals(typeof(string)))
\r
430 ok = propValue.Get(out value);
\r
433 propertyInfo.SetValue(view, value);
\r
436 else if (type.Equals(typeof(Vector2)))
\r
438 Vector2 value = new Vector2();
\r
439 ok = propValue.Get(value);
\r
442 propertyInfo.SetValue(view, value);
\r
445 else if (type.Equals(typeof(Vector3)))
\r
447 Vector3 value = new Vector3();
\r
448 ok = propValue.Get(value);
\r
451 propertyInfo.SetValue(view, value);
\r
454 else if (type.Equals(typeof(Vector4)))
\r
456 Vector4 value = new Vector4();
\r
457 ok = propValue.Get(value);
\r
461 propertyInfo.SetValue(view, value);
\r
464 else if (type.Equals(typeof(Position)))
\r
466 Position value = new Position();
\r
467 ok = propValue.Get(value);
\r
470 propertyInfo.SetValue(view, value);
\r
473 else if (type.Equals(typeof(Size)))
\r
475 // DALi sizes are Vector3
\r
476 Size value = new Size();
\r
477 ok = propValue.Get(value);
\r
480 propertyInfo.SetValue(view, new Size(value.Width, value.Height, value.Depth));
\r
483 else if (type.Equals(typeof(Color)))
\r
485 // Colors are stored as Vector4's in DALi
\r
486 Color value = new Color();
\r
487 ok = propValue.Get(value);
\r
490 propertyInfo.SetValue(view, (Color)value);
\r
495 throw new global::System.InvalidOperationException("SetPropertyValue Unimplemented type for Property Value");
\r
499 throw new global::System.InvalidOperationException("SetPropertyValue propValue.Get failed");
\r
504 throw new global::System.InvalidOperationException("failed to find the control to write a property to: cptr = " + controlPtr);
\r