[f-spot/icon-view-cleanup: 13/24] Move render code for the thumbnail decorations to own classes



commit b5c94bd21c923d45f370c7cb5dbfeb0e955ef841
Author: Mike Gemünde <mike gemuende de>
Date:   Sat Aug 14 19:19:35 2010 +0200

    Move render code for the thumbnail decorations to own classes

 src/Clients/MainApp/FSpot.Widgets/CellGridView.cs  |    2 +
 src/Clients/MainApp/FSpot.Widgets/IconView.cs      |  555 +++++++-------------
 .../FSpot.Widgets/ThumbnailCaptionRenderer.cs      |   49 ++
 .../FSpot.Widgets/ThumbnailDateCaptionRenderer.cs  |   91 ++++
 .../FSpot.Widgets/ThumbnailDecorationRenderer.cs   |   47 ++
 .../ThumbnailFilenameCaptionRenderer.cs            |   39 ++
 .../ThumbnailRatingDecorationRenderer.cs           |   62 +++
 .../FSpot.Widgets/ThumbnailTagsCaptionRenderer.cs  |  123 +++++
 .../FSpot.Widgets/ThumbnailTextCaptionRenderer.cs  |   73 +++
 src/Clients/MainApp/FSpot.Widgets/TrayView.cs      |    3 -
 src/Clients/MainApp/Makefile.am                    |    7 +
 11 files changed, 677 insertions(+), 374 deletions(-)
---
diff --git a/src/Clients/MainApp/FSpot.Widgets/CellGridView.cs b/src/Clients/MainApp/FSpot.Widgets/CellGridView.cs
index 9805ef3..5e327f0 100644
--- a/src/Clients/MainApp/FSpot.Widgets/CellGridView.cs
+++ b/src/Clients/MainApp/FSpot.Widgets/CellGridView.cs
@@ -135,6 +135,8 @@ namespace FSpot.Widgets
         private double scroll_value;
         // suppress scroll is currently not used. where do we need it?
         private bool suppress_scroll = false;
+        // Size of the frame that may be selected
+        protected int cell_border_padding = 3;
 
 #endregion
 
diff --git a/src/Clients/MainApp/FSpot.Widgets/IconView.cs b/src/Clients/MainApp/FSpot.Widgets/IconView.cs
index 3d8eee7..37f55ce 100644
--- a/src/Clients/MainApp/FSpot.Widgets/IconView.cs
+++ b/src/Clients/MainApp/FSpot.Widgets/IconView.cs
@@ -1,39 +1,75 @@
 /*
-* Widgets/IconView.cs
-*
-* Author(s):
-* 	Etore Perazzoli
-*	Larry Ewing <lewing novell com>
-*	Stephane Delcroix <stephane delcroix org>
-*
-* This is free software. See COPYING for details.
-*/
+ * IconView.cs
+ *
+ * Author(s)
+ *  Etore Perazzoli
+ *  Larry Ewing <lewing novell com>
+ *  Stephane Delcroix <stephane delcroix org>
+ *  Mike Gemuende <mike gemuende de>
+ *
+ * This is free software. See COPYING for details.
+ */
 
-using Gtk;
-using Gdk;
 using System;
-using System.Reflection;
-using System.Collections;
 using System.IO;
 
+using Gtk;
+using Gdk;
+
 using Hyena.Gui;
 
 using FSpot.Core;
 using FSpot.Utils;
 using FSpot.Platform;
 
+
 namespace FSpot.Widgets
 {
 
-	public class IconView : CollectionGridView
+    public class IconView : CollectionGridView
     {
 
-		// Public properties.
-		FSpot.PixbufCache cache;
+#region Private Fields
+
+        private FSpot.PixbufCache cache;
+
+        private ThumbnailDecorationRenderer rating_renderer = new ThumbnailRatingDecorationRenderer ();
+
+        private ThumbnailCaptionRenderer tag_renderer = new ThumbnailTagsCaptionRenderer ();
+        private ThumbnailCaptionRenderer date_renderer = new ThumbnailDateCaptionRenderer ();
+        private ThumbnailCaptionRenderer filename_renderer = new ThumbnailFilenameCaptionRenderer ();
+
+#endregion
+
+#region Properties
+
+        public FSpot.PixbufCache Cache {
+            get { return cache; }
+        }
+
+#endregion
+
+#region Constructors
+
+        public IconView (IntPtr raw) : base (raw) {}
+
+        public IconView (IBrowsableCollection collection) : base (collection)
+        {
+            cache = new FSpot.PixbufCache ();
+            cache.OnPixbufLoaded += HandlePixbufLoaded;
+
+            Name = "ImageContainer";
+            Collection.ItemsChanged += HandleItemsChanged;
+
+            ScrollEvent += new ScrollEventHandler (HandleScrollEvent);
+
+            Destroyed += HandleDestroyed;
+        }
+
+#endregion
 
 #region Public Events
 
-        // Public events.
         public event EventHandler ZoomChanged;
 
 #endregion
@@ -44,6 +80,16 @@ namespace FSpot.Widgets
         protected const double ZOOM_FACTOR = 1.2;
         protected const int MAX_THUMBNAIL_WIDTH = 256;
         protected const int MIN_THUMBNAIL_WIDTH = 64;
+        // size of the border of the whole pane
+        protected const int BORDER_SIZE = 6;
+        protected const int SELECTION_THICKNESS = 5;
+
+        // frame around the whole cell
+        protected const int CELL_BORDER_WIDTH = 10;
+
+        // padding between the thumbnail and the thumbnail caption
+        protected const int CAPTION_PADDING = 6;
+
 
         // current with of the thumbnails. (height is calculated)
         private int thumbnail_width = 128;
@@ -88,7 +134,6 @@ namespace FSpot.Widgets
             get { return (int) Math.Round ((double) thumbnail_width / ThumbnailRatio); }
         }
 
-
         public void ZoomIn ()
         {
             ThumbnailWidth = (int) (ThumbnailWidth * ZOOM_FACTOR);
@@ -105,32 +150,26 @@ namespace FSpot.Widgets
 
         protected override int CellHeight {
             get {
-                int cell_height = ThumbnailHeight + 2 * cell_border_width;
-
-                cell_details = 0;
+                int cell_height = ThumbnailHeight + 2 * CELL_BORDER_WIDTH;
 
                 if (DisplayTags || DisplayDates || DisplayFilenames)
-                    cell_details += tag_icon_vspacing;
-    
+                    cell_height += CAPTION_PADDING;
+
                 if (DisplayTags)
-                    cell_details += tag_icon_size;
+                    cell_height += tag_renderer.GetHeight (this, ThumbnailWidth);
 
-                if (DisplayDates && Style != null) {
-                    cell_details += Style.FontDescription.MeasureTextHeight (PangoContext);
-                }
-    
-                if (DisplayFilenames && Style != null) {
-                    cell_details += Style.FontDescription.MeasureTextHeight (PangoContext);
-                }
+                if (DisplayDates && Style != null)
+                    cell_height += date_renderer.GetHeight (this, ThumbnailWidth);
 
-                cell_height += cell_details;
+                if (DisplayFilenames && Style != null)
+                    cell_height += filename_renderer.GetHeight (this, ThumbnailWidth);
 
                 return cell_height;
             }
         }
 
         protected override int CellWidth {
-            get { return ThumbnailWidth + 2 * cell_border_width; }
+            get { return ThumbnailWidth + 2 * CELL_BORDER_WIDTH; }
         }
 
         protected override int MaxColumns {
@@ -143,11 +182,6 @@ namespace FSpot.Widgets
 
 #endregion
 
-
-		public FSpot.PixbufCache Cache {
-			get { return cache; }
-		}
-
 		private bool display_tags = true;
 		public bool DisplayTags {
 			get {
@@ -201,46 +235,7 @@ namespace FSpot.Widgets
 			}
 		}
 
-		// Size of the frame around the thumbnail.
-		protected int cell_border_width = 10;
-
-		// Size of the frame that may be selected
-        protected int cell_border_padding = 3;
-
-		// Border around the scrolled area.
-		protected const int BORDER_SIZE = 6;
-
-		// Thickness of the outline used to indicate selected items.
-		private const int SELECTION_THICKNESS = 5;
-
-		// Size of the tag icon in the view.
-		protected int tag_icon_size = 16;
-
-		// Horizontal spacing between the tag icons
-		protected int tag_icon_hspacing = 2;
-
-		// Vertical spacing between the thumbnail and additional infos (tags, dates, ...).
-		protected int tag_icon_vspacing = 3;
-
-		// Various other layout values.
-		protected int cell_details;
-
-		// Public API.
-		public IconView (IntPtr raw) : base (raw) {}
-
-		public IconView (IBrowsableCollection collection) : base (collection)
-		{
-            cache = new FSpot.PixbufCache ();
-            cache.OnPixbufLoaded += HandlePixbufLoaded;
-
-			Name = "ImageContainer";
-			Collection.ItemsChanged += HandleItemsChanged;
-
-            ScrollEvent += new ScrollEventHandler(HandleScrollEvent);
-
-            Destroyed += HandleDestroyed;
-		}
-
+#region Event Handlers
 
         private void HandleItemsChanged (IBrowsableCollection sender, BrowsableEventArgs args)
         {
@@ -251,129 +246,76 @@ namespace FSpot.Widgets
             }
         }
 
-
-		// Updating.
-		public void UpdateThumbnail (int thumbnail_num)
-		{
-			IPhoto photo = Collection [thumbnail_num];
-			cache.Remove (photo.DefaultVersion.Uri);
-			InvalidateCell (thumbnail_num);
-		}
-
-
-		// Layout and drawing.
-/*		protected virtual void UpdateLayout ()
-		{
-			UpdateLayout (Allocation);
-		}
-
-		protected virtual void UpdateLayout (Gdk.Rectangle allocation)
-		{
-			int available_width = allocation.Width - 2 * BORDER_SIZE;
-			int available_height = allocation.Height - 2 * BORDER_SIZE;
-			cell_width = ThumbnailWidth + 2 * cell_border_width;
-			cell_height = ThumbnailHeight + 2 * cell_border_width;
-			cells_per_row = Math.Max ((int) (available_width / cell_width), 1);
-			cell_width += (available_width - cells_per_row * cell_width) / cells_per_row;
-			cell_details = 0;
-
-			if (DisplayTags || DisplayDates || DisplayFilenames)
-				cell_details += tag_icon_vspacing;
-
-			if (DisplayTags)
-				cell_details += tag_icon_size;
-
-            if (DisplayDates && Style != null) {
-                cell_details += Style.FontDescription.MeasureTextHeight (PangoContext);
-            }
-
-            if (DisplayFilenames && Style != null) {
-                cell_details += Style.FontDescription.MeasureTextHeight (PangoContext);
+        private void HandlePixbufLoaded (FSpot.PixbufCache cache, FSpot.PixbufCache.CacheEntry entry)
+        {
+            Gdk.Pixbuf result = entry.ShallowCopyPixbuf ();
+            int order = (int) entry.Data;
+
+            if (result == null)
+                return;
+
+            // We have to do the scaling here rather than on load because we need to preserve the
+            // Pixbuf option iformation to verify the thumbnail validity later
+            int width, height;
+            PixbufUtils.Fit (result, ThumbnailWidth, ThumbnailHeight, false, out width, out height);
+            if (result.Width > width && result.Height > height) {
+                //  Log.Debug ("scaling");
+                Gdk.Pixbuf temp = PixbufUtils.ScaleDown (result, width, height);
+                result.Dispose ();
+                result = temp;
+            } else if (result.Width < ThumbnailWidth && result.Height < ThumbnailHeight) {
+                // FIXME this is a workaround to handle images whose actual size is smaller than
+                // the thumbnail size, it needs to be fixed at a different level.
+                Gdk.Pixbuf temp = new Gdk.Pixbuf (Gdk.Colorspace.Rgb, true, 8, ThumbnailWidth, ThumbnailHeight);
+                temp.Fill (0x00000000);
+                result.CopyArea (0, 0,
+                        result.Width, result.Height,
+                        temp,
+                        (temp.Width - result.Width)/ 2,
+                        temp.Height - result.Height);
+
+                result.Dispose ();
+                result = temp;
             }
 
-			cell_height += cell_details;
-
-			displayed_rows = (int)Math.Max (available_height / cell_height, 1);
-
-			int num_thumbnails;
-			if (collection != null)
-				num_thumbnails = collection.Count;
-			else
-				num_thumbnails = 0;
-
-			int num_rows = num_thumbnails / cells_per_row;
-			if (num_thumbnails % cells_per_row != 0)
-				num_rows ++;
-
-			int height = num_rows * cell_height + 2 * BORDER_SIZE;
-
-			Vadjustment.StepIncrement = cell_height;
-			int x = (int)(Hadjustment.Value);
-			int y = (int)(height * scroll_value);
-			SetSize (x, y, (int) allocation.Width, (int) height);
-		}
-
-		void SetSize (int x, int y, int width, int height)
-		{
-			bool xchange = false;
-			bool ychange = false;
-
-			Hadjustment.Upper = System.Math.Max (Allocation.Width, width);
-			Vadjustment.Upper = System.Math.Max (Allocation.Height, height);
-
-			if (scroll) {
-				xchange = (int)(Hadjustment.Value) != x;
-				ychange = (int)(Vadjustment.Value) != y;
-				scroll = false;
-			}
-
-			if (IsRealized)
-				BinWindow.FreezeUpdates ();
-
-			if (xchange || ychange) {
-				if (IsRealized)
-					BinWindow.MoveResize (-x, -y, (int)(Hadjustment.Upper), (int)(Vadjustment.Upper));
-				Vadjustment.Value = y;
-				Hadjustment.Value = x;
-			}
-
-			if (scroll)
-				scroll = false;
-
-			if (this.Width != Allocation.Width || this.Height != Allocation.Height)
-				SetSize ((uint)Allocation.Width, (uint)height);
+            cache.Update (entry, result);
+            InvalidateCell (order);
+        }
 
-			if (xchange || ychange) {
-				Vadjustment.ChangeValue ();
-				Hadjustment.ChangeValue ();
-			}
+        private void HandleScrollEvent(object sender, ScrollEventArgs args)
+        {
+            // Activated only by Control + ScrollWheelUp/ScrollWheelDown
+            if (ModifierType.ControlMask != (args.Event.State & ModifierType.ControlMask))
+                return;
+
+            if (args.Event.Direction == ScrollDirection.Up) {
+                ZoomIn ();
+                // stop event from propagating.
+                args.RetVal = true;
+            } else if (args.Event.Direction == ScrollDirection.Down ) {
+                ZoomOut ();
+                args.RetVal = true;
+            }
+        }
 
-			if (IsRealized) {
-				BinWindow.ThawUpdates ();
-				BinWindow.ProcessUpdates (true);
-			}
-		}*/
+        private void HandleDestroyed (object sender, System.EventArgs args)
+        {
+            cache.OnPixbufLoaded -= HandlePixbufLoaded;
+            CancelThrob ();
+        }
 
-		int ThrobExpansion (int cell, bool selected)
-		{
-			int expansion = 0;
-			if (cell == throb_cell) {
-				double t = throb_state / (double) (throb_state_max - 1);
-				double s;
-				if (selected)
-					s = Math.Cos (-2 * Math.PI * t);
-				else
-					s = 1 - Math.Cos (-2 * Math.PI * t);
+#endregion
 
-				expansion = (int) (SELECTION_THICKNESS * s);
-			} else if (selected) {
-				expansion = SELECTION_THICKNESS;
-			}
+#region Drawing Methods
 
-			return expansion;
-		}
+        // Updating.
+        public void UpdateThumbnail (int thumbnail_num)
+        {
+            IPhoto photo = Collection [thumbnail_num];
+            cache.Remove (photo.DefaultVersion.Uri);
+            InvalidateCell (thumbnail_num);
+        }
 
-		System.Collections.Hashtable date_layouts = new Hashtable ();
 		// FIXME Cache the GCs?
 		protected override void DrawPhoto (int cell_num, Rectangle cell_area, Rectangle expose_area, bool selected, bool focussed)
 		{
@@ -407,7 +349,7 @@ namespace FSpot.Widgets
 			}
 
 			Gdk.Rectangle region = Gdk.Rectangle.Zero;
-			Gdk.Rectangle image_bounds = Gdk.Rectangle.Inflate (cell_area, -cell_border_width, -cell_border_width);
+			Gdk.Rectangle image_bounds = Gdk.Rectangle.Inflate (cell_area, -CELL_BORDER_WIDTH, -CELL_BORDER_WIDTH);
 			int expansion = ThrobExpansion (cell_num, selected);
 
 			Gdk.Pixbuf thumbnail = null;
@@ -421,7 +363,7 @@ namespace FSpot.Widgets
 						true, out region.Width, out region.Height);
 
 				region.X = (int) (cell_area.X + (cell_area.Width - region.Width) / 2);
-				region.Y = (int) cell_area.Y + ThumbnailHeight - region.Height + cell_border_width;
+				region.Y = (int) cell_area.Y + ThumbnailHeight - region.Height + CELL_BORDER_WIDTH;
 
 				if (Math.Abs (region.Width - thumbnail.Width) > 1
 					&& Math.Abs (region.Height - thumbnail.Height) > 1)
@@ -497,129 +439,38 @@ namespace FSpot.Widgets
 			if (thumbnail != null) {
 				thumbnail.Dispose ();
 			}
-			if (DisplayRatings && photo.Rating > 0 && region.X == draw.X && region.X != 0) {
-				FSpot.Widgets.RatingSmall rating;
-				rating = new FSpot.Widgets.RatingSmall ((int) photo.Rating, false);
-				rating.DisplayPixbuf.RenderToDrawable (BinWindow, Style.WhiteGC,
-						0, 0, region.X, region.Y, -1, -1, RgbDither.None, 0, 0);
-
-			}
-			Gdk.Rectangle layout_bounds = Gdk.Rectangle.Zero;
-			if (DisplayDates) {
-				string date;
-				try {
-					if (CellWidth > 200) {
-						date = photo.Time.ToString ();
-					} else {
-						date = photo.Time.ToShortDateString ();
-					}
-				} catch (Exception) {
-					date = String.Empty;
-				}
-
-				Pango.Layout layout = (Pango.Layout)date_layouts [date];
-				if (layout == null) {
-					layout = new Pango.Layout (this.PangoContext);
-					layout.SetText (date);
-					date_layouts [date] = layout;
-				}
-
-				layout.GetPixelSize (out layout_bounds.Width, out layout_bounds.Height);
-
-				layout_bounds.Y = cell_area.Y + cell_area.Height -
-					cell_border_width - layout_bounds.Height + tag_icon_vspacing;
-				layout_bounds.X = cell_area.X + (cell_area.Width - layout_bounds.Width) / 2;
-
-				if (DisplayTags)
-					layout_bounds.Y -= tag_icon_size;
-
-				if (DisplayFilenames) {
-					layout_bounds.Y -= Style.FontDescription.MeasureTextHeight (PangoContext);
-				}
-
-				if (layout_bounds.Intersect (expose_area, out region)) {
-					Style.PaintLayout (Style, BinWindow, cell_state,
-							true, expose_area, this, "IconView",
-							layout_bounds.X, layout_bounds.Y,
-							layout);
-				}
-			}
-
-			if (DisplayFilenames) {
-
-				string filename = System.IO.Path.GetFileName (photo.DefaultVersion.Uri.LocalPath);
-				Pango.Layout layout = new Pango.Layout (this.PangoContext);
-				layout.SetText (filename);
-
-				layout.GetPixelSize (out layout_bounds.Width, out layout_bounds.Height);
-
-				layout_bounds.Y = cell_area.Y + cell_area.Height - cell_border_width - layout_bounds.Height + tag_icon_vspacing;
-				layout_bounds.X = cell_area.X + (cell_area.Width - layout_bounds.Width) / 2;
-
-				if (DisplayTags)
-					layout_bounds.Y -= tag_icon_size;
-
-				if (layout_bounds.Intersect (expose_area, out region)) {
-					Style.PaintLayout (Style, BinWindow, cell_state,
-							true, expose_area, this, "IconView",
-							layout_bounds.X, layout_bounds.Y,
-							layout);
-				}
-
-			}
 
-			if (DisplayTags) {
-				Tag [] tags = photo.Tags;
-				Gdk.Rectangle tag_bounds;
+            // Render Decorations
+            if (DisplayRatings) {
+                rating_renderer.Render (BinWindow, this, region, expose_area, cell_state, photo);
+            }
 
-				tag_bounds.X = cell_area.X + (cell_area.Width  + tag_icon_hspacing - tags.Length * (tag_icon_size + tag_icon_hspacing)) / 2;
-				tag_bounds.Y = cell_area.Y + cell_area.Height - cell_border_width - tag_icon_size + tag_icon_vspacing;
-				tag_bounds.Width = tag_icon_size;
-				tag_bounds.Height = tag_icon_size;
+            // Render Captions
+            Rectangle caption_area = Rectangle.Zero;
+            caption_area.Y = cell_area.Y + CELL_BORDER_WIDTH + ThumbnailHeight + CAPTION_PADDING;
+            caption_area.X = cell_area.X + CELL_BORDER_WIDTH;
+            caption_area.Width = cell_area.Width - 2 * CELL_BORDER_WIDTH;
 
-				foreach (Tag t in tags) {
-					if (t == null)
-						continue;
+            if (DisplayDates) {
+                caption_area.Height = date_renderer.GetHeight (this, ThumbnailWidth);
+                date_renderer.Render (BinWindow, this, caption_area, expose_area, cell_state, photo);
 
-					Pixbuf icon = t.Icon;
+                caption_area.Y += caption_area.Height;
+            }
 
-					Tag tag_iter = t.Category;
-					while (icon == null && tag_iter != App.Instance.Database.Tags.RootCategory && tag_iter != null) {
-						icon = tag_iter.Icon;
-						tag_iter = tag_iter.Category;
-					}
+            if (DisplayFilenames) {
+                caption_area.Height = filename_renderer.GetHeight (this, ThumbnailWidth);
+                filename_renderer.Render (BinWindow, this, caption_area, expose_area, cell_state, photo);
 
-					if (icon == null)
-						continue;
-
-					if (tag_bounds.Intersect (expose_area, out region)) {
-						Pixbuf scaled_icon;
-						if (icon.Width == tag_bounds.Width) {
-							scaled_icon = icon;
-						} else {
-							scaled_icon = icon.ScaleSimple (tag_bounds.Width,
-									tag_bounds.Height,
-									InterpType.Bilinear);
-						}
+                caption_area.Y += caption_area.Height;
+            }
 
-						Cms.Profile screen_profile;
-						if (FSpot.ColorManagement.Profiles.TryGetValue (Preferences.Get<string> (Preferences.COLOR_MANAGEMENT_DISPLAY_PROFILE), out screen_profile))
-							FSpot.ColorManagement.ApplyProfile (scaled_icon, screen_profile);
-
-						scaled_icon.RenderToDrawable (BinWindow, Style.WhiteGC,
-								region.X - tag_bounds.X,
-								region.Y - tag_bounds.Y,
-								region.X, region.Y,
-								region.Width, region.Height,
-								RgbDither.None, region.X, region.Y);
-						if (scaled_icon != icon) {
-							scaled_icon.Dispose ();
-						}
-					}
-					tag_bounds.X += tag_bounds.Width + tag_icon_hspacing;
-				}
-			}
+            if (DisplayTags) {
+                caption_area.Height = tag_renderer.GetHeight (this, ThumbnailWidth);
+                tag_renderer.Render (BinWindow, this, caption_area, expose_area, cell_state, photo);
 
+                caption_area.Y += caption_area.Height;
+            }
 		}
 
         protected override void PreloadCell (int cell_num)
@@ -631,9 +482,11 @@ namespace FSpot.Widgets
                 cache.Request (photo.DefaultVersion.Uri, cell_num, ThumbnailWidth, ThumbnailHeight);
         }
 
-		//
-		// The throb interface
-		//
+#endregion
+
+
+#region Throb Interface
+
 		private uint throb_timer_id;
 		private int throb_cell = -1;
 		private int throb_state;
@@ -668,61 +521,26 @@ namespace FSpot.Widgets
 		}
 
 
+        int ThrobExpansion (int cell, bool selected)
+        {
+            int expansion = 0;
+            if (cell == throb_cell) {
+                double t = throb_state / (double) (throb_state_max - 1);
+                double s;
+                if (selected)
+                    s = Math.Cos (-2 * Math.PI * t);
+                else
+                    s = 1 - Math.Cos (-2 * Math.PI * t);
+
+                expansion = (int) (SELECTION_THICKNESS * s);
+            } else if (selected) {
+                expansion = SELECTION_THICKNESS;
+            }
 
-		// Event handlers.
-
-		private void HandlePixbufLoaded (FSpot.PixbufCache cache, FSpot.PixbufCache.CacheEntry entry)
-		{
-			Gdk.Pixbuf result = entry.ShallowCopyPixbuf ();
-			int order = (int) entry.Data;
-
-			if (result == null)
-				return;
-
-			// We have to do the scaling here rather than on load because we need to preserve the
-			// Pixbuf option iformation to verify the thumbnail validity later
-			int width, height;
-			PixbufUtils.Fit (result, ThumbnailWidth, ThumbnailHeight, false, out width, out height);
-			if (result.Width > width && result.Height > height) {
-				//  Log.Debug ("scaling");
-				Gdk.Pixbuf temp = PixbufUtils.ScaleDown (result, width, height);
-				result.Dispose ();
-				result = temp;
-			} else if (result.Width < ThumbnailWidth && result.Height < ThumbnailHeight) {
-				// FIXME this is a workaround to handle images whose actual size is smaller than
-				// the thumbnail size, it needs to be fixed at a different level.
-				Gdk.Pixbuf temp = new Gdk.Pixbuf (Gdk.Colorspace.Rgb, true, 8, ThumbnailWidth, ThumbnailHeight);
-				temp.Fill (0x00000000);
-				result.CopyArea (0, 0,
-						result.Width, result.Height,
-						temp,
-						(temp.Width - result.Width)/ 2,
-						temp.Height - result.Height);
-
-				result.Dispose ();
-				result = temp;
-			}
-
-			cache.Update (entry, result);
-			InvalidateCell (order);
-		}
-
-
-		private void HandleScrollEvent(object sender, ScrollEventArgs args)
-		{
-			// Activated only by Control + ScrollWheelUp/ScrollWheelDown
-			if (ModifierType.ControlMask != (args.Event.State & ModifierType.ControlMask))
-				return;
+            return expansion;
+        }
 
-			if (args.Event.Direction == ScrollDirection.Up) {
-				ZoomIn ();
-				// stop event from propagating.
-				args.RetVal = true;
-			} else if (args.Event.Direction == ScrollDirection.Down ) {
-				ZoomOut ();
-				args.RetVal = true;
-			}
-		}
+#endregion
 
 		private void SetColors ()
 		{
@@ -749,10 +567,5 @@ namespace FSpot.Widgets
 			SetColors ();
 		}
 
-		private void HandleDestroyed (object sender, System.EventArgs args)
-		{
-			cache.OnPixbufLoaded -= HandlePixbufLoaded;
-			CancelThrob ();
-		}
 	}
 }
diff --git a/src/Clients/MainApp/FSpot.Widgets/ThumbnailCaptionRenderer.cs b/src/Clients/MainApp/FSpot.Widgets/ThumbnailCaptionRenderer.cs
new file mode 100644
index 0000000..d96e5a1
--- /dev/null
+++ b/src/Clients/MainApp/FSpot.Widgets/ThumbnailCaptionRenderer.cs
@@ -0,0 +1,49 @@
+/*
+ * ThumbnailCaptionRenderer.cs
+ *
+ * Author(s)
+ *  Mike Gemuende <mike gemuende de>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using System;
+
+using Gtk;
+using Gdk;
+
+using FSpot.Core;
+
+
+namespace FSpot.Widgets
+{
+    /// <summary>
+    ///    Renders a caption below a thumbnail. It must compute the height needed for
+    ///    the annotation.
+    /// </summary>
+    public abstract class ThumbnailCaptionRenderer
+    {
+
+#region Constructor
+
+        public ThumbnailCaptionRenderer ()
+        {
+        }
+
+#endregion
+
+#region Drawing Methods
+
+        public abstract int GetHeight (Widget widget, int width);
+
+        public abstract void Render (Drawable window,
+                                     Widget widget,
+                                     Rectangle cell_area,
+                                     Rectangle expose_area,
+                                     StateType cell_state,
+                                     IPhoto photo);
+
+#endregion
+
+    }
+}
diff --git a/src/Clients/MainApp/FSpot.Widgets/ThumbnailDateCaptionRenderer.cs b/src/Clients/MainApp/FSpot.Widgets/ThumbnailDateCaptionRenderer.cs
new file mode 100644
index 0000000..a8b795d
--- /dev/null
+++ b/src/Clients/MainApp/FSpot.Widgets/ThumbnailDateCaptionRenderer.cs
@@ -0,0 +1,91 @@
+/*
+ * ThumbnailDateCaptionRenderer.cs
+ *
+ * Author(s)
+ *  Mike Gemuende <mike gemuende de>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using System;
+using System.Collections.Generic;
+
+using Gtk;
+using Gdk;
+
+using Hyena.Gui;
+
+using FSpot.Core;
+
+
+namespace FSpot.Widgets
+{
+    /// <summary>
+    ///    Renders a text caption with the date of the photo. This class is not based on
+    ///    TextCaptionRenderer, because it uses caching of the dates.
+    /// </summary>
+    public class ThumbnailDateCaptionRenderer : ThumbnailCaptionRenderer
+    {
+
+#region Private Fields
+
+        private Dictionary <string, Pango.Layout> cache = new Dictionary <string, Pango.Layout> ();
+
+#endregion
+
+#region Constructor
+
+        public ThumbnailDateCaptionRenderer ()
+        {
+        }
+
+#endregion
+
+#region Drawing Methods
+
+        public override int GetHeight (Widget widget, int width)
+        {
+            return widget.Style.FontDescription.MeasureTextHeight (widget.PangoContext);
+        }
+
+        public override void Render (Drawable window,
+                                     Widget widget,
+                                     Rectangle cell_area,
+                                     Rectangle expose_area,
+                                     StateType cell_state,
+                                     IPhoto photo)
+        {
+            string date_text = null;
+
+            if (cell_area.Width > 200) {
+                date_text = photo.Time.ToString ();
+            } else {
+                date_text = photo.Time.ToShortDateString ();
+            }
+
+            Pango.Layout layout = null;
+            if ( ! cache.TryGetValue (date_text, out layout)) {
+                layout = new Pango.Layout (widget.PangoContext);
+                layout.SetText (date_text);
+
+                cache.Add (date_text, layout);
+            }
+
+            Rectangle layout_bounds;
+            layout.GetPixelSize (out layout_bounds.Width, out layout_bounds.Height);
+
+            layout_bounds.Y = cell_area.Y;
+            layout_bounds.X = cell_area.X + (cell_area.Width - layout_bounds.Width) / 2;
+
+            if (layout_bounds.IntersectsWith (expose_area)) {
+                Style.PaintLayout (widget.Style, window, cell_state,
+                                   true, expose_area, widget, "IconView",
+                                   layout_bounds.X, layout_bounds.Y,
+                                   layout);
+            }
+        }
+
+#endregion
+
+    }
+}
diff --git a/src/Clients/MainApp/FSpot.Widgets/ThumbnailDecorationRenderer.cs b/src/Clients/MainApp/FSpot.Widgets/ThumbnailDecorationRenderer.cs
new file mode 100644
index 0000000..7fd78d4
--- /dev/null
+++ b/src/Clients/MainApp/FSpot.Widgets/ThumbnailDecorationRenderer.cs
@@ -0,0 +1,47 @@
+/*
+ * ThumbnailDecorationRenderer.cs
+ *
+ * Author(s)
+ *  Mike Gemuende <mike gemuende de>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using System;
+
+using Gtk;
+using Gdk;
+
+using FSpot.Core;
+
+
+namespace FSpot.Widgets
+{
+    /// <summary>
+    ///    This is a renderer for drawing annotations to a thumbnail. The annotations
+    ///    are rendered directly to the thumbnail and no previous size computation is needed.
+    /// </summary>
+    public abstract class ThumbnailDecorationRenderer
+    {
+
+#region Constructor
+
+        public ThumbnailDecorationRenderer ()
+        {
+        }
+
+#endregion
+
+#region Drawing Methods
+
+        public abstract void Render (Drawable window,
+                                     Widget widget,
+                                     Rectangle cell_area,
+                                     Rectangle expose_area,
+                                     StateType cell_state,
+                                     IPhoto photo);
+
+#endregion
+
+    }
+}
diff --git a/src/Clients/MainApp/FSpot.Widgets/ThumbnailFilenameCaptionRenderer.cs b/src/Clients/MainApp/FSpot.Widgets/ThumbnailFilenameCaptionRenderer.cs
new file mode 100644
index 0000000..d591d2d
--- /dev/null
+++ b/src/Clients/MainApp/FSpot.Widgets/ThumbnailFilenameCaptionRenderer.cs
@@ -0,0 +1,39 @@
+/*
+ * ThumbnailFilenameCaptionRenderer.cs
+ *
+ * Author(s)
+ *  Mike Gemuende <mike gemuende de>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using System;
+using System.IO;
+
+using FSpot.Core;
+
+
+namespace FSpot.Widgets
+{
+
+    public class ThumbnailFilenameCaptionRenderer : ThumbnailTextCaptionRenderer
+    {
+#region Constructor
+
+        public ThumbnailFilenameCaptionRenderer ()
+        {
+        }
+
+#endregion
+
+#region Drawing Methods
+
+        protected override string GetRenderText (IPhoto photo)
+        {
+            return Path.GetFileName (photo.DefaultVersion.Uri.LocalPath);
+        }
+
+#endregion
+
+    }
+}
diff --git a/src/Clients/MainApp/FSpot.Widgets/ThumbnailRatingDecorationRenderer.cs b/src/Clients/MainApp/FSpot.Widgets/ThumbnailRatingDecorationRenderer.cs
new file mode 100644
index 0000000..d96e768
--- /dev/null
+++ b/src/Clients/MainApp/FSpot.Widgets/ThumbnailRatingDecorationRenderer.cs
@@ -0,0 +1,62 @@
+/*
+ * ThumbnailRatingDecorationRenderer.cs
+ *
+ * Author(s)
+ *  Mike Gemuende <mike gemuende de>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using System;
+
+using Gtk;
+using Gdk;
+
+using FSpot.Core;
+
+
+namespace FSpot.Widgets
+{
+
+    /// <summary>
+    ///    Renders the Rating of a photo as stars to the top left of the thumbnail.
+    /// </summary>
+    public class ThumbnailRatingDecorationRenderer : ThumbnailDecorationRenderer
+    {
+
+#region Private Fields
+
+        RatingSmall rating = new RatingSmall (false);
+
+#endregion
+
+#region Constructor
+
+        public ThumbnailRatingDecorationRenderer ()
+        {
+        }
+
+#endregion
+
+#region Drawing Methods
+
+        public override void Render (Drawable window,
+                                     Widget widget,
+                                     Rectangle cell_area,
+                                     Rectangle expose_area,
+                                     StateType cell_state,
+                                     IPhoto photo)
+        {
+            if (photo.Rating > 0) {
+                rating.Value = (int) photo.Rating;
+
+                rating.DisplayPixbuf.RenderToDrawable (window, widget.Style.WhiteGC,
+                                                       0, 0, cell_area.X, cell_area.Y,
+                                                       -1, -1, RgbDither.None, 0, 0);
+            }
+        }
+
+#endregion
+
+    }
+}
\ No newline at end of file
diff --git a/src/Clients/MainApp/FSpot.Widgets/ThumbnailTagsCaptionRenderer.cs b/src/Clients/MainApp/FSpot.Widgets/ThumbnailTagsCaptionRenderer.cs
new file mode 100644
index 0000000..6b0e2cc
--- /dev/null
+++ b/src/Clients/MainApp/FSpot.Widgets/ThumbnailTagsCaptionRenderer.cs
@@ -0,0 +1,123 @@
+/*
+ * ThumbnailCaptionRenderer.cs
+ *
+ * Author(s)
+ *  Mike Gemuende <mike gemuende de>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using System;
+
+using Gtk;
+using Gdk;
+
+using FSpot.Core;
+
+
+namespace FSpot.Widgets
+{
+    public class ThumbnailTagsCaptionRenderer : ThumbnailCaptionRenderer
+    {
+
+#region private fields
+
+        private int tag_icon_size;
+
+        private int tag_icon_hspacing;
+
+#endregion
+
+#region Constructor
+
+        public ThumbnailTagsCaptionRenderer () : this (16)
+        {
+        }
+
+        public ThumbnailTagsCaptionRenderer (int tag_icon_size) : this (tag_icon_size, 2)
+        {
+        }
+
+        public ThumbnailTagsCaptionRenderer (int tag_icon_size, int tag_icon_hspacing)
+        {
+            this.tag_icon_size = tag_icon_size;
+            this.tag_icon_hspacing = tag_icon_hspacing;
+        }
+
+#endregion
+
+#region Drawing Methods
+
+        public override int GetHeight (Widget widget, int width)
+        {
+            return tag_icon_size;
+        }
+
+        public override void Render (Drawable window,
+                                     Widget widget,
+                                     Rectangle cell_area,
+                                     Rectangle expose_area,
+                                     StateType cell_state,
+                                     IPhoto photo)
+        {
+            Tag [] tags = photo.Tags;
+            Rectangle tag_bounds;
+
+            tag_bounds.X = cell_area.X + (cell_area.Width  + tag_icon_hspacing - tags.Length * (tag_icon_size + tag_icon_hspacing)) / 2;
+            tag_bounds.Y = cell_area.Y;// + cell_area.Height - cell_border_width - tag_icon_size + tag_icon_vspacing;
+            tag_bounds.Width = tag_icon_size;
+            tag_bounds.Height = tag_icon_size;
+
+
+            foreach (Tag t in tags) {
+
+                if (t == null)
+                    continue;
+
+                Pixbuf icon = t.Icon;
+
+                Tag tag_iter = t.Category;
+                while (icon == null && tag_iter != App.Instance.Database.Tags.RootCategory && tag_iter != null) {
+                    icon = tag_iter.Icon;
+                    tag_iter = tag_iter.Category;
+                }
+
+                if (icon == null)
+                    continue;
+
+                Rectangle region;
+                if (tag_bounds.Intersect (expose_area, out region)) {
+                    Pixbuf scaled_icon;
+                    if (icon.Width == tag_bounds.Width) {
+                        scaled_icon = icon;
+                    } else {
+                        scaled_icon = icon.ScaleSimple (tag_bounds.Width,
+                                tag_bounds.Height,
+                                InterpType.Bilinear);
+                    }
+
+                    Cms.Profile screen_profile;
+                    if (FSpot.ColorManagement.Profiles.TryGetValue (Preferences.Get<string> (Preferences.COLOR_MANAGEMENT_DISPLAY_PROFILE), out screen_profile))
+                        FSpot.ColorManagement.ApplyProfile (scaled_icon, screen_profile);
+
+                    scaled_icon.RenderToDrawable (window, widget.Style.WhiteGC,
+                            region.X - tag_bounds.X,
+                            region.Y - tag_bounds.Y,
+                            region.X, region.Y,
+                            region.Width, region.Height,
+                            RgbDither.None, region.X, region.Y);
+
+                    if (scaled_icon != icon) {
+                        scaled_icon.Dispose ();
+                    }
+                }
+
+                tag_bounds.X += tag_bounds.Width + tag_icon_hspacing;
+            }
+        }
+
+#endregion
+
+    }
+}
+
diff --git a/src/Clients/MainApp/FSpot.Widgets/ThumbnailTextCaptionRenderer.cs b/src/Clients/MainApp/FSpot.Widgets/ThumbnailTextCaptionRenderer.cs
new file mode 100644
index 0000000..67cbed0
--- /dev/null
+++ b/src/Clients/MainApp/FSpot.Widgets/ThumbnailTextCaptionRenderer.cs
@@ -0,0 +1,73 @@
+/*
+ * ThumbnailTextCaptionRenderer.cs
+ *
+ * Author(s)
+ *  Mike Gemuende <mike gemuende de>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using System;
+
+using Gtk;
+using Gdk;
+
+using Hyena.Gui;
+
+using FSpot.Core;
+
+
+namespace FSpot.Widgets
+{
+    /// <summary>
+    ///    Class to provide a single text line rendered as caption to a thumbnail.
+    /// </summary>
+    public abstract class ThumbnailTextCaptionRenderer : ThumbnailCaptionRenderer
+    {
+#region Constructor
+
+        public ThumbnailTextCaptionRenderer ()
+        {
+        }
+
+#endregion
+
+#region Drawing Methods
+
+        public override int GetHeight (Widget widget, int width)
+        {
+            return widget.Style.FontDescription.MeasureTextHeight (widget.PangoContext);
+        }
+
+        public override void Render (Drawable window,
+                                     Widget widget,
+                                     Rectangle cell_area,
+                                     Rectangle expose_area,
+                                     StateType cell_state,
+                                     IPhoto photo)
+        {
+            string text = GetRenderText (photo);
+
+            var layout = new Pango.Layout (widget.PangoContext);
+            layout.SetText (text);
+
+            Rectangle layout_bounds;
+            layout.GetPixelSize (out layout_bounds.Width, out layout_bounds.Height);
+
+            layout_bounds.Y = cell_area.Y;
+            layout_bounds.X = cell_area.X + (cell_area.Width - layout_bounds.Width) / 2;
+
+            if (layout_bounds.IntersectsWith (expose_area)) {
+                Style.PaintLayout (widget.Style, window, cell_state,
+                                   true, expose_area, widget, "IconView",
+                                   layout_bounds.X, layout_bounds.Y,
+                                   layout);
+            }
+        }
+
+        protected abstract string GetRenderText (IPhoto photo);
+
+#endregion
+
+    }
+}
diff --git a/src/Clients/MainApp/FSpot.Widgets/TrayView.cs b/src/Clients/MainApp/FSpot.Widgets/TrayView.cs
index 50411c4..2f422be 100644
--- a/src/Clients/MainApp/FSpot.Widgets/TrayView.cs
+++ b/src/Clients/MainApp/FSpot.Widgets/TrayView.cs
@@ -20,9 +20,6 @@ namespace FSpot.Widgets
 		{
 			DisplayDates = false;
 			DisplayTags = false;
-			cell_border_width = 10;
-			tag_icon_vspacing = 0;
-			tag_icon_size = 0;
 		}
 
 /*		protected override void UpdateLayout ()
diff --git a/src/Clients/MainApp/Makefile.am b/src/Clients/MainApp/Makefile.am
index 6f05eb6..c8425c8 100644
--- a/src/Clients/MainApp/Makefile.am
+++ b/src/Clients/MainApp/Makefile.am
@@ -115,6 +115,13 @@ SOURCES =  \
 	FSpot.Widgets/TagMenu.cs \
 	FSpot.Widgets/TagView.cs \
 	FSpot.Widgets/Tests/FindBarTests.cs \
+	FSpot.Widgets/ThumbnailCaptionRenderer.cs \
+	FSpot.Widgets/ThumbnailDateCaptionRenderer.cs \
+	FSpot.Widgets/ThumbnailDecorationRenderer.cs \
+	FSpot.Widgets/ThumbnailFilenameCaptionRenderer.cs \
+	FSpot.Widgets/ThumbnailRatingDecorationRenderer.cs \
+	FSpot.Widgets/ThumbnailTagsCaptionRenderer.cs \
+	FSpot.Widgets/ThumbnailTextCaptionRenderer.cs \
 	FSpot.Widgets/TrayView.cs \
 	FSpot.Widgets/ViewContext.cs \
 	FSpot/Accelerometer.cs \



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