2 using System.Runtime.InteropServices;
3 using System.Collections.Generic;
6 using System.Reflection;
12 /// Add this attribute to any property belonging to a View (control) you want to be scriptable from JSON
17 /// class MyView : public CustomView
19 /// [ScriptableProperty()]
20 /// public int MyProperty
24 /// return _myProperty;
28 /// _myProperty = value;
33 /// Internally the following occurs for property registration ( this only occurs once per Type, not per Instance):
35 /// - The controls static constructor should call ViewRegistry.Register() (only called once for the lifecycle of the app)
36 /// - Within Register() the code will introspect the Controls properties, looking for the ScriptableProperty() attribute
37 /// - For every property with the ScriptableProperty() attribute, TypeRegistration.RegisterProperty is called.
38 /// - TypeRegistration.RegisterProperty calls in to DALi C++ Code Dali::CSharpTypeRegistry::RegisterProperty()
39 /// - 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).
41 /// The DALi C# example
43 /// class MyView : public CustomView
46 /// [ScriptableProperty()]
47 /// public double Hours
49 /// get { return seconds / 3600; }
50 /// set { seconds = value * 3600; }
54 /// Equivalent code in DALi C++:
56 /// class MyControl : public Control
62 /// HOURS = Control::CONTROL_PROPERTY_END_INDEX + 1
67 /// in MyControl-impl.cpp
69 /// DALI_TYPE_REGISTRATION_BEGIN( Toolkit::MyControl, Toolkit::Control, Create );
70 /// DALI_PROPERTY_REGISTRATION( Toolkit, MyControl, "Hours", INTEGER, DISABLED )
71 /// DALI_TYPE_REGISTRATION_END()
75 public class ScriptableProperty : System.Attribute
\r
77 public enum ScriptableType
\r
79 Default, // Read Writable, non-animatable property, event thread only
\r
80 // Animatable // Animatable property, Currently disabled, UK
\r
82 public readonly ScriptableType type;
\r
84 public ScriptableProperty(ScriptableType type = ScriptableType.Default)
\r
91 /// View Registry singleton.
92 /// Used for registering controls and any scriptable properties they have ( see ScriptableProperty )
94 /// Internal Design from C# to C++
96 /// - Each custom C# view should have it's static constructor called before any JSON file is loaded.
97 /// Static constructors for a class will only run once ( they are run per control type, not per instance).
98 /// Example of running a static constructor:
99 /// System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (typeof(Spin).TypeHandle);
100 /// Inside the static constructor the control should register it's type with the ViewRegistry
105 /// ViewRegistry.Instance.RegisterControl("Spin", CreateInstance, typeof(Spin) );
108 /// The control should also provide a CreateInstance function, which gets passed to the ViewRegistry
109 /// // Eventually it will be called if DALi Builderfinds a Spin control in a JSON file
110 /// static CustomView CreateInstance()
112 /// return new Spin();
117 /// The DALi C++ equivalent of this is
119 /// TypeRegistration mType( typeid(Toolkit::Spin), typeid(Toolkit::Control), CreateInstance );
124 public sealed class ViewRegistry
\r
127 /// ViewRegistry is a singleton
129 private static ViewRegistry instance = null;
\r
131 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
\r
132 delegate IntPtr CreateControlDelegate(IntPtr cPtrControlName);
\r
134 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
\r
135 delegate IntPtr GetPropertyDelegate(IntPtr controlPtr, IntPtr propertyName);
\r
137 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
\r
138 delegate void SetPropertyDelegate(IntPtr controlPtr, IntPtr propertyName, IntPtr propertyValue);
\r
140 private CreateControlDelegate _createCallback;
\r
141 private SetPropertyDelegate _setPropertyCallback;
\r
142 private GetPropertyDelegate _getPropertyCallback;
\r
143 private PropertyRangeManager _propertyRangeManager;
\r
146 /// Given a C++ custom control the dictionary allows us to find what CustomView it belongs to
148 private Dictionary<IntPtr, Tizen.NUI.CustomView> _controlMap;
\r
151 // Maps the name of a custom view to a create instance function
\r
152 /// E.g. given a string "Spin", we can get a function used to create the Spin View.
154 private Dictionary<String, Func<CustomView>> _constructorMap;
\r
157 /// Lookup table to match C# types to DALi types, used for the automatic property registration
159 private static readonly Dictionary<string, Tizen.NUI.PropertyType> _daliPropertyTypeLookup
\r
160 = new Dictionary<string, Tizen.NUI.PropertyType>
\r
162 { "float", PropertyType.Float },
163 { "int", PropertyType.Integer },
164 { "Int32", PropertyType.Integer },
165 { "Boolean", PropertyType.Boolean },
166 { "string", PropertyType.String },
167 { "Vector2", PropertyType.Vector2 },
168 { "Vector3", PropertyType.Vector3 },
169 { "Vector4", PropertyType.Vector4 },
170 { "Size", PropertyType.Vector2 },
171 { "Position",PropertyType.Vector3 },
172 { "Color", PropertyType.Vector4 },
\r
173 // { "Matrix3", PropertyType.MATRIX3 }, commented out until we need to use Matrices from JSON
\r
174 // { "Matrix", PropertyType.MATRIX },
\r
178 public ViewRegistry()
\r
180 _createCallback = new CreateControlDelegate(CreateControl);
\r
181 _getPropertyCallback = new GetPropertyDelegate(GetProperty);
\r
182 _setPropertyCallback = new SetPropertyDelegate(SetProperty);
\r
184 _controlMap = new Dictionary<IntPtr, CustomView>();
\r
185 _constructorMap = new Dictionary<string, Func<CustomView>>();
\r
186 _propertyRangeManager = new PropertyRangeManager();
\r
190 private Tizen.NUI.PropertyType GetDaliPropertyType(string cSharpTypeName)
\r
192 Tizen.NUI.PropertyType daliType;
\r
193 if (_daliPropertyTypeLookup.TryGetValue(cSharpTypeName, out daliType))
\r
195 //Console.WriteLine("mapped "+ cSharpTypeName + " to dAli type " +daliType );
\r
200 // Console.WriteLine("Failed to find a mapping between C# property" + cSharpTypeName +" and DALi type");
\r
201 return PropertyType.None;
\r
206 /// Called directly from DALi C++ type registry to create a control (View) uses no marshalling.
208 /// <returns>Pointer to the Control (Views) handle </returns>
209 /// <param name="cPtrControlName"> C pointer to the Control (View) name</param>
210 private static IntPtr CreateControl(IntPtr cPtrControlName)
\r
212 string controlName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(cPtrControlName);
\r
213 // Console.WriteLine ("Create controlled called from C++ create a " + controlName);
\r
215 Func<CustomView> controlConstructor;
\r
217 // find the control constructor
\r
218 if (Instance._constructorMap.TryGetValue(controlName, out controlConstructor))
\r
220 // Create the control
\r
221 CustomView newControl = controlConstructor();
\r
223 // Store the mapping between this instance of the custom control and native part
\r
224 // We store a pointer to the RefObject for the control
\r
225 IntPtr cPtr = newControl.GetPtrfromActor();
\r
226 RefObject refObj = newControl.GetObjectPtr();
\r
227 IntPtr refCptr = (IntPtr)RefObject.getCPtr(refObj);
\r
229 //Console.WriteLine ("________Storing ref object cptr in control map Hex: {0:X}", refCptr);
\r
230 Instance._controlMap.Add(refCptr, newControl);
\r
232 return cPtr; // return pointer to handle
\r
236 throw new global::System.InvalidOperationException("C# View not registererd with ViewRegistry" + controlName);
\r
237 return IntPtr.Zero;
\r
241 private static IntPtr GetProperty(IntPtr controlPtr, IntPtr propertyName)
\r
243 string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(propertyName);
\r
244 return Instance.GetPropertyValue(controlPtr, name);
\r
247 private static void SetProperty(IntPtr controlPtr, IntPtr propertyName, IntPtr propertyValue)
\r
249 string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(propertyName);
\r
250 //Console.WriteLine ( SetControlProperty called for:" + name );
\r
251 Instance.SetPropertyValue(controlPtr, name, propertyValue);
\r
255 public static ViewRegistry Instance
\r
259 if (instance == null)
\r
261 instance = new ViewRegistry();
\r
267 public static CustomView GetCustomViewFromActor(Actor actor)
\r
269 // we store a dictionary of ref-obects (C++ land) to custom views (C# land)
\r
270 Tizen.NUI.CustomView view;
\r
272 RefObject refObj = actor.GetObjectPtr();
\r
273 IntPtr refObjectPtr = (IntPtr)RefObject.getCPtr(refObj);
\r
275 if (Instance._controlMap.TryGetValue(refObjectPtr, out view))
\r
278 // call the get property function
\r
290 /// Function which registers a view and all it's scriptable properties with DALi's type registry.
291 /// Means the View can be created / configured from a JSON script.
293 /// The function uses introspection to scan a Views C# properties, then selects the ones with
294 ///[ScriptableProperty] attribute to be registered.
295 /// Example of a Spin view registering itself
298 /// ViewRegistry registers control type with DALi type registery
299 /// also uses introspection to find any properties that need to be registered with type registry
300 /// ViewRegistry.Instance.Register("Spin", CreateInstance, typeof(Spin) );
304 public void Register(string viewName, Func<CustomView> createFunction, System.Type viewType)
\r
306 // add the mapping between the view name and it's create function
\r
307 _constructorMap.Add(viewName, createFunction);
\r
309 // Call into DALi C++ to register the control with the type registry
\r
310 TypeRegistration.RegisterControl(viewName, _createCallback);
\r
312 // Cycle through each property in the class
\r
313 foreach (System.Reflection.PropertyInfo propertyInfo in viewType.GetProperties())
\r
316 if (propertyInfo.CanRead)
\r
320 IEnumerable<Attribute> ie_attrs = propertyInfo.GetCustomAttributes<Attribute>();
\r
321 List<Attribute> li_attrs = new List<Attribute>(ie_attrs);
\r
322 System.Attribute[] attrs = li_attrs.ToArray();
\r
324 System.Attribute[] attrs = System.Attribute.GetCustomAttributes(propertyInfo);
\r
327 foreach (System.Attribute attr in attrs)
\r
329 // If the Scriptable attribute exists, then register it with the type registry.
\r
330 if (attr is ScriptableProperty)
\r
332 //Console.WriteLine ("Got a DALi JSON scriptable property = " + propertyInfo.Name +", of type " + propertyInfo.PropertyType.Name);
\r
334 // first get the attribute type, ( default, or animatable)
\r
335 ScriptableProperty scriptableProp = attr as ScriptableProperty;
\r
337 // 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
338 int propertyIndex = _propertyRangeManager.GetPropertyIndex(viewName, viewType, scriptableProp.type);
\r
340 // get the enum for the property type... E.g. registering a string property returns Tizen.NUI.PropertyType.String
\r
341 Tizen.NUI.PropertyType propertyType = GetDaliPropertyType(propertyInfo.PropertyType.Name);
\r
343 // Example RegisterProperty("spin","maxValue", 50001, FLOAT, set, get );
\r
344 // Native call to register the property
\r
345 TypeRegistration.RegisterProperty(viewName, propertyInfo.Name, propertyIndex, propertyType, _setPropertyCallback, _getPropertyCallback);
\r
351 // Console.WriteLine ("property name = " + propertyInfo.Name);
\r
357 /// Get a property value from a View
360 private IntPtr GetPropertyValue(IntPtr controlPtr, string propertyName)
\r
362 // Get the C# control that maps to the C++ control
\r
363 Tizen.NUI.CustomView view;
\r
365 BaseHandle baseHandle = new BaseHandle(controlPtr, false);
\r
367 RefObject refObj = baseHandle.GetObjectPtr();
\r
369 IntPtr refObjectPtr = (IntPtr)RefObject.getCPtr(refObj);
\r
371 if (_controlMap.TryGetValue(refObjectPtr, out view))
\r
374 // call the get property function
\r
375 System.Object val = view.GetType().GetProperty(propertyName).GetAccessors()[0].Invoke(view, null);
\r
377 PropertyValue value = PropertyValue.CreateFromObject(val);
\r
379 return (IntPtr)PropertyValue.getCPtr(value);
\r
383 return IntPtr.Zero;
\r
388 /// Set a property value on a View
391 private void SetPropertyValue(IntPtr controlPtr, string propertyName, IntPtr propertyValuePtr)
\r
393 // Get the C# control that maps to the C++ control
\r
394 Tizen.NUI.CustomView view;
\r
396 //Console.WriteLine ("SetPropertyValue refObjectPtr = {0:X}", controlPtr);
\r
398 PropertyValue propValue = new PropertyValue(propertyValuePtr, false);
\r
400 if (_controlMap.TryGetValue(controlPtr, out view))
\r
403 System.Reflection.PropertyInfo propertyInfo = view.GetType().GetProperty(propertyName);
\r
405 // 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
406 System.Type type = propertyInfo.PropertyType;
\r
409 if (type.Equals(typeof(Int32)))
\r
412 ok = propValue.Get(ref value);
\r
415 propertyInfo.SetValue(view, value);
\r
418 else if (type.Equals(typeof(bool)))
\r
420 bool value = false;
\r
421 ok = propValue.Get(ref value);
\r
424 propertyInfo.SetValue(view, value);
\r
427 else if (type.Equals(typeof(float)))
\r
430 ok = propValue.Get(ref value);
\r
433 propertyInfo.SetValue(view, value);
\r
436 else if (type.Equals(typeof(string)))
\r
439 ok = propValue.Get(out value);
\r
442 propertyInfo.SetValue(view, value);
\r
445 else if (type.Equals(typeof(Vector2)))
\r
447 Vector2 value = new Vector2();
\r
448 ok = propValue.Get(value);
\r
451 propertyInfo.SetValue(view, value);
\r
454 else if (type.Equals(typeof(Vector3)))
\r
456 Vector3 value = new Vector3();
\r
457 ok = propValue.Get(value);
\r
460 propertyInfo.SetValue(view, value);
\r
463 else if (type.Equals(typeof(Vector4)))
\r
465 Vector4 value = new Vector4();
\r
466 ok = propValue.Get(value);
\r
470 propertyInfo.SetValue(view, value);
\r
473 else if (type.Equals(typeof(Position)))
\r
475 Position value = new Position();
\r
476 ok = propValue.Get(value);
\r
479 propertyInfo.SetValue(view, value);
\r
482 else if (type.Equals(typeof(Size)))
\r
484 // DALi sizes are Vector3
\r
485 Size value = new Size();
\r
486 ok = propValue.Get(value);
\r
489 propertyInfo.SetValue(view, new Size(value.Width, value.Height, value.Depth));
\r
492 else if (type.Equals(typeof(Color)))
\r
494 // Colors are stored as Vector4's in DALi
\r
495 Color value = new Color();
\r
496 ok = propValue.Get(value);
\r
499 propertyInfo.SetValue(view, (Color)value);
\r
504 throw new global::System.InvalidOperationException("SetPropertyValue Unimplemented type for Property Value");
\r
508 throw new global::System.InvalidOperationException("SetPropertyValue propValue.Get failed");
\r
513 throw new global::System.InvalidOperationException("failed to find the control to write a property to: cptr = " + controlPtr);
\r