[banshee/grid] [ListView] New implementation of child measuring



commit 2ce68fdc55622589947c1ecd7c486c81b8ab1986
Author: Aaron Bockover <abockover novell com>
Date:   Wed Dec 16 16:26:14 2009 -0500

    [ListView] New implementation of child measuring
    
    Inspired by Silverlight the new method of 'measuring' children
    (replacing the originally hard-coded row-height calculation,
    later hackily augmented with a RowHeightProvider delegate) allows
    for more flexibility and is less intensive.
    
    The RowHeight property is removed, replaced with ChildSize
    which has Width and Height properties.
    
    RowHeightProvider is removed, and two protected virtual methods
    added, OnInvalidateMeasure (to queue a re-measure) and OnMeasureChild
    to actually provide the size of a child in the view.
    
    For grid layout and rendering, both Width and Height must be
    greater than 0. For list, only the height needs to be provided.
    
    Each view and necessary cell renderers were updated to use the
    new measure APIs. Additionally, the text measuring code for
    ColumnCellAlbum was greatly improved. ColumnCellPodcast now
    derives from ColumnCellAlbum. ColumnCellAlbum will soon be
    broken down into a generic ColumnCellTile and moved into Hyena.
    
    A new extension class was added, Hyena.Gui.PangoExtensions that
    currently adds a MeasureTextHeight method to Pango.FontDescription.

 .../Banshee.Collection.Gui/AlbumListView.cs        |   12 ++-
 .../Banshee.Collection.Gui/BaseTrackListView.cs    |    2 +-
 .../Banshee.Collection.Gui/ColumnCellAlbum.cs      |   32 +++---
 .../Banshee.Collection.Gui/ColumnCellTrack.cs      |   14 ++--
 .../Banshee.Collection.Gui/TerseTrackListView.cs   |   13 ++-
 .../Banshee.Podcasting.Gui/ColumnCellPodcast.cs    |   29 +-----
 .../Banshee.Podcasting.Gui/PodcastFeedView.cs      |   10 ++-
 .../Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs         |    5 +
 .../Hyena.Gui/Hyena.Data.Gui/ListView/ListView.cs  |    6 +-
 .../Hyena.Data.Gui/ListView/ListView_Accessible.cs |    2 +-
 .../ListView/ListView_DragAndDrop.cs               |    2 +-
 .../ListView/ListView_Interaction.cs               |   60 +++++------
 .../Hyena.Data.Gui/ListView/ListView_Rendering.cs  |  115 ++++++++++----------
 .../Hyena.Data.Gui/ListView/ListView_Windowing.cs  |   17 +++-
 src/Libraries/Hyena.Gui/Hyena.Gui.csproj           |   17 +++-
 .../Hyena.Gui/Hyena.Gui/PangoExtensions.cs         |   47 ++++++++
 src/Libraries/Hyena.Gui/Makefile.am                |    1 +
 17 files changed, 222 insertions(+), 162 deletions(-)
---
diff --git a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/AlbumListView.cs b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/AlbumListView.cs
index 86b3ef4..d4abdd9 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/AlbumListView.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/AlbumListView.cs
@@ -40,15 +40,16 @@ namespace Banshee.Collection.Gui
 {
     public class AlbumListView : TrackFilterListView<AlbumInfo>
     {
+        private ColumnCellAlbum renderer;
+
         public AlbumListView () : base ()
         {
             LayoutStyle = DataViewLayoutStyle.Grid;
-            ColumnCellAlbum renderer = new ColumnCellAlbum () { LayoutStyle = LayoutStyle };
+            renderer = new ColumnCellAlbum () { LayoutStyle = LayoutStyle };
+
             column_controller.Add (new Column ("Album", renderer, 1.0));
             ColumnController = column_controller;
 
-            RowHeightProvider = renderer.ComputeRowHeight;
-
             ServiceManager.PlayerEngine.ConnectEvent (OnPlayerEvent, PlayerEvent.TrackInfoUpdated);
         }
 
@@ -58,5 +59,10 @@ namespace Banshee.Collection.Gui
             //       b) xfade the artwork if it is, that'd be slick
             QueueDraw ();
         }
+
+        protected override Gdk.Size OnMeasureChild ()
+        {
+            return renderer.Measure (this);
+        }
     }
 }
diff --git a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/BaseTrackListView.cs b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/BaseTrackListView.cs
index 21b398d..be36449 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/BaseTrackListView.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/BaseTrackListView.cs
@@ -168,7 +168,7 @@ namespace Banshee.Collection.Gui
                 if (playlist != null) {
                     //Gtk.Drag.
                     int row = GetModelRowAt (0, y);
-                    if (row != GetModelRowAt (0, y + RowHeight / 2)) {
+                    if (row != GetModelRowAt (0, y + ChildSize.Height / 2)) {
                         row += 1;
                     }
 
diff --git a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs
index b9cce0e..4e56128 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellAlbum.cs
@@ -150,29 +150,25 @@ namespace Banshee.Collection.Gui
             PangoCairoHelper.ShowLayout (context.Context, layout);
         }
 
-        public int ComputeRowHeight (Widget widget)
+        public override Gdk.Size Measure (Widget widget)
         {
-            int height;
-            int text_w, text_h;
+            int text_height = 0;
 
-            Pango.Layout layout = new Pango.Layout (widget.PangoContext);
-            layout.FontDescription = widget.PangoContext.FontDescription.Copy ();
+            using (var layout = new Pango.Layout (widget.PangoContext) {
+                FontDescription = widget.PangoContext.FontDescription.Copy () }) {
 
-            layout.FontDescription.Weight = Pango.Weight.Bold;
-            layout.SetText ("W");
-            layout.GetPixelSize (out text_w, out text_h);
-            height = text_h;
-
-            layout.FontDescription.Weight = Pango.Weight.Normal;
-            layout.FontDescription.Size = (int)(layout.FontDescription.Size * Pango.Scale.Small);
-            layout.FontDescription.Style = Pango.Style.Italic;
-            layout.SetText ("W");
-            layout.GetPixelSize (out text_w, out text_h);
-            height += text_h;
+                layout.FontDescription.Weight = Pango.Weight.Bold;
+                text_height = layout.FontDescription.MeasureTextHeight (widget.PangoContext);
 
-            layout.Dispose ();
+                layout.FontDescription.Weight = Pango.Weight.Normal;
+                layout.FontDescription.Size = (int)(layout.FontDescription.Size * Pango.Scale.Small);
+                layout.FontDescription.Style = Pango.Style.Italic;
+                text_height += layout.FontDescription.MeasureTextHeight (widget.PangoContext);
+            }
 
-            return (height < image_size ? image_size : height) + 6;
+            return LayoutStyle == DataViewLayoutStyle.Grid
+                ? new Gdk.Size (100, 100 + text_height + 6)
+                : new Gdk.Size (0, (text_height < image_size ? image_size : text_height) + 6);
         }
     }
 }
diff --git a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellTrack.cs b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellTrack.cs
index 4aebd48..34540b1 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellTrack.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ColumnCellTrack.cs
@@ -44,14 +44,14 @@ namespace Banshee.Collection.Gui
         {
         }
 
-        public int ComputeRowHeight (Widget widget)
+        public override Gdk.Size Measure (Widget widget)
         {
-            int lw, lh;
-            Pango.Layout layout = new Pango.Layout (widget.PangoContext);
-            layout.SetMarkup ("<b>W</b>\n<small><i>W</i></small>");
-            layout.GetPixelSize (out lw, out lh);
-            layout.Dispose ();
-            return lh + 8;
+            using (var layout = new Pango.Layout (widget.PangoContext)) {
+                int lw, lh;
+                layout.SetMarkup ("<b>W</b>\n<small><i>W</i></small>");
+                layout.GetPixelSize (out lw, out lh);
+                return new Gdk.Size (0, lh + 8);
+            }
         }
 
         public override void Render (CellContext context, StateType state, double cellWidth, double cellHeight)
diff --git a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/TerseTrackListView.cs b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/TerseTrackListView.cs
index bd24875..2470e3c 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/TerseTrackListView.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/TerseTrackListView.cs
@@ -40,18 +40,23 @@ namespace Banshee.Collection.Gui
     public class TerseTrackListView : BaseTrackListView
     {
         private ColumnController column_controller;
-
+        private ColumnCellTrack renderer;
+        
         public TerseTrackListView () : base ()
         {
-            column_controller = new ColumnController ();
+            renderer = new ColumnCellTrack ();
 
-            ColumnCellTrack renderer = new ColumnCellTrack ();
+            column_controller = new ColumnController ();
             column_controller.Add (new Column ("Track", renderer, 1.0));
 
             ColumnController = column_controller;
 
-            RowHeightProvider = renderer.ComputeRowHeight;
             HeaderVisible = false;
         }
+
+        protected override Gdk.Size OnMeasureChild ()
+        {
+            return renderer.Measure (this);
+        }
     }
 }
diff --git a/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/ColumnCellPodcast.cs b/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/ColumnCellPodcast.cs
index 169d8b1..d898fa2 100644
--- a/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/ColumnCellPodcast.cs
+++ b/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/ColumnCellPodcast.cs
@@ -44,7 +44,7 @@ using Banshee.Collection.Gui;
 
 namespace Banshee.Podcasting.Gui
 {
-    public class ColumnCellPodcast : ColumnCell
+    public class ColumnCellPodcast : ColumnCellAlbum
     {
         private static int image_spacing = 4;
         private static int image_size = 48;
@@ -55,7 +55,7 @@ namespace Banshee.Podcasting.Gui
 
         private ArtworkManager artwork_manager;
 
-        public ColumnCellPodcast () : base (null, true)
+        public ColumnCellPodcast () : base ()
         {
             artwork_manager = ServiceManager.Get<ArtworkManager> ();
         }
@@ -143,30 +143,5 @@ namespace Banshee.Podcasting.Gui
             context.Context.Color = text_color;
             PangoCairoHelper.ShowLayout (context.Context, layout);
         }
-
-        public int ComputeRowHeight (Widget widget)
-        {
-            int height;
-            int text_w, text_h;
-
-            Pango.Layout layout = new Pango.Layout (widget.PangoContext);
-            layout.FontDescription = widget.PangoContext.FontDescription.Copy ();
-
-            layout.FontDescription.Weight = Pango.Weight.Bold;
-            layout.SetText ("W");
-            layout.GetPixelSize (out text_w, out text_h);
-            height = text_h;
-
-            layout.FontDescription.Weight = Pango.Weight.Normal;
-            layout.FontDescription.Size = (int)(layout.FontDescription.Size * Pango.Scale.Small);
-            layout.FontDescription.Style = Pango.Style.Italic;
-            layout.SetText ("W");
-            layout.GetPixelSize (out text_w, out text_h);
-            height += text_h;
-
-            layout.Dispose ();
-
-            return (height < image_size ? image_size : height) + 6;
-        }
     }
 }
diff --git a/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastFeedView.cs b/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastFeedView.cs
index 9ef40e7..f16724f 100644
--- a/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastFeedView.cs
+++ b/src/Extensions/Banshee.Podcasting/Banshee.Podcasting.Gui/PodcastFeedView.cs
@@ -49,14 +49,15 @@ namespace Banshee.Podcasting.Gui
 {
     public class PodcastFeedView : TrackFilterListView<Feed>
     {
+        private ColumnCellPodcast renderer;
+
         public PodcastFeedView () : base ()
         {
-            ColumnCellPodcast renderer = new ColumnCellPodcast ();
+            renderer = new ColumnCellPodcast ();
             column_controller.Add (new Column ("Podcast", renderer, 1.0));
             //column_controller.Add (new Column (null, "Activity", new FeedActivityColumnCell ("Activity"), 0.00, true, 26, 26));
 
             ColumnController = column_controller;
-            RowHeightProvider = renderer.ComputeRowHeight;
         }
 
         protected override bool OnPopupMenu ()
@@ -64,6 +65,11 @@ namespace Banshee.Podcasting.Gui
             ServiceManager.Get<InterfaceActionService> ().FindAction ("Podcast.PodcastFeedPopupAction").Activate ();
             return true;
         }
+
+        protected override Gdk.Size OnMeasureChild ()
+        {
+            return renderer.Measure (this);
+        }
     }
 
     /*public class PodcastFeedView : ListView<Feed>
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs
index 4817dd2..8c4a923 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs
@@ -124,6 +124,11 @@ namespace Hyena.Data.Gui
 
         public abstract void Render (CellContext context, StateType state, double cellWidth, double cellHeight);
 
+        public virtual Gdk.Size Measure (Gtk.Widget widget)
+        {
+            return Gdk.Size.Empty;
+        }
+
         public bool Expand {
             get { return expand; }
             set { expand = value; }
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView.cs
index 5d02fcc..8c500da 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView.cs
@@ -61,8 +61,8 @@ namespace Hyena.Data.Gui
                         rect.Y = args.Y - list_interaction_alloc.Y;
 
                         // get the top of the cell pointed to by list_y
-                        rect.Y -= VadjustmentValue % RowHeight;
-                        rect.Y -= rect.Y % RowHeight;
+                        rect.Y -= VadjustmentValue % ChildSize.Height;
+                        rect.Y -= rect.Y % ChildSize.Height;
 
                         // convert back to widget coords
                         rect.Y += list_interaction_alloc.Y;
@@ -71,7 +71,7 @@ namespace Hyena.Data.Gui
                         rect.Width = cached_column.Width;
 
                         // TODO not right - could be smaller if at the top/bottom and only partially showing
-                        rect.Height = RowHeight;
+                        rect.Height = ChildSize.Height;
 
                         args.Tooltip.Markup = markup;
                         args.Tooltip.TipArea = rect;
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Accessible.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Accessible.cs
index 4727adb..1646e9b 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Accessible.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Accessible.cs
@@ -59,7 +59,7 @@ namespace Hyena.Data.Gui
         public Gdk.Rectangle GetColumnCellExtents (int row, int column, bool clip, Atk.CoordType coord_type)
         {
             int width = GetColumnWidth (column);
-            int height = RowHeight;
+            int height = ChildSize.Height;
 
             int y = (int)GetViewPointForModelRow (row).Y - VadjustmentValue + ListAllocation.Y;
 
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_DragAndDrop.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_DragAndDrop.cs
index 64d7a13..ccbddeb 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_DragAndDrop.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_DragAndDrop.cs
@@ -203,7 +203,7 @@ namespace Hyena.Data.Gui
                 return -1;
             }
 
-            if (row != GetModelRowAt (0, y + RowHeight / 2)) {
+            if (row != GetModelRowAt (0, y + ChildSize.Height / 2)) {
                 row++;
             }
 
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 7aa0168..59b13bf 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
@@ -145,11 +145,11 @@ namespace Hyena.Data.Gui
             if (align_y) {
                 if (y_at_row < VadjustmentValue) {
                     ScrollTo (y_at_row);
-                } else if (vadjustment != null && (y_at_row + RowHeight) > (vadjustment.Value + vadjustment.PageSize)) {
-                    ScrollTo (y_at_row + RowHeight - (vadjustment.PageSize));
+                } else if (vadjustment != null && (y_at_row + ChildSize.Height) > (vadjustment.Value + vadjustment.PageSize)) {
+                    ScrollTo (y_at_row + ChildSize.Height - (vadjustment.PageSize));
                 }
             } else if (vadjustment != null) {
-                ScrollTo (vadjustment.Value + ((row_index - Selection.FocusedIndex) * RowHeight));
+                ScrollTo (vadjustment.Value + ((row_index - Selection.FocusedIndex) * ChildSize.Height));
             }
 
             Selection.FocusedIndex = row_index;
@@ -215,14 +215,14 @@ namespace Hyena.Data.Gui
                 case Gdk.Key.KP_Page_Up:
                     if (!HeaderFocused)
                         handled = vadjustment != null && KeyboardScroll (press.State,
-                            (int)(-vadjustment.PageIncrement / (double)RowHeight), false);
+                            (int)(-vadjustment.PageIncrement / (double)ChildSize.Height), false);
                     break;
 
                 case Gdk.Key.Page_Down:
                 case Gdk.Key.KP_Page_Down:
                     if (!HeaderFocused)
                         handled = vadjustment != null && KeyboardScroll (press.State,
-                            (int)(vadjustment.PageIncrement / (double)RowHeight), false);
+                            (int)(vadjustment.PageIncrement / (double)ChildSize.Height), false);
                     break;
 
                 case Gdk.Key.Home:
@@ -356,19 +356,19 @@ namespace Hyena.Data.Gui
             // Turn the view-absolute coordinates into cell-relative coordinates
             CachedColumn cached_column = GetCachedColumnForColumn (column);
             x -= cached_column.X1 - HadjustmentValue;
-            int page_offset = VadjustmentValue % RowHeight;
-            y = (y + page_offset) % RowHeight;
+            int page_offset = VadjustmentValue % ChildSize.Height;
+            y = (y + page_offset) % ChildSize.Height;
 
             var view_point = GetViewPointForModelRow (row_index);
             icell_area.Y = (int)view_point.Y + list_interaction_alloc.Y + Allocation.Y;
             if (LayoutStyle == DataViewLayoutStyle.Grid) {
                 icell_area.X = (int)view_point.X + Allocation.X;
-                icell_area.Width = GridCellWidth;
-                icell_area.Height = GridCellHeight;
+                icell_area.Width = ChildSize.Width;
+                icell_area.Height = ChildSize.Height;
             } else {
                 icell_area.X = cached_column.X1 + Allocation.X;
                 icell_area.Width = cached_column.Width;
-                icell_area.Height = RowHeight;
+                icell_area.Height = ChildSize.Height;
             }
 
             // Send the cell a synthesized input event
@@ -763,38 +763,36 @@ namespace Hyena.Data.Gui
 
         protected int GetModelRowAt (int x, int y)
         {
-            if (y < 0) {
+            if (y < 0 || ChildSize.Height <= 0) {
                 return -1;
             }
 
             if (LayoutStyle == DataViewLayoutStyle.Grid) {
-                int v_page_offset = VadjustmentValue % GridCellHeight;
-                int h_page_offset = HadjustmentValue % GridCellWidth;
-                int first_row = VadjustmentValue / GridCellHeight;
-                int first_col = HadjustmentValue / GridCellWidth;
-                int row_offset = (y + v_page_offset) / GridCellHeight;
-                int col_offset = Math.Min ((x + h_page_offset) / GridCellWidth, GridColumnsInView);
+                if (ChildSize.Width <= 0) {
+                    return -1;
+                }
+
+                int v_page_offset = VadjustmentValue % ChildSize.Height;
+                int h_page_offset = HadjustmentValue % ChildSize.Width;
+                int first_row = VadjustmentValue / ChildSize.Height;
+                int first_col = HadjustmentValue / ChildSize.Width;
+                int row_offset = (y + v_page_offset) / ChildSize.Height;
+                int col_offset = Math.Min ((x + h_page_offset) / ChildSize.Width, GridColumnsInView);
                 int model_row = ((first_row + row_offset) * GridColumnsInView) + first_col + col_offset;
                 return model_row;
             } else {
-                int v_page_offset = VadjustmentValue % RowHeight;
-                int first_row = VadjustmentValue / RowHeight;
-                int row_offset = (y + v_page_offset) / RowHeight;
+                int v_page_offset = VadjustmentValue % ChildSize.Height;
+                int first_row = VadjustmentValue / ChildSize.Height;
+                int row_offset = (y + v_page_offset) / ChildSize.Height;
                 return first_row + row_offset;
             }
         }
 
-        [Obsolete ("Use GetModelRowAt (x, y) instead.")]
-        protected int GetRowAtY (int y)
-        {
-            return GetModelRowAt (0, y);
-        }
-
         protected Cairo.PointD GetViewPointForModelRow (int row)
         {
             return LayoutStyle == DataViewLayoutStyle.Grid
-                ? new Cairo.PointD (0, (double)RowHeight * row)
-                : new Cairo.PointD (0, (double)RowHeight * row);
+                ? new Cairo.PointD (0, (double)ChildSize.Height * row)
+                : new Cairo.PointD (0, (double)ChildSize.Height * row);
         }
 
         private void FocusModelRow (int index)
@@ -831,9 +829,9 @@ namespace Hyena.Data.Gui
 
             if (vadjustment != null && model != null) {
                 vadjustment.Upper = LayoutStyle == DataViewLayoutStyle.List
-                    ? RowHeight * model.Count
-                    : (int)Math.Ceiling (model.Count / (double)GridColumnsInView) * RowHeight;
-                vadjustment.StepIncrement = RowHeight;
+                    ? ChildSize.Height * model.Count
+                    : (int)Math.Ceiling (model.Count / (double)GridColumnsInView) * ChildSize.Height;
+                vadjustment.StepIncrement = ChildSize.Height;
                 if (vadjustment.Value + vadjustment.PageSize > vadjustment.Upper) {
                     vadjustment.Value = vadjustment.Upper - vadjustment.PageSize;
                 }
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 9aba3a7..849614b 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
@@ -66,7 +66,7 @@ namespace Hyena.Data.Gui
             changing_style = false;
 
             base.OnStyleSet (old_style);
-            RecomputeRowHeight = true;
+            OnInvalidateMeasure ();
             theme = Hyena.Gui.Theming.ThemeEngine.CreateTheme (this);
 
             // Save the drawable so we can reuse it
@@ -98,6 +98,8 @@ namespace Hyena.Data.Gui
             cell_context.Context = cairo_context;
             cell_context.Layout = pango_layout;
 
+            OnMeasure ();
+
             Theme.DrawFrameBackground (cairo_context, Allocation, true);
             if (header_visible && LayoutStyle != DataViewLayoutStyle.Grid && column_controller != null) {
                 PaintHeader (damage);
@@ -214,6 +216,10 @@ namespace Hyena.Data.Gui
 
         private void PaintList (Rectangle clip)
         {
+            if (ChildSize.Height <= 0) {
+                return;
+            }
+
             // TODO factor this out?
             // Render the sort effect to the GdkWindow.
             if (sort_column_index != -1 && (!pressed_column_is_dragging || pressed_column_index != sort_column_index)) {
@@ -232,9 +238,9 @@ namespace Hyena.Data.Gui
             cell_context.TextAsForeground = false;
 
             int vadjustment_value = VadjustmentValue;
-            int first_row = vadjustment_value / RowHeight;
+            int first_row = vadjustment_value / ChildSize.Height;
             int last_row = Math.Min (model.Count, first_row + RowsInView);
-            int offset = list_rendering_alloc.Y - vadjustment_value % RowHeight;
+            int offset = list_rendering_alloc.Y - vadjustment_value % ChildSize.Height;
 
             Rectangle selected_focus_alloc = Rectangle.Zero;
             Rectangle single_list_alloc = new Rectangle ();
@@ -242,7 +248,7 @@ namespace Hyena.Data.Gui
             single_list_alloc.X = list_rendering_alloc.X - HadjustmentValue;
             single_list_alloc.Y = offset;
             single_list_alloc.Width = list_rendering_alloc.Width + HadjustmentValue;
-            single_list_alloc.Height = RowHeight;
+            single_list_alloc.Height = ChildSize.Height;
 
             int selection_height = 0;
             int selection_y = 0;
@@ -350,7 +356,7 @@ namespace Hyena.Data.Gui
             bool bold = IsRowBold (item);
 
             Rectangle cell_area = new Rectangle ();
-            cell_area.Height = RowHeight;
+            cell_area.Height = ChildSize.Height;
             cell_area.Y = area.Y;
 
             cell_context.ViewRowIndex = cell_context.ModelRowIndex = row_index;
@@ -443,6 +449,10 @@ namespace Hyena.Data.Gui
 
         private void PaintGrid (Rectangle clip)
         {
+            if (ChildSize.Width <= 0 || ChildSize.Height <= 0) {
+                return;
+            }
+            
             clip.Intersect (list_rendering_alloc);
             cairo_context.Rectangle (clip.X, clip.Y, clip.Width, clip.Height);
             cairo_context.Clip ();
@@ -452,20 +462,20 @@ namespace Hyena.Data.Gui
 
             int rows_in_view = RowsInView;
             int columns_in_view = GridColumnsInView;
-            int cell_height = RowHeight;
-            int cell_width = GridCellWidth + ((list_rendering_alloc.Width -
-                columns_in_view * GridCellWidth) / columns_in_view);
+            int cell_height = ChildSize.Height;
+            int cell_width = ChildSize.Width + ((list_rendering_alloc.Width -
+                columns_in_view * ChildSize.Width) / columns_in_view);
             int vadjustment_value = VadjustmentValue;
 
-            int offset = list_rendering_alloc.Y - vadjustment_value % RowHeight;
-            int first_model_row = (int)Math.Floor (vadjustment_value / (double)RowHeight) * columns_in_view;
+            int offset = list_rendering_alloc.Y - vadjustment_value % ChildSize.Height;
+            int first_model_row = (int)Math.Floor (vadjustment_value / (double)ChildSize.Height) * columns_in_view;
             int last_model_row = Math.Min (model.Count, first_model_row + rows_in_view * columns_in_view);
 
             var grid_cell_alloc = new Rectangle () {
                 X = list_rendering_alloc.X,
                 Y = offset,
-                Width = GridCellWidth,
-                Height = GridCellHeight
+                Width = ChildSize.Width,
+                Height = ChildSize.Height
             };
 
             selected_rows.Clear ();
@@ -538,66 +548,53 @@ namespace Hyena.Data.Gui
             }
         }
 
-        private ListViewRowHeightHandler row_height_handler;
-        public virtual ListViewRowHeightHandler RowHeightProvider {
-            get { return row_height_handler; }
-            set {
-                if (value != row_height_handler) {
-                    row_height_handler = value;
-                    RecomputeRowHeight = true;
-                }
-            }
-        }
-
-        private bool recompute_row_height = true;
-        protected bool RecomputeRowHeight {
-            get { return recompute_row_height; }
+        private DataViewLayoutStyle layout_style = DataViewLayoutStyle.List;
+        public DataViewLayoutStyle LayoutStyle {
+            get { return layout_style; }
             set {
-                recompute_row_height = value;
-                if (value && IsMapped && IsRealized) {
-                    QueueDraw ();
-                }
+                layout_style = value;
+                OnInvalidateMeasure ();
             }
         }
 
-        private int row_height = 32;
-        public int RowHeight {
-            get {
-                if (LayoutStyle == DataViewLayoutStyle.Grid) {
-                    return GridCellHeight;
-                }
+#region Measuring
 
-                if (RecomputeRowHeight) {
-                    row_height = RowHeightProvider != null
-                        ? RowHeightProvider (this)
-                        : ColumnCellText.ComputeRowHeight (this);
+        private Size child_size = Size.Empty;
+        public Size ChildSize {
+            get { return child_size; }
+        }
 
-                    header_height = 0;
-                    MoveResize (Allocation);
+        private bool measure_pending;
 
-                    RecomputeRowHeight = false;
-                }
-
-                return row_height;
+        protected virtual void OnInvalidateMeasure ()
+        {
+            measure_pending = true;
+            if (IsMapped && IsRealized) {
+                QueueDraw ();
             }
         }
 
-        private DataViewLayoutStyle layout_style = DataViewLayoutStyle.List;
-        public DataViewLayoutStyle LayoutStyle {
-            get { return layout_style; }
-            set {
-                layout_style = value;
-                MoveResize (Allocation);
-                InvalidateList ();
-            }
+        protected virtual Size OnMeasureChild ()
+        {
+            return LayoutStyle == DataViewLayoutStyle.Grid
+                ? new Size (48, 48)
+                : new Size (0, ColumnCellText.ComputeRowHeight (this));
         }
 
-        public int GridCellWidth {
-            get { return 100; }
-        }
+        private void OnMeasure ()
+        {
+            if (!measure_pending) {
+                return;
+            }
 
-        public int GridCellHeight {
-            get { return 100; }
+            measure_pending = false;
+
+            header_height = 0;
+            child_size = OnMeasureChild ();
+            UpdateAdjustments ();
         }
+
+#endregion
+
     }
 }
diff --git a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs
index b1ee8a0..3bacd6d 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs
+++ b/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs
@@ -180,11 +180,24 @@ namespace Hyena.Data.Gui
         }
 
         protected int RowsInView {
-            get { return (int)Math.Ceiling ((list_rendering_alloc.Height + RowHeight) / (double)RowHeight); }
+            get {
+                if (ChildSize.Height <= 0) {
+                    return 0;
+                }
+
+                return (int)Math.Ceiling ((list_rendering_alloc.Height +
+                    ChildSize.Height) / (double)ChildSize.Height);
+            }
         }
 
         protected int GridColumnsInView {
-            get { return Math.Max (list_rendering_alloc.Width / GridCellWidth, 1); }
+            get {
+                if (ChildSize.Width <= 0) {
+                    return 0;
+                }
+
+                return Math.Max (list_rendering_alloc.Width / ChildSize.Width, 1);
+            }
         }
     }
 }
diff --git a/src/Libraries/Hyena.Gui/Hyena.Gui.csproj b/src/Libraries/Hyena.Gui/Hyena.Gui.csproj
index 10e3ebb..e230d46 100644
--- a/src/Libraries/Hyena.Gui/Hyena.Gui.csproj
+++ b/src/Libraries/Hyena.Gui/Hyena.Gui.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"; ToolsVersion="3.5">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -19,21 +19,29 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
+    <ReleaseVersion>1.3</ReleaseVersion>
+    <RootNamespace>Hyena.Gui</RootNamespace>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
-    <DebugType>Full</DebugType>
+    <DebugType>full</DebugType>
     <CustomCommands>
       <CustomCommands>
         <Command type="Build" command="make" workingdir="${SolutionDir}" />
         <Command type="Execute" command="make run" workingdir="${SolutionDir}" />
       </CustomCommands>
     </CustomCommands>
+    <OutputPath>bin\Debug</OutputPath>
+    <WarningLevel>4</WarningLevel>
+    <Optimize>false</Optimize>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Windows|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
-    <DebugType>Full</DebugType>
+    <DebugType>full</DebugType>
     <PlatformTarget>x86</PlatformTarget>
+    <OutputPath>bin\Windows</OutputPath>
+    <WarningLevel>4</WarningLevel>
+    <Optimize>false</Optimize>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="ICSharpCode.SharpZipLib">
@@ -159,6 +167,9 @@
     <Compile Include="Hyena.Data.Gui\Accessibility\ListViewAccessible_Selection.cs" />
     <Compile Include="Hyena.Data.Gui\Accessibility\ColumnCellTextAccessible.cs" />
     <Compile Include="Hyena.Data.Gui\Accessibility\ColumnHeaderCellTextAccessible.cs" />
+    <Compile Include="Hyena.Widgets\EntryPopup.cs" />
+    <Compile Include="Hyena.Widgets\SimpleTable.cs" />
+    <Compile Include="Hyena.Gui\PangoExtensions.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
diff --git a/src/Libraries/Hyena.Gui/Hyena.Gui/PangoExtensions.cs b/src/Libraries/Hyena.Gui/Hyena.Gui/PangoExtensions.cs
new file mode 100644
index 0000000..e593a50
--- /dev/null
+++ b/src/Libraries/Hyena.Gui/Hyena.Gui/PangoExtensions.cs
@@ -0,0 +1,47 @@
+//
+// PangoExtensions.cs
+// 
+// Author:
+//   Aaron Bockover <abockover novell com>
+// 
+// Copyright 2009 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 Pango;
+
+namespace Hyena.Gui
+{
+    public static class PangoExtensions
+    {
+        public static int MeasureTextHeight (this FontDescription description, Context context)
+        {
+            return MeasureTextHeight (description, context, context.Language);
+        }
+
+        public static int MeasureTextHeight (this FontDescription description, Context context, Language language)
+        {
+            using (var metrics = context.GetMetrics (description, language)) {
+                return ((int)(metrics.Ascent + metrics.Descent) + 512) >> 10; // PANGO_PIXELS (d)
+            }
+        }
+    }
+}
diff --git a/src/Libraries/Hyena.Gui/Makefile.am b/src/Libraries/Hyena.Gui/Makefile.am
index 406cc5d..fad6382 100644
--- a/src/Libraries/Hyena.Gui/Makefile.am
+++ b/src/Libraries/Hyena.Gui/Makefile.am
@@ -62,6 +62,7 @@ SOURCES =  \
 	Hyena.Gui/GtkUtilities.cs \
 	Hyena.Gui/GtkWorkarounds.cs \
 	Hyena.Gui/PangoCairoHelper.cs \
+	Hyena.Gui/PangoExtensions.cs \
 	Hyena.Gui/PixbufImageSurface.cs \
 	Hyena.Gui/RatingRenderer.cs \
 	Hyena.Gui/ShadingTestWindow.cs \



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