[ease/iconview] Started working on Clutter iconview



commit af49c68a569911431c4f76cd3a8803bbd90fe321
Author: Nate Stedman <natesm gmail com>
Date:   Thu Aug 26 05:31:49 2010 -0400

    Started working on Clutter iconview

 ease-core/Makefile.am                          |    2 +
 ease-core/ease-background-widget.vala          |    2 +-
 ease-core/ease-icon-view.vala                  |  394 ++++++++++++++++++++++++
 {ease => ease-core}/ease-scrollable-embed.vala |   16 +-
 ease/Makefile.am                               |    1 -
 ease/ease-slide-sorter.vala                    |   29 +-
 6 files changed, 417 insertions(+), 27 deletions(-)
---
diff --git a/ease-core/Makefile.am b/ease-core/Makefile.am
index 177fb1f..764d64c 100644
--- a/ease-core/Makefile.am
+++ b/ease-core/Makefile.am
@@ -17,6 +17,7 @@ libease_core_ EASE_CORE_VERSION@_la_SOURCES = \
 	ease-enums.vala \
 	ease-gradient.vala \
 	ease-html-exporter.vala \
+	ease-icon-view.vala \
 	ease-image-actor.vala \
 	ease-image-element.vala \
 	ease-image.vala \
@@ -26,6 +27,7 @@ libease_core_ EASE_CORE_VERSION@_la_SOURCES = \
 	ease-plugin-import-service.vala \
 	ease-pdf-actor.vala \
 	ease-pdf-element.vala \
+	ease-scrollable-embed.vala \
 	ease-shape-element.vala \
 	ease-slide.vala \
 	ease-temp.vala \
diff --git a/ease-core/ease-background-widget.vala b/ease-core/ease-background-widget.vala
index 41e4794..5bfa421 100644
--- a/ease-core/ease-background-widget.vala
+++ b/ease-core/ease-background-widget.vala
@@ -47,7 +47,7 @@ public class Ease.BackgroundWidget : Gtk.Alignment
 	/**
 	 * Whether or not the background widget's color selection dialogs display
 	 * an opacity slider. By default, they will display the slider (except with 
-	 * the { link BackgroundWidget.for_slide} constructor.
+	 * the for_slide constructor.
 	 *
 	 * This property controls visibility of the opacity control for both solid
 	 * color and gradient backgrounds. There is no way to disable or enable it
diff --git a/ease-core/ease-icon-view.vala b/ease-core/ease-icon-view.vala
new file mode 100644
index 0000000..d6ce669
--- /dev/null
+++ b/ease-core/ease-icon-view.vala
@@ -0,0 +1,394 @@
+/*  Ease, a GTK presentation application
+    Copyright (C) 2010 Nate Stedman
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+public class Ease.IconView : ScrollableEmbed
+{
+	/**
+	 * The column-spacing property specifies the space which is inserted between
+	 * the columns of the icon view.
+	 */
+	public int column_spacing { get; set; default = 6; }
+	
+	/**
+	 * The item-padding property specifies the padding around each of the icon
+	 * view's items.
+	 */
+	public int item_padding { get; set; default = 6; }
+	
+	/**
+	 * The item-width property specifies the width to use for each item. If it
+	 * is set to -1, the icon view will automatically determine a suitable item
+	 * size.
+	 */
+	public int item_width { get; set; default = 64; }
+	
+	/**
+	 * The margin property specifies the space which is inserted at the edges of
+	 * the icon view.
+	 */
+	public int margin { get; set; default = 6; }
+	
+	/**
+	 * The markup-column property contains the number of the model column
+	 * containing markup information to be displayed. The markup column must be
+	 * of type string. If this property and the text-column property are both
+	 * set to column numbers, it overrides the text column. If both are set to
+	 * -1, no texts are displayed.
+	 */
+	public int markup_column { get; set; default = -1; }
+	
+	/**
+	 * The model for the icon view.
+	 */
+	public Gtk.TreeModel model
+	{
+		get { return model_priv; }
+		set
+		{
+			// remove signal handlers from the old model if applicable
+			if (model_priv != null)
+			{
+				model_priv.row_changed.disconnect(on_model_row_changed);
+				model_priv.row_deleted.disconnect(on_model_row_deleted);
+				model_priv.row_inserted.disconnect(on_model_row_inserted);
+				model_priv.rows_reordered.disconnect(on_model_rows_reordered);
+			}
+			
+			// set the new model
+			model_priv = value;
+			
+			// attach signal handlers to the new model
+			model_priv.row_changed.connect(on_model_row_changed);
+			model_priv.row_deleted.connect(on_model_row_deleted);
+			model_priv.row_inserted.connect(on_model_row_inserted);
+			model_priv.rows_reordered.connect(on_model_rows_reordered);
+			
+			// purge the old icons
+			foreach (var actor in actors)
+			{
+				(actor.get_parent() as Clutter.Container).remove_actor(actor);
+			}
+			actors.clear();
+			
+			// add new actors for each of the model's rows
+			Gdk.Pixbuf pixbuf = null;
+			string text = null;
+			
+			model.foreach((model, path, iter) => {
+				// create a new actor
+				var actor = new IconActor();
+				
+				// set the actor's pixbuf (if possible)
+				if (pixbuf_column != -1)
+				{
+					model.get(iter, pixbuf_column, out pixbuf);
+					if (pixbuf != null) actor.set_pixbuf(pixbuf);
+				}
+				
+				// set the actor's markup (if possible)
+				bool text_set = false;
+				if (markup_column != -1)
+				{
+					model.get(iter, markup_column, out text);
+					if (text != null)
+					{
+						actor.set_markup(text);
+						text_set = true;
+					}
+				}
+				
+				// set the actor's text (if necessary & possible)
+				if (!text_set && text_column != -1)
+				{
+					model.get(iter, text_column, out text);
+					if (text != null) actor.set_text(text);
+				}
+				
+				// add the actor
+				actors.offer_tail(actor);
+				
+				// continue iterating
+				return false;
+			});
+		}
+	}
+	private Gtk.TreeModel model_priv;
+	
+	/**
+	 * The orientation property specifies how the cells (i.e. the icon and the
+	 * text) of the item are positioned relative to each other.
+	 */
+	public Gtk.Orientation orientation { get; set;
+	                                     default = Gtk.Orientation.VERTICAL; }
+	
+	/**
+	 * The pixbuf-column property contains the number of the model column
+	 * containing the pixbufs which are displayed. The pixbuf column must be of
+	 * type Gdk.Pixbuf. Setting this property to -1 turns off the display of
+	 * pixbufs.
+	 */
+	public int pixbuf_column { get; set; default = -1; }
+	
+	/**
+	 * The reorderable property specifies if the items can be reordered by DND.
+	 */
+	public bool reorderable { get; set; default = false; }
+	
+	/**
+	 * The row-spacing property specifies the space which is inserted between
+	 * the rows of the icon view.
+	 */
+	public int row_spacing { get; set; default = 6; }
+	
+	/**
+	 * The selection-mode property specifies the selection mode of icon view. If
+	 * the mode is Gtk.SelectionMode.MULTIPLE, rubberband selection is enabled,
+	 * for the other modes, only keyboard selection is possible.
+	 */
+	public Gtk.SelectionMode selection_mode
+	{
+		get; set;
+		default = Gtk.SelectionMode.SINGLE;
+	}
+	
+	/**
+	 * The spacing property specifies the space which is inserted between the
+	 * cells (i.e. the icon and the text) of an item.
+	 */
+	public int spacing { get; set; default = 1; }
+	
+	/**
+	 * The text-column property contains the number of the model column
+	 * containing the texts which are displayed. The text column must be of type
+	 * string. If this property and the :markup-column property are both set to
+	 * -1, no texts are displayed.
+	 */
+	public int text_column { get; set; default = -1; }
+	
+	/**
+	 * The column in the model containing the tooltip texts for the items.
+	 */
+	public int tooltip_column { get; set; default = -1; }
+	
+	/**
+	 * The item-activated signal is emitted when the method
+	 * { link item_activated} is called or the user double clicks an item. It is
+	 * also emitted when a non-editable item is selected and one of the keys:
+	 * Space, Return or Enter is pressed.
+	 */
+	public signal void item_activated(IconView iconview, Gtk.TreePath path);
+	
+	/**
+	 * The move-cursor signal is a keybinding signal which gets emitted when
+	 * the user initiates a cursor movement.
+	 *
+	 * Applications should not connect to it, but may emit it with
+	 * g_signal_emit_by_name() if they need to control the cursor
+	 * programmatically.
+	 *
+	 * The default bindings for this signal include:
+	 *
+	 * - Arrow keys which move by individual steps
+	 * - Home/End keys which move to the first/last item
+	 * - PageUp/PageDown which move by "pages"
+	 *
+	 * All of these will extend the selection when combined with the Shift
+	 * modifier.
+	 */
+	public signal void move_cursor(IconView iconview, Gtk.MovementStep step,
+	                               int count);
+	
+	/**
+	 * A keybinding signal which gets emitted when the user selects all items.
+	 *
+	 * Applications should not connect to it, but may emit it with
+	 * g_signal_emit_by_name() if they need to control selection
+	 * programmatically.
+	 *
+	 * The default binding for this signal is Ctrl-a.
+	 */
+	public signal void select_all(IconView iconview);
+	
+	/**
+	 * A keybinding signal which gets emitted when the user selects the item
+	 * that is currently focused.
+	 *
+	 * Applications should not connect to it, but may emit it with
+	 * g_signal_emit_by_name() if they need to control selection
+	 * programmatically.
+	 *
+	 * There is no default binding for this signal.
+	 */
+	public signal void select_cursor_item(IconView iconview);
+	
+	/**
+	 * The selection-changed signal is emitted when the selection (i.e. the set
+	 * of selected items) changes.
+	 */
+	public signal void selection_changed(IconView iconview);
+	
+	/**
+	 * A keybinding signal which gets emitted when the user toggles whether the
+	 * currently focused item is selected or not. The exact effect of this
+	 * depend on the selection mode.
+	 * 
+	 * Applications should not connect to it, but may emit it with
+	 * g_signal_emit_by_name() if they need to control selection
+	 * programmatically.
+	 *
+	 * There is no default binding for this signal is Ctrl-Space.
+	 */
+	public signal void toggle_cursor_item(IconView iconview);
+	
+	/**
+	 * A keybinding signal which gets emitted when the user unselects all items.
+	 *
+	 * Applications should not connect to it, but may emit it with
+	 * g_signal_emit_by_name() if they need to control selection
+	 * programmatically.
+	 *
+	 * The default binding for this signal is Ctrl-Shift-a.
+	 */
+	public signal void unselect_all(IconView iconview);
+	
+	/**
+	 * A function used by { link selected_foreach} to iterate over all selected
+	 * rows.
+	 */
+	public delegate void IconViewForeachFunc(IconView view, Gtk.TreePath path);
+	
+	// private stuff
+	
+	/**
+	 * A list containing all { link IconActor}s currently active. This is kept
+	 * in sync with the { link model}.
+	 */
+	private Gee.LinkedList<IconActor> actors = new Gee.LinkedList<IconActor>();
+	
+	public IconView()
+	{
+		// initialize the ScrollableEmbed
+		base(false, false);
+	}
+	
+	public IconView.with_model(Gtk.TreeModel model)
+	{
+		this();
+		this.model = model;
+	}
+	
+	/**
+	 * Calls a function for each selected icon. Note that the model or selection
+	 * cannot be modified from within this function.
+	 */
+	public void selected_foreach(IconViewForeachFunc func)
+	{
+		
+	}
+	
+	// model signal handlers
+	private void on_model_row_changed(Gtk.TreeModel model, Gtk.TreePath path,
+	                                  Gtk.TreeIter iter)
+	{
+	}
+	
+	private void on_model_row_deleted(Gtk.TreeModel model, Gtk.TreePath path)
+	{
+	}
+	
+	private void on_model_row_inserted(Gtk.TreeModel model, Gtk.TreePath path,
+	                                   Gtk.TreeIter iter)
+	{
+	}
+	
+	private void on_model_rows_reordered(Gtk.TreeModel model, Gtk.TreePath path,
+	                                     Gtk.TreeIter iter, void* new_order)
+	{
+	}
+	
+	/**
+	 * An embedded ClutterGroup that forms the basis of each icon/title tile.
+	 */
+	private class IconActor : Clutter.Group
+	{
+		private const int TEXT_PADDING = 5;
+		private const int TEXT_HEIGHT = 12;
+		
+		/**
+		 * Text, with data from the markup or text column of the model.
+		 */
+		public Clutter.Text text;
+		
+		/**
+		 * The texture, created from the pixbuf column.
+		 */
+		public Clutter.Texture texture;
+		
+		/**
+		 * A background that is automatically placed behind defocused icons.
+		 * This prevents these widgets from being transparent when they
+		 * overlap during reshuffling. This is automatically synced with the
+		 * overall view's background color.
+		 */
+		public Clutter.Rectangle background;
+		
+		public IconActor()
+		{
+			text = new Clutter.Text();
+			text.color = {0, 0, 0, 255};
+			text.font_name = "Sans 12";
+			
+			texture = new Clutter.Texture();
+		}
+		
+		/**
+		 * Sets this IconActor's texture to a GdkPixbuf.
+		 */
+		public void set_pixbuf(Gdk.Pixbuf pixbuf)
+		{
+			try
+			{
+				GtkClutter.texture_set_from_pixbuf(texture, pixbuf);
+				
+				height = width * (texture.height / texture.width) +
+				         2 * TEXT_PADDING + TEXT_HEIGHT;
+			}
+			catch (Error e)
+			{
+				critical(e.message);
+			}                         
+		}
+		
+		/**
+		 * Sets this IconActor's text to a markup string.
+		 */
+		public void set_markup(string markup)
+		{
+			text.use_markup = true;
+			text.text = markup;
+		}
+		
+		/**
+		 * Sets this IconActor's text to a string.
+		 */
+		public void set_text(string text)
+		{
+			this.text.use_markup = false;
+			this.text.text = text;
+		}
+	}
+}
diff --git a/ease/ease-scrollable-embed.vala b/ease-core/ease-scrollable-embed.vala
similarity index 93%
rename from ease/ease-scrollable-embed.vala
rename to ease-core/ease-scrollable-embed.vala
index 9692c8f..e1e4ff1 100644
--- a/ease/ease-scrollable-embed.vala
+++ b/ease-core/ease-scrollable-embed.vala
@@ -21,13 +21,13 @@
  * A ScollableEmbed contains a { link GtkClutter.Viewport} within a
  * { link GtkClutter.Embed}. The horizontal scrollbar is optional.
  */
-internal class Ease.ScrollableEmbed : Gtk.HBox
+public class Ease.ScrollableEmbed : Gtk.HBox
 {
 	// actors
 	private GtkClutter.Embed embed;
 	private GtkClutter.Viewport viewport;
 	private Clutter.Stage stage;
-	internal Clutter.Group contents { get; private set; }
+	public Clutter.Group contents { get; private set; }
 
 	// scrolling
 	private Gtk.HScrollbar h_scrollbar;
@@ -41,17 +41,17 @@ internal class Ease.ScrollableEmbed : Gtk.HBox
 	// constants
 	private const int FRAME_PADDING = 2;
 	
-	internal bool has_horizontal { get; private set; }
+	public bool has_horizontal { get; private set; }
 	
 	/**
 	 * The width of this ScrollableEmbed's Stage.
 	 */
-	internal float width { get{ return stage.width; } }
+	public float width { get{ return stage.width; } }
 
 	/**
 	 * The height of this ScrollableEmbed's Stage.
 	 */
-	internal float height { get { return stage.height; } }
+	public float height { get { return stage.height; } }
 	
 	/**
 	 * Instantiate a ScollableEmbed with an optional vertical sidebar.
@@ -63,7 +63,7 @@ internal class Ease.ScrollableEmbed : Gtk.HBox
 	 * scrollbar in addition to the vertical scrollbar.
 	 * @param has_frame If the EditorEmbed should have a frame around its stage.
 	 */
-	internal ScrollableEmbed(bool horizontal, bool has_frame)
+	public ScrollableEmbed(bool horizontal, bool has_frame)
 	{
 		has_horizontal = horizontal;
 		// create children
@@ -173,7 +173,7 @@ internal class Ease.ScrollableEmbed : Gtk.HBox
 	 * Returns the stage of this ScrollableEmbed. Use with caution. Most
 	 * actors should be placed onto the "contents" ClutterGroup.
 	 */
-	internal Clutter.Stage get_stage()
+	public Clutter.Stage get_stage()
 	{
 		return (Clutter.Stage)(embed.get_stage());
 	}
@@ -193,7 +193,7 @@ internal class Ease.ScrollableEmbed : Gtk.HBox
 	/**
 	 * When grabbing focus, grab it on the embed.
 	 */
-	internal override void grab_focus()
+	public override void grab_focus()
 	{
 		embed.grab_focus();
 	}
diff --git a/ease/Makefile.am b/ease/Makefile.am
index d57a9ac..37b2b37 100644
--- a/ease/Makefile.am
+++ b/ease/Makefile.am
@@ -21,7 +21,6 @@ ease_SOURCES = \
 	ease-inspector.vala \
 	ease-main.vala \
 	ease-player.vala \
-	ease-scrollable-embed.vala \
 	ease-selection-rectangle.vala \
 	ease-slide-actor.vala \
 	ease-slide-button-panel.vala \
diff --git a/ease/ease-slide-sorter.vala b/ease/ease-slide-sorter.vala
index 3b49f40..557503c 100644
--- a/ease/ease-slide-sorter.vala
+++ b/ease/ease-slide-sorter.vala
@@ -18,9 +18,8 @@
 /**
  * A widget displaying an icon view the user can use to sort and delete slides.
  */
-internal class Ease.SlideSorter : Gtk.ScrolledWindow
+internal class Ease.SlideSorter : IconView
 {
-	private Gtk.IconView view;
 	private Document document;
 	
 	private const int WIDTH = 100;
@@ -31,6 +30,7 @@ internal class Ease.SlideSorter : Gtk.ScrolledWindow
 	
 	internal SlideSorter(Document doc, double zoom)
 	{
+		base.with_model(doc.slides);
 		document = doc;
 		document.slide_added.connect(on_slide_added);
 		
@@ -38,22 +38,17 @@ internal class Ease.SlideSorter : Gtk.ScrolledWindow
 		set_zoom(zoom);
 		
 		// set up the icon view
-		view = new Gtk.IconView.with_model(document.slides);
-		view.pixbuf_column = Document.COL_PIXBUF_DYNAMIC;
-		view.markup_column = Document.COL_TITLE;
-		view.reorderable = true;
-		view.item_width = WIDTH;
-		
-		// add and show the iconview
-		add(view);
-		view.show();
+		pixbuf_column = Document.COL_PIXBUF_DYNAMIC;
+		markup_column = Document.COL_TITLE;
+		reorderable = true;
+		item_width = WIDTH;
 		
 		// when a slide is clicked, show it in the editor
-		view.item_activated.connect((v, path) => {
+		item_activated.connect((v, path) => {
 			Gtk.TreeIter itr;
 			Slide slide;
-			view.model.get_iter(out itr, path);
-			view.model.get(itr, Document.COL_SLIDE, out slide);
+			model.get_iter(out itr, path);
+			model.get(itr, Document.COL_SLIDE, out slide);
 			display_slide(slide);
 		});
 	}
@@ -63,10 +58,10 @@ internal class Ease.SlideSorter : Gtk.ScrolledWindow
 		Slide slide = null, ret_slide = null;
 		GLib.List<Slide> slides_to_remove = null;
 		
-		view.selected_foreach((v, path) => {
+		selected_foreach((v, path) => {
 			Gtk.TreeIter itr;
-			view.model.get_iter(out itr, path);
-			view.model.get(itr, Document.COL_SLIDE, out slide);
+			model.get_iter(out itr, path);
+			model.get(itr, Document.COL_SLIDE, out slide);
 			slides_to_remove.append(slide);
 		});
 		



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