f-spot r3785 - in trunk: . src src/UI.Dialog



Author: sdelcroix
Date: Wed Mar 26 10:21:29 2008
New Revision: 3785
URL: http://svn.gnome.org/viewvc/f-spot?rev=3785&view=rev

Log:
2008-03-26  Stephane Delcroix  <sdelcroix novell com>

	* src/f-spot.glade:
	* src/Makefile.am:
	* src/Preferences.cs:
	* src/UI.Dialog/SelectionRatioDialog.cs:
	* src/PhotoView.cs: new dialog for custom selection ratios. Fixes
	bgo #329581 and #399302.


Added:
   trunk/src/UI.Dialog/SelectionRatioDialog.cs
Modified:
   trunk/ChangeLog
   trunk/src/Makefile.am
   trunk/src/PhotoView.cs
   trunk/src/Preferences.cs
   trunk/src/f-spot.glade

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Wed Mar 26 10:21:29 2008
@@ -226,6 +226,7 @@
 	$(srcdir)/UI.Dialog/AboutDialog.cs	\
 	$(srcdir)/UI.Dialog/EditExceptionDialog.cs	\
 	$(srcdir)/UI.Dialog/HigMessageDialog.cs	\
+	$(srcdir)/UI.Dialog/SelectionRatioDialog.cs	\
 	$(srcdir)/Updater.cs			\
 	$(srcdir)/UriCollection.cs		\
 	$(srcdir)/Util.cs			\

Modified: trunk/src/PhotoView.cs
==============================================================================
--- trunk/src/PhotoView.cs	(original)
+++ trunk/src/PhotoView.cs	Wed Mar 26 10:21:29 2008
@@ -1,8 +1,22 @@
+/*
+ * FSpot.PhotoView.cs
+ *
+ * Author(s)
+ * 	Ettore Perazzoli
+ * 	Larry Ewing
+ *	Stephane Delcroix
+ *
+ * This is free software. See COPYING for details.
+ */
+
 using Gdk;
 using GLib;
 using Gtk;
 using GtkSharp;
 using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Xml.Serialization;
 using Mono.Unix;
 
 using FSpot.Xmp;
@@ -11,612 +25,638 @@
 using FSpot.UI.Dialog;
 
 namespace FSpot {
-public class PhotoView : EventBox {
-	FSpot.Delay commit_delay; 
-
-	private bool has_selection = false;
-	private FSpot.PhotoImageView photo_view;
-	private ScrolledWindow photo_view_scrolled;
-	private EventBox background;
+	public class PhotoView : EventBox {
+		FSpot.Delay commit_delay; 
 	
-	private Filmstrip filmstrip;
-
-	private Widgets.TagView tag_view;
+		private bool has_selection = false;
+		private FSpot.PhotoImageView photo_view;
+		private ScrolledWindow photo_view_scrolled;
+		private EventBox background;
+		
+		private Filmstrip filmstrip;
 	
-	private Gtk.ToolButton display_next_button, display_previous_button;
-	private Label count_label;
-	private Entry description_entry;
-	private Widgets.Rating rating;
-
-	private Gtk.ToolButton crop_button;
-	private Gtk.ToolButton redeye_button;
-	private Gtk.ToolButton color_button;	
-	private Gtk.ToolButton desaturate_button;
-	private Gtk.ToolButton sepia_button;
-
-	private OptionMenu constraints_option_menu;
-	private int selection_constraint_ratio_idx;
-	private uint restore_scrollbars_idle_id;
-
-	private System.Collections.Hashtable constraint_table = new System.Collections.Hashtable ();
-
-	// Public events.
-
-	public delegate void PhotoChangedHandler (PhotoView me);
-	public event PhotoChangedHandler PhotoChanged;
-
-	public delegate void UpdateStartedHandler (PhotoView view);
-	public event UpdateStartedHandler UpdateStarted;
-
-	public delegate void UpdateFinishedHandler (PhotoView view);
-	public event UpdateFinishedHandler UpdateFinished;
-
-	// Selection constraints.
-	private const string CONSTRAINT_RATIO_IDX_KEY = "FEditModeManager::constraint_idx";
-
-	private struct SelectionConstraint {
-		public string Label;
-		public double XyRatio;
+		private Widgets.TagView tag_view;
 		
-		public SelectionConstraint (string label, double ratio)
-		{
-			Label = label;
-			XyRatio = ratio;
+		private Gtk.ToolButton display_next_button, display_previous_button;
+		private Label count_label;
+		private Entry description_entry;
+		private Widgets.Rating rating;
+	
+		private Gtk.ToolButton crop_button;
+		private Gtk.ToolButton redeye_button;
+		private Gtk.ToolButton color_button;	
+		private Gtk.ToolButton desaturate_button;
+		private Gtk.ToolButton sepia_button;
+		
+		private TreeStore constraints_store;
+		private ComboBox constraints_combo = new ComboBox ();
+		private uint restore_scrollbars_idle_id;
+	
+		// Public events.
+	
+		public delegate void PhotoChangedHandler (PhotoView me);
+		public event PhotoChangedHandler PhotoChanged;
+	
+		public delegate void UpdateStartedHandler (PhotoView view);
+		public event UpdateStartedHandler UpdateStarted;
+	
+		public delegate void UpdateFinishedHandler (PhotoView view);
+		public event UpdateFinishedHandler UpdateFinished;
+	
+		private List<SelectionRatioDialog.SelectionConstraint> custom_constraints;
+	
+		private static SelectionRatioDialog.SelectionConstraint [] default_constraints = {
+			new SelectionRatioDialog.SelectionConstraint (Catalog.GetString ("No Constraint"), 0.0),
+			new SelectionRatioDialog.SelectionConstraint (Catalog.GetString ("4 x 3 (Book)"), 4.0 / 3.0),
+			new SelectionRatioDialog.SelectionConstraint (Catalog.GetString ("4 x 6 (Postcard)"), 6.0 / 4.0),
+			new SelectionRatioDialog.SelectionConstraint (Catalog.GetString ("5 x 7 (L, 2L)"), 7.0 / 5.0),
+			new SelectionRatioDialog.SelectionConstraint (Catalog.GetString ("8 x 10"), 10.0 / 8.0),
+			new SelectionRatioDialog.SelectionConstraint (Catalog.GetString ("Square"), 1.0)
+		};
+	
+		public FSpot.PhotoImageView View {
+			get { return photo_view; }
 		}
-	}
-
-	private static SelectionConstraint [] constraints = {
-		new SelectionConstraint (Catalog.GetString ("No Constraint"), 0.0),
-		new SelectionConstraint (Catalog.GetString ("4 x 3 (Book)"), 4.0 / 3.0),
-		new SelectionConstraint (Catalog.GetString ("4 x 6 (Postcard)"), 6.0 / 4.0),
-		new SelectionConstraint (Catalog.GetString ("5 x 7 (L, 2L)"), 7.0 / 5.0),
-		new SelectionConstraint (Catalog.GetString ("8 x 10"), 10.0 / 8.0),
-//		new SelectionConstraint (Catalog.GetString ("4 x 3 Portrait (Book)"), 3.0 / 4.0),
-//		new SelectionConstraint (Catalog.GetString ("4 x 6 Portrait (Postcard)"), 4.0 / 6.0),
-//		new SelectionConstraint (Catalog.GetString ("5 x 7 Portrait (L, 2L)"), 5.0 / 7.0),
-//		new SelectionConstraint (Catalog.GetString ("8 x 10 Portrait"), 8.0 / 10.0),
-		new SelectionConstraint (Catalog.GetString ("Square"), 1.0)
-	};
-
-	public FSpot.PhotoImageView View {
-		get { return photo_view; }
-	}
-
-	new public FSpot.BrowsablePointer Item {
-		get { return photo_view.Item; }
-	}
-
-
-	private IBrowsableCollection query;
-	public IBrowsableCollection Query {
-		get { return query; }
-		set { query = value; }
-	}
-
-	public double Zoom {
-		get { return photo_view.Zoom; }
-		set { photo_view.Zoom = value; }
-	}
 	
-	public double NormalizedZoom {
-		get { return photo_view.NormalizedZoom; }
-		set { photo_view.NormalizedZoom = value; }
-	}
-
-	private void HandleSelectionConstraintOptionMenuActivated (object sender, EventArgs args)
-	{
-		selection_constraint_ratio_idx = (int) constraint_table [sender];
-		photo_view.SelectionXyRatio = constraints [selection_constraint_ratio_idx].XyRatio;
-	}
-
-	public void Reload ()
-	{
-		photo_view.Reload ();
-	}
-
-	private OptionMenu CreateConstraintsOptionMenu ()
-	{
-		Menu menu = new Menu ();
-
-		int i = 0;
-		foreach (SelectionConstraint c in constraints) {
-			MenuItem menu_item = new MenuItem (c.Label);
-			menu_item.Show ();
-			constraint_table [menu_item] = i;
-			menu_item.Activated += new EventHandler (HandleSelectionConstraintOptionMenuActivated);
-
-			menu.Append (menu_item);
-			i ++;
+		new public FSpot.BrowsablePointer Item {
+			get { return photo_view.Item; }
+		}
+	
+	
+		private IBrowsableCollection query;
+		public IBrowsableCollection Query {
+			get { return query; }
+			set { query = value; }
+		}
+	
+		public double Zoom {
+			get { return photo_view.Zoom; }
+			set { photo_view.Zoom = value; }
 		}
-
-		constraints_option_menu = new OptionMenu ();
-		constraints_option_menu.Menu = menu;
-
-		return constraints_option_menu;
-	}
-
-	private void ItemChanged (BrowsablePointer item, BrowsablePointerChangedArgs args)
-	{
 		
-	}
-
-	private void UpdateButtonSensitivity ()
-	{
-		bool valid = photo_view.Item.IsValid;
-		bool prev = valid && Item.Index > 0;
-		bool next = valid && Item.Index < query.Count - 1;
-
-		if (valid) {
-			Gnome.Vfs.Uri vfs = new Gnome.Vfs.Uri (photo_view.Item.Current.DefaultVersionUri.ToString ());
-			valid = vfs.Scheme == "file";
+		public double NormalizedZoom {
+			get { return photo_view.NormalizedZoom; }
+			set { photo_view.NormalizedZoom = value; }
 		}
-
-		display_previous_button.Sensitive = prev;
-		display_next_button.Sensitive = next;
-
-		if (valid && has_selection) {
-			crop_button.SetTooltip (tips, Catalog.GetString ("Crop photo to selected area"), String.Empty);
-			redeye_button.SetTooltip (tips, Catalog.GetString ("Remove redeye from selected area"), String.Empty);
-		} else {
-			crop_button.SetTooltip (tips, Catalog.GetString ("Select an area to crop"), null);
-			redeye_button.SetTooltip (tips, Catalog.GetString ("Select an area to remove redeye"), null);
+	
+		public void Reload ()
+		{
+			photo_view.Reload ();
+		}
+	
+		private void UpdateButtonSensitivity ()
+		{
+			bool valid = photo_view.Item.IsValid;
+			bool prev = valid && Item.Index > 0;
+			bool next = valid && Item.Index < query.Count - 1;
+	
+			if (valid) {
+				Gnome.Vfs.Uri vfs = new Gnome.Vfs.Uri (photo_view.Item.Current.DefaultVersionUri.ToString ());
+				valid = vfs.Scheme == "file";
+			}
+	
+			display_previous_button.Sensitive = prev;
+			display_next_button.Sensitive = next;
+	
+			if (valid && has_selection) {
+				crop_button.SetTooltip (tips, Catalog.GetString ("Crop photo to selected area"), String.Empty);
+				redeye_button.SetTooltip (tips, Catalog.GetString ("Remove redeye from selected area"), String.Empty);
+			} else {
+				crop_button.SetTooltip (tips, Catalog.GetString ("Select an area to crop"), null);
+				redeye_button.SetTooltip (tips, Catalog.GetString ("Select an area to remove redeye"), null);
+			}
+			
+			crop_button.Sensitive = valid;
+			redeye_button.Sensitive = valid;
+			color_button.Sensitive = valid;
+			desaturate_button.Sensitive = valid;
+			sepia_button.Sensitive = valid;
+		}
+	
+		private void UpdateCountLabel ()
+		{
+			if (query == null)
+				count_label.Text = String.Empty;
+			else {
+				if (query.Count == 0)
+					count_label.Text = String.Format ("{0} of {1}", 0, 0);
+				else 
+					count_label.Text = String.Format ("{0} of {1}", Item.Index + 1, Query.Count);
+			}
+		}
+	
+		private void UpdateDescriptionEntry ()
+		{
+			description_entry.Changed -= HandleDescriptionChanged;
+			if (Item.IsValid) {
+				if (description_entry.Sensitive == false)
+					description_entry.Sensitive = true;
+	
+				string desc = Item.Current.Description;
+				if (description_entry.Text != desc) {
+					description_entry.Text = desc == null ? String.Empty : desc;
+				}
+			} else {
+				description_entry.Sensitive = false;
+				description_entry.Text = String.Empty;
+			}
+	
+			tips.SetTip (description_entry, description_entry.Text ?? String.Empty, description_entry.Text ?? String.Empty);
+	
+			description_entry.Changed += HandleDescriptionChanged;
+		}    
+	
+		public void UpdateRating ()
+		{
+			rating.Changed -= HandleRatingChanged;
+			if (Item.IsValid)
+				rating.Value = (int)Item.Current.Rating;
+			rating.Changed += HandleRatingChanged;
+		}
+	
+		private void Update ()
+		{
+			if (UpdateStarted != null)
+				UpdateStarted (this);
+	
+			UpdateButtonSensitivity ();
+			UpdateCountLabel ();
+			UpdateDescriptionEntry ();
+			UpdateRating ();
+	
+			if (UpdateFinished != null)
+				UpdateFinished (this);
+		}
+	
+		public void ZoomIn ()
+		{
+			photo_view.ZoomIn ();
 		}
 		
-		crop_button.Sensitive = valid;
-		redeye_button.Sensitive = valid;
-		color_button.Sensitive = valid;
-		desaturate_button.Sensitive = valid;
-		sepia_button.Sensitive = valid;
-	}
-
-	private void UpdateCountLabel ()
-	{
-		if (query == null)
-			count_label.Text = String.Empty;
-		else {
-			if (query.Count == 0)
-				count_label.Text = String.Format ("{0} of {1}", 0, 0);
-			else 
-				count_label.Text = String.Format ("{0} of {1}", Item.Index + 1, Query.Count);
+		public void ZoomOut ()
+		{
+			photo_view.ZoomOut ();
 		}
-	}
-
-	private void UpdateDescriptionEntry ()
-	{
-		description_entry.Changed -= HandleDescriptionChanged;
-		if (Item.IsValid) {
-			if (description_entry.Sensitive == false)
-				description_entry.Sensitive = true;
-
-			string desc = Item.Current.Description;
-			if (description_entry.Text != desc) {
-				description_entry.Text = desc == null ? String.Empty : desc;
-			}
-		} else {
-			description_entry.Sensitive = false;
-			description_entry.Text = String.Empty;
+	
+		// Event handlers.
+		private void HandleButtonPressEvent (object sender, ButtonPressEventArgs args)
+		{
+			if (args.Event.Type == EventType.ButtonPress
+			    && args.Event.Button == 3) {
+				PhotoPopup popup = new PhotoPopup ();
+				popup.Activate (this.Toplevel, args.Event);
+			}
 		}
-
-		tips.SetTip (description_entry, description_entry.Text ?? String.Empty, description_entry.Text ?? String.Empty);
-
-		description_entry.Changed += HandleDescriptionChanged;
-	}    
-
-	public void UpdateRating ()
-	{
-		rating.Changed -= HandleRatingChanged;
-		if (Item.IsValid)
-			rating.Value = (int)Item.Current.Rating;
-		rating.Changed += HandleRatingChanged;
-	}
-
-	private void Update ()
-	{
-		if (UpdateStarted != null)
-			UpdateStarted (this);
-
-		UpdateButtonSensitivity ();
-		UpdateCountLabel ();
-		UpdateDescriptionEntry ();
-		UpdateRating ();
-
-		if (UpdateFinished != null)
-			UpdateFinished (this);
-	}
-
-	public void ZoomIn ()
-	{
-		photo_view.ZoomIn ();
-	}
 	
-	public void ZoomOut ()
-	{
-		photo_view.ZoomOut ();
-	}
-
-	// Event handlers.
-	private void HandleButtonPressEvent (object sender, ButtonPressEventArgs args)
-	{
-		if (args.Event.Type == EventType.ButtonPress
-		    && args.Event.Button == 3) {
+		protected override bool OnPopupMenu ()
+		{
 			PhotoPopup popup = new PhotoPopup ();
-			popup.Activate (this.Toplevel, args.Event);
+			popup.Activate (this.Toplevel);
+			return true;
 		}
-	}
-
-	protected override bool OnPopupMenu ()
-	{
-		PhotoPopup popup = new PhotoPopup ();
-		popup.Activate (this.Toplevel);
-		return true;
-	}
-
-	private void HandleDisplayNextButtonClicked (object sender, EventArgs args)
-	{
-		View.Item.MoveNext ();
-	}
-
-	private void HandleDisplayPreviousButtonClicked (object sender, EventArgs args)
-	{
-		View.Item.MovePrevious ();
-	}
-
-
-	private void HandleRedEyeButtonClicked (object sender, EventArgs args)
-	{
-		ProcessImage (true);
-	}
 	
-	private void HandleCropButtonClicked (object sender, EventArgs args)
-	{
-		ProcessImage (false);
-	}
-
-	private void ShowError (System.Exception e, Photo photo)
-	{
-		string msg = Catalog.GetString ("Error editing photo");
-		string desc = String.Format (Catalog.GetString ("Received exception \"{0}\". Unable to save photo {1}"),
-					     e.Message, photo.Name);
-		
-		HigMessageDialog md = new HigMessageDialog ((Gtk.Window)this.Toplevel, DialogFlags.DestroyWithParent, 
-							    Gtk.MessageType.Error, ButtonsType.Ok, 
-							    msg,
-							    desc);
-		md.Run ();
-		md.Destroy ();
-	}
-
-	private void HandleSepiaButtonClicked (object sender, EventArgs args)
-	{
-		PhotoQuery pq = query as PhotoQuery;
-
-		if (pq == null)
-			return;
-
-		try {
-			FSpot.SepiaTone sepia = new FSpot.SepiaTone ((Photo)View.Item.Current);
-			sepia.Pixbuf = View.CompletePixbuf ();
-			sepia.Adjust ();
-			pq.Commit (Item.Index);
-		} catch (System.Exception e) {
-			ShowError (e, (Photo)View.Item.Current); 
+		private void HandleDisplayNextButtonClicked (object sender, EventArgs args)
+		{
+			View.Item.MoveNext ();
 		}
-	}
-
-	private void HandleDesaturateButtonClicked (object sender, EventArgs args)
-	{
-		PhotoQuery pq = query as PhotoQuery;
-
-		if (pq == null)
-			return;
-
-		try {
-			FSpot.Desaturate desaturate = new FSpot.Desaturate ((Photo) View.Item.Current);
-			desaturate.Pixbuf = View.CompletePixbuf ();
-			desaturate.Adjust ();
-			pq.Commit (Item.Index);
-		} catch (System.Exception e) {
-			ShowError (e, (Photo)View.Item.Current);
+	
+		private void HandleDisplayPreviousButtonClicked (object sender, EventArgs args)
+		{
+			View.Item.MovePrevious ();
 		}
-	}
-
-	// FIXME this design sucks, I'm just doing it this way while
-	// I redesign the editing system.
-	private void ProcessImage (bool redeye)
-	{
-		int x, y, width, height;
-		if (! photo_view.GetSelection (out x, out y, out width, out height)) {
-			string msg = Catalog.GetString ("No selection available");
-			string desc = Catalog.GetString ("This tool requires an active selection. Please select a region of the photo and try the operation again");
+	
+	
+		private void HandleRedEyeButtonClicked (object sender, EventArgs args)
+		{
+			ProcessImage (true);
+		}
+		
+		private void HandleCropButtonClicked (object sender, EventArgs args)
+		{
+			ProcessImage (false);
+		}
+	
+		private void ShowError (System.Exception e, Photo photo)
+		{
+			string msg = Catalog.GetString ("Error editing photo");
+			string desc = String.Format (Catalog.GetString ("Received exception \"{0}\". Unable to save photo {1}"),
+						     e.Message, photo.Name);
 			
 			HigMessageDialog md = new HigMessageDialog ((Gtk.Window)this.Toplevel, DialogFlags.DestroyWithParent, 
 								    Gtk.MessageType.Error, ButtonsType.Ok, 
 								    msg,
 								    desc);
-
 			md.Run ();
 			md.Destroy ();
-			return;
-		}		
-
-		Photo photo = (Photo)Item.Current;
-		try {
-			Pixbuf original_pixbuf = photo_view.CompletePixbuf ();
-			if (original_pixbuf == null) {
+		}
+	
+		private void HandleSepiaButtonClicked (object sender, EventArgs args)
+		{
+			PhotoQuery pq = query as PhotoQuery;
+	
+			if (pq == null)
 				return;
+	
+			try {
+				FSpot.SepiaTone sepia = new FSpot.SepiaTone ((Photo)View.Item.Current);
+				sepia.Pixbuf = View.CompletePixbuf ();
+				sepia.Adjust ();
+				pq.Commit (Item.Index);
+			} catch (System.Exception e) {
+				ShowError (e, (Photo)View.Item.Current); 
 			}
-			
-			Pixbuf edited;
-			if (redeye) {
-				Gdk.Rectangle area = new Gdk.Rectangle (x, y, width, height);
-				edited = PixbufUtils.RemoveRedeye (original_pixbuf, 
-								   area,
-								   (int) Preferences.Get (Preferences.EDIT_REDEYE_THRESHOLD));
-			} else { // Crop (I told you it was ugly)
-				edited = new Pixbuf (original_pixbuf.Colorspace, 
-						     original_pixbuf.HasAlpha, original_pixbuf.BitsPerSample,
-						     width, height);
+		}
+	
+		private void HandleDesaturateButtonClicked (object sender, EventArgs args)
+		{
+			PhotoQuery pq = query as PhotoQuery;
+	
+			if (pq == null)
+				return;
+	
+			try {
+				FSpot.Desaturate desaturate = new FSpot.Desaturate ((Photo) View.Item.Current);
+				desaturate.Pixbuf = View.CompletePixbuf ();
+				desaturate.Adjust ();
+				pq.Commit (Item.Index);
+			} catch (System.Exception e) {
+				ShowError (e, (Photo)View.Item.Current);
+			}
+		}
+	
+		// FIXME this design sucks, I'm just doing it this way while
+		// I redesign the editing system.
+		private void ProcessImage (bool redeye)
+		{
+			int x, y, width, height;
+			if (! photo_view.GetSelection (out x, out y, out width, out height)) {
+				string msg = Catalog.GetString ("No selection available");
+				string desc = Catalog.GetString ("This tool requires an active selection. Please select a region of the photo and try the operation again");
 				
-				original_pixbuf.CopyArea (x, y, width, height, edited, 0, 0);
+				HigMessageDialog md = new HigMessageDialog ((Gtk.Window)this.Toplevel, DialogFlags.DestroyWithParent, 
+									    Gtk.MessageType.Error, ButtonsType.Ok, 
+									    msg,
+									    desc);
+	
+				md.Run ();
+				md.Destroy ();
+				return;
+			}		
+	
+			Photo photo = (Photo)Item.Current;
+			try {
+				Pixbuf original_pixbuf = photo_view.CompletePixbuf ();
+				if (original_pixbuf == null) {
+					return;
+				}
+				
+				Pixbuf edited;
+				if (redeye) {
+					Gdk.Rectangle area = new Gdk.Rectangle (x, y, width, height);
+					edited = PixbufUtils.RemoveRedeye (original_pixbuf, 
+									   area,
+									   (int) Preferences.Get (Preferences.EDIT_REDEYE_THRESHOLD));
+				} else { // Crop (I told you it was ugly)
+					edited = new Pixbuf (original_pixbuf.Colorspace, 
+							     original_pixbuf.HasAlpha, original_pixbuf.BitsPerSample,
+							     width, height);
+					
+					original_pixbuf.CopyArea (x, y, width, height, edited, 0, 0);
+				}
+				
+				bool create_version = photo.DefaultVersion.IsProtected;
+				photo.SaveVersion (edited, create_version);
+				((PhotoQuery)query).Commit (Item.Index);
+	
+				// FIXME the fact that the selection doesn't go away is a bug in ImageView, it should
+				// be fixed there.
+				photo_view.Pixbuf = edited;
+				original_pixbuf.Dispose ();
+				photo_view.UnsetSelection ();
+	
+				photo_view.Fit = true;
+				
+				if (PhotoChanged != null)
+					PhotoChanged (this);
+			} catch (System.Exception e) {
+				ShowError (e, photo);
 			}
+		}
+	
+		private void HandleColorButtonClicked (object sender, EventArgs args) 
+		{
+			ColorDialog.CreateForView (photo_view);
+		}	
+	
+		int changed_photo;
+		private bool CommitPendingChanges ()
+		{
+			if (commit_delay.IsPending) {
+				commit_delay.Stop ();
+				((PhotoQuery)query).Commit (changed_photo);
+			}
+			return true;
+		}
+	
+		private void HandleDescriptionChanged (object sender, EventArgs args) 
+		{
+			if (!Item.IsValid)
+				return;
 			
-			bool create_version = photo.DefaultVersion.IsProtected;
-			photo.SaveVersion (edited, create_version);
-			((PhotoQuery)query).Commit (Item.Index);
-
-			// FIXME the fact that the selection doesn't go away is a bug in ImageView, it should
-			// be fixed there.
-			photo_view.Pixbuf = edited;
-			original_pixbuf.Dispose ();
-			photo_view.UnsetSelection ();
-
-			photo_view.Fit = true;
+			((Photo)Item.Current).Description = description_entry.Text;
 			
-			if (PhotoChanged != null)
-				PhotoChanged (this);
-		} catch (System.Exception e) {
-			ShowError (e, photo);
-		}
-	}
-
-	private void HandleColorButtonClicked (object sender, EventArgs args) 
-	{
-		ColorDialog.CreateForView (photo_view);
-	}	
-
-	int changed_photo;
-	private bool CommitPendingChanges ()
-	{
-		if (commit_delay.IsPending) {
-			commit_delay.Stop ();
-			((PhotoQuery)query).Commit (changed_photo);
+			if (commit_delay.IsPending)
+				if (changed_photo == Item.Index)
+					commit_delay.Stop ();
+				else
+					CommitPendingChanges ();
+			
+			tips.SetTip (description_entry, description_entry.Text, "This is a tip");
+			changed_photo = Item.Index;
+			commit_delay.Start ();
 		}
-		return true;
-	}
-
-	private void HandleDescriptionChanged (object sender, EventArgs args) 
-	{
-		if (!Item.IsValid)
-			return;
-		
-		((Photo)Item.Current).Description = description_entry.Text;
-		
-		if (commit_delay.IsPending)
-			if (changed_photo == Item.Index)
-				commit_delay.Stop ();
-			else
+	
+		private void HandleRatingChanged (object o, EventArgs e)
+		{
+			if (!Item.IsValid)
+				return;
+	
+			((Photo)Item.Current).Rating = (uint)(o as Widgets.Rating).Value;
+	
+			if (commit_delay.IsPending)
+				if (changed_photo == Item.Index)
+					commit_delay.Stop();
+				else
+					CommitPendingChanges ();
+			changed_photo = Item.Index;
+			commit_delay.Start ();
+	 	}
+	
+		private void HandlePhotoChanged (FSpot.PhotoImageView view)
+		{
+			if (query is PhotoQuery) {
 				CommitPendingChanges ();
+			}
+			
+			tag_view.Current = Item.Current;
+			Update ();
+	
+			if (this.PhotoChanged != null)
+				PhotoChanged (this);
+		}
+	
+		private void HandleSelectionChanged ()
+		{
+			int x, y, width, height;
+			bool old = has_selection;
+			has_selection = photo_view.GetSelection (out x, out y, out width, out height);
 		
-		tips.SetTip (description_entry, description_entry.Text, "This is a tip");
-		changed_photo = Item.Index;
-		commit_delay.Start ();
-	}
-
-	private void HandleRatingChanged (object o, EventArgs e)
-	{
-		if (!Item.IsValid)
-			return;
-
-		((Photo)Item.Current).Rating = (uint)(o as Widgets.Rating).Value;
-
-		if (commit_delay.IsPending)
-			if (changed_photo == Item.Index)
-				commit_delay.Stop();
-			else
-				CommitPendingChanges ();
-		changed_photo = Item.Index;
-		commit_delay.Start ();
- 	}
-
-	private void HandlePhotoChanged (FSpot.PhotoImageView view)
-	{
-		if (query is PhotoQuery) {
+			if (has_selection != old)
+				UpdateButtonSensitivity ();
+		}
+	
+		private void HandleDestroy (object sender, System.EventArgs args)
+		{
 			CommitPendingChanges ();
 		}
-		
-		tag_view.Current = Item.Current;
-		Update ();
-
-		if (this.PhotoChanged != null)
-			PhotoChanged (this);
-	}
+	
+		public bool FilmStripVisibility {
+			get { return filmstrip.Visible; }
+			set { filmstrip.Visible = value; }
+		}
+	
+		Gtk.Tooltips tips = new Gtk.Tooltips ();
+	
+		public PhotoView (IBrowsableCollection query)
+			: base ()
+		{
+			this.query = query;
+	
+			commit_delay = new FSpot.Delay (1000, new GLib.IdleHandler (CommitPendingChanges));
+			this.Destroyed += HandleDestroy;
+	
+			Name = "ImageContainer";
+			Box vbox = new VBox (false, 6);
+			Add (vbox);
+	
+		        background = new EventBox ();
+			Frame frame = new Frame ();
+			background.Add (frame);
+	
+			frame.ShadowType = ShadowType.In;
+			vbox.PackStart (background, true, true, 0);
+			
+			Box inner_vbox = new VBox (false , 2);
+	
+			frame.Add (inner_vbox);
+			
+			BrowsablePointer bp = new BrowsablePointer (query, -1);
+			photo_view = new FSpot.PhotoImageView (bp);
+	
+			filmstrip = new Filmstrip (bp);
+			Gdk.Pixbuf bg = new Gdk.Pixbuf (Gdk.Colorspace.Rgb, true, 8, 1, 69);
+			bg.Fill (0x00000000);
+			filmstrip.BackgroundTile = bg;
+			filmstrip.ThumbOffset = 1;
+			filmstrip.Spacing = 4;
+			inner_vbox.PackStart (filmstrip, false, false, 0);
+	
+			photo_view.PhotoChanged += HandlePhotoChanged;
+			photo_view.SelectionChanged += HandleSelectionChanged;
+	
+			photo_view_scrolled = new ScrolledWindow (null, null);
+	
+			photo_view_scrolled.SetPolicy (PolicyType.Automatic, PolicyType.Automatic);
+			photo_view_scrolled.ShadowType = ShadowType.None;
+			photo_view_scrolled.Add (photo_view);
+			photo_view_scrolled.ButtonPressEvent += HandleButtonPressEvent;
+			photo_view.AddEvents ((int) EventMask.KeyPressMask);
+			inner_vbox.PackStart (photo_view_scrolled, true, true, 0);
+			
+			HBox inner_hbox = new HBox (false, 2);
+			//inner_hbox.BorderWidth = 6;
+	
+			tag_view = new Widgets.TagView ();
+			inner_hbox.PackStart (tag_view, false, true, 0);
+	
+			Label comment = new Label (Catalog.GetString ("Comment:"));
+			inner_hbox.PackStart (comment, false, false, 0);
+			description_entry = new Entry ();
+			inner_hbox.PackStart (description_entry, true, true, 0);
+			description_entry.Changed += HandleDescriptionChanged;
+	
+			rating = new Widgets.Rating();
+			inner_hbox.PackStart (rating, false, false, 0);
+			rating.Changed += HandleRatingChanged;
+	
+			CellRendererText constraint_name_cell = new CellRendererText ();
+			CellRendererPixbuf constraint_pix_cell = new CellRendererPixbuf ();
+			constraints_combo.PackStart (constraint_name_cell, true);
+			constraints_combo.PackStart (constraint_pix_cell, false);
+			constraints_combo.SetCellDataFunc (constraint_name_cell, new CellLayoutDataFunc (ConstraintNameCellFunc));
+			constraints_combo.SetCellDataFunc (constraint_pix_cell, new CellLayoutDataFunc (ConstraintPixCellFunc));
+			constraints_combo.Changed += HandleConstraintsComboChanged;
 
-	private void HandleSelectionChanged ()
-	{
-		int x, y, width, height;
-		bool old = has_selection;
-		has_selection = photo_view.GetSelection (out x, out y, out width, out height);
+			SetColors ();
+			
+			inner_vbox.PackStart (inner_hbox, false, true, 0);
+	
+			Toolbar toolbar = new Toolbar ();
+			toolbar.IconSize = IconSize.SmallToolbar;
+			toolbar.ToolbarStyle = ToolbarStyle.Icons;
+			vbox.PackStart (toolbar, false, true, 0);
+	
+			ToolItem constraints_menu = new ToolItem ();
+			LoadPreference (Preferences.CUSTOM_CROP_RATIOS);
+			constraints_menu.Child = constraints_combo;
+			constraints_combo.Active = 0;
+			toolbar.Insert (constraints_menu, -1);	
+			constraints_menu.SetTooltip (tips, Catalog.GetString ("Constrain the aspect ratio of the selection"), String.Empty);
+	
+			crop_button = GtkUtil.ToolButtonFromTheme ("crop", Catalog.GetString ("Crop"), false);
+			toolbar.Insert (crop_button, -1);
+			crop_button.Clicked += new EventHandler (HandleCropButtonClicked);
+	
+			redeye_button = GtkUtil.ToolButtonFromTheme ("red-eye-remove", Catalog.GetString ("Reduce Red-Eye"), false);
+			toolbar.Insert (redeye_button, -1);
+			redeye_button.Clicked += new EventHandler (HandleRedEyeButtonClicked);
+	
+			color_button = GtkUtil.ToolButtonFromTheme ("adjust-colors", Catalog.GetString ("Adjust Colors"), false);
+			toolbar.Insert (color_button, -1);
+			color_button.SetTooltip (tips, Catalog.GetString ("Adjust the photo colors"), String.Empty);
+			color_button.Clicked += new EventHandler (HandleColorButtonClicked);
+	
+			desaturate_button = GtkUtil.ToolButtonFromTheme ("color-desaturate", Catalog.GetString ("Desaturate"), false);
+			toolbar.Insert (desaturate_button, -1);
+			desaturate_button.SetTooltip (tips, Catalog.GetString ("Convert the photo to black and white"), String.Empty);
+			desaturate_button.Clicked += HandleDesaturateButtonClicked;
+	
+			sepia_button = GtkUtil.ToolButtonFromTheme ("color-sepia", Catalog.GetString ("Sepia Tone"), false);
+			toolbar.Insert (sepia_button, -1);
+			sepia_button.SetTooltip (tips, Catalog.GetString ("Convert the photo to sepia tones"), String.Empty);
+			sepia_button.Clicked += HandleSepiaButtonClicked;
+	
+			ItemAction straighten = new TiltEditorAction (photo_view);
+			ToolButton straighten_btn = straighten.CreateToolItem () as ToolButton;
+			straighten_btn.SetTooltip (tips, straighten.Tooltip, String.Empty);
+			toolbar.Insert (straighten_btn, -1);
+			
+			ItemAction softfocus = new SoftFocusEditorAction (photo_view);
+			ToolButton softfocus_btn = softfocus.CreateToolItem () as ToolButton;
+			softfocus_btn.SetTooltip (tips, softfocus.Tooltip, String.Empty);
+			toolbar.Insert (softfocus_btn, -1);
+	
+			ItemAction autocolor = new AutoColor (photo_view.Item);
+			ToolButton autocolor_btn = autocolor.CreateToolItem () as ToolButton;
+			autocolor_btn.SetTooltip (tips, autocolor.Tooltip, String.Empty);
+			toolbar.Insert (autocolor_btn, -1);
+	
+			SeparatorToolItem white_space = new SeparatorToolItem ();
+			white_space.Draw = false;
+			white_space.Expand = true;
+			toolbar.Insert (white_space, -1);
+	
+			ToolItem label_item = new ToolItem ();
+			count_label = new Label (String.Empty);
+			label_item.Child = count_label;
+			toolbar.Insert (label_item, -1);
+	
+			display_previous_button = new ToolButton (Stock.GoBack);
+			toolbar.Insert (display_previous_button, -1);
+			display_previous_button.SetTooltip (tips, Catalog.GetString ("Previous photo"), String.Empty);
+			display_previous_button.Clicked += new EventHandler (HandleDisplayPreviousButtonClicked);
+	
+			display_next_button = new ToolButton (Stock.GoForward);
+			toolbar.Insert (display_next_button, -1);
+			display_next_button.SetTooltip (tips, Catalog.GetString ("Next photo"), String.Empty);
+			display_next_button.Clicked += new EventHandler (HandleDisplayNextButtonClicked);
 	
-		if (has_selection != old)
 			UpdateButtonSensitivity ();
-	}
-
-	private void HandleDestroy (object sender, System.EventArgs args)
-	{
-		CommitPendingChanges ();
-	}
-
-	public bool FilmStripVisibility {
-		get { return filmstrip.Visible; }
-		set { filmstrip.Visible = value; }
-	}
-
-	Gtk.Tooltips tips = new Gtk.Tooltips ();
-
-	public PhotoView (IBrowsableCollection query)
-		: base ()
-	{
-		this.query = query;
-
-		commit_delay = new FSpot.Delay (1000, new GLib.IdleHandler (CommitPendingChanges));
-		this.Destroyed += HandleDestroy;
-
-		Name = "ImageContainer";
-		Box vbox = new VBox (false, 6);
-		Add (vbox);
-
-	        background = new EventBox ();
-		Frame frame = new Frame ();
-		background.Add (frame);
-
-		frame.ShadowType = ShadowType.In;
-		vbox.PackStart (background, true, true, 0);
-		
-		Box inner_vbox = new VBox (false , 2);
-
-		frame.Add (inner_vbox);
-		
-		BrowsablePointer bp = new BrowsablePointer (query, -1);
-		photo_view = new FSpot.PhotoImageView (bp);
-
-		filmstrip = new Filmstrip (bp);
-		Gdk.Pixbuf bg = new Gdk.Pixbuf (Gdk.Colorspace.Rgb, true, 8, 1, 69);
-		bg.Fill (0x00000000);
-		filmstrip.BackgroundTile = bg;
-		filmstrip.ThumbOffset = 1;
-		filmstrip.Spacing = 4;
-		inner_vbox.PackStart (filmstrip, false, false, 0);
-
-		photo_view.PhotoChanged += HandlePhotoChanged;
-		photo_view.SelectionChanged += HandleSelectionChanged;
-
-		photo_view_scrolled = new ScrolledWindow (null, null);
-
-		photo_view_scrolled.SetPolicy (PolicyType.Automatic, PolicyType.Automatic);
-		photo_view_scrolled.ShadowType = ShadowType.None;
-		photo_view_scrolled.Add (photo_view);
-		photo_view_scrolled.ButtonPressEvent += HandleButtonPressEvent;
-		photo_view.AddEvents ((int) EventMask.KeyPressMask);
-		inner_vbox.PackStart (photo_view_scrolled, true, true, 0);
-		
-		HBox inner_hbox = new HBox (false, 2);
-		//inner_hbox.BorderWidth = 6;
-
-		tag_view = new Widgets.TagView ();
-		inner_hbox.PackStart (tag_view, false, true, 0);
-
-		Label comment = new Label (Catalog.GetString ("Comment:"));
-		inner_hbox.PackStart (comment, false, false, 0);
-		description_entry = new Entry ();
-		inner_hbox.PackStart (description_entry, true, true, 0);
-		description_entry.Changed += HandleDescriptionChanged;
-
-		rating = new Widgets.Rating();
-		inner_hbox.PackStart (rating, false, false, 0);
-		rating.Changed += HandleRatingChanged;
-
-		SetColors ();
-		
-		inner_vbox.PackStart (inner_hbox, false, true, 0);
-
-		Toolbar toolbar = new Toolbar ();
-		toolbar.IconSize = IconSize.SmallToolbar;
-		toolbar.ToolbarStyle = ToolbarStyle.Icons;
-		vbox.PackStart (toolbar, false, true, 0);
-
-		ToolItem constraints_menu = new ToolItem ();
-		constraints_menu.Child = CreateConstraintsOptionMenu ();
-		toolbar.Insert (constraints_menu, -1);	
-		constraints_menu.SetTooltip (tips, Catalog.GetString ("Constrain the aspect ratio of the selection"), String.Empty);
-
-		crop_button = GtkUtil.ToolButtonFromTheme ("crop", Catalog.GetString ("Crop"), false);
-		toolbar.Insert (crop_button, -1);
-		crop_button.Clicked += new EventHandler (HandleCropButtonClicked);
-
-		redeye_button = GtkUtil.ToolButtonFromTheme ("red-eye-remove", Catalog.GetString ("Reduce Red-Eye"), false);
-		toolbar.Insert (redeye_button, -1);
-		redeye_button.Clicked += new EventHandler (HandleRedEyeButtonClicked);
-
-		color_button = GtkUtil.ToolButtonFromTheme ("adjust-colors", Catalog.GetString ("Adjust Colors"), false);
-		toolbar.Insert (color_button, -1);
-		color_button.SetTooltip (tips, Catalog.GetString ("Adjust the photo colors"), String.Empty);
-		color_button.Clicked += new EventHandler (HandleColorButtonClicked);
-
-		desaturate_button = GtkUtil.ToolButtonFromTheme ("color-desaturate", Catalog.GetString ("Desaturate"), false);
-		toolbar.Insert (desaturate_button, -1);
-		desaturate_button.SetTooltip (tips, Catalog.GetString ("Convert the photo to black and white"), String.Empty);
-		desaturate_button.Clicked += HandleDesaturateButtonClicked;
-
-		sepia_button = GtkUtil.ToolButtonFromTheme ("color-sepia", Catalog.GetString ("Sepia Tone"), false);
-		toolbar.Insert (sepia_button, -1);
-		sepia_button.SetTooltip (tips, Catalog.GetString ("Convert the photo to sepia tones"), String.Empty);
-		sepia_button.Clicked += HandleSepiaButtonClicked;
-
-		ItemAction straighten = new TiltEditorAction (photo_view);
-		ToolButton straighten_btn = straighten.CreateToolItem () as ToolButton;
-		straighten_btn.SetTooltip (tips, straighten.Tooltip, String.Empty);
-		toolbar.Insert (straighten_btn, -1);
-		
-		ItemAction softfocus = new SoftFocusEditorAction (photo_view);
-		ToolButton softfocus_btn = softfocus.CreateToolItem () as ToolButton;
-		softfocus_btn.SetTooltip (tips, softfocus.Tooltip, String.Empty);
-		toolbar.Insert (softfocus_btn, -1);
-
-		ItemAction autocolor = new AutoColor (photo_view.Item);
-		ToolButton autocolor_btn = autocolor.CreateToolItem () as ToolButton;
-		autocolor_btn.SetTooltip (tips, autocolor.Tooltip, String.Empty);
-		toolbar.Insert (autocolor_btn, -1);
-
-		SeparatorToolItem white_space = new SeparatorToolItem ();
-		white_space.Draw = false;
-		white_space.Expand = true;
-		toolbar.Insert (white_space, -1);
-
-		ToolItem label_item = new ToolItem ();
-		count_label = new Label (String.Empty);
-		label_item.Child = count_label;
-		toolbar.Insert (label_item, -1);
-
-		display_previous_button = new ToolButton (Stock.GoBack);
-		toolbar.Insert (display_previous_button, -1);
-		display_previous_button.SetTooltip (tips, Catalog.GetString ("Previous photo"), String.Empty);
-		display_previous_button.Clicked += new EventHandler (HandleDisplayPreviousButtonClicked);
-
-		display_next_button = new ToolButton (Stock.GoForward);
-		toolbar.Insert (display_next_button, -1);
-		display_next_button.SetTooltip (tips, Catalog.GetString ("Next photo"), String.Empty);
-		display_next_button.Clicked += new EventHandler (HandleDisplayNextButtonClicked);
+	
+			vbox.ShowAll ();
+	
+			Realized += delegate (object o, EventArgs e) {SetColors ();};
+			Preferences.SettingChanged += OnPreferencesChanged;
+		}
+	
+		private void OnPreferencesChanged (object sender, NotifyEventArgs args)
+		{
+			LoadPreference (args.Key);
+		}
+	
+		private void LoadPreference (String key)
+		{
+			object val = Preferences.Get (key);
+	
+			if (val == null)
+				return;
+	
+			switch (key) {
+			case Preferences.CUSTOM_CROP_RATIOS:
+				custom_constraints = new List<SelectionRatioDialog.SelectionConstraint> ();
+				XmlSerializer serializer = new XmlSerializer (typeof(SelectionRatioDialog.SelectionConstraint));
+				foreach (string xml in val as string[]) {
+					custom_constraints.Add ((SelectionRatioDialog.SelectionConstraint)serializer.Deserialize (new StringReader (xml)));
+				}
+				PopulateConstraints ();
+				break;
+			}
+		}
 
-		UpdateButtonSensitivity ();
+		private void PopulateConstraints()
+		{
+			constraints_store = new TreeStore (typeof (string), typeof (string), typeof (double));
+			constraints_combo.Model = constraints_store;
+			foreach (SelectionRatioDialog.SelectionConstraint constraint in default_constraints)
+				constraints_store.AppendValues (null, constraint.Label, constraint.XyRatio);
+			foreach (SelectionRatioDialog.SelectionConstraint constraint in custom_constraints)
+				constraints_store.AppendValues (null, constraint.Label, constraint.XyRatio);
+			constraints_store.AppendValues (Stock.Edit, Catalog.GetString ("Custom Ratios..."), -1.0);
+			constraints_combo.Active = 0;
+		}
 
-		vbox.ShowAll ();
+		void ConstraintNameCellFunc (CellLayout cell_layout, CellRenderer cell, TreeModel tree_model, TreeIter iter)
+		{
+			string name = (string)tree_model.GetValue (iter, 1);
+			(cell as CellRendererText).Text = name;	
+		}
 
-		Realized += delegate (object o, EventArgs e) {SetColors ();};
-	}
+		void ConstraintPixCellFunc (CellLayout cell_layout, CellRenderer cell, TreeModel tree_model, TreeIter iter)
+		{
+			string stockname = (string)tree_model.GetValue (iter, 0);
+			if (stockname != null)
+				(cell as CellRendererPixbuf).Pixbuf = GtkUtil.TryLoadIcon (FSpot.Global.IconTheme, stockname, 16, (Gtk.IconLookupFlags)0);
+			else
+				(cell as CellRendererPixbuf).Pixbuf = null;
+		}
 
-	private void SetColors ()
-	{
-		GtkUtil.ModifyColors (filmstrip);
-		GtkUtil.ModifyColors (tag_view);
-		GtkUtil.ModifyColors (photo_view);
-		GtkUtil.ModifyColors (background);
-		GtkUtil.ModifyColors (photo_view_scrolled);
-		GtkUtil.ModifyColors (rating);
-	}
+		void HandleConstraintsComboChanged (object o, EventArgs e)
+		{
+			TreeIter iter;
+			if (constraints_combo.GetActiveIter (out iter)) {
+				double ratio = ((double)constraints_store.GetValue(iter, 2));
+				if (ratio >= 0.0)
+					photo_view.SelectionXyRatio = ratio;
+				else {
+					SelectionRatioDialog dialog = new SelectionRatioDialog ();
+					dialog.Dialog.Run ();
+				}
+			}	
+		}
 
-	protected override void OnStyleSet (Style previous)
-	{
-		SetColors ();
+		private void SetColors ()
+		{
+			GtkUtil.ModifyColors (filmstrip);
+			GtkUtil.ModifyColors (tag_view);
+			GtkUtil.ModifyColors (photo_view);
+			GtkUtil.ModifyColors (background);
+			GtkUtil.ModifyColors (photo_view_scrolled);
+			GtkUtil.ModifyColors (rating);
+		}
+	
+		protected override void OnStyleSet (Style previous)
+		{
+			SetColors ();
+		}
 	}
 }
-}

Modified: trunk/src/Preferences.cs
==============================================================================
--- trunk/src/Preferences.cs	(original)
+++ trunk/src/Preferences.cs	Wed Mar 26 10:21:29 2008
@@ -29,6 +29,7 @@
 		public const string VIEWER_INTERPOLATION = "/apps/f-spot/viewer/interpolation";
 		public const string VIEWER_TRANS_COLOR = "/apps/f-spot/viewer/trans_color";
 		public const string VIEWER_TRANSPARENCY = "/apps/f-spot/viewer/transparency";
+		public const string CUSTOM_CROP_RATIOS = "/apps/f-spot/viewer/custom_crop_ratios";
 		
 		public const string SHOW_TOOLBAR = "/apps/f-spot/ui/show_toolbar";
 		public const string SHOW_SIDEBAR = "/apps/f-spot/ui/show_sidebar";
@@ -200,7 +201,8 @@
 			case PROXY_USER:
 			case PROXY_PASSWORD:
 				return String.Empty;
-			
+			case CUSTOM_CROP_RATIOS:
+				return new string [] {};
 			default:
 				return null;
 			}

Added: trunk/src/UI.Dialog/SelectionRatioDialog.cs
==============================================================================
--- (empty file)
+++ trunk/src/UI.Dialog/SelectionRatioDialog.cs	Wed Mar 26 10:21:29 2008
@@ -0,0 +1,177 @@
+/*
+ * FSpot.UI.Dialog.SelectionRatioDailog.cs
+ *
+ * Author(s):
+ *	Stephane Delcroix  <stephane delcroix org>
+ *
+ * This is free software. See COPYING fro details.
+ */
+
+using System;
+using System.IO;
+using System.Xml.Serialization;
+using System.Collections.Generic;
+
+using Gtk;
+
+using Mono.Unix;
+
+namespace FSpot.UI.Dialog {
+	public class SelectionRatioDialog : GladeDialog
+	{
+		[Serializable]
+		public struct SelectionConstraint {
+			private string label;
+			public string Label {
+				get { return label; }
+				set { label = value; }
+			}
+			private double ratio;
+			public double XyRatio {
+				get { return ratio; }
+				set { ratio = value; }
+			}
+			
+			public SelectionConstraint (string label, double ratio)
+			{
+				this.label = label;
+				this.ratio = ratio;
+			}
+		}
+
+		[Glade.Widget] Button close_button;
+		[Glade.Widget] Button add_button;
+		[Glade.Widget] Button delete_button;
+		[Glade.Widget] Button up_button;
+		[Glade.Widget] Button down_button;
+		[Glade.Widget] TreeView content_treeview;
+		private ListStore constraints_store;
+
+		public SelectionRatioDialog () : base ("customratio_dialog")
+		{
+			close_button.Clicked += delegate (object o, EventArgs e) {SavePrefs (); this.Dialog.Destroy (); };
+			add_button.Clicked += delegate (object o, EventArgs e) {constraints_store.AppendValues ("New Selection", 1.0);};
+			delete_button.Clicked += DeleteSelectedRows;
+			up_button.Clicked += MoveUp;
+			down_button.Clicked += MoveDown;
+			CellRendererText text_renderer = new CellRendererText ();
+			text_renderer.Editable = true;
+			text_renderer.Edited += HandleLabelEdited;
+			content_treeview.AppendColumn (Catalog.GetString ("Label"), text_renderer, "text", 0);
+			text_renderer = new CellRendererText ();
+			text_renderer.Editable = true;
+			text_renderer.Edited += HandleRatioEdited;
+			content_treeview.AppendColumn (Catalog.GetString ("Ratio"), text_renderer, "text", 1);
+
+			LoadPreference (Preferences.CUSTOM_CROP_RATIOS);
+			Preferences.SettingChanged += OnPreferencesChanged;
+		}
+	
+		private void Populate ()
+		{
+			constraints_store = new ListStore (typeof (string), typeof (double));
+			content_treeview.Model = constraints_store;
+			XmlSerializer serializer = new XmlSerializer (typeof(SelectionConstraint));
+			foreach (string xml in Preferences.Get (Preferences.CUSTOM_CROP_RATIOS) as string[]) {
+				SelectionConstraint constraint = (SelectionConstraint)serializer.Deserialize (new StringReader (xml));
+				constraints_store.AppendValues (constraint.Label, constraint.XyRatio);
+			}	
+		}
+
+		private void OnPreferencesChanged (object sender, NotifyEventArgs args)
+		{
+			LoadPreference (args.Key);
+		}
+	
+		private void LoadPreference (String key)
+		{
+			object val = Preferences.Get (key);
+	
+			if (val == null)
+				return;
+	
+			switch (key) {
+			case Preferences.CUSTOM_CROP_RATIOS:
+				Populate ();
+				break;
+			}
+		}
+
+		private void SavePrefs ()
+		{
+			List<string> prefs = new List<string> ();
+			XmlSerializer serializer = new XmlSerializer (typeof (SelectionConstraint));
+			foreach (object[] row in constraints_store) {
+				StringWriter sw = new StringWriter ();
+				serializer.Serialize (sw, new SelectionConstraint ((string)row[0], (double)row[1]));
+				sw.Close ();
+				prefs.Add (sw.ToString ());
+				Preferences.Set (Preferences.CUSTOM_CROP_RATIOS, prefs.ToArray());
+			}
+		}
+
+		public void HandleLabelEdited (object sender, EditedArgs args)
+		{
+			args.RetVal = false;
+			TreeIter iter;
+			if (!constraints_store.GetIterFromString (out iter, args.Path))
+				return;
+
+			using (GLib.Value val = new GLib.Value (args.NewText))
+				constraints_store.SetValue (iter, 0, val);
+
+			args.RetVal = true;
+		}
+
+		public void HandleRatioEdited (object sender, EditedArgs args)
+		{
+			args.RetVal = false;
+			TreeIter iter;
+			if (!constraints_store.GetIterFromString (out iter, args.Path))
+				return;
+
+			double ratio = Convert.ToDouble (args.NewText);
+			if (ratio < 1.0)
+				return;
+
+			using (GLib.Value val = new GLib.Value (ratio))
+				constraints_store.SetValue (iter, 1, val);
+
+			args.RetVal = true;
+		}
+
+
+		private void DeleteSelectedRows (object o, EventArgs e)
+		{
+			TreeIter iter;
+			TreeModel model;
+			if (content_treeview.Selection.GetSelected (out model, out iter))
+				(model as ListStore).Remove (ref iter);
+		}
+
+		private void MoveUp (object o, EventArgs e)
+		{
+			TreeIter selected;
+			TreeModel model;
+			if (content_treeview.Selection.GetSelected (out model, out selected)) {
+				//no IterPrev :(
+				TreeIter prev;
+				TreePath path = model.GetPath (selected);
+				if (path.Prev ())
+					if (model.GetIter (out prev, path))
+						(model as ListStore).Swap (prev, selected);
+			}
+		}
+
+		private void MoveDown (object o, EventArgs e)
+		{
+			TreeIter current;
+			TreeModel model;
+			if (content_treeview.Selection.GetSelected (out model, out current)) {
+				TreeIter next = current;
+				if ((model as ListStore).IterNext (ref next))
+					(model as ListStore).Swap (current, next);
+			}
+		}
+	}
+}

Modified: trunk/src/f-spot.glade
==============================================================================
--- trunk/src/f-spot.glade	(original)
+++ trunk/src/f-spot.glade	Wed Mar 26 10:21:29 2008
@@ -8049,4 +8049,120 @@
       </widget>
     </child>
   </widget>
+  <widget class="GtkDialog" id="customratio_dialog">
+    <property name="border_width">5</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox26">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="vbox6">
+            <property name="visible">True</property>
+            <child>
+              <widget class="GtkLabel" id="label6">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">Manage your custom selection ratios</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="padding">6</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox7">
+                <property name="visible">True</property>
+                <child>
+                  <widget class="GtkTreeView" id="content_treeview">
+                    <property name="visible">True</property>
+                  </widget>
+                  <packing>
+                    <property name="padding">6</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkVButtonBox" id="vbuttonbox1">
+                    <property name="visible">True</property>
+                    <property name="spacing">6</property>
+                    <property name="layout_style">GTK_BUTTONBOX_START</property>
+                    <child>
+                      <widget class="GtkButton" id="add_button">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">gtk-add</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="delete_button">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">gtk-delete</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="up_button">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">gtk-go-up</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="down_button">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">gtk-go-down</property>
+                        <property name="use_stock">True</property>
+                      </widget>
+                      <packing>
+                        <property name="position">3</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="padding">6</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area26">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="close_button">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+              </widget>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
 </glade-interface>



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