4 using System.Reflection;
7 using System.Runtime.InteropServices;
8 using System.Collections.Generic;
13 /// Add this attribute to any property belonging to a View (control) you want to be scriptable from JSON
18 /// class MyView : public CustomView
20 /// [ScriptableProperty()]
21 /// public int MyProperty
25 /// return _myProperty;
29 /// _myProperty = value;
34 /// Internally the following occurs for property registration ( this only occurs once per Type, not per Instance):
36 /// - The controls static constructor should call ViewRegistry.Register() (only called once for the lifecycle of the app)
37 /// - Within Register() the code will introspect the Controls properties, looking for the ScriptableProperty() attribute
38 /// - For every property with the ScriptableProperty() attribute, TypeRegistration.RegisterProperty is called.
39 /// - TypeRegistration.RegisterProperty calls in to DALi C++ Code Dali::CSharpTypeRegistry::RegisterProperty()
40 /// - 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).
42 /// The DALi C# example
44 /// class MyView : public CustomView
47 /// [ScriptableProperty()]
48 /// public double Hours
50 /// get { return seconds / 3600; }
51 /// set { seconds = value * 3600; }
55 /// Equivalent code in DALi C++:
57 /// class MyControl : public Control
63 /// HOURS = Control::CONTROL_PROPERTY_END_INDEX + 1
68 /// in MyControl-impl.cpp
70 /// DALI_TYPE_REGISTRATION_BEGIN( Toolkit::MyControl, Toolkit::Control, Create );
71 /// DALI_PROPERTY_REGISTRATION( Toolkit, MyControl, "Hours", INTEGER, DISABLED )
72 /// DALI_TYPE_REGISTRATION_END()
76 public class ScriptableProperty : System.Attribute
78 public enum ScriptableType
80 Default, // Read Writable, non-animatable property, event thread only
81 // Animatable // Animatable property, Currently disabled, UK
83 public readonly ScriptableType type;
85 public ScriptableProperty(ScriptableType type = ScriptableType.Default)
92 /// View Registry singleton.
93 /// Used for registering controls and any scriptable properties they have ( see ScriptableProperty )
95 /// Internal Design from C# to C++
97 /// - Each custom C# view should have it's static constructor called before any JSON file is loaded.
98 /// Static constructors for a class will only run once ( they are run per control type, not per instance).
99 /// Example of running a static constructor:
100 /// System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (typeof(Spin).TypeHandle);
101 /// Inside the static constructor the control should register it's type with the ViewRegistry
106 /// ViewRegistry.Instance.Register(CreateInstance, typeof(Spin) );
109 /// The control should also provide a CreateInstance function, which gets passed to the ViewRegistry
110 /// // Eventually it will be called if DALi Builderfinds a Spin control in a JSON file
111 /// static CustomView CreateInstance()
113 /// return new Spin();
118 /// The DALi C++ equivalent of this is
120 /// TypeRegistration mType( typeid(Toolkit::Spin), typeid(Toolkit::Control), CreateInstance );
125 public sealed class ViewRegistry
128 /// ViewRegistry is a singleton
130 private static ViewRegistry instance = null;
132 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
133 delegate IntPtr CreateControlDelegate(IntPtr cPtrControlName);
135 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
136 delegate IntPtr GetPropertyDelegate(IntPtr controlPtr, IntPtr propertyName);
138 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
139 delegate void SetPropertyDelegate(IntPtr controlPtr, IntPtr propertyName, IntPtr propertyValue);
141 private CreateControlDelegate _createCallback;
142 private SetPropertyDelegate _setPropertyCallback;
143 private GetPropertyDelegate _getPropertyCallback;
144 private PropertyRangeManager _propertyRangeManager;
147 /// Given a C++ control the dictionary allows us to find which C# control (View) it belongs to.
148 /// By keeping the weak reference only, it will allow the object to be garbage collected.
150 private Dictionary<IntPtr, WeakReference> _controlMap;
153 // Maps the name of a custom view to a create instance function
154 /// E.g. given a string "Spin", we can get a function used to create the Spin View.
156 private Dictionary<String, Func<CustomView>> _constructorMap;
159 /// Lookup table to match C# types to DALi types, used for the automatic property registration
161 private static readonly Dictionary<string, Tizen.NUI.PropertyType> _daliPropertyTypeLookup
162 = new Dictionary<string, Tizen.NUI.PropertyType>
164 { "float", PropertyType.Float },
165 { "int", PropertyType.Integer },
166 { "Int32", PropertyType.Integer },
167 { "Boolean", PropertyType.Boolean },
168 { "string", PropertyType.String },
169 { "Vector2", PropertyType.Vector2 },
170 { "Vector3", PropertyType.Vector3 },
171 { "Vector4", PropertyType.Vector4 },
172 { "Size", PropertyType.Vector2 },
173 { "Position",PropertyType.Vector3 },
174 { "Color", PropertyType.Vector4 },
175 // { "Matrix3", PropertyType.MATRIX3 }, commented out until we need to use Matrices from JSON
176 // { "Matrix", PropertyType.MATRIX },
180 public ViewRegistry()
182 _createCallback = new CreateControlDelegate(CreateControl);
183 _getPropertyCallback = new GetPropertyDelegate(GetProperty);
184 _setPropertyCallback = new SetPropertyDelegate(SetProperty);
186 _controlMap = new Dictionary<IntPtr, WeakReference>();
187 _constructorMap = new Dictionary<string, Func<CustomView>>();
188 _propertyRangeManager = new PropertyRangeManager();
192 private Tizen.NUI.PropertyType GetDaliPropertyType(string cSharpTypeName)
194 Tizen.NUI.PropertyType daliType;
195 if (_daliPropertyTypeLookup.TryGetValue(cSharpTypeName, out daliType))
197 //Tizen.Log.Debug("NUI", "mapped "+ cSharpTypeName + " to dAli type " +daliType );
202 // Tizen.Log.Debug("NUI", "Failed to find a mapping between C# property" + cSharpTypeName +" and DALi type");
203 return PropertyType.None;
208 /// Called directly from DALi C++ type registry to create a control (View) using no marshalling.
210 /// <returns>Pointer to the Control (Views) handle </returns>
211 /// <param name="cPtrControlName"> C pointer to the Control (View) name</param>
212 private static IntPtr CreateControl(IntPtr cPtrControlName)
214 string controlName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(cPtrControlName);
215 // Tizen.Log.Debug("NUI", "Create controlled called from C++ create a " + controlName);
217 Func<CustomView> controlConstructor;
219 // find the control constructor
220 if (Instance._constructorMap.TryGetValue(controlName, out controlConstructor))
222 // Create the control
223 CustomView newControl = controlConstructor();
224 return newControl.GetPtrfromActor(); // return pointer to handle
228 throw new global::System.InvalidOperationException("C# View not registererd with ViewRegistry" + controlName);
234 /// Store the mapping between this instance of control (View) and native part.
236 /// <param name="view"> The instance of control (View)</param>
237 public static void RegisterView(View view)
239 // We store a pointer to the RefObject for the control
240 RefObject refObj = view.GetObjectPtr();
241 IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj);
243 //Tizen.Log.Debug("NUI", "________Storing ref object cptr in control map Hex: {0:X}", refCptr);
244 if (!Instance._controlMap.ContainsKey(refCptr))
246 Instance._controlMap.Add(refCptr, new WeakReference(view, false));
253 /// Remove the this instance of control (View) and native part from the mapping table.
255 /// <param name="view"> The instance of control (View)</param>
256 public static void UnregisterView(View view)
258 RefObject refObj = view.GetObjectPtr();
259 IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj);
261 if (Instance._controlMap.ContainsKey(refCptr))
263 Instance._controlMap.Remove(refCptr);
269 private static IntPtr GetProperty(IntPtr controlPtr, IntPtr propertyName)
271 string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(propertyName);
272 return Instance.GetPropertyValue(controlPtr, name);
275 private static void SetProperty(IntPtr controlPtr, IntPtr propertyName, IntPtr propertyValue)
277 string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(propertyName);
278 //Tizen.Log.Debug("NUI", SetControlProperty called for:" + name );
279 Instance.SetPropertyValue(controlPtr, name, propertyValue);
283 public static ViewRegistry Instance
287 if (instance == null)
289 instance = new ViewRegistry();
295 public static View GetViewFromActor(Actor actor)
297 // we store a dictionary of ref-obects (C++ land) to custom views (C# land)
299 RefObject refObj = actor.GetObjectPtr();
300 IntPtr refObjectPtr = (IntPtr)RefObject.getCPtr(refObj);
302 WeakReference viewReference;
303 if (Instance._controlMap.TryGetValue(refObjectPtr, out viewReference))
305 View view = viewReference.Target as View;
316 /// Function which registers a view and all it's scriptable properties with DALi's type registry.
317 /// Means the View can be created / configured from a JSON script.
319 /// The function uses introspection to scan a Views C# properties, then selects the ones with
320 ///[ScriptableProperty] attribute to be registered.
321 /// Example of a Spin view registering itself
324 /// ViewRegistry registers control type with DALi type registery
325 /// also uses introspection to find any properties that need to be registered with type registry
326 /// ViewRegistry.Instance.Register(CreateInstance, typeof(Spin) );
330 public void Register(Func<CustomView> createFunction, System.Type viewType)
332 // add the mapping between the view name and it's create function
333 _constructorMap.Add(viewType.Name, createFunction);
335 // Call into DALi C++ to register the control with the type registry
336 TypeRegistration.RegisterControl(viewType.Name, _createCallback);
338 // Cycle through each property in the class
339 foreach (System.Reflection.PropertyInfo propertyInfo in viewType.GetProperties())
342 if (propertyInfo.CanRead)
346 IEnumerable<Attribute> ie_attrs = propertyInfo.GetCustomAttributes<Attribute>();
347 List<Attribute> li_attrs = new List<Attribute>(ie_attrs);
348 System.Attribute[] attrs = li_attrs.ToArray();
350 System.Attribute[] attrs = System.Attribute.GetCustomAttributes(propertyInfo);
353 foreach (System.Attribute attr in attrs)
355 // If the Scriptable attribute exists, then register it with the type registry.
356 if (attr is ScriptableProperty)
358 //Tizen.Log.Debug("NUI", "Got a DALi JSON scriptable property = " + propertyInfo.Name +", of type " + propertyInfo.PropertyType.Name);
360 // first get the attribute type, ( default, or animatable)
361 ScriptableProperty scriptableProp = attr as ScriptableProperty;
363 // 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)
364 int propertyIndex = _propertyRangeManager.GetPropertyIndex(viewType.Name, viewType, scriptableProp.type);
366 // get the enum for the property type... E.g. registering a string property returns Tizen.NUI.PropertyType.String
367 Tizen.NUI.PropertyType propertyType = GetDaliPropertyType(propertyInfo.PropertyType.Name);
369 // Example RegisterProperty("spin","maxValue", 50001, FLOAT, set, get );
370 // Native call to register the property
371 TypeRegistration.RegisterProperty(viewType.Name, propertyInfo.Name, propertyIndex, propertyType, _setPropertyCallback, _getPropertyCallback);
374 // Tizen.Log.Debug("NUI", "property name = " + propertyInfo.Name);
380 /// Get a property value from a View
383 private IntPtr GetPropertyValue(IntPtr controlPtr, string propertyName)
385 // Get the C# control that maps to the C++ control
386 BaseHandle baseHandle = new BaseHandle(controlPtr, false);
388 RefObject refObj = baseHandle.GetObjectPtr();
390 IntPtr refObjectPtr = (IntPtr)RefObject.getCPtr(refObj);
392 WeakReference viewReference;
393 if (_controlMap.TryGetValue(refObjectPtr, out viewReference))
395 View view = viewReference.Target as View;
397 // call the get property function
398 System.Object val = view.GetType().GetProperty(propertyName).GetAccessors()[0].Invoke(view, null);
400 PropertyValue value = PropertyValue.CreateFromObject(val);
402 return (IntPtr)PropertyValue.getCPtr(value);
411 /// Set a property value on a View
414 private void SetPropertyValue(IntPtr controlPtr, string propertyName, IntPtr propertyValuePtr)
416 // Get the C# control that maps to the C++ control
418 //Tizen.Log.Debug("NUI", "SetPropertyValue refObjectPtr = {0:X}", controlPtr);
420 PropertyValue propValue = new PropertyValue(propertyValuePtr, false);
422 WeakReference viewReference;
423 if (_controlMap.TryGetValue(controlPtr, out viewReference))
425 View view = viewReference.Target as View;
426 System.Reflection.PropertyInfo propertyInfo = view.GetType().GetProperty(propertyName);
428 // We know the property name, we know it's type, we just need to convert from a DALi property value to native C# type
429 System.Type type = propertyInfo.PropertyType;
432 if (type.Equals(typeof(Int32)))
435 ok = propValue.Get(ref value);
438 propertyInfo.SetValue(view, value);
441 else if (type.Equals(typeof(bool)))
444 ok = propValue.Get(ref value);
447 propertyInfo.SetValue(view, value);
450 else if (type.Equals(typeof(float)))
453 ok = propValue.Get(ref value);
456 propertyInfo.SetValue(view, value);
459 else if (type.Equals(typeof(string)))
462 ok = propValue.Get(out value);
465 propertyInfo.SetValue(view, value);
468 else if (type.Equals(typeof(Vector2)))
470 Vector2 value = new Vector2();
471 ok = propValue.Get(value);
474 propertyInfo.SetValue(view, value);
477 else if (type.Equals(typeof(Vector3)))
479 Vector3 value = new Vector3();
480 ok = propValue.Get(value);
483 propertyInfo.SetValue(view, value);
486 else if (type.Equals(typeof(Vector4)))
488 Vector4 value = new Vector4();
489 ok = propValue.Get(value);
493 propertyInfo.SetValue(view, value);
496 else if (type.Equals(typeof(Position)))
498 Position value = new Position();
499 ok = propValue.Get(value);
502 propertyInfo.SetValue(view, value);
505 else if (type.Equals(typeof(Size)))
507 Size value = new Size();
508 ok = propValue.Get(value);
511 propertyInfo.SetValue(view, new Size(value.Width, value.Height, value.Depth));
514 else if (type.Equals(typeof(Color)))
516 // Colors are stored as Vector4's in DALi
517 Color value = new Color();
518 ok = propValue.Get(value);
521 propertyInfo.SetValue(view, (Color)value);
526 throw new global::System.InvalidOperationException("SetPropertyValue Unimplemented type for Property Value");
530 throw new global::System.InvalidOperationException("SetPropertyValue propValue.Get failed");
535 throw new global::System.InvalidOperationException("failed to find the control to write a property to: cptr = " + controlPtr);