aboutsummaryrefslogtreecommitdiffstatsci
path: root/src
diff options
context:
space:
mode:
authorjpbruyere <jp.bruyere@hotmail.com>2017-01-01 18:30:51 +0100
committerjpbruyere <jp.bruyere@hotmail.com>2017-01-01 18:30:51 +0100
commit0f1346e33b59f7693f4ff40b5524c93d2629c5ce (patch)
tree7f531b6bf6fe3f37da101a12a9b2529403e4c53c /src
parent7c00385bda3a9a913050480fada2efab8d6d3090 (diff)
parent7fa6c6ca89e7a3aeadd815867de8a2a3b955134a (diff)
New binding system and new inherited measures
Diffstat (limited to 'src')
-rw-r--r--src/Colors.cs33
-rw-r--r--src/CompilerServices/Bindings.cs8
-rw-r--r--src/CompilerServices/CompilerServices.cs877
-rw-r--r--src/Enums.cs2
-rw-r--r--src/ExtensionsMethods.cs11
-rw-r--r--src/GraphicObjects/Button.cs6
-rw-r--r--src/GraphicObjects/ColorPicker.cs223
-rw-r--r--src/GraphicObjects/ColorSelector.cs89
-rw-r--r--src/GraphicObjects/DataSourceChangeEventArgs.cs41
-rw-r--r--src/GraphicObjects/DirectoryView.cs8
-rw-r--r--src/GraphicObjects/Expandable.cs37
-rw-r--r--src/GraphicObjects/FileDialog.cs175
-rw-r--r--src/GraphicObjects/GraphicObject.cs346
-rw-r--r--src/GraphicObjects/Group.cs24
-rw-r--r--src/GraphicObjects/HueSelector.cs143
-rw-r--r--src/GraphicObjects/Label.cs4
-rw-r--r--src/GraphicObjects/Menu.cs2
-rw-r--r--src/GraphicObjects/MenuItem.cs6
-rw-r--r--src/GraphicObjects/Popper.cs17
-rw-r--r--src/GraphicObjects/PrivateContainer.cs38
-rw-r--r--src/GraphicObjects/SaturationValueSelector.cs129
-rw-r--r--src/GraphicObjects/TabItem.cs12
-rw-r--r--src/GraphicObjects/TemplatedContainer.cs13
-rw-r--r--src/GraphicObjects/TemplatedControl.cs2
-rw-r--r--src/GraphicObjects/TemplatedGroup.cs93
-rw-r--r--src/GraphicObjects/Window.cs6
-rw-r--r--src/IML/BindingDefinition.cs84
-rw-r--r--src/IML/Context.cs193
-rw-r--r--src/IML/EventBinding.cs (renamed from src/GraphicObjects/IBindable.cs)21
-rw-r--r--src/IML/MemberAddress.cs110
-rw-r--r--src/IML/Node.cs85
-rw-r--r--src/IML/NodeAddress.cs69
-rw-r--r--src/IML/NodeStack.cs44
-rw-r--r--src/IML/Reader.cs223
-rw-r--r--src/IMLReader.cs346
-rw-r--r--src/Instantiator.cs971
-rw-r--r--src/Interface.cs30
-rw-r--r--src/ItemTemplate.cs52
-rw-r--r--src/LayoutingQueueItem.cs2
-rw-r--r--src/Rectangle.cs3
-rw-r--r--src/Rectangles.cs102
-rw-r--r--src/Size.cs3
-rw-r--r--src/SolidColor.cs2
43 files changed, 3333 insertions, 1352 deletions
diff --git a/src/Colors.cs b/src/Colors.cs
index 6787c382..65a7f037 100644
--- a/src/Colors.cs
+++ b/src/Colors.cs
@@ -15,6 +15,8 @@ namespace Crow
/// </summary>
public struct Color
{
+ internal static Type TColor = typeof(Color);
+
#region CTOR
public Color(double _R, double _G, double _B, double _A)
{
@@ -1046,7 +1048,7 @@ namespace Crow
}
public override bool Equals (object obj)
{
- return (obj == null || obj.GetType() != typeof(Color)) ?
+ return (obj == null || obj.GetType() != TColor) ?
false :
this == (Color)obj;
}
@@ -1071,5 +1073,34 @@ namespace Crow
{
return (Color)s;
}
+ public static Color FromHSV(double _h, double _v = 1.0, double _s = 1.0){
+ Color c = Color.Black;
+
+ if (_s == 0) {//HSV from 0 to 1
+ c.R = _v;
+ c.G = _v;
+ c.B = _v;
+ }else{
+ double var_h = _h * 6.0;
+
+ if (var_h == 6.0)
+ var_h = 0; //H must be < 1
+ double var_i = Math.Floor( var_h ); //Or ... var_i = floor( var_h )
+ double var_1 = _v * ( 1.0 - _s );
+ double var_2 = _v * (1.0 - _s * (var_h - var_i));
+ double var_3 = _v * (1.0 - _s * (1.0 - (var_h - var_i)));
+
+ if (var_i == 0.0) {
+ c.R = _v;
+ c.G = var_3;
+ c.B = var_1;
+ }else if ( var_i == 1.0 ) { c.R = var_2 ; c.G = _v ; c.B = var_1; }
+ else if ( var_i == 2 ) { c.R = var_1 ; c.G = _v ; c.B = var_3; }
+ else if ( var_i == 3 ) { c.R = var_1 ; c.G = var_2 ; c.B = _v; }
+ else if ( var_i == 4 ) { c.R = var_3 ; c.G = var_1 ; c.B = _v; }
+ else { c.R = _v ; c.G = var_1 ; c.B = var_2; }
+ }
+ return c;
+ }
}
}
diff --git a/src/CompilerServices/Bindings.cs b/src/CompilerServices/Bindings.cs
index 64f412f6..2f4077b2 100644
--- a/src/CompilerServices/Bindings.cs
+++ b/src/CompilerServices/Bindings.cs
@@ -199,10 +199,10 @@ namespace Crow
if (Target.TryFindMember (memberName)) {
if (TwoWayBinding) {
- IBindable source = Target.Instance as IBindable;
- if (source == null)
- throw new Exception (Source.Instance + " does not implement IBindable for 2 way bindings");
- source.Bindings.Add (new Binding (Target, Source));
+// IBindable source = Target.Instance as IBindable;
+// if (source == null)
+// throw new Exception (Source.Instance + " does not implement IBindable for 2 way bindings");
+// source.Bindings.Add (new Binding (Target, Source));
}
}
#if DEBUG_BINDING
diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs
index 43c9d704..c0acc5d5 100644
--- a/src/CompilerServices/CompilerServices.cs
+++ b/src/CompilerServices/CompilerServices.cs
@@ -6,41 +6,101 @@ using System.Linq;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Xml;
+using Crow.IML;
namespace Crow
{
public static class CompilerServices
{
- static MethodInfo miAddBinding = typeof(GraphicObject).GetMethod ("BindMember");
- static FieldInfo miSetCurIface = typeof(GraphicObject).GetField ("currentInterface",
- BindingFlags.NonPublic | BindingFlags.Instance);
- static MethodInfo stringEquals = typeof (string).GetMethod
- ("Equals", new Type [3] { typeof (string), typeof (string), typeof (StringComparison) });
- static MethodInfo miFindByName = typeof (GraphicObject).GetMethod ("FindByName");
-
+ internal static Type TObject = typeof(object);
+ internal static MethodInfo stringEquals = typeof (string).GetMethod("Equals", new Type [3] { typeof (string), typeof (string), typeof (StringComparison) });
+ internal static MethodInfo miObjToString = typeof(object).GetMethod("ToString");
+ internal static MethodInfo miGetType = typeof(object).GetMethod("GetType");
+ internal static MethodInfo miParseEnum = typeof(Enum).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public,
+ Type.DefaultBinder, new Type [] {typeof (Type), typeof (string), typeof (bool)}, null);
- #region ValueChange Reflexion member info
- static EventInfo eiValueChange = typeof (IValueChange).GetEvent ("ValueChanged");
- static MethodInfo miInvokeValueChange = eiValueChange.EventHandlerType.GetMethod ("Invoke");
- static Type [] argsValueChange = { typeof (object), typeof (object), miInvokeValueChange.GetParameters () [1].ParameterType };
- static FieldInfo fiNewValue = typeof (ValueChangeEventArgs).GetField ("NewValue");
- static FieldInfo fiMbName = typeof (ValueChangeEventArgs).GetField ("MemberName");
- static MethodInfo miValueChangeAdd = eiValueChange.GetAddMethod ();
+ internal static MethodInfo miGetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");
+ internal static MethodInfo miGetEvent = typeof(Type).GetMethod("GetEvent", new Type[] {typeof(string)});
+
+ internal static MethodInfo miMIInvoke = typeof(MethodInfo).GetMethod ("Invoke", new Type[] {
+ typeof(object),
+ typeof(object[])
+ });
+
+ internal static MethodInfo miCreateBoundDel = typeof(Delegate).GetMethod ("CreateDelegate", new Type[] { typeof(Type), typeof(object), typeof(MethodInfo) });//create bound delegate
+ internal static MethodInfo miGetColCount = typeof(System.Collections.ICollection).GetProperty("Count").GetGetMethod();
+ internal static MethodInfo miGetDelegateListItem = typeof(List<Delegate>).GetMethod("get_Item", new Type[] { typeof(Int32) });
+
+ internal static MethodInfo miCompileDynEventHandler = typeof(CompilerServices).GetMethod ("compileDynEventHandler", BindingFlags.Static | BindingFlags.Public);
+ internal static MethodInfo miRemEvtHdlByName = typeof(CompilerServices).GetMethod("RemoveEventHandlerByName", BindingFlags.Static | BindingFlags.Public);
+ internal static MethodInfo miRemEvtHdlByTarget = typeof(CompilerServices).GetMethod("RemoveEventHandlerByTarget", BindingFlags.Static | BindingFlags.Public);
+ internal static MethodInfo miGetMethInfoWithRefx = typeof(CompilerServices).GetMethod ("getMethodInfoWithReflexion", BindingFlags.Static | BindingFlags.Public);
+ internal static MethodInfo miGetMembIinfoWithRefx = typeof(CompilerServices).GetMethod("getMemberInfoWithReflexion", BindingFlags.Static | BindingFlags.Public);
+ internal static MethodInfo miSetValWithRefx = typeof(CompilerServices).GetMethod("setValueWithReflexion", BindingFlags.Static | BindingFlags.Public);
+ internal static MethodInfo miGetValWithRefx = typeof(CompilerServices).GetMethod("getValueWithReflexion", BindingFlags.Static | BindingFlags.Public);
+ internal static MethodInfo miCreateDel = typeof(CompilerServices).GetMethod ("createDel", BindingFlags.Static | BindingFlags.NonPublic);
+ internal static MethodInfo miGetImplOp = typeof(CompilerServices).GetMethod ("getImplicitOp", BindingFlags.Static | BindingFlags.Public);
+
+ internal static FieldInfo fiCachedDel = typeof(Instantiator).GetField("cachedDelegates", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static FieldInfo fiTemplateBinding = typeof(Instantiator).GetField("templateBinding", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static MethodInfo miDSChangeEmitHelper = typeof(Instantiator).GetMethod("dataSourceChangedEmitHelper", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static MethodInfo miDSReverseBinding = typeof(Instantiator).GetMethod("dataSourceReverseBinding", BindingFlags.Static | BindingFlags.NonPublic);
+
+ internal static FieldInfo miSetCurIface = typeof(GraphicObject).GetField ("currentInterface", BindingFlags.NonPublic | BindingFlags.Instance);
+ internal static MethodInfo miFindByName = typeof (GraphicObject).GetMethod ("FindByName");
+ internal static MethodInfo miGetGObjItem = typeof(List<GraphicObject>).GetMethod("get_Item", new Type[] { typeof(Int32) });
+ internal static MethodInfo miLoadDefaultVals = typeof (GraphicObject).GetMethod ("loadDefaultValues");
+ internal static PropertyInfo piStyle = typeof (GraphicObject).GetProperty ("Style");
+ internal static MethodInfo miGetLogicalParent = typeof(GraphicObject).GetProperty("LogicalParent").GetGetMethod();
+ internal static MethodInfo miGetDataSource = typeof(GraphicObject).GetProperty("DataSource").GetGetMethod ();
+ internal static EventInfo eiLogicalParentChanged = typeof(GraphicObject).GetEvent("LogicalParentChanged");
+
+ internal static MethodInfo miIFaceLoad = typeof(Interface).GetMethod ("Load", BindingFlags.Instance | BindingFlags.Public);
+ internal static MethodInfo miGetITemp = typeof(Interface).GetMethod ("GetItemTemplate");
+
+ internal static MethodInfo miAddITemp = typeof(Dictionary<string, ItemTemplate>).GetMethod ("set_Item", new Type[] { typeof(string), typeof(ItemTemplate) });
+ internal static MethodInfo miGetITempFromDic = typeof(Dictionary<string, ItemTemplate>).GetMethod ("get_Item", new Type[] { typeof(string) });
+ internal static FieldInfo fldItemTemplates = typeof(TemplatedGroup).GetField("ItemTemplates");
+ internal static MethodInfo miCreateExpDel = typeof(ItemTemplate).GetMethod ("CreateExpandDelegate");
+
+ #region tree handling methods
+ internal static FieldInfo fiChild = typeof(PrivateContainer).GetField ("child", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static MethodInfo miSetChild = typeof (Container).GetMethod ("SetChild");
+ internal static MethodInfo miAddChild = typeof (Group).GetMethod ("AddChild");
+ internal static FieldInfo fiChildren = typeof(Group).GetField ("children", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static MethodInfo miLoadTmp = typeof (TemplatedControl).GetMethod ("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic);
+ internal static PropertyInfo piContent = typeof(TemplatedContainer).GetProperty ("Content");
+ internal static MethodInfo miAddItem = typeof (TemplatedGroup).GetMethod ("AddItem", BindingFlags.Instance | BindingFlags.Public);
+ internal static MethodInfo miGetItems = typeof(TemplatedGroup).GetProperty ("Items").GetGetMethod ();
#endregion
+ #region ValueChange & DSChange Reflexion member info
+ internal static EventInfo eiValueChange = typeof (IValueChange).GetEvent ("ValueChanged");
+ internal static MethodInfo miInvokeValueChange = eiValueChange.EventHandlerType.GetMethod ("Invoke");
+ internal static Type [] argsBoundValueChange = { typeof (object), typeof (object), miInvokeValueChange.GetParameters () [1].ParameterType };
+ internal static Type [] argsValueChange = { typeof (object), miInvokeValueChange.GetParameters () [1].ParameterType };
+ internal static FieldInfo fiVCNewValue = typeof (ValueChangeEventArgs).GetField ("NewValue");
+ internal static FieldInfo fiVCMbName = typeof (ValueChangeEventArgs).GetField ("MemberName");
+ internal static MethodInfo miValueChangeAdd = eiValueChange.GetAddMethod ();
+
+ internal static EventInfo eiDSChange = typeof (GraphicObject).GetEvent ("DataSourceChanged");
+ internal static MethodInfo miInvokeDSChange = eiDSChange.EventHandlerType.GetMethod ("Invoke");
+ internal static Type [] argsBoundDSChange = {typeof (object), typeof (object), miInvokeDSChange.GetParameters () [1].ParameterType };
+ internal static FieldInfo fiDSCNewDS = typeof (DataSourceChangeEventArgs).GetField ("NewDataSource");
+ internal static FieldInfo fiDSCOldDS = typeof (DataSourceChangeEventArgs).GetField ("OldDataSource");
+ internal static Type ehTypeDSChange = eiDSChange.EventHandlerType;
+ #endregion
+ /// <summary>
+ /// Loc0 is the current graphic object and arg2 of loader is the current interface
+ /// </summary>
+ /// <param name="il">Il.</param>
public static void emitSetCurInterface(ILGenerator il){
il.Emit (OpCodes.Ldloc_0);
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Stfld, miSetCurIface);
}
- public static void emitBindingCreation(ILGenerator il, string memberName, string expression){
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Ldstr, memberName);
- il.Emit (OpCodes.Ldstr, expression);
- il.Emit (OpCodes.Callvirt, miAddBinding);
- }
public static void EmitSetValue(ILGenerator il, PropertyInfo pi, object val){
il.Emit (OpCodes.Ldloc_0);
@@ -119,25 +179,17 @@ namespace Crow
if (pi.PropertyType == typeof(string))
il.Emit (OpCodes.Ldstr, Convert.ToString (val));
else if (pi.PropertyType.IsEnum) {
- MethodInfo miParse = typeof(Enum).GetMethod
- ("Parse", BindingFlags.Static | BindingFlags.Public,
- Type.DefaultBinder, new Type [] {typeof (Type), typeof (string), typeof (bool)}, null);
-
- if (miParse == null)
- throw new Exception ("Enum Parse method not found");
-
//load type of enum
il.Emit(OpCodes.Ldtoken, pi.PropertyType);
- il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new
- Type[1]{typeof(RuntimeTypeHandle)}));
+ il.Emit(OpCodes.Call, CompilerServices.miGetTypeFromHandle);
//load enum value name
il.Emit (OpCodes.Ldstr, Convert.ToString (val));//TODO:is this convert required?
//load false
il.Emit (OpCodes.Ldc_I4_0);
- il.Emit (OpCodes.Callvirt, miParse);
+ il.Emit (OpCodes.Callvirt, CompilerServices.miParseEnum);
- if (miParse.ReturnType != pi.PropertyType)
- il.Emit (OpCodes.Unbox_Any, pi.PropertyType);
+ if (CompilerServices.miParseEnum.ReturnType != pi.PropertyType)
+ il.Emit (OpCodes.Unbox_Any, pi.PropertyType);
} else {
MethodInfo miParse = pi.PropertyType.GetMethod
("Parse", BindingFlags.Static | BindingFlags.Public,
@@ -152,275 +204,385 @@ namespace Crow
il.Emit (OpCodes.Unbox_Any, pi.PropertyType);
}
}
- il.Emit (OpCodes.Callvirt, pi.GetSetMethod ());
+ il.Emit (OpCodes.Callvirt, pi.GetSetMethod ());
}
- public static void ResolveBindings (List<Binding> Bindings)
- {
- if (Bindings == null)
- return;
- if (Bindings.Count == 0)
- return;
- //#if DEBUG_BINDING
- // Debug.WriteLine ("Resolve Bindings => " + this.ToString ());
- //#endif
- //grouped bindings by Instance of Source
- Dictionary<object, List<Binding>> resolved = new Dictionary<object, List<Binding>> ();
-
- foreach (Binding b in Bindings) {
- if (b.Resolved)
- continue;
- if (b.Source.Member.MemberType == MemberTypes.Event) {
- if (b.Expression.StartsWith ("{")) {
- CompilerServices.CompileEventSource (b);
- continue;
- }
- if (!b.TryFindTarget ())
- continue;
- //register handler for event
- if (b.Target.Method == null) {
- //Debug.WriteLine ("\tError: Handler Method not found: " + b.ToString ());
- continue;
- }
- try {
- MethodInfo addHandler = b.Source.Event.GetAddMethod ();
- Delegate del = Delegate.CreateDelegate (b.Source.Event.EventHandlerType, b.Target.Instance, b.Target.Method);
- addHandler.Invoke (b.Source.Instance, new object [] { del });
+ #region conversions
-#if DEBUG_BINDING
- Debug.WriteLine ("\tHandler binded => " + b.ToString());
-#endif
- b.Resolved = true;
- } catch (Exception ex) {
- //Debug.WriteLine ("\tERROR: " + ex.ToString ());
- }
- continue;
- }
+ internal static MethodInfo GetConvertMethod (Type targetType)
+ {
+ string name;
- if (!b.TryFindTarget ())
- continue;
+ if (targetType == typeof (bool))
+ name = "ToBoolean";
+ else if (targetType == typeof (byte))
+ name = "ToByte";
+ else if (targetType == typeof (short))
+ name = "ToInt16";
+ else if (targetType == typeof (int))
+ name = "ToInt32";
+ else if (targetType == typeof (long))
+ name = "ToInt64";
+ else if (targetType == typeof (double))
+ name = "ToDouble";
+ else if (targetType == typeof (float))
+ name = "ToSingle";
+ else if (targetType == typeof (string))
+ return typeof (object).GetMethod ("ToString", Type.EmptyTypes);
+ else //try to find implicit convertion
+ throw new NotImplementedException (string.Format ("Conversion to {0} is not implemented.", targetType.Name));
- //group Bindings by target instanceq
- List<Binding> bindings = null;
- if (!resolved.TryGetValue (b.Target.Instance, out bindings)) {
- bindings = new List<Binding> ();
- resolved [b.Target.Instance] = bindings;
- }
- bindings.Add (b);
- b.Resolved = true;
- }
+ return typeof (Convert).GetMethod (name, BindingFlags.Static | BindingFlags.Public, null, new Type [] { typeof (object) }, null);
+ }
+ #endregion
- Type target_Type = Bindings [0].Source.Instance.GetType ();
+ /// <summary>
+ /// retrieve event handler in class or ancestors
+ /// </summary>
+ public static FieldInfo GetEventHandlerField (Type type, string eventName)
+ {
+ FieldInfo fi;
+ Type ty = type;
+ do {
+ fi = ty.GetField (eventName,
+ BindingFlags.NonPublic |
+ BindingFlags.Instance |
+ BindingFlags.GetField);
+ ty = ty.BaseType;
+ if (ty == null)
+ break;
+ } while (fi == null);
+ return fi;
+ }
- //group;only one dynMethods by target (valuechanged event source)
- //changed value name tested in switch
- //IEnumerable<Binding[]> groupedByTarget = resolved.GroupBy (g => g.Target.Instance, g => g, (k, g) => g.ToArray ());
- foreach (List<Binding> grouped in resolved.Values) {
- int i = 0;
- Type source_Type = grouped [0].Target.Instance.GetType ();
+ /// <summary>
+ /// Gets extension methods defined in assembley for extendedType
+ /// </summary>
+ /// <returns>Extension methods enumerable</returns>
+ /// <param name="assembly">Assembly</param>
+ /// <param name="extendedType">Extended type to search for</param>
+ public static IEnumerable<MethodInfo> GetExtensionMethods (Assembly assembly,
+ Type extendedType)
+ {
+ IEnumerable<MethodInfo> query = null;
+ Type curType = extendedType;
- DynamicMethod dm = null;
- ILGenerator il = null;
+ do {
+ query = from type in assembly.GetTypes ()
+ where type.IsSealed && !type.IsGenericType && !type.IsNested
+ from method in type.GetMethods (BindingFlags.Static
+ | BindingFlags.Public | BindingFlags.NonPublic)
+ where method.IsDefined (typeof (ExtensionAttribute), false)
+ where method.GetParameters () [0].ParameterType == curType
+ select method;
- System.Reflection.Emit.Label [] jumpTable = null;
- System.Reflection.Emit.Label endMethod = new System.Reflection.Emit.Label ();
+ if (query.Count () > 0)
+ break;
- #region Retrieve EventHandler parameter type
- //EventInfo ei = targetType.GetEvent ("ValueChanged");
- //no dynamic update if ValueChanged interface is not implemented
- if (source_Type.GetInterfaces ().Contains (typeof (IValueChange))) {
- dm = new DynamicMethod (grouped [0].CreateNewDynMethodId (),
- MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
- CallingConventions.Standard,
- typeof (void),
- argsValueChange,
- target_Type, true);
+ curType = curType.BaseType;
+ } while (curType != null);
- il = dm.GetILGenerator (256);
+ return query;
+ }
- endMethod = il.DefineLabel ();
- jumpTable = new System.Reflection.Emit.Label [grouped.Count];
- for (i = 0; i < grouped.Count; i++)
- jumpTable [i] = il.DefineLabel ();
- il.DeclareLocal (typeof (string));
- il.DeclareLocal (typeof (object));
+ public static MethodInfo SearchExtMethod(Type t, string methodName){
+ MethodInfo mi = null;
+ mi = GetExtensionMethods (Assembly.GetEntryAssembly(), t)
+ .Where (em => em.Name == methodName).FirstOrDefault ();
+ if (mi != null)
+ return mi;
- il.Emit (OpCodes.Nop);
- il.Emit (OpCodes.Ldarg_0);
- //il.Emit(OpCodes.Isinst, sourceType);
- //push new value onto stack
- il.Emit (OpCodes.Ldarg_2);
- il.Emit (OpCodes.Ldfld, fiNewValue);
- il.Emit (OpCodes.Stloc_1);
- //push name
- il.Emit (OpCodes.Ldarg_2);
- il.Emit (OpCodes.Ldfld, fiMbName);
- il.Emit (OpCodes.Stloc_0);
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Brfalse, endMethod);
- }
- #endregion
+ return GetExtensionMethods (Assembly.GetExecutingAssembly(), t)
+ .Where (em => em.Name == methodName).FirstOrDefault ();
+ }
- i = 0;
- foreach (Binding b in grouped) {
- #region initialize target with actual value
- object targetValue = null;
- if (b.Target.Member != null) {
- if (b.Target.Member.MemberType == MemberTypes.Property)
- targetValue = b.Target.Property.GetGetMethod ().Invoke (b.Target.Instance, null);
- else if (b.Target.Member.MemberType == MemberTypes.Field)
- targetValue = b.Target.Field.GetValue (b.Target.Instance);
- else if (b.Target.Member.MemberType == MemberTypes.Method) {
- MethodInfo mthSrc = b.Target.Method;
- if (mthSrc.IsDefined (typeof (ExtensionAttribute), false))
- targetValue = mthSrc.Invoke (null, new object [] { b.Target.Instance });
- else
- targetValue = mthSrc.Invoke (b.Target.Instance, null);
- } else
- throw new Exception ("unandled source member type for binding");
- } else if (string.IsNullOrEmpty (b.Expression))
- targetValue = grouped [0].Target.Instance;//empty binding exp=> bound to target object by default
- //TODO: handle other dest type conversions
- if (b.Source.Property.PropertyType == typeof (string)) {
- if (targetValue == null) {
- //set default value
+ public static MemberInfo getMemberInfoWithReflexion(object instance, string member){
+ return instance.GetType ().GetMember (member).FirstOrDefault();
+ }
+ public static MethodInfo getMethodInfoWithReflexion(object instance, string method){
+ return instance.GetType ().GetMethod (method, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+ }
+ public static Type getEventHandlerType(object instance, string eventName){
+ return instance.GetType ().GetEvent (eventName).EventHandlerType;
+ }
+ public static void setValueWithReflexion(object dest, object value, string destMember){
+ Type destType = null;
+ Type origType = null;
+ object convertedVal = null;
- } else
- targetValue = targetValue.ToString ();
- }
- try {
- if (targetValue != null)
- b.Source.Property.GetSetMethod ().Invoke
- (b.Source.Instance, new object [] { b.Source.Property.PropertyType.Cast (targetValue) });
- else
- b.Source.Property.GetSetMethod ().Invoke
- (b.Source.Instance, new object [] { targetValue });
- } catch (Exception ex) {
- Debug.WriteLine (ex.ToString ());
- }
- #endregion
+ MemberInfo miDest = getMemberInfoWithReflexion (dest, destMember);
- //if no dyn update, skip jump table
- if (il == null)
- continue;
+ if (miDest == null) {
+ Debug.WriteLine ("Reverse template binding error: " + destMember + " not found in " + dest);
+ return;
+ }
- il.Emit (OpCodes.Ldloc_0);
- if (b.Target.Member != null)
- il.Emit (OpCodes.Ldstr, b.Target.Member.Name);
- else
- il.Emit (OpCodes.Ldstr, b.Expression.Split ('/').LastOrDefault ());
- il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
- il.Emit (OpCodes.Callvirt, stringEquals);
- il.Emit (OpCodes.Brtrue, jumpTable [i]);
- i++;
- }
+ if (miDest.MemberType == MemberTypes.Property)
+ destType =(miDest as PropertyInfo).PropertyType;
+ else if (miDest.MemberType == MemberTypes.Field)
+ destType =(miDest as FieldInfo).FieldType;
- if (il == null)
- continue;
+ if (value != null) {
+ origType = value.GetType ();
+ if (destType.IsAssignableFrom (origType))
+ convertedVal = Convert.ChangeType (value, destType);
+ else if (origType.IsPrimitive & destType.IsPrimitive)
+ convertedVal = GetConvertMethod (destType).Invoke (null, new Object[] { value });
+ else
+ convertedVal = getImplicitOp (origType, destType).Invoke (value, null);
+ }
- il.Emit (OpCodes.Br, endMethod);
+ if (miDest.MemberType == MemberTypes.Property)
+ (miDest as PropertyInfo).SetValue (dest, convertedVal);
+ else if (miDest.MemberType == MemberTypes.Field)
+ (miDest as FieldInfo).SetValue (dest, convertedVal);
+ }
+ public static object getValueWithReflexion(object instance, MemberInfo mi){
+ object tmp = null;
+ Type dstType = null;
+ if (mi == null)
+ return null;
+ if (mi.MemberType == MemberTypes.Property) {
+ PropertyInfo pi = mi as PropertyInfo;
+ tmp = pi.GetValue (instance);
+ dstType = pi.PropertyType;
+ }
+ if (mi.MemberType == MemberTypes.Field) {
+ FieldInfo fi = mi as FieldInfo;
+ tmp = fi.GetValue (instance);
+ dstType = fi.FieldType;
+ }
+ if (tmp != null)
+ return tmp;
+ if (dstType == typeof(string) || dstType == CompilerServices.TObject)//TODO:object should be allowed to return null and not ""
+ return "";
+ if (dstType.IsValueType)
+ return Activator.CreateInstance (dstType);
- i = 0;
- foreach (Binding b in grouped) {
+ return null;
+ }
+ public static void emitGetInstance (ILGenerator il, NodeAddress orig, NodeAddress dest){
+ int ptr = 0;
+ while (orig [ptr] == dest [ptr]) {
+ ptr++;
+ if (ptr == orig.Count || ptr == dest.Count)
+ break;
+ }
+ for (int i = 0; i < orig.Count - ptr; i++)
+ il.Emit (OpCodes.Callvirt, CompilerServices.miGetLogicalParent);
+ while (ptr < dest.Count) {
+ emitGetChild (il, dest [ptr-1].CrowType, dest [ptr].Index);
+ ptr++;
+ }
+ }
+ public static void emitGetInstance (ILGenerator il, NodeAddress dest){
+ if (dest == null)
+ return;
+ for (int i = 0; i < dest.Count - 1; i++)
+ emitGetChild (il, dest [i].CrowType, dest [i + 1].Index);
+ }
+ public static void emitGetChild(ILGenerator il, Type parentType, int index){
+ if (typeof (Group).IsAssignableFrom (parentType)) {
+ il.Emit (OpCodes.Ldfld, fiChildren);
+ il.Emit(OpCodes.Ldc_I4, index);
+ il.Emit (OpCodes.Callvirt, miGetGObjItem);
+ return;
+ }
+ if (typeof(Container).IsAssignableFrom (parentType) || index < 0) {
+ il.Emit (OpCodes.Ldfld, fiChild);
+ return;
+ }
+ if (typeof(TemplatedContainer).IsAssignableFrom (parentType)) {
+ il.Emit (OpCodes.Callvirt, piContent.GetGetMethod());
+ return;
+ }
+ if (typeof(TemplatedGroup).IsAssignableFrom (parentType)) {
+ il.Emit (OpCodes.Callvirt, miGetItems);
+ il.Emit(OpCodes.Ldc_I4, index);
+ il.Emit (OpCodes.Callvirt, miGetGObjItem);
+ return;
+ }
+ }
+ /// <summary>
+ /// Emit conversion from orig type to dest type
+ /// </summary>
+ public static void emitConvert(ILGenerator il, Type origType, Type destType){
+ if (destType == CompilerServices.TObject)
+ return;
+ if (destType == typeof(string)) {
+ System.Reflection.Emit.Label emitNullStr = il.DefineLabel ();
+ System.Reflection.Emit.Label endConvert = il.DefineLabel ();
+ il.Emit (OpCodes.Dup);
+ il.Emit (OpCodes.Brfalse, emitNullStr);
+ il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
+ il.Emit (OpCodes.Br, endConvert);
+ il.MarkLabel (emitNullStr);
+ il.Emit (OpCodes.Pop);//remove null string from stack
+ il.Emit (OpCodes.Ldstr, "");//replace with empty string
+ il.MarkLabel (endConvert);
+ }else if (origType.IsValueType) {
+ if (destType != origType) {
+ il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (destType));
+ }else
+ il.Emit (OpCodes.Unbox_Any, destType);//TODO:double check this
+ } else {
+ if (origType.IsAssignableFrom(destType))
+ il.Emit (OpCodes.Castclass, destType);
+ else {
+ MethodInfo miIO = getImplicitOp (origType, destType);
+ if (miIO != null)
+ il.Emit (OpCodes.Callvirt, miIO);
+ }
+ }
+ }
+ /// <summary>
+ /// check type of current object on the stack and convert to dest type,
+ /// use loc_0 so store it as object!!!
+ /// </summary>
+ public static void emitConvert(ILGenerator il, Type dstType){
+ System.Reflection.Emit.Label endConvert = il.DefineLabel ();
+ System.Reflection.Emit.Label convert = il.DefineLabel ();
- il.MarkLabel (jumpTable [i]);
+ il.Emit (OpCodes.Dup);
+ il.Emit (OpCodes.Isinst, dstType);
+ il.Emit (OpCodes.Brfalse, convert);
+ if (dstType.IsValueType)
+ il.Emit (OpCodes.Unbox_Any, dstType);
+ else
+ il.Emit (OpCodes.Isinst, dstType);
+ il.Emit (OpCodes.Br, endConvert);
- //load 2 times to check first for null
- il.Emit (OpCodes.Ldloc_1);
- il.Emit (OpCodes.Ldloc_1);
+ il.MarkLabel (convert);
- System.Reflection.Emit.Label labSetValue = il.DefineLabel ();
- il.Emit (OpCodes.Brtrue, labSetValue);
- //if null
- il.Emit (OpCodes.Unbox_Any, b.Source.Property.PropertyType);
- il.Emit (OpCodes.Callvirt, b.Source.Property.GetSetMethod ());
- il.Emit (OpCodes.Br, endMethod);
+ if (dstType == typeof(string)) {
+ il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
+ } else if (dstType.IsPrimitive) {
+ //il.Emit (OpCodes.Unbox_Any, dstType);
+ il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (dstType));
+ } else if (dstType.IsValueType) {
+ il.Emit (OpCodes.Unbox_Any, dstType);
+ } else{
+ il.Emit (OpCodes.Stloc_0); //save orig value in loc0
+ il.Emit (OpCodes.Ldloc_0);
+ il.Emit (OpCodes.Callvirt, miGetType);
+ il.Emit (OpCodes.Ldtoken, dstType);//push destination property type for testing
+ il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle);
+ il.Emit (OpCodes.Call, miGetImplOp);
+ il.Emit (OpCodes.Dup);
+ convert = il.DefineLabel ();
+ il.Emit (OpCodes.Brtrue, convert);
+ il.Emit (OpCodes.Pop);
+ il.Emit (OpCodes.Ldloc_0);
+ il.Emit (OpCodes.Isinst, dstType);
+ il.Emit (OpCodes.Br, endConvert);
- il.MarkLabel (labSetValue);
- //new value not null
+ il.MarkLabel (convert);
+ il.Emit (OpCodes.Ldnull);//null instance for invoke
+ il.Emit (OpCodes.Ldc_I4_1);
+ il.Emit(OpCodes.Newarr, CompilerServices.TObject);
+ il.Emit (OpCodes.Dup);//duplicate the array ref
+ il.Emit (OpCodes.Ldc_I4_0);//push the index 0
+ il.Emit (OpCodes.Ldloc_0);//push the orig value to convert
+ il.Emit (OpCodes.Stelem, CompilerServices.TObject);//set the array element at index 0
+ il.Emit (OpCodes.Callvirt, miMIInvoke);
+ }
- //by default, source value type is deducted from target member type to allow
- //memberless binding, if targetMember exists, it will be used to determine target
- //value type for conversion
- Type sourceValueType = b.Source.Property.PropertyType;
- if (b.Target.Member != null) {
- if (b.Target.Member.MemberType == MemberTypes.Property)
- sourceValueType = b.Target.Property.PropertyType;
- else if (b.Target.Member.MemberType == MemberTypes.Field)
- sourceValueType = b.Target.Field.FieldType;
- else
- throw new Exception ("unhandle target member type in binding");
+ il.MarkLabel (endConvert);
+ }
+ /// <summary>
+ /// search for an implicit conversion method in origine or destination classes
+ /// </summary>
+ public static MethodInfo getImplicitOp(Type origType, Type dstType){
+ foreach(MethodInfo mi in origType.GetMethods(BindingFlags.Public|BindingFlags.Static)){
+ if (mi.Name == "op_Implicit") {
+ if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType)
+ return mi;
+ }
+ }
+ foreach(MethodInfo mi in dstType.GetMethods(BindingFlags.Public|BindingFlags.Static)){
+ if (mi.Name == "op_Implicit") {
+ if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType)
+ return mi;
+ }
+ }
+ return null;
+ }
+ /// <summary>
+ /// Removes delegate from event handler by name
+ /// </summary>
+ public static void RemoveEventHandlerByName(object instance, string eventName, string delegateName){
+ Type t = instance.GetType ();
+ FieldInfo fiEvt = CompilerServices.GetEventHandlerField (t, eventName);
+ if (fiEvt == null) {
+ Debug.WriteLine ("RemoveHandlerByName: Event '" + eventName + "' not found in " + instance);
+ return;
+ }
+ EventInfo eiEvt = t.GetEvent (eventName);
+ MulticastDelegate multiDel = fiEvt.GetValue (instance) as MulticastDelegate;
+ if (multiDel != null) {
+ foreach (Delegate d in multiDel.GetInvocationList()) {
+ if (d.Method.Name == delegateName) {
+ eiEvt.RemoveEventHandler (instance, d);
+ #if DEBUG_BINDING
+ Debug.WriteLine ("\t{0} handler removed in {1} for: {2}", d.Method.Name,instance, eventName);
+ #endif
}
-
-
-
- if (b.Source.Property.PropertyType == typeof (string)) {
- MemberReference tostring = new MemberReference (b.Source.Instance);
- if (!tostring.TryFindMember ("ToString"))
- throw new Exception ("ToString method not found");
- il.Emit (OpCodes.Callvirt, tostring.Method);
- } else if (!sourceValueType.IsValueType)
- il.Emit (OpCodes.Castclass, sourceValueType);
- else if (b.Source.Property.PropertyType != sourceValueType) {
- il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (b.Source.Property.PropertyType));
- } else
- il.Emit (OpCodes.Unbox_Any, b.Source.Property.PropertyType);
-
- il.Emit (OpCodes.Callvirt, b.Source.Property.GetSetMethod ());
-
- //il.BeginCatchBlock (typeof (Exception));
- //il.Emit (OpCodes.Pop);
- //il.EndExceptionBlock ();
-
- il.Emit (OpCodes.Br, endMethod);
- i++;
-
}
- il.MarkLabel (endMethod);
- il.Emit (OpCodes.Pop);
- il.Emit (OpCodes.Ret);
-
- Delegate del = dm.CreateDelegate (eiValueChange.EventHandlerType, Bindings [0].Source.Instance);
- miValueChangeAdd.Invoke (grouped [0].Target.Instance, new object [] { del });
}
}
-
/// <summary>
- /// Compile events expression in GOML attributes
+ /// Removes delegate from event handler by searching for the object they are bond to
/// </summary>
- /// <param name="binding">Event binding details</param>
- public static void CompileEventSource (Binding binding)
- {
-#if DEBUG_BINDING
- Debug.WriteLine ("\tCompile Event Source => " + binding.ToString());
-#endif
+ public static void RemoveEventHandlerByTarget(object instance, string eventName, object target){
+ Type t = instance.GetType ();
+ FieldInfo fiEvt = CompilerServices.GetEventHandlerField (t, eventName);
+ EventInfo eiEvt = t.GetEvent (eventName);
+ MulticastDelegate multiDel = fiEvt.GetValue (instance) as MulticastDelegate;
+ if (multiDel != null) {
+ foreach (Delegate d in multiDel.GetInvocationList()) {
+ if (d.Target == target) {
+ eiEvt.RemoveEventHandler (instance, d);
+ #if DEBUG_BINDING
+ Debug.WriteLine ("\t{0} handler removed in {1} for: {2}", d.Method.Name,instance, eventName);
+ #endif
+ }
+ }
+ }
+ }
+ internal static Delegate createDel(Type eventType, object instance, string method){
+ Type t = instance.GetType ();
+ MethodInfo mi = t.GetMethod (method);
+ if (mi == null)
+ return null;
+ return Delegate.CreateDelegate (eventType, instance, mi);
+ }
+ public static Delegate compileDynEventHandler(EventInfo sourceEvent, string expression, NodeAddress currentNode = null){
+ #if DEBUG_BINDING
+ Debug.WriteLine ("\tCompile Event {0}: {1}", sourceEvent.Name, expression);
+ #endif
- Type target_type = binding.Source.Instance.GetType ();
+ Type lopType = null;
+
+ if (currentNode == null)
+ lopType = sourceEvent.DeclaringType;
+ else
+ lopType = currentNode.NodeType;
#region Retrieve EventHandler parameter type
- MethodInfo evtInvoke = binding.Source.Event.EventHandlerType.GetMethod ("Invoke");
+ MethodInfo evtInvoke = sourceEvent.EventHandlerType.GetMethod ("Invoke");
ParameterInfo [] evtParams = evtInvoke.GetParameters ();
Type handlerArgsType = evtParams [1].ParameterType;
#endregion
- Type [] args = { typeof (object), typeof (object), handlerArgsType };
- DynamicMethod dm = new DynamicMethod (binding.CreateNewDynMethodId (),
- typeof (void),
- args,
- target_type);
-
-
- #region IL generation
+ Type [] args = { CompilerServices.TObject, handlerArgsType };
+ DynamicMethod dm = new DynamicMethod ("dyn_eventHandler",
+ typeof(void),
+ args, true);
ILGenerator il = dm.GetILGenerator (256);
+ il.Emit (OpCodes.Nop);
- string src = binding.Expression.Trim ();
-
- if (!(src.StartsWith ("{") || src.EndsWith ("}")))
- throw new Exception (string.Format ("GOML:Malformed {0} Event handler: {1}", binding.Source.Member.Name, binding.Expression));
-
- src = src.Substring (1, src.Length - 2);
- string [] srcLines = src.Split (new char [] { ';' });
+ string [] srcLines = expression.Trim ().Split (new char [] { ';' });
foreach (string srcLine in srcLines) {
string statement = srcLine.Trim ();
@@ -428,51 +590,59 @@ namespace Crow
string [] operandes = statement.Split (new char [] { '=' });
if (operandes.Length < 2) //not an affectation
{
+ //maybe we could handle here handler function name
continue;
}
- string lop = operandes [0].Trim ();
+
string rop = operandes [operandes.Length - 1].Trim ();
#region LEFT OPERANDES
- GraphicObject lopObj = binding.Source.Instance as GraphicObject; //default left operand base object is
- //the first arg (object sender) of the event handler
+ string [] lopParts = operandes [0].Trim ().Split ('/');
+ MemberInfo lopMI = null;
il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack
- string [] lopParts = lop.Split (new char [] { '.' });
- if (lopParts.Length > 1) {//should search also for member of es.Source
- for (int j = 0; j < lopParts.Length - 1; j++) {
- il.Emit (OpCodes.Ldstr, lopParts [j]);
- il.Emit (OpCodes.Callvirt, miFindByName);
- }
+ if (lopParts.Length > 1) {
+ NodeAddress lopNA = getNodeAdressFromBindingExp (currentNode, lopParts);
+ CompilerServices.emitGetInstance (il, currentNode, lopNA);
+ lopType = lopNA.NodeType;
}
- int i = lopParts.Length - 1;
+ string [] bindTrg = lopParts.Last().Split ('.');
+
+ if (bindTrg.Length == 1)
+ lopMI = lopType.GetMember (bindTrg [0]).FirstOrDefault();
+ else if (bindTrg.Length == 2) {
+ //named target
+ //TODO:
+ il.Emit(OpCodes.Ldstr, bindTrg[0]);
+ il.Emit(OpCodes.Callvirt, miFindByName);
+ lopMI = lopType.GetMember (bindTrg [1]).FirstOrDefault();
+ } else
+ throw new Exception ("Syntax error in binding, expected 'go dot member'");
- MemberInfo [] lopMbis = lopObj.GetType ().GetMember (lopParts [i]);
- if (lopMbis.Length < 1)
- throw new Exception (string.Format ("CROW BINDING: Member not found '{0}'", lop));
+ if (lopMI == null)
+ throw new Exception (string.Format ("IML BINDING: Member not found"));
- OpCode lopSetOC;
- dynamic lopSetMbi;
+ OpCode lopSetOpCode;
+ dynamic lopSetMI;
Type lopT = null;
- switch (lopMbis [0].MemberType) {
+ switch (lopMI.MemberType) {
case MemberTypes.Property:
- PropertyInfo lopPi = target_type.GetProperty (lopParts [i]);
- MethodInfo dstMi = lopPi.GetSetMethod ();
+ lopSetOpCode = OpCodes.Callvirt;
+ PropertyInfo lopPi = lopMI as PropertyInfo;
lopT = lopPi.PropertyType;
- lopSetMbi = dstMi;
- lopSetOC = OpCodes.Callvirt;
+ lopSetMI = lopPi.GetSetMethod ();
break;
case MemberTypes.Field:
- FieldInfo dstFi = target_type.GetField (lopParts [i]);
+ lopSetOpCode = OpCodes.Stfld;
+ FieldInfo dstFi = lopMI as FieldInfo;
lopT = dstFi.FieldType;
- lopSetMbi = dstFi;
- lopSetOC = OpCodes.Stfld;
+ lopSetMI = dstFi;
break;
default:
- throw new Exception (string.Format ("GOML:member type not handle: {0}", lopParts [i]));
+ throw new Exception (string.Format ("GOML:member type not handle"));
}
#endregion
@@ -501,108 +671,67 @@ namespace Crow
#endregion
//emit left operand assignment
- il.Emit (lopSetOC, lopSetMbi);
+ il.Emit (lopSetOpCode, lopSetMI);
}
il.Emit (OpCodes.Ret);
- #endregion
-
- Delegate del = dm.CreateDelegate (binding.Source.Event.EventHandlerType, binding.Source.Instance);
- MethodInfo addHandler = binding.Source.Event.GetAddMethod ();
- addHandler.Invoke (binding.Source.Instance, new object [] { del });
-
- binding.Resolved = true;
- }
-
- #region conversions
-
- internal static MethodInfo GetConvertMethod (Type targetType)
- {
- string name;
-
- if (targetType == typeof (bool))
- name = "ToBoolean";
- else if (targetType == typeof (byte))
- name = "ToByte";
- else if (targetType == typeof (short))
- name = "ToInt16";
- else if (targetType == typeof (int))
- name = "ToInt32";
- else if (targetType == typeof (long))
- name = "ToInt64";
- else if (targetType == typeof (double))
- name = "ToDouble";
- else if (targetType == typeof (float))
- name = "ToSingle";
- else if (targetType == typeof (string))
- return typeof (object).GetMethod ("ToString", Type.EmptyTypes);
- else //try to find implicit convertion
- throw new NotImplementedException (string.Format ("Conversion to {0} is not implemented.", targetType.Name));
-
- return typeof (Convert).GetMethod (name, BindingFlags.Static | BindingFlags.Public, null, new Type [] { typeof (object) }, null);
+ return dm.CreateDelegate (sourceEvent.EventHandlerType);
}
- #endregion
-
- /// <summary>
- /// retrieve event handler in class or ancestors
- /// </summary>
- public static FieldInfo GetEventHandlerField (Type type, string eventName)
- {
- FieldInfo fi;
- Type ty = type;
- do {
- fi = ty.GetField (eventName,
- BindingFlags.NonPublic |
- BindingFlags.Instance |
- BindingFlags.GetField);
- ty = ty.BaseType;
- if (ty == null)
+ public static string[] splitOnSemiColumnOutsideAccolades (string expression){
+ List<String> exps = new List<string>();
+ int accCount = 0;
+ int expPtr = 0;
+ for (int c = 0; c < expression.Length; c++) {
+ switch (expression[c]){
+ case '{':
+ accCount++;
break;
- } while (fi == null);
- return fi;
+ case '}':
+ accCount--;
+ break;
+ case ';':
+ if (accCount > 0)
+ break;
+ exps.Add(expression.Substring(expPtr, c - expPtr - 1));
+ expPtr = c + 1;
+ break;
+ }
+ }
+ if (exps.Count == 0)
+ exps.Add(expression);
+ return exps.ToArray ();
}
-
/// <summary>
- /// Gets extension methods defined in assembley for extendedType
+ /// Gets the node adress from binding expression splitted with '/' starting at a given node
/// </summary>
- /// <returns>Extension methods enumerable</returns>
- /// <param name="assembly">Assembly</param>
- /// <param name="extendedType">Extended type to search for</param>
- public static IEnumerable<MethodInfo> GetExtensionMethods (Assembly assembly,
- Type extendedType)
- {
- IEnumerable<MethodInfo> query = null;
- Type curType = extendedType;
-
- do {
- query = from type in assembly.GetTypes ()
- where type.IsSealed && !type.IsGenericType && !type.IsNested
- from method in type.GetMethods (BindingFlags.Static
- | BindingFlags.Public | BindingFlags.NonPublic)
- where method.IsDefined (typeof (ExtensionAttribute), false)
- where method.GetParameters () [0].ParameterType == curType
- select method;
+ public static NodeAddress getNodeAdressFromBindingExp(NodeAddress sourceAddr, string[] bindingExp){
+ int ptr = sourceAddr.Count - 1;
- if (query.Count () > 0)
- break;
-
- curType = curType.BaseType;
- } while (curType != null);
-
- return query;
+ //if exp start with '/' => Graphic tree parsing start at source
+ if (string.IsNullOrEmpty (bindingExp [0])) {
+ //TODO:
+ } else if (bindingExp [0] == ".") { //search template root
+ ptr--;
+ while (ptr >= 0) {
+ if (typeof(TemplatedControl).IsAssignableFrom (sourceAddr [ptr].CrowType))
+ break;
+ ptr--;
+ }
+ } else if (bindingExp [0] == "..") { //search starting at current node
+ int levelUp = bindingExp.Length - 1;
+ if (levelUp > ptr + 1)
+ throw new Exception ("Binding error: try to bind outside IML source");
+ ptr -= levelUp;
+ }
+ //TODO:change Template special address identified with Nodecount = 0 to something not using array count to 0,
+ //here linq is working without limits checking in compile option
+ //but defining a 0 capacity array with limits cheking enabled, cause 'out of memory' error
+ return new NodeAddress (sourceAddr.Take(ptr+1).ToArray());//[ptr+1];
+ //Array.Copy (sourceAddr.ToArray (), targetNode, ptr + 1);
+ //return new NodeAddress (targetNode);
}
- public static MethodInfo SearchExtMethod(Type t, string methodName){
- MethodInfo mi = null;
- mi = GetExtensionMethods (Assembly.GetEntryAssembly(), t)
- .Where (em => em.Name == methodName).FirstOrDefault ();
- if (mi != null)
- return mi;
-
- return GetExtensionMethods (Assembly.GetExecutingAssembly(), t)
- .Where (em => em.Name == methodName).FirstOrDefault ();
- }
}
}
diff --git a/src/Enums.cs b/src/Enums.cs
index aac12e16..46f8cdab 100644
--- a/src/Enums.cs
+++ b/src/Enums.cs
@@ -11,7 +11,7 @@ namespace Crow
Vertical
}
- public enum Alignment : byte
+ public enum Alignment
{
Top = 0x01,
Left = 0x02,
diff --git a/src/ExtensionsMethods.cs b/src/ExtensionsMethods.cs
index 2bfc36ea..5e58cdd5 100644
--- a/src/ExtensionsMethods.cs
+++ b/src/ExtensionsMethods.cs
@@ -114,18 +114,7 @@ namespace Crow
handler(sender, e);
}
}
- /// <summary>
- /// Type Extension method for Casting
- /// </summary>
- public static object Cast(this Type Type, object data)
- {
- var DataParam = Expression.Parameter(typeof(object), "data");
- var Body = Expression.Block(Expression.Convert(Expression.Convert(DataParam, data.GetType()), Type));
- var Run = Expression.Lambda(Body, DataParam).Compile();
- var ret = Run.DynamicInvoke(data);
- return ret;
- }
public static bool IsWhiteSpaceOrNewLine (this char c)
{
return c == '\t' || c == '\r' || c == '\n' || char.IsWhiteSpace (c);
diff --git a/src/GraphicObjects/Button.cs b/src/GraphicObjects/Button.cs
index 59762182..1cfbe85c 100644
--- a/src/GraphicObjects/Button.cs
+++ b/src/GraphicObjects/Button.cs
@@ -47,12 +47,6 @@ namespace Crow
#endregion
#region GraphicObject Overrides
- public override void ResolveBindings ()
- {
- base.ResolveBindings ();
- if (Content != null)
- Content.ResolveBindings ();
- }
public override void onMouseDown (object sender, MouseButtonEventArgs e)
{
IsPressed = true;
diff --git a/src/GraphicObjects/ColorPicker.cs b/src/GraphicObjects/ColorPicker.cs
new file mode 100644
index 00000000..cc8dfac3
--- /dev/null
+++ b/src/GraphicObjects/ColorPicker.cs
@@ -0,0 +1,223 @@
+//
+// ColorPicker.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ public class ColorPicker : TemplatedControl
+ {
+ public ColorPicker () : base ()
+ {
+ }
+
+ const double div = 255.0;
+ const double colDiv = 1.0 / div;
+
+ Color curColor;
+ double h,s,v;
+
+ [XmlAttributeAttribute()]
+ public virtual double R {
+ get { return Math.Round(curColor.R * div); }
+ set {
+ if (R == value)
+ return;
+ curColor.R = value * colDiv;
+ NotifyValueChanged ("R", R);
+ hsvFromRGB ();
+ notifyCurColorHasChanged ();
+ }
+ }
+ [XmlAttributeAttribute()]
+ public virtual double G {
+ get { return Math.Round(curColor.G * div); }
+ set {
+ if (G == value)
+ return;
+ curColor.G = value * colDiv;
+ NotifyValueChanged ("G", G);
+ notifyCurColorHasChanged ();
+ hsvFromRGB ();
+ }
+ }
+ [XmlAttributeAttribute()]
+ public virtual double B {
+ get { return Math.Round(curColor.B * div); }
+ set {
+ if (B == value)
+ return;
+ curColor.B = value * colDiv;
+ NotifyValueChanged ("B", B);
+ notifyCurColorHasChanged ();
+ hsvFromRGB ();
+ }
+ }
+ [XmlAttributeAttribute()]
+ public virtual double A {
+ get { return Math.Round(curColor.A * div); }
+ set {
+ if (A == value)
+ return;
+ curColor.A = value * colDiv;
+ NotifyValueChanged ("A", A);
+ notifyCurColorHasChanged ();
+ hsvFromRGB ();
+ }
+ }
+ [XmlAttributeAttribute()]
+ public virtual double H {
+ get { return Math.Round (h, 3); }
+ set {
+ if (H == value)
+ return;
+ h = value;
+ NotifyValueChanged ("H", H);
+ rgbFromHSV ();
+ }
+ }
+ [XmlAttributeAttribute()]
+ public virtual double S {
+ get { return Math.Round (s, 2); }
+ set {
+ if (s == value)
+ return;
+ s = value;
+ NotifyValueChanged ("S", S);
+ rgbFromHSV ();
+ }
+ }
+ [XmlAttributeAttribute()]
+ public virtual double V {
+ get { return Math.Round (v, 2); }
+ set {
+ if (v == value)
+ return;
+ v = value;
+ NotifyValueChanged ("V", V);
+ rgbFromHSV ();
+ }
+ }
+
+ [XmlAttributeAttribute]
+ public virtual Fill SelectedColor {
+ get { return new SolidColor(curColor); }
+ set {
+ Color c = (value as SolidColor).color;
+ if (curColor == c)
+ return;
+ curColor = c;
+ notifyCurColorHasChanged ();
+ notifyRGBAHasChanged ();
+ hsvFromRGB ();
+ }
+ }
+
+ void notifyCurColorHasChanged(){
+ NotifyValueChanged ("SelectedColor", SelectedColor);
+ string n = curColor.ToString ();
+ if (char.IsLetter(n[0]))
+ NotifyValueChanged ("SelectedColorName", n);
+ else
+ NotifyValueChanged ("SelectedColorName", "-");
+ NotifyValueChanged ("HexColor", ((int)R).ToString ("X2") + ((int)G).ToString ("X2") + ((int)B).ToString ("X2") + ((int)A).ToString ("X2"));
+ }
+ void notifyRGBAHasChanged(){
+ NotifyValueChanged ("R", R);
+ NotifyValueChanged ("G", G);
+ NotifyValueChanged ("B", B);
+ NotifyValueChanged ("A", A);
+ }
+ void notifyHSVHasChanged(){
+ NotifyValueChanged ("H", H);
+ NotifyValueChanged ("S", S);
+ NotifyValueChanged ("V", V);
+ }
+ void hsvFromRGB(){
+ Color c = curColor;
+ double min = Math.Min (c.R, Math.Min (c.G, c.B)); //Min. value of RGB
+ double max = Math.Max (c.R, Math.Max (c.G, c.B)); //Max. value of RGB
+ double diff = max - min; //Delta RGB value
+
+ v = max;
+
+ if ( diff == 0 )//This is a gray, no chroma...
+ {
+ h = 0;
+ s = 0;
+ }else{//Chromatic data...
+ s = diff / max;
+
+ double diffR = (((max - c.R) / 6.0) + (diff / 2.0)) / diff;
+ double diffG = (((max - c.G) / 6.0) + (diff / 2.0)) / diff;
+ double diffB = (((max - c.B) / 6.0) + (diff / 2.0)) / diff;
+
+ if (c.R == max)
+ h = diffB - diffG;
+ else if (c.G == max)
+ h = (1.0 / 3.0) + diffR - diffB;
+ else if (c.B == max)
+ h = (2.0 / 3.0) + diffG - diffR;
+
+ if (h < 0)
+ h += 1;
+ if (h > 1)
+ h -= 1;
+
+ }
+ notifyHSVHasChanged ();
+ }
+ void rgbFromHSV(){
+ Color c = Color.Black;
+
+ if (s == 0) {//HSV from 0 to 1
+ c.R = v;
+ c.G = v;
+ c.B = v;
+ }else{
+ double var_h = h * 6.0;
+
+ if (var_h == 6.0)
+ var_h = 0; //H must be < 1
+ double var_i = Math.Floor( var_h ); //Or ... var_i = floor( var_h )
+ double var_1 = v * ( 1.0 - s );
+ double var_2 = v * (1.0 - s * (var_h - var_i));
+ double var_3 = v * (1.0 - s * (1.0 - (var_h - var_i)));
+
+ if (var_i == 0.0) {
+ c.R = v;
+ c.G = var_3;
+ c.B = var_1;
+ }else if ( var_i == 1.0 ) { c.R = var_2 ; c.G = v ; c.B = var_1; }
+ else if ( var_i == 2 ) { c.R = var_1 ; c.G = v ; c.B = var_3; }
+ else if ( var_i == 3 ) { c.R = var_1 ; c.G = var_2 ; c.B = v; }
+ else if ( var_i == 4 ) { c.R = var_3 ; c.G = var_1 ; c.B = v; }
+ else { c.R = v ; c.G = var_1 ; c.B = var_2; }
+ }
+
+ curColor = c;
+ notifyCurColorHasChanged ();
+ notifyRGBAHasChanged ();
+ }
+ }
+}
+
diff --git a/src/GraphicObjects/ColorSelector.cs b/src/GraphicObjects/ColorSelector.cs
new file mode 100644
index 00000000..13a588ce
--- /dev/null
+++ b/src/GraphicObjects/ColorSelector.cs
@@ -0,0 +1,89 @@
+//
+// ColorPicker.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ public class ColorSelector : GraphicObject
+ {
+ public ColorSelector (): base()
+ {
+ }
+
+ const double div = 255.0;
+ const double colDiv = 1.0 / div;
+ protected Point mousePos;
+
+ public override void onMouseMove (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseMove (sender, e);
+ if (CurrentInterface.Mouse.LeftButton == ButtonState.Released)
+ return;
+ updateMouseLocalPos (e.Position);
+ }
+ public override void onMouseDown (object sender, MouseButtonEventArgs e)
+ {
+ base.onMouseDown (sender, e);
+ if (e.Button == MouseButton.Left)
+ updateMouseLocalPos (e.Position);
+ }
+
+ protected virtual void updateMouseLocalPos(Point mPos){
+ Rectangle r = ScreenCoordinates (Slot);
+ Rectangle cb = ClientRectangle;
+ mousePos = mPos - r.Position;
+
+ mousePos.X = Math.Max(cb.X, mousePos.X);
+ mousePos.X = Math.Min(cb.Right-1, mousePos.X);
+ mousePos.Y = Math.Max(cb.Y, mousePos.Y);
+ mousePos.Y = Math.Min(cb.Bottom-1, mousePos.Y);
+ }
+// virtual protected void updateColorFromPicking(bool redraw = true){
+// SelectedColor = new SolidColor(getPixelAt(mousePos.X, mousePos.Y));
+//
+// updateHSV ();
+//
+// NotifyValueChanged ("R", R);
+// NotifyValueChanged ("G", G);
+// NotifyValueChanged ("B", B);
+// NotifyValueChanged ("A", A);
+//
+// if (redraw)
+// RegisterForRedraw ();
+// }
+//
+// protected Color getPixelAt(int x, int y){
+// if (bmp == null)
+// return Color.Transparent;
+//
+// int ptr = y * Slot.Width * 4 + x * 4;
+//
+// return new Color(
+// (double)bmp[ptr + 2] * colDiv,
+// (double)bmp[ptr + 1] * colDiv,
+// (double)bmp[ptr] * colDiv,
+// (double)bmp[ptr + 3] * colDiv);
+// }
+ }
+}
+
diff --git a/src/GraphicObjects/DataSourceChangeEventArgs.cs b/src/GraphicObjects/DataSourceChangeEventArgs.cs
new file mode 100644
index 00000000..56d44428
--- /dev/null
+++ b/src/GraphicObjects/DataSourceChangeEventArgs.cs
@@ -0,0 +1,41 @@
+//
+// DataSourceChangeEventArg.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+
+namespace Crow
+{
+ public class DataSourceChangeEventArgs : EventArgs
+ {
+ public object OldDataSource;
+ public object NewDataSource;
+
+ public DataSourceChangeEventArgs (object oldDataSource, object newDataSource) : base()
+ {
+ OldDataSource = oldDataSource;
+ NewDataSource = newDataSource;
+ }
+ public override string ToString ()
+ {
+ return string.Format ("DSChangeEA: {0} => {1}", OldDataSource, NewDataSource);
+ }
+ }
+}
+
diff --git a/src/GraphicObjects/DirectoryView.cs b/src/GraphicObjects/DirectoryView.cs
index 4e29621e..5ed46f3e 100644
--- a/src/GraphicObjects/DirectoryView.cs
+++ b/src/GraphicObjects/DirectoryView.cs
@@ -52,7 +52,7 @@ namespace Crow
NotifyValueChanged ("SelectedItem", _selectedItem);
}
}
- [XmlAttributeAttribute()][DefaultValue(false)]
+ [XmlAttributeAttribute()][DefaultValue(true)]
public virtual bool ShowFiles {
get { return showFiles; }
set {
@@ -76,8 +76,10 @@ namespace Crow
}
[XmlIgnore]public FileSystemInfo[] FileSystemEntries {
get {
- return showFiles ? new DirectoryInfo (CurrentDirectory).GetFileSystemInfos ():
- new DirectoryInfo(currentDirectory).GetDirectories();
+ return string.IsNullOrEmpty(CurrentDirectory) ? null :
+ showFiles ?
+ new DirectoryInfo (CurrentDirectory).GetFileSystemInfos () :
+ new DirectoryInfo(CurrentDirectory).GetDirectories();
}
}
public void onSelectedItemChanged (object sender, SelectionChangeEventArgs e){
diff --git a/src/GraphicObjects/Expandable.cs b/src/GraphicObjects/Expandable.cs
index 70451f41..38506de8 100644
--- a/src/GraphicObjects/Expandable.cs
+++ b/src/GraphicObjects/Expandable.cs
@@ -45,14 +45,12 @@ namespace Crow
public event EventHandler Collapse;
#endregion
- #region GraphicObject overrides
- public override void onMouseClick (object sender, MouseButtonEventArgs e)
+ public BooleanTestOnInstance GetIsExpandable;
+
+ public void onClickForExpand (object sender, MouseButtonEventArgs e)
{
- if (this.HasFocus)
- IsExpanded = !IsExpanded;
- base.onMouseClick (sender, e);
+ IsExpanded = !IsExpanded;
}
- #endregion
public override GraphicObject Content {
get {
@@ -70,15 +68,9 @@ namespace Crow
_contentContainer = this.child.FindByName ("Content") as Container;
}
- public override void ResolveBindings ()
- {
- base.ResolveBindings ();
- if (Content != null)
- Content.ResolveBindings ();
- }
#region Public properties
- [XmlAttributeAttribute()][DefaultValue("Expandable")]
+ [XmlAttributeAttribute][DefaultValue("Expandable")]
public string Caption {
get { return caption; }
set {
@@ -88,7 +80,7 @@ namespace Crow
NotifyValueChanged ("Caption", caption);
}
}
- [XmlAttributeAttribute()][DefaultValue("#Crow.Images.Icons.expandable.svg")]
+ [XmlAttributeAttribute][DefaultValue("#Crow.Images.Icons.expandable.svg")]
public string Image {
get { return image; }
set {
@@ -98,7 +90,7 @@ namespace Crow
NotifyValueChanged ("Image", image);
}
}
- [XmlAttributeAttribute()][DefaultValue(false)]
+ [XmlAttributeAttribute][DefaultValue(false)]
public bool IsExpanded
{
get { return _isExpanded; }
@@ -109,7 +101,9 @@ namespace Crow
_isExpanded = value;
- if (!HasContent)
+ bool isExp = IsExpandable;
+ NotifyValueChanged ("IsExpandable", isExp);
+ if (!(HasContent & isExp))
_isExpanded = false;
NotifyValueChanged ("IsExpanded", _isExpanded);
@@ -123,7 +117,16 @@ namespace Crow
[XmlIgnore]public bool HasContent {
get { return _contentContainer == null ? false : _contentContainer.Child != null; }
}
-
+ [XmlIgnore]public bool IsExpandable {
+ get {
+ try {
+ return GetIsExpandable == null ? true : GetIsExpandable (this);
+ } catch (Exception ex) {
+ System.Diagnostics.Debug.WriteLine ("Not Expandable error: " + ex.ToString ());
+ return false;
+ }
+ }
+ }
#endregion
public virtual void onExpand(object sender, EventArgs e)
diff --git a/src/GraphicObjects/FileDialog.cs b/src/GraphicObjects/FileDialog.cs
index 16a60a4f..543b27cc 100644
--- a/src/GraphicObjects/FileDialog.cs
+++ b/src/GraphicObjects/FileDialog.cs
@@ -29,112 +29,103 @@ using System.Text.RegularExpressions;
namespace Crow
{
- public class FileDialog: IValueChange
+ public class FileDialog: Window
{
- #region IValueChange implementation
- public event EventHandler<ValueChangeEventArgs> ValueChanged;
- public virtual void NotifyValueChanged(string MemberName, object _value)
- {
- ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value));
- }
- #endregion
-
- Window window;
- DirectoryInfo currentDir;
- FileInfo selectedFile;
- string searchPattern = "*";
+ string searchPattern, curDirectory;
#region CTOR
- public FileDialog ()
+ public FileDialog () : base()
{
- currentDir = new DirectoryInfo (Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
- //window = Interface..Load("#Crow.Templates.FileDialog.goml") as Window;
- window.DataSource = this;
}
#endregion
-
- public string CurrentPath {
- get { return currentDir.FullName; }
+ //[DefaultValue(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments))]
+ [XmlAttributeAttribute][DefaultValue("/home")]
+ public virtual string CurrentDirectory {
+ get { return curDirectory; }
set {
- currentDir = new DirectoryInfo (value);
- NotifyValueChanged ("CurrentPath", CurrentPath);
+ if (curDirectory == value)
+ return;
+ curDirectory = value;
+ NotifyValueChanged ("CurrentDirectory", curDirectory);
+
}
- }
- public string SearchPattern {
+ }
+
+ [XmlAttributeAttribute()][DefaultValue("*")]
+ public virtual string SearchPattern {
get { return searchPattern; }
set {
- searchPattern = value;
- NotifyValueChanged ("Files", Files);
- }
- }
+ if (searchPattern == value)
+ return;
+ searchPattern = value;
+ NotifyValueChanged ("SearchPattern", searchPattern);
- public DirectoryInfo[] Directories
- {
- get {
- //currentDir.GetDirectories
- List<DirectoryInfo> tmp = currentDir.GetDirectories ().Where(fi => !fi.Attributes.HasFlag(FileAttributes.Hidden)).ToList();
- if (currentDir.Parent != null)
- tmp.Insert (0, currentDir.Parent);
- return tmp.ToArray ();
}
- }
- public FileInfo[] Files
- {
- get {
- string[] exts = searchPattern.Replace("*","").Split ('|');
- //return currentDir.GetFiles (searchPattern).Where(fi => !fi.Attributes.HasFlag(FileAttributes.Hidden)).ToArray();
- return currentDir.GetFiles().Where(f => exts.Any
- (x => f.Name.EndsWith (x, StringComparison.InvariantCultureIgnoreCase))).ToArray();
- }
- }
-
- public void Show(){
- //.AddWidget(window);
- }
-
- void OnSelectedItemChanged (object sender, SelectionChangeEventArgs e)
- {
- currentDir = e.NewValue as DirectoryInfo;
- NotifyValueChanged ("CurrentPath", CurrentPath);
- NotifyValueChanged ("Directories", Directories);
- NotifyValueChanged ("Files", Files);
-
- }
- void onFileListItemChanged (object sender, SelectionChangeEventArgs e)
- {
- selectedFile = e.NewValue as FileInfo;
- }
- void onFileSelect(object sender, MouseButtonEventArgs e){
- //OpenTKGameWindow.currentWindow.DeleteWidget(window);
- }
- }
- public class DirContainer: IValueChange
- {
- #region IValueChange implementation
- public event EventHandler<ValueChangeEventArgs> ValueChanged;
- public void NotifyValueChanged(string name, object value)
- {
- ValueChanged.Raise (this, new ValueChangeEventArgs (name, value));
- }
- #endregion
+ }
- public DirectoryInfo CurDir;
- public DirContainer(DirectoryInfo _dir){
- CurDir = _dir;
- }
- public string Name {
- get { return CurDir.Name; }
- }
-
- void onDirUp(object sender, MouseButtonEventArgs e)
- {
-
- }
- public void onMouseDown(object sender, MouseButtonEventArgs e)
- {
- Debug.WriteLine (sender.ToString ());
- }
+// public DirectoryInfo[] Directories
+// {
+// get {
+// //currentDir.GetDirectories
+// List<DirectoryInfo> tmp = currentDir.GetDirectories ().Where(fi => !fi.Attributes.HasFlag(FileAttributes.Hidden)).ToList();
+// if (currentDir.Parent != null)
+// tmp.Insert (0, currentDir.Parent);
+// return tmp.ToArray ();
+// }
+// }
+// public FileInfo[] Files
+// {
+// get {
+// string[] exts = searchPattern.Replace("*","").Split ('|');
+// //return currentDir.GetFiles (searchPattern).Where(fi => !fi.Attributes.HasFlag(FileAttributes.Hidden)).ToArray();
+// return currentDir.GetFiles().Where(f => exts.Any
+// (x => f.Name.EndsWith (x, StringComparison.InvariantCultureIgnoreCase))).ToArray();
+// }
+// }
+// void OnSelectedItemChanged (object sender, SelectionChangeEventArgs e)
+// {
+// currentDir = e.NewValue as DirectoryInfo;
+// NotifyValueChanged ("CurrentPath", CurrentPath);
+// NotifyValueChanged ("Directories", Directories);
+// NotifyValueChanged ("Files", Files);
+//
+// }
+// void onFileListItemChanged (object sender, SelectionChangeEventArgs e)
+// {
+// selectedFile = e.NewValue as FileInfo;
+// }
+// void onFileSelect(object sender, MouseButtonEventArgs e){
+// //OpenTKGameWindow.currentWindow.DeleteWidget(window);
+// }
}
+// public class DirContainer: IValueChange
+// {
+// #region IValueChange implementation
+// public event EventHandler<ValueChangeEventArgs> ValueChanged;
+// public void NotifyValueChanged(string name, object value)
+// {
+// ValueChanged.Raise (this, new ValueChangeEventArgs (name, value));
+// }
+// #endregion
+//
+// public DirectoryInfo CurDir;
+// public DirContainer(DirectoryInfo _dir){
+// CurDir = _dir;
+// }
+// public string Name {
+// get { return CurDir.Name; }
+// }
+//
+// void onDirUp(object sender, MouseButtonEventArgs e)
+// {
+//
+// }
+// public void onMouseDown(object sender, MouseButtonEventArgs e)
+// {
+// Debug.WriteLine (sender.ToString ());
+// }
+//
+// }
}
diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs
index e69aaaca..e5313ea2 100644
--- a/src/GraphicObjects/GraphicObject.cs
+++ b/src/GraphicObjects/GraphicObject.cs
@@ -12,22 +12,14 @@ using System.IO;
namespace Crow
{
- public class GraphicObject : IXmlSerializable, ILayoutable, IValueChange, ICloneable, IBindable
+ public class GraphicObject : IXmlSerializable, ILayoutable, IValueChange, ICloneable
{
- #region IBindable implementation
- List<Binding> bindings = new List<Binding> ();
- public List<Binding> Bindings {
- get { return bindings; }
- }
-
- #endregion
-
internal static ulong currentUid = 0;
internal ulong uid = 0;
Interface currentInterface = null;
- public Interface CurrentInterface {
+ [XmlIgnore]public Interface CurrentInterface {
get {
if (currentInterface == null) {
currentInterface = Interface.CurrentInterface;
@@ -47,6 +39,7 @@ namespace Crow
public event EventHandler<ValueChangeEventArgs> ValueChanged;
public virtual void NotifyValueChanged(string MemberName, object _value)
{
+ //Debug.WriteLine ("Value changed: {0}->{1} = {2}", this, MemberName, _value);
ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value));
}
#endregion
@@ -87,7 +80,7 @@ namespace Crow
Size minimumSize = "0,0";
bool cacheEnabled = false;
bool clipToClientRect = true;
- object dataSource;
+ protected object dataSource;
string style;
#endregion
@@ -132,11 +125,29 @@ namespace Crow
/// </summary>
[XmlIgnore]public virtual ILayoutable Parent {
get { return parent; }
- set { parent = value; }
+ set {
+ if (parent == value)
+ return;
+ DataSourceChangeEventArgs e = new DataSourceChangeEventArgs (parent, value);
+ parent = value;
+
+ onParentChanged (this, e);
+ }
}
[XmlIgnore]public ILayoutable LogicalParent {
get { return logicalParent == null ? Parent : logicalParent; }
- set { logicalParent = value; }
+ set {
+ if (logicalParent == value)
+ return;
+ if (logicalParent != null)
+ (logicalParent as GraphicObject).DataSourceChanged -= onLogicalParentDataSourceChanged;
+ DataSourceChangeEventArgs dsce = new DataSourceChangeEventArgs (LogicalParent, null);
+ logicalParent = value;
+ dsce.NewDataSource = LogicalParent;
+ if (logicalParent != null)
+ (logicalParent as GraphicObject).DataSourceChanged += onLogicalParentDataSourceChanged;
+ onLogicalParentChanged (this, dsce);
+ }
}
[XmlIgnore]public virtual Rectangle ClientRectangle {
get {
@@ -177,6 +188,9 @@ namespace Crow
public event EventHandler Enabled;
public event EventHandler Disabled;
public event EventHandler<LayoutingEventArgs> LayoutChanged;
+ public event EventHandler<DataSourceChangeEventArgs> DataSourceChanged;
+ public event EventHandler<DataSourceChangeEventArgs> ParentChanged;
+ public event EventHandler<DataSourceChangeEventArgs> LogicalParentChanged;
#endregion
#region public properties
@@ -226,6 +240,7 @@ namespace Crow
verticalAlignment = value;
NotifyValueChanged("VerticalAlignment", verticalAlignment);
+ RegisterForLayouting (LayoutingType.Y);
}
}
[XmlAttributeAttribute()][DefaultValue(HorizontalAlignment.Center)]
@@ -237,6 +252,7 @@ namespace Crow
horizontalAlignment = value;
NotifyValueChanged("HorizontalAlignment", horizontalAlignment);
+ RegisterForLayouting (LayoutingType.X);
}
}
[XmlAttributeAttribute()][DefaultValue(0)]
@@ -373,6 +389,10 @@ namespace Crow
return;
hasFocus = value;
+ if (hasFocus)
+ onFocused (this, null);
+ else
+ onUnfocused (this, null);
NotifyValueChanged ("HasFocus", hasFocus);
}
}
@@ -402,6 +422,8 @@ namespace Crow
set {
if (background == value)
return;
+ if (value == null)
+ return;
background = value;
NotifyValueChanged ("Background", background);
RegisterForRedraw ();
@@ -523,32 +545,45 @@ namespace Crow
RegisterForLayouting (LayoutingType.Sizing);
}
}
+ /// <summary>
+ /// Seek first logical tree upward if logicalParent is set, or seek graphic tree for
+ /// a not null dataSource that will be active for all descendants having dataSource=null
+ /// </summary>
[XmlAttributeAttribute][DefaultValue(null)]
public virtual object DataSource {
set {
- if (dataSource == value)
+ if (DataSource == value)
return;
- #if DEBUG_BINDING
- Debug.WriteLine("******************************");
- Debug.WriteLine("New DataSource for => " + this.ToString());
- Debug.WriteLine("\t- " + DataSource);
- Debug.WriteLine("\t+ " + value);
- #endif
-
- this.ClearBinding ();
+ DataSourceChangeEventArgs dse = new DataSourceChangeEventArgs (DataSource, null);
dataSource = value;
+ dse.NewDataSource = DataSource;
- this.ResolveBindings();
+ OnDataSourceChanged (this, dse);
- NotifyValueChanged ("DataSource", dataSource);
+ NotifyValueChanged ("DataSource", DataSource);
}
get {
- return dataSource == null ? LogicalParent == null ? null :
- LogicalParent is GraphicObject ?
- (LogicalParent as GraphicObject).DataSource : null : dataSource;
+ return dataSource == null ?
+ LogicalParent == null ? null :
+ LogicalParent is GraphicObject ? (LogicalParent as GraphicObject).DataSource : null :
+ dataSource;
}
}
+ protected virtual void onLogicalParentDataSourceChanged(object sender, DataSourceChangeEventArgs e){
+ if (localDataSourceIsNull)
+ OnDataSourceChanged (this, e);
+ }
+ internal bool localDataSourceIsNull { get { return dataSource == null; } }
+ internal bool localLogicalParentIsNull { get { return logicalParent == null; } }
+
+ public virtual void OnDataSourceChanged(object sender, DataSourceChangeEventArgs e){
+ DataSourceChanged.Raise (this, e);
+ #if DEBUG_BINDING
+ Debug.WriteLine("New DataSource for => {0} \n\t{1}=>{2}", this.ToString(),e.OldDataSource,e.NewDataSource);
+ #endif
+ }
+
[XmlAttributeAttribute]
public virtual string Style {
get { return style; }
@@ -630,10 +665,10 @@ namespace Crow
dm = new DynamicMethod("dyn_loadDefValues",
MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
CallingConventions.Standard,
- typeof(void),new Type[] {typeof(object)},thisType,true);
+ typeof(void),new Type[] {CompilerServices.TObject},thisType,true);
il = dm.GetILGenerator(256);
- il.DeclareLocal(typeof(GraphicObject));
+ il.DeclareLocal(CompilerServices.TObject);
il.Emit(OpCodes.Nop);
//set local GraphicObject to root object passed as 1st argument
il.Emit (OpCodes.Ldarg_0);
@@ -643,7 +678,26 @@ namespace Crow
string expression;
if (!getDefaultEvent(ei, styling, out expression))
continue;
- CompilerServices.emitBindingCreation (il, ei.Name, expression);
+ //TODO:dynEventHandler could be cached somewhere, maybe a style instanciato class holding the styling delegate and bound to it.
+ foreach (string exp in CompilerServices.splitOnSemiColumnOutsideAccolades(expression)) {
+ string trimed = exp.Trim();
+ if (trimed.StartsWith ("{", StringComparison.OrdinalIgnoreCase)){
+ il.Emit (OpCodes.Ldloc_0);//load this as 1st arg of event Add
+
+ //push eventInfo as 1st arg of compile
+ il.Emit (OpCodes.Ldloc_0);
+ il.Emit (OpCodes.Call, CompilerServices.miGetType);
+ il.Emit (OpCodes.Ldstr, ei.Name);//push event name
+ il.Emit (OpCodes.Call, CompilerServices.miGetEvent);
+ //push expression as 2nd arg of compile
+ il.Emit (OpCodes.Ldstr, trimed.Substring (1, trimed.Length - 2));
+ il.Emit (OpCodes.Ldnull);
+ il.Emit (OpCodes.Callvirt, CompilerServices.miCompileDynEventHandler);
+ il.Emit (OpCodes.Castclass, ei.EventHandlerType);
+ il.Emit (OpCodes.Callvirt, ei.AddMethod);
+ }else
+ Debug.WriteLine("error in styling, event not handled : " + trimed);
+ }
}
foreach (PropertyInfo pi in thisType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) {
@@ -1030,9 +1084,6 @@ namespace Crow
/// of the widget </summary>
public virtual void Paint (ref Context ctx)
{
- if (!Visible)
- return;
-
//TODO:this test should not be necessary
if (Slot.Height < 0 || Slot.Width < 0)
return;
@@ -1120,6 +1171,12 @@ namespace Crow
MouseMove.Raise (sender, e);
}
public virtual void onMouseDown(object sender, MouseButtonEventArgs e){
+ if (CurrentInterface.eligibleForDoubleClick == this && CurrentInterface.clickTimer.ElapsedMilliseconds < Interface.DoubleClick)
+ onMouseDoubleClick (this, e);
+ else
+ currentInterface.clickTimer.Restart();
+ CurrentInterface.eligibleForDoubleClick = null;
+
if (CurrentInterface.activeWidget == null)
CurrentInterface.activeWidget = this;
if (this.Focusable && !Interface.FocusOnHover) {
@@ -1144,19 +1201,13 @@ namespace Crow
MouseUp.Raise (this, e);
- if (MouseIsIn (e.Position) && IsActive)
+ if (MouseIsIn (e.Position) && IsActive) {
+ if (CurrentInterface.clickTimer.ElapsedMilliseconds < Interface.DoubleClick)
+ CurrentInterface.eligibleForDoubleClick = this;
onMouseClick (this, e);
+ }
}
public virtual void onMouseClick(object sender, MouseButtonEventArgs e){
-
- if (Interface.clickTimer.ElapsedMilliseconds > 0 &&
- Interface.clickTimer.ElapsedMilliseconds < Interface.DoubleClick) {
- Interface.clickTimer.Reset ();
- onMouseDoubleClick (this, e);
- return;
- } else
- Interface.clickTimer.Restart ();
-
GraphicObject p = Parent as GraphicObject;
if (p != null)
p.onMouseClick(sender,e);
@@ -1191,20 +1242,17 @@ namespace Crow
}
#endregion
- public virtual void onFocused(object sender, EventArgs e){
+ protected virtual void onFocused(object sender, EventArgs e){
#if DEBUG_FOCUS
Debug.WriteLine("Focused => " + this.ToString());
#endif
Focused.Raise (this, e);
- this.HasFocus = true;
}
- public virtual void onUnfocused(object sender, EventArgs e){
+ protected virtual void onUnfocused(object sender, EventArgs e){
#if DEBUG_FOCUS
Debug.WriteLine("UnFocused => " + this.ToString());
#endif
-
Unfocused.Raise (this, e);
- this.HasFocus = false;
}
public virtual void onEnable(object sender, EventArgs e){
Enabled.Raise (this, e);
@@ -1212,147 +1260,73 @@ namespace Crow
public virtual void onDisable(object sender, EventArgs e){
Disabled.Raise (this, e);
}
-
- #region Binding
- public void BindMember(string _member, string _expression){
- Bindings.Add(new Binding (this, _member, _expression));
+ protected virtual void onParentChanged(object sender, DataSourceChangeEventArgs e) {
+ ParentChanged.Raise (this, e);
+ if (logicalParent == null)
+ LogicalParentChanged.Raise (this, e);
}
- public virtual void ResolveBindings()
- {
- if (Bindings.Count == 0)
- return;
- #if DEBUG_BINDING
- Debug.WriteLine ("Resolve Bindings => " + this.ToString ());
- #endif
-
- CompilerServices.ResolveBindings (Bindings);
+ protected virtual void onLogicalParentChanged(object sender, DataSourceChangeEventArgs e) {
+ LogicalParentChanged.Raise (this, e);
}
-
- /// <summary>
- /// Remove dynamic delegates by ids from dataSource
- /// and delete ref of this in Shared interface refs
- /// </summary>
- public virtual void ClearBinding(){
- //dont clear binding if dataSource is not null,
- foreach (Binding b in Bindings) {
- try {
- if (!b.Resolved)
- continue;
- //cancel compiled events
- if (b.Target == null){
- continue;
- #if DEBUG_BINDING
- Debug.WriteLine("Clear binding canceled for => " + b.ToString());
- #endif
- }
- if (b.Target.Instance != DataSource){
- #if DEBUG_BINDING
- Debug.WriteLine("Clear binding canceled for => " + b.ToString());
- #endif
- continue;
- }
- #if DEBUG_BINDING
- Debug.WriteLine("ClearBinding => " + b.ToString());
- #endif
- if (string.IsNullOrEmpty (b.DynMethodId)) {
- b.Resolved = false;
- if (b.Source.Member.MemberType == MemberTypes.Event)
- removeEventHandler (b);
- //TODO:check if full reset is necessary
- continue;
- }
- MemberReference mr = null;
- if (b.Target == null)
- mr = b.Source;
- else
- mr = b.Target;
- Type dataSourceType = mr.Instance.GetType();
- EventInfo evtInfo = dataSourceType.GetEvent ("ValueChanged");
- FieldInfo evtFi = CompilerServices.GetEventHandlerField (dataSourceType, "ValueChanged");
- MulticastDelegate multicastDelegate = evtFi.GetValue (mr.Instance) as MulticastDelegate;
- if (multicastDelegate != null) {
- foreach (Delegate d in multicastDelegate.GetInvocationList()) {
- if (d.Method.Name == b.DynMethodId)
- evtInfo.RemoveEventHandler (mr.Instance, d);
- }
- }
- b.Reset ();
- } catch (Exception ex) {
- Debug.WriteLine("\t Error: " + ex.ToString());
- }
- }
- }
- void removeEventHandler(Binding b){
- FieldInfo fiEvt = CompilerServices.GetEventHandlerField (b.Source.Instance.GetType(), b.Source.Member.Name);
- MulticastDelegate multiDel = fiEvt.GetValue (b.Source.Instance) as MulticastDelegate;
- if (multiDel != null) {
- foreach (Delegate d in multiDel.GetInvocationList()) {
- if (d.Method.Name == b.Target.Member.Name)
- b.Source.Event.RemoveEventHandler (b.Source.Instance, d);
- }
- }
- }
- #endregion
-
#region IXmlSerializable
public virtual System.Xml.Schema.XmlSchema GetSchema ()
{
return null;
}
- void affectMember(string name, string value){
- Type thisType = this.GetType ();
-
- if (string.IsNullOrEmpty (value))
- return;
-
- MemberInfo mi = thisType.GetMember (name).FirstOrDefault();
- if (mi == null) {
- Debug.WriteLine ("XML: Unknown attribute in " + thisType.ToString() + " : " + name);
- return;
- }
- if (mi.MemberType == MemberTypes.Event) {
- this.Bindings.Add (new Binding (new MemberReference(this, mi), value));
- return;
- }
- if (mi.MemberType == MemberTypes.Property) {
- PropertyInfo pi = mi as PropertyInfo;
-
- if (pi.GetSetMethod () == null) {
- Debug.WriteLine ("XML: Read only property in " + thisType.ToString() + " : " + name);
- return;
- }
-
- XmlAttributeAttribute xaa = (XmlAttributeAttribute)pi.GetCustomAttribute (typeof(XmlAttributeAttribute));
- if (xaa != null) {
- if (!string.IsNullOrEmpty (xaa.AttributeName))
- name = xaa.AttributeName;
- }
- if (value.StartsWith("{",StringComparison.Ordinal)) {
- //binding
- if (!value.EndsWith("}", StringComparison.Ordinal))
- throw new Exception (string.Format("XML:Malformed binding: {0}", value));
-
- this.Bindings.Add (new Binding (new MemberReference(this, pi), value.Substring (1, value.Length - 2)));
- return;
- }
- if (pi.GetCustomAttribute (typeof(XmlIgnoreAttribute)) != null)
- return;
- if (xaa == null)//not define as xmlAttribute
- return;
-
- if (pi.PropertyType == typeof(string)) {
- pi.SetValue (this, value, null);
- return;
- }
-
- if (pi.PropertyType.IsEnum) {
- pi.SetValue (this, Enum.Parse (pi.PropertyType, value), null);
- } else {
- MethodInfo me = pi.PropertyType.GetMethod ("Parse", new Type[] { typeof(string) });
- pi.SetValue (this, me.Invoke (null, new string[] { value }), null);
- }
- }
- }
+// void affectMember(string name, string value){
+// Type thisType = this.GetType ();
+//
+// if (string.IsNullOrEmpty (value))
+// return;
+//
+// MemberInfo mi = thisType.GetMember (name).FirstOrDefault();
+// if (mi == null) {
+// Debug.WriteLine ("XML: Unknown attribute in " + thisType.ToString() + " : " + name);
+// return;
+// }
+// if (mi.MemberType == MemberTypes.Event) {
+// this.Bindings.Add (new Binding (new MemberReference(this, mi), value));
+// return;
+// }
+// if (mi.MemberType == MemberTypes.Property) {
+// PropertyInfo pi = mi as PropertyInfo;
+//
+// if (pi.GetSetMethod () == null) {
+// Debug.WriteLine ("XML: Read only property in " + thisType.ToString() + " : " + name);
+// return;
+// }
+//
+// XmlAttributeAttribute xaa = (XmlAttributeAttribute)pi.GetCustomAttribute (typeof(XmlAttributeAttribute));
+// if (xaa != null) {
+// if (!string.IsNullOrEmpty (xaa.AttributeName))
+// name = xaa.AttributeName;
+// }
+// if (value.StartsWith("{",StringComparison.Ordinal)) {
+// //binding
+// if (!value.EndsWith("}", StringComparison.Ordinal))
+// throw new Exception (string.Format("XML:Malformed binding: {0}", value));
+//
+// this.Bindings.Add (new Binding (new MemberReference(this, pi), value.Substring (1, value.Length - 2)));
+// return;
+// }
+// if (pi.GetCustomAttribute (typeof(XmlIgnoreAttribute)) != null)
+// return;
+// if (xaa == null)//not define as xmlAttribute
+// return;
+//
+// if (pi.PropertyType == typeof(string)) {
+// pi.SetValue (this, value, null);
+// return;
+// }
+//
+// if (pi.PropertyType.IsEnum) {
+// pi.SetValue (this, Enum.Parse (pi.PropertyType, value), null);
+// } else {
+// MethodInfo me = pi.PropertyType.GetMethod ("Parse", new Type[] { typeof(string) });
+// pi.SetValue (this, me.Invoke (null, new string[] { value }), null);
+// }
+// }
+// }
public virtual void ReadXml (System.Xml.XmlReader reader)
{
if (reader.HasAttributes) {
@@ -1365,7 +1339,7 @@ namespace Crow
if (reader.Name == "Style")
continue;
- affectMember (reader.Name, reader.Value);
+ //affectMember (reader.Name, reader.Value);
}
reader.MoveToElement ();
}else
@@ -1483,12 +1457,6 @@ namespace Crow
/// <summary>
/// full GraphicTree clone with binding definition
/// </summary>
- public virtual GraphicObject DeepClone(){
- GraphicObject tmp = Clone () as GraphicObject;
- foreach (Binding b in this.bindings)
- tmp.Bindings.Add (new Binding (new MemberReference (tmp, b.Source.Member), b.Expression));
- return tmp;
- }
public override string ToString ()
{
diff --git a/src/GraphicObjects/Group.cs b/src/GraphicObjects/Group.cs
index efe02d95..a285e282 100644
--- a/src/GraphicObjects/Group.cs
+++ b/src/GraphicObjects/Group.cs
@@ -40,7 +40,6 @@ namespace Crow
lock (children)
Children.Add(g);
g.Parent = this;
- g.ResolveBindings ();
g.RegisteredLayoutings = LayoutingType.None;
g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
g.LayoutChanged += OnChildLayoutChanges;
@@ -48,7 +47,6 @@ namespace Crow
public virtual void RemoveChild(GraphicObject child)
{
child.LayoutChanged -= OnChildLayoutChanges;
- child.ClearBinding ();
//child.Parent = null;
lock (children)
Children.Remove(child);
@@ -65,7 +63,6 @@ namespace Crow
while(Children.Count > 0){
GraphicObject g = Children[Children.Count-1];
g.LayoutChanged -= OnChildLayoutChanges;
- g.ClearBinding ();
g.Parent = null;
Children.RemoveAt(Children.Count-1);
}
@@ -94,11 +91,12 @@ namespace Crow
}
#region GraphicObject overrides
- public override void ResolveBindings ()
+ public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
{
- base.ResolveBindings ();
- foreach (GraphicObject w in Children)
- w.ResolveBindings ();
+ base.OnDataSourceChanged (this, e);
+ foreach (GraphicObject g in children)
+ if (g.localDataSourceIsNull & g.localLogicalParentIsNull)
+ g.OnDataSourceChanged (sender, e);
}
public override GraphicObject FindByName (string nameToFind)
{
@@ -365,17 +363,5 @@ namespace Crow
#endregion
- public override void ClearBinding(){
- foreach (GraphicObject c in Children)
- c.ClearBinding ();
- base.ClearBinding ();
- }
- public override GraphicObject DeepClone ()
- {
- Group tmp = base.DeepClone () as Group;
- foreach (GraphicObject c in Children)
- tmp.AddChild (c.DeepClone ());
- return tmp;
- }
}
}
diff --git a/src/GraphicObjects/HueSelector.cs b/src/GraphicObjects/HueSelector.cs
new file mode 100644
index 00000000..ec0a6f2c
--- /dev/null
+++ b/src/GraphicObjects/HueSelector.cs
@@ -0,0 +1,143 @@
+//
+// HueSelector.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Xml.Serialization;
+using System.ComponentModel;
+using Cairo;
+
+namespace Crow
+{
+ public class HueSelector : ColorSelector
+ {
+ public HueSelector () : base()
+ {
+ }
+
+ Orientation _orientation;
+ double hue;
+
+ [XmlAttributeAttribute][DefaultValue(Orientation.Horizontal)]
+ public virtual Orientation Orientation
+ {
+ get { return _orientation; }
+ set {
+ if (_orientation == value)
+ return;
+ _orientation = value;
+ NotifyValueChanged ("Orientation", _orientation);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ [XmlAttributeAttribute()]
+ public virtual double Hue {
+ get { return hue; }
+ set {
+ if (hue == value)
+ return;
+ hue = value;
+
+ notifyHueChanged ();
+ updateMousePosFromHue ();
+ }
+ }
+ protected override void onDraw (Cairo.Context gr)
+ {
+ base.onDraw (gr);
+
+ Rectangle r = ClientRectangle;
+
+ Gradient.Type gt = Gradient.Type.Horizontal;
+ if (Orientation == Orientation.Vertical)
+ gt = Gradient.Type.Vertical;
+
+ Crow.Gradient grad = new Gradient (gt);
+
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (1, 0, 0, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.167, new Color (1, 1, 0, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.333, new Color (0, 1, 0, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.5, new Color (0, 1, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.667, new Color (0, 0, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.833, new Color (1, 0, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (1, 0, 0, 1)));
+
+ grad.SetAsSource (gr, r);
+ CairoHelpers.CairoRectangle (gr, r, CornerRadius);
+ gr.Fill();
+ }
+
+ public override void Paint (ref Context ctx)
+ {
+ base.Paint (ref ctx);
+
+ Rectangle rb = Slot + Parent.ClientRectangle.Position;
+ ctx.Save ();
+
+ ctx.Translate (rb.X, rb.Y);
+
+ ctx.SetSourceColor (Color.White);
+ Rectangle r = ClientRectangle;
+ if (Orientation == Orientation.Horizontal) {
+ r.Width = 5;
+ r.X = mousePos.X;
+ } else {
+ r.Height = 5;
+ r.Y = mousePos.Y;
+ }
+
+ CairoHelpers.CairoRectangle (ctx, r, 2);
+ ctx.SetSourceColor (Color.White);
+ ctx.LineWidth = 2.0;
+ ctx.Stroke();
+ ctx.Restore ();
+ }
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ base.OnLayoutChanges (layoutType);
+
+ if (Orientation == Orientation.Horizontal) {
+ if (layoutType == LayoutingType.Width)
+ updateMousePosFromHue ();
+ } else if (layoutType == LayoutingType.Height)
+ updateMousePosFromHue ();
+ }
+ protected override void updateMouseLocalPos (Point mPos)
+ {
+ base.updateMouseLocalPos (mPos);
+ if (Orientation == Orientation.Horizontal)
+ hue = (double)mousePos.X / (double)ClientRectangle.Width;
+ else
+ hue = (double)mousePos.Y / (double)ClientRectangle.Height;
+ notifyHueChanged ();
+ }
+ void updateMousePosFromHue(){
+ if (Orientation == Orientation.Horizontal)
+ mousePos.X = (int)Math.Floor(hue * (double)ClientRectangle.Width);
+ else
+ mousePos.Y = (int)Math.Floor(hue * (double)ClientRectangle.Height);
+ CurrentInterface.EnqueueForRepaint (this);
+ }
+ void notifyHueChanged(){
+ NotifyValueChanged ("Hue", hue);
+ NotifyValueChanged ("HueColor", new SolidColor (Color.FromHSV (hue)));
+ }
+ }
+}
+
diff --git a/src/GraphicObjects/Label.cs b/src/GraphicObjects/Label.cs
index 666f00a2..2f35c223 100644
--- a/src/GraphicObjects/Label.cs
+++ b/src/GraphicObjects/Label.cs
@@ -670,7 +670,7 @@ namespace Crow
base.onMouseLeave (sender, e);
CurrentInterface.MouseCursor = XCursor.Default;
}
- public override void onFocused (object sender, EventArgs e)
+ protected override void onFocused (object sender, EventArgs e)
{
base.onFocused (sender, e);
@@ -680,7 +680,7 @@ namespace Crow
SelRelease = new Point (lines.LastOrDefault ().Length, lines.Count-1);
RegisterForRedraw ();
}
- public override void onUnfocused (object sender, EventArgs e)
+ protected override void onUnfocused (object sender, EventArgs e)
{
base.onUnfocused (sender, e);
diff --git a/src/GraphicObjects/Menu.cs b/src/GraphicObjects/Menu.cs
index 765925e9..5726afdf 100644
--- a/src/GraphicObjects/Menu.cs
+++ b/src/GraphicObjects/Menu.cs
@@ -65,7 +65,7 @@ namespace Crow
public override void onMouseLeave (object sender, MouseMoveEventArgs e)
{
base.onMouseLeave (sender, e);
- IsOpened = false;
+ //IsOpened = false;
}
}
}
diff --git a/src/GraphicObjects/MenuItem.cs b/src/GraphicObjects/MenuItem.cs
index 78162fbb..9fc0b226 100644
--- a/src/GraphicObjects/MenuItem.cs
+++ b/src/GraphicObjects/MenuItem.cs
@@ -50,8 +50,8 @@ namespace Crow
if (isOpened) {
onOpen (this, null);
- if (MenuRoot != null)
- MenuRoot.IsOpened = true;
+// if (MenuRoot != null)
+// MenuRoot.IsOpened = true;
}else
onClose (this, null);
}
@@ -102,7 +102,7 @@ namespace Crow
Execute.Raise (this, null);
}
protected virtual void onOpen (object sender, EventArgs e){
- MenuRoot.IsOpened = true;
+ //MenuRoot.IsOpened = true;
Open.Raise (this, null);
}
protected virtual void onClose (object sender, EventArgs e){
diff --git a/src/GraphicObjects/Popper.cs b/src/GraphicObjects/Popper.cs
index 669b8d7f..1b8c0d95 100644
--- a/src/GraphicObjects/Popper.cs
+++ b/src/GraphicObjects/Popper.cs
@@ -175,21 +175,6 @@ namespace Crow
_content.MinimumSize = new Size (this.Slot.Width, _content.MinimumSize.Height);
}
- public override void ClearBinding ()
- {
- //ensure popped window is cleared
- if (Content != null) {
- if (Content.Parent != null)
- CurrentInterface.DeleteWidget (Content);
- }
- base.ClearBinding ();
- }
- public override void ResolveBindings ()
- {
- base.ResolveBindings ();
- if (Content != null)
- Content.ResolveBindings ();
- }
public override void onMouseClick (object sender, MouseButtonEventArgs e)
{
@@ -201,13 +186,11 @@ namespace Crow
{
if (!_isPopped || _content == null) {
base.onMouseLeave (sender, e);
- System.Diagnostics.Debug.WriteLine ("NotPopped***popper mouse leave:"+ this.ToString());
return;
}
if (!_content.MouseIsIn (e.Position)) {
base.onMouseLeave (sender, e);
- System.Diagnostics.Debug.WriteLine ("***popper mouse leave:"+ this.ToString());
IsPopped = false;
return;
}
diff --git a/src/GraphicObjects/PrivateContainer.cs b/src/GraphicObjects/PrivateContainer.cs
index 2a5deeaa..9c65e935 100644
--- a/src/GraphicObjects/PrivateContainer.cs
+++ b/src/GraphicObjects/PrivateContainer.cs
@@ -47,7 +47,6 @@ namespace Crow
{
if (child != null) {
- child.ClearBinding ();
contentSize = new Size (0, 0);
child.LayoutChanged -= OnChildLayoutChanges;
child.Parent = null;
@@ -66,16 +65,7 @@ namespace Crow
}
#region GraphicObject Overrides
- public override void ResolveBindings ()
- {
- base.ResolveBindings ();
- if (child != null)
- child.ResolveBindings ();
- }
- protected void ResolveBindingsWithNoRecurse ()
- {
- base.ResolveBindings ();
- }
+
public override GraphicObject FindByName (string nameToFind)
{
if (Name == nameToFind)
@@ -88,6 +78,13 @@ namespace Crow
return child == goToFind ? true :
child == null ? false : child.Contains(goToFind);
}
+ public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
+ {
+ base.OnDataSourceChanged (this, e);
+ if (child != null)
+ if (child.localDataSourceIsNull & child.localLogicalParentIsNull)
+ child.OnDataSourceChanged (sender, e);
+ }
public override bool UpdateLayout (LayoutingType layoutType)
{
if (child != null) {
@@ -161,8 +158,10 @@ namespace Crow
gr.Clip ();
}
- if (child != null)
- child.Paint (ref gr);
+ if (child != null) {
+ if (child.Visible)
+ child.Paint (ref gr);
+ }
gr.Restore ();
}
protected override void UpdateCache (Context ctx)
@@ -197,19 +196,6 @@ namespace Crow
}
#endregion
- public override void ClearBinding ()
- {
- if (child != null)
- child.ClearBinding ();
- base.ClearBinding ();
- }
- public override GraphicObject DeepClone ()
- {
- PrivateContainer tmp = base.DeepClone () as PrivateContainer;
- if (child != null)
- tmp.SetChild (child.DeepClone ());
- return tmp;
- }
}
}
diff --git a/src/GraphicObjects/SaturationValueSelector.cs b/src/GraphicObjects/SaturationValueSelector.cs
new file mode 100644
index 00000000..b71fa7ef
--- /dev/null
+++ b/src/GraphicObjects/SaturationValueSelector.cs
@@ -0,0 +1,129 @@
+//
+// SaturationValueSelector.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+using Cairo;
+using System.Xml.Serialization;
+
+namespace Crow
+{
+ public class SaturationValueSelector : ColorSelector
+ {
+ public SaturationValueSelector () : base()
+ {
+ }
+
+ double v, s;
+
+ [XmlAttributeAttribute()]
+ public virtual double V {
+ get { return v; }
+ set {
+ if (v == value)
+ return;
+ v = value;
+ NotifyValueChanged ("V", v);
+ mousePos.Y = (int)Math.Floor((1.0-v) * (double)ClientRectangle.Height);
+
+ CurrentInterface.EnqueueForRepaint (this);
+ }
+ }
+ [XmlAttributeAttribute()]
+ public virtual double S {
+ get { return s; }
+ set {
+ if (s == value)
+ return;
+ s = value;
+ NotifyValueChanged ("S", s);
+ mousePos.X = (int)Math.Floor(s * (double)ClientRectangle.Width);
+ CurrentInterface.EnqueueForRepaint (this);
+ }
+ }
+ protected override void onDraw (Cairo.Context gr)
+ {
+ base.onDraw (gr);
+
+ Rectangle r = ClientRectangle;
+ Rectangle rGrad = r;
+ rGrad.Inflate (-1);
+
+ if (Foreground != null) {//TODO:test if null should be removed
+ Foreground.SetAsSource (gr, r);
+ CairoHelpers.CairoRectangle (gr, r, CornerRadius);
+ gr.Fill ();
+ }
+
+ Crow.Gradient grad = new Gradient (Gradient.Type.Horizontal);
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (1, 1, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (1, 1, 1, 0)));
+ grad.SetAsSource (gr, rGrad);
+ CairoHelpers.CairoRectangle (gr, r, CornerRadius);
+ gr.Fill();
+ grad = new Gradient (Gradient.Type.Vertical);
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (0, 0, 0, 0)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (0, 0, 0, 1)));
+ grad.SetAsSource (gr, rGrad);
+ CairoHelpers.CairoRectangle (gr, r, CornerRadius);
+ gr.Fill();
+ }
+
+ public override void Paint (ref Context ctx)
+ {
+ base.Paint (ref ctx);
+
+ Rectangle rb = Slot + Parent.ClientRectangle.Position;
+ ctx.Save ();
+
+ ctx.Translate (rb.X, rb.Y);
+
+ ctx.SetSourceColor (Color.White);
+ ctx.Arc (mousePos.X, mousePos.Y, 3.0, 0, Math.PI * 2.0);
+ ctx.LineWidth = 1.0;
+ ctx.Stroke ();
+
+ ctx.Restore ();
+ }
+
+ protected override void updateMouseLocalPos (Point mPos)
+ {
+ base.updateMouseLocalPos (mPos);
+
+ Rectangle cb = ClientRectangle;
+ s = (double)mousePos.X / (double)cb.Width;
+ v = 1.0 - (double)mousePos.Y / (double)cb.Height;
+ NotifyValueChanged ("S", s);
+ NotifyValueChanged ("V", v);
+ }
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ base.OnLayoutChanges (layoutType);
+ switch (layoutType) {
+ case LayoutingType.Width:
+ mousePos.X = (int)Math.Floor(s * (double)ClientRectangle.Width);
+ break;
+ case LayoutingType.Height:
+ mousePos.Y = (int)Math.Floor((1.0-v) * (double)ClientRectangle.Height);
+ break;
+ }
+ }
+ }
+}
+
diff --git a/src/GraphicObjects/TabItem.cs b/src/GraphicObjects/TabItem.cs
index e14a7815..cd57b221 100644
--- a/src/GraphicObjects/TabItem.cs
+++ b/src/GraphicObjects/TabItem.cs
@@ -46,15 +46,15 @@ namespace Crow
return _contentContainer == null ? null : _contentContainer.Child;
}
set {
+ if (Content != null) {
+ Content.LogicalParent = null;
+ _contentContainer.SetChild (null);
+ }
_contentContainer.SetChild(value);
+ if (value != null)
+ value.LogicalParent = this;
}
}
- public override void ResolveBindings ()
- {
- base.ResolveBindings ();
- if (_contentContainer != null)
- _contentContainer.ResolveBindings ();
- }
protected override void loadTemplate(GraphicObject template = null)
{
base.loadTemplate (template);
diff --git a/src/GraphicObjects/TemplatedContainer.cs b/src/GraphicObjects/TemplatedContainer.cs
index 7a4649a4..44c2ad08 100644
--- a/src/GraphicObjects/TemplatedContainer.cs
+++ b/src/GraphicObjects/TemplatedContainer.cs
@@ -34,19 +34,6 @@ namespace Crow
[XmlIgnore]public abstract GraphicObject Content{ get; set;}
#region GraphicObject overrides
- public override void ClearBinding ()
- {
- if (Content != null)
- Content.ClearBinding ();
-
- base.ClearBinding ();
- }
-// public override void ResolveBindings ()
-// {
-// base.ResolveBindings ();
-// if (Content != null)
-// Content.ResolveBindings ();
-// }
public override GraphicObject FindByName (string nameToFind)
{
if (Name == nameToFind)
diff --git a/src/GraphicObjects/TemplatedControl.cs b/src/GraphicObjects/TemplatedControl.cs
index 7f2e1b87..ba49f44f 100644
--- a/src/GraphicObjects/TemplatedControl.cs
+++ b/src/GraphicObjects/TemplatedControl.cs
@@ -94,8 +94,6 @@ namespace Crow
this.SetChild (CurrentInterface.Load (Interface.DefaultTemplates[this.GetType ().FullName]));
}else
this.SetChild (template);
-
- this.ResolveBindings ();
}
//TODO:IXmlSerializable is not used anymore
diff --git a/src/GraphicObjects/TemplatedGroup.cs b/src/GraphicObjects/TemplatedGroup.cs
index 500e5ea6..3c1fed9e 100644
--- a/src/GraphicObjects/TemplatedGroup.cs
+++ b/src/GraphicObjects/TemplatedGroup.cs
@@ -36,13 +36,12 @@ namespace Crow
#endregion
protected Group items;
- string _itemTemplate;
+ string _itemTemplate, _dataTest;
#region events
public event EventHandler<SelectionChangeEventArgs> SelectedItemChanged;
#endregion
- Group _list;
IList data;
int _selectedIndex;
Color selBackground, selForeground;
@@ -56,6 +55,9 @@ namespace Crow
//but then i should test if null in msil gen
public Dictionary<string, ItemTemplate> ItemTemplates = new Dictionary<string, Crow.ItemTemplate>();
+ /// <summary>
+ /// Default item template
+ /// </summary>
[XmlAttributeAttribute][DefaultValue("#Crow.Templates.ItemTemplate.goml")]
public string ItemTemplate {
get { return _itemTemplate; }
@@ -81,6 +83,24 @@ namespace Crow
else
NotifyValueChanged ("HasChildren", true);
}
+ /// <summary>
+ /// Use to define condition on Data item for selecting among ItemTemplates.
+ /// Default value is 'TypeOf' for selecting Template depending on Type of Data.
+ /// Other possible values are properties of Data
+ /// </summary>
+ /// <value>The data property test.</value>
+ [XmlAttributeAttribute][DefaultValue("TypeOf")]
+ public string DataTest {
+ get { return _dataTest; }
+ set {
+ if (value == _dataTest)
+ return;
+
+ _dataTest = value;
+
+ NotifyValueChanged("DataTest", _dataTest);
+ }
+ }
#endregion
public virtual List<GraphicObject> Items{ get { return items.Children; }}
@@ -100,7 +120,9 @@ namespace Crow
[XmlIgnore]public virtual object SelectedItem{
get { return data == null ? null : _selectedIndex < 0 ? null : data[_selectedIndex]; }
}
-
+ [XmlIgnore]public bool HasItems {
+ get { return Items.Count > 0; }
+ }
[XmlAttributeAttribute]public IList Data {
get { return data; }
set {
@@ -113,7 +135,7 @@ namespace Crow
NotifyValueChanged ("Data", data);
- lock (CurrentInterface.UpdateMutex)
+ //lock (CurrentInterface.UpdateMutex)
ClearItems ();
if (data == null)
@@ -127,6 +149,7 @@ namespace Crow
NotifyValueChanged ("SelectedIndex", _selectedIndex);
NotifyValueChanged ("SelectedItem", SelectedItem);
SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
+ NotifyValueChanged ("HasItems", HasItems);
}
}
@@ -160,10 +183,12 @@ namespace Crow
public virtual void AddItem(GraphicObject g){
items.AddChild (g);
+ g.LogicalParent = this;
NotifyValueChanged ("HasChildren", true);
}
public virtual void RemoveItem(GraphicObject g)
{
+ g.LogicalParent = null;
items.RemoveChild (g);
if (items.Children.Count == 0)
NotifyValueChanged ("HasChildren", false);
@@ -281,6 +306,7 @@ namespace Crow
if (cancelLoading)
return;
loadPage (i);
+ Thread.Sleep (1);
}
}
void cancelLoadingThread(){
@@ -299,20 +325,25 @@ namespace Crow
loadingTime.Start ();
#endif
- Group page = items.Clone () as Group;
+ Group page;
+ if (typeof(Wrapper).IsAssignableFrom (items.GetType ())){
+ page = items;
+ itemPerPage = int.MaxValue;
+ }else if (typeof(GenericStack).IsAssignableFrom (items.GetType ())) {
+ GenericStack gs = new GenericStack ();
+ gs.CurrentInterface = items.CurrentInterface;
+ gs.initialize ();
+ gs.Orientation = (items as GenericStack).Orientation;
+ gs.Width = items.Width;
+ gs.Height = items.Height;
+ gs.VerticalAlignment = items.VerticalAlignment;
+ gs.HorizontalAlignment = items.HorizontalAlignment;
+ page = gs;
- page.Name = "page" + pageNum;
+ }else
+ page = Activator.CreateInstance (items.GetType ()) as Group;
-// //reset size to fit in the dir of the stacking
-// //because items total size is forced to approx size
-// if (_gsList.Orientation == Orientation.Horizontal) {
-// page.Width = Measure.Fit;
- page.BindMember ("Height", "../HeightPolicy");
- page.BindMember ("Width", "../WidthPolicy");
-// } else {
-// page.Height = Measure.Fit;
-// page.BindMember ("Width", "../WidthPolicy");
-// }
+ page.Name = "page" + pageNum;
for (int i = (pageNum - 1) * itemPerPage; i < pageNum * itemPerPage; i++) {
if (i >= data.Count)
@@ -321,10 +352,10 @@ namespace Crow
return;
loadItem (i, page);
-
- //g.LogicalParent = this;
}
+ if (page == items)
+ return;
lock (CurrentInterface.LayoutMutex)
items.AddChild (page);
@@ -335,27 +366,41 @@ namespace Crow
loadingTime.ElapsedMilliseconds, this.ToString());
#endif
}
+ string getItempKey(Type dataType, object o){
+ try {
+ return dataType.GetProperty (_dataTest).GetGetMethod ().Invoke (o, null).ToString();
+ } catch (Exception ex) {
+ return dataType.FullName;
+ }
+ }
protected void loadItem(int i, Group page){
GraphicObject g = null;
ItemTemplate iTemp = null;
Type dataType = data [i].GetType ();
+ string itempKey = dataType.FullName;
- if (ItemTemplates.ContainsKey (dataType.FullName))
- iTemp = ItemTemplates [dataType.FullName];
+ if (_dataTest != "TypeOf")
+ itempKey = getItempKey (dataType, data [i]);
+
+ if (ItemTemplates.ContainsKey (itempKey))
+ iTemp = ItemTemplates [itempKey];
else
iTemp = ItemTemplates ["default"];
lock (CurrentInterface.LayoutMutex) {
g = iTemp.CreateInstance(CurrentInterface);
page.AddChild (g);
- g.DataSource = data [i];
+ registerItemClick (g);
}
- registerItemClick (g);
-
if (iTemp.Expand != null && g is Expandable) {
(g as Expandable).Expand += iTemp.Expand;
- }
+ (g as Expandable).GetIsExpandable = iTemp.HasSubItems;
+ }
+ //g.LogicalParent = this;
+
+
+ g.DataSource = data [i];
}
protected virtual void registerItemClick(GraphicObject g){
g.MouseClick += itemClick;
diff --git a/src/GraphicObjects/Window.cs b/src/GraphicObjects/Window.cs
index 9ef9e642..86f05d86 100644
--- a/src/GraphicObjects/Window.cs
+++ b/src/GraphicObjects/Window.cs
@@ -134,12 +134,6 @@ namespace Crow
#endregion
#region GraphicObject Overrides
- public override void ResolveBindings ()
- {
- base.ResolveBindings ();
- if (Content != null)
- Content.ResolveBindings ();
- }
public override void onMouseMove (object sender, MouseMoveEventArgs e)
{
base.onMouseMove (sender, e);
diff --git a/src/IML/BindingDefinition.cs b/src/IML/BindingDefinition.cs
new file mode 100644
index 00000000..eadbc9df
--- /dev/null
+++ b/src/IML/BindingDefinition.cs
@@ -0,0 +1,84 @@
+//
+// BindingDefinition.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+
+namespace Crow.IML
+{
+ /// <summary>
+ /// store binding source and target addresses and member names
+ /// </summary>
+ public class BindingDefinition
+ {
+ public NodeAddress SourceNA = null;
+ public string SourceMember = "";
+ public NodeAddress TargetNA = null;
+ public string TargetMember = "";
+ public string TargetName = "";
+ public bool TwoWay = false;
+
+ #region CTOR
+ public BindingDefinition (NodeAddress _sourceNA, string _sourceMember){
+ SourceNA = _sourceNA;
+ SourceMember = _sourceMember;
+ }
+ public BindingDefinition (NodeAddress _sourceNA, string _sourceMember, NodeAddress _targetNA, string _targetMember, string _targetName = "", bool _twoWay = false)
+ {
+ SourceNA = _sourceNA;
+ SourceMember = _sourceMember;
+ TargetNA = _targetNA;
+ TargetMember = _targetMember;
+ TargetName = _targetName;
+ TwoWay = _twoWay;
+ }
+ #endregion
+
+ public bool IsDataSourceBinding { get { return TargetNA == null; }}
+ public bool IsTemplateBinding { get { return IsDataSourceBinding ? false : TargetNA.Count == 0; }}
+ public bool HasUnresolvedTargetName { get { return !string.IsNullOrEmpty(TargetName); }}
+ public MemberAddress SourceMemberAddress { get { return new MemberAddress (SourceNA, SourceMember);}}
+ public MemberAddress TargetMemberAddress { get { return new MemberAddress (TargetNA, TargetMember);}}
+
+ /// <summary>
+ /// replace the target node address with corresponding named node address, and clear the target name once resolved
+ /// </summary>
+ /// <param name="newTargetNA">Named Node</param>
+ public void ResolveTargetName(NodeAddress newTargetNA){
+ TargetNA = newTargetNA;
+ TargetName = "";
+ }
+
+ public override string ToString ()
+ {
+ string tmp = string.Format ("Source:{0}.{1}", SourceNA, SourceMember);
+ if (TwoWay)
+ tmp += " <=> ";
+ else
+ tmp += " <= ";
+
+ if (string.IsNullOrEmpty (TargetName))
+ tmp += string.Format ("Target:{0}.{1}]", TargetNA, TargetMember);
+ else
+ tmp += string.Format ("Target:{0}.{1}.{2}]", TargetNA, TargetName, TargetMember);
+ return tmp;
+ }
+ }
+}
+
diff --git a/src/IML/Context.cs b/src/IML/Context.cs
new file mode 100644
index 00000000..7f739c37
--- /dev/null
+++ b/src/IML/Context.cs
@@ -0,0 +1,193 @@
+//
+// Context.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Xml;
+
+namespace Crow.IML
+{
+ public class DataSourceBinding {
+ public bool TwoWay;
+ public MemberAddress Source;
+ public string DataSourceMember;
+ }
+ /// <summary>
+ /// Context while parsing IML, this will store what's needed only while parsing and not during instancing
+ /// </summary>
+ public class Context
+ {
+ public XmlTextReader reader = null;
+ public Type RootType = null;
+
+ public DynamicMethod dm = null;
+ public ILGenerator il = null;
+ //public SubNodeType curSubNodeType;
+ public NodeStack nodesStack = new NodeStack ();
+
+ /// <summary> store addresses of named node for name resolution at end of parsing </summary>
+ public Dictionary<string, List<NodeAddress>> Names = new Dictionary<string, List<NodeAddress>>();
+ /// <summary> Store non datasource binding (in tree and template) by origine and orig member </summary>
+ public Dictionary<NodeAddress, Dictionary<string, List<MemberAddress>>> Bindings =
+ new Dictionary<NodeAddress, Dictionary<string, List<MemberAddress>>>();
+ /// <summary> Store binding with name in target, will be resolved at end of parsing </summary>
+ public List<BindingDefinition> UnresolvedTargets = new List<BindingDefinition>();
+
+
+ public Context (Type rootType)
+ {
+ RootType = rootType;
+ dm = new DynamicMethod ("dyn_instantiator",
+ CompilerServices.TObject, new Type [] { typeof (Instantiator), typeof (Interface) }, true);
+ il = dm.GetILGenerator (256);
+
+ il.DeclareLocal (typeof (GraphicObject));
+ il.Emit (OpCodes.Nop);
+ //set local GraphicObject to root object
+ il.Emit (OpCodes.Newobj, rootType.GetConstructors () [0]);
+ il.Emit (OpCodes.Stloc_0);
+ CompilerServices.emitSetCurInterface (il);
+ }
+
+ public NodeAddress CurrentNodeAddress {
+ get {
+ Node[] n = nodesStack.ToArray ();
+ Array.Reverse (n);
+ return new NodeAddress(n);
+ }
+ }
+ public Type CurrentNodeType {
+ get { return nodesStack.Peek().CrowType; }
+ }
+ public void StorePropertyBinding(NodeAddress origNA, string origMember, NodeAddress destNA, string destMember){
+ Dictionary<string, List<MemberAddress>> nodeBindings = null;
+ if (Bindings.ContainsKey (origNA))
+ nodeBindings = Bindings [origNA];
+ else {
+ nodeBindings = new Dictionary<string, List<MemberAddress>> ();
+ Bindings [origNA] = nodeBindings;
+ }
+
+ if (!nodeBindings.ContainsKey (origMember))
+ nodeBindings [origMember] = new List<MemberAddress> ();
+ nodeBindings [origMember].Add (new MemberAddress (destNA, destMember));
+ }
+ public void StorePropertyBinding(BindingDefinition bindDef){
+ if (bindDef.HasUnresolvedTargetName) {
+ UnresolvedTargets.Add (bindDef);
+ return;
+ }
+ StorePropertyBinding (bindDef.TargetNA, bindDef.TargetMember, bindDef.SourceNA, bindDef.SourceMember);
+ if (bindDef.TwoWay)
+ StorePropertyBinding (bindDef.SourceNA, bindDef.SourceMember, bindDef.TargetNA, bindDef.TargetMember);
+ }
+ public void StoreCurrentName(string name){
+ if (!Names.ContainsKey(name))
+ Names[name] = new List<NodeAddress>();
+ Names[name].Add(CurrentNodeAddress);
+ }
+ public void ResolveNamedTargets(){//TODO:methodinfo fetching is redundant with early parsing
+ foreach (BindingDefinition bd in UnresolvedTargets) {
+ if (bd.HasUnresolvedTargetName) {
+ try {
+ ResolveName (bd);
+ } catch (Exception ex) {
+ System.Diagnostics.Debug.WriteLine (ex.ToString ());
+ continue;
+ }
+ }
+
+ if (bd is EventBinding) {
+ emitHandlerMethodAddition (bd as EventBinding);
+ continue;
+ }
+
+ MemberInfo miSource = bd.SourceMemberAddress.member;
+ if (miSource == null)
+ throw new Exception ("Source member '" + bd.SourceMember + "' not found");
+ StorePropertyBinding (bd);
+ }
+ }
+ public void ResolveName (BindingDefinition bd){
+
+ if (!Names.ContainsKey (bd.TargetName))
+ throw new Exception ("Target Name '" + bd.TargetName + "' not found");
+
+ NodeAddress resolvedNA = null;
+ foreach (NodeAddress na in Names[bd.TargetName]) {
+ bool naMatch = true;
+ for (int i = 0; i < bd.TargetNA.Count; i++) {
+ if (bd.TargetNA [i] != na [i]) {
+ naMatch = false;
+ break;
+ }
+ }
+ if (naMatch) {
+ resolvedNA = na;
+ break;
+ }
+ }
+
+ if (resolvedNA == null)
+ throw new Exception ("Target Name '" + bd.TargetName + "' not found");
+
+ bd.ResolveTargetName (resolvedNA);
+ }
+
+ /// <summary>
+ /// Emits cached delegate handler addition in the context of instantiator (ctx)
+ /// </summary>
+ public void emitCachedDelegateHandlerAddition(int index, EventInfo evt, NodeAddress address = null){
+ il.Emit(OpCodes.Ldloc_0);//load ref to current graphic object
+ CompilerServices.emitGetInstance (il, address);
+ il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+ il.Emit(OpCodes.Ldfld, CompilerServices.fiCachedDel);
+ il.Emit(OpCodes.Ldc_I4, index);//load delegate index
+ il.Emit(OpCodes.Callvirt, CompilerServices.miGetDelegateListItem);
+ il.Emit(OpCodes.Callvirt, evt.AddMethod);//call add event
+ }
+ /// <summary>
+ /// Emits the handler method addition, done at end of parsing, Loc_0 is root node instance
+ /// </summary>
+ /// <param name="bd">Bd.</param>
+ /// <param name="evt">passed as arg to prevent refetching it for the 3rd time</param>
+ public void emitHandlerMethodAddition(EventBinding bd){
+ //fetch source instance with address for handler addition (as 1st arg of handler.add)
+ il.Emit (OpCodes.Ldloc_0);//push root
+ CompilerServices.emitGetInstance (il, bd.SourceNA);
+
+ //load handlerType of sourceEvent to create handler delegate (1st arg)
+ il.Emit (OpCodes.Ldtoken, bd.SourceEvent.EventHandlerType);
+ il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle);
+ //load target the where the method is defined (2nd arg)
+ il.Emit (OpCodes.Ldloc_0);
+ CompilerServices.emitGetInstance (il, bd.TargetNA);
+ //load methodInfo (3rd arg)
+ il.Emit (OpCodes.Ldstr, bd.TargetMember);
+
+ il.Emit (OpCodes.Callvirt, CompilerServices.miCreateDel);
+
+ il.Emit (OpCodes.Callvirt, bd.SourceEvent.AddMethod);//call add event
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/GraphicObjects/IBindable.cs b/src/IML/EventBinding.cs
index 45ff5864..90a797e0 100644
--- a/src/GraphicObjects/IBindable.cs
+++ b/src/IML/EventBinding.cs
@@ -1,10 +1,10 @@
//
-// IValueChange.cs
+// EventBinding.cs
//
// Author:
// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
//
-// Copyright (c) 2015 jp
+// Copyright (c) 2016 jp
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -19,14 +19,21 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
-using System.Collections.Generic;
+using System.Reflection;
-namespace Crow
+namespace Crow.IML
{
- public interface IBindable
+ public class EventBinding : BindingDefinition
{
- List<Binding> Bindings { get; }
- object DataSource { get; set; }
+ public EventInfo SourceEvent;
+
+ #region CTOR
+ public EventBinding (NodeAddress _sourceNA, EventInfo _sourceEvt, NodeAddress _targetNA, string _targetMember, string _targetName = "")
+ : base (_sourceNA, _sourceEvt.Name, _targetNA, _targetMember, _targetName)
+ {
+ SourceEvent = _sourceEvt;
+ }
+ #endregion
}
}
diff --git a/src/IML/MemberAddress.cs b/src/IML/MemberAddress.cs
new file mode 100644
index 00000000..a131927e
--- /dev/null
+++ b/src/IML/MemberAddress.cs
@@ -0,0 +1,110 @@
+//
+// MemberAddress.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Linq;
+using System.Reflection;
+
+namespace Crow.IML
+{
+ /// <summary>
+ /// Address member of a node
+ /// </summary>
+ public struct MemberAddress
+ {
+ public string memberName;
+ public MemberInfo member;
+ public NodeAddress Address;
+
+ public PropertyInfo Property { get { return member as PropertyInfo; }}
+ public bool IsTemplateBinding { get { return Address == null ? false : Address.Count == 0; }}
+// public string Name {
+// get { return memberName; }
+// set { memberName = value; }
+// }
+
+ public MemberAddress (NodeAddress _address, string _member, bool findMember = true)
+ {
+ Address = _address;
+ memberName = _member;
+ member = null;
+
+ if (Address == null)
+ return;
+ if (Address.Count == 0)
+ return;
+
+ if (!findMember)
+ return;
+ if (!tryFindMember ())
+ throw new Exception ("Member Not Found: " + memberName);
+ }
+ public MemberAddress (NodeAddress _address, MemberInfo _member)
+ {
+ Address = _address;
+ member = _member;
+ memberName = "";
+
+ if (member != null)
+ memberName = member.Name;
+ }
+
+ #region Equality Compare
+ public override bool Equals (object obj)
+ {
+ return obj is MemberAddress && this == (MemberAddress)obj;
+ }
+ public override int GetHashCode ()
+ {
+ return Address.GetHashCode () ^ member.GetHashCode ();
+ }
+ public static bool operator == (MemberAddress x, MemberAddress y)
+ {
+ return x.Address == y.Address && x.memberName == y.memberName;
+ }
+ public static bool operator != (MemberAddress x, MemberAddress y)
+ {
+ return !(x == y);
+ }
+ #endregion
+
+ bool tryFindMember ()
+ {
+ if (member != null)
+ throw new Exception ("member already found");
+ if (Address == null)
+ return false;
+ if (Address.Count == 0)
+ return false;
+ Type t = Address.LastOrDefault ().CrowType;
+ member = t.GetMember (memberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).FirstOrDefault ();
+
+ #region search for extensions methods if member not found in type
+ if (member == null && !string.IsNullOrEmpty (memberName)) {
+ Assembly a = Assembly.GetExecutingAssembly ();
+ string mn = memberName;
+ member = CompilerServices.GetExtensionMethods (a, t).Where (em => em.Name == mn).FirstOrDefault ();
+ }
+ #endregion
+
+ return member != null;
+ }
+ }
+}
diff --git a/src/IML/Node.cs b/src/IML/Node.cs
new file mode 100644
index 00000000..4ba61c03
--- /dev/null
+++ b/src/IML/Node.cs
@@ -0,0 +1,85 @@
+//
+// Node.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Collections.Generic;
+
+namespace Crow.IML
+{
+ /// <summary>
+ /// IML Node are defined with a type and the index in the parent,
+ /// </summary>
+ public struct Node
+ {
+ /// <summary> Current node type</summary>
+ public Type CrowType;
+ /// <summary> Index in parent, -1 for template</summary>
+ public int Index;
+
+ public Node (Type crowType, int _index = 0)
+ {
+ CrowType = crowType;
+ Index = _index;
+ }
+
+ public MethodInfo GetAddMethod(int childIdx){
+ if (typeof (Group).IsAssignableFrom (CrowType))
+ return CompilerServices.miAddChild;
+ if (typeof (Container).IsAssignableFrom (CrowType))
+ return CompilerServices.miSetChild;
+ if (typeof (TemplatedContainer).IsAssignableFrom (CrowType))
+ return childIdx < 0 ? CompilerServices.miLoadTmp : CompilerServices.piContent.GetSetMethod();
+ if (typeof (TemplatedGroup).IsAssignableFrom (CrowType))
+ return childIdx < 0 ? CompilerServices.miLoadTmp : CompilerServices.miAddItem;
+ if (typeof (TemplatedControl).IsAssignableFrom (CrowType))
+ return CompilerServices.miLoadTmp;
+ return null;
+ }
+
+ #region Equality Compare
+ public override bool Equals (object obj)
+ {
+ if (obj == null)
+ return false;
+ Node n = (Node)obj;
+ return CrowType == n.CrowType && Index == n.Index;
+ }
+ public override int GetHashCode ()
+ {
+ return CrowType.GetHashCode () ^ Index.GetHashCode ();
+ }
+ #endregion
+
+ public bool HasTemplate {
+ get { return typeof (TemplatedControl).IsAssignableFrom (CrowType);}
+ }
+
+ public static implicit operator string (Node sn)
+ {
+ return sn.ToString ();
+ }
+ public override string ToString ()
+ {
+ return string.Format ("{0}.{1}", CrowType.FullName, Index);
+ }
+ }
+}
diff --git a/src/IML/NodeAddress.cs b/src/IML/NodeAddress.cs
new file mode 100644
index 00000000..460998da
--- /dev/null
+++ b/src/IML/NodeAddress.cs
@@ -0,0 +1,69 @@
+//
+// NodeAddress.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Crow.IML
+{
+ public class NodeAddress : List<Node>
+ {
+ public NodeAddress (Node[] nodes) : base(nodes) {
+ }
+
+ public Type NodeType { get { return Count == 0 ? null : this[this.Count -1].CrowType; }}
+
+ public override bool Equals (object obj)
+ {
+ if (obj == null)
+ return false;
+
+ NodeAddress na = (NodeAddress)obj;
+ return this.SequenceEqual (na);
+ }
+ public override int GetHashCode ()
+ {
+ unchecked {
+ int hash = 19;
+ foreach (Node n in this)
+ hash = hash * 31 + (n == null ? 0 : n.GetHashCode ());
+ return hash;
+ }
+ }
+
+ public override string ToString ()
+ {
+ string tmp = "";
+ foreach (Node n in this)
+ tmp += string.Format ("{0};", n.Index);
+ return tmp;
+ }
+ }
+
+ public class NamedNodeAddress : NodeAddress {
+ public string Name;
+ public NamedNodeAddress(string name, Node[] nodes) : base(nodes){
+ Name = name;
+ }
+ }
+}
diff --git a/src/IML/NodeStack.cs b/src/IML/NodeStack.cs
new file mode 100644
index 00000000..bec45e26
--- /dev/null
+++ b/src/IML/NodeStack.cs
@@ -0,0 +1,44 @@
+//
+// NodeStack.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Collections.Generic;
+
+namespace Crow.IML
+{
+ public class NodeStack : Stack<Node>
+ {
+ public NodeStack () : base()
+ {
+ }
+ public void IncrementCurrentNodeIndex(){
+ Node n = this.Pop();
+ this.Push (new Node (n.CrowType, n.Index + 1));
+ }
+ public void DecrementCurrentNodeIndex(){
+ Node n = this.Pop();
+ this.Push (new Node (n.CrowType, n.Index - 1));
+ }
+ public void ResetCurrentNodeIndex(){
+ this.Push (new Node (this.Pop().CrowType));
+ }
+ }
+}
+
diff --git a/src/IML/Reader.cs b/src/IML/Reader.cs
new file mode 100644
index 00000000..7a0c8405
--- /dev/null
+++ b/src/IML/Reader.cs
@@ -0,0 +1,223 @@
+//
+// IMLReader.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2016 jp
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+using System;
+using System.Xml;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace Crow.IML2
+{
+ public class Reader : XmlTextReader
+ {
+ static List<Type> CrowTypes = new List<Type> ();
+
+ public enum SubNodeType{
+ None,
+ Child,
+ Children,
+ Template,
+ Content,
+ Items,
+ ItemTemplate
+ }
+
+ //public static Node Parse(string str){
+ // string[] tmp = str.Trim ().Split ('.');
+ // switch (tmp.Length) {
+ // case 1:
+ // return new Node ((SubNodeType)int.Parse (tmp [0]));
+ // case 2:
+ // return new Node ((SubNodeType)int.Parse (tmp [0]), int.Parse (tmp[1]));
+ // case 0:
+ // default:
+ // return new Node ();
+ // }
+ //}
+ //public static string AddressToString(Node[] address){
+ // string tmp = "";
+ // foreach (Node n in address) {
+ // tmp += n.ToString () + ";";
+ // }
+ // return string.IsNullOrEmpty(tmp) ? tmp : tmp.Substring (0, tmp.Length - 1);
+ //}
+ //public static Node[] AddressFromString(string address) {
+ // List<Node> nodes = new List<Node> ();
+ // string[] tmp = address.Split (';');
+ // for (int i = 0; i < tmp.Length; i++)
+ // nodes.Add (Node.Parse (tmp [i]));
+ // return nodes.ToArray();
+ //}
+
+
+ // public class PropertyBinding {
+ // public string OriginePropertyName = "";
+ // public MemberAddress Destination;
+ // }
+
+ public Type RootType = null;
+ public Context context;
+
+ InstanciatorInvoker loader = null;
+ DynamicMethod dm = null;
+
+ ILGenerator il { get { return context.il; }}
+
+ /// <summary>
+ /// Finalize instatiator MSIL and return LoaderInvoker delegate
+ /// </summary>
+ public InstanciatorInvoker GetLoader(){
+ if (loader != null)
+ return loader;
+
+ il.Emit(OpCodes.Ret);
+ loader = (InstanciatorInvoker)dm.CreateDelegate (typeof(InstanciatorInvoker));
+ return loader;
+ }
+
+ protected int curDepth {
+ get { return context.nodesStack.Count - 1;}
+ }
+ protected Node curNode {
+ get { return context.nodesStack.Peek(); }
+ }
+ //protected Stack<int> curTemplateDepth = new Stack<int>(new int[] {0}); //current template root depth
+
+ #region CTOR
+ public Reader (string path)
+ : this(Interface.GetStreamFromPath (path)){
+ }
+ public Reader (Stream stream)
+ : base(stream)
+ {
+ createInstantiator ();
+ }
+ /// <summary>
+ /// Used to parse xmlFrament with same code generator linked
+ /// If ilGen=null, a new Code Generator will be created.
+ /// </summary>
+ public Reader (Context ctx, string xmlFragment)
+ : base(xmlFragment, XmlNodeType.Element,null){
+
+ context = ctx;
+//
+// if (IMLCtx != null)
+// return;
+//
+// createInstantiator();
+ }
+ #endregion
+
+
+ void createBindingDelegates(){
+// foreach (Dictionary<string, MemberAddress> pb in IMLCtx.PropertyBindings) {
+//
+// }
+ }
+
+
+ void registerPropertyBinding(string origNode, string origProp, MemberAddress ma){
+ if (!context.PropertyBindings.ContainsKey(origNode))
+ context.PropertyBindings [origNode] = new Dictionary<string, MemberAddress> ();
+ context.PropertyBindings [origNode] [origProp] = ma;
+ }
+ void readPropertyBinding(string srcProperty, string expression){
+ //if binding exp = '{}' => binding is done on datasource
+ if (string.IsNullOrEmpty (expression)) {
+ registerPropertyBinding ("DS", "", new MemberAddress (context.nodesStack.ToArray (), srcProperty));
+ return;
+ }
+
+// if (expression.StartsWith ("²")) {
+// expression = expression.Substring (1);
+// TwoWayBinding = true;
+// }
+//
+ string [] bindingExp = expression.Split ('/');
+
+
+ if (bindingExp.Length == 1) {
+ registerPropertyBinding ("DS", bindingExp [0],
+ new MemberAddress (context.nodesStack.ToArray (), srcProperty));
+ return;
+ }
+
+ string targetName = "";
+ string nodeId = "";
+ Node[] target = context.nodesStack.ToArray ();
+
+ int nodeIdx = target.Length - 1;//index of target in nodeStack
+ int ptr = 0;//pointer in bindingExp splitted on '/'
+
+// //if exp start with '/' => WidgetName.property
+ if (string.IsNullOrEmpty (bindingExp [0])) {
+ string[] bindTrg = bindingExp [1].Split ('.');
+ if (bindTrg.Length == 1) {
+ nodeId = Node.AddressToString (target);
+ targetName = bindTrg [0];
+ }else if (bindTrg.Length == 2) {
+ nodeId = context.Names [bindTrg [0]];
+ targetName = bindTrg [1];
+ } else
+ throw new Exception ("Syntax error in binding, expected 'go dot member'");
+ } else {
+ if (bindingExp [0] == ".") { //template binding
+ //parse nodes up until template node
+ while (nodeIdx > 0) {
+ if (target [nodeIdx].Type == SubNodeType.Template)
+ break;
+ nodeIdx--;
+ }
+ ptr++;
+ } else {
+ while (ptr < bindingExp.Length - 1) {
+ if (bindingExp [ptr] == "..")
+ nodeIdx--;
+ else
+ break;
+ ptr++;
+ }
+ }
+ Node[] origine = new Node[nodeIdx + 1];
+ try {
+ Array.Copy (target, origine, nodeIdx + 1);
+
+ int destLength = target.Length - nodeIdx;
+ Node[] dest = new Node[destLength];
+ Array.Copy (target, nodeIdx, dest, 0, destLength);
+
+ } catch (Exception ex) {
+ System.Diagnostics.Debug.WriteLine (ex.ToString ());
+ }
+
+
+ nodeId = Node.AddressToString (origine);
+ targetName = bindingExp [ptr];
+ }
+
+ registerPropertyBinding (nodeId, targetName, new MemberAddress (context.nodesStack.ToArray (), srcProperty));
+ }
+
+ }
+}
+
diff --git a/src/IMLReader.cs b/src/IMLReader.cs
deleted file mode 100644
index ad4fd835..00000000
--- a/src/IMLReader.cs
+++ /dev/null
@@ -1,346 +0,0 @@
-//
-// IMLReader.cs
-//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2016 jp
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-using System;
-using System.Xml;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Linq;
-using System.Collections.Generic;
-
-namespace Crow
-{
- public class IMLReader : XmlTextReader
- {
- InstanciatorInvoker loader = null;
- DynamicMethod dm = null;
-
- public ILGenerator il = null;
- public Type RootType = null;
-
- /// <summary>
- /// Finalize instatiator MSIL and return LoaderInvoker delegate
- /// </summary>
- public InstanciatorInvoker GetLoader(){
- if (loader != null)
- return loader;
-
- il.Emit(OpCodes.Ret);
- loader = (InstanciatorInvoker)dm.CreateDelegate (typeof(InstanciatorInvoker));
- return loader;
- }
-
- #region CTOR
- public IMLReader (string path)
- : this(Interface.GetStreamFromPath (path)){
- }
- public IMLReader (Stream stream)
- : base(stream)
- {
- createInstantiator ();
- }
- /// <summary>
- /// Used to parse xmlFrament with same code generator linked
- /// If ilGen=null, a new Code Generator will be created.
- /// </summary>
- public IMLReader (ILGenerator ilGen, string xmlFragment)
- : base(xmlFragment, XmlNodeType.Element,null){
- il = ilGen;
-
- if (il != null)
- return;
-
- createInstantiator();
- }
- #endregion
-
- void createInstantiator(){
- readRootType();
- InitEmitter();
- emitLoader(RootType);
- Read();//close tag
- }
- /// <summary>
- /// Inits il generator, RootType must have been read first
- /// </summary>
- void InitEmitter(){
-
- dm = new DynamicMethod("dyn_instantiator",
- MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
- CallingConventions.Standard,
- typeof(void),new Type[] {typeof(object), typeof(Interface)}, RootType, true);
-
- il = dm.GetILGenerator(256);
- il.DeclareLocal(typeof(GraphicObject));
- il.Emit(OpCodes.Nop);
- //set local GraphicObject to root object passed as 1st argument
- il.Emit (OpCodes.Ldarg_0);
- il.Emit (OpCodes.Stloc_0);
- CompilerServices.emitSetCurInterface (il);
- }
- void emitLoader(Type crowType){
- string tmpXml = ReadOuterXml ();
-
- il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added
-
- #region Template and ItemTemplates loading
- if (typeof(TemplatedControl).IsAssignableFrom (crowType)) {
- //if its a template, first read template elements
- using (IMLReader reader = new IMLReader (il, tmpXml)) {
-
- string templatePath = reader.GetAttribute ("Template");
- //string itemTemplatePath = reader.GetAttribute ("ItemTemplate");
-
- List<string[]> itemTemplateIds = new List<string[]> ();
- bool inlineTemplate = false;
- reader.Read ();
- int depth = reader.Depth + 1;
- while (reader.Read ()) {
- if (!reader.IsStartElement () || reader.Depth > depth)
- continue;
- if (reader.Name == "Template") {
- inlineTemplate = true;
- reader.Read ();
-
- readChildren (reader, crowType,true);
- } else if (reader.Name == "ItemTemplate") {
- string dataType = "default", datas = "", path = "";
- while (reader.MoveToNextAttribute ()) {
- if (reader.Name == "DataType")
- dataType = reader.Value;
- else if (reader.Name == "Data")
- datas = reader.Value;
- else if (reader.Name == "Path")
- path = reader.Value;
- }
- reader.MoveToElement ();
-
- string itemTmpID;
-
- if (string.IsNullOrEmpty (path)) {
- using (IMLReader iTmp = new IMLReader (null, reader.ReadInnerXml ())) {
- itemTmpID = Guid.NewGuid ().ToString ();
- Interface.Instantiators [itemTmpID] =
- new ItemTemplate (iTmp.RootType, iTmp.GetLoader (), dataType, datas);
- }
- }else{
- if (!reader.IsEmptyElement)
- throw new Exception ("ItemTemplate with Path attribute may not include sub nodes");
- itemTmpID = path;
- Interface.Instantiators [itemTmpID] =
- new ItemTemplate (itemTmpID, dataType, datas);
- }
- itemTemplateIds.Add (new string[] { dataType, itemTmpID, datas });
- }
- }
-
- if (!inlineTemplate) {
- reader.il.Emit (OpCodes.Ldloc_0);//Load this templateControl ref
- if (string.IsNullOrEmpty (templatePath)) {
- reader.il.Emit (OpCodes.Ldnull);//default template loading
- }else{
- reader.il.Emit (OpCodes.Ldarg_1);//load currentInterface
- reader.il.Emit (OpCodes.Ldstr, templatePath); //Load template path string
- reader.il.Emit (OpCodes.Callvirt,//call Interface.Load(path)
- typeof(Interface).GetMethod ("Load", BindingFlags.Instance | BindingFlags.Public));
- }
- reader.il.Emit (OpCodes.Callvirt,//load template
- crowType.GetMethod ("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic));
- }
- foreach (string[] iTempId in itemTemplateIds) {
- reader.il.Emit (OpCodes.Ldloc_0);//load TempControl ref
- reader.il.Emit (OpCodes.Ldfld,//load ItemTemplates dic field
- typeof(TemplatedGroup).GetField("ItemTemplates"));
- reader.il.Emit (OpCodes.Ldstr, iTempId[0]);//load key
- reader.il.Emit (OpCodes.Ldstr, iTempId[1]);//load value
- reader.il.Emit (OpCodes.Callvirt,
- typeof(Interface).GetMethod ("GetItemTemplate"));
- reader.il.Emit (OpCodes.Callvirt,
- typeof(Dictionary<string, ItemTemplate>).GetMethod ("set_Item",
- new Type[] { typeof(string), typeof(ItemTemplate) }));
-
- if (!string.IsNullOrEmpty (iTempId [2])) {
- //expand delegate creation
- reader.il.Emit (OpCodes.Ldloc_0);//load TempControl ref
- reader.il.Emit (OpCodes.Ldfld,//load ItemTemplates dic field
- typeof(TemplatedGroup).GetField ("ItemTemplates"));
- reader.il.Emit (OpCodes.Ldstr, iTempId [0]);//load key
- reader.il.Emit (OpCodes.Callvirt,
- typeof(Dictionary<string, ItemTemplate>).GetMethod ("get_Item",
- new Type[] { typeof(string) }));
- reader.il.Emit (OpCodes.Ldloc_0);//load root of treeView
- reader.il.Emit (OpCodes.Callvirt,
- typeof(ItemTemplate).GetMethod ("CreateExpandDelegate"));
- }
- }
- }
- }
- #endregion
-
- using (IMLReader reader = new IMLReader(il,tmpXml)){
- reader.Read ();
-
- #region Styling and default values loading
- if (reader.HasAttributes) {
- string style = reader.GetAttribute ("Style");
- if (!string.IsNullOrEmpty (style)) {
- PropertyInfo pi = crowType.GetProperty ("Style");
- CompilerServices.EmitSetValue (reader.il, pi, style);
- }
- }
- reader.il.Emit (OpCodes.Ldloc_0);
- reader.il.Emit (OpCodes.Callvirt, typeof(GraphicObject).GetMethod ("loadDefaultValues"));
- #endregion
-
- #region Attributes reading
- if (reader.HasAttributes) {
-
- while (reader.MoveToNextAttribute ()) {
- if (reader.Name == "Style")
- continue;
-
- MemberInfo mi = crowType.GetMember (reader.Name).FirstOrDefault();
- if (mi == null)
- throw new Exception ("Member '" + reader.Name + "' not found in " + crowType.Name);
- if (mi.MemberType == MemberTypes.Event) {
- CompilerServices.emitBindingCreation (reader.il, reader.Name, reader.Value);
- continue;
- }
- PropertyInfo pi = mi as PropertyInfo;
- if (pi == null)
- throw new Exception ("Member '" + reader.Name + "' not found in " + crowType.Name);
-
- if (reader.Value.StartsWith ("{")) {
- CompilerServices.emitBindingCreation (reader.il, reader.Name, reader.Value.Substring (1, reader.Value.Length - 2));
- }else
- CompilerServices.EmitSetValue (reader.il, pi, reader.Value);
-
- }
- reader.MoveToElement ();
- }
- #endregion
-
- if (reader.IsEmptyElement) {
- reader.il.Emit (OpCodes.Pop);//pop saved ref to current object
- return;
- }
-
- readChildren (reader, crowType);
- }
- il.Emit (OpCodes.Pop);//pop saved ref to current object
- }
- /// <summary>
- /// Parse child node an generate corresponding msil
- /// </summary>
- void readChildren(IMLReader reader, Type crowType, bool templateLoading = false){
- MethodInfo miAddChild = null;
- bool endTagReached = false;
- while (reader.Read()){
- switch (reader.NodeType) {
- case XmlNodeType.EndElement:
- endTagReached = true;
- break;
- case XmlNodeType.Element:
- //Templates
- if (reader.Name == "Template" ||
- reader.Name == "ItemTemplate") {
- reader.Skip ();
- continue;
- }
-
- if (miAddChild == null) {
- if (typeof(Group).IsAssignableFrom (crowType))
- miAddChild = typeof(Group).GetMethod ("AddChild");
- else if (typeof(Container).IsAssignableFrom (crowType))
- miAddChild = typeof(Container).GetMethod ("SetChild");
- else if (typeof(TemplatedContainer).IsAssignableFrom (crowType) && !templateLoading)
- miAddChild = typeof(TemplatedContainer).GetProperty ("Content").GetSetMethod ();
- else if (typeof(TemplatedGroup).IsAssignableFrom (crowType) && !templateLoading)
- miAddChild = typeof(TemplatedGroup).GetMethod ("AddItem",
- BindingFlags.Instance | BindingFlags.Public);
- else if (typeof(TemplatedControl).IsAssignableFrom (crowType))
- miAddChild = typeof(TemplatedControl).GetMethod ("loadTemplate",
- BindingFlags.Instance | BindingFlags.NonPublic);
- else if (typeof(PrivateContainer).IsAssignableFrom (crowType))
- miAddChild = typeof(PrivateContainer).GetMethod ("SetChild",
- BindingFlags.Instance | BindingFlags.NonPublic);
- }
- //push current instance on stack for parenting
- //loc_0 will be used for child
- reader.il.Emit (OpCodes.Ldloc_0);
-
- Type t = Type.GetType ("Crow." + reader.Name);
- if (t == null) {
- Assembly a = Assembly.GetEntryAssembly ();
- foreach (Type expT in a.GetExportedTypes ()) {
- if (expT.Name == reader.Name)
- t = expT;
- }
- }
- if (t == null)
- throw new Exception (reader.Name + " type not found");
-
- reader.il.Emit (OpCodes.Newobj, t.GetConstructors () [0]);//TODO:search parameterless ctor
- reader.il.Emit (OpCodes.Stloc_0);//child is now loc_0
- CompilerServices.emitSetCurInterface (il);
-
- reader.emitLoader (t);
-
- reader.il.Emit (OpCodes.Ldloc_0);//load child on stack for parenting
- if (miAddChild == null)
- System.Diagnostics.Debugger.Break ();
- reader.il.Emit (OpCodes.Callvirt, miAddChild);
- reader.il.Emit (OpCodes.Stloc_0); //reset local to current go
- reader.il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added
- break;
- }
- if (endTagReached)
- break;
- }
- }
- /// <summary>
- /// read first node to set GraphicObject class for loading
- /// and let reader position on that node
- /// </summary>
- Type readRootType ()
- {
- string root = "Object";
- while (Read()) {
- if (NodeType == XmlNodeType.Element) {
- root = this.Name;
- break;
- }
- }
-
- Type t = Type.GetType ("Crow." + root);
- if (t == null) {
- Assembly a = Assembly.GetEntryAssembly ();
- foreach (Type expT in a.GetExportedTypes ()) {
- if (expT.Name == root)
- t = expT;
- }
- }
- RootType = t;
- return t;
- }
- }
-}
-
diff --git a/src/Instantiator.cs b/src/Instantiator.cs
index 1a8cdb75..402df1cc 100644
--- a/src/Instantiator.cs
+++ b/src/Instantiator.cs
@@ -23,85 +23,962 @@ using System.Threading;
using System.IO;
using System.Text;
using System.Diagnostics;
+using System.Xml;
+using System.Reflection.Emit;
+using System.Reflection;
+using System.Collections.Generic;
+using System.Linq;
+using Crow.IML;
namespace Crow
{
- public delegate void InstanciatorInvoker(object instance, Interface iface);
+ public delegate object InstanciatorInvoker(Interface iface);
+ /// <summary>
+ /// Instantiator
+ /// </summary>
public class Instantiator
{
+ #region Dynamic Method ID generation
+ static long curId = 0;
+ internal static long NewId {
+ get { return curId++; }
+ }
+ #endregion
+
public Type RootType;
InstanciatorInvoker loader;
- string imlPath;
+ internal string sourcePath;
#region CTOR
- public Instantiator (string path){
- imlPath = path;
-
- #if DEBUG_LOAD
+ public Instantiator (string path) : this (Interface.GetStreamFromPath(path)) {
+ sourcePath = path;
+ }
+ public Instantiator (Stream stream)
+ {
+#if DEBUG_LOAD
Stopwatch loadingTime = new Stopwatch ();
loadingTime.Start ();
- #endif
- try {
- using (IMLReader itr = new IMLReader (path)){
- loader = itr.GetLoader ();
- RootType = itr.RootType;
- }
- } catch (Exception ex) {
- throw new Exception ("Error loading <" + path + ">:\n", ex);
+#endif
+ using (XmlTextReader itr = new XmlTextReader (stream)) {
+ parseIML (itr);
}
-
- #if DEBUG_LOAD
+#if DEBUG_LOAD
loadingTime.Stop ();
Debug.WriteLine ("IML Instantiator creation '{2}' : {0} ticks, {1} ms",
- loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, path);
- #endif
+ loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, imlPath);
+#endif
}
- public static Instantiator CreateFromImlFragment(string fragment){
+ public Instantiator (Type _root, InstanciatorInvoker _loader)
+ {
+ RootType = _root;
+ loader = _loader;
+ }
+ public static Instantiator CreateFromImlFragment (string fragment)
+ {
try {
- using (Stream s = new MemoryStream(Encoding.UTF8.GetBytes(fragment))){
- return new Instantiator(s);
+ using (Stream s = new MemoryStream (Encoding.UTF8.GetBytes (fragment))) {
+ return new Instantiator (s);
}
} catch (Exception ex) {
throw new Exception ("Error loading fragment:\n" + fragment + "\n", ex);
}
}
- public Instantiator (Stream stream){
- #if DEBUG_LOAD
- Stopwatch loadingTime = new Stopwatch ();
- loadingTime.Start ();
- #endif
- using (IMLReader itr = new IMLReader (stream)){
- loader = itr.GetLoader ();
- RootType = itr.RootType;
+ #endregion
+
+ public GraphicObject CreateInstance(Interface iface){
+ return loader (iface) as GraphicObject;
+ }
+
+ List<DynamicMethod> dsValueChangedDynMeths = new List<DynamicMethod>();
+ List<Delegate> cachedDelegates = new List<Delegate>();
+ List<int> templateCachedDelegateIndices = new List<int>();//store indices of template delegate to be handled by root parentChanged event
+ Delegate templateBinding;
+
+ #region IML parsing
+ /// <summary>
+ /// Parses IML and build a dynamic method that will be used to instanciate one or multiple occurence of the IML file or fragment
+ /// </summary>
+ void parseIML (XmlTextReader reader) {
+ Context ctx = new Context (findRootType (reader));
+
+ ctx.nodesStack.Push (new Node (ctx.RootType));
+ emitLoader (reader, ctx);
+ ctx.nodesStack.Pop ();
+
+ foreach (int idx in templateCachedDelegateIndices)
+ ctx.emitCachedDelegateHandlerAddition(idx, CompilerServices.eiLogicalParentChanged);
+
+ ctx.ResolveNamedTargets ();
+
+ emitBindingDelegates (ctx);
+
+ ctx.il.Emit (OpCodes.Ldloc_0);//load root obj to return
+ ctx.il.Emit(OpCodes.Ret);
+
+ reader.Read ();//close tag
+ RootType = ctx.RootType;
+ loader = (InstanciatorInvoker)ctx.dm.CreateDelegate (typeof (InstanciatorInvoker), this);
+ }
+ /// <summary>
+ /// read first node to set GraphicObject class for loading
+ /// and let reader position on that node
+ /// </summary>
+ Type findRootType (XmlTextReader reader)
+ {
+ string root = "Object";
+ while (reader.Read ()) {
+ if (reader.NodeType == XmlNodeType.Element) {
+ root = reader.Name;
+ break;
+ }
}
- #if DEBUG_LOAD
- loadingTime.Stop ();
- Debug.WriteLine ("IML Instantiator creation '{2}' : {0} ticks, {1} ms",
- loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, imlPath);
- #endif
+
+ Type t = Type.GetType ("Crow." + root);
+ if (t == null) {
+ Assembly a = Assembly.GetEntryAssembly ();
+ foreach (Type expT in a.GetExportedTypes ()) {
+ if (expT.Name == root)
+ t = expT;
+ }
+ }
+ return t;
}
- public Instantiator (Type _root, InstanciatorInvoker _loader)
+ void emitLoader (XmlTextReader reader, Context ctx)
{
- RootType = _root;
- loader = _loader;
+ string tmpXml = reader.ReadOuterXml ();
+
+ if (ctx.nodesStack.Peek().HasTemplate)
+ emitTemplateLoad (ctx, tmpXml);
+
+ emitGOLoad (ctx, tmpXml);
+
+ //emitCheckAndBindValueChanged (ctx);
+ }
+ void emitTemplateLoad (Context ctx, string tmpXml) {
+ //if its a template, first read template elements
+ using (XmlTextReader reader = new XmlTextReader (tmpXml, XmlNodeType.Element, null)) {
+ List<string[]> itemTemplateIds = new List<string[]> ();
+ bool inlineTemplate = false;
+
+ string templatePath = reader.GetAttribute ("Template");
+
+ reader.Read ();
+ int depth = reader.Depth + 1;
+ while (reader.Read ()) {
+ if (!reader.IsStartElement () || reader.Depth > depth)
+ continue;
+ if (reader.Name == "Template") {
+ inlineTemplate = true;
+ reader.Read ();
+ readChildren (reader, ctx, -1);
+ } else if (reader.Name == "ItemTemplate") {
+ string dataType = "default", datas = "", path = "";
+ while (reader.MoveToNextAttribute ()) {
+ if (reader.Name == "DataType")
+ dataType = reader.Value;
+ else if (reader.Name == "Data")
+ datas = reader.Value;
+ else if (reader.Name == "Path")
+ path = reader.Value;
+ }
+ reader.MoveToElement ();
+
+ string itemTmpID;
+
+ if (string.IsNullOrEmpty (path)) {
+ itemTmpID = Guid.NewGuid ().ToString ();
+ Interface.Instantiators [itemTmpID] =
+ new ItemTemplate (new MemoryStream (Encoding.UTF8.GetBytes (reader.ReadInnerXml ())), dataType, datas);
+
+ } else {
+ if (!reader.IsEmptyElement)
+ throw new Exception ("ItemTemplate with Path attribute may not include sub nodes");
+ itemTmpID = path;
+ Interface.Instantiators [itemTmpID] =
+ new ItemTemplate (Interface.GetStreamFromPath (itemTmpID), dataType, datas);
+ }
+ itemTemplateIds.Add (new string [] { dataType, itemTmpID, datas });
+ }
+ }
+
+ if (!inlineTemplate) {//load from path or default template
+ ctx.il.Emit (OpCodes.Ldloc_0);//Load current templatedControl ref
+ if (string.IsNullOrEmpty (templatePath)) {
+ ctx.il.Emit (OpCodes.Ldnull);//default template loading
+ } else {
+ ctx.il.Emit (OpCodes.Ldarg_1);//load currentInterface
+ ctx.il.Emit (OpCodes.Ldstr, templatePath); //Load template path string
+ ctx.il.Emit (OpCodes.Callvirt,//call Interface.Load(path)
+ CompilerServices.miIFaceLoad);
+ }
+ ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miLoadTmp);//load template
+ }
+ //copy item templates (review this)
+ foreach (string [] iTempId in itemTemplateIds) {
+ ctx.il.Emit (OpCodes.Ldloc_0);//load TempControl ref
+ ctx.il.Emit (OpCodes.Ldfld, CompilerServices.fldItemTemplates);//load ItemTemplates dic field
+ ctx.il.Emit (OpCodes.Ldstr, iTempId [0]);//load key
+ ctx.il.Emit (OpCodes.Ldstr, iTempId [1]);//load value
+ ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miGetITemp);
+ ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miAddITemp);
+
+ if (!string.IsNullOrEmpty (iTempId [2])) {
+ //expand delegate creation
+ ctx.il.Emit (OpCodes.Ldloc_0);//load TempControl ref
+ ctx.il.Emit (OpCodes.Ldfld, CompilerServices.fldItemTemplates);
+ ctx.il.Emit (OpCodes.Ldstr, iTempId [0]);//load key
+ ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miGetITempFromDic);
+ ctx.il.Emit (OpCodes.Ldloc_0);//load root of treeView
+ ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miCreateExpDel);
+ }
+ }
+ }
+ }
+ void emitGOLoad (Context ctx, string tmpXml) {
+ using (XmlTextReader reader = new XmlTextReader (tmpXml, XmlNodeType.Element, null)) {
+ reader.Read ();
+
+ #region Styling and default values loading
+ if (reader.HasAttributes) {
+ string style = reader.GetAttribute ("Style");
+ if (!string.IsNullOrEmpty (style))
+ CompilerServices.EmitSetValue (ctx.il, CompilerServices.piStyle, style);
+ }
+ ctx.il.Emit (OpCodes.Ldloc_0);
+ ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miLoadDefaultVals);
+ #endregion
+
+ #region Attributes reading
+ if (reader.HasAttributes) {
+
+ while (reader.MoveToNextAttribute ()) {
+ if (reader.Name == "Style")
+ continue;
+
+ MemberInfo mi = ctx.CurrentNodeType.GetMember (reader.Name).FirstOrDefault ();
+ if (mi == null)
+ throw new Exception ("Member '" + reader.Name + "' not found in " + ctx.CurrentNodeType.Name);
+
+ if (mi.MemberType == MemberTypes.Event) {
+ foreach (string exp in CompilerServices.splitOnSemiColumnOutsideAccolades(reader.Value)) {
+ string trimed = exp.Trim();
+ if (trimed.StartsWith ("{", StringComparison.OrdinalIgnoreCase))
+ compileAndStoreDynHandler (ctx, mi as EventInfo, trimed.Substring (1, trimed.Length - 2));
+ else
+ emitHandlerBinding (ctx, mi as EventInfo, trimed);
+ }
+
+ continue;
+ }
+ PropertyInfo pi = mi as PropertyInfo;
+ if (pi == null)
+ throw new Exception ("Member '" + reader.Name + "' is not a property in " + ctx.CurrentNodeType.Name);
+
+ if (pi.Name == "Name")
+ ctx.StoreCurrentName (reader.Value);
+
+ if (reader.Value.StartsWith ("{", StringComparison.OrdinalIgnoreCase))
+ readPropertyBinding (ctx, reader.Name, reader.Value.Substring (1, reader.Value.Length - 2));
+ else
+ CompilerServices.EmitSetValue (ctx.il, pi, reader.Value);
+
+ }
+ reader.MoveToElement ();
+ }
+ #endregion
+
+ readChildren (reader, ctx);
+
+ ctx.nodesStack.ResetCurrentNodeIndex ();
+ }
+ }
+
+ /// <summary>
+ /// Parse child node an generate corresponding msil
+ /// </summary>
+ void readChildren (XmlTextReader reader, Context ctx, int startingIdx = 0)
+ {
+ bool endTagReached = false;
+ int nodeIdx = startingIdx;
+ while (reader.Read ()) {
+ switch (reader.NodeType) {
+ case XmlNodeType.EndElement:
+ endTagReached = true;
+ break;
+ case XmlNodeType.Element:
+ //skip Templates
+ if (reader.Name == "Template" ||
+ reader.Name == "ItemTemplate") {
+ reader.Skip ();
+ continue;
+ }
+
+ //push 2x current instance on stack for parenting and reseting loc0 to parent
+ //loc_0 will be used for child
+ ctx.il.Emit (OpCodes.Ldloc_0);
+ ctx.il.Emit (OpCodes.Ldloc_0);
+
+ Type t = Type.GetType ("Crow." + reader.Name);
+ if (t == null) {
+ Assembly a = Assembly.GetEntryAssembly ();
+ foreach (Type expT in a.GetExportedTypes ()) {
+ if (expT.Name == reader.Name)
+ t = expT;
+ }
+ }
+ if (t == null)
+ throw new Exception (reader.Name + " type not found");
+
+ ctx.il.Emit (OpCodes.Newobj, t.GetConstructors () [0]);//TODO:search parameterless ctor
+ ctx.il.Emit (OpCodes.Stloc_0);//child is now loc_0
+ CompilerServices.emitSetCurInterface (ctx.il);
+
+ ctx.nodesStack.Push (new Node (t, nodeIdx));
+ emitLoader (reader, ctx);
+ ctx.nodesStack.Pop ();
+
+ ctx.il.Emit (OpCodes.Ldloc_0);//load child on stack for parenting
+ ctx.il.Emit (OpCodes.Callvirt, ctx.nodesStack.Peek().GetAddMethod(nodeIdx));
+ ctx.il.Emit (OpCodes.Stloc_0); //reset local to current go
+
+ nodeIdx++;
+
+ break;
+ }
+ if (endTagReached)
+ break;
+ }
}
#endregion
- public GraphicObject CreateInstance(Interface iface){
- GraphicObject tmp = (GraphicObject)Activator.CreateInstance(RootType);
- loader (tmp, iface);
- return tmp;
+ void readPropertyBinding (Context ctx, string sourceMember, string expression)
+ {
+ NodeAddress sourceNA = ctx.CurrentNodeAddress;
+ BindingDefinition bindingDef = splitBindingExp (sourceNA, sourceMember, expression);
+
+ if (bindingDef.IsDataSourceBinding)//bind on data source
+ emitDataSourceBindings (ctx, bindingDef);
+ else
+ ctx.StorePropertyBinding (bindingDef);
}
- public string GetImlSourcesCode(){
- try {
- using (StreamReader sr = new StreamReader (imlPath))
- return sr.ReadToEnd();
- } catch (Exception ex) {
- throw new Exception ("Error getting sources for <" + imlPath + ">:", ex);
+
+ /// <summary>
+ /// Splits the binding expression
+ /// </summary>
+ /// <returns><c>true</c>, if it's a two way binding, <c>false</c> otherwise.</returns>
+ /// <param name="sourceNA">Source Node address</param>
+ /// <param name="expression">Expression.</param>
+ /// <param name="targetNA">Target Node Address</param>
+ /// <param name="targetMember">Target member name</param>
+ /// <param name="targetName">Target node name</param>
+ BindingDefinition splitBindingExp(NodeAddress sourceNA, string sourceMember, string expression){
+ BindingDefinition bindingDef = new BindingDefinition(sourceNA, sourceMember);
+ if (string.IsNullOrEmpty (expression)) {
+ return bindingDef;
+ } else {
+ if (expression.StartsWith ("²")) {
+ bindingDef.TwoWay = true;
+ expression = expression.Substring (1);
+ }
+ string[] bindingExp = expression.Split ('/');
+
+ if (bindingExp.Length > 1)
+ bindingDef.TargetNA = CompilerServices.getNodeAdressFromBindingExp (sourceNA, bindingExp);
+
+ string [] bindTrg = bindingExp.Last().Split ('.');
+
+ if (bindTrg.Length == 1)
+ bindingDef.TargetMember = bindTrg [0];
+ else if (bindTrg.Length == 2) {
+ //named target
+ bindingDef.TargetName = bindTrg[0];
+ bindingDef.TargetMember = bindTrg [1];
+ } else
+ throw new Exception ("Syntax error in binding, expected 'go dot member'");
}
+
+ return bindingDef;
+ }
+
+ #region Emit Helper
+ void dataSourceChangedEmitHelper(object dscSource, object dataSource, int dynMethIdx){
+ if (dataSource is IValueChange)
+ (dataSource as IValueChange).ValueChanged +=
+ (EventHandler<ValueChangeEventArgs>)dsValueChangedDynMeths [dynMethIdx].CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>), dscSource);
+ }
+ #endregion
+
+ #region Event Bindings
+ /// <summary>
+ /// Compile events expression in IML attributes, and store the result in the instanciator
+ /// Those handlers will be bound when instatiing
+ /// </summary>
+ void compileAndStoreDynHandler (Context ctx, EventInfo sourceEvent, string expression)
+ {
+ //store event handler dynamic method in instanciator
+ int dmIdx = cachedDelegates.Count;
+ cachedDelegates.Add (CompilerServices.compileDynEventHandler (sourceEvent, expression, ctx.CurrentNodeAddress));
+ ctx.emitCachedDelegateHandlerAddition(dmIdx, sourceEvent);
}
+ /// <summary> Emits handler method bindings </summary>
+ void emitHandlerBinding (Context ctx, EventInfo sourceEvent, string expression){
+ NodeAddress currentNode = ctx.CurrentNodeAddress;
+ BindingDefinition bindingDef = splitBindingExp (currentNode, sourceEvent.Name, expression);
+
+ if (bindingDef.IsTemplateBinding | bindingDef.IsDataSourceBinding) {
+ //we need to bind datasource method to source event
+ DynamicMethod dm = new DynamicMethod ("dyn_dschangedForHandler" + NewId,
+ typeof(void),
+ CompilerServices.argsBoundDSChange, true);
+
+ ILGenerator il = dm.GetILGenerator (256);
+ System.Reflection.Emit.Label cancel = il.DefineLabel ();
+
+ il.DeclareLocal (typeof(MethodInfo));//used to cancel binding if method doesn't exist
+
+ il.Emit (OpCodes.Nop);
+
+ emitRemoveOldDataSourceHandler (il, sourceEvent.Name, bindingDef.TargetMember, false);
+
+ //fetch method in datasource and test if it exist
+ il.Emit (OpCodes.Ldarg_2);//load new datasource
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ il.Emit (OpCodes.Brfalse, cancel);//cancel if new datasource is null
+ il.Emit (OpCodes.Ldarg_2);//load new datasource
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ il.Emit (OpCodes.Ldstr, bindingDef.TargetMember);//load handler method name
+ il.Emit (OpCodes.Call, CompilerServices.miGetMethInfoWithRefx);
+ il.Emit (OpCodes.Stloc_0);//save MethodInfo
+ il.Emit (OpCodes.Ldloc_0);//push mi for test if null
+
+ il.Emit (OpCodes.Brfalse, cancel);
+
+ il.Emit (OpCodes.Ldarg_1);//load datasource change source where the event is as 1st arg of handler.add
+ if (bindingDef.IsTemplateBinding)//fetch source instance with address
+ CompilerServices.emitGetInstance (il, bindingDef.SourceNA);
+
+ //load handlerType of sourceEvent to create delegate (1st arg)
+ il.Emit (OpCodes.Ldtoken, sourceEvent.EventHandlerType);
+ il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle);
+ il.Emit (OpCodes.Ldarg_2);//load new datasource where the method is defined
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ il.Emit (OpCodes.Ldloc_0);//load methodInfo (3rd arg)
+
+ il.Emit (OpCodes.Callvirt, CompilerServices.miCreateBoundDel);
+ il.Emit (OpCodes.Callvirt, sourceEvent.AddMethod);//call add event
+
+ System.Reflection.Emit.Label finish = il.DefineLabel ();
+ il.Emit (OpCodes.Br, finish);
+ il.MarkLabel (cancel);
+ il.EmitWriteLine (string.Format ("Handler method '{0}' for '{1}' not found in new dataSource ", bindingDef.TargetMember, sourceEvent.Name));
+ il.MarkLabel (finish);
+ il.Emit (OpCodes.Ret);
+
+ //store dschange delegate in instatiator instance for access while instancing graphic object
+ int delDSIndex = cachedDelegates.Count;
+ cachedDelegates.Add (dm.CreateDelegate (CompilerServices.ehTypeDSChange, this));
+
+ if (bindingDef.IsDataSourceBinding)
+ ctx.emitCachedDelegateHandlerAddition (delDSIndex, CompilerServices.eiDSChange);
+ else //template handler binding, will be added to root parentChanged
+ templateCachedDelegateIndices.Add (delDSIndex);
+ } else {//normal in tree handler binding, store until tree is complete (end of parse)
+ ctx.UnresolvedTargets.Add (new EventBinding (
+ bindingDef.SourceNA, sourceEvent,
+ bindingDef.TargetNA, bindingDef.TargetMember, bindingDef.TargetName));
+ }
+ }
+ #endregion
+
+ #region Property Bindings
+ /// <summary>
+ /// Create and store in the instanciator the ValueChanged delegates
+ /// those delegates uses grtree functions to set destination value so they don't
+ /// need to be bound to destination instance as in the ancient system.
+ /// </summary>
+ void emitBindingDelegates(Context ctx){
+ foreach (KeyValuePair<NodeAddress,Dictionary<string, List<MemberAddress>>> bindings in ctx.Bindings ) {
+ if (bindings.Key.Count == 0)//template binding
+ emitTemplateBindings (ctx, bindings.Value);
+ else
+ emitPropertyBindings (ctx, bindings.Key, bindings.Value);
+ }
+ }
+ void emitPropertyBindings(Context ctx, NodeAddress origine, Dictionary<string, List<MemberAddress>> bindings){
+ Type origineNodeType = origine.NodeType;
+
+ //value changed dyn method
+ DynamicMethod dm = new DynamicMethod ("dyn_valueChanged" + NewId,
+ typeof (void), CompilerServices.argsValueChange, true);
+ ILGenerator il = dm.GetILGenerator (256);
+
+ System.Reflection.Emit.Label endMethod = il.DefineLabel ();
+
+ il.DeclareLocal (CompilerServices.TObject);
+
+ il.Emit (OpCodes.Nop);
+
+ int i = 0;
+ foreach (KeyValuePair<string, List<MemberAddress>> bindingCase in bindings ) {
+
+ System.Reflection.Emit.Label nextTest = il.DefineLabel ();
+
+ #region member name test
+ //load source member name
+ il.Emit (OpCodes.Ldarg_1);
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiVCMbName);
+
+ il.Emit (OpCodes.Ldstr, bindingCase.Key);//load name to test
+ il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
+ il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
+ il.Emit (OpCodes.Brfalse, nextTest);//if not equal, jump to next case
+ #endregion
+
+ #region destination member affectations
+ PropertyInfo piOrig = origineNodeType.GetProperty (bindingCase.Key);
+ Type origineType = null;
+ if (piOrig != null)
+ origineType = piOrig.PropertyType;
+ foreach (MemberAddress ma in bindingCase.Value) {
+ //first we have to load destination instance onto the stack, it is access
+ //with graphic tree functions deducted from nodes topology
+ il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event
+
+ NodeAddress destination = ma.Address;
+
+ if (destination.Count == 0){//template reverse binding
+ //fetch destination instance (which is the template root)
+ for (int j = 0; j < origine.Count ; j++)
+ il.Emit(OpCodes.Callvirt, CompilerServices.miGetLogicalParent);
+ }else
+ CompilerServices.emitGetInstance (il, origine, destination);
+
+ if (origineType != null && destination.Count > 0){//else, prop less binding or reverse template bind, no init requiered
+ //for initialisation dynmeth, push destination instance loc_0 is root node in ctx
+ ctx.il.Emit(OpCodes.Ldloc_0);
+ CompilerServices.emitGetInstance (ctx.il, destination);
+
+ //init dynmeth: load actual value from origine
+ ctx.il.Emit (OpCodes.Ldloc_0);
+ CompilerServices.emitGetInstance (ctx.il, origine);
+ ctx.il.Emit (OpCodes.Callvirt, origineNodeType.GetProperty (bindingCase.Key).GetGetMethod());
+ }
+ //load new value
+ il.Emit (OpCodes.Ldarg_1);
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiVCNewValue);
+
+ if (origineType == null)//property less binding, no init
+ CompilerServices.emitConvert (il, ma.Property.PropertyType);
+ else if (destination.Count > 0) {
+ if (origineType.IsValueType)
+ ctx.il.Emit(OpCodes.Box, origineType);
+
+ CompilerServices.emitConvert (ctx.il, origineType, ma.Property.PropertyType);
+ CompilerServices.emitConvert (il, origineType, ma.Property.PropertyType);
+
+ ctx.il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());//set init value
+ } else {// reverse templateBinding
+ il.Emit (OpCodes.Ldstr, ma.memberName);//arg 3 of setValueWithReflexion
+ il.Emit (OpCodes.Call, CompilerServices.miSetValWithRefx);
+ continue;
+ }
+ il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());//set value on value changes
+ }
+ #endregion
+ il.Emit (OpCodes.Br, endMethod);
+ il.MarkLabel (nextTest);
+
+ i++;
+ }
+
+ il.MarkLabel (endMethod);
+ il.Emit (OpCodes.Ret);
+
+ //store and emit Add in ctx
+ int dmIdx = cachedDelegates.Count;
+ cachedDelegates.Add (dm.CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>)));
+ ctx.emitCachedDelegateHandlerAddition (dmIdx, CompilerServices.eiValueChange, origine);
+ }
+ void emitTemplateBindings(Context ctx, Dictionary<string, List<MemberAddress>> bindings){
+ //value changed dyn method
+ DynamicMethod dm = new DynamicMethod ("dyn_tmpValueChanged",
+ typeof (void), CompilerServices.argsValueChange, true);
+ ILGenerator il = dm.GetILGenerator (256);
+
+ //create parentchanged dyn meth in parallel to have only one loop over bindings
+ DynamicMethod dmPC = new DynamicMethod ("dyn_InitAndLogicalParentChanged",
+ typeof (void),
+ CompilerServices.argsBoundDSChange, true);
+ ILGenerator ilPC = dmPC.GetILGenerator (256);
+
+ il.Emit (OpCodes.Nop);
+ ilPC.Emit (OpCodes.Nop);
+
+ System.Reflection.Emit.Label endMethod = il.DefineLabel ();
+
+ il.DeclareLocal (CompilerServices.TObject);
+ ilPC.DeclareLocal (CompilerServices.TObject);//used for checking propery less bindings
+ ilPC.DeclareLocal (typeof(MemberInfo));//used for checking propery less bindings
+
+ System.Reflection.Emit.Label cancel = ilPC.DefineLabel ();
+
+ #region Unregister previous parent event handler
+ //unregister previous parent handler if not null
+ ilPC.Emit (OpCodes.Ldarg_2);//load old parent
+ ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCOldDS);
+ ilPC.Emit (OpCodes.Brfalse, cancel);//old parent is null
+
+ ilPC.Emit (OpCodes.Ldarg_2);//load old parent
+ ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCOldDS);
+ //Load cached delegate
+ ilPC.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+ ilPC.Emit(OpCodes.Ldfld, CompilerServices.fiTemplateBinding);
+
+ //add template bindings dynValueChanged delegate to new parent event
+ ilPC.Emit(OpCodes.Callvirt, CompilerServices.eiValueChange.RemoveMethod);//call remove event
+ #endregion
+
+ ilPC.MarkLabel(cancel);
+
+ #region check if new parent is null
+ cancel = ilPC.DefineLabel ();
+ ilPC.Emit (OpCodes.Ldarg_2);//load datasource change arg
+ ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ ilPC.Emit (OpCodes.Brfalse, cancel);//new ds is null
+ #endregion
+
+ int i = 0;
+ foreach (KeyValuePair<string, List<MemberAddress>> bindingCase in bindings ) {
+
+ System.Reflection.Emit.Label nextTest = il.DefineLabel ();
+
+ #region member name test
+ //load source member name
+ il.Emit (OpCodes.Ldarg_1);
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiVCMbName);
+
+ il.Emit (OpCodes.Ldstr, bindingCase.Key);//load name to test
+ il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
+ il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
+ il.Emit (OpCodes.Brfalse, nextTest);//if not equal, jump to next case
+ #endregion
+
+ #region destination member affectations
+
+ foreach (MemberAddress ma in bindingCase.Value) {
+ if (ma.Address.Count == 0){
+ Debug.WriteLine("\t\tBUG: reverse template binding in normal template binding");
+ continue;//template binding
+ }
+ //first we try to get memberInfo of new parent, if it doesn't exist, it's a propery less binding
+ ilPC.Emit (OpCodes.Ldarg_2);//load new parent onto the stack for handler addition
+ ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ ilPC.Emit (OpCodes.Stloc_0);//save new parent
+ //get parent type
+ ilPC.Emit (OpCodes.Ldloc_0);//push parent instance
+ ilPC.Emit (OpCodes.Ldstr, bindingCase.Key);//load member name
+ ilPC.Emit (OpCodes.Call, CompilerServices.miGetMembIinfoWithRefx);
+ ilPC.Emit (OpCodes.Stloc_1);//save memberInfo
+ ilPC.Emit (OpCodes.Ldloc_1);//push mi for test if null
+ System.Reflection.Emit.Label propLessReturn = ilPC.DefineLabel ();
+ ilPC.Emit (OpCodes.Brfalse, propLessReturn);
+
+
+ //first we have to load destination instance onto the stack, it is access
+ //with graphic tree functions deducted from nodes topology
+ il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event
+ CompilerServices.emitGetChild (il, typeof(TemplatedControl), -1);
+ CompilerServices.emitGetInstance (il, ma.Address);
+
+ ilPC.Emit (OpCodes.Ldarg_2);//load destination instance to set actual value of member
+ ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ CompilerServices.emitGetChild (ilPC, typeof(TemplatedControl), -1);
+ CompilerServices.emitGetInstance (ilPC, ma.Address);
+
+ //load new value
+ il.Emit (OpCodes.Ldarg_1);
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiVCNewValue);
+
+ //for the parent changed dyn meth we need to fetch actual value for initialisation thrue reflexion
+ ilPC.Emit (OpCodes.Ldloc_0);//push root instance of instanciator as parentChanged source
+ ilPC.Emit (OpCodes.Ldloc_1);//push mi for value fetching
+ ilPC.Emit (OpCodes.Call, CompilerServices.miGetValWithRefx);
+
+ CompilerServices.emitConvert (il, ma.Property.PropertyType);
+ CompilerServices.emitConvert (ilPC, ma.Property.PropertyType);
+
+ il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());
+ ilPC.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());
+
+ ilPC.MarkLabel(propLessReturn);
+ }
+ #endregion
+ il.Emit (OpCodes.Br, endMethod);
+ il.MarkLabel (nextTest);
+
+ i++;
+ }
+ //il.Emit (OpCodes.Pop);
+ il.MarkLabel (endMethod);
+ il.Emit (OpCodes.Ret);
+
+ //store template bindings in instanciator
+ templateBinding = dm.CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>));
+
+ #region emit LogicalParentChanged method
+
+ //load new parent onto the stack for handler addition
+ ilPC.Emit (OpCodes.Ldarg_2);
+ ilPC.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+
+ //Load cached delegate
+ ilPC.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+ ilPC.Emit(OpCodes.Ldfld, CompilerServices.fiTemplateBinding);
+
+ //add template bindings dynValueChanged delegate to new parent event
+ ilPC.Emit(OpCodes.Callvirt, CompilerServices.eiValueChange.AddMethod);//call add event
+
+ ilPC.MarkLabel (cancel);
+ ilPC.Emit (OpCodes.Ret);
+
+ //store dschange delegate in instatiator instance for access while instancing graphic object
+ int delDSIndex = cachedDelegates.Count;
+ cachedDelegates.Add(dmPC.CreateDelegate (CompilerServices.ehTypeDSChange, this));
+ #endregion
+
+ ctx.emitCachedDelegateHandlerAddition(delDSIndex, CompilerServices.eiLogicalParentChanged);
+ }
+ /// <summary>
+ /// create the valuechanged handler, the datasourcechanged handler and emit event handling
+ /// </summary>
+ void emitDataSourceBindings(Context ctx, BindingDefinition bindingDef){
+ DynamicMethod dm = null;
+ ILGenerator il = null;
+ int dmVC = 0;
+ PropertyInfo piSource = ctx.CurrentNodeType.GetProperty(bindingDef.SourceMember);
+ //if no dataSource member name is provided, valuechange is not handle and datasource change
+ //will be used as origine value
+ string delName = "dyn_DSvalueChanged" + NewId;
+ if (!string.IsNullOrEmpty(bindingDef.TargetMember)){
+ #region create valuechanged method
+ dm = new DynamicMethod (delName,
+ typeof (void),
+ CompilerServices.argsBoundValueChange, true);
+
+ il = dm.GetILGenerator (256);
+
+ System.Reflection.Emit.Label endMethod = il.DefineLabel ();
+
+ il.DeclareLocal (CompilerServices.TObject);
+
+ il.Emit (OpCodes.Nop);
+
+ //load value changed member name onto the stack
+ il.Emit (OpCodes.Ldarg_2);
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiVCMbName);
+
+ //test if it's the expected one
+ il.Emit (OpCodes.Ldstr, bindingDef.TargetMember);
+ il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
+ il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
+ il.Emit (OpCodes.Brfalse, endMethod);
+ //set destination member with valueChanged new value
+ //load destination ref
+ il.Emit (OpCodes.Ldarg_0);
+ //load new value onto the stack
+ il.Emit (OpCodes.Ldarg_2);
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiVCNewValue);
+
+ //by default, source value type is deducted from target member type to allow
+ //memberless binding, if targetMember exists, it will be used to determine target
+ //value type for conversion
+
+ CompilerServices.emitConvert (il, piSource.PropertyType);
+
+ il.Emit (OpCodes.Callvirt, piSource.GetSetMethod ());
+
+ il.MarkLabel (endMethod);
+ il.Emit (OpCodes.Ret);
+
+ //vc dyn meth is stored in a cached list, it will be bound to datasource only
+ //when datasource of source graphic object changed
+ dmVC = dsValueChangedDynMeths.Count;
+ dsValueChangedDynMeths.Add (dm);
+ #endregion
+ }
+
+ #region emit dataSourceChanged event handler
+ //now we create the datasource changed method that will init the destination member with
+ //the actual value of the origin member of the datasource and then will bind the value changed
+ //dyn methode.
+ //dm is bound to the instanciator instance to have access to cached dyn meth and delegates
+ dm = new DynamicMethod ("dyn_dschanged",
+ typeof (void),
+ CompilerServices.argsBoundDSChange, true);
+
+ il = dm.GetILGenerator (256);
+
+ il.DeclareLocal (CompilerServices.TObject);//used for checking propery less bindings
+ il.DeclareLocal (typeof(MemberInfo));//used for checking propery less bindings
+ System.Reflection.Emit.Label cancel = il.DefineLabel ();
+ System.Reflection.Emit.Label cancelInit = il.DefineLabel ();
+
+ il.Emit (OpCodes.Nop);
+
+ emitRemoveOldDataSourceHandler(il, "ValueChanged", delName);
+
+ if (!string.IsNullOrEmpty(bindingDef.TargetMember)){
+ if (bindingDef.TwoWay){
+ System.Reflection.Emit.Label cancelRemove = il.DefineLabel ();
+ //remove handler if not null
+ il.Emit (OpCodes.Ldarg_2);//load old parent
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCOldDS);
+ il.Emit (OpCodes.Brfalse, cancelRemove);//old parent is null
+
+ //remove handler
+ il.Emit (OpCodes.Ldarg_2);//1st arg load old datasource
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCOldDS);
+ il.Emit (OpCodes.Ldstr, "ValueChanged");//2nd arg event name
+ il.Emit (OpCodes.Ldarg_1);//3d arg: instance bound to delegate (the source)
+ il.Emit (OpCodes.Call, CompilerServices.miRemEvtHdlByTarget);
+ il.MarkLabel(cancelRemove);
+ }
+ il.Emit (OpCodes.Ldarg_2);//load datasource change arg
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ il.Emit (OpCodes.Brfalse, cancel);//new ds is null
+ }
+
+ #region fetch initial Value
+ if (!string.IsNullOrEmpty(bindingDef.TargetMember)){
+ il.Emit (OpCodes.Ldarg_2);//load new datasource
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ il.Emit (OpCodes.Ldstr, bindingDef.TargetMember);//load member name
+ il.Emit (OpCodes.Call, CompilerServices.miGetMembIinfoWithRefx);
+ il.Emit (OpCodes.Stloc_1);//save memberInfo
+ il.Emit (OpCodes.Ldloc_1);//push mi for test if null
+ il.Emit (OpCodes.Brfalse, cancelInit);//propertyLessBinding
+ }
+
+ il.Emit (OpCodes.Ldarg_1);//load source of dataSourceChanged which is the dest instance
+ il.Emit (OpCodes.Ldarg_2);//load new datasource
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ if (!string.IsNullOrEmpty(bindingDef.TargetMember)){
+ il.Emit (OpCodes.Ldloc_1);//push mi for value fetching
+ il.Emit (OpCodes.Call, CompilerServices.miGetValWithRefx);
+ }
+ CompilerServices.emitConvert (il, piSource.PropertyType);
+ il.Emit (OpCodes.Callvirt, piSource.GetSetMethod ());
+ #endregion
+
+ if (!string.IsNullOrEmpty(bindingDef.TargetMember)){
+ il.MarkLabel(cancelInit);
+ //check if new dataSource implement IValueChange
+ il.Emit (OpCodes.Ldarg_2);//load new datasource
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ il.Emit (OpCodes.Isinst, typeof(IValueChange));
+ il.Emit (OpCodes.Brfalse, cancel);
+
+ il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+ il.Emit (OpCodes.Ldarg_1);//load datasource change source
+ il.Emit (OpCodes.Ldarg_2);//load new datasource
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ il.Emit(OpCodes.Ldc_I4, dmVC);//load index of dynmathod
+ il.Emit (OpCodes.Call, CompilerServices.miDSChangeEmitHelper);
+
+ if (bindingDef.TwoWay){
+ il.Emit (OpCodes.Ldarg_1);//arg1: dataSourceChange source, the origine of the binding
+ il.Emit (OpCodes.Ldstr, bindingDef.SourceMember);//arg2: orig member
+ il.Emit (OpCodes.Ldarg_2);//arg3: new datasource
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ il.Emit (OpCodes.Ldstr, bindingDef.TargetMember);//arg4: dest member
+ il.Emit (OpCodes.Call, CompilerServices.miDSReverseBinding);
+ }
+
+ il.MarkLabel (cancel);
+ }
+ il.Emit (OpCodes.Ret);
+
+ //store dschange delegate in instatiator instance for access while instancing graphic object
+ int delDSIndex = cachedDelegates.Count;
+ cachedDelegates.Add(dm.CreateDelegate (CompilerServices.ehTypeDSChange, this));
+ #endregion
+
+ ctx.emitCachedDelegateHandlerAddition(delDSIndex, CompilerServices.eiDSChange);
+ }
+ /// <summary>
+ /// Two way binding for datasource, graphicObj=>dataSource link, datasource value has priority
+ /// and will be set as init for source property (in emitDataSourceBindings func)
+ /// </summary>
+ /// <param name="orig">Graphic object instance, source of binding</param>
+ /// <param name="origMember">Origin member name</param>
+ /// <param name="dest">datasource instance, target of the binding</param>
+ /// <param name="destMember">Destination member name</param>
+ static void dataSourceReverseBinding(IValueChange orig, string origMember, object dest, string destMember){
+ Type tOrig = orig.GetType ();
+ Type tDest = dest.GetType ();
+ PropertyInfo piOrig = tOrig.GetProperty (origMember);
+ PropertyInfo piDest = tDest.GetProperty (destMember);
+
+ #region ValueChanged emit
+ DynamicMethod dm = new DynamicMethod ("dyn_valueChanged" + NewId,
+ typeof (void), CompilerServices.argsBoundValueChange, true);
+ ILGenerator il = dm.GetILGenerator (256);
+
+ System.Reflection.Emit.Label endMethod = il.DefineLabel ();
+
+ il.DeclareLocal (CompilerServices.TObject);
+ il.Emit (OpCodes.Nop);
+
+ //load value changed member name onto the stack
+ il.Emit (OpCodes.Ldarg_2);
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiVCMbName);
+
+ //test if it's the expected one
+ il.Emit (OpCodes.Ldstr, origMember);
+ il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
+ il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
+ il.Emit (OpCodes.Brfalse, endMethod);
+ //set destination member with valueChanged new value
+ //load destination ref
+ il.Emit (OpCodes.Ldarg_0);
+ //load new value onto the stack
+ il.Emit (OpCodes.Ldarg_2);
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiVCNewValue);
+
+ CompilerServices.emitConvert (il, piOrig.PropertyType, piDest.PropertyType);
+
+ il.Emit (OpCodes.Callvirt, piDest.GetSetMethod ());
+
+ il.MarkLabel (endMethod);
+ il.Emit (OpCodes.Ret);
+ #endregion
+
+ orig.ValueChanged += (EventHandler<ValueChangeEventArgs>)dm.CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>), dest);
+ }
+ #endregion
+
+ /// <summary> Emits remove old data source event handler./summary>
+ void emitRemoveOldDataSourceHandler(ILGenerator il, string eventName, string delegateName, bool DSSide = true){
+ System.Reflection.Emit.Label cancel = il.DefineLabel ();
+
+ il.Emit (OpCodes.Ldarg_2);//load old parent
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCOldDS);
+ il.Emit (OpCodes.Brfalse, cancel);//old parent is null
+
+ //remove handler
+ if (DSSide){//event is defined in the dataSource instance
+ il.Emit (OpCodes.Ldarg_2);//1st arg load old datasource
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCOldDS);
+ }else//the event is in the source
+ il.Emit (OpCodes.Ldarg_1);//1st arg load old datasource
+ il.Emit (OpCodes.Ldstr, eventName);//2nd arg event name
+ il.Emit (OpCodes.Ldstr, delegateName);//3d arg: delegate name
+ il.Emit (OpCodes.Call, CompilerServices.miRemEvtHdlByName);
+ il.MarkLabel(cancel);
+ }
+
}
}
diff --git a/src/Interface.cs b/src/Interface.cs
index 1659c0ea..0cff9b87 100644
--- a/src/Interface.cs
+++ b/src/Interface.cs
@@ -63,7 +63,8 @@ namespace Crow
#region Static and constants
public static int DoubleClick = 200;//ms
- internal static Stopwatch clickTimer = new Stopwatch();
+ internal Stopwatch clickTimer = new Stopwatch();
+ internal GraphicObject eligibleForDoubleClick = null;
public static int TabSize = 4;
public static string LineBreak = "\r\n";
//TODO: shold be declared in graphicObject
@@ -100,10 +101,10 @@ namespace Crow
// if (g.RegisteredLayoutings != LayoutingType.None)
// return;
ILayoutable l = g;
- while (l.Parent != null)
- l = l.Parent;
- if (!(l is Interface))
- return;
+// while (l.Parent != null)
+// l = l.Parent;
+// if (!(l is Interface))
+// return;
lock (DrawingQueue) {
if (g.IsQueueForRedraw)
@@ -312,10 +313,10 @@ namespace Crow
if (_focusedWidget == value)
return;
if (_focusedWidget != null)
- _focusedWidget.onUnfocused (this, null);
+ _focusedWidget.HasFocus = false;
_focusedWidget = value;
if (_focusedWidget != null)
- _focusedWidget.onFocused (this, null);
+ _focusedWidget.HasFocus = true;
}
}
#endregion
@@ -411,15 +412,9 @@ namespace Crow
while (DrawingQueue.Count > 0) {
GraphicObject g = DrawingQueue.Dequeue ();
g.IsQueueForRedraw = false;
- try {
- if (g.Parent == null)
- continue;
- g.Parent.RegisterClip (g.LastPaintedSlot);
- if (g.getSlot () != g.LastPaintedSlot)
- g.Parent.RegisterClip (g.getSlot ());
- } catch (Exception ex) {
- Debug.WriteLine ("Error Register Clip: " + ex.ToString ());
- }
+ g.Parent.RegisterClip (g.LastPaintedSlot);
+ if (g.getSlot () != g.LastPaintedSlot)
+ g.Parent.RegisterClip (g.getSlot ());
}
}
#if MEASURE_TIME
@@ -499,7 +494,6 @@ namespace Crow
public void DeleteWidget(GraphicObject g)
{
g.Visible = false;//trick to ensure clip is added to refresh zone
- g.ClearBinding();
GraphicTree.Remove (g);
}
public void PutOnTop(GraphicObject g)
@@ -519,8 +513,8 @@ namespace Crow
//TODO:parent is not reset to null because object will be added
//to ObjectToRedraw list, and without parent, it fails
GraphicObject g = GraphicTree [i];
+ g.DataSource = null;
g.Visible = false;
- g.ClearBinding ();
GraphicTree.RemoveAt (0);
}
#if DEBUG_LAYOUTING
diff --git a/src/ItemTemplate.cs b/src/ItemTemplate.cs
index fe26f7a7..1f03f7f8 100644
--- a/src/ItemTemplate.cs
+++ b/src/ItemTemplate.cs
@@ -31,8 +31,11 @@ using System.Linq;
namespace Crow
{
+ public delegate bool BooleanTestOnInstance(object instance);
+
public class ItemTemplate : Instantiator {
public EventHandler Expand;
+ public BooleanTestOnInstance HasSubItems;
string strDataType;
string fetchMethodName;
@@ -41,9 +44,10 @@ namespace Crow
: base(path) {
strDataType = _dataType;
fetchMethodName = _fetchDataMethod;
+
}
- public ItemTemplate (Type _root, InstanciatorInvoker _loader,string _dataType, string _fetchDataMethod)
- :base(_root, _loader)
+ public ItemTemplate (Stream ImlFragment, string _dataType, string _fetchDataMethod)
+ :base(ImlFragment)
{
strDataType = _dataType;
fetchMethodName = _fetchDataMethod;
@@ -53,7 +57,6 @@ namespace Crow
public void CreateExpandDelegate (TemplatedGroup host){
Type dataType = Type.GetType(strDataType);
Type tmpGrpType = typeof(TemplatedGroup);
- Type hostType = tmpGrpType;//not sure is the best place to put the dyn method
Type evtType = typeof(EventHandler);
PropertyInfo piData = tmpGrpType.GetProperty ("Data");
@@ -62,14 +65,14 @@ namespace Crow
ParameterInfo [] evtParams = evtInvoke.GetParameters ();
Type handlerArgsType = evtParams [1].ParameterType;
- Type [] args = { typeof (object), typeof (object), handlerArgsType };
- DynamicMethod dm = new DynamicMethod ("dyn_expand_" + fetchMethodName,
- typeof (void),
- args,
- hostType);
+ Type [] args = { CompilerServices.TObject, CompilerServices.TObject, handlerArgsType };
+ #region Expand dyn meth
+ //DM is bound to templatedGroup root (arg0)
+ //arg1 is the sender of the expand event
+ DynamicMethod dm = new DynamicMethod ("dyn_expand_" + fetchMethodName,
+ typeof (void), args, true);
- #region IL generation
System.Reflection.Emit.Label gotoEnd;
System.Reflection.Emit.Label ifDataIsNull;
@@ -81,9 +84,8 @@ namespace Crow
il.Emit (OpCodes.Ldarg_1);//load sender of expand event
- MethodInfo miFindByName = typeof(GraphicObject).GetMethod("FindByName");
il.Emit(OpCodes.Ldstr, "List");
- il.Emit (OpCodes.Callvirt, miFindByName);
+ il.Emit (OpCodes.Callvirt, CompilerServices.miFindByName);
il.Emit (OpCodes.Stloc_0);
//check that 'Data' of list is not already set
@@ -103,11 +105,10 @@ namespace Crow
//call 'fetchMethodName' from the dataSource to build the sub nodes list
il.Emit (OpCodes.Ldloc_0);//push 'List' (of sub nodes) into the stack
il.Emit (OpCodes.Ldarg_1);//get the dataSource of the sender
- il.Emit (OpCodes.Callvirt, typeof(GraphicObject).GetProperty("DataSource").GetGetMethod ());
+ il.Emit (OpCodes.Callvirt, CompilerServices.miGetDataSource);
- if (fetchMethodName != "self"){//special keyword self allows the use of recurent list<<<
- emitGetSubData(il, dataType);
- }
+ if (fetchMethodName != "self")//special keyword self allows the use of recurent list<<<
+ emitGetSubData(il, dataType);
//set 'return' from the fetch method as 'data' of the list
il.Emit (OpCodes.Callvirt, piData.GetSetMethod ());
@@ -115,9 +116,28 @@ namespace Crow
il.MarkLabel(gotoEnd);
il.Emit (OpCodes.Ret);
+ Expand = (EventHandler)dm.CreateDelegate (evtType, host);
#endregion
- Expand = (EventHandler)dm.CreateDelegate (evtType, host);
+ #region Items counting dyn method
+ //dm is unbound, arg0 is instance of Item container to expand
+ dm = new DynamicMethod ("dyn_count_" + fetchMethodName,
+ typeof (bool), new Type[] {CompilerServices.TObject}, true);
+ il = dm.GetILGenerator (256);
+
+ //get the dataSource of the arg0
+ il.Emit (OpCodes.Ldarg_0);
+ il.Emit (OpCodes.Callvirt, CompilerServices.miGetDataSource);
+
+ if (fetchMethodName != "self")
+ emitGetSubData(il, dataType);
+
+ il.Emit (OpCodes.Callvirt, CompilerServices.miGetColCount);
+ il.Emit (OpCodes.Ldc_I4_0);
+ il.Emit (OpCodes.Cgt);
+ il.Emit (OpCodes.Ret);
+ HasSubItems = (BooleanTestOnInstance)dm.CreateDelegate (typeof(BooleanTestOnInstance));
+ #endregion
}
void emitGetSubData(ILGenerator il, Type dataType){
MethodInfo miGetDatas = dataType.GetMethod (fetchMethodName, new Type[] {});
diff --git a/src/LayoutingQueueItem.cs b/src/LayoutingQueueItem.cs
index 3b19efc9..2257ae8e 100644
--- a/src/LayoutingQueueItem.cs
+++ b/src/LayoutingQueueItem.cs
@@ -96,7 +96,9 @@ namespace Crow
if (Layoutable.Parent == null) {//TODO:improve this
//cancel layouting for object without parent, maybe some were in queue when
//removed from a listbox
+ #if DEBUG_LAYOUTING
Debug.WriteLine ("ERROR: processLayouting, no parent for: " + this.ToString ());
+ #endif
return;
}
#if DEBUG_LAYOUTING
diff --git a/src/Rectangle.cs b/src/Rectangle.cs
index 9a4ef396..3ceb396e 100644
--- a/src/Rectangle.cs
+++ b/src/Rectangle.cs
@@ -7,6 +7,7 @@ namespace Crow
{
public struct Rectangle
{
+ internal static Type TRectangle = typeof(Rectangle);
#region private fields
int _x;
int _y;
@@ -262,7 +263,7 @@ namespace Crow
}
public override bool Equals (object obj)
{
- return (obj == null || obj.GetType() != typeof(Rectangle)) ?
+ return (obj == null || obj.GetType() != TRectangle) ?
false :
this == (Rectangle)obj;
}
diff --git a/src/Rectangles.cs b/src/Rectangles.cs
index 5168f3db..9f3c3337 100644
--- a/src/Rectangles.cs
+++ b/src/Rectangles.cs
@@ -35,7 +35,7 @@ namespace Crow
return false;
return true;
}
-
+
public bool intersect(Rectangle r)
{
foreach (Rectangle rInList in list)
@@ -43,102 +43,10 @@ namespace Crow
return true;
return false;
}
-
- public Rectangles intersectingRects(Rectangle r)
- {
- Rectangles tmp = new Rectangles();
-
- foreach (Rectangle rInList in list)
- if (rInList.Intersect(r))
- tmp.list.Add(rInList);//on bypass le test déjà fait a l'ajout intial du rect dans la liste
-
- return tmp;
- }
- public Rectangles SmallerContainedRects(Rectangle r)
- {
- Rectangles tmp = new Rectangles();
-
- foreach (Rectangle rInList in list)
- if (r.ContainsOrIsEqual(rInList) && rInList.Size < r.Size)
- tmp.list.Add(rInList);
-
- return tmp;
- }
- /// <summary>
- /// Return rectangles with size smaller than r.size
- /// </summary>
- public Rectangles SmallerRects(Rectangle r)
- {
- Rectangles tmp = new Rectangles();
-
- foreach (Rectangle rInList in list)
- if (rInList.Size < r.Size)
- tmp.list.Add(rInList);
-
- return tmp;
- }
- public Rectangles containedOrEqualRects(Rectangle r)
- {
- Rectangles tmp = new Rectangles();
-
- foreach (Rectangle rInList in list)
- if (r.ContainsOrIsEqual(rInList))// && rInList.Size <= r.Size)
- tmp.list.Add(rInList);
-
- return tmp;
- }
- public void Srcoll(GraphicObject w)
- {
- Scroller sw = w as Scroller;
- if (sw == null)
- return;
-
- List<Rectangle> newList = new List<Rectangle>();
-
- foreach (Rectangle rInList in list)
- {
- Rectangle r = rInList;
-
- if (sw.VerticalScrolling)
- r.Top -= (int)sw.ScrollY;
- if (sw.HorizontalScrolling)
- r.Left -= (int)sw.ScrollX;
-
- newList.Add(r);
- }
- list = newList;
- }
- public void Rebase(GraphicObject w)
- {
- Rectangle r = w.Parent.ContextCoordinates(w.Slot);
- List<Rectangle> newList = new List<Rectangle>();
-
- foreach (Rectangle rInList in list)
- {
- Rectangle rebasedR = rInList;
- rebasedR.TopLeft-= r.TopLeft;
-
- Scroller sw = w as Scroller;
- if (sw != null)
- {
- if (sw.VerticalScrolling) {
- rebasedR.Top -= (int)sw.ScrollY;
-// if (sw.scrollY < 0)
-// Debug.WriteLine ("..");
- }if (sw.HorizontalScrolling)
- rebasedR.Left -= (int)sw.ScrollX;
- }
-
- newList.Add(rebasedR);
- }
- list = newList;
- }
public void stroke(Context ctx, Color c)
{
foreach (Rectangle r in list)
- {
ctx.Rectangle(r);
- }
ctx.SetSourceColor(c);
@@ -153,17 +61,15 @@ namespace Crow
ctx.Rectangle(r);
ctx.ClipPreserve();
- ctx.Operator = Operator.Clear;
+ ctx.Operator = Operator.Clear;
ctx.Fill();
- ctx.Operator = Operator.Over;
+ ctx.Operator = Operator.Over;
}
public void clip(Context ctx)
{
foreach (Rectangle r in list)
- {
- ctx.Rectangle(r);
- }
+ ctx.Rectangle(r);
ctx.Clip();
}
diff --git a/src/Size.cs b/src/Size.cs
index 5059d31a..996de49f 100644
--- a/src/Size.cs
+++ b/src/Size.cs
@@ -7,6 +7,7 @@ namespace Crow
{
public struct Size
{
+ internal static Type TSize = typeof(Size);
public static Size Zero
{ get { return new Size(0, 0); } }
@@ -143,7 +144,7 @@ namespace Crow
}
public override bool Equals (object obj)
{
- return (obj == null || obj.GetType() != typeof(Size)) ?
+ return (obj == null || obj.GetType() != TSize) ?
false :
this == (Size)obj;
}
diff --git a/src/SolidColor.cs b/src/SolidColor.cs
index 2b6f7e71..d214f592 100644
--- a/src/SolidColor.cs
+++ b/src/SolidColor.cs
@@ -12,7 +12,7 @@ namespace Crow
{
public class SolidColor : Fill
{
- Color color = Color.Transparent;
+ public Color color = Color.Transparent;
#region CTOR
public SolidColor(Color c)
{