diff options
| author | j-p <jp.bruyere@live.be> | 2016-06-21 02:02:52 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-06-21 02:02:52 +0200 |
| commit | aed3905ffee6e07662290f3cf0787044ed95a360 (patch) | |
| tree | b245fd7f1454f520a58083fdefffac114e40d5ca /src | |
| parent | b3c2c1f21e96418d6b3a91ff75a182e84cb5b6a5 (diff) | |
| parent | 4e3802bba7c4d7fa564cec723ff93d5aa2c1a056 (diff) | |
Merge pull request #7 from jpbruyere/dynSizing
Dyn sizing
Diffstat (limited to 'src')
| -rw-r--r-- | src/CompilerServices/Bindings.cs | 199 | ||||
| -rw-r--r-- | src/CompilerServices/CompilerServices.cs | 519 | ||||
| -rw-r--r-- | src/CompilerServices/MemberReference.cs | 73 | ||||
| -rw-r--r-- | src/GraphicObjects/GenericStack.cs | 194 | ||||
| -rw-r--r-- | src/GraphicObjects/GraphicObject.cs | 169 | ||||
| -rw-r--r-- | src/GraphicObjects/Group.cs | 96 | ||||
| -rw-r--r-- | src/GraphicObjects/IBindable.cs | 1 | ||||
| -rw-r--r-- | src/GraphicObjects/ListBox.cs | 5 | ||||
| -rw-r--r-- | src/GraphicObjects/PrivateContainer.cs | 81 | ||||
| -rw-r--r-- | src/GraphicObjects/Splitter.cs | 12 | ||||
| -rw-r--r-- | src/Input/KeyboardState.cs | 2 | ||||
| -rw-r--r-- | src/Interface.cs | 21 | ||||
| -rw-r--r-- | src/LayoutingQueueItem.cs | 1 | ||||
| -rw-r--r-- | src/Measure.cs | 6 |
14 files changed, 715 insertions, 664 deletions
diff --git a/src/CompilerServices/Bindings.cs b/src/CompilerServices/Bindings.cs new file mode 100644 index 00000000..5931bb81 --- /dev/null +++ b/src/CompilerServices/Bindings.cs @@ -0,0 +1,199 @@ +// +// Bindings.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.Diagnostics; + +namespace Crow +{ + /// <summary> + /// Binding Class + /// </summary> + public class Binding + { + static int bindingCpt; + string dynMethodId = ""; + bool resolved; + + public bool TwoWayBinding; + public MemberReference Target; + public MemberReference Source; + + public string Expression; + + public string DynMethodId { + get { return dynMethodId; } + } + + public bool Resolved { + get { return resolved; } + set { + if (value == resolved) + return; +#if DEBUG_BINDING + if (value == true) + Debug.WriteLine ("\tOk => " + this.ToString()); + else + Debug.WriteLine ("\tresolved state reseted => " + this.ToString()); +#endif + resolved = value; + } + } + + #region CTOR + public Binding () { } + public Binding (MemberReference _target, string _expression) + { + Target = _target; + Expression = _expression; + } + public Binding (object _target, string _member, string _expression) + { + 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 string CreateNewDynMethodId () + { + if (!string.IsNullOrEmpty (dynMethodId)) + return dynMethodId; + dynMethodId = "dynHandle_" + bindingCpt; + bindingCpt++; + return dynMethodId; + } + + public bool FindSource () + { + if (Source != null) + return true; + + string member = null; + + //if binding exp = '{}' => binding is done on datasource + if (string.IsNullOrEmpty (Expression)) { + Object o = (Target.Instance as GraphicObject).DataSource; + if (o == null) + return false; + Source = new MemberReference (o); + return true; + } + + string expression = Expression; + + if (expression.StartsWith ("²")) { + expression = expression.Substring (1); + TwoWayBinding = true; + } + + string [] bindingExp = expression.Split ('/'); + + if (bindingExp.Length == 1) { + //datasource binding + Source = new MemberReference ((Target.Instance as GraphicObject).DataSource); + member = bindingExp [0]; + } else { + int ptr = 0; + ILayoutable tmp = Target.Instance as ILayoutable; + if (string.IsNullOrEmpty (bindingExp [0])) { + //if exp start with '/' => Graphic tree parsing start at top container + tmp = Interface.CurrentInterface as ILayoutable; + ptr++; + } + while (ptr < bindingExp.Length - 1) { + if (tmp == null) { +#if DEBUG_BINDING + Debug.WriteLine ("\tERROR: target not found => " + this.ToString()); +#endif + return false; + } + if (bindingExp [ptr] == "..") + tmp = tmp.LogicalParent; + else if (bindingExp [ptr] == ".") { + if (ptr > 0) + throw new Exception ("Syntax error in binding, './' may only appear in first position"); + tmp = Target.Instance as ILayoutable; + } else + tmp = (tmp as GraphicObject).FindByName (bindingExp [ptr]); + ptr++; + } + + if (tmp == null) { +#if DEBUG_BINDING + Debug.WriteLine ("\tERROR: target not found => " + this.ToString()); +#endif + return false; + } + + string [] bindTrg = bindingExp [ptr].Split ('.'); + + if (bindTrg.Length == 1) + member = bindTrg [0]; + else if (bindTrg.Length == 2) { + tmp = (tmp as GraphicObject).FindByName (bindTrg [0]); + member = bindTrg [1]; + } else + throw new Exception ("Syntax error in binding, expected 'go dot member'"); + + Source = new MemberReference (tmp); + } + if (Source == null) { + Debug.WriteLine ("Binding Source is null: " + Expression); + return false; + } + + if (Source.TryFindMember (member)) { + if (TwoWayBinding) { + IBindable source = Source.Instance as IBindable; + if (source == null) + throw new Exception (Target.Instance + " 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 () + { + Source = null; + dynMethodId = ""; + Resolved = false; + } + public override string ToString () + { + return string.Format ("[Binding: {0}.{1} <= {2}]", Target.Instance, Target.Member.Name, Expression); + } + } + +} + diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index ea46d439..71f119e2 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -1,7 +1,6 @@ using System; using System.Reflection.Emit; using System.Reflection; -using System.Collections; using System.Diagnostics; using System.Linq; using System.Collections.Generic; @@ -10,250 +9,46 @@ using System.Runtime.CompilerServices; namespace Crow { - public class MemberReference - { - public object Instance; - public MemberInfo Member; - - public PropertyInfo Property { get { return Member as PropertyInfo; } } - public FieldInfo Field { get { return Member as FieldInfo; } } - public EventInfo Event { get { return Member as EventInfo; } } - public MethodInfo Method { get { return Member as MethodInfo; } } - - public MemberReference(){ - } - public MemberReference(object _instance, MemberInfo _member = null) - { - Instance = _instance; - Member = _member; - } - public bool FindMember(string _memberName) - { - if (Instance == null) - return false; - Type t = Instance.GetType (); - 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(); - Member = CompilerServices.GetExtensionMethods(a, t).Where(em=>em.Name == _memberName).FirstOrDefault(); - } - #endregion - - return string.IsNullOrEmpty(_memberName) ? false : true; - } - } - public class Binding{ - static int bindingCpt = 0; - string dynMethodId = ""; - bool resolved = false; - - public bool TwoWayBinding = false; - - public string NewDynMethodId { - get { - if (!string.IsNullOrEmpty (dynMethodId)) - return dynMethodId; - dynMethodId = "dynHandle_" + bindingCpt; - bindingCpt++; - return dynMethodId; - } - } - public string DynMethodId { - get { return dynMethodId; } - } - - - public bool Resolved { - get { - return resolved; - } - set { - if (value == resolved) - return; - #if DEBUG_BINDING - if (value == true) - Debug.WriteLine ("\tOk => " + this.ToString()); - else - Debug.WriteLine ("\tresolved state reseted => " + this.ToString()); - #endif - resolved = value; - } - } - - public MemberReference Target; - public MemberReference Source; - - public string Expression; - - #region CTOR - public Binding(){} - public Binding(MemberReference _target, string _expression) - { - Target = _target; - Expression = _expression; - } - public Binding(object _target, string _member, string _expression) - { - 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 FindSource(){ - if (Source != null) - return true; - - string member = null; - - //if binding exp = '{}' => binding is done on datasource - if (string.IsNullOrEmpty (Expression)) { - Object o = (Target.Instance as GraphicObject).DataSource; - if (o == null) - return false; - Source = new MemberReference (o); - return true; - } - - string expression = Expression; - - if (Expression.StartsWith ("²")) { - expression = expression.Substring (1); - TwoWayBinding = true; - } - - string[] bindingExp = expression.Split ('/'); - - if (bindingExp.Length == 1) { - //datasource binding - Source = new MemberReference((Target.Instance as GraphicObject).DataSource); - member = bindingExp [0]; - } else { - int ptr = 0; - ILayoutable tmp = Target.Instance as ILayoutable; - if (string.IsNullOrEmpty (bindingExp [0])) { - //if exp start with '/' => Graphic tree parsing start at top container - tmp = Interface.CurrentInterface as ILayoutable; - ptr++; - } - while (ptr < bindingExp.Length - 1) { - if (tmp == null) { - Debug.WriteLine ("\tERROR: target not found => " + this.ToString()); - return false; - } - if (bindingExp [ptr] == "..") - tmp = tmp.LogicalParent; - else if (bindingExp [ptr] == ".") { - if (ptr > 0) - throw new Exception ("Syntax error in binding, './' may only appear in first position"); - tmp = Target.Instance as ILayoutable; - }else - tmp = (tmp as GraphicObject).FindByName (bindingExp [ptr]); - ptr++; - } - - if (tmp == null) { - Debug.WriteLine ("\tERROR: target not found => " + this.ToString()); - return false; - } - - string[] bindTrg = bindingExp [ptr].Split ('.'); - - if (bindTrg.Length == 1) - member = bindTrg [0]; - else if (bindTrg.Length == 2){ - tmp = (tmp as GraphicObject).FindByName (bindTrg [0]); - member = bindTrg [1]; - } else - throw new Exception ("Syntax error in binding, expected 'go dot member'"); - - Source = new MemberReference(tmp); - } - if (Source == null) { - Debug.WriteLine ("Binding Source is null: " + Expression); - return false; - } - - 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() - { - Source = null; - dynMethodId = ""; - Resolved = false; - } - public override string ToString () - { - return string.Format ("[Binding: {0}.{1} <= {2}]", Target.Instance, Target.Member.Name, Expression); - } - } - - - public static class CompilerServices { - public static void ResolveBindings(List<Binding> Bindings) + 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 + //#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>>(); + 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); + 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()); + 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 }); + addHandler.Invoke (b.Target.Instance, new object [] { del }); - #if DEBUG_BINDING +#if DEBUG_BINDING Debug.WriteLine ("\tHandler binded => " + b.ToString()); - #endif +#endif b.Resolved = true; } catch (Exception ex) { - Debug.WriteLine ("\tERROR: " + ex.ToString()); + Debug.WriteLine ("\tERROR: " + ex.ToString ()); } continue; } @@ -270,63 +65,63 @@ namespace Crow 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 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 (); + 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"); + 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(); + 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(); + 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, + if (source_Type.GetInterfaces ().Contains (typeof (IValueChange))) { + dm = new DynamicMethod (grouped [0].CreateNewDynMethodId (), MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot, CallingConventions.Standard, - typeof(void), + typeof (void), args, - target_Type,true); + target_Type, true); - il = dm.GetILGenerator(256); + il = dm.GetILGenerator (256); - endMethod = il.DefineLabel(); - jumpTable = new System.Reflection.Emit.Label[grouped.Count]; + 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.DeclareLocal (typeof (string)); + il.DeclareLocal (typeof (object)); - il.Emit(OpCodes.Nop); - il.Emit(OpCodes.Ldarg_0); + 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); + 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); + 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 @@ -334,35 +129,39 @@ namespace Crow foreach (Binding b in grouped) { #region initialize target with actual value object targetValue = null; - if (b.Source.Member != 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){ + 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}); + if (mthSrc.IsDefined (typeof (ExtensionAttribute), false)) + targetValue = mthSrc.Invoke (null, new object [] { b.Source.Instance }); else - targetValue = mthSrc.Invoke(b.Source.Instance, null); - }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){ + } 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 + } 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 }); + try { + 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 }); + } catch (Exception ex) { + Debug.WriteLine (ex.ToString ()); + } #endregion //if no dyn update, skip jump table @@ -373,10 +172,10 @@ namespace Crow 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.Ldstr, b.Expression.Split ('/').LastOrDefault ()); il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal il.Emit (OpCodes.Callvirt, stringEquals); - il.Emit (OpCodes.Brtrue, jumpTable[i]); + il.Emit (OpCodes.Brtrue, jumpTable [i]); i++; } @@ -389,7 +188,21 @@ namespace Crow foreach (Binding b in grouped) { il.MarkLabel (jumpTable [i]); - il.Emit(OpCodes.Ldloc_1); + + + //load 2 times to check first for null + il.Emit (OpCodes.Ldloc_1); + il.Emit (OpCodes.Ldloc_1); + + System.Reflection.Emit.Label labSetValue = il.DefineLabel (); + il.Emit (OpCodes.Brtrue, labSetValue); + //if null + il.Emit (OpCodes.Unbox_Any, b.Target.Property.PropertyType); + il.Emit (OpCodes.Callvirt, b.Target.Property.GetSetMethod ()); + il.Emit (OpCodes.Br, endMethod); + + il.MarkLabel (labSetValue); + //new value not null //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 @@ -404,193 +217,203 @@ namespace Crow throw new Exception ("unhandle target member type in binding"); } - if (b.Target.Property.PropertyType == typeof(string)) { + + + if (b.Target.Property.PropertyType == typeof (string)) { MemberReference tostring = new MemberReference (b.Target.Instance); - if (!tostring.FindMember ("ToString")) + 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.Target.Property.PropertyType != sourceValueType) { il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (b.Target.Property.PropertyType)); - }else - il.Emit(OpCodes.Unbox_Any, b.Target.Property.PropertyType); + } else + il.Emit (OpCodes.Unbox_Any, b.Target.Property.PropertyType); + + il.Emit (OpCodes.Callvirt, b.Target.Property.GetSetMethod ()); + + //il.BeginCatchBlock (typeof (Exception)); + //il.Emit (OpCodes.Pop); + //il.EndExceptionBlock (); - 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); + il.MarkLabel (endMethod); + il.Emit (OpCodes.Pop); + il.Emit (OpCodes.Ret); - Delegate del = dm.CreateDelegate(ei.EventHandlerType, Bindings[0].Target.Instance); + Delegate del = dm.CreateDelegate (ei.EventHandlerType, Bindings [0].Target.Instance); MethodInfo addHandler = ei.GetAddMethod (); - addHandler.Invoke(grouped [0].Source.Instance, new object[] {del}); + 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) + /// <param name="binding">Event binding details</param> + public static void CompileEventSource (Binding binding) { - #if DEBUG_BINDING +#if DEBUG_BINDING Debug.WriteLine ("\tCompile Event Source => " + binding.ToString()); - #endif +#endif - Type target_type = binding.Target.Instance.GetType(); + Type target_type = binding.Target.Instance.GetType (); #region Retrieve EventHandler parameter type MethodInfo evtInvoke = binding.Target.Event.EventHandlerType.GetMethod ("Invoke"); - ParameterInfo[] evtParams = evtInvoke.GetParameters (); + 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), + Type [] args = { typeof (object), typeof (object), handlerArgsType }; + DynamicMethod dm = new DynamicMethod (binding.CreateNewDynMethodId (), + typeof (void), args, target_type); #region IL generation - ILGenerator il = dm.GetILGenerator(256); + ILGenerator il = dm.GetILGenerator (256); - string src = binding.Expression.Trim(); + 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)); + 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[] { ';' }); + string [] srcLines = src.Split (new char [] { ';' }); foreach (string srcLine in srcLines) { string statement = srcLine.Trim (); - string[] operandes = statement.Split (new char[] { '=' }); + 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 (); + 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 + 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 + il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack - string[] lopParts = lop.Split (new char[] { '.' }); + string [] lopParts = lop.Split (new char [] { '.' }); if (lopParts.Length > 1) {//should search also for member of es.Source - MethodInfo FindByNameMi = typeof(GraphicObject).GetMethod("FindByName"); + 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); + il.Emit (OpCodes.Ldstr, lopParts [j]); + il.Emit (OpCodes.Callvirt, FindByNameMi); } } - int i = lopParts.Length -1; + int i = lopParts.Length - 1; - MemberInfo[] lopMbis = lopObj.GetType().GetMember (lopParts[i]); + MemberInfo [] lopMbis = lopObj.GetType ().GetMember (lopParts [i]); - if (lopMbis.Length<1) - throw new Exception (string.Format("CROW BINDING: Member not found '{0}'", lop)); + 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) { + switch (lopMbis [0].MemberType) { case MemberTypes.Property: - PropertyInfo lopPi = target_type.GetProperty (lopParts[i]); + 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]); + 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])); + throw new Exception (string.Format ("GOML:member type not handle: {0}", lopParts [i])); } #endregion #region RIGHT OPERANDES - if (rop.StartsWith("\'")){ - if (!rop.EndsWith("\'")) + 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); + il.Emit (OpCodes.Ldstr, strcst); - }else{ + } else { if (lopT.IsEnum) - throw new NotImplementedException(); + throw new NotImplementedException (); - MethodInfo lopParseMi = lopT.GetMethod("Parse"); + 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); + 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 (lopSetOC, lopSetMbi); } - il.Emit(OpCodes.Ret); + il.Emit (OpCodes.Ret); #endregion - Delegate del = dm.CreateDelegate(binding.Target.Event.EventHandlerType, binding.Target.Instance); + 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}); + addHandler.Invoke (binding.Target.Instance, new object [] { del }); binding.Resolved = true; } #region conversions - internal static MethodInfo GetConvertMethod( Type targetType ) + internal static MethodInfo GetConvertMethod (Type targetType) { string name; - if( targetType == typeof( bool ) ) + if (targetType == typeof (bool)) name = "ToBoolean"; - else if( targetType == typeof( byte ) ) + else if (targetType == typeof (byte)) name = "ToByte"; - else if( targetType == typeof( short ) ) + else if (targetType == typeof (short)) name = "ToInt16"; - else if( targetType == typeof( int ) ) + else if (targetType == typeof (int)) name = "ToInt32"; - else if( targetType == typeof( long ) ) + else if (targetType == typeof (long)) name = "ToInt64"; - else if( targetType == typeof( double ) ) + else if (targetType == typeof (double)) name = "ToDouble"; - else if( targetType == typeof( float ) ) + else if (targetType == typeof (float)) name = "ToSingle"; - else if (targetType == typeof (string ) ) - return typeof(object).GetMethod("ToString", Type.EmptyTypes); + 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 ) ); + 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 typeof (Convert).GetMethod (name, BindingFlags.Static | BindingFlags.Public, null, new Type [] { typeof (object) }, null); } #endregion - - public static FieldInfo GetEventHandlerField(Type type, string eventName) + + /// <summary> + /// retrieve event handler in class or ancestors + /// </summary> + public static FieldInfo GetEventHandlerField (Type type, string eventName) { FieldInfo fi; Type ty = type; @@ -602,17 +425,17 @@ namespace Crow ty = ty.BaseType; if (ty == null) break; - } while(fi == null); + } while (fi == null); return fi; } - + /// <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, + public static IEnumerable<MethodInfo> GetExtensionMethods (Assembly assembly, Type extendedType) { IEnumerable<MethodInfo> query = null; @@ -620,19 +443,19 @@ namespace Crow 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; + 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; - if (query.Count() > 0) + if (query.Count () > 0) break; - + curType = curType.BaseType; } while (curType != null); - + return query; } } diff --git a/src/CompilerServices/MemberReference.cs b/src/CompilerServices/MemberReference.cs new file mode 100644 index 00000000..1dc3a3e4 --- /dev/null +++ b/src/CompilerServices/MemberReference.cs @@ -0,0 +1,73 @@ +// +// MemberReference.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 +{ + /// <summary> + /// link MemberInfo and instance in one class + /// </summary> + public class MemberReference + { + public object Instance; + public MemberInfo Member; + + public PropertyInfo Property { get { return Member as PropertyInfo; } } + public FieldInfo Field { get { return Member as FieldInfo; } } + public EventInfo Event { get { return Member as EventInfo; } } + public MethodInfo Method { get { return Member as MethodInfo; } } + + #region CTOR + public MemberReference () {} + public MemberReference (object _instance, MemberInfo _member = null) + { + Instance = _instance; + Member = _member; + } + #endregion + + /// <summary> + /// Try to find member by name in instance class or, if not found, + /// in extension methods + /// </summary> + /// <returns>True if found, false otherwise</returns> + /// <param name="_memberName">Member name to search for</param> + public bool TryFindMember (string _memberName) + { + if (Instance == null) + return false; + Type t = Instance.GetType (); + 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 (); + Member = CompilerServices.GetExtensionMethods (a, t).Where (em => em.Name == _memberName).FirstOrDefault (); + } + #endregion + + return Member != null; + } + } +} + diff --git a/src/GraphicObjects/GenericStack.cs b/src/GraphicObjects/GenericStack.cs index 455ed928..adf428c5 100644 --- a/src/GraphicObjects/GenericStack.cs +++ b/src/GraphicObjects/GenericStack.cs @@ -1,14 +1,10 @@ -using System; +using System.ComponentModel; using System.Diagnostics; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Xml.Serialization; -using System.ComponentModel; namespace Crow { - public class GenericStack : Group + public class GenericStack : Group { #region CTOR public GenericStack() @@ -54,41 +50,20 @@ namespace Crow } protected override int measureRawSize (LayoutingType lt) { - int tmp = 0; - switch (lt) { - case LayoutingType.Width: - if (Orientation == Orientation.Horizontal) { - if (Children.Count > 0) { - foreach (GraphicObject c in Children) { - if (!c.Visible) - continue; - if (c.RegisteredLayoutings.HasFlag (LayoutingType.Width)) - return -1; - tmp += c.Slot.Width + Spacing; - } - tmp -= Spacing; - } - break; - } - return base.measureRawSize (lt); - case LayoutingType.Height: - if (Orientation == Orientation.Vertical) { - if (Children.Count > 0) { - foreach (GraphicObject c in Children) { - if (!c.Visible) - continue; - if (c.RegisteredLayoutings.HasFlag (LayoutingType.Height)) - return -1; - tmp += c.Slot.Height + Spacing; - } - tmp -= Spacing; - } - break; - } - return base.measureRawSize (lt); + int totSpace = 0; + for (int i = 0; i < Children.Count; i++) { + if (Children [i].Visible) + totSpace += Spacing; } - - return tmp + 2 * Margin; + if (totSpace > 0) + totSpace -= Spacing; + if (lt == LayoutingType.Width) { + if (Orientation == Orientation.Horizontal) + return contentSize.Width + totSpace + 2 * Margin; + }else if (Orientation == Orientation.Vertical) + return contentSize.Height + totSpace + 2 * Margin; + + return base.measureRawSize (lt); } public virtual void ComputeChildrenPositions() { @@ -99,7 +74,6 @@ namespace Crow continue; c.Slot.X = d; d += c.Slot.Width + Spacing; - c.RegisterForLayouting (LayoutingType.Y); } } else { foreach (GraphicObject c in Children) { @@ -107,12 +81,11 @@ namespace Crow continue; c.Slot.Y = d; d += c.Slot.Height + Spacing; - c.RegisterForLayouting (LayoutingType.X); } } bmp = null; } - + GraphicObject stretchedGO = null; public override bool UpdateLayout (LayoutingType layoutType) { RegisteredLayoutings &= (~layoutType); @@ -122,86 +95,6 @@ namespace Crow //this child will occupy remaining space //if stack size policy is Fit, no child may have stretch enabled //in the direction of stacking. - if (Orientation == Orientation.Horizontal) { - GraphicObject stretchedGO = null; - int tmpWidth = Slot.Width; - int cptChildren = 0; - for (int i = 0; i < Children.Count; i++) { - if (!Children [i].Visible) - continue; - //requeue Positionning if child is not layouted - if (Children [i].RegisteredLayoutings.HasFlag (LayoutingType.Width)) - return false; - cptChildren++; - if (Children [i].Width == Measure.Stretched) { - if (!(stretchedGO == null && Width != Measure.Fit)) { - //change size policy of other stretched children - Children [i].Width = Measure.Fit; - return false; - } - stretchedGO = Children [i]; - if (i < Children.Count - 1) - tmpWidth -= Spacing; - continue; - } - tmpWidth -= Children [i].Slot.Width + Spacing; - } - if (stretchedGO != null && Width != Measure.Fit) { - tmpWidth += (Spacing - 2 * Margin); - if (tmpWidth < MinimumSize.Width) - tmpWidth = MinimumSize.Width; - else if (tmpWidth > MaximumSize.Width && MaximumSize.Width > 0) - tmpWidth = MaximumSize.Width; - if (stretchedGO.LastSlots.Width != tmpWidth) { - stretchedGO.Slot.Width = tmpWidth; - stretchedGO.bmp = null; - #if DEBUG_LAYOUTING - Debug.WriteLine ("\tAdjusting Width of " + stretchedGO.ToString()); - #endif - stretchedGO.OnLayoutChanges (LayoutingType.Width); - stretchedGO.LastSlots.Width = stretchedGO.Slot.Width; - } - } - } else { - GraphicObject stretchedGO = null; - int tmpHeight = Slot.Height; - int cptChildren = 0; - for (int i = 0; i < Children.Count; i++) { - if (!Children [i].Visible) - continue; - if (Children [i].RegisteredLayoutings.HasFlag (LayoutingType.Height)) - return false; - cptChildren++; - if (Children [i].Height == Measure.Stretched) { - if (!(stretchedGO == null && Height != Measure.Fit)){ - Children [i].Height = Measure.Fit; - return false; - } - stretchedGO = Children [i]; - if (i < Children.Count - 1) - tmpHeight -= Spacing; - continue; - } - tmpHeight -= Children[i].Slot.Height + Spacing; - } - if (stretchedGO != null && Height != Measure.Fit) { - tmpHeight += (Spacing - 2 * Margin); - if (tmpHeight < MinimumSize.Height) - tmpHeight = MinimumSize.Height; - else if (tmpHeight > MaximumSize.Height && MaximumSize.Height > 0) - tmpHeight = MaximumSize.Height; - if (stretchedGO.LastSlots.Height != tmpHeight) { - stretchedGO.Slot.Height = tmpHeight; - stretchedGO.bmp = null; - #if DEBUG_LAYOUTING - Debug.WriteLine ("\tAdjusting Height of " + stretchedGO.ToString()); - #endif - stretchedGO.OnLayoutChanges (LayoutingType.Height); - stretchedGO.LastSlots.Height = stretchedGO.Slot.Height; - } - } - } - ComputeChildrenPositions (); //if no layouting remains in queue for item, registre for redraw @@ -216,24 +109,75 @@ namespace Crow public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) { - base.OnChildLayoutChanges (sender, arg); - + GraphicObject go = sender as GraphicObject; + //Debug.WriteLine ("child layout change: " + go.LastSlots.ToString() + " => " + go.Slot.ToString()); switch (arg.LayoutType) { case LayoutingType.Width: if (Orientation == Orientation.Horizontal) { + if (go.Width == Measure.Stretched) { + if (stretchedGO == null && Width != Measure.Fit) + stretchedGO = go; + else if (stretchedGO != go) { + go.Slot.Width = 0; + go.Width = Measure.Fit; + return; + } + } else + contentSize.Width += go.Slot.Width - go.LastSlots.Width; + + if (stretchedGO != null) { + stretchedGO.Slot.Width = this.ClientRectangle.Width - contentSize.Width - Spacing * (Children.Count - 1); + stretchedGO.bmp = null; +#if DEBUG_LAYOUTING + Debug.WriteLine ("\tAdjusting Width of " + stretchedGO.ToString()); +#endif + stretchedGO.LayoutChanged -= OnChildLayoutChanges; + stretchedGO.OnLayoutChanges (LayoutingType.Width); + stretchedGO.LayoutChanged += OnChildLayoutChanges; + stretchedGO.LastSlots.Width = stretchedGO.Slot.Width; + } + if (Width == Measure.Fit) this.RegisterForLayouting (LayoutingType.Width); + this.RegisterForLayouting (LayoutingType.ArrangeChildren); + return; } break; case LayoutingType.Height: if (Orientation == Orientation.Vertical) { + if (go.Height == Measure.Stretched) { + if (stretchedGO == null && Height != Measure.Fit) + stretchedGO = go; + else if (stretchedGO != go){ + go.Slot.Height = 0; + go.Height = Measure.Fit; + return; + } + } else + contentSize.Height += go.Slot.Height - go.LastSlots.Height; + + if (stretchedGO != null) { + stretchedGO.Slot.Height = this.ClientRectangle.Height - contentSize.Height - Spacing * (Children.Count -1); + stretchedGO.bmp = null; +#if DEBUG_LAYOUTING + Debug.WriteLine ("\tAdjusting Width of " + stretchedGO.ToString()); +#endif + stretchedGO.LayoutChanged -= OnChildLayoutChanges; + stretchedGO.OnLayoutChanges (LayoutingType.Height); + stretchedGO.LayoutChanged += OnChildLayoutChanges; + stretchedGO.LastSlots.Height = stretchedGO.Slot.Height; + } + if (Height == Measure.Fit) this.RegisterForLayouting (LayoutingType.Height); + this.RegisterForLayouting (LayoutingType.ArrangeChildren); + return; } break; } + base.OnChildLayoutChanges (sender, arg); } #endregion diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 4e230d4f..16371e51 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -22,10 +22,8 @@ namespace Crow #endregion - #if DEBUG_LAYOUTING internal static ulong currentUid = 0; internal ulong uid = 0; - #endif internal int layoutingTries = 0; @@ -44,10 +42,8 @@ namespace Crow #region CTOR public GraphicObject () { - #if DEBUG_LAYOUTING uid = currentUid; currentUid++; - #endif if (Interface.XmlSerializerInit) return; @@ -398,7 +394,8 @@ namespace Crow if (Parent is GenericStack) (Parent as GraphicObject).RegisterForLayouting (LayoutingType.ArrangeChildren); - RegisterForLayouting (LayoutingType.Sizing); + if (_isVisible) + RegisterForLayouting (LayoutingType.Sizing); RegisterForGraphicUpdate (); NotifyValueChanged ("Visible", _isVisible); @@ -664,15 +661,14 @@ namespace Crow get { return layoutingTries; } set { layoutingTries = value; } } + protected Size contentSize; /// <summary> return size of content + margins </summary> protected virtual int measureRawSize (LayoutingType lt) { return lt == LayoutingType.Width ? - Width == Measure.Fit ? MinimumSize.Width : (int)Width : - Height == Measure.Fit ? MinimumSize.Height : (int)Height; + contentSize.Width + 2 * Margin: contentSize.Height + 2 * Margin; } /// <summary> By default in groups, LayoutingType.ArrangeChildren is reset </summary> public virtual void ChildrenLayoutingConstraints(ref LayoutingType layoutType){ - } public virtual bool ArrangeChildren { get { return false; } } public virtual void RegisterForLayouting(LayoutingType layoutType){ @@ -680,9 +676,9 @@ namespace Crow return; lock (Interface.CurrentInterface.LayoutMutex) { //dont set position for stretched item - if (Width == 0) + if (Width == Measure.Stretched) layoutType &= (~LayoutingType.X); - if (Height == 0) + if (Height == Measure.Stretched) layoutType &= (~LayoutingType.Y); if (!ArrangeChildren) @@ -747,7 +743,7 @@ namespace Crow if (Left == 0) { if (Parent.RegisteredLayoutings.HasFlag (LayoutingType.Width) || - RegisteredLayoutings.HasFlag (LayoutingType.Width)) + RegisteredLayoutings.HasFlag (LayoutingType.Width)) return false; switch (HorizontalAlignment) { @@ -763,21 +759,12 @@ namespace Crow } } else Slot.X = Left; - - if (LastSlots.X == Slot.X) - break; - - bmp = null; - - OnLayoutChanges (layoutType); - - LastSlots.X = Slot.X; break; case LayoutingType.Y: if (Top == 0) { if (Parent.RegisteredLayoutings.HasFlag (LayoutingType.Height) || - RegisteredLayoutings.HasFlag (LayoutingType.Height)) + RegisteredLayoutings.HasFlag (LayoutingType.Height)) return false; switch (VerticalAlignment) { @@ -791,42 +778,97 @@ namespace Crow Slot.Y = Parent.ClientRectangle.Height / 2 - Slot.Height / 2; break; } - }else + } else Slot.Y = Top; + break; + case LayoutingType.Width: + if (Visible) { + if (Width.IsFixed) + Slot.Width = Width; + else if (Width == Measure.Fit) { + Slot.Width = measureRawSize (LayoutingType.Width); + } else if (Parent.RegisteredLayoutings.HasFlag (LayoutingType.Width)) + return false; + else if (Width == Measure.Stretched) + Slot.Width = Parent.ClientRectangle.Width; + else + Slot.Width = (int)Math.Round ((double)(Parent.ClientRectangle.Width * Width) / 100.0); - if (LastSlots.Y == Slot.Y) + if (Slot.Width < 0) + return false; + + //size constrain + if (Slot.Width < MinimumSize.Width) { + Slot.Width = MinimumSize.Width; + //NotifyValueChanged ("WidthPolicy", Measure.Stretched); + } else if (Slot.Width > MaximumSize.Width && MaximumSize.Width > 0) { + Slot.Width = MaximumSize.Width; + //NotifyValueChanged ("WidthPolicy", Measure.Stretched); + } + } else + Slot.Width = 0; + break; + case LayoutingType.Height: + if (Visible) { + if (Height.IsFixed) + Slot.Height = Height; + else if (Height == Measure.Fit) { + Slot.Height = measureRawSize (LayoutingType.Height); + } else if (Parent.RegisteredLayoutings.HasFlag (LayoutingType.Height)) + return false; + else if (Height == Measure.Stretched) + Slot.Height = Parent.ClientRectangle.Height; + else + Slot.Height = (int)Math.Round ((double)(Parent.ClientRectangle.Height * Height) / 100.0); + + if (Slot.Height < 0) + return false; + + //size constrain + if (Slot.Height < MinimumSize.Height) { + Slot.Height = MinimumSize.Height; + //NotifyValueChanged ("HeightPolicy", Measure.Stretched); + } else if (Slot.Height > MaximumSize.Height && MaximumSize.Height > 0) { + Slot.Height = MaximumSize.Height; + //NotifyValueChanged ("HeightPolicy", Measure.Stretched); + } + } else + Slot.Height = 0; + break; + } + + updateSlot (layoutType); + + //if no layouting remains in queue for item, registre for redraw + if (this.registeredLayoutings == LayoutingType.None && bmp == null) + this.AddToRedrawList (); + + return true; + } + protected void updateSlot(LayoutingType layoutType) + { + switch (layoutType) { + case LayoutingType.X: + if (LastSlots.X == Slot.X) break; bmp = null; OnLayoutChanges (layoutType); - LastSlots.Y = Slot.Y; + LastSlots.X = Slot.X; break; - case LayoutingType.Width: - if (Width.IsFixed) - Slot.Width = Width; - else if (Width == Measure.Fit) { - Slot.Width = measureRawSize (LayoutingType.Width); - } else if (Parent.RegisteredLayoutings.HasFlag (LayoutingType.Width)) - return false; - else if (Width == Measure.Stretched) - Slot.Width = Parent.ClientRectangle.Width; - else - Slot.Width = (int)Math.Round((double)(Parent.ClientRectangle.Width * Width) / 100.0); + case LayoutingType.Y: + if (LastSlots.Y == Slot.Y) + break; - if (Slot.Width < 0) - return false; + bmp = null; - //size constrain - if (Slot.Width < MinimumSize.Width) { - Slot.Width = MinimumSize.Width; - NotifyValueChanged ("WidthPolicy", Measure.Stretched); - } else if (Slot.Width > MaximumSize.Width && MaximumSize.Width > 0) { - Slot.Width = MaximumSize.Width; - NotifyValueChanged ("WidthPolicy", Measure.Stretched); - } + OnLayoutChanges (layoutType); + LastSlots.Y = Slot.Y; + break; + case LayoutingType.Width: if (LastSlots.Width == Slot.Width) break; @@ -834,32 +876,9 @@ namespace Crow OnLayoutChanges (layoutType); - LastSlots.Width = Slot.Width; + LastSlots.Width = Slot.Width; break; case LayoutingType.Height: - if (Height.IsFixed) - Slot.Height = Height; - else if (Height == Measure.Fit) { - Slot.Height = measureRawSize (LayoutingType.Height); - } else if (Parent.RegisteredLayoutings.HasFlag (LayoutingType.Height)) - return false; - else if (Height == Measure.Stretched) - Slot.Height = Parent.ClientRectangle.Height; - else - Slot.Height = (int)Math.Round((double)(Parent.ClientRectangle.Height * Height) / 100.0); - - if (Slot.Height < 0) - return false; - - //size constrain - if (Slot.Height < MinimumSize.Height) { - Slot.Height = MinimumSize.Height; - NotifyValueChanged ("HeightPolicy", Measure.Stretched); - } else if (Slot.Height > MaximumSize.Height && MaximumSize.Height > 0) { - Slot.Height = MaximumSize.Height; - NotifyValueChanged ("HeightPolicy", Measure.Stretched); - } - if (LastSlots.Height == Slot.Height) break; @@ -867,15 +886,9 @@ namespace Crow OnLayoutChanges (layoutType); - LastSlots.Height = Slot.Height; + LastSlots.Height = Slot.Height; break; } - - //if no layouting remains in queue for item, registre for redraw - if (this.registeredLayoutings == LayoutingType.None && bmp == null) - this.AddToRedrawList (); - - return true; } #endregion @@ -1199,9 +1212,9 @@ namespace Crow if (!string.IsNullOrEmpty (xaa.AttributeName)) name = xaa.AttributeName; } - if (value.StartsWith("{")) { + if (value.StartsWith("{",StringComparison.Ordinal)) { //binding - if (!value.EndsWith("}")) + if (!value.EndsWith("}", StringComparison.Ordinal)) throw new Exception (string.Format("GOML:Malformed binding: {0}", value)); this.Bindings.Add (new Binding (new MemberReference(this, pi), value.Substring (1, value.Length - 2))); diff --git a/src/GraphicObjects/Group.cs b/src/GraphicObjects/Group.cs index 78c5bca3..2b440ac1 100644 --- a/src/GraphicObjects/Group.cs +++ b/src/GraphicObjects/Group.cs @@ -21,8 +21,6 @@ namespace Crow public event EventHandler<EventArgs> ChildrenCleared; #endregion - internal int maxChildrenWidth = 0; - internal int maxChildrenHeight = 0; internal GraphicObject largestChild = null; internal GraphicObject tallestChild = null; @@ -59,9 +57,9 @@ namespace Crow //child.Parent = null; Children.Remove(child); - if (child == largestChild) + if (child == largestChild && Width == Measure.Fit) searchLargestChild (); - if (child == tallestChild) + if (child == tallestChild && Height == Measure.Fit) searchTallestChild (); this.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren); @@ -130,28 +128,26 @@ namespace Crow } protected override int measureRawSize (LayoutingType lt) { - if (Children.Count == 0) - return base.measureRawSize (lt); - - if (lt == LayoutingType.Width) { - if (largestChild == null) - searchLargestChild (); - if (largestChild == null){ - //if still null, not possible to determine a width - //because all children are stretched, force first one to fit - Children[0].Width = Measure.Fit; - return -1;//cancel actual sizing to let child computation take place - } - return maxChildrenWidth + 2 * Margin; - }else{ - if (tallestChild == null) - searchTallestChild (); - if (tallestChild == null) { - Children[0].Height = Measure.Fit; - return -1; + if (Children.Count > 0) { + if (lt == LayoutingType.Width) { + if (largestChild == null) + searchLargestChild (); + if (largestChild == null) { + //if still null, not possible to determine a width + //because all children are stretched, force first one to fit + Children [0].Width = Measure.Fit; + return -1;//cancel actual sizing to let child computation take place + } + } else { + if (tallestChild == null) + searchTallestChild (); + if (tallestChild == null) { + Children [0].Height = Measure.Fit; + return -1; + } } - return maxChildrenHeight + 2 * Margin; } + return base.measureRawSize (lt); } public override void OnLayoutChanges (LayoutingType layoutType) @@ -173,36 +169,29 @@ namespace Crow public virtual void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) { GraphicObject g = sender as GraphicObject; + switch (arg.LayoutType) { case LayoutingType.Width: - if (g.Slot.Width > maxChildrenWidth) { - maxChildrenWidth = g.Slot.Width; + if (Width != Measure.Fit) + return; + if (g.Slot.Width > contentSize.Width) { largestChild = g; - if (Width == Measure.Fit) - this.RegisterForLayouting (LayoutingType.Width); - } else if (g == largestChild) { - - largestChild = null; - maxChildrenWidth = 0; + contentSize.Width = g.Slot.Width; + } else if (g == largestChild) + searchLargestChild (); - if (Width == Measure.Fit) - this.RegisterForLayouting (LayoutingType.Width); - } + this.RegisterForLayouting (LayoutingType.Width); break; case LayoutingType.Height: - if (g.Slot.Height > maxChildrenHeight) { - maxChildrenHeight = g.Slot.Height; + if (Height != Measure.Fit) + return; + if (g.Slot.Height > contentSize.Height) { tallestChild = g; - if (Height == Measure.Fit) - this.RegisterForLayouting (LayoutingType.Height); - } else if (g == tallestChild) { - - tallestChild = null; - maxChildrenHeight = 0; + contentSize.Height = g.Slot.Height; + } else if (g == tallestChild) + searchTallestChild (); - if (Height == Measure.Fit) - this.RegisterForLayouting (LayoutingType.Height); - } + this.RegisterForLayouting (LayoutingType.Height); break; } } @@ -211,22 +200,21 @@ namespace Crow void resetChildrenMaxSize(){ largestChild = null; tallestChild = null; - maxChildrenWidth = 0; - maxChildrenHeight = 0; + contentSize = 0; } void searchLargestChild(){ #if DEBUG_LAYOUTING Debug.WriteLine("\tSearch largest child"); #endif largestChild = null; - maxChildrenWidth = 0; + contentSize.Width = 0; for (int i = 0; i < Children.Count; i++) { if (!Children [i].Visible) continue; if (children [i].RegisteredLayoutings.HasFlag (LayoutingType.Width)) continue; - if (Children [i].Slot.Width > maxChildrenWidth) { - maxChildrenWidth = Children [i].Slot.Width; + if (Children [i].Slot.Width > contentSize.Width) { + contentSize.Width = Children [i].Slot.Width; largestChild = Children [i]; } } @@ -236,14 +224,14 @@ namespace Crow Debug.WriteLine("\tSearch tallest child"); #endif tallestChild = null; - maxChildrenHeight = 0; + contentSize.Height = 0; for (int i = 0; i < Children.Count; i++) { if (!Children [i].Visible) continue; if (children [i].RegisteredLayoutings.HasFlag (LayoutingType.Height)) continue; - if (Children [i].Slot.Height > maxChildrenHeight) { - maxChildrenHeight = Children [i].Slot.Height; + if (Children [i].Slot.Height > contentSize.Height) { + contentSize.Height = Children [i].Slot.Height; tallestChild = Children [i]; } } diff --git a/src/GraphicObjects/IBindable.cs b/src/GraphicObjects/IBindable.cs index 642c1e9e..45ff5864 100644 --- a/src/GraphicObjects/IBindable.cs +++ b/src/GraphicObjects/IBindable.cs @@ -26,6 +26,7 @@ namespace Crow public interface IBindable { List<Binding> Bindings { get; } + object DataSource { get; set; } } } diff --git a/src/GraphicObjects/ListBox.cs b/src/GraphicObjects/ListBox.cs index 54871241..34834b8d 100644 --- a/src/GraphicObjects/ListBox.cs +++ b/src/GraphicObjects/ListBox.cs @@ -93,7 +93,7 @@ namespace Crow } } public object SelectedItem{ - get { return data == null ? "" : _selectedIndex < 0 ? "" : data[_selectedIndex]; } + get { return data == null ? null : _selectedIndex < 0 ? null : data[_selectedIndex]; } } [XmlAttributeAttribute]//[DefaultValue(null)] public IList Data { @@ -207,6 +207,9 @@ namespace Crow } protected void _list_LayoutChanged (object sender, LayoutingEventArgs e) { +#if DEBUG_LAYOUTING + Debug.WriteLine("list_LayoutChanged"); +#endif if (_gsList.Orientation == Orientation.Horizontal) { if (e.LayoutType == LayoutingType.Width) _gsList.Width = approxSize; diff --git a/src/GraphicObjects/PrivateContainer.cs b/src/GraphicObjects/PrivateContainer.cs index 99b85dd2..16a797d7 100644 --- a/src/GraphicObjects/PrivateContainer.cs +++ b/src/GraphicObjects/PrivateContainer.cs @@ -51,6 +51,7 @@ namespace Crow { if (child != null) { + contentSize = new Size (0, 0); child.LayoutChanged -= OnChildLayoutChanges; this.RegisterForLayouting (LayoutingType.Sizing); child.Parent = null; @@ -61,6 +62,7 @@ namespace Crow if (child != null) { child.Parent = this; child.LayoutChanged += OnChildLayoutChanges; + contentSize = child.Slot.Size; child.RegisterForLayouting (LayoutingType.Sizing); } @@ -90,22 +92,17 @@ namespace Crow return child == goToFind ? true : child == null ? false : child.Contains(goToFind); } - protected override int measureRawSize (LayoutingType lt) - { - if (child == null) - return base.measureRawSize (lt); - if (lt == LayoutingType.Width) - return child.RegisteredLayoutings.HasFlag(LayoutingType.Width) ? - -1 : child.Slot.Size.Width + 2 * Margin; - else - return child.RegisteredLayoutings.HasFlag(LayoutingType.Height) ? - -1 : child.Slot.Size.Height + 2 * Margin; + public override void ChildrenLayoutingConstraints (ref LayoutingType layoutType) + { + if (Width == Measure.Fit) + layoutType &= (~LayoutingType.X); + if (Height == Measure.Fit) + layoutType &= (~LayoutingType.Y); } public override bool UpdateLayout (LayoutingType layoutType) { if (child != null) { - //force sizing to fit if sizing on children and - //child has stretched size + //force sizing to fit if sizing on children and child has stretched size switch (layoutType) { case LayoutingType.Width: if (Width == Measure.Fit && child.Width.Units == Unit.Percent) @@ -123,34 +120,46 @@ namespace Crow { base.OnLayoutChanges (layoutType); - switch (layoutType) { - case LayoutingType.Width: - if (child != null) { - child.RegisterForLayouting (LayoutingType.X | LayoutingType.Width); + if (child == null) + return; + + LayoutingType ltChild = LayoutingType.None; + + if (layoutType == LayoutingType.Width) { + if (Width == Measure.Fit) + return; + if (child.Width.Units == Unit.Percent) { + ltChild |= LayoutingType.Width; + if (child.Width.Value < 100 && child.Left == 0) + ltChild |= LayoutingType.X; } - break; - case LayoutingType.Height: - if (child != null) { - child.RegisterForLayouting (LayoutingType.Y | LayoutingType.Height); + } else if (layoutType == LayoutingType.Height) { + if (Height == Measure.Fit) + return; + if (child.Height.Units == Unit.Percent) { + ltChild |= LayoutingType.Height; + if (child.Height.Value < 100 && child.Top == 0) + ltChild |= LayoutingType.Y; } - break; - } + } + if (ltChild == LayoutingType.None) + return; + child.RegisterForLayouting (ltChild); } public virtual void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) - { - switch (arg.LayoutType) { - case LayoutingType.X: - break; - case LayoutingType.Y: - break; - case LayoutingType.Width: - if (Width < 0) - this.RegisterForLayouting (LayoutingType.Width); - break; - case LayoutingType.Height: - if (Height < 0) - this.RegisterForLayouting (LayoutingType.Height); - break; + { + GraphicObject g = sender as GraphicObject; + + if (arg.LayoutType == LayoutingType.Width) { + if (Width != Measure.Fit) + return; + contentSize.Width = g.Slot.Width; + this.RegisterForLayouting (LayoutingType.Width); + }else if (arg.LayoutType == LayoutingType.Height){ + if (Height != Measure.Fit) + return; + contentSize.Height = g.Slot.Height; + this.RegisterForLayouting (LayoutingType.Height); } } protected override void onDraw (Context gr) diff --git a/src/GraphicObjects/Splitter.cs b/src/GraphicObjects/Splitter.cs index 6a1f2254..527b4084 100644 --- a/src/GraphicObjects/Splitter.cs +++ b/src/GraphicObjects/Splitter.cs @@ -83,14 +83,14 @@ namespace Crow if (gs.Orientation == Orientation.Horizontal) { if (ptrThis >= 0) - gs.Children [ptrThis - 1].Width = Math.Max(gs.Children [ptrThis - 1].Slot.Width + e.XDelta*2, 1); + gs.Children [ptrThis - 1].Width = Math.Max(gs.Children [ptrThis - 1].Slot.Width + e.XDelta, 1); if (ptrThis < gs.Children.Count - 1) - gs.Children [ptrThis + 1].Width = Math.Max(gs.Children [ptrThis + 1].Slot.Width - e.XDelta*2, 1); + gs.Children [ptrThis + 1].Width = Math.Max(gs.Children [ptrThis + 1].Slot.Width - e.XDelta, 1); } else { if (ptrThis >= 0) - gs.Children [ptrThis - 1].Height = Math.Max(gs.Children [ptrThis - 1].Slot.Height + e.YDelta*2, 1); + gs.Children [ptrThis - 1].Height = Math.Max(gs.Children [ptrThis - 1].Slot.Height + e.YDelta, 1); if (ptrThis < gs.Children.Count - 1) - gs.Children [ptrThis + 1].Height = Math.Max(gs.Children [ptrThis + 1].Slot.Height - e.YDelta*2, 1); + gs.Children [ptrThis + 1].Height = Math.Max(gs.Children [ptrThis + 1].Slot.Height - e.YDelta, 1); } } public override bool UpdateLayout (LayoutingType layoutType) @@ -100,12 +100,12 @@ namespace Crow if (gs.Orientation == Orientation.Horizontal) Width = thickness; else - Width = 0; + Width = Measure.Stretched; } else if (layoutType == LayoutingType.Height){ if (gs.Orientation == Orientation.Vertical) Height = thickness; else - Height = 0; + Height = Measure.Stretched; } return base.UpdateLayout (layoutType); } diff --git a/src/Input/KeyboardState.cs b/src/Input/KeyboardState.cs index 283b4a69..e3784bc3 100644 --- a/src/Input/KeyboardState.cs +++ b/src/Input/KeyboardState.cs @@ -236,7 +236,7 @@ namespace Crow internal void EnableBit(int offset) { - ValidateOffset(offset); + //ValidateOffset(offset); int int_offset = offset / 32; int bit_offset = offset % 32; diff --git a/src/Interface.cs b/src/Interface.cs index 063a34de..8e00a284 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -19,18 +19,13 @@ // 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.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Reflection; -using System.Diagnostics; -using System.Collections.Generic; -using System.Xml; -using System.Linq; -using System.Reflection.Emit; -using System.CodeDom; -using Microsoft.CSharp; -using System.CodeDom.Compiler; using System.Threading; +using System.Xml; +using System.Xml.Serialization; using Cairo; namespace Crow @@ -52,6 +47,7 @@ namespace Crow internal static bool XmlSerializerInit = false; /// <summary> keep ressource path for debug msg </summary> internal static string CurrentGOMLPath = ""; + //used in templatedControl internal static int XmlLoaderCount = 0; public static int TabSize = 4; @@ -325,6 +321,8 @@ namespace Crow public void Update(){ + CurrentInterface = this; + if (mouseRepeatCount > 0) { int mc = mouseRepeatCount; mouseRepeatCount -= mc; @@ -655,6 +653,7 @@ namespace Crow if (!FocusedWidget.MouseRepeat) return true; mouseRepeatThread = new Thread (mouseRepeatThreadFunc); + mouseRepeatThread.IsBackground = true; mouseRepeatThread.Start (); return true; } @@ -685,8 +684,7 @@ namespace Crow #endregion #region Keyboard - public bool ProcessKeyDown(int Key){ - Keyboard.SetKeyState ((Crow.Key)Key, true); + public bool ProcessKeyDown(int Key){ if (_focusedWidget == null) return false; KeyboardKeyEventArgs e = new KeyboardKeyEventArgs((Crow.Key)Key, false, Keyboard); @@ -694,7 +692,6 @@ namespace Crow 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); diff --git a/src/LayoutingQueueItem.cs b/src/LayoutingQueueItem.cs index 5fbde097..933fc57c 100644 --- a/src/LayoutingQueueItem.cs +++ b/src/LayoutingQueueItem.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; namespace Crow { + [Flags] public enum LayoutingType : byte { None = 0x00, diff --git a/src/Measure.cs b/src/Measure.cs index 4fbac421..64e5cc98 100644 --- a/src/Measure.cs +++ b/src/Measure.cs @@ -30,7 +30,7 @@ namespace Crow public static Measure Fit = new Measure(-1); //TODO:implement stretching as 100%, not 0% - public static Measure Stretched = new Measure(0, Unit.Percent); + public static Measure Stretched = new Measure(100, Unit.Percent); public Measure (int _value, Unit _units = Unit.Pixel) { @@ -72,8 +72,8 @@ namespace Crow public override string ToString () { return Value == -1 ? "Fit" : - Value == 0 ? "Stretched" : - Units == Unit.Percent ? Value.ToString () + "%" : Value.ToString (); + Units == Unit.Percent ? Value == 100 ? "Stretched" : + Value.ToString () + "%" : Value.ToString (); } public static Measure Parse(string s){ if (string.IsNullOrEmpty (s)) |