aboutsummaryrefslogtreecommitdiffstatsci
path: root/src
diff options
context:
space:
mode:
authorjp <jp_bruyere@hotmail.com>2016-03-18 12:39:38 +0100
committerjp <jp_bruyere@hotmail.com>2016-03-18 12:39:38 +0100
commit22644afe6f0722dcfb5fd27ba353f12274f55eb6 (patch)
tree7472299f2c96d9a071b6101bd97542b8e8fce306 /src
parente5069093ba483ef8644c5cac685d76f2600606f0 (diff)
parent356bfaaed4f46a727ae033f37f362b062c8c32d9 (diff)
Merge branch 'master' of https://github.com/jpbruyere/Crow
Diffstat (limited to 'src')
-rw-r--r--src/CompilerServices/CompilerServices.cs389
-rw-r--r--src/GraphicObjects/GraphicObject.cs338
-rw-r--r--src/GraphicObjects/IBindable.cs31
-rw-r--r--src/GraphicObjects/TextBox.cs71
-rw-r--r--src/Input/KeyPressEventArgs.cs58
-rw-r--r--src/Interface.cs29
6 files changed, 520 insertions, 396 deletions
diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs
index da5c0fe4..cd491c4d 100644
--- a/src/CompilerServices/CompilerServices.cs
+++ b/src/CompilerServices/CompilerServices.cs
@@ -50,6 +50,8 @@ namespace Crow
string dynMethodId = "";
bool resolved = false;
+ public bool TwoWayBinding = false;
+
public string NewDynMethodId {
get {
if (!string.IsNullOrEmpty (dynMethodId))
@@ -88,19 +90,32 @@ namespace Crow
#region CTOR
public Binding(){}
- public Binding(MemberReference _source, string _expression)
+ public Binding(MemberReference _target, string _expression)
{
- Target = _source;
+ Target = _target;
Expression = _expression;
}
- public Binding(object _source, string _member, string _expression)
+ public Binding(object _target, string _member, string _expression)
{
- Target = new MemberReference (_source, _source.GetType().GetMember (_member) [0]);
+ Target = new MemberReference (_target, _target.GetType().GetMember (_member) [0]);
Expression = _expression;
}
+ public Binding(object _target, string _targetMember, object _source, string _sourceMember)
+ {
+ Target = new MemberReference (_target, _target.GetType().GetMember (_targetMember) [0]);
+ Source = new MemberReference (_source, _source.GetType().GetMember (_sourceMember) [0]);
+ }
+ public Binding(MemberReference _target, MemberReference _source)
+ {
+ Target = _target;
+ Source = _source;
+ }
#endregion
- public bool FindTarget(){
+ public bool FindSource(){
+ if (Source != null)
+ return true;
+
string member = null;
//if binding exp = '{}' => binding is done on datasource
@@ -112,7 +127,14 @@ namespace Crow
return true;
}
- string[] bindingExp = Expression.Split ('/');
+ string expression = Expression;
+
+ if (Expression.StartsWith ("²")) {
+ expression = expression.Substring (1);
+ TwoWayBinding = true;
+ }
+
+ string[] bindingExp = expression.Split ('/');
if (bindingExp.Length == 1) {
//datasource binding
@@ -164,10 +186,18 @@ namespace Crow
return false;
}
- if (Source.FindMember (member))
+ if (Source.FindMember (member)) {
+ if (TwoWayBinding) {
+ IBindable source = Source.Instance as IBindable;
+ if (source == null)
+ throw new Exception (Target.Instance.ToString() + " does not implement IBindable for 2 way bindings");
+ source.Bindings.Add (new Binding (Source, Target));
+ }
return true;
+ }
Debug.WriteLine ("Binding member not found: " + member);
+ Source = null;
return false;
}
public void Reset()
@@ -186,6 +216,351 @@ namespace Crow
public static class CompilerServices
{
+ 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.Target.Member.MemberType == MemberTypes.Event) {
+ if (b.Expression.StartsWith("{")){
+ CompilerServices.CompileEventSource(b);
+ continue;
+ }
+ if (!b.FindSource ())
+ continue;
+ //register handler for event
+ if (b.Source.Method == null) {
+ Debug.WriteLine ("\tError: Handler Method not found: " + b.ToString());
+ continue;
+ }
+ try {
+ MethodInfo addHandler = b.Target.Event.GetAddMethod ();
+ Delegate del = Delegate.CreateDelegate (b.Target.Event.EventHandlerType, b.Source.Instance, b.Source.Method);
+ addHandler.Invoke (b.Target.Instance, new object[] { del });
+
+ #if DEBUG_BINDING
+ Debug.WriteLine ("\tHandler binded => " + b.ToString());
+ #endif
+ b.Resolved = true;
+ } catch (Exception ex) {
+ Debug.WriteLine ("\tERROR: " + ex.ToString());
+ }
+ continue;
+ }
+
+ if (!b.FindSource ())
+ continue;
+
+ List<Binding> bindings = null;
+ if (!resolved.TryGetValue (b.Source.Instance, out bindings)) {
+ bindings = new List<Binding> ();
+ resolved [b.Source.Instance] = bindings;
+ }
+ bindings.Add (b);
+ b.Resolved = true;
+ }
+
+ MethodInfo stringEquals = typeof(string).GetMethod
+ ("Equals", new Type[3] {typeof(string), typeof(string), typeof(StringComparison)});
+ Type target_Type = Bindings[0].Target.Instance.GetType();
+ EventInfo ei = typeof(IValueChange).GetEvent("ValueChanged");
+ MethodInfo evtInvoke = ei.EventHandlerType.GetMethod ("Invoke");
+ ParameterInfo[] evtParams = evtInvoke.GetParameters ();
+ Type handlerArgsType = evtParams [1].ParameterType;
+ Type[] args = {typeof(object), typeof(object),handlerArgsType};
+ FieldInfo fiNewValue = typeof(ValueChangeEventArgs).GetField("NewValue");
+ FieldInfo fiMbName = typeof(ValueChangeEventArgs).GetField("MemberName");
+
+ //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].Source.Instance.GetType();
+
+ DynamicMethod dm = null;
+ ILGenerator il = null;
+
+ System.Reflection.Emit.Label[] jumpTable = null;
+ System.Reflection.Emit.Label endMethod = new System.Reflection.Emit.Label();
+
+ #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].NewDynMethodId,
+ MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
+ CallingConventions.Standard,
+ typeof(void),
+ args,
+ target_Type,true);
+
+ il = dm.GetILGenerator(256);
+
+ 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));
+
+ 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
+
+ i = 0;
+ foreach (Binding b in grouped) {
+ #region initialize target with actual value
+ object targetValue = null;
+ if (b.Source.Member != null){
+ if (b.Source.Member.MemberType == MemberTypes.Property)
+ targetValue = b.Source.Property.GetGetMethod ().Invoke (b.Source.Instance, null);
+ else if (b.Source.Member.MemberType == MemberTypes.Field)
+ targetValue = b.Source.Field.GetValue (b.Source.Instance);
+ else if (b.Source.Member.MemberType == MemberTypes.Method){
+ MethodInfo mthSrc = b.Source.Method;
+ if (mthSrc.IsDefined(typeof(ExtensionAttribute), false))
+ targetValue = mthSrc.Invoke(null, new object[] {b.Source.Instance});
+ else
+ targetValue = mthSrc.Invoke(b.Source.Instance, null);
+ }else
+ throw new Exception ("unandled source member type for binding");
+ }else if (string.IsNullOrEmpty(b.Expression))
+ targetValue= grouped [0].Source.Instance;//empty binding exp=> bound to target object by default
+ //TODO: handle other dest type conversions
+ if (b.Target.Property.PropertyType == typeof(string)){
+ if (targetValue == null){
+ //set default value
+
+ }else
+ targetValue = targetValue.ToString ();
+ }
+ if (targetValue != null)
+ b.Target.Property.GetSetMethod ().Invoke
+ (b.Target.Instance, new object[] { b.Target.Property.PropertyType.Cast(targetValue)});
+ else
+ b.Target.Property.GetSetMethod ().Invoke
+ (b.Target.Instance, new object[] { targetValue });
+ #endregion
+
+ //if no dyn update, skip jump table
+ if (il == null)
+ continue;
+
+ il.Emit (OpCodes.Ldloc_0);
+ if (b.Source.Member != null)
+ il.Emit (OpCodes.Ldstr, b.Source.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 (il == null)
+ continue;
+
+ il.Emit (OpCodes.Br, endMethod);
+
+ i = 0;
+ foreach (Binding b in grouped) {
+
+ il.MarkLabel (jumpTable [i]);
+ il.Emit(OpCodes.Ldloc_1);
+
+ //by default, target value type is deducted from source member type to allow
+ //memberless binding, if targetMember exists, it will be used to determine target
+ //value type for conversion
+ Type targetValueType = b.Target.Property.PropertyType;
+ if (b.Source.Member != null) {
+ if (b.Source.Member.MemberType == MemberTypes.Property)
+ targetValueType = b.Source.Property.PropertyType;
+ else if (b.Source.Member.MemberType == MemberTypes.Field)
+ targetValueType = b.Source.Field.FieldType;
+ else
+ throw new Exception ("unhandle target member type in binding");
+ }
+
+ if (b.Target.Property.PropertyType == typeof(string)) {
+ MemberReference tostring = new MemberReference (b.Target.Instance);
+ if (!tostring.FindMember ("ToString"))
+ throw new Exception ("ToString method not found");
+ il.Emit (OpCodes.Callvirt, tostring.Method);
+ }else if (!targetValueType.IsValueType)
+ il.Emit(OpCodes.Castclass, targetValueType);
+ else if (b.Target.Property.PropertyType != targetValueType)
+ il.Emit(OpCodes.Callvirt, CompilerServices.GetConvertMethod( b.Target.Property.PropertyType ));
+ else
+ il.Emit(OpCodes.Unbox_Any, b.Target.Property.PropertyType);
+
+ il.Emit(OpCodes.Callvirt, b.Target.Property.GetSetMethod());
+ il.Emit (OpCodes.Br, endMethod);
+ i++;
+
+ }
+ il.MarkLabel(endMethod);
+ il.Emit(OpCodes.Pop);
+ il.Emit(OpCodes.Ret);
+
+ Delegate del = dm.CreateDelegate(ei.EventHandlerType, Bindings[0].Target.Instance);
+ MethodInfo addHandler = ei.GetAddMethod ();
+ addHandler.Invoke(grouped [0].Source.Instance, new object[] {del});
+ }
+ }
+
+ /// <summary>
+ /// Compile events expression in GOML attributes
+ /// </summary>
+ /// <param name="es">Event binding details</param>
+ public static void CompileEventSource(Binding binding)
+ {
+ #if DEBUG_BINDING
+ Debug.WriteLine ("\tCompile Event Source => " + binding.ToString());
+ #endif
+
+ Type target_type = binding.Target.Instance.GetType();
+
+ #region Retrieve EventHandler parameter type
+ MethodInfo evtInvoke = binding.Target.Event.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.NewDynMethodId,
+ typeof(void),
+ args,
+ target_type);
+
+
+ #region IL generation
+ ILGenerator il = dm.GetILGenerator(256);
+
+ string src = binding.Expression.Trim();
+
+ if (! (src.StartsWith("{") || src.EndsWith ("}")))
+ throw new Exception (string.Format("GOML:Malformed {0} Event handler: {1}", binding.Target.Member.Name, binding.Expression));
+
+ src = src.Substring (1, src.Length - 2);
+ string[] srcLines = src.Split (new char[] { ';' });
+
+ foreach (string srcLine in srcLines) {
+ string statement = srcLine.Trim ();
+
+ string[] operandes = statement.Split (new char[] { '=' });
+ if (operandes.Length < 2) //not an affectation
+ {
+ continue;
+ }
+ string lop = operandes [0].Trim ();
+ string rop = operandes [operandes.Length-1].Trim ();
+
+ #region LEFT OPERANDES
+ GraphicObject lopObj = binding.Target.Instance as GraphicObject; //default left operand base object is
+ //the first arg (object sender) of the event handler
+
+ 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
+ MethodInfo FindByNameMi = typeof(GraphicObject).GetMethod("FindByName");
+ for (int j = 0; j < lopParts.Length - 1; j++) {
+ il.Emit (OpCodes.Ldstr, lopParts[j]);
+ il.Emit(OpCodes.Callvirt, FindByNameMi);
+ }
+ }
+
+ int i = lopParts.Length -1;
+
+ MemberInfo[] lopMbis = lopObj.GetType().GetMember (lopParts[i]);
+
+ if (lopMbis.Length<1)
+ throw new Exception (string.Format("CROW BINDING: Member not found '{0}'", lop));
+
+ OpCode lopSetOC;
+ dynamic lopSetMbi;
+ Type lopT = null;
+ switch (lopMbis[0].MemberType) {
+ case MemberTypes.Property:
+ PropertyInfo lopPi = target_type.GetProperty (lopParts[i]);
+ MethodInfo dstMi = lopPi.GetSetMethod ();
+ lopT = lopPi.PropertyType;
+ lopSetMbi = dstMi;
+ lopSetOC = OpCodes.Callvirt;
+ break;
+ case MemberTypes.Field:
+ FieldInfo dstFi = target_type.GetField(lopParts[i]);
+ lopT = dstFi.FieldType;
+ lopSetMbi = dstFi;
+ lopSetOC = OpCodes.Stfld;
+ break;
+ default:
+ throw new Exception (string.Format("GOML:member type not handle: {0}", lopParts[i]));
+ }
+ #endregion
+
+ #region RIGHT OPERANDES
+ if (rop.StartsWith("\'")){
+ if (!rop.EndsWith("\'"))
+ throw new Exception (string.Format
+ ("GOML:malformed string constant in handler: {0}", rop));
+ string strcst = rop.Substring (1, rop.Length - 2);
+
+ il.Emit(OpCodes.Ldstr,strcst);
+
+ }else{
+ if (lopT.IsEnum)
+ throw new NotImplementedException();
+
+ MethodInfo lopParseMi = lopT.GetMethod("Parse");
+ if (lopParseMi == null)
+ throw new Exception (string.Format
+ ("GOML:no parse method found in: {0}", lopT.Name));
+ il.Emit(OpCodes.Ldstr, rop);
+ il.Emit(OpCodes.Callvirt, lopParseMi);
+ il.Emit(OpCodes.Unbox_Any, lopT);
+ }
+
+ #endregion
+
+ //emit left operand assignment
+ il.Emit(lopSetOC, lopSetMbi);
+ }
+
+ il.Emit(OpCodes.Ret);
+
+ #endregion
+
+ Delegate del = dm.CreateDelegate(binding.Target.Event.EventHandlerType, binding.Target.Instance);
+ MethodInfo addHandler = binding.Target.Event.GetAddMethod ();
+ addHandler.Invoke(binding.Target.Instance, new object[] {del});
+
+ binding.Resolved = true;
+ }
+
#region conversions
internal static MethodInfo GetConvertMethod( Type targetType )
diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs
index cddc918a..c526e909 100644
--- a/src/GraphicObjects/GraphicObject.cs
+++ b/src/GraphicObjects/GraphicObject.cs
@@ -156,6 +156,7 @@ namespace Crow
public event EventHandler<MouseMoveEventArgs> MouseLeave;
public event EventHandler<KeyboardKeyEventArgs> KeyDown;
public event EventHandler<KeyboardKeyEventArgs> KeyUp;
+ public event EventHandler<KeyPressEventArgs> KeyPress;
public event EventHandler Focused;
public event EventHandler Unfocused;
public event EventHandler<LayoutingEventArgs> LayoutChanged;
@@ -939,6 +940,9 @@ namespace Crow
public virtual void onKeyDown(object sender, KeyboardKeyEventArgs e){
KeyDown.Raise (sender, e);
}
+ public virtual void onKeyPress(object sender, KeyPressEventArgs e){
+ KeyPress.Raise (sender, e);
+ }
#endregion
#region Mouse handling
@@ -1055,342 +1059,10 @@ namespace Crow
#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.Target.Member.MemberType == MemberTypes.Event) {
- if (b.Expression.StartsWith("{")){
- CompileEventSource(b);
- continue;
- }
- if (!b.FindTarget ())
- continue;
- //register handler for event
- if (b.Source.Method == null) {
- Debug.WriteLine ("\tError: Handler Method not found: " + b.ToString());
- continue;
- }
- try {
- MethodInfo addHandler = b.Target.Event.GetAddMethod ();
- Delegate del = Delegate.CreateDelegate (b.Target.Event.EventHandlerType, b.Source.Instance, b.Source.Method);
- addHandler.Invoke (this, new object[] { del });
-
- #if DEBUG_BINDING
- Debug.WriteLine ("\tHandler binded => " + b.ToString());
- #endif
- b.Resolved = true;
- } catch (Exception ex) {
- Debug.WriteLine ("\tERROR: " + ex.ToString());
- }
- continue;
- }
-
- if (!b.FindTarget ())
- continue;
-
- List<Binding> bindings = null;
- if (!resolved.TryGetValue (b.Source.Instance, out bindings)) {
- bindings = new List<Binding> ();
- resolved [b.Source.Instance] = bindings;
- }
- bindings.Add (b);
- b.Resolved = true;
-
- }
-
- MethodInfo stringEquals = typeof(string).GetMethod
- ("Equals", new Type[3] {typeof(string), typeof(string), typeof(StringComparison)});
- Type sourceType = this.GetType();
- EventInfo ei = typeof(IValueChange).GetEvent("ValueChanged");
- MethodInfo evtInvoke = ei.EventHandlerType.GetMethod ("Invoke");
- ParameterInfo[] evtParams = evtInvoke.GetParameters ();
- Type handlerArgsType = evtParams [1].ParameterType;
- Type[] args = {typeof(object), typeof(object),handlerArgsType};
- FieldInfo fiNewValue = typeof(ValueChangeEventArgs).GetField("NewValue");
- FieldInfo fiMbName = typeof(ValueChangeEventArgs).GetField("MemberName");
-
- //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 targetType = grouped[0].Source.Instance.GetType();
-
- DynamicMethod dm = null;
- ILGenerator il = null;
-
- System.Reflection.Emit.Label[] jumpTable = null;
- System.Reflection.Emit.Label endMethod = new System.Reflection.Emit.Label();
-
- #region Retrieve EventHandler parameter type
- //EventInfo ei = targetType.GetEvent ("ValueChanged");
- //no dynamic update if ValueChanged interface is not implemented
- if (targetType.GetInterfaces().Contains(typeof(IValueChange))){
- dm = new DynamicMethod(grouped[0].NewDynMethodId,
- MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
- CallingConventions.Standard,
- typeof(void),
- args,
- sourceType,true);
-
- il = dm.GetILGenerator(256);
-
- 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));
-
- 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
-
- i = 0;
- foreach (Binding b in grouped) {
- #region initialize target with actual value
- object targetValue = null;
- if (b.Source.Member != null){
- if (b.Source.Member.MemberType == MemberTypes.Property)
- targetValue = b.Source.Property.GetGetMethod ().Invoke (b.Source.Instance, null);
- else if (b.Source.Member.MemberType == MemberTypes.Field)
- targetValue = b.Source.Field.GetValue (b.Source.Instance);
- else if (b.Source.Member.MemberType == MemberTypes.Method){
- MethodInfo mthSrc = b.Source.Method;
- if (mthSrc.IsDefined(typeof(ExtensionAttribute), false))
- targetValue = mthSrc.Invoke(null, new object[] {b.Source.Instance});
- else
- targetValue = mthSrc.Invoke(b.Source.Instance, null);
- }else
- throw new Exception ("unandled source member type for binding");
- }else if (string.IsNullOrEmpty(b.Expression))
- targetValue= grouped [0].Source.Instance;//empty binding exp=> bound to target object by default
- //TODO: handle other dest type conversions
- if (b.Target.Property.PropertyType == typeof(string)){
- if (targetValue == null){
- //set default value
-
- }else
- targetValue = targetValue.ToString ();
- }
- if (targetValue != null)
- b.Target.Property.GetSetMethod ().Invoke
- (this, new object[] { b.Target.Property.PropertyType.Cast(targetValue)});
- else
- b.Target.Property.GetSetMethod ().Invoke
- (this, new object[] { targetValue });
- #endregion
-
- //if no dyn update, skip jump table
- if (il == null)
- continue;
-
- il.Emit (OpCodes.Ldloc_0);
- if (b.Source.Member != null)
- il.Emit (OpCodes.Ldstr, b.Source.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 (il == null)
- continue;
-
- il.Emit (OpCodes.Br, endMethod);
-
- i = 0;
- foreach (Binding b in grouped) {
-
- il.MarkLabel (jumpTable [i]);
- il.Emit(OpCodes.Ldloc_1);
-
- //by default, target value type is deducted from source member type to allow
- //memberless binding, if targetMember exists, it will be used to determine target
- //value type for conversion
- Type targetValueType = b.Target.Property.PropertyType;
- if (b.Source.Member != null) {
- if (b.Source.Member.MemberType == MemberTypes.Property)
- targetValueType = b.Source.Property.PropertyType;
- else if (b.Source.Member.MemberType == MemberTypes.Field)
- targetValueType = b.Source.Field.FieldType;
- else
- throw new Exception ("unhandle target member type in binding");
- }
-
- if (b.Target.Property.PropertyType == typeof(string)) {
- MemberReference tostring = new MemberReference (b.Target.Instance);
- if (!tostring.FindMember ("ToString"))
- throw new Exception ("ToString method not found");
- il.Emit (OpCodes.Callvirt, tostring.Method);
- }else if (!targetValueType.IsValueType)
- il.Emit(OpCodes.Castclass, targetValueType);
- else if (b.Target.Property.PropertyType != targetValueType)
- il.Emit(OpCodes.Callvirt, CompilerServices.GetConvertMethod( b.Target.Property.PropertyType ));
- else
- il.Emit(OpCodes.Unbox_Any, b.Target.Property.PropertyType);
- il.Emit(OpCodes.Callvirt, b.Target.Property.GetSetMethod());
- il.Emit (OpCodes.Br, endMethod);
- i++;
-
- }
- il.MarkLabel(endMethod);
- il.Emit(OpCodes.Pop);
- il.Emit(OpCodes.Ret);
-
- Delegate del = dm.CreateDelegate(ei.EventHandlerType, this);
- MethodInfo addHandler = ei.GetAddMethod ();
- addHandler.Invoke(grouped [0].Source.Instance, new object[] {del});
- }
+ CompilerServices.ResolveBindings (Bindings);
}
- /// <summary>
- /// Compile events expression in GOML attributes
- /// </summary>
- /// <param name="es">Event binding details</param>
- public void CompileEventSource(Binding binding)
- {
- #if DEBUG_BINDING
- Debug.WriteLine ("\tCompile Event Source => " + binding.ToString());
- #endif
-
- Type sourceType = this.GetType();
-
- #region Retrieve EventHandler parameter type
- MethodInfo evtInvoke = binding.Target.Event.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.NewDynMethodId,
- typeof(void),
- args,
- sourceType);
-
- #region IL generation
- ILGenerator il = dm.GetILGenerator(256);
-
- string src = binding.Expression.Trim();
-
- if (! (src.StartsWith("{") || src.EndsWith ("}")))
- throw new Exception (string.Format("GOML:Malformed {0} Event handler: {1}", binding.Target.Member.Name, binding.Expression));
-
- src = src.Substring (1, src.Length - 2);
- string[] srcLines = src.Split (new char[] { ';' });
-
- foreach (string srcLine in srcLines) {
- string statement = srcLine.Trim ();
-
- string[] operandes = statement.Split (new char[] { '=' });
- if (operandes.Length < 2) //not an affectation
- {
- continue;
- }
- string lop = operandes [0].Trim ();
- string rop = operandes [operandes.Length-1].Trim ();
-
- #region LEFT OPERANDES
- GraphicObject lopObj = this; //default left operand base object is
- //the first arg (object sender) of the event handler
-
- 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
- MethodInfo FindByNameMi = typeof(GraphicObject).GetMethod("FindByName");
- for (int j = 0; j < lopParts.Length - 1; j++) {
- il.Emit (OpCodes.Ldstr, lopParts[j]);
- il.Emit(OpCodes.Callvirt, FindByNameMi);
- }
- }
-
- int i = lopParts.Length -1;
-
- MemberInfo[] lopMbis = lopObj.GetType().GetMember (lopParts[i]);
-
- if (lopMbis.Length<1)
- throw new Exception (string.Format("CROW BINDING: Member not found '{0}'", lop));
-
- OpCode lopSetOC;
- dynamic lopSetMbi;
- Type lopT = null;
- switch (lopMbis[0].MemberType) {
- case MemberTypes.Property:
- PropertyInfo lopPi = sourceType.GetProperty (lopParts[i]);
- MethodInfo dstMi = lopPi.GetSetMethod ();
- lopT = lopPi.PropertyType;
- lopSetMbi = dstMi;
- lopSetOC = OpCodes.Callvirt;
- break;
- case MemberTypes.Field:
- FieldInfo dstFi = sourceType.GetField(lopParts[i]);
- lopT = dstFi.FieldType;
- lopSetMbi = dstFi;
- lopSetOC = OpCodes.Stfld;
- break;
- default:
- throw new Exception (string.Format("GOML:member type not handle: {0}", lopParts[i]));
- }
- #endregion
-
- #region RIGHT OPERANDES
- if (rop.StartsWith("\'")){
- if (!rop.EndsWith("\'"))
- throw new Exception (string.Format
- ("GOML:malformed string constant in handler: {0}", rop));
- string strcst = rop.Substring (1, rop.Length - 2);
-
- il.Emit(OpCodes.Ldstr,strcst);
-
- }else{
- if (lopT.IsEnum)
- throw new NotImplementedException();
-
- MethodInfo lopParseMi = lopT.GetMethod("Parse");
- if (lopParseMi == null)
- throw new Exception (string.Format
- ("GOML:no parse method found in: {0}", lopT.Name));
- il.Emit(OpCodes.Ldstr, rop);
- il.Emit(OpCodes.Callvirt, lopParseMi);
- il.Emit(OpCodes.Unbox_Any, lopT);
- }
-
- #endregion
-
- //emit left operand assignment
- il.Emit(lopSetOC, lopSetMbi);
- }
-
- il.Emit(OpCodes.Ret);
-
- #endregion
-
- Delegate del = dm.CreateDelegate(binding.Target.Event.EventHandlerType,this);
- MethodInfo addHandler = binding.Target.Event.GetAddMethod ();
- addHandler.Invoke(this, new object[] {del});
-
- binding.Resolved = true;
- }
/// <summary>
/// Remove dynamic delegates by ids from dataSource
/// and delete ref of this in Shared interface refs
diff --git a/src/GraphicObjects/IBindable.cs b/src/GraphicObjects/IBindable.cs
new file mode 100644
index 00000000..642c1e9e
--- /dev/null
+++ b/src/GraphicObjects/IBindable.cs
@@ -0,0 +1,31 @@
+//
+// IValueChange.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2015 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
+{
+ public interface IBindable
+ {
+ List<Binding> Bindings { get; }
+ }
+}
+
diff --git a/src/GraphicObjects/TextBox.cs b/src/GraphicObjects/TextBox.cs
index 14cc1830..08ec1f69 100644
--- a/src/GraphicObjects/TextBox.cs
+++ b/src/GraphicObjects/TextBox.cs
@@ -80,9 +80,9 @@ namespace Crow
case Key.Back:
if (!selectionIsEmpty)
{
-// Text = Text.Remove(selectionStart, selectionEnd - selectionStart);
-// selReleasePos = -1;
-// currentCol = selBeginPos;
+ // Text = Text.Remove(selectionStart, selectionEnd - selectionStart);
+ // selReleasePos = -1;
+ // currentCol = selBeginPos;
}
else
this.DeleteChar();
@@ -142,61 +142,26 @@ namespace Crow
case Key.RWin:
break;
case Key.Tab:
- this.Insert("\t");
- break;
- case Key.KeypadDecimal:
- this.Insert (".");
- break;
- case Key.Space:
- this.Insert(" ");
- break;
- case Key.KeypadDivide:
- case Key.Slash:
- this.Insert("/");
- break;
- case Key.KeypadMultiply:
- this.Insert("*");
- break;
- case Key.KeypadMinus:
- case Key.Minus:
- this.Insert("-");
- break;
- case Key.KeypadPlus:
- case Key.Plus:
- this.Insert("+");
- break;
- case Key.ShiftLeft:
- case Key.ShiftRight:
- case Key.AltLeft:
- case Key.AltRight:
- break;
- case Key.Semicolon:
- this.Insert(";");
+ this.Insert ("\t");
break;
default:
- if (!selectionIsEmpty)
- {
-// Text = Text.Remove(selectionStart, selectionEnd - selectionStart);
-// currentCol = selBeginPos;
- }
-
- string k = "?";
- if ((char)key >= 67 && (char)key <= 76)
- k = ((int)key - 67).ToString();
- else if ((char)key >= 109 && (char)key <= 118)
- k = ((int)key - 109).ToString();
- else if (e.Shift)
- k = key.ToString();
- else
- k = key.ToString().ToLower();
+ break;
+ }
+ if (Width < 0)
+ RegisterForLayouting (LayoutingType.Width);
+ if (Height < 0)
+ RegisterForLayouting (LayoutingType.Height);
+ RegisterForGraphicUpdate();
+ }
+ public override void onKeyPress (object sender, KeyPressEventArgs e)
+ {
+ base.onKeyPress (sender, e);
- this.Insert (k);
+ this.Insert (e.KeyChar.ToString());
- SelRelease = -1;
- SelBegin = new Point(CurrentColumn, SelBegin.Y);
+ SelRelease = -1;
+ SelBegin = new Point(CurrentColumn, SelBegin.Y);
- break;
- }
if (Width < 0)
RegisterForLayouting (LayoutingType.Width);
if (Height < 0)
diff --git a/src/Input/KeyPressEventArgs.cs b/src/Input/KeyPressEventArgs.cs
new file mode 100644
index 00000000..73990613
--- /dev/null
+++ b/src/Input/KeyPressEventArgs.cs
@@ -0,0 +1,58 @@
+// #region License
+// //
+// // The Open Toolkit Library License
+// //
+// // Copyright (c) 2006 - 2009 the Open Toolkit library.
+// //
+// // Permission is hereby granted, free of charge, to any person obtaining a copy
+// // of this software and associated documentation files (the "Software"), to deal
+// // in the Software without restriction, including without limitation the rights to
+// // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+// // the Software, and to permit persons to whom the Software is furnished to do
+// // so, subject to the following conditions:
+// //
+// // The above copyright notice and this permission notice shall be included in all
+// // copies or substantial portions of the Software.
+// //
+// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// // OTHER DEALINGS IN THE SOFTWARE.
+// //
+// #endregion
+
+using System;
+
+namespace Crow
+{
+ /// <summary>
+ /// Defines the event arguments for KeyPress events. Instances of this class are cached:
+ /// KeyPressEventArgs should only be used inside the relevant event, unless manually cloned.
+ /// </summary>
+ public class KeyPressEventArgs : EventArgs
+ {
+ char key_char;
+
+ /// <summary>
+ /// Constructs a new instance.
+ /// </summary>
+ /// <param name="keyChar">The ASCII character that was typed.</param>
+ public KeyPressEventArgs(char keyChar)
+ {
+ KeyChar = keyChar;
+ }
+
+ /// <summary>
+ /// Gets a <see cref="System.Char"/> that defines the ASCII character that was typed.
+ /// </summary>
+ public char KeyChar
+ {
+ get { return key_char; }
+ internal set { key_char = value; }
+ }
+ }
+}
diff --git a/src/Interface.cs b/src/Interface.cs
index 1084ef7b..4cb94e76 100644
--- a/src/Interface.cs
+++ b/src/Interface.cs
@@ -647,9 +647,7 @@ namespace Crow
hoverWidget.onMouseWheel (this, e);
return true;
}
-// public bool ProcessKeyDown(int Key){
-//
-// }
+
volatile bool mouseRepeatOn;
volatile int mouseRepeatCount;
Thread mouseRepeatThread;
@@ -665,6 +663,31 @@ namespace Crow
}
#endregion
+ #region Keyboard
+ public bool ProcessKeyDown(int Key){
+ Keyboard.SetKeyState ((Crow.Key)Key, true);
+ if (_focusedWidget == null)
+ return false;
+ KeyboardKeyEventArgs e = new KeyboardKeyEventArgs((Crow.Key)Key, false, Keyboard);
+ _focusedWidget.onKeyDown (this, e);
+ return true;
+ }
+ public bool ProcessKeyUp(int Key){
+ Keyboard.SetKeyState ((Crow.Key)Key, false);
+ if (_activeWidget == null)
+ return false;
+ //KeyboardKeyEventArgs e = new KeyboardKeyEventArgs((Crow.Key)Key, false, Keyboard);
+ return true;
+ }
+ public bool ProcessKeyPress(char Key){
+ if (_focusedWidget == null)
+ return false;
+ KeyPressEventArgs e = new KeyPressEventArgs(Key);
+ _focusedWidget.onKeyPress (this, e);
+ return true;
+ }
+ #endregion
+
#region ILayoutable implementation
public void RegisterClip(Rectangle r){
clipping.AddRectangle (r);