f-spot r3751 - trunk/src/Widgets



Author: sdelcroix
Date: Wed Mar 12 11:56:03 2008
New Revision: 3751
URL: http://svn.gnome.org/viewvc/f-spot?rev=3751&view=rev

Log:
missing file

Added:
   trunk/src/Widgets/Filmstrip.cs

Added: trunk/src/Widgets/Filmstrip.cs
==============================================================================
--- (empty file)
+++ trunk/src/Widgets/Filmstrip.cs	Wed Mar 12 11:56:03 2008
@@ -0,0 +1,561 @@
+/*
+ * Widgets.Filmstrip.cs
+ *
+ * Author(s)
+ * 	Stephane Delcroix  <stephane delcroix org>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+//TODO:
+//	* deal with vertical orientations (medium)
+//	* only redraw required parts on ExposeEvents (low)
+//	* Handle orientation changes (low) (require gtk# changes, so I can trigger an OrientationChanged event)
+
+using System;
+using System.Collections;
+
+using Gtk;
+using Gdk;
+
+namespace FSpot.Widgets
+{
+	public class Filmstrip : EventBox, IDisposable
+	{
+
+		public event OrientationChangedHandler OrientationChanged;
+		public event EventHandler PositionChanged;
+
+		bool extendable = true;
+		public bool Extendable {
+			get { return extendable; }
+			set { extendable = value; }
+		}
+
+		Orientation orientation = Orientation.Horizontal;
+		public Orientation Orientation {
+			get { return orientation; }
+			set {
+				if (orientation == value)
+					return;
+
+				throw new NotImplementedException ();
+				if (OrientationChanged != null) {
+					OrientationChangedArgs args = new OrientationChangedArgs ();
+					//args.Orientation = value;
+					//OrientationChanged (this, args);
+				}
+			}
+		}
+
+		int spacing = 6;
+		public int Spacing {
+			get { return spacing; }
+			set {
+				if (value < 0)
+					throw new ArgumentException ("Spacing is negative!");
+				spacing = value;
+			}
+		}
+
+		int thumb_offset = 17;
+		public int ThumbOffset {
+			get { return thumb_offset; }
+			set { 
+				if (value < 0)
+					throw new ArgumentException ("ThumbOffset is negative!");
+				thumb_offset = value;
+			}
+		}
+
+		int thumb_size = 67;
+		public int ThumbSize {
+			get { return thumb_size; }
+			set { 
+				if (value < 0)
+					throw new ArgumentException ("ThumbSize is negative!");
+				thumb_size = value;
+			}
+		}
+
+		static string [] film_100_xpm = {
+		"14 100 2 1",
+		" 	c None",
+		".	c #000000",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		".....    .....",
+		"....      ....",
+		"....      ....",
+		"....      ....",
+		"....      ....",
+		"....      ....",
+		"....      ....",
+		".....    .....",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		".....    .....",
+		"....      ....",
+		"....      ....",
+		"....      ....",
+		"....      ....",
+		"....      ....",
+		"....      ....",
+		".....    .....",
+		"..............",
+		"..............",
+		"..............",
+		"..............",
+		".............."};
+		Pixbuf background_tile;
+		public Pixbuf BackgroundTile {
+			get {
+				if (background_tile == null)
+					if (orientation == Orientation.Horizontal)
+						background_tile = new Pixbuf(film_100_xpm);
+					else
+						throw new NotImplementedException ("doesn't support Vertical orientation yet");
+				return background_tile;
+			}
+			set { 
+				if (background_tile != value && background_tile != null)
+					background_tile.Dispose ();
+				background_tile = value;
+				BackgroundPixbuf = null;
+			}
+		}
+
+		int x_offset = 2, y_offset = 2;
+		public int XOffset {
+			get { return x_offset; }
+			set { 
+				if (value < 0)
+					throw new ArgumentException ("value is negative!");
+				x_offset = value;
+			}
+		}
+
+		public int YOffset {
+			get { return y_offset; }
+			set { 
+				if (value < 0)
+					throw new ArgumentException ("value is negative!");
+				y_offset = value;
+			}
+		}
+
+		float x_align = 0.5f, y_align = 0.5f;
+		public float XAlign {
+			get { return x_align; }
+			set {
+				if (value < 0.0 || value > 1.0)
+					throw new ArgumentException ("value is not between 0.0 and 1.0");
+				x_align = value;
+			}
+		}
+
+		public float YAlign {
+			get { return y_align; }
+			set {
+				if (value < 0.0 || value > 1.0)
+					throw new ArgumentException ("value is not between 0.0 and 1.0");
+				y_align = value;
+			}
+		}
+
+		IAnimator animator;
+		IAnimator Animator {
+			get {
+				if (animator == null)
+					animator = new ConstantSpeedAnimator (this, OnPositionChanged);
+				return animator;
+			}
+		}
+		public int AnimatorOrder {
+			set {
+				switch (value) {
+				case 0:
+					animator = new DirectAnimator (OnPositionChanged);
+					break;
+				default:
+					throw new ArgumentException ("No animator of that order defined");
+				}
+			}
+		}
+
+		public int ActiveItem {
+			get { return selection.Index; }
+			set { selection.Index = value; }
+		}
+
+		float position;
+		public float Position {
+			get { 
+				position = Math.Min (position, selection.Collection.Count - 1);
+				return position; 
+			}
+			set {
+				if (value == position)
+					return;
+				if (value < 0)
+					value = 0;
+				if (value > selection.Collection.Count - 1)
+					value = selection.Collection.Count - 1;
+
+				Animator.MoveTo (value);
+				if (PositionChanged != null)
+					PositionChanged (this, EventArgs.Empty);
+			}
+		}
+
+		FSpot.BrowsablePointer selection;
+		ThumbnailCache thumb_cache;
+
+		public Filmstrip (FSpot.BrowsablePointer selection) : base ()
+		{
+			CanFocus = true;
+			this.selection = selection;
+			this.selection.Changed += HandlePointerChanged;
+			this.selection.Collection.Changed += HandleCollectionChanged;
+			this.selection.Collection.ItemsChanged += HandleCollectionItemsChanged;
+			thumb_cache = new ThumbnailCache (30);
+		}
+	
+		int min_length = 400;
+		protected override void OnSizeRequested (ref Gtk.Requisition requisition)
+		{
+			requisition.Width = min_length + 2 * x_offset;
+			if (min_length % BackgroundTile.Width != 0)
+				requisition.Width += BackgroundTile.Width - min_length % BackgroundTile.Width;	
+
+			requisition.Height = BackgroundTile.Height + (2 * y_offset);
+			base.OnSizeRequested(ref requisition);
+		}
+
+		Pixbuf background_pixbuf;
+		protected Pixbuf BackgroundPixbuf {
+			get {
+				if (background_pixbuf == null) {
+					int length;
+					if (Allocation.Width < min_length || !extendable)
+						length = min_length;
+					else
+						length = Allocation.Width;
+
+					length = length - length % BackgroundTile.Width;
+
+					background_pixbuf = new Pixbuf (Gdk.Colorspace.Rgb, true, 8, length, BackgroundTile.Height);
+					for (int i = 0; i < length; i += BackgroundTile.Width) {
+						BackgroundTile.CopyArea (0, 0, BackgroundTile.Width, BackgroundTile.Height, 
+								background_pixbuf, i, 0);
+					}
+				}
+				return background_pixbuf;
+			}
+			set {
+				if (background_pixbuf != value && background_pixbuf != null) {
+					background_pixbuf.Dispose ();
+					background_pixbuf = value;
+				}
+			}
+		}
+
+	
+		Hashtable start_indexes;
+		protected override bool OnExposeEvent (EventExpose evnt)
+		{
+			if (evnt.Window != GdkWindow)
+				return true;
+
+			if (extendable && Allocation.Width >= BackgroundPixbuf.Width + (2 * x_offset) + BackgroundTile.Width)
+				BackgroundPixbuf = null;
+
+			if (extendable && Allocation.Width < BackgroundPixbuf.Width + (2 * x_offset))
+				BackgroundPixbuf = null;
+
+			int xpad = 0, ypad = 0;
+			if (Allocation.Width > BackgroundPixbuf.Width + (2 * x_offset))
+				xpad = (int) (x_align * (Allocation.Width - (BackgroundPixbuf.Width + (2 * x_offset))));
+
+			if (Allocation.Height > BackgroundPixbuf.Height + (2 * y_offset))
+				ypad = (int) (y_align * (Allocation.Height - (BackgroundPixbuf.Height + (2 * y_offset))));
+
+			GdkWindow.DrawPixbuf (Style.BackgroundGC (StateType.Normal), BackgroundPixbuf, 
+					0, 0, x_offset + xpad, y_offset + ypad, 
+					BackgroundPixbuf.Width, BackgroundPixbuf.Height, Gdk.RgbDither.None, 0, 0);
+
+			//drawing the icons...
+			start_indexes = new Hashtable ();
+
+			Pixbuf icon_pixbuf = new Pixbuf (Gdk.Colorspace.Rgb, true, 8, BackgroundPixbuf.Width, thumb_size);
+			icon_pixbuf.Fill (0x00000000);
+
+			Pixbuf current = GetPixbuf ((int) Math.Round (Position));
+			int ref_x = (int)(icon_pixbuf.Width / 2.0 - current.Width * (Position + 0.5f - Math.Round (Position))); //xpos of the reference icon
+
+			int start_x = ref_x;
+			for (int i = (int) Math.Round (Position); i < selection.Collection.Count; i++) {
+				current = GetPixbuf (i, ActiveItem == i);
+				current.CopyArea (0, 0, Math.Min (current.Width, icon_pixbuf.Width - start_x) , current.Height, icon_pixbuf, start_x, 0);
+				start_indexes [start_x] = i; 
+				start_x += current.Width + spacing;
+				if (start_x > icon_pixbuf.Width)
+					break;
+			}
+
+			start_x = ref_x;
+			for (int i = (int) Math.Round (Position) - 1; i >= 0; i--) {
+				current = GetPixbuf (i, ActiveItem == i);
+				start_x -= (current.Width + spacing);
+				current.CopyArea (Math.Max (0, -start_x), 0, Math.Min (current.Width, current.Width + start_x), current.Height, icon_pixbuf, Math.Max (start_x, 0), 0);
+				start_indexes [Math.Max (0, start_x)] = i; 
+				if (start_x < 0)
+					break;
+			}
+			
+			GdkWindow.DrawPixbuf (Style.BackgroundGC (StateType.Normal), icon_pixbuf,
+					0, 0, x_offset + xpad, y_offset + ypad + thumb_offset,
+					icon_pixbuf.Width, icon_pixbuf.Height, Gdk.RgbDither.None, 0, 0);
+
+			icon_pixbuf.Dispose ();
+
+			return true;
+		}
+
+		protected override bool OnScrollEvent (EventScroll args)
+		{
+			switch (args.Direction) {
+			case ScrollDirection.Up:
+			case ScrollDirection.Right:
+				Position += 0.3f;
+				return true;
+			case Gdk.ScrollDirection.Down:
+			case Gdk.ScrollDirection.Left:
+				Position -= 0.3f;
+				return true;
+			}
+			return false;
+		}
+
+		public delegate void PositionChangedHandler (float position);
+
+		protected virtual void OnPositionChanged (float position)
+		{
+			this.position = position;
+			QueueDraw ();
+		}
+
+		public void HandlePointerChanged (BrowsablePointer pointer, BrowsablePointerChangedArgs old)
+		{
+			Position = ActiveItem;
+		}
+
+		public void HandleCollectionChanged (IBrowsableCollection coll)
+		{
+			Position = ActiveItem;
+			QueueDraw ();
+		}
+
+		public void HandleCollectionItemsChanged (IBrowsableCollection coll, BrowsableEventArgs args)
+		{
+			//FIXME: need to be smarter here...
+
+			//invalidate the thumbs cache
+			thumb_cache.Dispose ();
+			thumb_cache = new ThumbnailCache (30);
+			QueueDraw ();
+		}
+
+		protected override bool OnButtonPressEvent (EventButton evnt)
+		{
+			if(evnt.Button != 1) 
+				return false;
+			HasFocus = true;
+			int pos = -1;
+			foreach (int key in start_indexes.Keys)
+				if (key <= evnt.X && key > pos)
+					pos = key;
+			try {
+				ActiveItem = (int)start_indexes [pos];
+				return true;
+			} catch {
+				return false;
+			}
+		}
+ 
+ 		protected Pixbuf GetPixbuf (int i)
+		{
+			return GetPixbuf (i, false);
+		}
+
+ 		protected virtual Pixbuf GetPixbuf (int i, bool highlighted)
+		{
+			Pixbuf current;
+			string thumb_path = FSpot.ThumbnailGenerator.ThumbnailPath ((selection.Collection [i]).DefaultVersionUri);
+			current = thumb_cache.GetThumbnailForPath (thumb_path);
+			if (current == null) {
+				current = new Pixbuf (thumb_path, -1, ThumbSize);
+				thumb_cache.AddThumbnail (thumb_path, current);
+			}
+
+			if (!highlighted)
+				return current;
+
+			Pixbuf highlight = new Pixbuf (Gdk.Colorspace.Rgb, true, 8, current.Width, current.Height);
+			Gdk.Color color = Style.Background (StateType.Selected);
+			uint ucol = (uint)((uint)color.Red / 256 << 24 ) + ((uint)color.Green / 256 << 16) + ((uint)color.Blue / 256 << 8) + 255;
+			highlight.Fill (ucol);
+			current.CopyArea (1, 1, current.Width - 2, current.Height - 2, highlight, 1, 1);	
+			return highlight;
+		}
+
+		~Filmstrip ()
+		{
+			this.Dispose ();
+		}
+			
+		public override void Dispose ()
+		{
+			lock (this) {
+				if (background_pixbuf != null)
+					background_pixbuf.Dispose ();
+				if (background_tile != null)
+					background_tile.Dispose ();
+			}
+			background_pixbuf = null;
+			background_tile = null;
+			System.GC.SuppressFinalize (this);
+		}
+
+		public interface IAnimator
+		{
+			void MoveTo (float target);
+		}
+
+		public class DirectAnimator : IAnimator
+		{
+			PositionChangedHandler handler;
+
+			public DirectAnimator (PositionChangedHandler handler)
+			{
+				this.handler = handler;
+			}
+
+			public void MoveTo (float target)
+			{
+				handler (target);
+			}
+		}
+
+		public class ConstantSpeedAnimator : IAnimator
+		{
+			PositionChangedHandler handler;
+			float speed = 20f; // images/second
+			uint interval = 40;
+			float target;
+			Filmstrip filmstrip;
+
+			public ConstantSpeedAnimator (Filmstrip filmstrip, PositionChangedHandler handler)
+			{
+				this.handler = handler;
+				this.filmstrip = filmstrip;
+			}
+
+			public void MoveTo (float target)
+			{
+				this.target = target;
+				GLib.Timeout.Add (interval, new GLib.TimeoutHandler (Step)); 
+			}
+
+			bool Step ()
+			{
+				float increment = speed * interval / 1000f;
+				if (Math.Abs (filmstrip.Position - target) < increment) {
+					handler (target);
+					return false;
+				}
+				if (target > filmstrip.Position)
+					handler (filmstrip.Position + increment);
+				else
+					handler (filmstrip.Position - increment);
+
+				return true;
+			}
+		}
+	}
+}



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