]> O.S.I.I.S - jp/crow.git/commitdiff
save commit to find bug
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 15 Apr 2021 03:33:39 +0000 (05:33 +0200)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Thu, 15 Apr 2021 10:48:08 +0000 (12:48 +0200)
12 files changed:
Crow/Templates/DefaultTableHeaderCell.template [new file with mode: 0644]
Crow/Templates/MenuItem.template
Crow/src/IML/CompilerServices.cs
Crow/src/IML/Node.cs
Crow/src/ItemTemplate.cs
Crow/src/Widgets/Group.cs
Crow/src/Widgets/GroupBase.cs [new file with mode: 0644]
Crow/src/Widgets/Table copy.cs [new file with mode: 0644]
Crow/src/Widgets/Table.cs
Crow/src/Widgets/TableRow copy.cs [new file with mode: 0644]
Crow/src/Widgets/TableRow.cs
Crow/src/Widgets/Widget.cs

diff --git a/Crow/Templates/DefaultTableHeaderCell.template b/Crow/Templates/DefaultTableHeaderCell.template
new file mode 100644 (file)
index 0000000..0bb5368
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<Label RootDataLevel="true" Style="TableHeaderLabel" Text="{Caption}" Width="{Width}"/>
\ No newline at end of file
index d5b39dd475a6125900f316ea5e1146546a1c10da..96adbd1eda38a117a4962ff11104f9d206d6e458 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <ListItem>
        <Popper Font="{./Font}" Caption="{./Caption}"  Background="{./Background}" PopDirection="{./PopDirection}"
-               Foreground = "{./Foreground}" CanPop="{./HasChildren}"
+               Foreground = "{./Foreground}" 
                IsPopped="{²./IsOpened}" PopWidth="{./PopWidth}" PopHeight="{./PopHeight}">
                <Template>
                        <CheckBox IsChecked="{²./IsPopped}" Caption="{./Caption}" Background="{./Background}" Foreground="{./Foreground}">
index 644902f0fa2782146a7b8b6e1d721fd296629e30..8d63bb8ddef08848ff901770398378d54941cb3f 100644 (file)
@@ -103,8 +103,8 @@ namespace Crow.IML
                #region tree handling methods
                internal static FieldInfo fiChild = typeof(PrivateContainer).GetField ("child", BindingFlags.Instance | BindingFlags.NonPublic);
                internal static MethodInfo miSetChild = typeof (Container).GetMethod ("SetChild");
-               internal static MethodInfo miAddChild = typeof (Group).GetMethod ("AddChild");
-               internal static FieldInfo fiChildren = typeof(Group).GetField ("children", BindingFlags.Instance | BindingFlags.NonPublic);
+               internal static MethodInfo miAddChild = typeof (GroupBase).GetMethod ("AddChild");
+               internal static MethodInfo miGetChildren = typeof(GroupBase).GetProperty ("Children", BindingFlags.Instance | BindingFlags.Public).GetGetMethod();
                internal static MethodInfo miLoadTmp = typeof (TemplatedControl).GetMethod ("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic);
                internal static PropertyInfo piContent = typeof(TemplatedContainer).GetProperty ("Content");
                internal static MethodInfo miAddItem = typeof (TemplatedGroup).GetMethod ("AddItem", BindingFlags.Instance | BindingFlags.Public);
@@ -504,8 +504,8 @@ namespace Crow.IML
                /// <param name="parentType">Parent type</param>
                /// <param name="index">Index of child, -1 for template root</param>
                internal static void emitGetChild(ILGenerator il, Type parentType, int index){
-                       if (typeof (Group).IsAssignableFrom (parentType)) {
-                               il.Emit (OpCodes.Ldfld, fiChildren);
+                       if (typeof (GroupBase).IsAssignableFrom (parentType)) {
+                               il.Emit (OpCodes.Callvirt, miGetChildren);
                                il.Emit(OpCodes.Ldc_I4, index);
                                il.Emit (OpCodes.Callvirt, miGetGObjItem);
                                return;
index 811cfd6d4dc5ee74ed99f0055f4caf9364539232..5ef078c14b4fcd5944a707fc9247d41e77ec69a7 100644 (file)
@@ -39,7 +39,7 @@ namespace Crow.IML
                /// <returns>The child addition method</returns>
                /// <param name="childIdx">child index or, template root node has index == -1</param>
                public MethodInfo GetAddMethod(int childIdx){
-                       if (typeof (Group).IsAssignableFrom (CrowType))
+                       if (typeof (GroupBase).IsAssignableFrom (CrowType))
                                return CompilerServices.miAddChild;
                        if (typeof (Container).IsAssignableFrom (CrowType))
                                return CompilerServices.miSetChild;
index e4fc2d8e87d345c2807c2bf84ddb2a1133db259b..7e2f7194e9d82d3301c58164adb6f94e2900289e 100644 (file)
@@ -279,8 +279,8 @@ namespace Crow
                }
                public static List<Widget> GetChildren (this Widget go) {
                        Type goType = go.GetType ();
-                       if (typeof (Group).IsAssignableFrom (goType))
-                               return (go as Group).Children;
+                       if (typeof (GroupBase).IsAssignableFrom (goType))
+                               return (go as GroupBase).Children;
                        if (typeof (Container).IsAssignableFrom (goType))
                                return new List<Widget> (new Widget[] { (go as Container).Child });
                        if (typeof (TemplatedContainer).IsAssignableFrom (goType))
index d5e3d5e0a5e573ca16726926426b9fcc52fefd30..4ce70c4af57c8298ccb69849fb3f65440572d302 100644 (file)
@@ -12,76 +12,20 @@ using static Crow.Logger;
 
 namespace Crow
 {
-       public class Group : Widget
+       public class Group : GroupBase
     {
-               #if DESIGN_MODE
-               public override bool FindByDesignID(string designID, out Widget go){
-                       go = null;
-                       if (base.FindByDesignID (designID, out go))
-                               return true;
-                       childrenRWLock.EnterReadLock ();
-                       foreach (Widget w in Children) {
-                               if (!w.FindByDesignID (designID, out go))
-                                       continue;
-                               childrenRWLock.ExitReadLock ();
-                               return true;
-                       }
-                       childrenRWLock.ExitReadLock ();
-                       return false;
-               }
-               public override void getIML (System.Xml.XmlDocument doc, System.Xml.XmlNode parentElem)
-               {
-                       if (this.design_isTGItem)
-                               return;
-                       base.getIML (doc, parentElem);
-                       foreach (Widget g in Children) {
-                               g.getIML (doc, parentElem.LastChild);   
-                       }
-               }
-               #endif
-
-               protected ReaderWriterLockSlim childrenRWLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
 
                #region CTOR
                public Group () {}
                public Group(Interface iface, string style = null) : base (iface, style) { }
                #endregion
 
+               internal Widget largestChild = null;
+               internal Widget tallestChild = null;
                #region EVENT HANDLERS
                public event EventHandler<EventArgs> ChildrenCleared;
                #endregion
-
-               internal Widget largestChild = null;
-               internal Widget tallestChild = null;
-
-        bool _multiSelect = false;
-               ObservableList<Widget> children = new ObservableList<Widget>();
-
-        public virtual ObservableList<Widget> Children => children;
-               [DefaultValue(false)]
-        public bool MultiSelect
-        {
-            get => _multiSelect;
-            set { _multiSelect = value; }
-        }
-               public virtual void AddChild(Widget g){
-                       if (disposed) {
-                               DbgLogger.AddEvent (DbgEvtType.AlreadyDisposed | DbgEvtType.GOAddChild);
-                               return;
-                       }
-
-                       childrenRWLock.EnterWriteLock();
-
-                       g.Parent = this;
-                       Children.Add (g);
-
-                       childrenRWLock.ExitWriteLock();
-
-                       //g.RegisteredLayoutings = LayoutingType.None;
-                       g.LayoutChanged += OnChildLayoutChanges;
-                       g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
-               }
-        public virtual void RemoveChild(Widget child)
+        public override void RemoveChild(Widget child)
                {
                        child.LayoutChanged -= OnChildLayoutChanges;
                        //check if HoverWidget is removed from Tree
@@ -106,12 +50,7 @@ namespace Crow
                        this.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
 
                }
-        public virtual void DeleteChild(Widget child)
-               {
-                       RemoveChild (child);
-                       child.Dispose ();
-        }
-               public virtual void InsertChild (int idx, Widget g) {
+               public override void InsertChild (int idx, Widget g) {
                        if (disposed) {
                                DbgLogger.AddEvent (DbgEvtType.AlreadyDisposed | DbgEvtType.GOAddChild);
                                return;
@@ -120,20 +59,23 @@ namespace Crow
                                
                        g.Parent = this;
                        Children.Insert (idx, g);
-
+                       
                        childrenRWLock.ExitWriteLock ();
 
-                       g.RegisteredLayoutings = LayoutingType.None;
+                       if (g.LastSlots.Width > contentSize.Width) {
+                               largestChild = g;
+                               contentSize.Width = g.LastSlots.Width;
+                       }
+                       if (g.LastSlots.Height > contentSize.Height) {
+                               tallestChild = g;
+                               contentSize.Height = g.LastSlots.Height;
+                       }
+
+                       
                        g.LayoutChanged += OnChildLayoutChanges;
                        g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
                }
-               public virtual void RemoveChild (int idx) {
-                       RemoveChild (children[idx]);
-               }
-               public virtual void DeleteChild (int idx) {
-                       DeleteChild (children[idx]);
-               }
-               public virtual void ClearChildren()
+               public override void ClearChildren()
                {
                        childrenRWLock.EnterWriteLock ();
 
@@ -151,104 +93,17 @@ namespace Crow
                        RegisterForLayouting (LayoutingType.Sizing);
                        ChildrenCleared.Raise (this, new EventArgs ());
                }
-               public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
-               {
-                       base.OnDataSourceChanged (this, e);
-
-                       childrenRWLock.EnterReadLock ();
-                       foreach (Widget g in Children) {
-                               if (g.localDataSourceIsNull & g.localLogicalParentIsNull)
-                                       g.OnDataSourceChanged (g, e);   
-                       }
-                       childrenRWLock.ExitReadLock ();
-               }
-
-               public void putWidgetOnTop(Widget w)
-               {
-                       if (Children.Contains(w))
-                       {
-                               childrenRWLock.EnterWriteLock ();
-
-                               Children.Remove (w);
-                               Children.Add (w);
-
-                               childrenRWLock.ExitWriteLock ();
-                       }
-               }
-               public void putWidgetOnBottom(Widget w)
-               {
-                       if (Children.Contains(w))
-                       {
-                               childrenRWLock.EnterWriteLock ();
-
-                               Children.Remove (w);
-                               Children.Insert (0, w);
-
-                               childrenRWLock.ExitWriteLock ();
-                       }
-               }
 
                #region GraphicObject overrides
-
-               public override Widget FindByName (string nameToFind)
-               {
-                       if (Name == nameToFind)
-                               return this;
-                       Widget tmp = null;
-
-                       childrenRWLock.EnterReadLock ();
-
-                       foreach (Widget w in Children) {
-                               tmp = w.FindByName (nameToFind);
-                               if (tmp != null)
-                                       break;
-                       }
-
-                       childrenRWLock.ExitReadLock ();
-
-                       return tmp;
-               }
-               public override Widget FindByType<T> ()
-               {
-                       if (this is T)
-                               return this;
-                       Widget tmp = null;
-
-                       childrenRWLock.EnterReadLock ();
-
-                       foreach (Widget w in Children) {
-                               tmp = w.FindByType<T> ();
-                               if (tmp != null)
-                                       break;
-                       }
-
-                       childrenRWLock.ExitReadLock ();
-
-                       return tmp;
-               }
-               public override bool Contains (Widget goToFind)
-               {
-                       foreach (Widget w in Children) {
-                               if (w == goToFind)
-                                       return true;
-                               if (w.Contains (goToFind))
-                                       return true;
-                       }
-                       return false;
-               }
                public override int measureRawSize (LayoutingType lt)
                {
                        if (Children.Count > 0) {
                                if (lt == LayoutingType.Width) {
                                        if (largestChild == null)
-                                               searchLargestChild ();
-                                       if (largestChild == null)
-                                               searchLargestChild (true);
+                                               searchLargestChild ();                                  
                                } else {
                                        if (tallestChild == null)
-                                               searchTallestChild ();
-                                       if (tallestChild == null)
-                                               searchTallestChild (true);
+                                               searchTallestChild ();                                  
                                }
                        }
                        return base.measureRawSize (lt);
@@ -262,97 +117,29 @@ namespace Crow
                        //position smaller objects in group when group size is fit
                        switch (layoutType) {
                        case LayoutingType.Width:
+                               //childrenRWLock.EnterReadLock ();
                                foreach (Widget c in Children) {
                                        if (c.Width.IsRelativeToParent)
                                                c.RegisterForLayouting (LayoutingType.Width);
                                        else
                                                c.RegisterForLayouting (LayoutingType.X);
                                }
+                               //childrenRWLock.ExitReadLock ();
                                break;
                        case LayoutingType.Height:
+                               //childrenRWLock.EnterReadLock ();
                                foreach (Widget c in Children) {
                                        if (c.Height.IsRelativeToParent)
                                                c.RegisterForLayouting (LayoutingType.Height);
                                        else
                                                c.RegisterForLayouting (LayoutingType.Y);
                                }
+                               //childrenRWLock.ExitReadLock ();
                                break;
                        }
                        childrenRWLock.ExitReadLock ();
                }
-               protected override void onDraw (Context gr)
-               {
-                       DbgLogger.StartEvent (DbgEvtType.GODraw, this);
-
-                       base.onDraw (gr);                       
-
-                       if (ClipToClientRect) {
-                               gr.Save ();
-                               //clip to client zone
-                               CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
-                               gr.Clip ();
-                       }
-
-                       childrenRWLock.EnterReadLock ();
-
-                       for (int i = 0; i < Children.Count; i++) 
-                               Children[i].Paint (gr);                 
-
-                       childrenRWLock.ExitReadLock ();
-
-                       if (ClipToClientRect)
-                               gr.Restore ();
-
-                       DbgLogger.EndEvent (DbgEvtType.GODraw);
-               }
-               protected override void UpdateCache (Context ctx)
-               {
-                       DbgLogger.StartEvent(DbgEvtType.GOUpdateCache, this);
-                       if (!Clipping.IsEmpty) {
-                               using (Context gr = new Context (bmp)) {
-                                       for (int i = 0; i < Clipping.NumRectangles; i++)
-                                               gr.Rectangle(Clipping.GetRectangle(i));
-                                       gr.ClipPreserve();
-                                       gr.Operator = Operator.Clear;
-                                       gr.Fill();
-                                       gr.Operator = Operator.Over;
-
-                                       base.onDraw (gr);
-
-                                       if (ClipToClientRect) {
-                                               CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
-                                               gr.Clip ();
-                                       }
-
-                                       childrenRWLock.EnterReadLock ();
-
-                                       foreach (Widget c in Children) {
-                                               if (!c.IsVisible)
-                                                       continue;
-                                               if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
-                                                       continue;
-                                               c.Paint (gr);
-                                       }
-
-                                       childrenRWLock.ExitReadLock ();
-
-                                       #if DEBUG_CLIP_RECTANGLE
-                                       /*gr.LineWidth = 1;
-                                       gr.SetSourceColor(Color.DarkMagenta.AdjustAlpha (0.8));
-                                       for (int i = 0; i < Clipping.NumRectangles; i++)
-                                               gr.Rectangle(Clipping.GetRectangle(i));
-                                       gr.Stroke ();*/
-                                       #endif
-                               }
-                               DbgLogger.AddEvent (DbgEvtType.GOResetClip, this);
-                               Clipping.Reset ();
-                       }/*else
-                               Console.WriteLine("GROUP REPAINT WITH EMPTY CLIPPING");*/
-                       paintCache (ctx, Slot + Parent.ClientRectangle.Position);
-                       DbgLogger.EndEvent(DbgEvtType.GOUpdateCache);                           
-               }
                #endregion
-
                public virtual void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
                {
                        DbgLogger.StartEvent(DbgEvtType.GOOnChildLayoutChange, this);
@@ -361,38 +148,28 @@ namespace Crow
 
                        switch (arg.LayoutType) {
                        case LayoutingType.Width:
-                               if (Width != Measure.Fit) {
-                                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
-                                       return;
-                               }
-                               if (g.Slot.Width > contentSize.Width) {
-                                       largestChild = g;
-                                       contentSize.Width = g.Slot.Width;
-                               } else if (g == largestChild)
-                                       searchLargestChild ();
-                               else {
-                                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
-                                       return;
+                               if (Width == Measure.Fit) {
+                                       if (g.Slot.Width > contentSize.Width) {
+                                               largestChild = g;
+                                               contentSize.Width = g.Slot.Width;
+                                       } else if (g == largestChild)
+                                               searchLargestChild ();
+                                       else
+                                               break;
+                                       this.RegisterForLayouting (LayoutingType.Width);
                                }
-
-                               this.RegisterForLayouting (LayoutingType.Width);
                                break;
                        case LayoutingType.Height:
-                               if (Height != Measure.Fit) {
-                                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);                                   
-                                       return;
-                               }
-                               if (g.Slot.Height > contentSize.Height) {
-                                       tallestChild = g;
-                                       contentSize.Height = g.Slot.Height;
-                               } else if (g == tallestChild)
-                                       searchTallestChild ();
-                               else {
-                                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
-                                       return;
+                               if (Height == Measure.Fit) {
+                                       if (g.Slot.Height > contentSize.Height) {
+                                               tallestChild = g;
+                                               contentSize.Height = g.Slot.Height;
+                                       } else if (g == tallestChild)
+                                               searchTallestChild ();
+                                       else
+                                               break;
+                                       this.RegisterForLayouting (LayoutingType.Height);
                                }
-
-                               this.RegisterForLayouting (LayoutingType.Height);
                                break;
                        }
                        DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
@@ -403,10 +180,12 @@ namespace Crow
                        tallestChild = null;
                        contentSize = 0;
                }
-               void searchLargestChild (bool forceMeasure = false)
+               protected virtual void searchLargestChild (bool forceMeasure = false)
                {
                        DbgLogger.StartEvent (DbgEvtType.GOSearchLargestChild, this);
 
+                       //childrenRWLock.EnterReadLock ();
+
                        largestChild = null;
                        contentSize.Width = 0;
                        for (int i = 0; i < Children.Count; i++) {
@@ -414,8 +193,8 @@ namespace Crow
                                        continue;
                                int cw = 0;
                                if (forceMeasure)
-                                       cw = children [i].measureRawSize (LayoutingType.Width);
-                               else if (children [i].RegisteredLayoutings.HasFlag (LayoutingType.Width))
+                                       cw = Children [i].measureRawSize (LayoutingType.Width);
+                               else if (Children [i].RegisteredLayoutings.HasFlag (LayoutingType.Width))
                                        continue;
                                else
                                        cw = Children [i].Slot.Width;
@@ -424,13 +203,19 @@ namespace Crow
                                        largestChild = Children [i];
                                }
                        }
+                       if (largestChild == null && !forceMeasure)
+                               searchLargestChild (true);
+
+                       //childrenRWLock.ExitReadLock ();
 
                        DbgLogger.EndEvent (DbgEvtType.GOSearchLargestChild);
                }
-               void searchTallestChild (bool forceMeasure = false)
+               protected virtual void searchTallestChild (bool forceMeasure = false)
                {
                        DbgLogger.StartEvent (DbgEvtType.GOSearchTallestChild, this);
 
+                       //childrenRWLock.EnterReadLock ();
+
                        tallestChild = null;
                        contentSize.Height = 0;
                        for (int i = 0; i < Children.Count; i++) {
@@ -438,8 +223,8 @@ namespace Crow
                                        continue;
                                int ch = 0;
                                if (forceMeasure)
-                                       ch = children [i].measureRawSize (LayoutingType.Height);
-                               else if (children [i].RegisteredLayoutings.HasFlag (LayoutingType.Height))
+                                       ch = Children [i].measureRawSize (LayoutingType.Height);
+                               else if (Children [i].RegisteredLayoutings.HasFlag (LayoutingType.Height))
                                        continue;
                                else
                                        ch = Children [i].Slot.Height;
@@ -448,50 +233,12 @@ namespace Crow
                                        tallestChild = Children [i];
                                }
                        }
+                       if (tallestChild == null && !forceMeasure)
+                               searchTallestChild (true);
 
-                       DbgLogger.EndEvent (DbgEvtType.GOSearchTallestChild);
-               }
-
+                       //childrenRWLock.ExitReadLock ();
 
-               #region Mouse handling
-               public override void checkHoverWidget (MouseMoveEventArgs e) {
-                       base.checkHoverWidget (e);//TODO:check if not possible to put it at beginning of meth to avoid doubled check to DropTarget.
-                       childrenRWLock.EnterReadLock ();
-                       for (int i = Children.Count - 1; i >= 0; i--) {
-                               if (Children[i].MouseIsIn (e.Position)) {
-                                       Children[i].checkHoverWidget (e);
-                                       childrenRWLock.ExitReadLock ();
-                                       return;
-                               }
-                       }
-                       childrenRWLock.ExitReadLock ();                 
-               }
-//             public override bool PointIsIn (ref Point m)
-//             {
-//                     if (!base.PointIsIn (ref m))
-//                             return false;
-//                     if (CurrentInterface.HoverWidget == this)
-//                             return true;
-//                     lock (Children) {
-//                             for (int i = Children.Count - 1; i >= 0; i--) {
-//                                     if (Children [i].Slot.ContainsOrIsEqual (m) && !(bool)CurrentInterface.HoverWidget?.IsOrIsInside(Children[i])) {                                                
-//                                             return false;
-//                                     }
-//                             }
-//                     }
-//                     return true;
-//             }
-               #endregion
-
-               protected override void Dispose (bool disposing)
-               {
-                       if (disposing) {
-                               childrenRWLock.EnterReadLock ();
-                               foreach (Widget c in children)
-                                       c.Dispose ();
-                               childrenRWLock.ExitReadLock ();
-                       }
-                       base.Dispose (disposing);
+                       DbgLogger.EndEvent (DbgEvtType.GOSearchTallestChild);
                }
        }
 }
diff --git a/Crow/src/Widgets/GroupBase.cs b/Crow/src/Widgets/GroupBase.cs
new file mode 100644 (file)
index 0000000..0ef24bd
--- /dev/null
@@ -0,0 +1,302 @@
+// Copyright (c) 2013-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using Crow.Cairo;
+using System.Threading;
+
+using static Crow.Logger;
+
+namespace Crow
+{
+       public abstract class GroupBase : Widget
+    {
+               #if DESIGN_MODE
+               public override bool FindByDesignID(string designID, out Widget go){
+                       go = null;
+                       if (base.FindByDesignID (designID, out go))
+                               return true;
+                       childrenRWLock.EnterReadLock ();
+                       foreach (Widget w in Children) {
+                               if (!w.FindByDesignID (designID, out go))
+                                       continue;
+                               childrenRWLock.ExitReadLock ();
+                               return true;
+                       }
+                       childrenRWLock.ExitReadLock ();
+                       return false;
+               }
+               public override void getIML (System.Xml.XmlDocument doc, System.Xml.XmlNode parentElem)
+               {
+                       if (this.design_isTGItem)
+                               return;
+                       base.getIML (doc, parentElem);
+                       foreach (Widget g in Children) {
+                               g.getIML (doc, parentElem.LastChild);   
+                       }
+               }
+               #endif
+               protected ReaderWriterLockSlim childrenRWLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
+
+               #region CTOR
+               public GroupBase () {}
+               public GroupBase (Interface iface, string style = null) : base (iface, style) { }
+               #endregion
+
+        bool _multiSelect = false;
+               ObservableList<Widget> children = new ObservableList<Widget>();
+        public virtual ObservableList<Widget> Children => children;
+
+               [DefaultValue(false)]
+        public bool MultiSelect
+        {
+            get => _multiSelect;
+            set {
+                               if (_multiSelect == value)
+                                       return;
+                               _multiSelect = value;
+                               NotifyValueChangedAuto (_multiSelect);
+                       }
+        }
+               public virtual void AddChild(Widget g){
+                       InsertChild (children.Count, g);
+               }
+        public virtual void RemoveChild(Widget child)
+               {
+                       //check if HoverWidget is removed from Tree
+                       if (IFace.HoverWidget != null) {
+                               if (this.Contains (IFace.HoverWidget))
+                                       IFace.HoverWidget = null;
+                       }
+
+                       childrenRWLock.EnterWriteLock ();
+
+                       Children.Remove(child);
+                       child.Parent = null;
+                       child.LogicalParent = null;
+
+                       childrenRWLock.ExitWriteLock ();
+               }
+        public virtual void DeleteChild(Widget child)
+               {
+                       RemoveChild (child);
+                       child.Dispose ();
+        }
+               public virtual void InsertChild (int idx, Widget g) {
+                       if (disposed) {
+                               DbgLogger.AddEvent (DbgEvtType.AlreadyDisposed | DbgEvtType.GOAddChild);
+                               return;
+                       }
+                       childrenRWLock.EnterWriteLock ();
+                               
+                       g.Parent = this;
+                       Children.Insert (idx, g);
+
+                       childrenRWLock.ExitWriteLock ();                        
+               }
+               public virtual void RemoveChild (int idx) {
+                       RemoveChild (children[idx]);
+               }
+               public virtual void DeleteChild (int idx) {
+                       DeleteChild (children[idx]);
+               }
+               public virtual void ClearChildren()
+               {
+                       childrenRWLock.EnterWriteLock ();
+
+                       while (Children.Count > 0) {
+                               Widget g = Children [Children.Count - 1];
+                               Children.RemoveAt (Children.Count - 1);
+                               g.Dispose ();
+                       }
+
+                       childrenRWLock.ExitWriteLock ();
+               }
+               public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
+               {
+                       base.OnDataSourceChanged (this, e);
+
+                       childrenRWLock.EnterReadLock ();
+                       foreach (Widget g in Children) {
+                               if (g.localDataSourceIsNull & g.localLogicalParentIsNull)
+                                       g.OnDataSourceChanged (g, e);   
+                       }
+                       childrenRWLock.ExitReadLock ();
+               }
+
+               public void putWidgetOnTop(Widget w)
+               {
+                       if (Children.Contains(w))
+                       {
+                               childrenRWLock.EnterWriteLock ();
+
+                               Children.Remove (w);
+                               Children.Add (w);
+
+                               childrenRWLock.ExitWriteLock ();
+                       }
+               }
+               public void putWidgetOnBottom(Widget w)
+               {
+                       if (Children.Contains(w))
+                       {
+                               childrenRWLock.EnterWriteLock ();
+
+                               Children.Remove (w);
+                               Children.Insert (0, w);
+
+                               childrenRWLock.ExitWriteLock ();
+                       }
+               }
+
+               #region GraphicObject overrides
+               public override Widget FindByName (string nameToFind)
+               {
+                       if (Name == nameToFind)
+                               return this;
+                       Widget tmp = null;
+
+                       childrenRWLock.EnterReadLock ();
+
+                       foreach (Widget w in Children) {
+                               tmp = w.FindByName (nameToFind);
+                               if (tmp != null)
+                                       break;
+                       }
+
+                       childrenRWLock.ExitReadLock ();
+
+                       return tmp;
+               }
+               public override Widget FindByType<T> ()
+               {
+                       if (this is T)
+                               return this;
+                       Widget tmp = null;
+
+                       childrenRWLock.EnterReadLock ();
+
+                       foreach (Widget w in Children) {
+                               tmp = w.FindByType<T> ();
+                               if (tmp != null)
+                                       break;
+                       }
+
+                       childrenRWLock.ExitReadLock ();
+
+                       return tmp;
+               }
+               public override bool Contains (Widget goToFind)
+               {
+                       foreach (Widget w in Children) {
+                               if (w == goToFind)
+                                       return true;
+                               if (w.Contains (goToFind))
+                                       return true;
+                       }
+                       return false;
+               }
+
+               protected override void onDraw (Context gr)
+               {
+                       DbgLogger.StartEvent (DbgEvtType.GODraw, this);
+
+                       base.onDraw (gr);                       
+
+                       if (ClipToClientRect) {
+                               gr.Save ();
+                               //clip to client zone
+                               CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+                               gr.Clip ();
+                       }
+
+                       childrenRWLock.EnterReadLock ();
+
+                       for (int i = 0; i < Children.Count; i++) 
+                               Children[i].Paint (gr);                 
+
+                       childrenRWLock.ExitReadLock ();
+
+                       if (ClipToClientRect)
+                               gr.Restore ();
+
+                       DbgLogger.EndEvent (DbgEvtType.GODraw);
+               }
+               protected override void UpdateCache (Context ctx)
+               {
+                       DbgLogger.StartEvent(DbgEvtType.GOUpdateCache, this);
+                       if (!Clipping.IsEmpty) {
+                               using (Context gr = new Context (bmp)) {
+                                       for (int i = 0; i < Clipping.NumRectangles; i++)
+                                               gr.Rectangle(Clipping.GetRectangle(i));
+                                       gr.ClipPreserve();
+                                       gr.Operator = Operator.Clear;
+                                       gr.Fill();
+                                       gr.Operator = Operator.Over;
+
+                                       base.onDraw (gr);
+
+                                       if (ClipToClientRect) {
+                                               CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+                                               gr.Clip ();
+                                       }
+
+                                       childrenRWLock.EnterReadLock ();
+
+                                       foreach (Widget c in Children) {
+                                               if (!c.IsVisible)
+                                                       continue;
+                                               if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
+                                                       continue;
+                                               c.Paint (gr);
+                                       }
+
+                                       childrenRWLock.ExitReadLock ();
+
+                                       #if DEBUG_CLIP_RECTANGLE
+                                       /*gr.LineWidth = 1;
+                                       gr.SetSourceColor(Color.DarkMagenta.AdjustAlpha (0.8));
+                                       for (int i = 0; i < Clipping.NumRectangles; i++)
+                                               gr.Rectangle(Clipping.GetRectangle(i));
+                                       gr.Stroke ();*/
+                                       #endif
+                               }
+                               DbgLogger.AddEvent (DbgEvtType.GOResetClip, this);
+                               Clipping.Reset ();
+                       }/*else
+                               Console.WriteLine("GROUP REPAINT WITH EMPTY CLIPPING");*/
+                       paintCache (ctx, Slot + Parent.ClientRectangle.Position);
+                       DbgLogger.EndEvent(DbgEvtType.GOUpdateCache);                           
+               }
+               #endregion
+
+               #region Mouse handling
+               public override void checkHoverWidget (MouseMoveEventArgs e) {
+                       base.checkHoverWidget (e);//TODO:check if not possible to put it at beginning of meth to avoid doubled check to DropTarget.
+                       childrenRWLock.EnterReadLock ();
+                       for (int i = Children.Count - 1; i >= 0; i--) {
+                               if (Children[i].MouseIsIn (e.Position)) {
+                                       Children[i].checkHoverWidget (e);
+                                       childrenRWLock.ExitReadLock ();
+                                       return;
+                               }
+                       }
+                       childrenRWLock.ExitReadLock ();                 
+               }
+               #endregion
+
+               protected override void Dispose (bool disposing)
+               {
+                       if (disposing) {
+                               childrenRWLock.EnterReadLock ();
+                               foreach (Widget c in Children)
+                                       c.Dispose ();
+                               childrenRWLock.ExitReadLock ();
+                       }
+                       base.Dispose (disposing);
+               }
+       }
+}
diff --git a/Crow/src/Widgets/Table copy.cs b/Crow/src/Widgets/Table copy.cs
new file mode 100644 (file)
index 0000000..5aeaede
--- /dev/null
@@ -0,0 +1,259 @@
+// Copyright (c) 2019-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.ComponentModel;
+using System.Linq;
+using Crow.Cairo;
+
+namespace Crow
+{
+       /// <summary>
+       /// Table column definition
+       /// </summary>
+       public class Column2 : IValueChange
+       {
+               #region IValueChange implementation
+               public event EventHandler<ValueChangeEventArgs> ValueChanged;
+               public virtual void NotifyValueChanged (string MemberName, object _value)
+                       => ValueChanged.Raise (this, new ValueChangeEventArgs (MemberName, _value));
+               #endregion
+
+               string caption;
+               Measure width = Measure.Fit;
+               public int ComputedWidth;
+               public Widget LargestWidget;
+
+               public string Caption {
+                       get => caption;
+                       set {
+                               if (caption == value)
+                                       return;
+                               caption = value;
+                               NotifyValueChanged ("Caption", caption);
+                       }
+               }
+               /// <summary>
+               /// column width, special value 'Inherit' will be used to share table width equaly among columns
+               /// </summary>
+               /// <value>The column's width.</value>
+               public Measure Width {
+                       get => width;
+                       set {
+                               if (width == value)
+                                       return;
+                               width = value;
+                               NotifyValueChanged ("Width", width);
+                       }
+               }
+
+               public static Column Parse (string str) {
+                       if (string.IsNullOrEmpty (str))
+                               return null;                            
+                       Column c = new Column();
+                       string[] tmp = str.Split (',');
+                       c.Caption = tmp[0];
+                       if (tmp.Length > 1)
+                               c.Width = Measure.Parse (tmp[1]);
+                       return c;
+               }
+       }
+
+
+       public class Table2 : VerticalStack
+       {
+               #region CTOR
+               public Table2 ()  {}
+               public Table2 (Interface iface, string style = null) : base (iface, style) { }
+               #endregion
+
+               //int lineWidth;
+               ObservableList<Column> columns = new ObservableList<Column>();
+
+               public ObservableList<Column> Columns {
+                       get => columns;
+                       set {
+                               if (columns == value)
+                                       return;
+                               if (columns != null) {
+                                       columns.ListAdd -= Ol_AddColumn;
+                                       columns.ListAdd -= Ol_RemoveColumn;
+
+                                       foreach (Column c in columns) 
+                                               c.ValueChanged += column_valueChanged;                                  
+                               }
+
+                               columns = value;
+
+                               if (columns != null) {
+                                       columns.ListAdd += Ol_AddColumn;
+                                       columns.ListAdd += Ol_RemoveColumn;
+
+                                       foreach (Column c in columns) 
+                                               c.ValueChanged += column_valueChanged;                                  
+
+                                       foreach (TableRow row in Children) {
+                                               for (int i = 0; i < columns.Count && i < row.Children.Count; i++)
+                                                       row.Children[i].Width = columns[i].Width;
+                                       }
+                               }
+                               NotifyValueChangedAuto(columns);
+                       }
+               }
+
+               void column_valueChanged (object sender, ValueChangeEventArgs e) {
+                       switch (e.MemberName) {
+                       case "Width":
+                               int columnIdx = columns.IndexOf (sender as Column);
+                               foreach (TableRow row in Children.OfType<TableRow>().Where (r => r.Children.Count > columnIdx)) 
+                                       row.Children[columnIdx].Width = (Measure)e.NewValue;
+                               break;                                                  
+                       }
+               }
+
+               public override void AddChild (Widget child) {
+                       if (!(child is TableRow tr))                    
+                               throw new Exception ("Table widget accept only TableRow as child.");
+                       base.AddChild (child);
+
+                       tr.Children.ListAdd += Ol_tableRow_ChildAdd;
+                       tr.Children.ListRemove += Ol_tableRow_ChildRemove;
+                       tr.Children.ListClear += Ol_tableRow_ChildClear;
+
+                       for (int i = 0; i < columns.Count && i < tr.Children.Count; i++)
+                               tr.Children[i].Width = columns[i].Width;
+               }
+               public override void RemoveChild(Widget child)
+               {
+                       base.RemoveChild(child);
+
+                       TableRow tr = child as TableRow;
+                       tr.Children.ListAdd -= Ol_tableRow_ChildAdd;
+                       tr.Children.ListRemove -= Ol_tableRow_ChildRemove;
+                       tr.Children.ListClear -= Ol_tableRow_ChildClear;
+               }
+               void Ol_tableRow_ChildAdd (object sender, ListChangedEventArg e)
+               {
+                       Widget w = e.Element as Widget;
+                       if (e.Index < Columns.Count)
+                               w.Width = Columns[e.Index].Width;
+                       w.LayoutChanged += onTableRow_ChildLayoutChanges;
+               }
+               void Ol_tableRow_ChildRemove (object sender, ListChangedEventArg e) {
+                       Widget w = e.Element as Widget;
+                       w.LayoutChanged -= onTableRow_ChildLayoutChanges;
+               }
+               void Ol_tableRow_ChildClear (object sender, ListClearEventArg e) {
+                       foreach (Widget w in e.Elements)                                
+                               w.LayoutChanged -= onTableRow_ChildLayoutChanges;
+               }
+               void onTableRow_ChildLayoutChanges (object sender, LayoutingEventArgs arg) {
+                       if (Columns == null)
+                               return;
+                       Widget g = sender as Widget;
+                       TableRow tr = g.Parent as TableRow;
+                       int cIdx = tr.Children.IndexOf (g);
+                       //if (cIdx < Columns.Count && Columns.wi)
+               }
+               void Ol_AddColumn (object sender, ListChangedEventArg e) {
+                       (e.Element as Column).ValueChanged += column_valueChanged;
+                       foreach (TableRow row in Children) {
+                               for (int i = e.Index; i < columns.Count && i < row.Children.Count; i++)
+                                       row.Children[i].Width = columns[i].Width;                                                                                               
+                       }
+                       
+               }
+               void Ol_RemoveColumn (object sender, ListChangedEventArg e) {
+                       (e.Element as Column).ValueChanged -= column_valueChanged;
+                       foreach (TableRow row in Children) {
+                               for (int i = e.Index; i < columns.Count && i < row.Children.Count; i++)
+                                       row.Children[i].Width = columns[i].Width;                                                                                               
+                       }                       
+               }
+
+
+               public override void ChildrenLayoutingConstraints(ILayoutable layoutable, ref LayoutingType layoutType)
+               {
+                       //trigger layouting for width only in the first row, the other will be set at the same horizontal position and width.
+                       if (layoutable == Children[0])
+                               layoutType &= (~LayoutingType.X);       
+                       else
+                               layoutType &= (~(LayoutingType.X|LayoutingType.Width));                 
+               }
+
+               //overriden to prevent search for largest child, all the rows have the same total width.
+               public override void ComputeChildrenPositions () {
+                       int d = 0;
+                       childrenRWLock.EnterReadLock();
+                       foreach (TableRow c in Children) {
+                               if (!c.IsVisible)
+                                       continue;
+                               c.Slot.Y = d;
+                               d += c.Slot.Height + Spacing;
+                       }
+                       childrenRWLock.ExitReadLock();                  
+                       IsDirty = true;
+               }
+/*             public override bool UpdateLayout(LayoutingType layoutType)
+               {
+                       RegisteredLayoutings &= (~layoutType);
+
+                       if (layoutType == LayoutingType.Width) {
+                               //propagate column.width to each row's children
+                       }
+                       return base.UpdateLayout(layoutType);
+               }*/
+       
+               /*public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) {                   
+                       TableRow row = sender as TableRow;
+                       TableRow firstRow = Children[0] as TableRow;
+
+                       if (arg.LayoutType == LayoutingType.Width) {
+                               if (row == firstRow) {
+                                       base.OnChildLayoutChanges (sender, arg);                                                                                
+                                       foreach (TableRow r in Children.Skip(1)) {                                              
+                                               r.contentSize = firstRow.contentSize;
+                                               setChildWidth (r, firstRow.Slot.Width);
+                                       }                                       
+                               }
+                       }
+
+                       base.OnChildLayoutChanges (sender, arg);
+               }*/
+               /*protected override void onDraw (Context gr) {
+                       DbgLogger.StartEvent (DbgEvtType.GODraw, this);
+
+                       base.onDraw (gr);
+
+                       if (Children.Count > 0) {
+
+                               Rectangle cb = ClientRectangle;
+                               TableRow fr = Children[0] as TableRow;
+
+                               
+                               gr.LineWidth = lineWidth;
+                               Foreground.SetAsSource (IFace, gr, cb);                         
+                               CairoHelpers.CairoRectangle (gr, cb, CornerRadius, lineWidth);
+                               double x = 0.5 + cb.Left + fr.Margin + 0.5 * fr.Spacing + fr.Children[0].Slot.Width;                            
+                               for (int i = 1; i < fr.Children.Count ; i++)
+                               {
+                                       gr.MoveTo (x, cb.Y);
+                                       gr.LineTo (x, cb.Bottom);
+                                       x += fr.Spacing + fr.Children[i].Slot.Width ;
+                               }
+
+                               //horizontal lines
+                               x = 0.5 + cb.Top + 0.5 * Spacing + Children[0].Slot.Height;
+                               for (int i = 0; i < Children.Count - 1; i++)
+                               {
+                                       gr.MoveTo (cb.Left, x);
+                                       gr.LineTo (cb.Right, x);
+                                       x += Spacing + Children[i].Slot.Height ;
+                               }
+                               gr.Stroke ();
+                       }
+
+                       DbgLogger.EndEvent (DbgEvtType.GODraw);
+               }*/             
+       }       
+}
index 0beafb561ac29b103c3bafc79460a06362072096..5ddd1af8f34cb0888627e5da3bd5c7f62c7f3fb5 100644 (file)
@@ -22,7 +22,7 @@ namespace Crow
                string caption;
                Measure width = Measure.Fit;
                public int ComputedWidth;
-               public Widget LargestWidget;
+               public Widget LargestChild;
 
                public string Caption {
                        get => caption;
@@ -66,111 +66,306 @@ namespace Crow
                public Table ()  {}
                public Table (Interface iface, string style = null) : base (iface, style) { }
                #endregion
+               int columnSpacing, borderLineWidth, verticalLineWidth, horizontalLineWidth, rowsMargin;
+               ObservableList<Column> columns;
+               HorizontalStack HeaderRow;
+               string headerCellTemplate;
+               IML.Instantiator headerCellITor;
 
-               //int lineWidth;
-               ObservableList<Column> columns = new ObservableList<Column>();
+               [DefaultValue ("#Crow.DefaultTableHeaderCell.template")]
+               public string HeaderCellTemplate {
+                       get => headerCellTemplate;
+                       set {
+                               if (headerCellTemplate == value)
+                                       return;
+                               headerCellTemplate = value;
+                               NotifyValueChangedAuto (headerCellTemplate);
 
+                               headerCellITor = new IML.Instantiator (IFace, HeaderCellTemplate);
+                               createHeaderRow();
+                       }
+               }
+               public override void InsertChild (int idx, Widget g) {
+                       g.Width = Measure.Stretched;
+                       g.Margin = RowsMargin;
+                       base.InsertChild (idx, g);                      
+               }
+               [DefaultValue (2)]
+               public int ColumnSpacing {
+                       get => columnSpacing;
+                       set {
+                               if (columnSpacing == value)
+                                       return;
+                               columnSpacing = value;
+                               NotifyValueChangedAuto (columnSpacing);
+                               if (HeaderRow != null)
+                                       HeaderRow.Spacing = ColumnSpacing;
+                               //RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
+                       }
+               }
+               [DefaultValue (1)]
+               public int BorderLineWidth {
+                       get => borderLineWidth;
+                       set {
+                               if (borderLineWidth == value)
+                                       return;
+                               borderLineWidth = value;
+                               NotifyValueChangedAuto (borderLineWidth);
+                               RegisterForRedraw ();
+                       }
+               }
+               [DefaultValue (1)]
+               public int HorizontalLineWidth {
+                       get => horizontalLineWidth;
+                       set {
+                               if (horizontalLineWidth == value)
+                                       return;
+                               horizontalLineWidth = value;
+                               NotifyValueChangedAuto (horizontalLineWidth);
+                               RegisterForRedraw ();
+                       }
+               }
+               [DefaultValue (1)]
+               public int VerticalLineWidth {
+                       get => verticalLineWidth;
+                       set {
+                               if (verticalLineWidth == value)
+                                       return;
+                               verticalLineWidth = value;
+                               NotifyValueChangedAuto (verticalLineWidth);
+                               RegisterForRedraw ();
+                       }
+               }
+               [DefaultValue (1)]
+               public int RowsMargin {
+                       get => rowsMargin;
+                       set {
+                               if (rowsMargin == value)
+                                       return;
+                               rowsMargin = value;
+                               NotifyValueChangedAuto (rowsMargin);
+                               childrenRWLock.EnterReadLock ();
+                               foreach (Widget row in Children)
+                                       row.Margin = rowsMargin;
+                               childrenRWLock.ExitReadLock ();
+                       }
+               }               
+               //int lineWidth;                
                public ObservableList<Column> Columns {
                        get => columns;
                        set {
                                if (columns == value)
                                        return;
+                               if (columns != null) {
+                                       deleteHeaderRow ();
+                                       columns.ListAdd -= Ol_AddColumn;
+                                       columns.ListAdd -= Ol_RemoveColumn;
+                               }
+
                                columns = value;
+
+                               if (columns != null) {
+                                       createHeaderRow ();                                     
+                                       columns.ListAdd += Ol_AddColumn;
+                                       columns.ListAdd += Ol_RemoveColumn;
+                               }
                                NotifyValueChangedAuto(columns);
                        }
                }
-               public override void AddChild (Widget child) {
-                       TableRow tr = child as TableRow;
-                       if (tr == null)
-                               throw new Exception ("Table widget accept only TableRow as child.");
-                       base.AddChild (child);
+               void deleteHeaderRow () {
+                       if (HeaderRow == null)
+                               return;
+                       DeleteChild (HeaderRow);
+                       HeaderRow = null;
                }
-               /*public override void ChildrenLayoutingConstraints(ILayoutable layoutable, ref LayoutingType layoutType)
+               void createHeaderRow () {
+                       deleteHeaderRow ();
+                       if (Columns == null || headerCellITor == null)
+                               return;
+                       HeaderRow = new HorizontalStack(IFace, "TableHeaderRow") {Spacing = ColumnSpacing};
+                       InsertChild (0, HeaderRow);                     
+                       foreach (Column c in Columns) {
+                               Widget cell = headerCellITor.CreateInstance();
+                               cell.LayoutChanged += onHeaderCell_LayoutChanges;
+                               HeaderRow.AddChild (cell);
+                               cell.DataSource = c;
+                       }
+               }
+               
+               void Ol_AddColumn (object sender, ListChangedEventArg e) {
+                       HeaderRow.InsertChild (e.Index, headerCellITor.CreateInstance());
+                       HeaderRow.DataSource = e.Element;
+               }
+               void Ol_RemoveColumn (object sender, ListChangedEventArg e) {
+                       Widget w = HeaderRow.Children[e.Index];
+                       HeaderRow.RemoveChild (e.Index);
+                       w.Dispose ();
+               }
+               void onHeaderCell_LayoutChanges (object sender, LayoutingEventArgs e) {
+                       if (Columns == null)
+                               return;
+                       if (e.LayoutType == LayoutingType.Width) {
+                               Widget g = sender as Widget;
+                               int cIdx = HeaderRow.Children.IndexOf (g);
+                               if (cIdx < Columns.Count &&  Columns[cIdx].Width.IsFit)
+                                       searchLargestChildInColumn (cIdx);                              
+                               childrenRWLock.EnterReadLock ();
+                               for (int i = 1; i < Children.Count; i++) {
+                                       TableRow row = Children[i] as TableRow;
+                                       if (row.Children.Count <= cIdx)
+                                               continue;
+                                       setRowCellWidth (row.Children[cIdx], g.Slot.Width);
+                               }
+                               childrenRWLock.ExitReadLock ();
+
+                               RegisterForRedraw ();
+                       } else if (e.LayoutType == LayoutingType.X) {
+                               Widget g = sender as Widget;
+                               int cIdx = HeaderRow.Children.IndexOf (g);
+                               childrenRWLock.EnterReadLock ();
+                               for (int i = 1; i < Children.Count; i++) {
+                                       TableRow row = Children[i] as TableRow;
+                                       if (row.Children.Count <= cIdx)
+                                               continue;
+                                       row.Children[cIdx].Slot.X = g.Slot.X;
+                                       row.RegisterForRedraw();
+                               }
+                               childrenRWLock.ExitReadLock ();
+                               RegisterForRedraw ();
+                       }
+               }
+               protected void setRowCellWidth (Widget w, int newW) {
+                       if (newW == w.Slot.Width)
+                               return;
+                       
+                       w.Slot.Width = newW;
+                       w.IsDirty = true;
+                       w.OnLayoutChanges (LayoutingType.Width);
+                       w.LastSlots.Width = w.Slot.Width;
+                       w.RegisterForRedraw ();
+               }               
+
+               public override void ClearChildren()
                {
-                       //trigger layouting for width only in the first row, the other will be set at the same horizontal position and width.
-                       if (layoutable == Children[0])
-                               layoutType &= (~LayoutingType.X);       
-                       else
-                               layoutType &= (~(LayoutingType.X|LayoutingType.Width));                 
-               }*/
-
-               //overriden to prevent search for largest child, all the rows as the same total width.
-               public override void ComputeChildrenPositions () {
-                       int d = 0;
-                       childrenRWLock.EnterReadLock();
-                       foreach (Widget c in Children) {
-                               if (!c.Visible)
+                       base.ClearChildren();
+                       createHeaderRow ();
+               }
+
+               void searchLargestChildInColumn (int cIdx)
+               {
+                       DbgLogger.StartEvent (DbgEvtType.GOSearchLargestChild, this);
+
+                       Column c = Columns[cIdx];
+
+                       childrenRWLock.EnterReadLock ();
+
+                       c.LargestChild = null;
+                       int largestWidth = 0;   
+                       for (int i = 1; i < Children.Count; i++) {
+                               TableRow row = Children[i] as TableRow;
+                               if (!row.IsVisible)
                                        continue;
-                               c.Slot.Y = d;
-                               d += c.Slot.Height + Spacing;
+                               int cw = row.Children [cIdx]. measureRawSize (LayoutingType.Width);
+                               if (cw > largestWidth) {
+                                       largestWidth = cw;
+                                       c.LargestChild = row.Children [cIdx];
+                               }
                        }
-                       childrenRWLock.ExitReadLock();                  
-                       IsDirty = true;
+                       childrenRWLock.ExitReadLock ();
+
+                       if (HeaderRow.Children[cIdx].Slot.Width > largestWidth) {
+                               c.LargestChild = HeaderRow.Children[cIdx];
+                               return;
+                       }
+                       HeaderRow.Children[cIdx].Slot.Width = largestWidth;
+                       //HeaderRow.adjustStretchedGo (LayoutingType.Width);
+
+                       DbgLogger.EndEvent (DbgEvtType.GOSearchLargestChild);
                }
-               public override bool UpdateLayout(LayoutingType layoutType)
+               int splitIndex = -1;            
+               const int minColumnSize = 10;           
+               public override void onMouseMove(object sender, MouseMoveEventArgs e)
                {
-                       RegisteredLayoutings &= (~layoutType);
-
-                       if (layoutType == LayoutingType.Width) {
-                               //propagate column.width to each row's children
-                               foreach (TableRow row in Children) {
-                                       for (int i = 0; i < Columns.Count && i < row.Children.Count; i++) 
-                                               row.Children[i].Width = Columns[i].Width;
-                               }                               
-                       }
-                       return base.UpdateLayout(layoutType);
-               }
-       
-               /*public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) {                   
-                       TableRow row = sender as TableRow;
-                       TableRow firstRow = Children[0] as TableRow;
-
-                       if (arg.LayoutType == LayoutingType.Width) {
-                               if (row == firstRow) {
-                                       base.OnChildLayoutChanges (sender, arg);                                                                                
-                                       foreach (TableRow r in Children.Skip(1)) {                                              
-                                               r.contentSize = firstRow.contentSize;
-                                               setChildWidth (r, firstRow.Slot.Width);
-                                       }                                       
+                       
+                       if (ColumnSpacing > 0 && Columns.Count > 0) {
+                               Point m = ScreenPointToLocal (e.Position);
+                               if (IFace.IsDown (Glfw.MouseButton.Left) && splitIndex >= 0) {                                  
+                                       int splitPos = (int)(0.5 * ColumnSpacing + m.X);                                        
+                                       if (splitPos > HeaderRow.Children[splitIndex].Slot.Left + minColumnSize && splitPos < HeaderRow.Children[splitIndex+1].Slot.Right - minColumnSize) {
+                                               Columns[splitIndex+1].Width = HeaderRow.Children[splitIndex+1].Slot.Right - splitPos;
+                                               splitPos -= ColumnSpacing;
+                                               Columns[splitIndex].Width =  splitPos - HeaderRow.Children[splitIndex].Slot.Left;
+                                               HeaderRow.RegisterForLayouting (LayoutingType.ArrangeChildren);
+                                               e.Handled = true;
+                                       }
+                                       //Console.WriteLine ($"left:{HeaderRow.Children[splitIndex].Slot.Left} right:{HeaderRow.Children[splitIndex+1].Slot.Right} splitPos:{splitPos} m:{m}");                         
+                               } else {
+                                       splitIndex = -1;                                        
+                                       for (int i = 0; i < Columns.Count - 1; i++)
+                                       {
+                                               Rectangle r = HeaderRow.Children[i].Slot;
+                                               if (m.X >= r.Right) {
+                                                       r = HeaderRow.Children[i+1].Slot;
+                                                       if (m.X <= r.Left && Columns.Count - 1 > i ) {
+                                                               IFace.MouseCursor = MouseCursor.sb_h_double_arrow;
+                                                               splitIndex = i;
+                                                               e.Handled = true;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       if (splitIndex < 0 && IFace.MouseCursor == MouseCursor.sb_h_double_arrow)
+                                               IFace.MouseCursor = MouseCursor.top_left_arrow;
                                }
                        }
+                       base.onMouseMove(sender, e);
+               }               
 
-                       base.OnChildLayoutChanges (sender, arg);
-               }*/
-               /*protected override void onDraw (Context gr) {
+
+               protected override void onDraw (Context gr) {
                        DbgLogger.StartEvent (DbgEvtType.GODraw, this);
 
                        base.onDraw (gr);
 
-                       if (Children.Count > 0) {
+                       if (Columns != null && columns.Count > 0 && HeaderRow != null) {
 
                                Rectangle cb = ClientRectangle;
-                               TableRow fr = Children[0] as TableRow;
-
-                               
-                               gr.LineWidth = lineWidth;
-                               Foreground.SetAsSource (IFace, gr, cb);                         
-                               CairoHelpers.CairoRectangle (gr, cb, CornerRadius, lineWidth);
-                               double x = 0.5 + cb.Left + fr.Margin + 0.5 * fr.Spacing + fr.Children[0].Slot.Width;                            
-                               for (int i = 1; i < fr.Children.Count ; i++)
-                               {
-                                       gr.MoveTo (x, cb.Y);
-                                       gr.LineTo (x, cb.Bottom);
-                                       x += fr.Spacing + fr.Children[i].Slot.Width ;
+                                                       
+                               Foreground.SetAsSource (IFace, gr, cb);
+                               if (BorderLineWidth > 0) {
+                                       gr.LineWidth = BorderLineWidth;
+                                       CairoHelpers.CairoRectangle (gr, cb, CornerRadius, borderLineWidth);
+                                       gr.Stroke ();
+                               }
+                               double x = 0;
+                               if (VerticalLineWidth > 0) {
+                                       gr.LineWidth = VerticalLineWidth;
+                                       x = cb.Left + HeaderRow.Margin + 0.5 * ColumnSpacing + HeaderRow.Children[0].Slot.Width;// - 0.5 * VerticalLineWidth;                           
+                                       for (int i = 1; i < HeaderRow.Children.Count ; i++)
+                                       {
+                                               gr.MoveTo (x, cb.Y);
+                                               gr.LineTo (x, cb.Bottom);
+                                               x += columnSpacing + HeaderRow.Children[i].Slot.Width ;
+                                       }
+                                       gr.Stroke ();
                                }
 
-                               //horizontal lines
-                               x = 0.5 + cb.Top + 0.5 * Spacing + Children[0].Slot.Height;
-                               for (int i = 0; i < Children.Count - 1; i++)
-                               {
-                                       gr.MoveTo (cb.Left, x);
-                                       gr.LineTo (cb.Right, x);
-                                       x += Spacing + Children[i].Slot.Height ;
+                               if (HorizontalLineWidth > 0) {
+                                       gr.LineWidth = HorizontalLineWidth;
+                                       x = cb.Top + 0.5 * Spacing + Children[0].Slot.Height;// - 0.5 * HorizontalLineWidth;
+                                       for (int i = 1; i < Children.Count; i++)
+                                       {
+                                               gr.MoveTo (cb.Left, x);
+                                               gr.LineTo (cb.Right, x);
+                                               x += Spacing + Children[i].Slot.Height ;
+                                       }
+                                       gr.Stroke ();
                                }
-                               gr.Stroke ();
+                               
                        }
 
                        DbgLogger.EndEvent (DbgEvtType.GODraw);
-               }*/             
-       }       
+               }                       
+
+       }
 }
diff --git a/Crow/src/Widgets/TableRow copy.cs b/Crow/src/Widgets/TableRow copy.cs
new file mode 100644 (file)
index 0000000..2184d48
--- /dev/null
@@ -0,0 +1,321 @@
+// Copyright (c) 2019-2021  Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.ComponentModel;
+using System.Linq;
+using Crow.Cairo;
+using Glfw;
+
+namespace Crow
+{
+       public class TableRow2 : Group, ISelectable {
+               #region ISelectable implementation
+               bool isSelected;
+               public event EventHandler Selected;
+               public event EventHandler Unselected;
+               [DefaultValue (false)]
+               public virtual bool IsSelected {
+                       get { return isSelected; }
+                       set {
+                               if (isSelected == value)
+                                       return;
+                               isSelected = value;
+
+                               if (isSelected)
+                                       Selected.Raise (this, null);
+                               else
+                                       Unselected.Raise (this, null);
+
+                               NotifyValueChangedAuto (isSelected);
+                       }
+               }
+               #endregion
+
+               public Table Table => Parent as Table;          
+
+               public override void ChildrenLayoutingConstraints(ILayoutable layoutable, ref LayoutingType layoutType)
+               {
+                       //trigger layouting for width only in the first row, the other will be set at the same horizontal position and width.
+                       if (Table == null) {
+                               base.ChildrenLayoutingConstraints (layoutable, ref layoutType);
+                               return;
+                       }
+                       if (this == Table.Children[0])
+                               layoutType &= (~LayoutingType.X);       
+                       else
+                               layoutType &= (~(LayoutingType.X|LayoutingType.Width));                 
+               }
+
+
+               public override void OnLayoutChanges(LayoutingType  layoutType)
+               {
+                       switch (layoutType) {
+                       case LayoutingType.Width:
+                               RegisterForLayouting (LayoutingType.X);
+                               break;
+                       case LayoutingType.Height:
+                               childrenRWLock.EnterReadLock ();
+                               foreach (Widget c in Children.Where (cc => cc.Height.IsRelativeToParent))
+                                       c.RegisterForLayouting (LayoutingType.Height);                          
+                               childrenRWLock.ExitReadLock ();
+                               break;
+                       }
+                       raiseLayoutChanged (layoutType);
+               }
+
+               //all the rows have equal size
+               protected override void searchLargestChild(bool forceMeasure = false) {}
+
+
+
+
+               /*public override void ComputeChildrenPositions () {
+                       if (Children.Count == 0)
+                               return;
+                       int spacing = Table.Spacing;
+                       ObservableList<Column> cols = Table.Columns;
+                                               
+                       Widget first = Children[0];
+                       TableRow firstRow = Table.Children[0] as TableRow;
+
+                       if (firstRow == this) {
+                               base.ComputeChildrenPositions();
+                               return;
+                       }                       
+                       childrenRWLock.EnterReadLock();                 
+                       
+                       for (int i = 0; i < Children.Count && i < firstRow.Children.Count; i++)
+                       {
+                               Widget w = Children[i];
+
+                                       w.Slot.X = firstRow.Children[i].Slot.X;
+                                       setChildWidth (w, firstRow.Children[i].Slot.Width);                             
+                               
+                       }
+
+                       childrenRWLock.ExitReadLock();
+                       IsDirty = true;
+               }*/
+
+
+
+
+
+               /*public override void ComputeChildrenPositions () {
+                       if (Children.Count == 0)
+                               return;
+                       int spacing = Table.Spacing;
+                       ObservableList<Column> cols = Table.Columns;
+                                               
+                       Widget first = Children[0];
+                       TableRow firstRow = Table.Children[0] as TableRow;
+
+                       if (firstRow == this) {
+                               base.ComputeChildrenPositions();
+                               return;
+                       }                       
+                       childrenRWLock.EnterReadLock();                 
+                       
+                       for (int i = 0; i < Children.Count && i < firstRow.Children.Count; i++)
+                       {
+                               Widget w = Children[i];
+
+                                       w.Slot.X = firstRow.Children[i].Slot.X;
+                                       setChildWidth (w, firstRow.Children[i].Slot.Width);                             
+                               
+                       }
+
+                       childrenRWLock.ExitReadLock();
+                       IsDirty = true;
+               }*/
+
+
+
+
+
+               /*public override void ComputeChildrenPositions () {
+                       if (Children.Count == 0)
+                               return;
+                       int spacing = Table.Spacing;
+                       ObservableList<Column> cols = Table.Columns;
+                                               
+                       Widget first = Children[0];
+                       TableRow firstRow = Table.Children[0] as TableRow;
+
+                       if (firstRow == this) {
+                               base.ComputeChildrenPositions();
+                               return;
+                       }                       
+                       childrenRWLock.EnterReadLock();                 
+                       
+                       for (int i = 0; i < Children.Count && i < firstRow.Children.Count; i++)
+                       {
+                               Widget w = Children[i];
+
+                                       w.Slot.X = firstRow.Children[i].Slot.X;
+                                       setChildWidth (w, firstRow.Children[i].Slot.Width);                             
+                               
+                       }
+
+                       childrenRWLock.ExitReadLock();
+                       IsDirty = true;
+               }*/
+
+
+
+
+
+               /*public override void ComputeChildrenPositions () {
+                       if (Children.Count == 0)
+                               return;
+                       int spacing = Table.Spacing;
+                       ObservableList<Column> cols = Table.Columns;
+                                               
+                       Widget first = Children[0];
+                       TableRow firstRow = Table.Children[0] as TableRow;
+
+                       if (firstRow == this) {
+                               base.ComputeChildrenPositions();
+                               return;
+                       }                       
+                       childrenRWLock.EnterReadLock();                 
+                       
+                       for (int i = 0; i < Children.Count && i < firstRow.Children.Count; i++)
+                       {
+                               Widget w = Children[i];
+
+                                       w.Slot.X = firstRow.Children[i].Slot.X;
+                                       setChildWidth (w, firstRow.Children[i].Slot.Width);                             
+                               
+                       }
+
+                       childrenRWLock.ExitReadLock();
+                       IsDirty = true;
+               }*/
+               
+               /*public override bool UpdateLayout(LayoutingType layoutType)
+               {
+                       RegisteredLayoutings &= (~layoutType);
+
+                       if (Table == null)
+                               return false;
+                       TableRow firstRow = Table.Children[0] as TableRow;
+                       if (layoutType == LayoutingType.Width) {
+                               if (firstRow.RegisteredLayoutings.HasFlag (LayoutingType.Width))
+                                       return false;
+                               if (this != firstRow) {                                 
+                                       Slot.Width = firstRow.Slot.Width;
+                                       if (Slot.Width != LastSlots.Width) {
+                                               IsDirty = true;
+                                               OnLayoutChanges (layoutType);
+                                               LastSlots.Width = Slot.Width;
+                                       }
+                                       if (RegisteredLayoutings == LayoutingType.None && IsDirty)
+                                               IFace.EnqueueForRepaint (this);
+
+                                       return true;
+                               }
+                       }
+                       
+                       return base.UpdateLayout(layoutType);
+               }*/
+               /*public override int measureRawSize (LayoutingType lt) {
+                       if (lt == LayoutingType.Width) {
+                               if (Table == null)
+                                       return -1;
+                               TableRow firstRow = Table.Children[0] as TableRow;                              
+                               if (this != firstRow) {
+                                       if (firstRow.RegisteredLayoutings.HasFlag (LayoutingType.Width))
+                                               return -1;
+                                       contentSize = firstRow.contentSize;
+                                       return firstRow.measureRawSize (lt);
+                               }
+
+                       }
+                       return base.measureRawSize (lt);
+               }*/
+               /*public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) {
+                       if (arg.LayoutType == LayoutingType.Width) {
+                               Widget w = sender as Widget;
+                               TableRow firstRow = Table.Children[0] as TableRow;
+                               int c = Children.IndexOf(w);                            
+                               if (c < Table.Columns.Count) {
+                                       Column col = Table.Columns[c];
+                                       if (col.Width.IsFit) {
+                                               if (col.LargestWidget == null || w.Slot.Width > col.ComputedWidth) {
+                                                       col.ComputedWidth = w.Slot.Width;
+                                                       col.LargestWidget = w;
+                                               } else if (w == col.LargestWidget)
+                                                       Console.WriteLine ("must search for largest widget");
+                                       }else if (w == firstRow)
+                                               col.ComputedWidth = w.Slot.Width;
+
+                               }
+                               Console.WriteLine ($"ROW:{Table.Children.IndexOf(this)} COL:{c} {w.LastSlots.Width} -> {w.Slot.Width} ");
+                       }
+                       base.OnChildLayoutChanges (sender, arg);
+               }*/
+               /*public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) {
+                       Widget go = sender as Widget;
+                       TableRow row = go.Parent as TableRow;
+                       TableRow firstRow = Table.Children[0] as TableRow;
+
+                       if (arg.LayoutType == LayoutingType.Width) {
+                               if (row == firstRow) {
+                                       base.OnChildLayoutChanges (sender, arg);
+                                       int idx = Children.IndexOf (go);                                        
+                                       foreach (TableRow r in Table.Children.Skip(1)) {
+                                               if (idx < r.Children.Count)
+                                                       r.setChildWidth (r.Children[idx], go.Slot.Width);
+                                               r.contentSize = firstRow.contentSize;
+                                       }                                       
+                               } //else
+                                       this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+                               return;
+                       }
+
+                       base.OnChildLayoutChanges (sender, arg);
+               }*/
+               int splitIndex = -1;            
+               const int minColumnSize = 10;
+               int Spacing => Table.Spacing;
+               public override void onMouseMove(object sender, MouseMoveEventArgs e)
+               {                       
+                       if (Spacing > 0 && Table != null && Table.Children.Count > 0) {
+                               Point m = ScreenPointToLocal (e.Position);
+                               if (IFace.IsDown (Glfw.MouseButton.Left) && splitIndex >= 0) {
+                                       TableRow firstRow = Table.Children[0] as TableRow;
+                                       Rectangle cb = ClientRectangle;
+                                       int splitPos = (int)(0.5 * Spacing + m.X);                                      
+                                       if (splitPos > firstRow.Children[splitIndex].Slot.Left + minColumnSize && splitPos < firstRow.Children[splitIndex+1].Slot.Right - minColumnSize) {
+                                               Table.Columns[splitIndex+1].Width = firstRow.Children[splitIndex+1].Slot.Right - splitPos;
+                                               splitPos -= Spacing;
+                                               Table.Columns[splitIndex].Width = splitPos - firstRow.Children[splitIndex].Slot.Left;
+                                               Table.RegisterForLayouting (LayoutingType.Width);
+                                               e.Handled = true;
+                                       }
+                                       //Console.WriteLine ($"left:{firstRow.Children[splitIndex].Slot.Left} right:{firstRow.Children[splitIndex+1].Slot.Right} cb.X:{cb.X} splitPos:{splitPos} m:{m}");                               
+                               } else {
+                                       splitIndex = -1;                                        
+                                       for (int i = 0; i < Children.Count - 1; i++)
+                                       {
+                                               Rectangle r = Children[i].Slot;
+                                               if (m.X >= r.Right) {
+                                                       r = Children[i+1].Slot;
+                                                       if (m.X <= r.Left && Table.Columns.Count - 1 > i ) {
+                                                               IFace.MouseCursor = MouseCursor.sb_h_double_arrow;
+                                                               splitIndex = i;
+                                                               e.Handled = true;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       if (splitIndex < 0 && IFace.MouseCursor == MouseCursor.sb_h_double_arrow)
+                                               IFace.MouseCursor = MouseCursor.top_left_arrow;
+                               }
+                       }
+                       base.onMouseMove(sender, e);
+               }
+       }
+}
index dbb076619ac8d3809c7b5effa998c835a1b032bf..1ce02c1550c49b593f3e387680efcce00869c576 100644 (file)
@@ -9,13 +9,11 @@ using Glfw;
 
 namespace Crow
 {
-       public class TableRow : HorizontalStack, ISelectable {
+       public class TableRow : GroupBase, ISelectable {
                #region ISelectable implementation
                bool isSelected;
-
                public event EventHandler Selected;
                public event EventHandler Unselected;
-
                [DefaultValue (false)]
                public virtual bool IsSelected {
                        get { return isSelected; }
@@ -33,173 +31,157 @@ namespace Crow
                        }
                }
                #endregion
-
-               public Table Table => Parent as Table;          
-
-               /*public override void ChildrenLayoutingConstraints(ILayoutable layoutable, ref LayoutingType layoutType)
-               {
-                       //trigger layouting for width only in the first row, the other will be set at the same horizontal position and width.
-                       if (Table == null) {
-                               base.ChildrenLayoutingConstraints (layoutable, ref layoutType);
+               #region EVENT HANDLERS
+               public event EventHandler<EventArgs> ChildrenCleared;
+               #endregion
+               public override void ChildrenLayoutingConstraints(ILayoutable layoutable, ref LayoutingType layoutType)
+                       => layoutType &= (~(LayoutingType.X|LayoutingType.Width));              
+
+               public Table Table => Parent as Table;
+               internal Widget tallestChild = null;
+               public override void InsertChild (int idx, Widget g) {
+                       if (disposed) {
+                               DbgLogger.AddEvent (DbgEvtType.AlreadyDisposed | DbgEvtType.GOAddChild);
                                return;
                        }
-                       if (this == Table.Children[0])
-                               layoutType &= (~LayoutingType.X);       
-                       else
-                               layoutType &= (~(LayoutingType.X|LayoutingType.Width));                 
-               }*/
-
-               public override void ComputeChildrenPositions () {
-                       if (Children.Count == 0)
-                               return;
-                       int spacing = Table.Spacing;
-                       ObservableList<Column> cols = Table.Columns;
-                                               
-                       Widget first = Children[0];
-                       TableRow firstRow = Table.Children[0] as TableRow;
-
-                       if (firstRow == this) {
-                               base.ComputeChildrenPositions();
-                               return;
-                       }                       
-                       childrenRWLock.EnterReadLock();                 
+                       childrenRWLock.EnterWriteLock ();
+                               
+                       g.Parent = this;
+                       Children.Insert (idx, g);
                        
-                       for (int i = 0; i < Children.Count && i < firstRow.Children.Count; i++)
-                       {
-                               Widget w = Children[i];
-                               /*if (i < cols.Count && cols[i].Width.IsFit && cols[i].LargestWidget != null) {
-                                       w.Slot.X
-                               }else{*/
-                                       w.Slot.X = firstRow.Children[i].Slot.X;
-                                       setChildWidth (w, firstRow.Children[i].Slot.Width);                             
-                               //}
+                       childrenRWLock.ExitWriteLock ();
+
+                       if (g.LastSlots.Height > contentSize.Height) {
+                               tallestChild = g;
+                               contentSize.Height = g.LastSlots.Height;
                        }
 
-                       childrenRWLock.ExitReadLock();
-                       IsDirty = true;
+                       
+                       g.LayoutChanged += OnChildLayoutChanges;
+                       g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
                }
-               
-               public override bool UpdateLayout(LayoutingType layoutType)
+               public override void RemoveChild(Widget child)
                {
-                       RegisteredLayoutings &= (~layoutType);
-
-                       if (Table == null)
-                               return false;
-                       TableRow firstRow = Table.Children[0] as TableRow;
-                       if (layoutType == LayoutingType.Width) {
-                               if (firstRow.RegisteredLayoutings.HasFlag (LayoutingType.Width))
-                                       return false;
-                               if (this != firstRow) {                                 
-                                       Slot.Width = firstRow.Slot.Width;
-                                       if (Slot.Width != LastSlots.Width) {
-                                               IsDirty = true;
-                                               OnLayoutChanges (layoutType);
-                                               LastSlots.Width = Slot.Width;
-                                       }
-                                       if (RegisteredLayoutings == LayoutingType.None && IsDirty)
-                                               IFace.EnqueueForRepaint (this);
-
-                                       return true;
-                               }
+                       child.LayoutChanged -= OnChildLayoutChanges;
+                       //check if HoverWidget is removed from Tree
+                       if (IFace.HoverWidget != null) {
+                               if (this.Contains (IFace.HoverWidget))
+                                       IFace.HoverWidget = null;
                        }
-                       
-                       return base.UpdateLayout(layoutType);
+
+                       childrenRWLock.EnterWriteLock ();
+
+                       Children.Remove(child);
+                       child.Parent = null;
+                       child.LogicalParent = null;
+
+                       childrenRWLock.ExitWriteLock ();
+
+                       if (child == tallestChild && Height == Measure.Fit)
+                               searchTallestChild ();
+
+                       this.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
+
                }
-               /*public override int measureRawSize (LayoutingType lt) {
-                       if (lt == LayoutingType.Width) {
-                               if (Table == null)
-                                       return -1;
-                               TableRow firstRow = Table.Children[0] as TableRow;                              
-                               if (this != firstRow) {
-                                       if (firstRow.RegisteredLayoutings.HasFlag (LayoutingType.Width))
-                                               return -1;
-                                       contentSize = firstRow.contentSize;
-                                       return firstRow.measureRawSize (lt);
-                               }
+               public override void ClearChildren()
+               {
+                       childrenRWLock.EnterWriteLock ();
 
+                       while (Children.Count > 0) {
+                               Widget g = Children [Children.Count - 1];
+                               g.LayoutChanged -= OnChildLayoutChanges;
+                               Children.RemoveAt (Children.Count - 1);
+                               g.Dispose ();
                        }
-                       return base.measureRawSize (lt);
-               }*/
-               /*public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) {
-                       if (arg.LayoutType == LayoutingType.Width) {
-                               Widget w = sender as Widget;
-                               TableRow firstRow = Table.Children[0] as TableRow;
-                               int c = Children.IndexOf(w);                            
-                               if (c < Table.Columns.Count) {
-                                       Column col = Table.Columns[c];
-                                       if (col.Width.IsFit) {
-                                               if (col.LargestWidget == null || w.Slot.Width > col.ComputedWidth) {
-                                                       col.ComputedWidth = w.Slot.Width;
-                                                       col.LargestWidget = w;
-                                               } else if (w == col.LargestWidget)
-                                                       Console.WriteLine ("must search for largest widget");
-                                       }else if (w == firstRow)
-                                               col.ComputedWidth = w.Slot.Width;
 
+                       childrenRWLock.ExitWriteLock ();
+
+                       resetChildrenMaxSize ();
+
+                       RegisterForLayouting (LayoutingType.Sizing);
+                       ChildrenCleared.Raise (this, new EventArgs ());
+               }
+               public override int measureRawSize (LayoutingType lt)
+               {
+                       if (lt == LayoutingType.Height && Children.Count > 0 && tallestChild == null)
+                               searchTallestChild ();                                  
+                       return base.measureRawSize (lt);
+               }               
+               public override void OnLayoutChanges (LayoutingType layoutType)
+               {
+                       base.OnLayoutChanges (layoutType);
+
+                       childrenRWLock.EnterReadLock ();
+                       //position smaller objects in group when group size is fit
+                       switch (layoutType) {
+                       case LayoutingType.Height:
+                               childrenRWLock.EnterReadLock ();
+                               foreach (Widget c in Children) {
+                                       if (c.Height.IsRelativeToParent)
+                                               c.RegisterForLayouting (LayoutingType.Height);
+                                       else
+                                               c.RegisterForLayouting (LayoutingType.Y);
                                }
-                               Console.WriteLine ($"ROW:{Table.Children.IndexOf(this)} COL:{c} {w.LastSlots.Width} -> {w.Slot.Width} ");
+                               childrenRWLock.ExitReadLock ();
+                               break;
                        }
-                       base.OnChildLayoutChanges (sender, arg);
-               }*/
-               /*public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) {
-                       Widget go = sender as Widget;
-                       TableRow row = go.Parent as TableRow;
-                       TableRow firstRow = Table.Children[0] as TableRow;
-
-                       if (arg.LayoutType == LayoutingType.Width) {
-                               if (row == firstRow) {
-                                       base.OnChildLayoutChanges (sender, arg);
-                                       int idx = Children.IndexOf (go);                                        
-                                       foreach (TableRow r in Table.Children.Skip(1)) {
-                                               if (idx < r.Children.Count)
-                                                       r.setChildWidth (r.Children[idx], go.Slot.Width);
-                                               r.contentSize = firstRow.contentSize;
-                                       }                                       
-                               } //else
-                                       this.RegisterForLayouting (LayoutingType.ArrangeChildren);
-                               return;
+                       childrenRWLock.ExitReadLock ();
+               }               
+               public virtual void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
+               {
+                       DbgLogger.StartEvent(DbgEvtType.GOOnChildLayoutChange, this);
+
+                       Widget g = sender as Widget;
+
+                       switch (arg.LayoutType) {
+                       case LayoutingType.Height:
+                               if (Height == Measure.Fit) {
+                                       if (g.Slot.Height > contentSize.Height) {
+                                               tallestChild = g;
+                                               contentSize.Height = g.Slot.Height;
+                                       } else if (g == tallestChild)
+                                               searchTallestChild ();
+                                       else
+                                               break;
+                                       this.RegisterForLayouting (LayoutingType.Height);
+                               }
+                               break;
                        }
-
-                       base.OnChildLayoutChanges (sender, arg);
-               }*/
-               int splitIndex = -1;            
-               const int minColumnSize = 10;
-               public override void onMouseMove(object sender, MouseMoveEventArgs e)
-               {                       
-                       if (Spacing > 0 && Table != null && Table.Children.Count > 0) {
-                               Point m = ScreenPointToLocal (e.Position);
-                               if (IFace.IsDown (Glfw.MouseButton.Left) && splitIndex >= 0) {
-                                       TableRow firstRow = Table.Children[0] as TableRow;
-                                       Rectangle cb = ClientRectangle;
-                                       int splitPos = (int)(0.5 * Spacing + m.X);                                      
-                                       if (splitPos > firstRow.Children[splitIndex].Slot.Left + minColumnSize && splitPos < firstRow.Children[splitIndex+1].Slot.Right - minColumnSize) {
-                                               Table.Columns[splitIndex+1].Width = firstRow.Children[splitIndex+1].Slot.Right - splitPos;
-                                               splitPos -= Spacing;
-                                               Table.Columns[splitIndex].Width = splitPos - firstRow.Children[splitIndex].Slot.Left;
-                                               Table.RegisterForLayouting (LayoutingType.Width);
-                                               e.Handled = true;
-                                       }
-                                       //Console.WriteLine ($"left:{firstRow.Children[splitIndex].Slot.Left} right:{firstRow.Children[splitIndex+1].Slot.Right} cb.X:{cb.X} splitPos:{splitPos} m:{m}");                               
-                               } else {
-                                       splitIndex = -1;                                        
-                                       for (int i = 0; i < Children.Count - 1; i++)
-                                       {
-                                               Rectangle r = Children[i].Slot;
-                                               if (m.X >= r.Right) {
-                                                       r = Children[i+1].Slot;
-                                                       if (m.X <= r.Left && Table.Columns.Count - 1 > i ) {
-                                                               IFace.MouseCursor = MouseCursor.sb_h_double_arrow;
-                                                               splitIndex = i;
-                                                               e.Handled = true;
-                                                               break;
-                                                       }
-                                               }
-                                       }
-                                       if (splitIndex < 0 && IFace.MouseCursor == MouseCursor.sb_h_double_arrow)
-                                               IFace.MouseCursor = MouseCursor.top_left_arrow;
+                       DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
+               }
+               protected virtual void searchTallestChild (bool forceMeasure = false)
+               {
+                       DbgLogger.StartEvent (DbgEvtType.GOSearchTallestChild, this);
+
+                       childrenRWLock.EnterReadLock ();
+
+                       tallestChild = null;
+                       contentSize.Height = 0;
+                       for (int i = 0; i < Children.Count; i++) {
+                               if (!Children [i].IsVisible)
+                                       continue;
+                               int ch = 0;
+                               if (forceMeasure)
+                                       ch = Children [i].measureRawSize (LayoutingType.Height);
+                               else if (Children [i].RegisteredLayoutings.HasFlag (LayoutingType.Height))
+                                       continue;
+                               else
+                                       ch = Children [i].Slot.Height;
+                               if (ch > contentSize.Height) {
+                                       contentSize.Height = ch;
+                                       tallestChild = Children [i];
                                }
                        }
-                       base.onMouseMove(sender, e);
+                       if (tallestChild == null && !forceMeasure)
+                               searchTallestChild (true);
+
+                       childrenRWLock.ExitReadLock ();
+
+                       DbgLogger.EndEvent (DbgEvtType.GOSearchTallestChild);
+               }
+               void resetChildrenMaxSize(){
+                       tallestChild = null;
+                       contentSize = 0;
                }
        }
 }
index 47ac67f53ec8ae5192ee21785c93e0b8749feebc..9f3f47810dec000547c9c87b52901e67f7d8bfdd 100644 (file)
@@ -911,18 +911,18 @@ namespace Crow
                                if (value == isVisible)
                                        return;
 
-                               isVisible = value;
+                               isVisible = value;                              
                                
-                               if (!isVisible)
+                               /*if (!isVisible)
                                        unshownPostActions ();
-                               RegisterForLayouting (LayoutingType.Sizing);
-                               
-                               /*if (isVisible){                                                                               
+                               RegisterForLayouting (LayoutingType.Sizing);*/
+
+                               if (isVisible){                                                                         
                                        IsDirty = true;
-                                       RegisterForLayouting(LayoutingType.Sizing);
                                } else {
                                        unshownPostActions ();                                  
-                               }*/
+                               }
+                               RegisterForLayouting(LayoutingType.Sizing);
                                
 
                                NotifyValueChangedAuto (isVisible);
@@ -1641,9 +1641,9 @@ namespace Crow
                        if (LayoutChanged != null)
                                LayoutChanged.Invoke (this, new LayoutingEventArgs (layoutType));
                }
-               internal protected void raiseLayoutChanged(LayoutingEventArgs e){
+               internal protected void raiseLayoutChanged(LayoutingType layoutingType){
                        if (LayoutChanged != null)
-                               LayoutChanged.Raise (this, e);
+                               LayoutChanged.Raise (this, new LayoutingEventArgs(layoutingType));
                }
                /// <summary> Update layout component only one at a time, this is where the computation of alignement
                /// and size take place.
@@ -1834,6 +1834,7 @@ namespace Crow
                        DbgLogger.EndEvent (DbgEvtType.GORecreateCache);
                }
                protected void paintCache(Context ctx, Rectangle rb) {
+                       DbgLogger.StartEvent(DbgEvtType.GOPaintCache, this);    
                        if (clearBackground) {
                                ctx.Operator = Operator.Clear;
                                ctx.Rectangle (rb);
@@ -1843,10 +1844,12 @@ namespace Crow
 
                        ctx.SetSource (bmp, rb.X, rb.Y);
                        ctx.Paint ();
+                       DbgLogger.EndEvent(DbgEvtType.GOPaintCache);    
                }
                protected virtual void UpdateCache(Context ctx){
                        DbgLogger.StartEvent(DbgEvtType.GOUpdateCache, this);                   
                        paintCache (ctx, Slot + Parent.ClientRectangle.Position);
+                       DbgLogger.AddEvent (DbgEvtType.GOResetClip, this);
                        Clipping.Reset ();                      
                        DbgLogger.EndEvent (DbgEvtType.GOUpdateCache);
                }
@@ -1854,8 +1857,8 @@ namespace Crow
                /// of the widget </summary>
                public virtual void Paint (Context ctx)
                {
-                       if (!IsVisible)
-                               return;
+                       /*if (!IsVisible)
+                               return;*/
 
                        DbgLogger.StartEvent (DbgEvtType.GOPaint, this);
 
@@ -2146,19 +2149,19 @@ namespace Crow
                /// Checks to handle when widget is removed from the visible graphic tree
                /// </summary>
                void unshownPostActions () {
-                       //IsDirty = true;
+                       IsDirty = true;                 
 
                        /*if (parent is Widget p)
                                p.RegisterForGraphicUpdate();
                        else*/
-                       /*try
+                       try
                        {
                                parent?.RegisterClip (ContextCoordinates(LastPaintedSlot));
                        }
                        catch (System.Exception e)
                        {
                                Debug.WriteLine($"[ERR]:unshownPostActions:{e}");
-                       }*/
+                       }
                                
 
                        if (IFace.ActiveWidget != null) {
@@ -2199,7 +2202,7 @@ namespace Crow
                        }
                        LastSlots = default;
                        LastPaintedSlot = default;*/
-                       
+                       //Slot = LastSlots = default;                   
                }
        }
 }