[ease] [editor] Allow zoom of the slide sorter



commit 2e4fe85a1c59416b509d1597a678ff3667a3b56a
Author: Nate Stedman <natesm gmail com>
Date:   Tue Aug 24 20:29:08 2010 -0400

    [editor] Allow zoom of the slide sorter
    
    Mostly fixes bug 627803 but a few issues:
    
    Text under the slide previews isn't centered when they are resized.
    Slide titles don't update properly when slides are rearranged.

 ease-core/ease-animated-zoom-slider.vala |   32 +++++++++---
 ease-core/ease-document.vala             |   55 ++++++++++++++++++--
 ease-core/ease-iterable-models.vala      |    7 +++
 ease-core/ease-slide.vala                |   21 ++++++++
 ease-core/ease-zoom-slider.vala          |   25 +++++++++-
 ease/ease-editor-window.vala             |   79 +++++++++++++++++++++++++----
 ease/ease-slide-button-panel.vala        |    2 +-
 ease/ease-slide-sorter.vala              |   35 ++++++++++++-
 8 files changed, 228 insertions(+), 28 deletions(-)
---
diff --git a/ease-core/ease-animated-zoom-slider.vala b/ease-core/ease-animated-zoom-slider.vala
index 21bac65..f346354 100644
--- a/ease-core/ease-animated-zoom-slider.vala
+++ b/ease-core/ease-animated-zoom-slider.vala
@@ -27,6 +27,15 @@ public class Ease.AnimatedZoomSlider : ZoomSlider, Clutter.Animatable
 	private const int ZOOM_TIME = 100;
 	private const int ZOOM_MODE = Clutter.AnimationMode.EASE_IN_OUT_SINE;
 	
+	/**
+	 * Whether or not the AnimatedZoomSlider should animate its zoom when the
+	 * + and - buttons are clicked. Setting this to false will make the
+	 * AnimatedZoomSlider perform identically to a { link ZoomSlider}.
+	 *
+	 * Set to "true" by default.
+	 */
+	public bool animate { get; set; default = true; }
+	
 	/** 
 	 * Creates a new AnimatedZoomSlider.
 	 *
@@ -39,14 +48,23 @@ public class Ease.AnimatedZoomSlider : ZoomSlider, Clutter.Animatable
 		base(adjustment, button_values);
 	}
 	
+	/**
+	 * { inheritDoc}
+	 *
+	 * If { link animate} is set to true, this will be a smoothed transition.
+	 */
 	protected override void change_zoom(double value)
 	{
-		zoom_anim = new Clutter.Animation();
-		zoom_anim.object = this;
-		zoom_anim.bind("sliderpos", value);
-		zoom_anim.duration = ZOOM_TIME;
-		zoom_anim.mode = ZOOM_MODE;
-		zoom_anim.timeline.start();
+		if (animate)
+		{
+			zoom_anim = new Clutter.Animation();
+			zoom_anim.object = this;
+			zoom_anim.bind("sliderpos", value);
+			zoom_anim.duration = ZOOM_TIME;
+			zoom_anim.mode = ZOOM_MODE;
+			zoom_anim.timeline.start();
+		}
+		else base.change_zoom(value);
 	}
 	
 	private bool animate_property(Clutter.Animation animation,
@@ -62,4 +80,4 @@ public class Ease.AnimatedZoomSlider : ZoomSlider, Clutter.Animatable
 		                 final_value.get_double() * progress);
 		return true;
 	}
-}
\ No newline at end of file
+}
diff --git a/ease-core/ease-document.vala b/ease-core/ease-document.vala
index 8289b99..775665c 100644
--- a/ease-core/ease-document.vala
+++ b/ease-core/ease-document.vala
@@ -66,6 +66,15 @@ public class Ease.Document : GLib.Object, UndoSource
 	public const int COL_TITLE = 2;
 	
 	/**
+	 * Model dynamic sized pixbuf column. This column may not contain any valid
+	 * pixbuf data at any given time, so use of it should be avoided.
+	 *
+	 * Only code inside Ease itself that "knows what it's doing" should use this
+	 * column.
+	 */
+	public const int COL_PIXBUF_DYNAMIC = 3;
+	
+	/**
 	 * Default slide title.
 	 */
 	private const string DEFAULT_TITLE = _("Slide %i");
@@ -104,10 +113,19 @@ public class Ease.Document : GLib.Object, UndoSource
 	/**
 	 * All { link Slide}s in this Document.
 	 */
-	public IterableListStore slides = new IterableListStore(
-		{ typeof(Slide),
-		  typeof(Gdk.Pixbuf),
-		  typeof(string) });
+	public IterableListStore slides
+	{
+		get
+		{
+			if (slides_priv != null) return slides_priv;
+			slides_priv = new IterableListStore({ typeof(Slide),
+			                                      typeof(Gdk.Pixbuf),
+			                                      typeof(string),
+			                                      typeof(Gdk.Pixbuf) });
+			return slides_priv;
+		}
+	}
+	private IterableListStore slides_priv;
 	
 	/**
 	 * The number of { link Slide}s in the Document.
@@ -287,6 +305,8 @@ public class Ease.Document : GLib.Object, UndoSource
 		slide.title_changed.connect(on_title_changed);
 		slide.title_reset.connect(on_title_reset);
 		
+		set_slide_titles();
+		
 		if (emit_undo) undo(new SlideAddUndoAction(slide));
 	}
 	
@@ -334,7 +354,9 @@ public class Ease.Document : GLib.Object, UndoSource
 				break;
 			}
 			index++;
-		}		
+		}
+		
+		set_slide_titles();
 		
 		Slide ret;
 		Gtk.TreeIter itr;
@@ -428,7 +450,6 @@ public class Ease.Document : GLib.Object, UndoSource
 	 */
 	internal void on_title_reset(Slide slide)
 	{
-		debug("title reset");
 		Slide s;
 		foreach (var itr in slides)
 		{
@@ -443,6 +464,28 @@ public class Ease.Document : GLib.Object, UndoSource
 	}
 	
 	/**
+	 * Sets all slide titles. Used when the slides model is rearranged, a new
+	 * slide is added, or a slide is removed.
+	 */
+	private void set_slide_titles()
+	{
+		Slide s;
+		int i = 1;
+		foreach (var itr_slide in slides)
+		{
+			s = null;
+			slides.get(itr_slide, COL_SLIDE, out s);
+			if (s != null)
+			{
+				var title = s.get_title();
+				slides.set(itr_slide, COL_TITLE, title != null ? title :
+					                             DEFAULT_TITLE.printf(i));
+			}
+			i++;
+		}
+	}
+	
+	/**
 	 * Renders this Document to a CairoSurface. Obviously, this only really
 	 * works with multi-page surfaces.
 	 *
diff --git a/ease-core/ease-iterable-models.vala b/ease-core/ease-iterable-models.vala
index e93d86d..43be1b7 100644
--- a/ease-core/ease-iterable-models.vala
+++ b/ease-core/ease-iterable-models.vala
@@ -27,6 +27,13 @@ public interface Ease.IterableTreeModel : Gtk.TreeModel
 	{
 		return new Iterator(this);
 	}
+	
+	public Gtk.TreeIter index(int index)
+	{
+		Gtk.TreeIter itr;
+		iter_nth_child(out itr, null, index);
+		return itr;
+	}
 
 	public class Iterator
 	{
diff --git a/ease-core/ease-slide.vala b/ease-core/ease-slide.vala
index bba1a07..13fa1f7 100644
--- a/ease-core/ease-slide.vala
+++ b/ease-core/ease-slide.vala
@@ -710,6 +710,27 @@ public class Ease.Slide : GLib.Object, UndoSource
 			}
 		}
 	}
+	
+	/**
+	 * Return's the slide's title from an element, or null if it doesn't have
+	 * one.
+	 */
+	internal string? get_title()
+	{
+		foreach (var element in this)
+		{
+			if (element is TextElement)
+			{
+				if ((element as TextElement).identifier == Theme.TITLE_TEXT || 
+					(element as TextElement).identifier == Theme.HEADER_TEXT)
+				{
+					var ret = (element as TextElement).text;
+					return ret.length > 0 ? ret : null;
+				}
+			}
+		}
+		return null;
+	}
 
 	// foreach iteration
 	
diff --git a/ease-core/ease-zoom-slider.vala b/ease-core/ease-zoom-slider.vala
index 1828cfa..806c510 100644
--- a/ease-core/ease-zoom-slider.vala
+++ b/ease-core/ease-zoom-slider.vala
@@ -26,7 +26,6 @@ public class Ease.ZoomSlider : Gtk.Alignment
 	private Gtk.HScale zoom_slider;
 	private Gtk.Button zoom_in_button;
 	private Gtk.Button zoom_out_button;
-	private int[] values;
 	
 	/** 
 	 * The position of the zoom slider's value.
@@ -56,6 +55,15 @@ public class Ease.ZoomSlider : Gtk.Alignment
 	}
 	
 	/**
+	 * The update policy of the slider.
+	 */
+	public Gtk.UpdateType update_policy
+	{
+		get { return zoom_slider.update_policy; }
+		set { zoom_slider.update_policy = value; }
+	}
+	
+	/**
 	 * Private store for buttons_shown property.
 	 */
 	private bool buttons_shown_priv = true;
@@ -76,6 +84,21 @@ public class Ease.ZoomSlider : Gtk.Alignment
 		}
 	}
 	
+	/**
+	 * The adjustment of the slider.
+	 */
+	public Gtk.Adjustment adjustment
+	{
+		get { return zoom_slider.adjustment; }
+		set { zoom_slider.adjustment = value; }
+	}
+	
+	/**
+	 * The values on which the slider should stop when the +/- buttons are
+	 * clicked.
+	 */
+	public int[] values;
+	
 	/** 
 	 * Creates a new ZoomSlider.
 	 *
diff --git a/ease/ease-editor-window.vala b/ease/ease-editor-window.vala
index 0063671..6ec9f38 100644
--- a/ease/ease-editor-window.vala
+++ b/ease/ease-editor-window.vala
@@ -39,7 +39,7 @@ internal class Ease.EditorWindow : Gtk.Window
 	 * A { link ZoomSlider} at the bottom of the window, controlling the zoom
 	 * level of the { link EditorEmbed}.
 	 */
-	internal ZoomSlider zoom_slider;
+	internal AnimatedZoomSlider zoom_slider;
 
 	/**
 	 * A { link Player} for the { link Document} displayed in this window.
@@ -142,10 +142,25 @@ internal class Ease.EditorWindow : Gtk.Window
 	internal signal void close(EditorWindow self);
 	
 	/**
-	 * The zoom levels for the { link ZoomSlider}
+	 * The zoom levels for the { link EditorEmbed}.
 	 */
-	private int[] ZOOM_LEVELS = {10, 25, 33, 50, 66, 75, 100, 125, 150,
-	                             200, 250, 300, 400};
+	private int[] ZOOM_LEVELS = { 10, 25, 33, 50, 66, 75, 100, 125, 150,
+	                              200, 250, 300, 400 };
+	
+	/**
+	 * The zoom levels for the { link EditorEmbed}.
+	 */
+	private int[] SORTER_ZOOM_LEVELS = { 0, 25, 50, 75, 100 };
+	
+	/**
+	 * The zoom adjustment for the { link EditorEmbed}.
+	 */
+	private Gtk.Adjustment zoom_adjustment;
+	
+	/**
+	 * The zoom adjustment for the { link SlideSorter}.
+	 */
+	private Gtk.Adjustment sorter_zoom_adjustment;
 	
 	private const string UI_FILE_PATH = "editor-window.ui";
 	
@@ -622,18 +637,50 @@ internal class Ease.EditorWindow : Gtk.Window
 		if (show_editor == sender)
 		{
 			if (main_bin.get_child() == editor) return;
+			
+			// stop drawing new dynamic pixbufs for new slides
+			document.slide_added.disconnect(sorter.on_slide_added);
+			
+			// switch the ui elements
 			main_bin.remove(sorter);
 			main_bin.add(editor);
 			sorter = null;
+			
+			// make the zoom slider work for the editor embed
+			zoom_slider.values = ZOOM_LEVELS;
+			zoom_slider.adjustment = zoom_adjustment;
+			zoom_slider.update_policy = Gtk.UpdateType.CONTINUOUS;
+			zoom_slider.animate = true;
+			
+			// wipe the document's dynamic pixbuf column
+			Slide s;
+			foreach (var itr in document.slides)
+			{
+				// get the slide
+				document.slides.get(itr, Document.COL_SLIDE, out s);
+			
+				// wipe its dynamically sized pixbuf
+				document.slides.set(itr, Document.COL_PIXBUF_DYNAMIC, null);
+			}
 		}
 		else if (show_sorter == sender)
 		{
-			if (sorter == null) sorter = new SlideSorter(document);
+			if (sorter == null)
+			{
+				sorter = new SlideSorter(document,
+				                         sorter_zoom_adjustment.value / 100f);
+			}
 			if (main_bin.get_child() == sorter) return;
 			main_bin.remove(editor);
 			main_bin.add(sorter);
 			sorter.show_all();
 			
+			// make the zoom slider work for the sorter
+			zoom_slider.values = SORTER_ZOOM_LEVELS;
+			zoom_slider.adjustment = sorter_zoom_adjustment;
+			zoom_slider.update_policy = Gtk.UpdateType.DELAYED;
+			zoom_slider.animate = false;
+			
 			// when a slide is clicked in the sorter, switch back here
 			sorter.display_slide.connect((s) => {
 				slide_button_panel.select_slide(s);
@@ -866,17 +913,27 @@ internal class Ease.EditorWindow : Gtk.Window
 	
 	private ZoomSlider create_zoom_slider()
 	{
+		// create adjustments
+		zoom_adjustment = new Gtk.Adjustment(100, 10, 400, 10, 50, 50);
+		sorter_zoom_adjustment = new Gtk.Adjustment(50, 0, 100, 10, 25, 25);
+		
 		// create zoom slider
-		zoom_slider = new AnimatedZoomSlider(new Gtk.Adjustment(100, 10, 400,
-		                                                        10, 50, 50),
-		                                                        ZOOM_LEVELS);
+		zoom_slider = new AnimatedZoomSlider(zoom_adjustment, ZOOM_LEVELS);
 		zoom_slider.value_pos = Gtk.PositionType.RIGHT;
 		zoom_slider.digits = 0;
 		
 		zoom_slider.value_changed.connect(() => {
-			embed.zoom_fit = false;
-			zoom_fit.active = false;
-			embed.zoom = (float)zoom_slider.get_value() / 100f;
+			// editor is currently shown
+			if (sorter == null)
+			{
+				embed.zoom_fit = false;
+				zoom_fit.active = false;
+				embed.zoom = (float)zoom_slider.get_value() / 100f;
+			}
+			
+			// slide sorter is currently shown
+			else sorter.set_zoom(zoom_slider.get_value() / 100f);
+			
 		});
 		
 		zoom_slider.show_all();
diff --git a/ease/ease-slide-button-panel.vala b/ease/ease-slide-button-panel.vala
index 1024293..2394225 100644
--- a/ease/ease-slide-button-panel.vala
+++ b/ease/ease-slide-button-panel.vala
@@ -175,7 +175,7 @@ internal class Ease.SlideButtonPanel : Gtk.ScrolledWindow
 	 *
 	 * @param slide The slide to create a pixbuf of.
 	 */
-	private static Gdk.Pixbuf? pixbuf(Slide slide, int width)
+	internal static Gdk.Pixbuf? pixbuf(Slide slide, int width)
 	{
 		var height = (int)((float)width * slide.height /
 		                                  slide.width);
diff --git a/ease/ease-slide-sorter.vala b/ease/ease-slide-sorter.vala
index c8865d9..3b49f40 100644
--- a/ease/ease-slide-sorter.vala
+++ b/ease/ease-slide-sorter.vala
@@ -24,14 +24,22 @@ internal class Ease.SlideSorter : Gtk.ScrolledWindow
 	private Document document;
 	
 	private const int WIDTH = 100;
+	private const int WIDTH_ADDITIONAL = 300;
+	private int width;
 	
 	internal signal void display_slide(Slide s);
 	
-	internal SlideSorter(Document doc)
+	internal SlideSorter(Document doc, double zoom)
 	{
 		document = doc;
+		document.slide_added.connect(on_slide_added);
+		
+		// render dynamic-sized pixbufs
+		set_zoom(zoom);
+		
+		// set up the icon view
 		view = new Gtk.IconView.with_model(document.slides);
-		view.pixbuf_column = Document.COL_PIXBUF;
+		view.pixbuf_column = Document.COL_PIXBUF_DYNAMIC;
 		view.markup_column = Document.COL_TITLE;
 		view.reorderable = true;
 		view.item_width = WIDTH;
@@ -69,4 +77,27 @@ internal class Ease.SlideSorter : Gtk.ScrolledWindow
 		
 		return ret_slide;
 	}
+	
+	internal void set_zoom(double zoom)
+	{
+		width = (int)(WIDTH + zoom * WIDTH_ADDITIONAL);
+		
+		Slide slide;
+		foreach (var itr in document.slides)
+		{
+			// get the slide
+			document.slides.get(itr, Document.COL_SLIDE, out slide);
+			
+			// render a pixbuf at the appropriate size
+			document.slides.set(itr, Document.COL_PIXBUF_DYNAMIC,
+			                    SlideButtonPanel.pixbuf(slide, width));
+		}
+	}
+	
+	internal void on_slide_added(Slide slide, int index)
+	{
+		var itr = document.slides.index(index);
+		document.slides.set(itr, Document.COL_PIXBUF_DYNAMIC,
+		                    SlideButtonPanel.pixbuf(slide, width));
+	}
 }



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