f-spot r4241 - in trunk: . src src/Editors src/Editors/Old src/Extensions src/Filters src/Widgets



Author: rubenv
Date: Tue Aug 12 10:30:00 2008
New Revision: 4241
URL: http://svn.gnome.org/viewvc/f-spot?rev=4241&view=rev

Log:
2008-08-08  Ruben Vermeersch  <ruben savanne be>

	Google Summer of Code 2008: Sidebar Improvements, version 1.

	This commit contains the bulk of my Summer of Code 2008 work, which aimed
	to move the editors into a switchable sidebar.

	* src/Editors/AutoStretchEditor.cs: Added.
	* src/Editors/CropEditor.cs: Added.
	* src/Editors/DesaturateEditor.cs: Added.
	* src/Editors/Editor.cs: Added.
	* src/Editors/Old/SoftFocus.cs: Removed.
	* src/Editors/Old/Tilt.cs: Removed.
	* src/Editors/RedEyeEditor.cs: Added.
	* src/Editors/SepiaEditor.cs: Added.
	* src/Editors/SoftFocusEditor.cs: Added.
	* src/Editors/TiltEditor.cs: Added.

	All previous files contain implementations of Editor tools. These are
	hooked up through the /FSpot/Editors addin point. The Editor class
	contains the abstract editor implementation. All other editors derive from
	this class, overriding methods where needed (Template Method Pattern).
	Most Editor options are set in the constructor (e.g. whether it needs a
	selection to operate).

	* src/Extensions/ViewModeCondition.cs: Do a small cleanup of
	ViewModeCondition, drop the Initialize method.

	* src/FSpot.addin.xml: Add the /FSpot/Editors extension point.

	* src/Filters/TiltFilter.cs: Removed.

	* src/ItemAction.cs: Most of this has become obsolete.

	* src/MainWindow.cs: Expose the PhotoView.

	* src/Makefile.am: Add / Remove needed files.

	* src/PhotoImageView.cs: Make sure we can poke at ZoomFit.

	* src/PhotoView.cs: Deprecate most of the old editors.

	* src/Widgets/EditorPage.cs: This hooks the editor tools into the sidebar.

	* src/Widgets/ImageDisplay.cs: Remove shortcuts from ImageDisplay, which
	is btw not used and should probably be removed completely.

	* src/Widgets/Sidebar.cs: Reflect the changes made in ViewModeCondition.

	* src/Widgets/SoftFocus.cs: Replaced with src/SoftFocus.cs.

	* src/Widgets/Tilt.cs: Removed.


Added:
   trunk/src/Editors/AutoStretchEditor.cs
   trunk/src/Editors/CropEditor.cs
   trunk/src/Editors/DesaturateEditor.cs
   trunk/src/Editors/Editor.cs
   trunk/src/Editors/RedEyeEditor.cs
   trunk/src/Editors/SepiaEditor.cs
   trunk/src/Editors/SoftFocusEditor.cs
   trunk/src/Editors/TiltEditor.cs
   trunk/src/SoftFocus.cs
      - copied, changed from r4240, /trunk/src/Widgets/SoftFocus.cs
Removed:
   trunk/src/Editors/Old/SoftFocus.cs
   trunk/src/Editors/Old/Tilt.cs
   trunk/src/Filters/TiltFilter.cs
   trunk/src/Widgets/SoftFocus.cs
   trunk/src/Widgets/Tilt.cs
Modified:
   trunk/ChangeLog
   trunk/src/Extensions/ViewModeCondition.cs
   trunk/src/FSpot.addin.xml
   trunk/src/ItemAction.cs
   trunk/src/MainWindow.cs
   trunk/src/Makefile.am
   trunk/src/PhotoImageView.cs
   trunk/src/PhotoView.cs
   trunk/src/Widgets/EditorPage.cs
   trunk/src/Widgets/ImageDisplay.cs
   trunk/src/Widgets/Sidebar.cs

Added: trunk/src/Editors/AutoStretchEditor.cs
==============================================================================
--- (empty file)
+++ trunk/src/Editors/AutoStretchEditor.cs	Tue Aug 12 10:30:00 2008
@@ -0,0 +1,27 @@
+/*
+ * SepiaEditor.cs
+ *
+ * Author(s)
+ * 	Ruben Vermeersch <ruben savanne be>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using FSpot;
+using FSpot.ColorAdjustment;
+using Gdk;
+using Mono.Unix;
+
+namespace FSpot.Editors {
+    class AutoStretchEditor : Editor {
+        public AutoStretchEditor () : base (Catalog.GetString ("Auto Color"), "autocolor") {
+			// FIXME: need tooltip Catalog.GetString ("Automatically adjust the colors")
+			CanHandleMultiple = true;
+        }
+
+        protected override Pixbuf Process (Pixbuf input, Cms.Profile input_profile) {
+            AutoStretch autostretch = new AutoStretch (input, input_profile);
+            return autostretch.Adjust ();
+        }
+    }
+}

Added: trunk/src/Editors/CropEditor.cs
==============================================================================
--- (empty file)
+++ trunk/src/Editors/CropEditor.cs	Tue Aug 12 10:30:00 2008
@@ -0,0 +1,181 @@
+/*
+ * CropEditor.cs
+ *
+ * Author(s)
+ * 	Ruben Vermeersch <ruben savanne be>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using FSpot;
+using FSpot.UI.Dialog;
+using FSpot.Utils;
+using Gdk;
+using Gtk;
+using Mono.Unix;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml.Serialization;
+
+namespace FSpot.Editors {
+	class CropEditor : Editor {
+		private TreeStore constraints_store;
+		private ComboBox constraints_combo;
+
+		public enum ConstraintType {
+			Normal,
+			AddCustom,
+			SameAsPhoto
+		}
+
+		private List<SelectionRatioDialog.SelectionConstraint> custom_constraints;
+
+		private static SelectionRatioDialog.SelectionConstraint [] default_constraints = {
+			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 CropEditor () : base (Catalog.GetString ("Crop"), "crop") {
+			NeedsSelection = true;
+
+			Preferences.SettingChanged += OnPreferencesChanged;
+
+			Initialized += delegate { State.PhotoImageView.PhotoChanged += delegate { UpdateSelectionCombo (); }; };
+		}
+
+		private void OnPreferencesChanged (object sender, NotifyEventArgs args)
+		{
+			LoadPreference (args.Key);
+		}
+
+		private void LoadPreference (String key)
+		{
+			switch (key) {
+			case Preferences.CUSTOM_CROP_RATIOS:
+				custom_constraints = new List<SelectionRatioDialog.SelectionConstraint> ();
+				if (Preferences.Get<string[]> (key) != null) {
+					XmlSerializer serializer = new XmlSerializer (typeof(SelectionRatioDialog.SelectionConstraint));
+					foreach (string xml in Preferences.Get<string[]> (key))
+						custom_constraints.Add ((SelectionRatioDialog.SelectionConstraint)serializer.Deserialize (new StringReader (xml)));
+				}
+				PopulateConstraints ();
+				break;
+			}
+		}
+
+		public override Widget ConfigurationWidget () {
+			VBox vbox = new VBox ();
+
+			Label info = new Label("Select the area that needs cropping.");
+
+			constraints_combo = new ComboBox ();
+			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;
+
+			// FIXME: need tooltip Catalog.GetString ("Constrain the aspect ratio of the selection")
+
+			LoadPreference (Preferences.CUSTOM_CROP_RATIOS);
+
+			vbox.Add (info);
+			vbox.Add (constraints_combo);
+
+			return vbox;
+		}
+
+		private void PopulateConstraints()
+		{
+			constraints_store = new TreeStore (typeof (string), typeof (string), typeof (double), typeof (ConstraintType));
+			constraints_combo.Model = constraints_store;
+			constraints_store.AppendValues (null, Catalog.GetString ("No Constraint"), 0.0, ConstraintType.Normal);
+			constraints_store.AppendValues (null, Catalog.GetString ("Same as photo"), 0.0, ConstraintType.SameAsPhoto);
+			foreach (SelectionRatioDialog.SelectionConstraint constraint in custom_constraints)
+				constraints_store.AppendValues (null, constraint.Label, constraint.XyRatio, ConstraintType.Normal);
+			foreach (SelectionRatioDialog.SelectionConstraint constraint in default_constraints)
+				constraints_store.AppendValues (null, constraint.Label, constraint.XyRatio, ConstraintType.Normal);
+			constraints_store.AppendValues (Stock.Edit, Catalog.GetString ("Custom Ratios..."), 0.0, ConstraintType.AddCustom);
+			constraints_combo.Active = 0;
+		}
+
+		public void UpdateSelectionCombo ()
+		{
+			if (!StateInitialized)
+				return;
+
+			//constraints_combo.Active = 0;
+			TreeIter iter;
+			if (constraints_combo.GetActiveIter (out iter)) {
+				if (((ConstraintType)constraints_store.GetValue (iter, 3)) == ConstraintType.SameAsPhoto)
+					constraints_combo.Active = 0;
+			}
+		}
+
+		private void HandleConstraintsComboChanged (object o, EventArgs e)
+		{
+			if (State.PhotoImageView == null) {
+				Log.Debug ("PhotoImageView is null");
+				return;
+			}
+
+			TreeIter iter;
+			if (constraints_combo.GetActiveIter (out iter)) {
+				double ratio = ((double)constraints_store.GetValue (iter, 2));
+				ConstraintType type = ((ConstraintType)constraints_store.GetValue (iter, 3));
+				switch (type) {
+				case ConstraintType.Normal:
+					State.PhotoImageView.SelectionXyRatio = ratio;
+					break;
+				case ConstraintType.AddCustom:
+					SelectionRatioDialog dialog = new SelectionRatioDialog ();
+					dialog.Dialog.Run ();
+					break;
+				case ConstraintType.SameAsPhoto:
+					try {
+						Pixbuf pb = State.PhotoImageView.CompletePixbuf ();
+						State.PhotoImageView.SelectionXyRatio = (double)pb.Width / (double)pb.Height;
+					} catch (System.Exception ex) {
+						Log.WarningFormat ("Exception in selection ratio's: {0}", ex);
+						State.PhotoImageView.SelectionXyRatio = 0;
+					}
+					break;
+				default:
+					State.PhotoImageView.SelectionXyRatio = 0;
+					break;
+				}
+			}
+		}
+
+		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;
+		}
+
+		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;
+		}
+
+		protected override Pixbuf Process (Pixbuf input, Cms.Profile input_profile) {
+			Pixbuf edited = new Pixbuf (input.Colorspace,
+						 input.HasAlpha, input.BitsPerSample,
+						 State.Selection.width, State.Selection.height);
+
+			input.CopyArea (State.Selection.x, State.Selection.y,
+					State.Selection.width, State.Selection.height, edited, 0, 0);
+			return edited;
+		}
+	}
+}

Added: trunk/src/Editors/DesaturateEditor.cs
==============================================================================
--- (empty file)
+++ trunk/src/Editors/DesaturateEditor.cs	Tue Aug 12 10:30:00 2008
@@ -0,0 +1,27 @@
+/*
+ * DesaturateEditor.cs
+ *
+ * Author(s)
+ * 	Ruben Vermeersch <ruben savanne be>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using FSpot;
+using FSpot.ColorAdjustment;
+using Gdk;
+using Mono.Unix;
+
+namespace FSpot.Editors {
+    class DesaturateEditor : Editor {
+        public DesaturateEditor () : base (Catalog.GetString ("Desaturate"), "color-desaturate") {
+			// FIXME: need tooltip Catalog.GetString ("Convert the photo to black and white")
+			CanHandleMultiple = true;
+        }
+
+        protected override Pixbuf Process (Pixbuf input, Cms.Profile input_profile) {
+            Desaturate desaturate = new Desaturate (input, input_profile);
+            return desaturate.Adjust ();
+        }
+    }
+}

Added: trunk/src/Editors/Editor.cs
==============================================================================
--- (empty file)
+++ trunk/src/Editors/Editor.cs	Tue Aug 12 10:30:00 2008
@@ -0,0 +1,244 @@
+/*
+ * Editor.cs
+ *
+ * Author(s)
+ * 	Ruben Vermeersch <ruben savanne be>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using FSpot;
+using FSpot.Utils;
+
+using Gdk;
+using Gtk;
+
+using Mono.Addins;
+using Mono.Unix;
+
+using System;
+
+namespace FSpot.Editors {
+	[ExtensionNode ("Editor")]
+	public class EditorNode : ExtensionNode {
+		[NodeAttribute (Required=true)]
+		protected string editor_type;
+
+		public Editor GetEditor () {
+			return (Editor) Addin.CreateInstance (editor_type);
+		}
+	}
+
+	public class EditorSelection {
+		public int x, y;
+		public int width, height;
+	}
+
+	public class EditorState {
+		// The area selected by the user.
+		public EditorSelection Selection;
+
+		// The images selected by the user.
+		public IBrowsableItem [] Items;
+
+		// The view, into which images are shown (null if we are in the browse view).
+		public PhotoImageView PhotoImageView;
+
+		// Has a portion of the image been selected?
+		public bool HasSelection {
+			get { return Selection != null; }
+		}
+
+		// Is the user in browse mode?
+		public bool InBrowseMode {
+			get { return PhotoImageView == null; }
+		}
+	}
+
+	// This is the base class from which all editors inherit.
+	public abstract class Editor {
+		// Contains the current selection, the items being edited, ...
+		private EditorState state;
+		public EditorState State {
+			get {
+				if (!StateInitialized)
+					throw new ApplicationException ("Editor has not been initialized yet!");
+
+				return state;
+			}
+			private set { state = value; }
+		}
+
+		public bool StateInitialized {
+			get { return state != null; }
+		}
+
+
+		// Whether the user needs to select a part of the image before it can be applied.
+		public bool NeedsSelection = false;
+
+		// A tool can be applied if it doesn't need a selection, or if it has one.
+		public bool CanBeApplied {
+			get {
+				Log.DebugFormat ("{0} can be applied? {1}", this, !NeedsSelection || (NeedsSelection && State.HasSelection));
+				return !NeedsSelection || (NeedsSelection && State.HasSelection);
+			}
+		}
+
+		private bool can_handle_multiple = false;
+		public bool CanHandleMultiple {
+			get { return can_handle_multiple; }
+			protected set { can_handle_multiple = value; }
+		}
+
+
+		protected void LoadPhoto (Photo photo, out Pixbuf photo_pixbuf, out Cms.Profile photo_profile) {
+			// FIXME: We might get this value from the PhotoImageView.
+			using (ImageFile img = ImageFile.Create (photo.DefaultVersionUri)) {
+				photo_pixbuf = img.Load ();
+				photo_profile = img.GetProfile ();
+			}
+		}
+
+		// The human readable name for this action.
+		public readonly string Label;
+
+		// The label on the apply button (usually shorter than the label).
+		private string apply_label = "";
+		public string ApplyLabel {
+			get { return apply_label == "" ? Label : apply_label; }
+			protected set { apply_label = value; }
+		}
+
+
+		// The icon name for this action (will be loaded from the theme).
+		public readonly string IconName;
+
+		public Editor (string label, string icon_name) {
+			Label = label;
+			IconName = icon_name;
+		}
+
+		// Apply the editor's action to a photo.
+		public void Apply () {
+			if (NeedsSelection && !State.HasSelection) {
+				throw new Exception ("Cannot apply without selection!");
+			}
+
+			foreach (Photo photo in State.Items) {
+				Pixbuf input;
+				Cms.Profile input_profile;
+				LoadPhoto (photo, out input, out input_profile);
+
+				Pixbuf edited = Process (input, input_profile);
+				input.Dispose ();
+
+				bool create_version = photo.DefaultVersion.IsProtected;
+				photo.SaveVersion (edited, create_version);
+				photo.Changes.DataChanged = true;
+				Core.Database.Photos.Commit (photo);
+			}
+
+			Reset ();
+		}
+
+		protected abstract Pixbuf Process (Pixbuf input, Cms.Profile input_profile);
+
+		protected virtual Pixbuf ProcessFast (Pixbuf input, Cms.Profile input_profile) {
+			return Process (input, input_profile);
+		}
+
+		private bool has_settings;
+		public bool HasSettings {
+			get { return has_settings; }
+			protected set { has_settings = value; }
+		}
+
+		private Pixbuf original;
+		private Pixbuf preview;
+		protected void UpdatePreview () {
+			if (State.InBrowseMode) {
+				throw new Exception ("Previews cannot be made in browse mode!");
+			}
+
+			if (State.Items.Length > 1) {
+				throw new Exception ("We should have one item selected when this happened, otherwise something is terribly wrong.");
+			}
+
+			if (original == null) {
+				original = State.PhotoImageView.Pixbuf;
+			}
+
+			if (preview == null) {
+				int width, height;
+				CalcPreviewSize (original, out width, out height);
+				preview = original.ScaleSimple (width, height, InterpType.Nearest);
+			}
+
+			Pixbuf previewed = ProcessFast (preview, null);
+			State.PhotoImageView.Pixbuf = previewed;
+			State.PhotoImageView.ZoomFit (false);
+		}
+
+		private void CalcPreviewSize (Pixbuf input, out int width, out int height) {
+			int awidth = State.PhotoImageView.Allocation.Width;
+			int aheight = State.PhotoImageView.Allocation.Height;
+			int iwidth = input.Width;
+			int iheight = input.Height;
+
+			if (iwidth <= awidth && iheight <= aheight) {
+				// Do not upscale
+				width = iwidth;
+				height = iheight;
+			} else {
+				double wratio = (double) iwidth / awidth;
+				double hratio = (double) iheight / aheight;
+
+				double ratio = Math.Max (wratio, hratio);
+				width = (int) (iwidth / ratio);
+				height = (int) (iheight / ratio);
+			}
+			//Log.DebugFormat ("Preview size: Allocation: {0}x{1}, Input: {2}x{3}, Result: {4}x{5}", awidth, aheight, iwidth, iheight, width, height);
+		}
+
+		public void Restore () {
+			if (original != null && State.PhotoImageView != null) {
+				State.PhotoImageView.Pixbuf = original;
+				State.PhotoImageView.ZoomFit (false);
+			}
+
+			Reset ();
+		}
+
+		private void Reset () {
+			if (preview != null) {
+				preview.Dispose ();
+			}
+
+			preview = null;
+			original = null;
+			State = null;
+		}
+
+		// Can be overriden to provide a specific configuration widget.
+		// Returning null means no configuration widget.
+		public virtual Widget ConfigurationWidget () {
+			return null;
+		}
+
+
+		public virtual EditorState CreateState () {
+			return new EditorState ();
+		}
+
+		public event InitializedHandler Initialized;
+		public delegate void InitializedHandler ();
+
+		public void Initialize (EditorState state) {
+			State = state;
+
+			if (Initialized != null)
+				Initialized ();
+		}
+	}
+}

Added: trunk/src/Editors/RedEyeEditor.cs
==============================================================================
--- (empty file)
+++ trunk/src/Editors/RedEyeEditor.cs	Tue Aug 12 10:30:00 2008
@@ -0,0 +1,35 @@
+/*
+ * RedEyeEditor.cs
+ *
+ * Author(s)
+ * 	Ruben Vermeersch <ruben savanne be>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using FSpot;
+using FSpot.Utils;
+using Gdk;
+using Gtk;
+using Mono.Unix;
+using System;
+
+namespace FSpot.Editors {
+	class RedEyeEditor : Editor {
+		public RedEyeEditor () : base (Catalog.GetString ("Red-eye Reduction"), "red-eye-remove") {
+			NeedsSelection = true;
+			ApplyLabel = Catalog.GetString ("Fix!");
+		}
+
+		public override Widget ConfigurationWidget () {
+			return new Label("Select the eyes you wish to fix.");
+		}
+
+		protected override Pixbuf Process (Pixbuf input, Cms.Profile input_profile) {
+			Gdk.Rectangle area = new Gdk.Rectangle (State.Selection.x, State.Selection.y,
+					State.Selection.width, State.Selection.height);
+			int threshold = Preferences.Get<int> (Preferences.EDIT_REDEYE_THRESHOLD);
+			return PixbufUtils.RemoveRedeye (input, area, threshold);
+		}
+	}
+}

Added: trunk/src/Editors/SepiaEditor.cs
==============================================================================
--- (empty file)
+++ trunk/src/Editors/SepiaEditor.cs	Tue Aug 12 10:30:00 2008
@@ -0,0 +1,27 @@
+/*
+ * SepiaEditor.cs
+ *
+ * Author(s)
+ * 	Ruben Vermeersch <ruben savanne be>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using FSpot;
+using FSpot.ColorAdjustment;
+using Gdk;
+using Mono.Unix;
+
+namespace FSpot.Editors {
+    class SepiaEditor : Editor {
+        public SepiaEditor () : base (Catalog.GetString ("Sepia Tone"), "color-sepia") {
+			// FIXME: need tooltip Catalog.GetString ("Convert the photo to sepia tones")
+			CanHandleMultiple = true;
+        }
+
+        protected override Pixbuf Process (Pixbuf input, Cms.Profile input_profile) {
+            SepiaTone sepia = new SepiaTone (input, input_profile);
+            return sepia.Adjust ();
+        }
+    }
+}

Added: trunk/src/Editors/SoftFocusEditor.cs
==============================================================================
--- (empty file)
+++ trunk/src/Editors/SoftFocusEditor.cs	Tue Aug 12 10:30:00 2008
@@ -0,0 +1,78 @@
+/*
+ * SoftFocusEditor.cs
+ *
+ * Author(s)
+ * 	Ruben Vermeersch <ruben savanne be>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using Cairo;
+
+using FSpot.Widgets;
+
+using Gdk;
+using Gtk;
+
+using Mono.Unix;
+
+using System;
+
+namespace FSpot.Editors {
+	// TODO: This had a keybinding e. Maybe we should add it back, but did people even knew it?
+	class SoftFocusEditor : Editor
+	{
+		double radius;
+		Scale scale;
+
+		public SoftFocusEditor () : base (Catalog.GetString ("Soft Focus"), "filter-soft-focus") {
+			// FIXME: need tooltip Catalog.GetString ("Create a soft focus visual effect")
+			HasSettings = true;
+        }
+
+		public override Widget ConfigurationWidget ()
+		{
+			scale = new HScale (0, 1, .01);
+			scale.Value = 0.5;
+			scale.ValueChanged += HandleValueChanged;
+			return scale;
+		}
+
+
+		protected override Pixbuf Process (Pixbuf input, Cms.Profile input_profile) {
+			return ProcessImpl (input, input_profile, false);
+		}
+
+		protected override Pixbuf ProcessFast (Pixbuf input, Cms.Profile input_profile)
+		{
+			return ProcessImpl (input, input_profile, true);
+		}
+
+
+		private Pixbuf ProcessImpl (Pixbuf input, Cms.Profile input_profile, bool fast) {
+			Pixbuf result;
+			using (ImageInfo info = new ImageInfo (input)) {
+				Widgets.SoftFocus soft = new Widgets.SoftFocus (info);
+				soft.Radius = radius;
+
+				MemorySurface surface = new MemorySurface (Format.Argb32,
+									   input.Width,
+									   input.Height);
+
+				Context ctx = new Context (surface);
+				soft.Apply (ctx, info.Bounds);
+				((IDisposable)ctx).Dispose ();
+
+				result = MemorySurface.CreatePixbuf (surface);
+				surface.Flush ();
+			}
+			return result;
+		}
+
+		private void HandleValueChanged (object sender, System.EventArgs args)
+		{
+			radius = scale.Value;
+			UpdatePreview ();
+		}
+	}
+}

Added: trunk/src/Editors/TiltEditor.cs
==============================================================================
--- (empty file)
+++ trunk/src/Editors/TiltEditor.cs	Tue Aug 12 10:30:00 2008
@@ -0,0 +1,81 @@
+/*
+ * TiltEditor.cs
+ *
+ * Author(s)
+ * 	Ruben Vermeersch <ruben savanne be>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+using Cairo;
+
+using FSpot.Widgets;
+
+using Gdk;
+using Gtk;
+
+using Mono.Unix;
+
+using System;
+
+namespace FSpot.Editors {
+	// TODO: there were keybindings (left/right) to adjust tilt, maybe they should be added back.
+	class TiltEditor : Editor
+	{
+		double angle;
+		Scale scale;
+
+		public TiltEditor () : base (Catalog.GetString ("Straighten"), "align-horizon") {
+			// FIXME: need tooltip Catalog.GetString ("Adjust the angle of the image to straighten the horizon")
+			HasSettings = true;
+        }
+
+		public override Widget ConfigurationWidget ()
+		{
+			scale = new HScale (-45, 45, 1);
+			scale.Value = 0.0;
+			scale.ValueChanged += HandleValueChanged;
+			return scale;
+		}
+
+
+		protected override Pixbuf Process (Pixbuf input, Cms.Profile input_profile) {
+			return ProcessImpl (input, input_profile, false);
+		}
+
+		protected override Pixbuf ProcessFast (Pixbuf input, Cms.Profile input_profile)
+		{
+			return ProcessImpl (input, input_profile, true);
+		}
+
+
+		private Pixbuf ProcessImpl (Pixbuf input, Cms.Profile input_profile, bool fast) {
+			Pixbuf result;
+			using (ImageInfo info = new ImageInfo (input)) {
+				MemorySurface surface = new MemorySurface (Format.Argb32,
+									   input.Width,
+									   input.Height);
+
+				Context ctx = new Context (surface);
+				ctx.Matrix = info.Fill (info.Bounds, angle);
+				SurfacePattern p = new SurfacePattern (info.Surface);
+				if (fast) {
+					p.Filter =  Filter.Fast;
+				}
+				ctx.Source = p;
+				ctx.Paint ();
+				((IDisposable)ctx).Dispose ();
+				p.Destroy ();
+				result = MemorySurface.CreatePixbuf (surface);
+				surface.Flush ();
+			}
+			return result;
+		}
+
+		private void HandleValueChanged (object sender, System.EventArgs args)
+		{
+			angle = scale.Value * Math.PI / 180;
+			UpdatePreview ();
+		}
+	}
+}

Modified: trunk/src/Extensions/ViewModeCondition.cs
==============================================================================
--- trunk/src/Extensions/ViewModeCondition.cs	(original)
+++ trunk/src/Extensions/ViewModeCondition.cs	Tue Aug 12 10:30:00 2008
@@ -33,15 +33,17 @@
 		private static event ViewModeChangedHandler ViewModeChanged;
 		private delegate void ViewModeChangedHandler ();
 
-		private static ViewMode Mode = ViewMode.Unknown;
+		private static ViewMode mode = ViewMode.Unknown;
+		public static ViewMode Mode {
+			get { return mode; }
+			set {
+				mode = value;
 
-		public static void Initialize (ViewMode mode) {
-			Mode = mode;
-
-			if (ViewModeChanged != null)
-				ViewModeChanged ();
+				if (ViewModeChanged != null)
+					ViewModeChanged ();
+			}
 		}
-		
+
 		public ViewModeCondition ()
 		{
 			ViewModeChanged += delegate { NotifyChanged (); };

Modified: trunk/src/FSpot.addin.xml
==============================================================================
--- trunk/src/FSpot.addin.xml	(original)
+++ trunk/src/FSpot.addin.xml	Tue Aug 12 10:30:00 2008
@@ -1,6 +1,6 @@
 <Addin namespace = "FSpot" 
        id = "Core" 
-       version = "0.4.4.100"
+       version = "0.4.4.101"
        compatVersion = "0.4.4.100"
        isroot="true">
 
@@ -9,6 +9,10 @@
 		<Import assembly="FSpot.Widgets.dll" />
 	</Runtime>
 
+	<ExtensionPoint path = "/FSpot/Editors">
+		<ExtensionNode type="FSpot.Editors.EditorNode"/>
+	</ExtensionPoint>
+
 	<ExtensionPoint path = "/FSpot/Menus">
 		<ExtensionNode type="FSpot.Extensions.SubmenuNode"/>
 	</ExtensionPoint>
@@ -57,4 +61,14 @@
 			<SidebarPage sidebar_page_type = "FSpot.Widgets.EditorPage" />
 		</Condition>
 	</Extension>
+
+	<Extension path = "/FSpot/Editors">
+		<Editor editor_type = "FSpot.Editors.CropEditor"/>
+		<Editor editor_type = "FSpot.Editors.RedEyeEditor"/>
+		<Editor editor_type = "FSpot.Editors.DesaturateEditor"/>
+		<Editor editor_type = "FSpot.Editors.SepiaEditor"/>
+		<Editor editor_type = "FSpot.Editors.TiltEditor"/>
+		<Editor editor_type = "FSpot.Editors.SoftFocusEditor"/>
+		<Editor editor_type = "FSpot.Editors.AutoStretchEditor"/>
+	</Extension>
 </Addin>

Modified: trunk/src/ItemAction.cs
==============================================================================
--- trunk/src/ItemAction.cs	(original)
+++ trunk/src/ItemAction.cs	Tue Aug 12 10:30:00 2008
@@ -140,215 +140,4 @@
 			item.MovePrevious ();
 		}
 	}
-
-	// FIXME this class is a hack to work around the considerable brokeness
-	// in the gaps between Photo and IBrowsable* It helps but it shouldn't
-	// be so introspective.
-	internal class EditTarget {
-		BrowsablePointer item;
-		bool created_version = false;
-		uint version;
-		Photo photo;
-		
-		public EditTarget (BrowsablePointer item)
-		{
-			this.item = item;
-			photo = item.Current as Photo;
-			if (photo != null) {
-				version = photo.DefaultVersionId;
-				bool create = photo.DefaultVersion.IsProtected;
-				
-				if (create) {
-					version = photo.CreateDefaultModifiedVersion (photo.DefaultVersionId, false);
-					created_version = true;
-				}
-			}
-		}
-		
-		public Uri Uri {
-			get {
-				if (photo != null)
-					return photo.VersionUri (version);
-				else 
-					return item.Current.DefaultVersionUri;
-			}
-		}
-
-		public void Commit ()
-		{
-			PhotoQuery q = item.Collection as PhotoQuery;
-			if (photo != null && q != null) {
-				photo.DefaultVersionId = version;
-				photo.Changes.DataChanged = true;
-				q.Commit (item.Index);
-			} else {
-				item.Collection.MarkChanged (item.Index, FullInvalidate.Instance);
-			}
-		}
-		
-		public void Delete ()
-		{
-			if (created_version)
-				photo.DeleteVersion (version);
-		}
-		
-	}
-	
-	public class FilterAction : ItemAction {
-		public FilterAction (BrowsablePointer pointer,
-				     string name,
-				     string label,
-				     string tooltip,
-				     string stock_id) : base (pointer, name, label, tooltip, stock_id)
-		{
-		}
-
-		protected virtual IFilter BuildFilter ()
-		{
-			throw new ApplicationException ("No filter specified");
-		}
-		
-
-		protected override void OnActivated ()
-		{
-			try {
-				if (!item.IsValid)
-					throw new ApplicationException ("attempt to filter invalid item");
-				
-				using (FilterRequest req = new FilterRequest (item.Current.DefaultVersionUri)) {
-					IFilter filter = BuildFilter ();
-					if (filter.Convert (req)) {
-						// The filter did something so lets ve
-						EditTarget target = new EditTarget (item);
-					
-						Gnome.Vfs.Result result = Gnome.Vfs.Result.Ok;
-						result = Gnome.Vfs.Xfer.XferUri (new Gnome.Vfs.Uri (req.Current.ToString ()),
-										 new Gnome.Vfs.Uri (target.Uri.ToString ()),
-										 Gnome.Vfs.XferOptions.Default,
-										 Gnome.Vfs.XferErrorMode.Abort, 
-										 Gnome.Vfs.XferOverwriteMode.Replace, 
-										 delegate {
-											 System.Console.WriteLine ("progress");
-											 return 1;
-										 });
-						
-						if (result == Gnome.Vfs.Result.Ok) {
-							System.Console.WriteLine ("Done modifying image");
-							target.Commit ();
-						} else {
-							target.Delete ();
-							throw new ApplicationException (String.Format (
-												       "{0}: error moving to destination {1}",
-												       this, target.ToString ()));
-						}
-					}
-				}
-			} catch (Exception e) {
-				Dialog d = new EditExceptionDialog (null, e, item.Current);
-				d.Show ();
-				d.Run ();
-				d.Destroy ();
-			} 
-		}
-	}
-
-	public class AutoColor : FilterAction {
-		public AutoColor (BrowsablePointer p)
-			: base (p, "Color", 
-				Catalog.GetString ("Auto Color"),
-				Catalog.GetString ("Automatically adjust the colors"),
-				"autocolor")
-		{
-		}
-
-		protected override IFilter BuildFilter ()
-		{
-			return new AutoStretchFilter ();
-		}
-	}
-
-	public class TiltAction : FilterAction {
-		double angle;
-		public TiltAction (BrowsablePointer p, double angle)
-			: base (p, "ApplyStraighten", 
-				Catalog.GetString ("Apply straightening"),
-				Catalog.GetString ("Apply straightening to image"),
-				"align-horizon")
-		{
-			this.angle = angle;
-		}
-
-		protected override IFilter BuildFilter ()
-		{
-			return new TiltFilter (angle);
-		}
-	}
-
-	public class ViewAction : ItemAction {
-		protected PhotoImageView view;
-
- 		public ViewAction (PhotoImageView view,
-				   string name,
-				   string label,
-				   string tooltip,
-				   string stock_id) : base (view.Item, name, label, tooltip, stock_id)
-		{
-			this.view = view;
-			view.Destroyed += HandleDestroyed;
-		}
-
-		private void HandleDestroyed (object sender, EventArgs args)
-		{
-			view = null;
-			Sensitive = false;
-		}
-	}
-
-	public class ViewEditorAction : ViewAction {
- 		public ViewEditorAction (PhotoImageView view,
-					 string name,
-					 string label,
-					 string tooltip,
-					 string stock_id) : base (view, name, label, tooltip, stock_id)
-		{
-		}
-
-		protected override void ItemChanged (BrowsablePointer p,
-						     BrowsablePointerChangedArgs args)
-		{
-			Sensitive = item.IsValid && view.Editor == null;
-		}
-	}
-
-	public class TiltEditorAction : ViewEditorAction {
-		public TiltEditorAction (PhotoImageView view)
-			: base (view, 
-				"TiltEdit", 
-				Catalog.GetString ("Straighten"),
-				Catalog.GetString ("Adjust the angle of the image to straighten the horizon"),
-				"align-horizon")
-		{
-		}
-
-		protected override void OnActivated ()
-		{
-			view.Editor = new Editors.Tilt (view);
-		}
-	}
-
-	public class SoftFocusEditorAction : ViewEditorAction {
-		public SoftFocusEditorAction (PhotoImageView view)
-			: base (view,
-				"SoftFocusEdit",
-				Catalog.GetString ("Soft Focus"),
-				Catalog.GetString ("Create a soft focus visual effect"),
-				"filter-soft-focus")
-		{
-		}
-
-		protected override void OnActivated ()
-		{
-			view.Editor = new Editors.SoftFocus (view);
-		}
-	}
 }

Modified: trunk/src/MainWindow.cs
==============================================================================
--- trunk/src/MainWindow.cs	(original)
+++ trunk/src/MainWindow.cs	Tue Aug 12 10:30:00 2008
@@ -160,6 +160,10 @@
 		set { Tag.TagIconSize = (Tag.IconSize) value; }
 	}
 
+	public PhotoView PhotoView {
+		get { return photo_view; }
+	}
+
 	// Drag and Drop
 	public enum TargetType {
 		UriList,

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Tue Aug 12 10:30:00 2008
@@ -95,9 +95,15 @@
 	$(srcdir)/DependentListStore.cs		\
 	$(srcdir)/DirectoryAdaptor.cs		\
 	$(srcdir)/DirectoryCollection.cs	\
+	$(srcdir)/Editors/Editor.cs		\
+	$(srcdir)/Editors/AutoStretchEditor.cs		\
+	$(srcdir)/Editors/CropEditor.cs		\
+	$(srcdir)/Editors/DesaturateEditor.cs		\
+	$(srcdir)/Editors/RedEyeEditor.cs		\
+	$(srcdir)/Editors/SepiaEditor.cs		\
+	$(srcdir)/Editors/SoftFocusEditor.cs		\
+	$(srcdir)/Editors/TiltEditor.cs		\
 	$(srcdir)/Editors/Old/OldEditor.cs		\
-	$(srcdir)/Editors/Old/SoftFocus.cs		\
-	$(srcdir)/Editors/Old/Tilt.cs		\
 	$(srcdir)/ExportStore.cs		\
 	$(srcdir)/Extensions/ExportMenuItemNode.cs	\
 	$(srcdir)/Extensions/IExporter.cs	\
@@ -124,7 +130,6 @@
 	$(srcdir)/Filters/OrientationFilter.cs	\
 	$(srcdir)/Filters/ResizeFilter.cs	\
 	$(srcdir)/Filters/SharpFilter.cs	\
-	$(srcdir)/Filters/TiltFilter.cs		\
 	$(srcdir)/Filters/UniqueNameFilter.cs	\
 	$(srcdir)/Filters/WhiteListFilter.cs	\
 	$(srcdir)/FotkiRemote.cs		\
@@ -198,6 +203,7 @@
 	$(srcdir)/SlideView.cs			\
 	$(srcdir)/SingleView.cs			\
 	$(srcdir)/SimpleCalendar.cs		\
+	$(srcdir)/SoftFocus.cs		\
 	$(srcdir)/TagCommands.cs		\
 	$(srcdir)/TagPopup.cs			\
 	$(srcdir)/TagQueryWidget.cs		\
@@ -253,10 +259,8 @@
 	$(srcdir)/Widgets/Reveal.cs		\
 	$(srcdir)/Widgets/ScalingIconView.cs	\
 	$(srcdir)/Widgets/Sidebar.cs		\
-	$(srcdir)/Widgets/SoftFocus.cs		\
 	$(srcdir)/Widgets/TagEntry.cs		\
 	$(srcdir)/Widgets/TagMenu.cs		\
-	$(srcdir)/Widgets/Tilt.cs		\
 	$(srcdir)/Widgets/TrayView.cs		\
 	$(srcdir)/Widgets/Wipe.cs		\
 	$(srcdir)/XmpTagsImporter.cs		\

Modified: trunk/src/PhotoImageView.cs
==============================================================================
--- trunk/src/PhotoImageView.cs	(original)
+++ trunk/src/PhotoImageView.cs	Tue Aug 12 10:30:00 2008
@@ -377,7 +377,7 @@
 			ZoomFit (upscale);
 		}
 
-		private void ZoomFit (bool upscale)
+		public void ZoomFit (bool upscale)
 		{			
 			Gdk.Pixbuf pixbuf = this.Pixbuf;
 			Gtk.ScrolledWindow scrolled = this.Parent as Gtk.ScrolledWindow;
@@ -506,9 +506,6 @@
 					loupe.Destroy ();	
 				}
 				break;
-			case Gdk.Key.e:
-				Editor = new FSpot.Editors.SoftFocus (this);
-				break;
 			case Gdk.Key.equal:
 			case Gdk.Key.plus:
 			case Gdk.Key.KP_Add:

Modified: trunk/src/PhotoView.cs
==============================================================================
--- trunk/src/PhotoView.cs	(original)
+++ trunk/src/PhotoView.cs	Tue Aug 12 10:30:00 2008
@@ -42,14 +42,8 @@
 		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.
@@ -66,22 +60,6 @@
 		public delegate void DoubleClickedHandler (Widget widget, BrowsableEventArgs args);
 		public event DoubleClickedHandler DoubleClicked;
 	
-		public enum ConstraintType {
-			Normal,
-			AddCustom,
-			SameAsPhoto
-		}
-
-		private List<SelectionRatioDialog.SelectionConstraint> custom_constraints;
-	
-		private static SelectionRatioDialog.SelectionConstraint [] default_constraints = {
-			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; }
 		}
@@ -124,20 +102,8 @@
 	
 			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 ()
@@ -182,16 +148,6 @@
 			rating.Value = r;
 			rating.Changed += HandleRatingChanged;
 		}
-
-		public void UpdateSelectionCombo ()
-		{
-			//constraints_combo.Active = 0;	
-			TreeIter iter;
-			if (constraints_combo.GetActiveIter (out iter)) {
-				if (((ConstraintType)constraints_store.GetValue (iter, 3)) == ConstraintType.SameAsPhoto)
-					constraints_combo.Active = 0;
-			}
-		}
 	
 		private void Update ()
 		{
@@ -202,7 +158,6 @@
 			UpdateCountLabel ();
 			UpdateDescriptionEntry ();
 			UpdateRating ();
-			UpdateSelectionCombo ();
 
 			if (UpdateFinished != null)
 				UpdateFinished (this);
@@ -247,16 +202,6 @@
 			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");
@@ -271,100 +216,6 @@
 			md.Destroy ();
 		}
 	
-		private void HandleSepiaButtonClicked (object sender, EventArgs args)
-		{
-			Photo photo = View.Item.Current as Photo;
-			bool create_version = photo.DefaultVersion.IsProtected;
-	
-			try {
-				FSpot.ColorAdjustment.SepiaTone sepia = new FSpot.ColorAdjustment.SepiaTone (View.CompletePixbuf (), null);
-				using (Pixbuf result = sepia.Adjust ()) {
-					photo.SaveVersion (result, create_version);
-					photo.Changes.DataChanged = true;
-					Core.Database.Photos.Commit (photo);
-				}
-			} catch (System.Exception e) {
-				ShowError (e, photo); 
-			}
-		}
-	
-		private void HandleDesaturateButtonClicked (object sender, EventArgs args)
-		{
-			Photo photo = View.Item.Current as Photo;
-			bool create_version = photo.DefaultVersion.IsProtected;
-	
-			try {
-				FSpot.ColorAdjustment.Desaturate desaturate = new FSpot.ColorAdjustment.Desaturate (View.CompletePixbuf (), null);
-				using (Pixbuf result = desaturate.Adjust ()) {
-					photo.SaveVersion (result, create_version);
-					photo.Changes.DataChanged = true;
-					Core.Database.Photos.Commit (photo);
-				}
-			} catch (System.Exception e) {
-				ShowError (e, photo);
-			}
-		}
-	
-		// 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");
-				
-				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,
-									   Preferences.Get<int> (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);
-				photo.Changes.DataChanged = true;
-				((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);
@@ -512,14 +363,6 @@
 			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;
-
 			SetColors ();
 			
 			inner_vbox.PackStart (inner_hbox, false, true, 0);
@@ -529,51 +372,11 @@
 			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;
@@ -599,7 +402,6 @@
 			vbox.ShowAll ();
 	
 			Realized += delegate (object o, EventArgs e) {SetColors ();};
-			Preferences.SettingChanged += OnPreferencesChanged;
 		}
 
 		~PhotoView ()
@@ -627,85 +429,6 @@
 			is_disposed = true;
 		}
 
-		private void OnPreferencesChanged (object sender, NotifyEventArgs args)
-		{
-			LoadPreference (args.Key);
-		}
-	
-		private void LoadPreference (String key)
-		{
-			switch (key) {
-			case Preferences.CUSTOM_CROP_RATIOS:
-				custom_constraints = new List<SelectionRatioDialog.SelectionConstraint> ();
-				if (Preferences.Get<string[]> (key) != null) {
-					XmlSerializer serializer = new XmlSerializer (typeof(SelectionRatioDialog.SelectionConstraint));
-					foreach (string xml in Preferences.Get<string[]> (key))
-						custom_constraints.Add ((SelectionRatioDialog.SelectionConstraint)serializer.Deserialize (new StringReader (xml)));
-				}
-				PopulateConstraints ();
-				break;
-			}
-		}
-
-		private void PopulateConstraints()
-		{
-			constraints_store = new TreeStore (typeof (string), typeof (string), typeof (double), typeof (ConstraintType));
-			constraints_combo.Model = constraints_store;
-			constraints_store.AppendValues (null, Catalog.GetString ("No Constraint"), 0.0, ConstraintType.Normal);
-			constraints_store.AppendValues (null, Catalog.GetString ("Same as photo"), 0.0, ConstraintType.SameAsPhoto);
-			foreach (SelectionRatioDialog.SelectionConstraint constraint in custom_constraints)
-				constraints_store.AppendValues (null, constraint.Label, constraint.XyRatio, ConstraintType.Normal);
-			foreach (SelectionRatioDialog.SelectionConstraint constraint in default_constraints)
-				constraints_store.AppendValues (null, constraint.Label, constraint.XyRatio, ConstraintType.Normal);
-			constraints_store.AppendValues (Stock.Edit, Catalog.GetString ("Custom Ratios..."), 0.0, ConstraintType.AddCustom);
-			constraints_combo.Active = 0;
-		}
-
-		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;	
-		}
-
-		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;
-		}
-
-		void HandleConstraintsComboChanged (object o, EventArgs e)
-		{
-			TreeIter iter;
-			if (constraints_combo.GetActiveIter (out iter)) {
-				double ratio = ((double)constraints_store.GetValue (iter, 2));
-				ConstraintType type = ((ConstraintType)constraints_store.GetValue (iter, 3));
-				switch (type) {
-				case ConstraintType.Normal:
-					photo_view.SelectionXyRatio = ratio;
-					break;
-				case ConstraintType.AddCustom:
-					SelectionRatioDialog dialog = new SelectionRatioDialog ();
-					dialog.Dialog.Run ();
-					break;
-				case ConstraintType.SameAsPhoto:
-					try {
-						Pixbuf pb = photo_view.CompletePixbuf ();
-						photo_view.SelectionXyRatio = (double)pb.Width / (double)pb.Height;
-					} catch (System.Exception ex) {
-						Console.WriteLine (ex);
-						photo_view.SelectionXyRatio = 0;
-					}
-					break;
-				default:
-					photo_view.SelectionXyRatio = 0;
-					break;
-				}	
-			}	
-		}
-
 		private void SetColors ()
 		{
 			GtkUtil.ModifyColors (filmstrip);

Copied: trunk/src/SoftFocus.cs (from r4240, /trunk/src/Widgets/SoftFocus.cs)
==============================================================================
--- /trunk/src/Widgets/SoftFocus.cs	(original)
+++ trunk/src/SoftFocus.cs	Tue Aug 12 10:30:00 2008
@@ -1,4 +1,4 @@
-/* 
+/*
  * SoftFocus.cs
  *
  * Author
@@ -12,7 +12,7 @@
 
 namespace FSpot.Widgets {
 
-	public class SoftFocus : IEffect {
+	public class SoftFocus {
 
 		[DllImport ("cairo")]
 		internal static extern int cairo_version ();
@@ -32,16 +32,16 @@
 			Amount = 3;
 			Radius = .5;
 		}
-		
+
 		public Gdk.Point Center {
 			get { return center; }
 			set { center = value; }
 		}
-		
+
 		public double Amount {
 			get { return amount; }
-			set { 
-				amount = value; 
+			set {
+				amount = value;
 
 				if (blur != null)
 					blur.Dispose ();
@@ -49,15 +49,15 @@
 				blur = CreateBlur (info);
 			}
 		}
-		
+
 		public double Radius {
 			get { return radius; }
-			set { 
-				radius = value; 
+			set {
+				radius = value;
 
 				if (blur == null)
 					return;
-				
+
 				if (mask != null)
 					mask.Destroy ();
 
@@ -73,11 +73,11 @@
 			Gdk.Rectangle small = new Gdk.Rectangle (0, 0,
 								(int) Math.Ceiling (source.Bounds.Width * scale),
 								(int) Math.Ceiling (source.Bounds.Height * scale));
-			
-			MemorySurface image = new MemorySurface (Format.Argb32, 
+
+			MemorySurface image = new MemorySurface (Format.Argb32,
 								 small.Width,
 								 small.Height);
-			
+
 			Context ctx = new Context (image);
 			//Pattern solid = new SolidPattern (0, 0, 0, 0);
 			//ctx.Source = solid;
@@ -99,7 +99,7 @@
 			image.Destroy ();
 			return overlay;
 		}
-		
+
 		private Pattern CreateMask ()
 		{
 			double max = Math.Max (blur.Bounds.Width, blur.Bounds.Height) * .25;
@@ -114,7 +114,7 @@
 
 				circle.AddColorStop (0, new Cairo.Color (0.0, 0.0, 0.0, 0.0));
 				circle.AddColorStop (1.0, new Cairo.Color (1.0, 1.0, 1.0, 1.0));
-		        } else {
+			} else {
 				circle = new RadialGradient (center.X * scale, center.Y * scale, radius * max + max * .2,
 							     center.X * scale, center.Y * scale, radius * max * .7);
 
@@ -123,8 +123,8 @@
 			}
 			return circle;
 		}
-		
-		public bool OnExpose (Context ctx, Gdk.Rectangle allocation)
+
+		public void Apply (Context ctx, Gdk.Rectangle allocation)
 		{
 			SurfacePattern p = new SurfacePattern (info.Surface);
 			ctx.Matrix = new Matrix ();
@@ -139,7 +139,7 @@
 			ctx.Matrix = blur.Fit (allocation);
 			ctx.Operator = Operator.Over;
 			ctx.Source = overlay;
-			
+
 			// FIXME ouch this is ugly.
 			if (mask == null)
 				Radius = Radius;
@@ -148,9 +148,8 @@
 			ctx.Mask (mask);
 			overlay.Destroy ();
 			p.Destroy ();
-			return true;
 		}
-		
+
 		public void Dispose ()
 		{
 			if (mask != null)

Modified: trunk/src/Widgets/EditorPage.cs
==============================================================================
--- trunk/src/Widgets/EditorPage.cs	(original)
+++ trunk/src/Widgets/EditorPage.cs	Tue Aug 12 10:30:00 2008
@@ -7,32 +7,236 @@
  * This is free software. See COPYING for details.
  */
 
+/*
+ * FIXME: add this back
+ * 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 phot
+ *
+ * HigMessageDialog md = new HigMessageDialog ((Gtk.Window)this.Toplevel, DialogFlags.DestroyWithParent,
+ *                                              Gtk.MessageType.Error, ButtonsType.Ok,
+ *                                              msg,
+ *                                             desc);
+ *
+ * md.Run ();
+ * md.Destroy ();
+ * return;
+ * }
+ */
+
 using FSpot;
+using FSpot.Editors;
+using FSpot.Utils;
+
 using Gtk;
+
+using Mono.Addins;
 using Mono.Unix;
+
 using System;
+using System.Collections.Generic;
 
 namespace FSpot.Widgets {
 	public class EditorPage : SidebarPage {
+		internal bool InPhotoView;
+		private readonly EditorPageWidget EditorPageWidget;
+
 		public EditorPage () : base (new EditorPageWidget (),
 									   Catalog.GetString ("Edit"),
 									   "mode-image-edit") {
 			// TODO: Somebody might need to change the icon to something more suitable.
 			// FIXME: The icon isn't shown in the menu, are we missing a size?
-			MainWindow.Toplevel.ViewModeChanged += HandleViewModeChanged;
+			EditorPageWidget = SidebarWidget as EditorPageWidget;
+			EditorPageWidget.Page = this;
+		}
+
+		protected override void AddedToSidebar () {
+			Sidebar.SelectionChanged += delegate (IBrowsableCollection collection) { EditorPageWidget.ShowTools (); };
+			Sidebar.ContextChanged += HandleContextChanged;
 		}
 
-		private void HandleViewModeChanged (object sender, EventArgs args)
+		private void HandleContextChanged (object sender, EventArgs args)
 		{
-			if (MainWindow.Toplevel.ViewMode == MainWindow.ModeType.PhotoView) {
-				CanSelect = true;
-			} else {
-				CanSelect = false;
-			}
+			InPhotoView = (Sidebar.Context == ViewContext.Edit);
+			EditorPageWidget.ChangeButtonVisibility ();
 		}
 	}
 
 	public class EditorPageWidget : ScrolledWindow {
-		
+		private VBox widgets;
+		private VButtonBox buttons;
+		private Widget active_editor;
+
+		private List<Editor> editors;
+		private Editor current_editor;
+
+		// Used to make buttons insensitive when selecting multiple images.
+		private Dictionary<Editor, Button> editor_buttons;
+
+		private EditorPage page;
+		internal EditorPage Page {
+			get { return page; }
+			set { page = value; ChangeButtonVisibility (); }
+		}
+
+		public EditorPageWidget () {
+			editors = new List<Editor> ();
+			AddinManager.AddExtensionNodeHandler ("/FSpot/Editors", OnExtensionChanged);
+
+			ShowTools ();
+		}
+
+		private void OnExtensionChanged (object s, ExtensionNodeEventArgs args) {
+			// FIXME: We do not do run-time removal of editors yet!
+			if (args.Change == ExtensionChange.Add)
+				editors.Add ((args.ExtensionNode as EditorNode).GetEditor ());
+		}
+
+		internal void ChangeButtonVisibility () {
+			foreach (Editor editor in editors) {
+				Button button;
+				editor_buttons.TryGetValue (editor, out button);
+
+				// Ugly add-remove thing to maintain ordering.
+				// Simply changing Button.Visible doesn't work,
+				// as ShowAll is called higher up in the stack :-(
+				buttons.Remove (button);
+				if (Page.InPhotoView || editor.CanHandleMultiple)
+					buttons.Add (button);
+			}
+		}
+
+		public void ShowTools () {
+			// Remove any open editor, if present.
+			if (current_editor != null) {
+				active_editor.Hide ();
+				Remove (active_editor);
+				active_editor = null;
+				current_editor.Restore ();
+				current_editor = null;
+			}
+
+			// No need to build the widget twice.
+			if (buttons != null) {
+				buttons.Show ();
+				return;
+			}
+
+			if (widgets == null) {
+				widgets = new VBox (false, 0);
+				Viewport widgets_port = new Viewport ();
+				widgets_port.Add (widgets);
+				Add (widgets_port);
+				widgets_port.ShowAll ();
+			}
+
+			// Build the widget (first time we call this method).
+			buttons = new VButtonBox ();
+			buttons.BorderWidth = 5;
+			buttons.Spacing = 5;
+			buttons.LayoutStyle = ButtonBoxStyle.Start;
+
+			editor_buttons = new Dictionary<Editor, Button> ();
+			foreach (Editor editor in editors) {
+				// Build sidebar button and add it to the sidebar.
+				Editor current = editor;
+				Button button = new Button (editor.Label);
+				button.Image = new Image (GtkUtil.TryLoadIcon (FSpot.Global.IconTheme, editor.IconName, 22, (Gtk.IconLookupFlags)0));
+				button.Clicked += delegate (object o, EventArgs e) { ChooseEditor (current); };
+				buttons.Add (button);
+				editor_buttons.Add (editor, button);
+			}
+
+			widgets.Add (buttons);
+			buttons.ShowAll ();
+		}
+
+		private void ChooseEditor (Editor editor) {
+			SetupEditor (editor);
+
+			if (!editor.CanBeApplied || editor.HasSettings)
+				ShowEditor (editor);
+			else
+				Apply (editor); // Instant apply
+		}
+
+		private void SetupEditor (Editor editor) {
+			EditorState state = editor.CreateState ();
+
+			EditorSelection selection = new EditorSelection ();
+			PhotoImageView photo_view = MainWindow.Toplevel.PhotoView.View;
+
+			if (Page.InPhotoView && photo_view != null) {
+				if (photo_view.GetSelection (out selection.x, out selection.y,
+							out selection.width, out selection.height))
+					state.Selection = selection;
+				else
+					state.Selection = null;
+				state.PhotoImageView = photo_view;
+			} else {
+				state.Selection = null;
+				state.PhotoImageView = null;
+			}
+			state.Items = Page.Sidebar.Selection.Items;
+
+			editor.Initialize (state);
+		}
+
+		private void Apply (Editor editor) {
+			SetupEditor (editor);
+
+			// TODO: Provide some user feedback about this.
+			if (!editor.CanBeApplied)
+				return;
+
+			// TODO: Might need to do some nicer things for multiple selections (progress?)
+			editor.Apply ();
+			ShowTools ();
+		}
+
+		private void ShowEditor (Editor editor) {
+			SetupEditor (editor);
+			current_editor = editor;
+
+			buttons.Hide ();
+
+			// Top label
+			VBox vbox = new VBox (false, 4);
+			Label label = new Label ();
+			label.Markup = String.Format("<b>{0}</b>", editor.Label);
+			vbox.PackStart (label, true, false, 5);
+
+			// Optional config widget
+			Widget config = editor.ConfigurationWidget ();
+			if (config != null) {
+				vbox.Add (config);
+			}
+
+			// Apply / Cancel buttons
+			HButtonBox tool_buttons = new HButtonBox ();
+			tool_buttons.LayoutStyle = ButtonBoxStyle.End;
+			tool_buttons.Spacing = 5;
+			tool_buttons.BorderWidth = 5;
+			tool_buttons.Homogeneous = false;
+
+			Button cancel = new Button (Stock.Cancel);
+			cancel.Clicked += HandleCancel;
+			tool_buttons.Add (cancel);
+
+			Button apply = new Button (editor.ApplyLabel);
+			apply.Image = new Image (GtkUtil.TryLoadIcon (FSpot.Global.IconTheme, editor.IconName, 22, (Gtk.IconLookupFlags)0));
+			apply.Clicked += delegate { Apply (editor); };
+			tool_buttons.Add (apply);
+
+			// Pack it all together
+			vbox.Add (tool_buttons);
+			active_editor = vbox;
+			widgets.Add (active_editor);
+			active_editor.ShowAll ();
+		}
+
+		void HandleCancel (object sender, System.EventArgs args) {
+			ShowTools ();
+		}
 	}
 }

Modified: trunk/src/Widgets/ImageDisplay.cs
==============================================================================
--- trunk/src/Widgets/ImageDisplay.cs	(original)
+++ trunk/src/Widgets/ImageDisplay.cs	Tue Aug 12 10:30:00 2008
@@ -20,10 +20,7 @@
 namespace FSpot.Widgets {
 	[Binding(Gdk.Key.Up, "Up")]
 	[Binding(Gdk.Key.Down, "Down")]
-	[Binding(Gdk.Key.Left, "TiltImage", 0.05)]
-	[Binding(Gdk.Key.Right, "TiltImage", -0.05)] 
 	[Binding(Gdk.Key.space, "Pan")]
-	[Binding(Gdk.Key.Q, "Vingette")]
 	[Binding(Gdk.Key.R, "RevealImage")]
 	[Binding(Gdk.Key.P, "PushImage")]
 	public class ImageDisplay : Gtk.EventBox {
@@ -97,35 +94,6 @@
 			return true;
 		}
 
-		public bool Vingette ()
-		{
-			SoftFocus f = effect as SoftFocus;
-			
-			if (f == null) {
-				f = new SoftFocus (current);
-				effect = f;
-			}
-
-			QueueDraw ();
-			return true;
-		}
-
-		public bool TiltImage (double radians)
-		{
-			Tilt t = effect as Tilt;
-
-			if (t == null) {
-				t = new Tilt (current);
-				effect = t;
-			}
-
-			t.Angle += radians;
-
-			QueueDraw ();
-
-			return true;
-		}
-
 		public bool Pan ()
 		{
 			Console.WriteLine ("space");

Modified: trunk/src/Widgets/Sidebar.cs
==============================================================================
--- trunk/src/Widgets/Sidebar.cs	(original)
+++ trunk/src/Widgets/Sidebar.cs	Tue Aug 12 10:30:00 2008
@@ -219,11 +219,11 @@
 		{
 			// Make sure the ViewModeCondition is set correctly.
 			if (Context == ViewContext.Single)
-				ViewModeCondition.Initialize (FSpot.Extensions.ViewMode.Single);
+				ViewModeCondition.Mode = FSpot.Extensions.ViewMode.Single;
 			else if (Context == ViewContext.Library || Context == ViewContext.Edit)
-				ViewModeCondition.Initialize (FSpot.Extensions.ViewMode.Library);
+				ViewModeCondition.Mode = FSpot.Extensions.ViewMode.Library;
 			else
-				ViewModeCondition.Initialize (FSpot.Extensions.ViewMode.Unknown);
+				ViewModeCondition.Mode = FSpot.Extensions.ViewMode.Unknown;
 
 			string name = ContextSwitchStrategy.PageForContext (Context);
 			SwitchTo (name);



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