diff options
| author | j-p <jp.bruyere@live.be> | 2016-08-05 18:48:09 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-08-05 18:48:09 +0200 |
| commit | beba8120aa8f1529d79ccf0f52f02069b02aaf4d (patch) | |
| tree | 8de343d8341be621c4b5daa12899155e0bc2f26a /src | |
| parent | da0cd66b6af42a3df1f35014617f1e0882ae9e63 (diff) | |
| parent | b9e90a3df66f4bd8228c1246af830d7801ea57ba (diff) | |
Merge pull request #15 from jpbruyere/TemplateImprovments
Template improvments
Diffstat (limited to 'src')
| -rw-r--r-- | src/CompilerServices/Bindings.cs | 18 | ||||
| -rw-r--r-- | src/GraphicObjects/CheckBox.cs | 12 | ||||
| -rw-r--r-- | src/GraphicObjects/Expandable.cs | 3 | ||||
| -rw-r--r-- | src/GraphicObjects/GraphicObject.cs | 70 | ||||
| -rw-r--r-- | src/GraphicObjects/Group.cs | 8 | ||||
| -rw-r--r-- | src/GraphicObjects/ILayoutable.cs | 2 | ||||
| -rw-r--r-- | src/GraphicObjects/Label.cs | 52 | ||||
| -rw-r--r-- | src/GraphicObjects/ListBox.cs | 292 | ||||
| -rw-r--r-- | src/GraphicObjects/PrivateContainer.cs | 56 | ||||
| -rw-r--r-- | src/GraphicObjects/RadioButton.cs | 11 | ||||
| -rw-r--r-- | src/GraphicObjects/TemplatedControl.cs | 70 | ||||
| -rw-r--r-- | src/GraphicObjects/TreeView.cs | 62 | ||||
| -rw-r--r-- | src/IMLStream.cs | 100 | ||||
| -rw-r--r-- | src/Interface.cs | 49 | ||||
| -rw-r--r-- | src/LayoutingQueueItem.cs | 75 |
15 files changed, 543 insertions, 337 deletions
diff --git a/src/CompilerServices/Bindings.cs b/src/CompilerServices/Bindings.cs index b7967a91..40ade60d 100644 --- a/src/CompilerServices/Bindings.cs +++ b/src/CompilerServices/Bindings.cs @@ -125,9 +125,17 @@ namespace Crow } else { int ptr = 0; ILayoutable tmp = Source.Instance as ILayoutable; - if (string.IsNullOrEmpty (bindingExp [0])) { - //if exp start with '/' => Graphic tree parsing start at top container - tmp = Interface.CurrentInterface as ILayoutable; + //if exp start with '/' => Graphic tree parsing start at source + if (string.IsNullOrEmpty (bindingExp [0])) + ptr++; + else if (bindingExp[0] == "."){ //search template root + do { + tmp = tmp.Parent; + if (tmp == null) + return false; + if (tmp is Interface) + throw new Exception ("Not in Templated Control"); + } while (!(tmp is TemplatedControl)); ptr++; } while (ptr < bindingExp.Length - 1) { @@ -168,7 +176,9 @@ namespace Crow Target = new MemberReference (tmp); } if (Target == null) { + #if DEBUG_BINDING Debug.WriteLine ("Binding Source is null: " + Expression); + #endif return false; } @@ -182,7 +192,9 @@ namespace Crow return true; } + #if DEBUG_BINDING Debug.WriteLine ("Binding member not found: " + member); + #endif Target = null; return false; } diff --git a/src/GraphicObjects/CheckBox.cs b/src/GraphicObjects/CheckBox.cs index f8193e24..61b581ed 100644 --- a/src/GraphicObjects/CheckBox.cs +++ b/src/GraphicObjects/CheckBox.cs @@ -49,17 +49,7 @@ namespace Crow caption = value; NotifyValueChanged ("Caption", caption); } - } - [XmlAttributeAttribute()][DefaultValue("#Crow.Images.Icons.checkbox.svg")] - public string Image { - get { return image; } - set { - if (image == value) - return; - image = value; - NotifyValueChanged ("Image", image); - } - } + } [XmlAttributeAttribute()][DefaultValue(false)] public bool IsChecked { diff --git a/src/GraphicObjects/Expandable.cs b/src/GraphicObjects/Expandable.cs index d21936e8..819987eb 100644 --- a/src/GraphicObjects/Expandable.cs +++ b/src/GraphicObjects/Expandable.cs @@ -49,7 +49,8 @@ namespace Crow #region GraphicObject overrides public override void onMouseClick (object sender, MouseButtonEventArgs e) { - IsExpanded = !IsExpanded; + if (this.HasFocus) + IsExpanded = !IsExpanded; base.onMouseClick (sender, e); } #endregion diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 865e664c..39556976 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -25,9 +25,6 @@ namespace Crow internal static ulong currentUid = 0; internal ulong uid = 0; - - internal int layoutingTries = 0; - Rectangles clipping = new Rectangles(); public Rectangles Clipping { get { return clipping; }} @@ -62,7 +59,7 @@ namespace Crow #endregion #region private fields - LayoutingType registeredLayoutings = LayoutingType.None; + LayoutingType registeredLayoutings = LayoutingType.All; ILayoutable logicalParent; ILayoutable _parent; string _name = "unamed"; @@ -104,8 +101,19 @@ namespace Crow /// IDEA is to add a ScreenCoordinates function that use only lastPaintedSlots /// </summary> public Rectangle LastPaintedSlot; + /// <summary>Prevent requeuing multiple times the same widget</summary> + public bool IsQueueForRedraw = false; + /// <summary>Random value placeholder</summary> public object Tag; + /// <summary>drawing Cache, if null, a redraw is done, cached or not</summary> public byte[] bmp; + /// <summary> + /// This size is computed on each child' layout changes. + /// In stacking widget, it is used to compute the remaining space for the stretched + /// widget inside the stack, which is never added to the contentSize, instead, its size + /// is deducted from (parent.ClientRectangle - contentSize) + /// </summary> + internal Size contentSize; #endregion #region ILayoutable @@ -119,12 +127,10 @@ namespace Crow get { return _parent; } set { _parent = value; } } - [XmlIgnore]public ILayoutable LogicalParent { get { return logicalParent == null ? Parent : logicalParent; } set { logicalParent = value; } } - [XmlIgnore]public virtual Rectangle ClientRectangle { get { Rectangle cb = Slot.Size; @@ -132,7 +138,6 @@ namespace Crow return cb; } } - public virtual Rectangle ContextCoordinates(Rectangle r){ GraphicObject go = Parent as GraphicObject; if (go == null) @@ -734,7 +739,6 @@ namespace Crow if (Parent != null) Parent.RegisterClip (clip + Slot.Position + ClientRectangle.Position); } - public bool IsQueueForRedraw = false; /// <summary> Full update, taking care of sizing policy </summary> [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RegisterForGraphicUpdate () @@ -742,21 +746,23 @@ namespace Crow bmp = null; if (Width == Measure.Fit || Height == Measure.Fit) RegisterForLayouting (LayoutingType.Sizing); - Interface.CurrentInterface.EnqueueForRepaint (this); + else if (RegisteredLayoutings == LayoutingType.None) + Interface.CurrentInterface.EnqueueForRepaint (this); } /// <summary> query an update of the content, a redraw </summary> [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RegisterForRedraw () { bmp = null; - Interface.CurrentInterface.EnqueueForRepaint (this); + if (RegisteredLayoutings == LayoutingType.None) + Interface.CurrentInterface.EnqueueForRepaint (this); } #region Layouting - [XmlIgnore]public int LayoutingTries { - get { return layoutingTries; } - set { layoutingTries = value; } - } - internal Size contentSize; + + #if DEBUG_LAYOUTING + public List<LayoutingQueueItem> CurrentDrawLQIs = null; + public List<List<LayoutingQueueItem>> LQIs = new List<List<LayoutingQueueItem>>(); + #endif /// <summary> return size of content + margins </summary> protected virtual int measureRawSize (LayoutingType lt) { return lt == LayoutingType.Width ? @@ -789,9 +795,6 @@ namespace Crow if (layoutType == LayoutingType.None) return; - #if DEBUG_LAYOUTING - Debug.WriteLine ("REGLayout => {1}->{0}", layoutType, this.ToString()); - #endif //enqueue LQI LayoutingTypes separately if (layoutType.HasFlag (LayoutingType.Width)) Interface.CurrentInterface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Width, this)); @@ -810,7 +813,8 @@ namespace Crow public virtual void OnLayoutChanges(LayoutingType layoutType) { #if DEBUG_LAYOUTING - Debug.WriteLine ("\t " + LastSlots.ToString() + "\n\t => " + Slot.ToString ()); + LayoutingQueueItem.currentLQI.Slot = LastSlots; + LayoutingQueueItem.currentLQI.Slot = Slot; #endif switch (layoutType) { @@ -1034,6 +1038,12 @@ namespace Crow return; LastPaintedSlot = Slot; + #if DEBUG_LAYOUTING + if (CurrentDrawLQIs != null){ + LQIs.Add (CurrentDrawLQIs); + CurrentDrawLQIs = null; + } + #endif if (cacheEnabled) { if (Slot.Width > Interface.MaxCacheSize || Slot.Height > Interface.MaxCacheSize) @@ -1126,10 +1136,13 @@ namespace Crow MouseUp.Raise (this, e); - if (MouseIsIn (e.Position)&&HasFocus) - onMouseClick(sender,e); + if (MouseIsIn (e.Position) && IsActive) + onMouseClick (this, e); } public virtual void onMouseClick(object sender, MouseButtonEventArgs e){ + GraphicObject p = Parent as GraphicObject; + if (p != null) + p.onMouseClick(sender,e); MouseClick.Raise (this, e); } public virtual void onMouseWheel(object sender, MouseWheelEventArgs e){ @@ -1443,17 +1456,20 @@ namespace Crow continue; if (pi.Name == "DataSource") continue; -// object[] att = pi.GetCustomAttributes (false); -// foreach (object o in att) { -// XmlIgnoreAttribute xia = o as XmlIgnoreAttribute; -// if (xia != null) -// continue; -// } pi.SetValue(result, pi.GetValue(this)); } return result; } #endregion + /// <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; + } } } diff --git a/src/GraphicObjects/Group.cs b/src/GraphicObjects/Group.cs index 48f835ac..4d851b1a 100644 --- a/src/GraphicObjects/Group.cs +++ b/src/GraphicObjects/Group.cs @@ -46,6 +46,7 @@ namespace Crow Children.Add(g); g.Parent = this as GraphicObject; g.ResolveBindings (); + g.RegisteredLayoutings = LayoutingType.None; g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren); g.LayoutChanged += OnChildLayoutChanges; return (T)child; @@ -362,5 +363,12 @@ namespace Crow c.ClearBinding (); base.ClearBinding (); } + public override GraphicObject DeepClone () + { + Group tmp = base.DeepClone () as Group; + foreach (GraphicObject c in Children) + tmp.AddChild (c.DeepClone ()); + return tmp; + } } } diff --git a/src/GraphicObjects/ILayoutable.cs b/src/GraphicObjects/ILayoutable.cs index b48e815a..33153935 100644 --- a/src/GraphicObjects/ILayoutable.cs +++ b/src/GraphicObjects/ILayoutable.cs @@ -5,8 +5,6 @@ namespace Crow { public interface ILayoutable { - /// <summary> Unsuccessfull UpdateLayout and requeueing count </summary> - int LayoutingTries { get; set; } /// <summary> Parent in the graphic tree </summary> ILayoutable Parent { get; set; } /// <summary> The logical parent (used mainly for bindings) as opposed diff --git a/src/GraphicObjects/Label.cs b/src/GraphicObjects/Label.cs index 2f5798ee..d09542b5 100644 --- a/src/GraphicObjects/Label.cs +++ b/src/GraphicObjects/Label.cs @@ -48,12 +48,13 @@ namespace Crow #region private and protected fields string _text = "label"; - Alignment _textAlignment = Alignment.Left; - bool horizontalStretch = false; - bool verticalStretch = false; - bool _multiline = false; - Color selColor; - Color selFontColor; + Alignment _textAlignment; + bool horizontalStretch; + bool verticalStretch; + bool _selectable; + bool _multiline; + Color selBackground; + Color selForeground; Point mouseLocalPos = -1;//mouse coord in widget space, filled only when clicked int _currentCol; //0 based cursor position in string int _currentLine; @@ -73,23 +74,23 @@ namespace Crow [XmlAttributeAttribute][DefaultValue("SteelBlue")] public virtual Color SelectionBackground { - get { return selColor; } + get { return selBackground; } set { - if (value == selColor) + if (value == selBackground) return; - selColor = value; - NotifyValueChanged ("SelectionBackground", selColor); + selBackground = value; + NotifyValueChanged ("SelectionBackground", selBackground); RegisterForRedraw (); } } [XmlAttributeAttribute][DefaultValue("White")] public virtual Color SelectionForeground { - get { return selFontColor; } + get { return selForeground; } set { - if (value == selFontColor) + if (value == selForeground) return; - selFontColor = value; - NotifyValueChanged ("SelectionForeground", selFontColor); + selForeground = value; + NotifyValueChanged ("SelectionForeground", selForeground); RegisterForRedraw (); } } @@ -151,6 +152,21 @@ namespace Crow } } [XmlAttributeAttribute][DefaultValue(false)] + public bool Selectable + { + get { return _selectable; } + set + { + if (value == _selectable) + return; + _selectable = value; + NotifyValueChanged ("Selectable", _selectable); + SelBegin = -1; + SelRelease = -1; + RegisterForRedraw (); + } + } + [XmlAttributeAttribute][DefaultValue(false)] public bool Multiline { get { return _multiline; } @@ -548,7 +564,7 @@ namespace Crow // lineRect.X += (rText.Width - lineLength); if (SelRelease >= 0 && i >= selectionStart.Y && i <= selectionEnd.Y) { - gr.SetSourceColor(selColor); + gr.SetSourceColor(selBackground); Rectangle selRect = lineRect ; @@ -594,6 +610,8 @@ namespace Crow { base.onFocused (sender, e); + if (!_selectable) + return; SelBegin = new Point(0,0); SelRelease = new Point (lines.LastOrDefault ().Length, lines.Count-1); RegisterForRedraw (); @@ -610,7 +628,7 @@ namespace Crow { base.onMouseMove (sender, e); - if (!(SelectionInProgress && HasFocus)) + if (!(SelectionInProgress && HasFocus && _selectable)) return; updatemouseLocalPos (e.Position); @@ -619,7 +637,7 @@ namespace Crow } public override void onMouseDown (object sender, MouseButtonEventArgs e) { - if (this.HasFocus){ + if (this.HasFocus && _selectable){ updatemouseLocalPos (e.Position); SelBegin = -1; SelRelease = -1; diff --git a/src/GraphicObjects/ListBox.cs b/src/GraphicObjects/ListBox.cs index 79efac33..6cef4fd9 100644 --- a/src/GraphicObjects/ListBox.cs +++ b/src/GraphicObjects/ListBox.cs @@ -22,7 +22,6 @@ using System; using System.Collections; using System.Xml.Serialization; using System.ComponentModel; -//TODO: implement ItemTemplate node in xml using System.IO; using System.Diagnostics; using System.Xml; @@ -32,71 +31,25 @@ using System.Threading; namespace Crow { [DefaultTemplate("#Crow.Templates.ListBox.goml")] - //[DefaultTemplate("#Crow.Templates.ItemTemplate.goml")] - public class ListBox : TemplatedControl//, IXmlSerializable + public class ListBox : TemplatedControl { #region CTOR public ListBox () : base() {} #endregion + #region events + public event EventHandler<SelectionChangeEventArgs> SelectedItemChanged; + #endregion + Group _list; GenericStack _gsList; IList data; int _selectedIndex; - string _itemTemplate; - - public event EventHandler<SelectionChangeEventArgs> SelectedItemChanged; - - #region implemented abstract members of TemplatedControl - protected override void loadTemplate (GraphicObject template = null) - { - base.loadTemplate (template); - _list = this.child.FindByName ("List") as Group; - if (_list == null) - throw new Exception ("ListBox Template MUST contain a Goup named 'List'."); - _gsList = _list as GenericStack; - } - - - #endregion - - [XmlAttributeAttribute][DefaultValue("#Crow.Templates.ItemTemplate.goml")] - public string ItemTemplate { - get { return _itemTemplate; } - set { - if (value == _itemTemplate) - return; - - _itemTemplate = value; - - if (templateStream != null) { - templateStream.Dispose (); - templateStream = null; - } - - //TODO:reload list with new template? - NotifyValueChanged("ItemTemplate", _itemTemplate); - } - } - [XmlAttributeAttribute][DefaultValue(-1)] - public int SelectedIndex{ - get { return _selectedIndex; } - set { - if (value == _selectedIndex) - return; - - _selectedIndex = value; + int itemPerPage = 50; + Thread loadingThread = null; + volatile bool cancelLoading = false; - NotifyValueChanged ("SelectedIndex", _selectedIndex); - NotifyValueChanged ("SelectedItem", SelectedItem); - SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem)); - } - } - public object SelectedItem{ - get { return data == null ? null : _selectedIndex < 0 ? null : data[_selectedIndex]; } - } - [XmlAttributeAttribute]//[DefaultValue(null)] - public IList Data { + [XmlAttributeAttribute]public IList Data { get { return data; } @@ -104,11 +57,14 @@ namespace Crow if (value == data) return; + cancelLoadingThread (); + data = value; NotifyValueChanged ("Data", data); - _list.ClearChildren (); + lock (Interface.CurrentInterface.UpdateMutex) + _list.ClearChildren (); if (_gsList.Orientation == Orientation.Horizontal) _gsList.Width = -1; else @@ -117,17 +73,68 @@ namespace Crow if (data == null) return; - loadPage (1); + loadingThread = new Thread (loading); + loadingThread.IsBackground = true; + loadingThread.Start (); + //loadPage(1); NotifyValueChanged ("SelectedIndex", _selectedIndex); NotifyValueChanged ("SelectedItem", SelectedItem); SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem)); } } - int itemPerPage = 50; - MemoryStream templateStream = null; - Type templateBaseType = null; + [XmlAttributeAttribute][DefaultValue(-1)]public int SelectedIndex{ + get { return _selectedIndex; } + set { + if (value == _selectedIndex) + return; + + _selectedIndex = value; + + NotifyValueChanged ("SelectedIndex", _selectedIndex); + NotifyValueChanged ("SelectedItem", SelectedItem); + SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem)); + } + } + [XmlIgnore]public virtual object SelectedItem{ + get { return data == null ? null : _selectedIndex < 0 ? null : data[_selectedIndex]; } + } + protected void raiseSelectedItemChanged(){ + SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem)); + } + + #region implemented abstract members of TemplatedControl + protected override void loadTemplate (GraphicObject template = null) + { + base.loadTemplate (template); + _list = this.child.FindByName ("List") as Group; + if (_list == null) + throw new Exception ("ListBox Template MUST contain a Goup widget named 'List'."); + _gsList = _list as GenericStack; + } + #endregion + void loading(){ + if (ItemTemplates == null) + ItemTemplates = new Dictionary<string, ItemTemplate> (); + if (!ItemTemplates.ContainsKey ("default")) + ItemTemplates["default"] = new ItemTemplate (ItemTemplate); + + for (int i = 1; i <= (data.Count / itemPerPage) + 1; i++) { + if (cancelLoading) + return; + loadPage (i); + } + } + void cancelLoadingThread(){ + if (loadingThread == null) + return; + if (!loadingThread.IsAlive) + return; + cancelLoading = true; + loadingThread.Join (); + cancelLoading = false; + } void loadPage(int pageNum) { #if DEBUG_LOAD @@ -135,46 +142,62 @@ namespace Crow loadingTime.Start (); #endif - if (templateStream == null) { - templateStream = new MemoryStream (); - lock (ItemTemplate) { - using (Stream stream = Interface.GetStreamFromPath (ItemTemplate)) - stream.CopyTo (templateStream); - } - templateBaseType = Interface.GetTopContainerOfXMLStream (templateStream); + Group page = _list.Clone () as Group; + + page.Name = "page" + pageNum; + + //reset size to fit in the dir of the stacking + //because _list total size is forced to approx size + if (_gsList.Orientation == Orientation.Horizontal) { + page.Width = Measure.Fit; + page.BindMember ("Height", "../HeightPolicy"); + } else { + page.Height = Measure.Fit; + page.BindMember ("Width", "../WidthPolicy"); } - lock (Interface.CurrentInterface.UpdateMutex) { + for (int i = (pageNum - 1) * itemPerPage; i < pageNum * itemPerPage; i++) { + if (i >= data.Count) + break; + if (cancelLoading) + return; - Group page = _list.Clone () as Group; - page.Name = "page" + pageNum; - //page.Background = Color.Green; + GraphicObject g = null; + ItemTemplate itemStream = null; + Type dataType = data [i].GetType (); - //reset size to fit in the dir of the stacking - //because _list total size is forced to approx size - if (_gsList.Orientation == Orientation.Horizontal) { - page.Width = -1; - } else { - page.Height = -1; -// Bindings.Add(new Binding -// (new MemberReference (page, typeof(GraphicObject).GetMember ("Width")[0]), "../../WidthPolicy")); - //page.Bindings.Add(new Binding (page, "Width", "../../WidthPolicy")); - page.BindMember("Width", "../WidthPolicy"); - } + if (ItemTemplates.ContainsKey (dataType.FullName)) + itemStream = ItemTemplates [dataType.FullName]; + else + itemStream = ItemTemplates ["default"]; - for (int i = (pageNum - 1) * itemPerPage; i < pageNum * itemPerPage; i++) { - if (i >= data.Count) - break; - templateStream.Seek (0, SeekOrigin.Begin); - GraphicObject g = Interface.Load (templateStream, templateBaseType); - g.MouseClick += itemClick; + lock (Interface.CurrentInterface.LayoutMutex) { + g = Interface.Load (itemStream); page.AddChild (g); g.DataSource = data [i]; - //g.LogicalParent = this; } + if (this is TreeView) { + TreeView tv = this as TreeView; + while (!tv.IsRoot) { + ILayoutable tmp = tv.Parent; + while (!(tmp is TreeView)) { + tmp = tmp.Parent; + } + tv = tmp as TreeView; + } + g.MouseClick += tv.itemClick; + }else + g.MouseClick += itemClick; + + if (itemStream.Expand != null && g is Expandable) { + (g as Expandable).Expand += itemStream.Expand; + } + //g.LogicalParent = this; + } + lock (Interface.CurrentInterface.LayoutMutex) _list.AddChild (page); - } + #if DEBUG_LOAD loadingTime.Stop (); Debug.WriteLine("Listbox {2} Loading: {0} ticks \t, {1} ms", @@ -182,29 +205,6 @@ namespace Crow loadingTime.ElapsedMilliseconds, this.ToString()); #endif } - protected void _scroller_ValueChanged (object sender, ValueChangeEventArgs e) - { - if (_gsList == null) - return; - if (data == null) - return; - if (data.Count <= itemPerPage) - return; - - if (_gsList.Orientation == Orientation.Horizontal) { - } else { - if (!string.Equals (e.MemberName, "ScrollY")) - return; - - double scroll = (double)e.NewValue; - int pageHeight = (int)Math.Ceiling((double)_gsList.getSlot().Height / (double)data.Count * (double)itemPerPage); - int pagePtr = (int)Math.Ceiling((scroll + (double)pageHeight / 2.0) / (double)pageHeight); - - for (int i = _gsList.Children.Count+1; i < pagePtr+1; i++) { - loadPage (i); - } - } - } protected void _list_LayoutChanged (object sender, LayoutingEventArgs e) { #if DEBUG_LAYOUTING @@ -223,7 +223,7 @@ namespace Crow return -1; GenericStack page1 = _list.FindByName ("page1") as GenericStack; if (page1 == null) - return - 1; + return -1; return page1.Orientation == Orientation.Horizontal ? data.Count < itemPerPage ? @@ -234,69 +234,9 @@ namespace Crow (int)Math.Ceiling ((double)page1.Slot.Height / (double)itemPerPage * (double)(data.Count+1)); } } - void itemClick(object sender, MouseButtonEventArgs e){ + internal virtual void itemClick(object sender, MouseButtonEventArgs e){ SelectedIndex = data.IndexOf((sender as GraphicObject).DataSource); } - - #region IXmlSerializable -// public override System.Xml.Schema.XmlSchema GetSchema(){ return null; } -// public override void ReadXml(System.Xml.XmlReader reader) -// { -// //Template could be either an attribute containing path or expressed inlined -// //as a Template Element -// using (System.Xml.XmlReader subTree = reader.ReadSubtree()) -// { -// subTree.Read (); -// -// string template = reader.GetAttribute ("Template"); -// string tmp = subTree.ReadOuterXml (); -// -// //Load template from path set as attribute in templated control -// if (string.IsNullOrEmpty (template)) { -// //seek for template tag first -// using (XmlReader xr = new XmlTextReader (tmp, XmlNodeType.Element, null)) { -// //load template first if inlined -// -// xr.Read (); //skip current node -// -// while (!xr.EOF) { -// xr.Read (); //read first child -// if (!xr.IsStartElement ()) -// continue; -// if (xr.Name == "Template") { -// xr.Read (); -// -// Type t = Type.GetType ("Crow." + xr.Name); -// GraphicObject go = (GraphicObject)Activator.CreateInstance (t); -// (go as IXmlSerializable).ReadXml (xr); -// -// loadTemplate (go); -// -// xr.Read ();//go close tag -// xr.Read ();//Template close tag -// break; -// } else { -// xr.ReadInnerXml (); -// } -// } -// } -// } else -// loadTemplate (Interface.Load (template, this)); -// -// -// //normal xml read -// using (XmlReader xr = new XmlTextReader (tmp, XmlNodeType.Element, null)) { -// xr.Read (); -// base.ReadXml(xr); -// } -// } -// } -// public override void WriteXml(System.Xml.XmlWriter writer) -// { -// //TODO: -// throw new NotImplementedException(); -// } - #endregion } } diff --git a/src/GraphicObjects/PrivateContainer.cs b/src/GraphicObjects/PrivateContainer.cs index 08abf95a..93bae7fa 100644 --- a/src/GraphicObjects/PrivateContainer.cs +++ b/src/GraphicObjects/PrivateContainer.cs @@ -63,6 +63,7 @@ namespace Crow child.Parent = this; child.LayoutChanged += OnChildLayoutChanges; contentSize = child.Slot.Size; + child.RegisteredLayoutings = LayoutingType.None; child.RegisterForLayouting (LayoutingType.Sizing); } @@ -92,13 +93,6 @@ namespace Crow return child == goToFind ? true : child == null ? false : child.Contains(goToFind); } - 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) { @@ -175,28 +169,15 @@ namespace Crow } protected override void UpdateCache (Context ctx) { - //ctx.Save (); - Rectangle rb = Slot + Parent.ClientRectangle.Position; using (ImageSurface cache = new ImageSurface (bmp, Format.Argb32, Slot.Width, Slot.Height, 4 * Slot.Width)) { Context gr = new Context (cache); - //clip to client zone - CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius); - gr.Clip (); - if (Clipping.count > 0) { - Clipping.clearAndClip (gr); - if (child != null) { - - base.onDraw (gr); - - - child.Paint (ref gr); - } + onDraw (gr); } gr.Dispose (); @@ -205,33 +186,7 @@ namespace Crow ctx.Paint (); } Clipping.Reset(); - - //ctx.Restore (); } -// public override Rectangle ContextCoordinates (Rectangle r) -// { -// return -// Parent.ContextCoordinates(r) + Slot.Position + ClientRectangle.Position; -// } -// public override void Paint(ref Cairo.Context ctx) -// { -// if (!Visible)//check if necessary?? -// return; -// -// ctx.Save(); -// -// base.Paint(ref ctx); -// -// //clip to client zone -// CairoHelpers.CairoRectangle (ctx, Parent.ContextCoordinates(ClientRectangle + Slot.Position), CornerRadius); -// ctx.Clip(); -// -// if (child != null) -// child.Paint(ref ctx); -// -// ctx.Restore(); -// } - #endregion #region Mouse handling @@ -250,6 +205,13 @@ namespace Crow child.ClearBinding (); base.ClearBinding (); } + public override GraphicObject DeepClone () + { + PrivateContainer tmp = base.DeepClone () as PrivateContainer; + if (child != null) + tmp.SetChild (child.DeepClone ()); + return tmp; + } } } diff --git a/src/GraphicObjects/RadioButton.cs b/src/GraphicObjects/RadioButton.cs index ffd5ba27..35c96c30 100644 --- a/src/GraphicObjects/RadioButton.cs +++ b/src/GraphicObjects/RadioButton.cs @@ -67,17 +67,6 @@ namespace Crow NotifyValueChanged ("Caption", caption); } } - [XmlAttributeAttribute()][DefaultValue("#Crow.Images.Icons.radiobutton.svg")] - public string Image { - get { return image; } - set { - if (image == value) - return; - image = value; - NotifyValueChanged ("Image", image); - } - } - [XmlAttributeAttribute()][DefaultValue(false)] public bool IsChecked { diff --git a/src/GraphicObjects/TemplatedControl.cs b/src/GraphicObjects/TemplatedControl.cs index 12c2b81f..f1c719f6 100644 --- a/src/GraphicObjects/TemplatedControl.cs +++ b/src/GraphicObjects/TemplatedControl.cs @@ -25,6 +25,8 @@ using System.IO; using System.Xml; using System.Diagnostics; using System.Linq; +using System.Collections.Generic; +using System.Text; namespace Crow { @@ -54,13 +56,15 @@ namespace Crow #region CTOR public TemplatedControl () : base() { - if (Interface.XmlLoaderCount > 0) + if (Interface.CurrentInterface.XmlLoading) return; loadTemplate (); } #endregion string _template; + string _itemTemplate; + public Dictionary<string, ItemTemplate> ItemTemplates; [XmlAttributeAttribute][DefaultValue(null)] public string Template { @@ -76,13 +80,36 @@ namespace Crow loadTemplate (Interface.Load (_template, this)); } } + [XmlAttributeAttribute][DefaultValue("#Crow.Templates.ItemTemplate.goml")] + public string ItemTemplate { + get { return _itemTemplate; } + set { + if (value == _itemTemplate) + return; + + _itemTemplate = value; + //TODO:reload list with new template? + NotifyValueChanged("ItemTemplate", _itemTemplate); + } + } #region GraphicObject overrides public override GraphicObject FindByName (string nameToFind) { //prevent name searching in template return nameToFind == this.Name ? this : null; } + protected override void onDraw (Cairo.Context gr) + { + gr.Save (); + //clip to client zone + CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius); + gr.Clip (); + + if (child != null) + child.Paint (ref gr); + gr.Restore (); + } #endregion protected virtual void loadTemplate(GraphicObject template = null) @@ -115,12 +142,34 @@ namespace Crow using (XmlReader xr = new XmlTextReader (tmp, XmlNodeType.Element, null)) { //load template first if inlined - xr.Read (); //skip current node + xr.Read (); //read first child + xr.Read (); //skip root node + + while (!xr.EOF) { + if (!xr.IsStartElement ()) { + xr.Read (); + continue; + } + if (xr.Name == "ItemTemplate") { + string dataType = "default", datas = "", itemTmp; + while (xr.MoveToNextAttribute ()) { + if (xr.Name == "DataType") + dataType = xr.Value; + else if (xr.Name == "Data") + datas = xr.Value; + } + xr.MoveToElement (); + itemTmp = xr.ReadInnerXml (); + + if (ItemTemplates == null) + ItemTemplates = new Dictionary<string, ItemTemplate> (); + //TODO:check encoding + ItemTemplates[dataType] = new ItemTemplate (Encoding.UTF8.GetBytes(itemTmp)); + if (!string.IsNullOrEmpty (datas)) + ItemTemplates [dataType].CreateExpandDelegate(this, dataType, datas); - while (!xr.EOF) { - xr.Read (); //read first child - if (!xr.IsStartElement ()) continue; + } if (xr.Name == "Template") { xr.Read (); @@ -129,12 +178,9 @@ namespace Crow (go as IXmlSerializable).ReadXml (xr); loadTemplate (go); - - xr.Read ();//go close tag - xr.Read ();//Template close tag - break; - } else - xr.ReadInnerXml (); + continue; + } + xr.ReadInnerXml (); } } } else @@ -143,7 +189,7 @@ namespace Crow //if no template found, load default one if (this.child == null) loadTemplate (); - + //normal xml read using (XmlReader xr = new XmlTextReader (tmp, XmlNodeType.Element, null)) { xr.Read (); diff --git a/src/GraphicObjects/TreeView.cs b/src/GraphicObjects/TreeView.cs index 64d4afcb..51080281 100644 --- a/src/GraphicObjects/TreeView.cs +++ b/src/GraphicObjects/TreeView.cs @@ -19,6 +19,9 @@ // 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.Diagnostics; +using System.ComponentModel; namespace Crow { @@ -27,9 +30,68 @@ namespace Crow [DefaultTemplate("#Crow.Templates.TreeView.crow")] public class TreeView : ListBox { + GraphicObject selectedItemContainer = null; + Color selBackground; + Color selForeground; + bool isRoot; + + public TreeView () : base() { } + [XmlAttributeAttribute()][DefaultValue(false)] + public virtual bool IsRoot { + get { return isRoot; } + set { + if (isRoot == value) + return; + isRoot = value; + NotifyValueChanged ("IsRoot", isRoot); + } + } + + [XmlAttributeAttribute][DefaultValue("SteelBlue")]//DeepJungleGreen + public virtual Color SelectionBackground { + get { return selBackground; } + set { + if (value == selBackground) + return; + selBackground = value; + NotifyValueChanged ("SelectionBackground", selBackground); + RegisterForRedraw (); + } + } + [XmlAttributeAttribute][DefaultValue("White")] + public virtual Color SelectionForeground { + get { return selForeground; } + set { + if (value == selForeground) + return; + selForeground = value; + NotifyValueChanged ("SelectionForeground", selForeground); + RegisterForRedraw (); + } + } + + [XmlIgnore]public override object SelectedItem { + get { + return selectedItemContainer == null ? + "" : selectedItemContainer.DataSource; + } + } + internal override void itemClick (object sender, MouseButtonEventArgs e) + { + GraphicObject tmp = sender as GraphicObject; + if (selectedItemContainer != null) { + selectedItemContainer.Foreground = Color.Transparent; + selectedItemContainer.Background = Color.Transparent; + } + selectedItemContainer = tmp; + selectedItemContainer.Foreground = SelectionForeground; + selectedItemContainer.Background = SelectionBackground; + NotifyValueChanged ("SelectedItem", SelectedItem); + raiseSelectedItemChanged (); + } } } diff --git a/src/IMLStream.cs b/src/IMLStream.cs new file mode 100644 index 00000000..ccc09f45 --- /dev/null +++ b/src/IMLStream.cs @@ -0,0 +1,100 @@ +// +// IMLStream.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.IO; +using System.Reflection; +using System.Reflection.Emit; + +namespace Crow +{ + public class IMLStream : MemoryStream { + public string Path; + public Type RootType; + public IMLStream(string path) : base (){ + Path = path; + using (Stream stream = Interface.GetStreamFromPath (path)) + stream.CopyTo (this); + RootType = Interface.GetTopContainerOfXMLStream (this); + } + public IMLStream(Byte[] b) : base (b){ + RootType = Interface.GetTopContainerOfXMLStream (this); + } + } + public class ItemTemplate : IMLStream { + public EventHandler Expand; + + public ItemTemplate(string path) + : base(path){} + public ItemTemplate(Byte[] b) + : base(b){} + + public void CreateExpandDelegate (TemplatedControl host, string strDataType, string method){ + Type dataType = Type.GetType(strDataType); + Type hostType = typeof(TemplatedControl);//not sure is the best place to put the dyn method + Type evtType = typeof(EventHandler); + Type listBoxType = typeof(ListBox); + + MethodInfo evtInvoke = evtType.GetMethod ("Invoke"); + ParameterInfo [] evtParams = evtInvoke.GetParameters (); + Type handlerArgsType = evtParams [1].ParameterType; + + Type [] args = { typeof (object), typeof (object), handlerArgsType }; + DynamicMethod dm = new DynamicMethod ("dyn_expand_" + method, + typeof (void), + args, + hostType); + + + #region IL generation + ILGenerator il = dm.GetILGenerator (256); + il.DeclareLocal(typeof(GraphicObject)); + + il.Emit (OpCodes.Ldarg_1); + + MethodInfo miFindByName = typeof(GraphicObject).GetMethod("FindByName"); + il.Emit(OpCodes.Ldstr, "List"); + il.Emit (OpCodes.Callvirt, miFindByName); + il.Emit (OpCodes.Stloc_0); + + FieldInfo fiTemplates = typeof(TemplatedControl).GetField("ItemTemplates"); + il.Emit (OpCodes.Ldloc_0); + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Ldfld, fiTemplates); + il.Emit (OpCodes.Stfld, fiTemplates); + + il.Emit (OpCodes.Ldloc_0); + il.Emit (OpCodes.Ldarg_1); + il.Emit (OpCodes.Callvirt, typeof(GraphicObject).GetProperty("DataSource").GetGetMethod ()); + + MethodInfo miGetDatas = dataType.GetMethod (method, new Type[] {}); + il.Emit (OpCodes.Callvirt, miGetDatas); + + il.Emit (OpCodes.Callvirt, listBoxType.GetProperty("Data").GetSetMethod ()); + + il.Emit (OpCodes.Ret); + + #endregion + + Expand = (EventHandler)dm.CreateDelegate (evtType, host); + } + } +} + diff --git a/src/Interface.cs b/src/Interface.cs index 607044d9..99ea974b 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -59,11 +59,6 @@ namespace Crow #endregion #region Static and constants - /// <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; public static string LineBreak = "\r\n"; //TODO: shold be declared in graphicObject @@ -81,18 +76,30 @@ namespace Crow public const int MaxCacheSize = 2048; /// <summary> Above this count, the layouting is discard for the widget and it /// will not be rendered on screen </summary> - public const int MaxLayoutingTries = 50; + public const int MaxLayoutingTries = 5; + public const int MaxDiscardCount = 10; /// <summary> Global font rendering settings for Cairo </summary> public static FontOptions FontRenderingOptions; #endregion internal bool XmlLoading = false; + public Dictionary<string,object> Ressources = new Dictionary<string, object>(); public Queue<LayoutingQueueItem> LayoutingQueue = new Queue<LayoutingQueueItem> (); + public Queue<LayoutingQueueItem> DiscardQueue; + public Queue<LayoutingQueueItem> ProcessedLayoutingQueue; public Queue<GraphicObject> DrawingQueue = new Queue<GraphicObject>(); public string Clipboard;//TODO:use object instead for complex copy paste public void EnqueueForRepaint(GraphicObject g) { +// if (g.RegisteredLayoutings != LayoutingType.None) +// return; + ILayoutable l = g; + while (l.Parent != null) + l = l.Parent; + if (!(l is Interface)) + return; + lock (DrawingQueue) { if (g.IsQueueForRedraw) return; @@ -216,22 +223,23 @@ namespace Crow System.Globalization.CultureInfo savedCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; - Interface.XmlLoaderCount ++; - CurrentGOMLPath = path; GraphicObject tmp = null; try { using (Stream stream = GetStreamFromPath (path)) { tmp = Load(stream, GetTopContainerOfXMLStream(stream), hostClass); } } catch (Exception ex) { - throw new Exception ("Error loading <" + CurrentGOMLPath + ">:", ex); + throw new Exception ("Error loading <" + path + ">:", ex); } - Interface.XmlLoaderCount --; Thread.CurrentThread.CurrentCulture = savedCulture; return tmp; } + internal static GraphicObject Load (IMLStream stream, object hostClass = null){ + stream.Seek (0, SeekOrigin.Begin); + return Load(stream, stream.RootType, hostClass); + } internal static GraphicObject Load (Stream stream, Type type, object hostClass = null) { #if DEBUG_LOAD @@ -280,7 +288,7 @@ namespace Crow #if MEASURE_TIME public Stopwatch clippingTime = new Stopwatch (); public Stopwatch layoutTime = new Stopwatch (); - public Stopwatch guTime = new Stopwatch (); + public Stopwatch updateTime = new Stopwatch (); public Stopwatch drawingTime = new Stopwatch (); #endif @@ -373,26 +381,38 @@ namespace Crow if (!Monitor.TryEnter (UpdateMutex)) return; + #if MEASURE_TIME + updateTime.Restart(); + #endif + processLayouting (); clippingRegistration (); processDrawing (); + #if MEASURE_TIME + updateTime.Stop (); + #endif + Monitor.Exit (UpdateMutex); } void processLayouting(){ #if MEASURE_TIME layoutTime.Restart(); #endif + DiscardQueue = new Queue<LayoutingQueueItem> (); lock (LayoutMutex) { //Debug.WriteLine ("======= Layouting queue start ======="); LayoutingQueueItem lqi = null; - while (Interface.CurrentInterface.LayoutingQueue.Count > 0) { - lqi = Interface.CurrentInterface.LayoutingQueue.Dequeue (); + while (LayoutingQueue.Count > 0) { + lqi = LayoutingQueue.Dequeue (); lqi.ProcessLayouting (); } + LayoutingQueue = DiscardQueue; } + DiscardQueue = null; + #if MEASURE_TIME layoutTime.Stop (); #endif @@ -487,6 +507,7 @@ namespace Crow { g.Parent = this; GraphicTree.Insert (0, g); + g.RegisteredLayoutings = LayoutingType.None; g.RegisterForLayouting (LayoutingType.Sizing); } public void DeleteWidget(GraphicObject g) @@ -644,7 +665,7 @@ namespace Crow mouseRepeatThread.Join (); } - _activeWidget.onMouseUp (this, e); + _activeWidget.onMouseUp (_activeWidget, e); activeWidget = null; return true; } diff --git a/src/LayoutingQueueItem.cs b/src/LayoutingQueueItem.cs index 82673444..b2a5f3ca 100644 --- a/src/LayoutingQueueItem.cs +++ b/src/LayoutingQueueItem.cs @@ -21,6 +21,7 @@ using System; using System.Diagnostics; using System.Collections.Generic; +using System.Linq; namespace Crow { @@ -42,48 +43,84 @@ namespace Crow public class LayoutingQueueItem { /// <summary> Instance of widget to be layouted</summary> - public ILayoutable GraphicObject; + public ILayoutable Layoutable; /// <summary> Bitfield containing the element of the layout to performs (x|y|width|height)</summary> public LayoutingType LayoutType; + /// <summary> Unsuccessfull UpdateLayout and requeueing count </summary> + public int LayoutingTries, DiscardCount; + + #if DEBUG_LAYOUTING + public static List<LayoutingQueueItem> processedLQIs = new List<LayoutingQueueItem>(); + public static LayoutingQueueItem[] MultipleRunsLQIs { + get { return processedLQIs.Where(l=>l.LayoutingTries>2 || l.DiscardCount > 0).ToArray(); } + } + public static LayoutingQueueItem currentLQI = null; + public Stopwatch LQITime = new Stopwatch(); + public List<LayoutingQueueItem> triggeredLQIs = new List<LayoutingQueueItem>(); + public LayoutingQueueItem wasTriggeredBy = null; + public GraphicObject graphicObject { + get { return Layoutable as GraphicObject; } + } + public Rectangle Slot, NewSlot; + #endif #region CTOR public LayoutingQueueItem (LayoutingType _layoutType, ILayoutable _graphicObject) { LayoutType = _layoutType; - GraphicObject = _graphicObject; - GraphicObject.RegisteredLayoutings |= LayoutType; + Layoutable = _graphicObject; + Layoutable.RegisteredLayoutings |= LayoutType; + #if DEBUG_LAYOUTING + if (graphicObject.CurrentDrawLQIs == null) + graphicObject.CurrentDrawLQIs = new List<LayoutingQueueItem>(); + graphicObject.CurrentDrawLQIs.Add(this); + if (currentLQI != null){ + wasTriggeredBy = currentLQI; + currentLQI.triggeredLQIs.Add(this); + } + #endif } #endregion public void ProcessLayouting() { - if (GraphicObject.Parent == null) { + if (Layoutable.Parent == null) {//TODO:improve this //cancel layouting for object without parent, maybe some were in queue when //removed from a listbox Debug.WriteLine ("ERROR: processLayouting, no parent for: " + this.ToString ()); return; } #if DEBUG_LAYOUTING - Debug.WriteLine ("Layouting => " + this.ToString ()); + currentLQI = this; + processedLQIs.Add(this); + LQITime.Start(); #endif - if (!GraphicObject.UpdateLayout (LayoutType)) { - #if DEBUG_LAYOUTING - Debug.WriteLine ("\tRequeuing => " + this.ToString ()); - #endif - GraphicObject.LayoutingTries ++; - if (GraphicObject.LayoutingTries < Interface.MaxLayoutingTries) { - GraphicObject.RegisteredLayoutings |= LayoutType; + if (!Layoutable.UpdateLayout (LayoutType)) { + if (LayoutingTries < Interface.MaxLayoutingTries) { + LayoutingTries++; + Layoutable.RegisteredLayoutings |= LayoutType; Interface.CurrentInterface.LayoutingQueue.Enqueue (this); + } else if (DiscardCount < Interface.MaxDiscardCount) { + LayoutingTries = 0; + DiscardCount++; + Layoutable.RegisteredLayoutings |= LayoutType; + Interface.CurrentInterface.DiscardQueue.Enqueue (this); } - } else { - GraphicObject.LayoutingTries = 0; + //#if DEBUG_LAYOUTING + else + Debug.WriteLine ("\tDELETED => " + this.ToString ()); + //#endif } + #if DEBUG_LAYOUTING + currentLQI = null; + LQITime.Stop(); + #endif } public static implicit operator GraphicObject(LayoutingQueueItem queueItem) { - return queueItem.GraphicObject as GraphicObject; + return queueItem.Layoutable as GraphicObject; } public static implicit operator LayoutingType(LayoutingQueueItem lqi) { @@ -91,7 +128,13 @@ namespace Crow } public override string ToString () { - return string.Format ("{1}->{0}", LayoutType,GraphicObject.ToString()); + #if DEBUG_LAYOUTING + return string.Format ("{2};{3};{4} {1}->{0}", LayoutType,Layoutable.ToString(), + LayoutingTries,DiscardCount,LQITime.ElapsedTicks); + #else + return string.Format ("{2};{3} {1}->{0}", LayoutType,Layoutable.ToString(), + LayoutingTries, DiscardCount); + #endif } } } |