[banshee/grid] [DataView] inching closer to world domination



commit bde373f5c09e57d7ea93bbfaa7f4b983a1f222c2
Author: Aaron Bockover <abockover novell com>
Date:   Fri Jan 22 18:27:58 2010 -0500

    [DataView] inching closer to world domination
    
    This chunk-o-work obsoletes the old ColumnCell stateless renderers
    and dependency on a ColumnController (which will eventually be
    moved internally to the the list layout).
    
    Instead I introduce the DataViewChild, which is more like a widget:
    
      - it holds a real allocation
      - it holds its bound model object
      - it can hold arbitrary internal state
    
    Since these layout children hold real state, awful hacks need not
    be employed for doing things like interaction or even animation.
    
    Similarly, awful hacks are not needed at the view interaction level
    to proxy proper input events to the layout children. This greatly
    simplifies the interaction code. Also, since a layout child knows
    its allocation at all times, it can request to be redrawn, so this
    is less work the view needs to do.
    
    ColumnCellAlbum has been ported to the new DataViewChild API. Next
    up will be animating this beast. Yes.
    
    Finally, DataViewLayoutGrid has a new ChildAllocator property that
    must be assigned to. This is a function that returns an instance
    of a DataViewChild. Alternatively, if subclassing DataViewLayoutGrid,
    the virtual CreateChild method may be overridden. This eliminates
    the need for AlbumListView to provide a subclassed DataViewLayoutGrid
    just to specify its children:
    
     +            ViewLayout = new DataViewLayoutGrid () {
     +                ChildAllocator = () => new DataViewChildAlbum (),
     +                View = this
     +            };
    
    Keep cool my babies!

 .../Banshee.Collection.Gui/AlbumListView.cs        |   28 +----
 .../Banshee.Collection.Gui/ColumnCellAlbum.cs      |   53 +++----
 .../Hyena.Gui/Hyena.Data.Gui/CellContext.cs        |    1 +
 .../Hyena.Gui/Hyena.Data.Gui/DataViewChild.cs      |  146 ++++++++++++++++++++
 .../Hyena.Gui/Hyena.Data.Gui/DataViewLayout.cs     |   31 +----
 .../Hyena.Gui/Hyena.Data.Gui/DataViewLayoutGrid.cs |   31 ++++-
 .../ListView/ListView_Interaction.cs               |  104 ++++++++++----
 .../Hyena.Data.Gui/ListView/ListView_Rendering.cs  |   13 ++-
 src/Libraries/Hyena.Gui/Hyena.Gui.csproj           |    1 +
 src/Libraries/Hyena.Gui/Makefile.am                |    3 +-
 10 files changed, 300 insertions(+), 111 deletions(-)
---
diff --git a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/AlbumListView.cs b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/AlbumListView.cs
index a22aab3..1827402 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/AlbumListView.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/AlbumListView.cs
@@ -38,34 +38,14 @@ using Banshee.Gui;
 
 namespace Banshee.Collection.Gui
 {
-    // FIXME: Renderers and the column controller will move into
-    // DataViewLayout, so this subclass will be unnecessary
-    public class AlbumViewGridLayout : DataViewLayoutGrid
-    {
-        public ColumnCellAlbum Renderer { get; private set; }
-
-        public AlbumViewGridLayout (AlbumListView view)
-        {
-            View = view;
-            Renderer = new ColumnCellAlbum () { ViewLayout = this };
-        }
-
-        protected override void InvalidateChildSize ()
-        {
-            ChildSize = Renderer.Measure (View);
-        }
-    }
-
     public class AlbumListView : TrackFilterListView<AlbumInfo>
     {
-        private AlbumViewGridLayout view_layout;
-
         public AlbumListView () : base ()
         {
-            ViewLayout = view_layout = new AlbumViewGridLayout (this);
-
-            column_controller.Add (new Column ("Album", view_layout.Renderer, 1.0));
-            ColumnController = column_controller;
+            ViewLayout = new DataViewLayoutGrid () {
+                ChildAllocator = () => new DataViewChildAlbum (),
+                View = this
+            };
 
             ServiceManager.PlayerEngine.ConnectEvent (OnPlayerEvent, PlayerEvent.TrackInfoUpdated);
         }
diff --git a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs
index f2fd347..96b01b7 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs
@@ -40,10 +40,10 @@ using Banshee.ServiceStack;
 
 namespace Banshee.Collection.Gui
 {
-    public class ColumnCellAlbum : ColumnCell, IInteractiveCell
+    public class DataViewChildAlbum : DataViewChild
     {
         private ArtworkManager artwork_manager;
-        private object hover_object;
+        private bool is_prelit;
 
         public double PaddingX { get; set; }
         public double PaddingY { get; set; }
@@ -54,10 +54,10 @@ namespace Banshee.Collection.Gui
         private bool IsGridLayout {
             // FIXME: Cache this after implementing virtual notification
             // on ColumnCell that ViewLayout has changed ...
-            get { return ViewLayout is AlbumViewGridLayout; }
+            get { return ParentLayout is DataViewLayoutGrid; }
         }
 
-        public ColumnCellAlbum () : base (null, true)
+        public DataViewChildAlbum ()
         {
             artwork_manager = ServiceManager.Get<ArtworkManager> ();
 
@@ -72,7 +72,7 @@ namespace Banshee.Collection.Gui
             TextSpacing = -2;
         }
 
-        public override void Render (CellContext context, StateType state, double cellWidth, double cellHeight)
+        public override void Render (CellContext context)
         {
             double x = 0;
             double y = 0;
@@ -97,15 +97,15 @@ namespace Banshee.Collection.Gui
             }
 
             if (IsGridLayout) {
-                x = Math.Round ((cellWidth - 2 * PaddingX - width) / 2.0);
+                x = Math.Round ((Allocation.Width - 2 * PaddingX - width) / 2.0);
             } else {
-                y = Math.Round ((cellHeight - 2 * PaddingY - height) / 2.0);
+                y = Math.Round ((Allocation.Height - 2 * PaddingY - height) / 2.0);
             }
 
             RenderImageSurface (context, new Rectangle (x, y, width, height), image_surface);
 
             // Render the overlay
-            if (IsGridLayout && hover_object == BoundObject) {
+            if (IsGridLayout && is_prelit) {
                 var cr = context.Context;
                 var grad = new RadialGradient (5, 5, (width + height) / 2.0, 5, 5, 0);
                 grad.AddColorStop (0, new Color (0, 0, 0, 0.65));
@@ -141,7 +141,7 @@ namespace Banshee.Collection.Gui
 
             // Render the text
             int fl_width = 0, fl_height = 0, sl_width = 0, sl_height = 0;
-            Cairo.Color text_color = context.Theme.Colors.GetWidgetColor (GtkColorClass.Text, state);
+            Cairo.Color text_color = context.Theme.Colors.GetWidgetColor (GtkColorClass.Text, context.State);
             text_color.A = 0.75;
 
             var layout = context.Layout;
@@ -149,8 +149,8 @@ namespace Banshee.Collection.Gui
             layout.FontDescription.Weight = Pango.Weight.Bold;
 
             layout.Width = (int)((IsGridLayout
-                ? cellWidth - 2 * PaddingX
-                : cellWidth - ImageSize - ImageSpacing - 2 * PaddingX) * Pango.Scale.PangoScale);
+                ? Allocation.Width - 2 * PaddingX
+                : Allocation.Height - ImageSize - ImageSpacing - 2 * PaddingX) * Pango.Scale.PangoScale);
 
             // Compute the layout sizes for both lines for centering on the cell
             int old_size = layout.FontDescription.Size;
@@ -171,7 +171,7 @@ namespace Banshee.Collection.Gui
                 y = ImageSize + ImageSpacing;
             } else {
                 x = ImageSize + ImageSpacing;
-                y = Math.Round ((cellHeight - fl_height + sl_height) / 2);
+                y = Math.Round (((double)Allocation.Height - fl_height + sl_height) / 2);
             }
 
             // Render the second line first since we have that state already
@@ -195,9 +195,10 @@ namespace Banshee.Collection.Gui
             PangoCairoHelper.ShowLayout (context.Context, layout);
         }
 
-        public override Gdk.Size Measure (Widget widget)
+        public override Gdk.Size Measure ()
         {
             int text_height = 0;
+            var widget = ParentLayout.View;
 
             using (var layout = new Pango.Layout (widget.PangoContext) {
                 FontDescription = widget.PangoContext.FontDescription.Copy () }) {
@@ -213,7 +214,7 @@ namespace Banshee.Collection.Gui
 
             double width, height;
 
-            if (ViewLayout is AlbumViewGridLayout) {
+            if (IsGridLayout) {
                 width = ImageSize + 2 * PaddingX;
                 height = ImageSize + ImageSpacing + TextSpacing + text_height + 2 * PaddingY;
             } else {
@@ -256,28 +257,19 @@ namespace Banshee.Collection.Gui
             return true;
         }
 
-#region IInteractiveCell
-
-        public bool ButtonEvent (int x, int y, bool pressed, Gdk.EventButton evnt)
-        {
-            return false;
-        }
-
-        public bool MotionEvent (int x, int y, Gdk.EventMotion evnt)
+        public override void CursorEnterEvent ()
         {
-            var redraw = hover_object != BoundObject;
-            hover_object = BoundObject;
-            return redraw;
+            is_prelit = true;
+            this.ParentLayout.View.QueueDraw ();
         }
 
-        public bool PointerLeaveEvent ()
+        public override void CursorLeaveEvent ()
         {
-            hover_object = null;
-            return true;
+            is_prelit = false;
+            this.ParentLayout.View.QueueDraw ();
         }
 
-#endregion
-
+#if false
 #region Accessibility
 
         private class ColumnCellAlbumAccessible : ColumnCellAccessible
@@ -296,6 +288,7 @@ namespace Banshee.Collection.Gui
         }
 
 #endregion
+#endif
 
     }
 }
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/CellContext.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/CellContext.cs
index 253d5b2..8927060 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/CellContext.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/CellContext.cs
@@ -42,6 +42,7 @@ namespace Hyena.Data.Gui
         public Cairo.Context Context { get; set; }
         public Pango.Layout Layout { get; set; }
         public Gtk.Widget Widget { get; set; }
+        public Gtk.StateType State { get; set; }
         public Gdk.Drawable Drawable { get; set; }
         public Theme Theme { get; set; }
         public Gdk.Rectangle Area { get; set; }
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewChild.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewChild.cs
new file mode 100644
index 0000000..07b2cef
--- /dev/null
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewChild.cs
@@ -0,0 +1,146 @@
+//
+// DataViewChild.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright 2010 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Reflection;
+
+using Cairo;
+
+namespace Hyena.Data.Gui
+{
+    public abstract class DataViewChild : CanvasItem
+    {
+        public DataViewLayout ParentLayout { get; set; }
+        public int ModelRowIndex { get; set; }
+
+#region Data Binding
+
+        private PropertyInfo property_info;
+        private PropertyInfo sub_property_info;
+
+        public void BindDataItem (object item)
+        {
+            if (item == null) {
+                BoundObjectParent = null;
+                bound_object = null;
+                return;
+            }
+
+            BoundObjectParent = item;
+
+            if (Property != null) {
+                EnsurePropertyInfo (Property, ref property_info, BoundObjectParent);
+                bound_object = property_info.GetValue (BoundObjectParent, null);
+
+                if (SubProperty != null) {
+                    EnsurePropertyInfo (SubProperty, ref sub_property_info, bound_object);
+                    bound_object = sub_property_info.GetValue (bound_object, null);
+                }
+            } else {
+                bound_object = BoundObjectParent;
+            }
+        }
+
+        private void EnsurePropertyInfo (string name, ref PropertyInfo prop, object obj)
+        {
+            if (prop == null || prop.ReflectedType != obj.GetType ()) {
+                prop = obj.GetType ().GetProperty (name);
+                if (prop == null) {
+                    throw new Exception (String.Format (
+                        "In {0}, type {1} does not have property {2}",
+                        this, obj.GetType (), name));
+                }
+            }
+        }
+
+        protected Type BoundType {
+            get { return bound_object.GetType (); }
+        }
+
+        private object bound_object;
+        protected object BoundObject {
+            get { return bound_object; }
+            set {
+                if (Property != null) {
+                    EnsurePropertyInfo (Property, ref property_info, BoundObjectParent);
+                    property_info.SetValue (BoundObjectParent, value, null);
+                }
+            }
+        }
+
+        protected object BoundObjectParent { get; private set; }
+
+        private string property;
+        public string Property {
+            get { return property; }
+            set {
+                property = value;
+                if (value != null) {
+                    int i = value.IndexOf (".");
+                    if (i != -1) {
+                        property = value.Substring (0, i);
+                        SubProperty = value.Substring (i + 1, value.Length - i - 1);
+                    }
+                }
+            }
+        }
+
+        public string SubProperty { get; set; }
+
+#endregion
+
+    }
+
+    public abstract class CanvasItem
+    {
+        public CanvasItem Parent { get; set; }
+        public Gdk.Rectangle Allocation { get; set; }
+        public Gdk.Rectangle VirtualAllocation { get; set; }
+
+        public abstract void Render (CellContext context);
+        public abstract Gdk.Size Measure ();
+
+        public virtual bool ButtonEvent (int x, int y, bool pressed, uint button)
+        {
+            return false;
+        }
+
+        public virtual bool CursorMotionEvent (int x, int y)
+        {
+            return false;
+        }
+
+        public virtual void CursorEnterEvent ()
+        {
+        }
+
+        public virtual void CursorLeaveEvent ()
+        {
+        }
+    }
+}
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewLayout.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewLayout.cs
index 842ef5e..c4791be 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewLayout.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewLayout.cs
@@ -33,19 +33,12 @@ namespace Hyena.Data.Gui
 {
     public abstract class DataViewLayout
     {
-        public class Child
-        {
-            public Gdk.Rectangle Allocation { get; set; }
-            public Gdk.Rectangle VirtualAllocation { get; set; }
-            public int ModelRowIndex { get; set; }
-        }
-
-        private List<Child> children = new List<Child> ();
-        protected List<Child> Children {
+        private List<DataViewChild> children = new List<DataViewChild> ();
+        protected List<DataViewChild> Children {
             get { return children; }
         }
 
-        protected ListViewBase View { get; set; }
+        public ListViewBase View { get; set; }
 
         public Gdk.Rectangle ActualAllocation { get; protected set; }
         public Gdk.Size VirtualSize { get; protected set; }
@@ -58,7 +51,7 @@ namespace Hyena.Data.Gui
             get { return Children.Count; }
         }
 
-        public Child this[int index] {
+        public DataViewChild this[int index] {
             get { return Children[index]; }
         }
 
@@ -84,13 +77,13 @@ namespace Hyena.Data.Gui
             InvalidateChildLayout ();
         }
 
-        public virtual Child FindChildAtPoint (int x, int y)
+        public virtual DataViewChild FindChildAtPoint (int x, int y)
         {
             return Children.Find (child => child.Allocation.Contains (
                 ActualAllocation.X + x, ActualAllocation.Y + y));
         }
 
-        public virtual Child FindChildAtModelRowIndex (int modelRowIndex)
+        public virtual DataViewChild FindChildAtModelRowIndex (int modelRowIndex)
         {
             return Children.Find (child => child.ModelRowIndex == modelRowIndex);
         }
@@ -100,18 +93,6 @@ namespace Hyena.Data.Gui
         protected abstract void InvalidateChildCollection ();
         protected abstract void InvalidateChildLayout ();
 
-        protected void ResizeChildCollection (int newChildCount)
-        {
-            int difference = Children.Count - newChildCount;
-            while (Children.Count != newChildCount) {
-                if (difference > 0) {
-                    Children.RemoveAt (0);
-                } else {
-                    Children.Add (new Child ());
-                }
-            }
-        }
-
         protected Gdk.Rectangle GetChildVirtualAllocation (Gdk.Rectangle childAllocation)
         {
             return new Gdk.Rectangle () {
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewLayoutGrid.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewLayoutGrid.cs
index 52460b8..5b36409 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewLayoutGrid.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/DataViewLayoutGrid.cs
@@ -36,9 +36,15 @@ namespace Hyena.Data.Gui
         public int Rows { get; private set; }
         public int Columns { get; private set; }
 
+        public Func<DataViewChild> ChildAllocator { get; set; }
+
         protected override void InvalidateChildSize ()
         {
-            ChildSize = new Gdk.Size (48, 48);
+            if (Children.Count <= 0) {
+                Children.Add (CreateChild ());
+            }
+
+            ChildSize = Children[0].Measure ();
         }
 
         protected override void InvalidateVirtualSize ()
@@ -112,5 +118,28 @@ namespace Hyena.Data.Gui
                 // FIXME: clear any layout children that go beyond the model
             }
         }
+
+        protected virtual DataViewChild CreateChild ()
+        {
+            if (ChildAllocator == null) {
+                throw new InvalidOperationException ("ChildAllocator is unset");
+            }
+
+            var child = ChildAllocator ();
+            child.ParentLayout = this;
+            return child;
+        }
+
+        private void ResizeChildCollection (int newChildCount)
+        {
+            int difference = Children.Count - newChildCount;
+            while (Children.Count != newChildCount) {
+                if (difference > 0) {
+                    Children.RemoveAt (0);
+                } else {
+                    Children.Add (CreateChild ());
+                }
+            }
+        }
     }
 }
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs
index babb903..689e2e7 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs
@@ -300,7 +300,69 @@ namespace Hyena.Data.Gui
             return false;
         }
 
-#region Cell Event Proxy
+#region DataViewLayout Interaction Events
+
+        private DataViewChild last_layout_child;
+
+        private bool LayoutChildHandlesEvent (Gdk.Event evnt, bool press)
+        {
+            if (ViewLayout == null) {
+                return false;
+            }
+
+            int x = 0;
+            int y = 0;
+            bool handled = false;
+
+            var evnt_button = evnt as Gdk.EventButton;
+            var evnt_motion = evnt as Gdk.EventMotion;
+
+            if (evnt_motion != null) {
+                x = (int)evnt_motion.X;
+                y = (int)evnt_motion.Y;
+            } else if (evnt_button != null) {
+                x = (int)evnt_button.X;
+                y = (int)evnt_button.Y;
+            } else if (evnt is Gdk.EventCrossing && last_layout_child != null) {
+                last_layout_child.CursorLeaveEvent ();
+                last_layout_child = null;
+                return false;
+            }
+
+            var child = GetLayoutChildAt (x, y);
+            if (child == null) {
+                return false;
+            }
+
+            x -= child.VirtualAllocation.X;
+            y -= child.VirtualAllocation.Y;
+
+            if (evnt_motion != null) {
+                if (last_layout_child != child) {
+                    if (last_layout_child != null) {
+                        last_layout_child.CursorLeaveEvent ();
+                    }
+                    last_layout_child = child;
+                    child.CursorEnterEvent ();
+                }
+                handled = child.CursorMotionEvent (x, y);
+            } else if (evnt_button != null) {
+                handled = child.ButtonEvent (x, y, press, evnt_button.Button);
+            }
+
+            return handled;
+        }
+
+        private DataViewChild GetLayoutChildAt (int x, int y)
+        {
+            x -= list_interaction_alloc.X;
+            y -= list_interaction_alloc.Y;
+            return ViewLayout.FindChildAtPoint (x, y);
+        }
+
+#endregion
+
+#region Cell Event Proxy (FIXME: THIS ENTIRE SECTION IS OBSOLETE YAY YAY YAY!)
 
         private IInteractiveCell last_icell;
         private Gdk.Rectangle last_icell_area = Gdk.Rectangle.Zero;
@@ -320,21 +382,6 @@ namespace Hyena.Data.Gui
             Gdk.Rectangle icell_area;
             bool redraw = ProxyEventToCell (evnt, press, out icell, out icell_area);
 
-            if (ViewLayout != null) {
-                if (last_icell_area != icell_area) {
-                    InvalidateLastIcell ();
-                    last_icell = icell;
-                    last_icell_area = icell_area;
-                }
-
-                if (redraw) {
-                    QueueDirtyRegion (icell_area);
-                }
-
-                return;
-            }
-
-            // FIXME: obsolete
             int xoffset = HadjustmentValue;
             int yoffset = VadjustmentValue;
 
@@ -394,17 +441,6 @@ namespace Hyena.Data.Gui
             x = evnt_x - list_interaction_alloc.X;
             y = evnt_y - list_interaction_alloc.Y;
 
-            if (ViewLayout != null) {
-                var child = ViewLayout.FindChildAtModelRowIndex (row_index);
-                icell_area = child.Allocation;
-                x -= child.VirtualAllocation.X;
-                y -= child.VirtualAllocation.Y;
-                return evnt_motion == null
-                    ? icell.ButtonEvent (x, y, press, evnt_button)
-                    : icell.MotionEvent (x, y, evnt_motion);
-            }
-
-            // FIXME: Obsolete
             // Turn the view-absolute coordinates into cell-relative coordinates
             CachedColumn cached_column = GetCachedColumnForColumn (column);
             x -= cached_column.X1 - HadjustmentValue;
@@ -532,6 +568,10 @@ namespace Hyena.Data.Gui
                 return true;
             }
 
+            if (LayoutChildHandlesEvent (evnt, true)) {
+                return true;
+            }
+
             ProxyEventToCell (evnt, true);
 
             object item = model[row_index];
@@ -612,6 +652,9 @@ namespace Hyena.Data.Gui
                 return OnHeaderButtonRelease (evnt);
             } else if (list_interaction_alloc.Contains ((int)evnt.X, (int)evnt.Y) && model != null &&
                 (evnt.State & (Gdk.ModifierType.ShiftMask | Gdk.ModifierType.ControlMask)) == 0) {
+                if (LayoutChildHandlesEvent (evnt, false)) {
+                    return true;
+                }
                 ProxyEventToCell (evnt, false);
                 return OnListButtonRelease (evnt);
             }
@@ -698,6 +741,10 @@ namespace Hyena.Data.Gui
                 ResizeColumn (x);
             }
 
+            if (LayoutChildHandlesEvent (evnt, false)) {
+                return true;
+            }
+
             ProxyEventToCell (evnt, false);
 
             return true;
@@ -756,6 +803,9 @@ namespace Hyena.Data.Gui
         {
             if (evnt.Mode == Gdk.CrossingMode.Normal) {
                 GdkWindow.Cursor = null;
+                if (LayoutChildHandlesEvent (evnt, false)) {
+                    return true;
+                }
                 ProxyEventToCell (evnt, false);
             }
             return base.OnLeaveNotifyEvent (evnt);
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
index 10f45cc..6fb7865 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
@@ -495,15 +495,22 @@ namespace Hyena.Data.Gui
                         child_allocation.X, child_allocation.Y,
                         child_allocation.Width, child_allocation.Height,
                         true, true, selection_color, CairoCorners.All);
+
+                    cell_context.State = StateType.Selected;
+                } else {
+                    cell_context.State = StateType.Normal;
                 }
 
                 cell_context.ModelRowIndex = model_row_index;
                 // cell_context.ViewRowIndex = view_row_index;
                 // cell_context.ViewColumnIndex = view_column_index;
 
-                var item = model[model_row_index];
-                PaintCell (item, 0, model_row_index, child_allocation,
-                    IsRowOpaque (item), IsRowBold (item), StateType.Normal, false);
+                layout_child.BindDataItem (model[model_row_index]);
+
+                cairo_context.Save ();
+                cairo_context.Translate (layout_child.Allocation.X, layout_child.Allocation.Y);
+                layout_child.Render (cell_context);
+                cairo_context.Restore ();
             }
 
             cairo_context.ResetClip ();
diff --git a/src/Libraries/Hyena.Gui/Hyena.Gui.csproj b/src/Libraries/Hyena.Gui/Hyena.Gui.csproj
index e34ce50..9553821 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Gui.csproj
+++ b/src/Libraries/Hyena.Gui/Hyena.Gui.csproj
@@ -177,6 +177,7 @@
     <Compile Include="Hyena.Data.Gui\DataViewLayout.cs" />
     <Compile Include="Hyena.Data.Gui\DataViewLayoutGrid.cs" />
     <Compile Include="Hyena.Gui\CairoDamageDebugger.cs" />
+    <Compile Include="Hyena.Data.Gui\DataViewChild.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
diff --git a/src/Libraries/Hyena.Gui/Makefile.am b/src/Libraries/Hyena.Gui/Makefile.am
index d9662c3..94c9c06 100644
--- a/src/Libraries/Hyena.Gui/Makefile.am
+++ b/src/Libraries/Hyena.Gui/Makefile.am
@@ -18,6 +18,7 @@ SOURCES =  \
 	Hyena.Data.Gui/ColumnCellText.cs \
 	Hyena.Data.Gui/ColumnController.cs \
 	Hyena.Data.Gui/ColumnHeaderCellText.cs \
+	Hyena.Data.Gui/DataViewChild.cs \
 	Hyena.Data.Gui/DataViewLayout.cs \
 	Hyena.Data.Gui/DataViewLayoutGrid.cs \
 	Hyena.Data.Gui/IHeaderCell.cs \
@@ -54,8 +55,8 @@ SOURCES =  \
 	Hyena.Gui.Theming/ThemeEngine.cs \
 	Hyena.Gui/ActionManager.cs \
 	Hyena.Gui/BaseWidgetAccessible.cs \
-	Hyena.Gui/CairoExtensions.cs \
 	Hyena.Gui/CairoDamageDebugger.cs \
+	Hyena.Gui/CairoExtensions.cs \
 	Hyena.Gui/CleanRoomStartup.cs \
 	Hyena.Gui/CompositeUtils.cs \
 	Hyena.Gui/Contrast.cs \



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]