2 using System.Runtime.InteropServices;
3 using System.Collections.Generic;
8 /// Add this attribute to any property belonging to a View (control) you want to be scriptable from JSON
13 /// class MyView : public CustomView
15 /// [ScriptableProperty()]
16 /// public int MyProperty
20 /// return _myProperty;
24 /// _myProperty = value;
29 /// Internally the following occurs for property registration ( this only occurs once per Type, not per Instance):
31 /// - The controls static constructor should call ViewRegistry.Register() (only called once for the lifecycle of the app)
32 /// - Within Register() the code will introspect the Controls properties, looking for the ScriptableProperty() attribute
33 /// - For every property with the ScriptableProperty() attribute, TypeRegistration.RegisterProperty is called.
34 /// - TypeRegistration.RegisterProperty calls in to DALi C++ Code Dali::CSharpTypeRegistry::RegisterProperty()
35 /// - 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).
37 /// The DALi C# example
39 /// class MyView : public CustomView
42 /// [ScriptableProperty()]
43 /// public double Hours
45 /// get { return seconds / 3600; }
46 /// set { seconds = value * 3600; }
50 /// Equivalent code in DALi C++:
52 /// class MyControl : public Control
58 /// HOURS = Control::CONTROL_PROPERTY_END_INDEX + 1
63 /// in MyControl-impl.cpp
65 /// DALI_TYPE_REGISTRATION_BEGIN( Toolkit::MyControl, Toolkit::Control, Create );
66 /// DALI_PROPERTY_REGISTRATION( Toolkit, MyControl, "Hours", INTEGER, DISABLED )
67 /// DALI_TYPE_REGISTRATION_END()
71 public class ScriptableProperty : System.Attribute
73 public enum ScriptableType
75 Default, // Read Writable, non-animatable property, event thread only
76 // Animatable // Animatable property, Currently disabled, UK
78 public readonly ScriptableType type;
80 public ScriptableProperty(ScriptableType type = ScriptableType.Default )
87 /// View Registry singleton.
88 /// Used for registering controls and any scriptable properties they have ( see ScriptableProperty )
90 /// Internal Design from C# to C++
92 /// - Each custom C# view should have it's static constructor called before any JSON file is loaded.
93 /// Static constructors for a class will only run once ( they are run per control type, not per instance).
94 /// Example of running a static constructor:
95 /// System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor (typeof(Spin).TypeHandle);
96 /// Inside the static constructor the control should register it's type with the ViewRegistry
101 /// ViewRegistry.Instance.Register(CreateInstance, typeof(Spin) );
104 /// The control should also provide a CreateInstance function, which gets passed to the ViewRegistry
105 /// // Eventually it will be called if DALi Builderfinds a Spin control in a JSON file
106 /// static CustomView CreateInstance()
108 /// return new Spin();
113 /// The DALi C++ equivalent of this is
115 /// TypeRegistration mType( typeid(Toolkit::Spin), typeid(Toolkit::Control), CreateInstance );
120 public sealed class ViewRegistry
123 /// ViewRegistry is a singleton
125 private static ViewRegistry instance = null;
127 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
128 delegate IntPtr CreateControlDelegate( IntPtr cPtrControlName );
130 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
131 delegate IntPtr GetPropertyDelegate( IntPtr controlPtr, IntPtr propertyName );
133 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
134 delegate void SetPropertyDelegate( IntPtr controlPtr, IntPtr propertyName, IntPtr propertyValue );
136 private CreateControlDelegate _createCallback;
137 private SetPropertyDelegate _setPropertyCallback;
138 private GetPropertyDelegate _getPropertyCallback;
139 private PropertyRangeManager _propertyRangeManager;
142 /// Given a C++ control the dictionary allows us to find which C# control (View) it belongs to.
143 /// By keeping the weak reference only, it will allow the object to be garbage collected.
145 private Dictionary<IntPtr, WeakReference> _controlMap;
148 // Maps the name of a custom view to a create instance function
149 /// E.g. given a string "Spin", we can get a function used to create the Spin View.
151 private Dictionary<String, Func< CustomView > > _constructorMap;
154 /// Lookup table to match C# types to DALi types, used for the automatic property registration
156 private static readonly Dictionary<string, Dali.Property.Type> _daliPropertyTypeLookup
157 = new Dictionary< string, Dali.Property.Type >
159 { "float", Property.Type.FLOAT },
160 { "int", Property.Type.INTEGER },
161 { "Int32", Property.Type.INTEGER },
162 { "Boolean", Property.Type.BOOLEAN },
163 { "string", Property.Type.STRING },
164 { "Vector2", Property.Type.VECTOR2 },
165 { "Vector3", Property.Type.VECTOR3 },
166 { "Vector4", Property.Type.VECTOR4 },
167 { "Size", Property.Type.VECTOR2 },
168 { "Position",Property.Type.VECTOR3 },
169 { "Color", Property.Type.VECTOR4 },
170 // { "Matrix3", Property.Type.MATRIX3 }, commented out until we need to use Matrices from JSON
171 // { "Matrix", Property.Type.MATRIX },
175 public ViewRegistry()
177 _createCallback = new CreateControlDelegate( CreateControl );
178 _getPropertyCallback = new GetPropertyDelegate (GetProperty);
179 _setPropertyCallback = new SetPropertyDelegate (SetProperty);
181 _controlMap = new Dictionary<IntPtr, WeakReference>();
182 _constructorMap = new Dictionary<string, Func<CustomView>>();
183 _propertyRangeManager = new PropertyRangeManager();
187 private Dali.Property.Type GetDaliPropertyType( string cSharpTypeName )
189 Dali.Property.Type daliType;
190 if ( _daliPropertyTypeLookup.TryGetValue (cSharpTypeName, out daliType) )
192 //Console.WriteLine("mapped "+ cSharpTypeName + " to dAli type " +daliType );
197 // Console.WriteLine("Failed to find a mapping between C# property" + cSharpTypeName +" and DALi type");
198 return Property.Type.NONE;
203 /// Called directly from DALi C++ type registry to create a control (View) using no marshalling.
205 /// <returns>Pointer to the Control (Views) handle </returns>
206 /// <param name="cPtrControlName"> C pointer to the Control (View) name</param>
207 private static IntPtr CreateControl( IntPtr cPtrControlName )
209 string controlName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (cPtrControlName);
210 // Console.WriteLine ("Create controlled called from C++ create a " + controlName);
212 Func< CustomView > controlConstructor;
214 // find the control constructor
215 if ( Instance._constructorMap.TryGetValue (controlName, out controlConstructor) )
217 // Create the control
218 CustomView newControl = controlConstructor ();
219 return newControl.GetPtrfromView(); // return pointer to handle
223 throw new global::System.InvalidOperationException("C# View not registererd with ViewRegistry"+ controlName );
229 /// Store the mapping between this instance of control (View) and native part.
231 /// <param name="view"> The instance of control (View)</param>
232 public static void RegisterView( View view )
234 // We store a pointer to the RefObject for the control
235 RefObject refObj = view.GetObjectPtr();
236 IntPtr refCptr = (IntPtr) RefObject.getCPtr(refObj);
238 //Console.WriteLine ("________Storing ref object cptr in control map Hex: {0:X}", refCptr);
239 if ( !Instance._controlMap.ContainsKey(refCptr) )
241 Instance._controlMap.Add(refCptr, new WeakReference(view, false));
248 /// Remove the this instance of control (View) and native part from the mapping table.
250 /// <param name="view"> The instance of control (View)</param>
251 public static void UnregisterView( View view )
253 RefObject refObj = view.GetObjectPtr();
254 IntPtr refCptr = (IntPtr) RefObject.getCPtr(refObj);
256 if ( Instance._controlMap.ContainsKey(refCptr) )
258 Instance._controlMap.Remove(refCptr);
264 private static IntPtr GetProperty( IntPtr controlPtr, IntPtr propertyName )
266 string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (propertyName);
267 return Instance.GetPropertyValue ( controlPtr, name);
270 private static void SetProperty( IntPtr controlPtr, IntPtr propertyName, IntPtr propertyValue )
272 string name = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (propertyName);
273 //Console.WriteLine ( SetControlProperty called for:" + name );
274 Instance.SetPropertyValue ( controlPtr, name, propertyValue);
278 public static ViewRegistry Instance
284 instance = new ViewRegistry();
290 public static View GetViewFromActor( View view )
292 // we store a dictionary of ref-obects (C++ land) to custom views (C# land)
294 RefObject refObj = view.GetObjectPtr ();
295 IntPtr refObjectPtr = (IntPtr) RefObject.getCPtr(refObj);
297 WeakReference viewReference;
298 if ( Instance._controlMap.TryGetValue ( refObjectPtr, out viewReference) )
300 View retview = viewReference.Target as View;
311 /// Function which registers a view and all it's scriptable properties with DALi's type registry.
312 /// Means the View can be created / configured from a JSON script.
314 /// The function uses introspection to scan a Views C# properties, then selects the ones with
315 ///[ScriptableProperty] attribute to be registered.
316 /// Example of a Spin view registering itself
319 /// ViewRegistry registers control type with DALi type registery
320 /// also uses introspection to find any properties that need to be registered with type registry
321 /// ViewRegistry.Instance.Register(CreateInstance, typeof(Spin) );
325 public void Register(Func< CustomView > createFunction, System.Type viewType )
327 // add the mapping between the view name and it's create function
328 _constructorMap.Add (viewType.Name, createFunction);
330 // Call into DALi C++ to register the control with the type registry
331 TypeRegistration.RegisterControl( viewType.Name, _createCallback );
333 // Cycle through each property in the class
334 foreach (System.Reflection.PropertyInfo propertyInfo in viewType.GetProperties())
337 if ( propertyInfo.CanRead )
340 System.Attribute[] attrs = System.Attribute.GetCustomAttributes(propertyInfo);
341 foreach (System.Attribute attr in attrs)
343 // If the Scriptable attribute exists, then register it with the type registry.
344 if (attr is ScriptableProperty)
346 //Console.WriteLine ("Got a DALi JSON scriptable property = " + propertyInfo.Name +", of type " + propertyInfo.PropertyType.Name);
348 // first get the attribute type, ( default, or animatable)
349 ScriptableProperty scriptableProp = attr as ScriptableProperty;
351 // 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)
352 int propertyIndex = _propertyRangeManager.GetPropertyIndex( viewType.Name, viewType, scriptableProp.type );
354 // get the enum for the property type... E.g. registering a string property returns Dali.PropertyType.String
355 Dali.Property.Type propertyType = GetDaliPropertyType( propertyInfo.PropertyType.Name );
357 // Example RegisterProperty("spin","maxValue", 50001, FLOAT, set, get );
358 // Native call to register the property
359 TypeRegistration.RegisterProperty (viewType.Name, propertyInfo.Name , propertyIndex, propertyType, _setPropertyCallback, _getPropertyCallback);
362 // Console.WriteLine ("property name = " + propertyInfo.Name);
368 /// Get a property value from a View
371 private IntPtr GetPropertyValue ( IntPtr controlPtr, string propertyName)
373 // Get the C# control that maps to the C++ control
374 BaseHandle baseHandle = new BaseHandle (controlPtr, false);
376 RefObject refObj = baseHandle.GetObjectPtr ();
378 IntPtr refObjectPtr = (IntPtr) RefObject.getCPtr(refObj);
380 WeakReference viewReference;
381 if ( _controlMap.TryGetValue ( refObjectPtr, out viewReference) )
383 View view = viewReference.Target as View;
385 // call the get property function
386 System.Object val = view.GetType ().GetProperty (propertyName).GetAccessors () [0].Invoke (view, null);
388 Property.Value value = Property.Value.CreateFromObject (val);
390 return (IntPtr)Property.Value.getCPtr (value);
399 /// Set a property value on a View
402 private void SetPropertyValue ( IntPtr controlPtr, string propertyName, IntPtr propertyValuePtr)
404 // Get the C# control that maps to the C++ control
406 //Console.WriteLine ("SetPropertyValue refObjectPtr = {0:X}", controlPtr);
408 Property.Value propValue = new Property.Value (propertyValuePtr, false);
410 WeakReference viewReference;
411 if ( _controlMap.TryGetValue ( controlPtr, out viewReference) )
413 View view = viewReference.Target as View;
414 System.Reflection.PropertyInfo propertyInfo = view.GetType().GetProperty(propertyName);
416 // We know the property name, we know it's type, we just need to convert from a DALi property value to native C# type
417 System.Type type = propertyInfo.PropertyType;
420 if ( type.Equals (typeof(Int32)) )
423 ok = propValue.Get( ref value );
426 propertyInfo.SetValue (view, value);
429 else if ( type.Equals (typeof(bool)) )
432 ok = propValue.Get( ref value );
435 propertyInfo.SetValue (view, value);
438 else if ( type.Equals (typeof(float)) )
441 ok = propValue.Get( ref value );
444 propertyInfo.SetValue (view, value);
447 else if ( type.Equals (typeof(string)) )
450 ok = propValue.Get( out value );
453 propertyInfo.SetValue (view, value);
456 else if ( type.Equals (typeof(Vector2)) )
458 Vector2 value = new Vector2 ();
459 ok = propValue.Get( value );
462 propertyInfo.SetValue (view, value);
465 else if ( type.Equals (typeof(Vector3)) )
467 Vector3 value = new Vector3 ();
468 ok = propValue.Get( value );
471 propertyInfo.SetValue (view, value);
474 else if ( type.Equals (typeof(Vector4)) )
476 Vector4 value = new Vector4 ();
477 ok = propValue.Get( value );
481 propertyInfo.SetValue (view, value);
484 else if ( type.Equals (typeof(Position)) )
486 Position value = new Position ();
487 ok = propValue.Get( value );
490 propertyInfo.SetValue (view, value);
493 else if ( type.Equals (typeof(Size)) )
495 Size value = new Size();
496 ok = propValue.Get( value );
499 propertyInfo.SetValue(view, new Size(value.Width, value.Height, value.Depth));
502 else if ( type.Equals (typeof(Color)) )
504 // Colors are stored as Vector4's in DALi
505 Vector4 value = new Vector4();
506 ok = propValue.Get( value );
509 propertyInfo.SetValue (view, (Color)value);
514 throw new global::System.InvalidOperationException("SetPropertyValue Unimplemented type for Property Value");
518 throw new global::System.InvalidOperationException("SetPropertyValue propValue.Get failed");
523 throw new global::System.InvalidOperationException("failed to find the control to write a property to: cptr = " + controlPtr);