diff options
| author | jpbruyere <jp.bruyere@hotmail.com> | 2017-01-05 15:47:33 +0100 |
|---|---|---|
| committer | jpbruyere <jp.bruyere@hotmail.com> | 2017-01-05 15:47:33 +0100 |
| commit | 49346012274739fd39745f9e035ee8853149bc73 (patch) | |
| tree | b8757165c6b31a6d08b7caad2118ed76f463c287 /src/GraphicObjects/GraphicObject.cs | |
| parent | 9c0f77e860a1852ee7de381a82118e6d8c7fb819 (diff) | |
| parent | 40b16003066ad42604fd82dc0eec9cfa0a4abeca (diff) | |
Merge branch 'master' into CrowIDE
Diffstat (limited to 'src/GraphicObjects/GraphicObject.cs')
| -rw-r--r-- | src/GraphicObjects/GraphicObject.cs | 375 |
1 files changed, 171 insertions, 204 deletions
diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 277e3d48..25332832 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -12,16 +12,8 @@ using System.IO; namespace Crow { - public class GraphicObject : IXmlSerializable, ILayoutable, IValueChange, ICloneable, IBindable + public class GraphicObject : IXmlSerializable, ILayoutable, IValueChange, ICloneable { - #region IBindable implementation - List<Binding> bindings = new List<Binding> (); - public List<Binding> Bindings { - get { return bindings; } - } - - #endregion - internal static ulong currentUid = 0; internal ulong uid = 0; @@ -88,7 +80,7 @@ namespace Crow Size minimumSize = "0,0"; bool cacheEnabled = false; bool clipToClientRect = true; - object dataSource; + protected object dataSource; string style; #endregion @@ -115,6 +107,7 @@ namespace Crow public object Tag; /// <summary>drawing Cache, if null, a redraw is done, cached or not</summary> public byte[] bmp; + public bool IsDirty = true; /// <summary> /// This size is computed on each child' layout changes. /// In stacking widget, it is used to compute the remaining space for the stretched @@ -133,11 +126,29 @@ namespace Crow /// </summary> [XmlIgnore]public virtual ILayoutable Parent { get { return parent; } - set { parent = value; } + set { + if (parent == value) + return; + DataSourceChangeEventArgs e = new DataSourceChangeEventArgs (parent, value); + parent = value; + + onParentChanged (this, e); + } } [XmlIgnore]public ILayoutable LogicalParent { get { return logicalParent == null ? Parent : logicalParent; } - set { logicalParent = value; } + set { + if (logicalParent == value) + return; + if (logicalParent != null) + (logicalParent as GraphicObject).DataSourceChanged -= onLogicalParentDataSourceChanged; + DataSourceChangeEventArgs dsce = new DataSourceChangeEventArgs (LogicalParent, null); + logicalParent = value; + dsce.NewDataSource = LogicalParent; + if (logicalParent != null) + (logicalParent as GraphicObject).DataSourceChanged += onLogicalParentDataSourceChanged; + onLogicalParentChanged (this, dsce); + } } [XmlIgnore]public virtual Rectangle ClientRectangle { get { @@ -178,6 +189,9 @@ namespace Crow public event EventHandler Enabled; public event EventHandler Disabled; public event EventHandler<LayoutingEventArgs> LayoutChanged; + public event EventHandler<DataSourceChangeEventArgs> DataSourceChanged; + public event EventHandler<DataSourceChangeEventArgs> ParentChanged; + public event EventHandler<DataSourceChangeEventArgs> LogicalParentChanged; #endregion #region public properties @@ -376,6 +390,10 @@ namespace Crow return; hasFocus = value; + if (hasFocus) + onFocused (this, null); + else + onUnfocused (this, null); NotifyValueChanged ("HasFocus", hasFocus); } } @@ -399,17 +417,23 @@ namespace Crow NotifyValueChanged ("MouseRepeat", mouseRepeat); } } + bool clearBackground = false; [XmlAttributeAttribute()][DefaultValue("Transparent")] public virtual Fill Background { get { return background; } set { if (background == value) return; + clearBackground = false; if (value == null) return; background = value; NotifyValueChanged ("Background", background); RegisterForRedraw (); + if (background is SolidColor) { + if ((Background as SolidColor).Equals (Color.Clear)) + clearBackground = true; + } } } [XmlAttributeAttribute()][DefaultValue("White")] @@ -528,32 +552,45 @@ namespace Crow RegisterForLayouting (LayoutingType.Sizing); } } + /// <summary> + /// Seek first logical tree upward if logicalParent is set, or seek graphic tree for + /// a not null dataSource that will be active for all descendants having dataSource=null + /// </summary> [XmlAttributeAttribute][DefaultValue(null)] public virtual object DataSource { set { - if (dataSource == value) + if (DataSource == value) return; - #if DEBUG_BINDING - Debug.WriteLine("******************************"); - Debug.WriteLine("New DataSource for => " + this.ToString()); - Debug.WriteLine("\t- " + DataSource); - Debug.WriteLine("\t+ " + value); - #endif - - this.ClearBinding (); + DataSourceChangeEventArgs dse = new DataSourceChangeEventArgs (DataSource, null); dataSource = value; + dse.NewDataSource = DataSource; - this.ResolveBindings(); + OnDataSourceChanged (this, dse); - NotifyValueChanged ("DataSource", dataSource); + NotifyValueChanged ("DataSource", DataSource); } get { - return dataSource == null ? LogicalParent == null ? null : - LogicalParent is GraphicObject ? - (LogicalParent as GraphicObject).DataSource : null : dataSource; + return dataSource == null ? + LogicalParent == null ? null : + LogicalParent is GraphicObject ? (LogicalParent as GraphicObject).DataSource : null : + dataSource; } } + protected virtual void onLogicalParentDataSourceChanged(object sender, DataSourceChangeEventArgs e){ + if (localDataSourceIsNull) + OnDataSourceChanged (this, e); + } + internal bool localDataSourceIsNull { get { return dataSource == null; } } + internal bool localLogicalParentIsNull { get { return logicalParent == null; } } + + public virtual void OnDataSourceChanged(object sender, DataSourceChangeEventArgs e){ + DataSourceChanged.Raise (this, e); + #if DEBUG_BINDING + Debug.WriteLine("New DataSource for => {0} \n\t{1}=>{2}", this.ToString(),e.OldDataSource,e.NewDataSource); + #endif + } + [XmlAttributeAttribute] public virtual string Style { get { return style; } @@ -635,10 +672,10 @@ namespace Crow dm = new DynamicMethod("dyn_loadDefValues", MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot, CallingConventions.Standard, - typeof(void),new Type[] {typeof(object)},thisType,true); + typeof(void),new Type[] {CompilerServices.TObject},thisType,true); il = dm.GetILGenerator(256); - il.DeclareLocal(typeof(GraphicObject)); + il.DeclareLocal(CompilerServices.TObject); il.Emit(OpCodes.Nop); //set local GraphicObject to root object passed as 1st argument il.Emit (OpCodes.Ldarg_0); @@ -648,7 +685,26 @@ namespace Crow string expression; if (!getDefaultEvent(ei, styling, out expression)) continue; - CompilerServices.emitBindingCreation (il, ei.Name, expression); + //TODO:dynEventHandler could be cached somewhere, maybe a style instanciato class holding the styling delegate and bound to it. + foreach (string exp in CompilerServices.splitOnSemiColumnOutsideAccolades(expression)) { + string trimed = exp.Trim(); + if (trimed.StartsWith ("{", StringComparison.OrdinalIgnoreCase)){ + il.Emit (OpCodes.Ldloc_0);//load this as 1st arg of event Add + + //push eventInfo as 1st arg of compile + il.Emit (OpCodes.Ldloc_0); + il.Emit (OpCodes.Call, CompilerServices.miGetType); + il.Emit (OpCodes.Ldstr, ei.Name);//push event name + il.Emit (OpCodes.Call, CompilerServices.miGetEvent); + //push expression as 2nd arg of compile + il.Emit (OpCodes.Ldstr, trimed.Substring (1, trimed.Length - 2)); + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Callvirt, CompilerServices.miCompileDynEventHandler); + il.Emit (OpCodes.Castclass, ei.EventHandlerType); + il.Emit (OpCodes.Callvirt, ei.AddMethod); + }else + Debug.WriteLine("error in styling, event not handled : " + trimed); + } } foreach (PropertyInfo pi in thisType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { @@ -732,7 +788,7 @@ namespace Crow #region Queuing public virtual void RegisterClip(Rectangle clip){ - if (CacheEnabled && bmp != null) + if (CacheEnabled && !IsDirty) Clipping.AddRectangle (clip + ClientRectangle.Position); if (Parent != null) Parent.RegisterClip (clip + Slot.Position + ClientRectangle.Position); @@ -741,7 +797,7 @@ namespace Crow [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RegisterForGraphicUpdate () { - bmp = null; + IsDirty = true; if (Width.IsFit || Height.IsFit) RegisterForLayouting (LayoutingType.Sizing); else if (RegisteredLayoutings == LayoutingType.None) @@ -751,7 +807,7 @@ namespace Crow [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RegisterForRedraw () { - bmp = null; + IsDirty = true; if (RegisteredLayoutings == LayoutingType.None) CurrentInterface.EnqueueForRepaint (this); } @@ -864,7 +920,7 @@ namespace Crow if (LastSlots.X == Slot.X) break; - bmp = null; + IsDirty = true; OnLayoutChanges (layoutType); @@ -894,7 +950,7 @@ namespace Crow if (LastSlots.Y == Slot.Y) break; - bmp = null; + IsDirty = true; OnLayoutChanges (layoutType); @@ -930,7 +986,7 @@ namespace Crow if (LastSlots.Width == Slot.Width) break; - bmp = null; + IsDirty = true; OnLayoutChanges (layoutType); @@ -966,7 +1022,7 @@ namespace Crow if (LastSlots.Height == Slot.Height) break; - bmp = null; + IsDirty = true; OnLayoutChanges (layoutType); @@ -975,7 +1031,7 @@ namespace Crow } //if no layouting remains in queue for item, registre for redraw - if (this.registeredLayoutings == LayoutingType.None && bmp == null) + if (this.registeredLayoutings == LayoutingType.None && IsDirty) CurrentInterface.EnqueueForRepaint (this); return true; @@ -1002,7 +1058,7 @@ namespace Crow int bmpSize = Math.Abs (stride) * Slot.Height; bmp = new byte[bmpSize]; - + IsDirty = false; using (ImageSurface draw = new ImageSurface(bmp, Format.Argb32, Slot.Width, Slot.Height, stride)) { using (Context gr = new Context (draw)) { @@ -1014,16 +1070,13 @@ namespace Crow } protected virtual void UpdateCache(Context ctx){ Rectangle rb = Slot + Parent.ClientRectangle.Position; - using (ImageSurface cache = new ImageSurface (bmp, Format.Argb32, Slot.Width, Slot.Height, 4 * Slot.Width)) { - //TODO:improve equality test for basic color and Fill - if (this.Background is SolidColor) { - if ((this.Background as SolidColor).Equals (Color.Clear)) { + using (ImageSurface cache = new ImageSurface (bmp, Format.Argb32, Slot.Width, Slot.Height, 4 * Slot.Width)) { + if (clearBackground) { ctx.Save (); ctx.Operator = Operator.Clear; ctx.Rectangle (rb); ctx.Fill (); ctx.Restore (); - } } ctx.SetSourceSurface (cache, rb.X, rb.Y); ctx.Paint (); @@ -1035,9 +1088,6 @@ namespace Crow /// of the widget </summary> public virtual void Paint (ref Context ctx) { - if (!Visible) - return; - //TODO:this test should not be necessary if (Slot.Height < 0 || Slot.Width < 0) return; @@ -1050,7 +1100,7 @@ namespace Crow } if (cacheEnabled) { - if (bmp == null) + if (IsDirty) RecreateCache (); UpdateCache (ctx); @@ -1113,7 +1163,7 @@ namespace Crow onMouseEnter (this, e); } - this.onMouseMove (this, e); + this.onMouseMove (this, e);//without this, window border doesn't work, should be removed } public virtual void onMouseMove(object sender, MouseMoveEventArgs e) { @@ -1125,6 +1175,12 @@ namespace Crow MouseMove.Raise (sender, e); } public virtual void onMouseDown(object sender, MouseButtonEventArgs e){ + if (CurrentInterface.eligibleForDoubleClick == this && CurrentInterface.clickTimer.ElapsedMilliseconds < Interface.DoubleClick) + onMouseDoubleClick (this, e); + else + currentInterface.clickTimer.Restart(); + CurrentInterface.eligibleForDoubleClick = null; + if (CurrentInterface.activeWidget == null) CurrentInterface.activeWidget = this; if (this.Focusable && !Interface.FocusOnHover) { @@ -1149,19 +1205,13 @@ namespace Crow MouseUp.Raise (this, e); - if (MouseIsIn (e.Position) && IsActive) + if (MouseIsIn (e.Position) && IsActive) { + if (CurrentInterface.clickTimer.ElapsedMilliseconds < Interface.DoubleClick) + CurrentInterface.eligibleForDoubleClick = this; onMouseClick (this, e); + } } public virtual void onMouseClick(object sender, MouseButtonEventArgs e){ - - if (Interface.clickTimer.ElapsedMilliseconds > 0 && - Interface.clickTimer.ElapsedMilliseconds < Interface.DoubleClick) { - Interface.clickTimer.Reset (); - onMouseDoubleClick (this, e); - return; - } else - Interface.clickTimer.Restart (); - GraphicObject p = Parent as GraphicObject; if (p != null) p.onMouseClick(sender,e); @@ -1196,20 +1246,17 @@ namespace Crow } #endregion - public virtual void onFocused(object sender, EventArgs e){ + protected virtual void onFocused(object sender, EventArgs e){ #if DEBUG_FOCUS Debug.WriteLine("Focused => " + this.ToString()); #endif Focused.Raise (this, e); - this.HasFocus = true; } - public virtual void onUnfocused(object sender, EventArgs e){ + protected virtual void onUnfocused(object sender, EventArgs e){ #if DEBUG_FOCUS Debug.WriteLine("UnFocused => " + this.ToString()); #endif - Unfocused.Raise (this, e); - this.HasFocus = false; } public virtual void onEnable(object sender, EventArgs e){ Enabled.Raise (this, e); @@ -1217,147 +1264,73 @@ namespace Crow public virtual void onDisable(object sender, EventArgs e){ Disabled.Raise (this, e); } - - #region Binding - public void BindMember(string _member, string _expression){ - Bindings.Add(new Binding (this, _member, _expression)); + protected virtual void onParentChanged(object sender, DataSourceChangeEventArgs e) { + ParentChanged.Raise (this, e); + if (logicalParent == null) + LogicalParentChanged.Raise (this, e); } - public virtual void ResolveBindings() - { - if (Bindings.Count == 0) - return; - #if DEBUG_BINDING - Debug.WriteLine ("Resolve Bindings => " + this.ToString ()); - #endif - - CompilerServices.ResolveBindings (Bindings); + protected virtual void onLogicalParentChanged(object sender, DataSourceChangeEventArgs e) { + LogicalParentChanged.Raise (this, e); } - - /// <summary> - /// Remove dynamic delegates by ids from dataSource - /// and delete ref of this in Shared interface refs - /// </summary> - public virtual void ClearBinding(){ - //dont clear binding if dataSource is not null, - foreach (Binding b in Bindings) { - try { - if (!b.Resolved) - continue; - //cancel compiled events - if (b.Target == null){ - continue; - #if DEBUG_BINDING - Debug.WriteLine("Clear binding canceled for => " + b.ToString()); - #endif - } - if (b.Target.Instance != DataSource){ - #if DEBUG_BINDING - Debug.WriteLine("Clear binding canceled for => " + b.ToString()); - #endif - continue; - } - #if DEBUG_BINDING - Debug.WriteLine("ClearBinding => " + b.ToString()); - #endif - if (string.IsNullOrEmpty (b.DynMethodId)) { - b.Resolved = false; - if (b.Source.Member.MemberType == MemberTypes.Event) - removeEventHandler (b); - //TODO:check if full reset is necessary - continue; - } - MemberReference mr = null; - if (b.Target == null) - mr = b.Source; - else - mr = b.Target; - Type dataSourceType = mr.Instance.GetType(); - EventInfo evtInfo = dataSourceType.GetEvent ("ValueChanged"); - FieldInfo evtFi = CompilerServices.GetEventHandlerField (dataSourceType, "ValueChanged"); - MulticastDelegate multicastDelegate = evtFi.GetValue (mr.Instance) as MulticastDelegate; - if (multicastDelegate != null) { - foreach (Delegate d in multicastDelegate.GetInvocationList()) { - if (d.Method.Name == b.DynMethodId) - evtInfo.RemoveEventHandler (mr.Instance, d); - } - } - b.Reset (); - } catch (Exception ex) { - Debug.WriteLine("\t Error: " + ex.ToString()); - } - } - } - void removeEventHandler(Binding b){ - FieldInfo fiEvt = CompilerServices.GetEventHandlerField (b.Source.Instance.GetType(), b.Source.Member.Name); - MulticastDelegate multiDel = fiEvt.GetValue (b.Source.Instance) as MulticastDelegate; - if (multiDel != null) { - foreach (Delegate d in multiDel.GetInvocationList()) { - if (d.Method.Name == b.Target.Member.Name) - b.Source.Event.RemoveEventHandler (b.Source.Instance, d); - } - } - } - #endregion - #region IXmlSerializable public virtual System.Xml.Schema.XmlSchema GetSchema () { return null; } - void affectMember(string name, string value){ - Type thisType = this.GetType (); - - if (string.IsNullOrEmpty (value)) - return; - - MemberInfo mi = thisType.GetMember (name).FirstOrDefault(); - if (mi == null) { - Debug.WriteLine ("XML: Unknown attribute in " + thisType.ToString() + " : " + name); - return; - } - if (mi.MemberType == MemberTypes.Event) { - this.Bindings.Add (new Binding (new MemberReference(this, mi), value)); - return; - } - if (mi.MemberType == MemberTypes.Property) { - PropertyInfo pi = mi as PropertyInfo; - - if (pi.GetSetMethod () == null) { - Debug.WriteLine ("XML: Read only property in " + thisType.ToString() + " : " + name); - return; - } - - XmlAttributeAttribute xaa = (XmlAttributeAttribute)pi.GetCustomAttribute (typeof(XmlAttributeAttribute)); - if (xaa != null) { - if (!string.IsNullOrEmpty (xaa.AttributeName)) - name = xaa.AttributeName; - } - if (value.StartsWith("{",StringComparison.Ordinal)) { - //binding - if (!value.EndsWith("}", StringComparison.Ordinal)) - throw new Exception (string.Format("XML:Malformed binding: {0}", value)); - - this.Bindings.Add (new Binding (new MemberReference(this, pi), value.Substring (1, value.Length - 2))); - return; - } - if (pi.GetCustomAttribute (typeof(XmlIgnoreAttribute)) != null) - return; - if (xaa == null)//not define as xmlAttribute - return; - - if (pi.PropertyType == typeof(string)) { - pi.SetValue (this, value, null); - return; - } - - if (pi.PropertyType.IsEnum) { - pi.SetValue (this, Enum.Parse (pi.PropertyType, value), null); - } else { - MethodInfo me = pi.PropertyType.GetMethod ("Parse", new Type[] { typeof(string) }); - pi.SetValue (this, me.Invoke (null, new string[] { value }), null); - } - } - } +// void affectMember(string name, string value){ +// Type thisType = this.GetType (); +// +// if (string.IsNullOrEmpty (value)) +// return; +// +// MemberInfo mi = thisType.GetMember (name).FirstOrDefault(); +// if (mi == null) { +// Debug.WriteLine ("XML: Unknown attribute in " + thisType.ToString() + " : " + name); +// return; +// } +// if (mi.MemberType == MemberTypes.Event) { +// this.Bindings.Add (new Binding (new MemberReference(this, mi), value)); +// return; +// } +// if (mi.MemberType == MemberTypes.Property) { +// PropertyInfo pi = mi as PropertyInfo; +// +// if (pi.GetSetMethod () == null) { +// Debug.WriteLine ("XML: Read only property in " + thisType.ToString() + " : " + name); +// return; +// } +// +// XmlAttributeAttribute xaa = (XmlAttributeAttribute)pi.GetCustomAttribute (typeof(XmlAttributeAttribute)); +// if (xaa != null) { +// if (!string.IsNullOrEmpty (xaa.AttributeName)) +// name = xaa.AttributeName; +// } +// if (value.StartsWith("{",StringComparison.Ordinal)) { +// //binding +// if (!value.EndsWith("}", StringComparison.Ordinal)) +// throw new Exception (string.Format("XML:Malformed binding: {0}", value)); +// +// this.Bindings.Add (new Binding (new MemberReference(this, pi), value.Substring (1, value.Length - 2))); +// return; +// } +// if (pi.GetCustomAttribute (typeof(XmlIgnoreAttribute)) != null) +// return; +// if (xaa == null)//not define as xmlAttribute +// return; +// +// if (pi.PropertyType == typeof(string)) { +// pi.SetValue (this, value, null); +// return; +// } +// +// if (pi.PropertyType.IsEnum) { +// pi.SetValue (this, Enum.Parse (pi.PropertyType, value), null); +// } else { +// MethodInfo me = pi.PropertyType.GetMethod ("Parse", new Type[] { typeof(string) }); +// pi.SetValue (this, me.Invoke (null, new string[] { value }), null); +// } +// } +// } public virtual void ReadXml (System.Xml.XmlReader reader) { if (reader.HasAttributes) { @@ -1370,7 +1343,7 @@ namespace Crow if (reader.Name == "Style") continue; - affectMember (reader.Name, reader.Value); + //affectMember (reader.Name, reader.Value); } reader.MoveToElement (); }else @@ -1488,12 +1461,6 @@ namespace Crow /// <summary> /// full GraphicTree clone with binding definition /// </summary> - public virtual GraphicObject DeepClone(){ - GraphicObject tmp = Clone () as GraphicObject; - foreach (Binding b in this.bindings) - tmp.Bindings.Add (new Binding (new MemberReference (tmp, b.Source.Member), b.Expression)); - return tmp; - } public override string ToString () { |