[mistelix] Slideshow preview



commit 739c2ae712c44ecf34988a01215b7d9f479c3a55
Author: Dani Hernandez Juarez <dhernandez0 gmail com>
Date:   Thu May 14 20:45:28 2009 +0200

    Slideshow preview
---
 po/POTFILES.in                    |    2 +
 src/Makefile.am                   |    1 +
 src/core/SlideImage.cs            |   45 ++++++-
 src/dialogs/AddSlideDialog.cs     |   18 ++-
 src/mistelix.cs                   |    2 +-
 src/mistelix.glade                |    3 +-
 src/widgets/ProjectElementView.cs |    2 +-
 src/widgets/SlideShowView.cs      |  261 +++++++++++++++++++++++++++++++++++++
 8 files changed, 326 insertions(+), 8 deletions(-)

diff --git a/po/POTFILES.in b/po/POTFILES.in
index a8699bc..8b07174 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -28,3 +28,5 @@ src/widgets/BrowseFile.cs
 src/widgets/DirectoryView.cs
 src/widgets/ProjectElementView.cs
 src/widgets/SlideShowImageView.cs
+src/widgets/SlideShowView.cs
+
diff --git a/src/Makefile.am b/src/Makefile.am
index f76bee7..f1004c5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,6 +25,7 @@ MISTELIX_CSDISTFILES =				\
 	$(srcdir)/widgets/AuthoringPaneView.cs	\
 	$(srcdir)/widgets/ProjectElementView.cs	\
 	$(srcdir)/widgets/PixbufImageSurface.cs	\
+	$(srcdir)/widgets/SlideShowView.cs	\
 	$(srcdir)/widgets/GtkMenu.cs	\
 	$(srcdir)/dialogs/GtkDialog.cs	\
 	$(srcdir)/dialogs/AddSlideDialog.cs	\
diff --git a/src/core/SlideImage.cs b/src/core/SlideImage.cs
index 13fe53f..713ba9b 100644
--- a/src/core/SlideImage.cs
+++ b/src/core/SlideImage.cs
@@ -154,6 +154,7 @@ namespace Mistelix.DataModel
 		[System.Xml.Serialization.XmlIgnoreAttribute]
 		public Project Project {
 			set { project = value; }
+			get { return project; }
 		}
 
 		public void CopyProperties (SlideImage src)
@@ -165,6 +166,8 @@ namespace Mistelix.DataModel
 			alpha = src.alpha;
 			channels = src.channels;
 			Effects = src.Effects;
+			project = src.project;
+			Position = src.Position;
 
 			image = src.image;
 		}
@@ -177,14 +180,54 @@ namespace Mistelix.DataModel
 		{
 			pixels = null;
 		}
-
+		
+		public SlideImage GetSlideThumbnail(int width, int height)
+		{
+			return GetSlideThumbnail(width, height, false);
+		}	
+			
+		public SlideImage GetSlideThumbnail(int width, int height, bool copyTitle)
+		{	
+			SlideImage newImage = new SlideImage();
+			newImage.CopyProperties(this);
+			using(DataImageSurface thumbnail = this.GetThumbnail(width, height, copyTitle)) {
+				newImage.FromDataImageSurface(thumbnail);
+			}
+			return newImage;
+		}
+		
 		public DataImageSurface GetThumbnail (int width, int height)
 		{
+			return GetThumbnail(width, height, false);
+		}
+		
+		public DataImageSurface GetThumbnail (int width, int height, bool copy_title)
+		{
 			PixelFormat pixelformat_src;
 			SlideImage slide = new SlideImage ();
 			slide.CopyProperties (this);
+			if(copy_title)
+				slide.Title = Title;
 			slide.LoadAndScaleImage (width, height);
 			slide.ProcessEffects ();
+			slide.ProcessImage ();
+
+			pixelformat_src = slide.pixel_format; // Pixel format of current buffer
+			slide.pixel_format = PixelFormat.CAIRO_ARGB; // New target format
+			slide.LoadFromPixelData (slide.pixels, pixelformat_src,
+				width, height, width * slide.channels, slide.channels);
+
+			return new DataImageSurface (DataImageSurface.Allocate (slide.Pixels),
+				Cairo.Format.ARGB32, slide.width, slide.height, slide.stride);
+		}
+		
+		public DataImageSurface ToDataImageSurface()
+		{
+			PixelFormat pixelformat_src;
+			SlideImage slide = new SlideImage ();
+			slide.CopyProperties (this);
+			slide.pixels = (byte[]) this.Pixels.Clone();
+			slide.ProcessEffects ();
 
 			pixelformat_src = slide.pixel_format; // Pixel format of current buffer
 			slide.pixel_format = PixelFormat.CAIRO_ARGB; // New target format
diff --git a/src/dialogs/AddSlideDialog.cs b/src/dialogs/AddSlideDialog.cs
index e299425..21ec209 100644
--- a/src/dialogs/AddSlideDialog.cs
+++ b/src/dialogs/AddSlideDialog.cs
@@ -55,6 +55,7 @@ namespace Mistelix.Dialogs
 		bool edit_mode;
 		string audiofile;
 		bool no_audio;
+		Project project;
 
 		[Glade.Widget] Gtk.VBox left_vbox;
 		[Glade.Widget ("scrolledwindow_files")] Gtk.ScrolledWindow scrolledwin_files;
@@ -66,15 +67,17 @@ namespace Mistelix.Dialogs
 		[Glade.Widget] Gtk.HBox ctrls_hbox;
 		[Glade.Widget] Gtk.Button up_button;
 		[Glade.Widget] Gtk.Button down_button;
+		[Glade.Widget] Gtk.Button preview;
 		[Glade.Widget] Gtk.Button audio_button;
 		[Glade.Widget] Gtk.VBox vbox_dir;
 		[Glade.Widget] Gtk.ComboBox textposition_combo;
 
 		// TODO: Since allows editing probably should be renamed to SlideDialog
-		public AddSlideDialog () : base ("addslide")		
+		public AddSlideDialog (Project project) : base ("addslide")		
 		{
+			this.project = project;
 			LoadWindowPosition ();
-
+			
 			image_view = new SlideShowImageView ();
 			image_view.ChangeEvent = new ShowImageSelectionEventHandler (OnChangeImage);
 			image_view.UpdatedElements = new ShowImageUpdatedElementsEventHandler (OnUpdatedImages);
@@ -116,8 +119,6 @@ namespace Mistelix.Dialogs
 		public SlideShow SlideShow {
 			get {
 				Logger.Debug ("AddSlideDialog.SlideShow");
-				if (slide != null && edit_mode == false)
-					return slide;
 
 				if (edit_mode == true) { // Reuse the same object, only store the images again
 					slide.images.Clear ();
@@ -140,6 +141,7 @@ namespace Mistelix.Dialogs
 				while (more)
 				{
 					image = (SlideImage) image_view.Model.GetValue (iter, SlideShowImageView.COL_OBJECT);
+					image.Project = this.project;
 					slide.images.Add (image);
 					more = image_view.Model.IterNext (ref iter);
 				}
@@ -324,6 +326,14 @@ namespace Mistelix.Dialogs
 				more = textposition_store.IterNext (ref iter);
 			}
 		}
+		
+		void OnPreview (object sender, EventArgs args) 
+		{
+			SlideShow slide_show = this.SlideShow;
+			SlideShowView slide_show_view = new SlideShowView(slide_show);
+			FullScreenWindow full_screen = new FullScreenWindow(slide_show_view);
+			Destroy ();
+		}
 
 		// If there are at least two elements we enable the navigation buttons
 		void OnUpdatedImages (object sender, EventArgs args)
diff --git a/src/mistelix.cs b/src/mistelix.cs
index 014d661..b5502ca 100644
--- a/src/mistelix.cs
+++ b/src/mistelix.cs
@@ -193,7 +193,7 @@ namespace Mistelix
 
 		void OnAddSlideShow (object sender, EventArgs args)
 		{
-			AddSlideDialog dialog = new AddSlideDialog ();
+			AddSlideDialog dialog = new AddSlideDialog (this.project);
 
 			if (dialog.RunNoDestroy () == ResponseType.Ok && dialog.SlideShow.images.Count > 0) {
 				Logger.Debug ("OnSlideshowsButtonClicked.Ok");
diff --git a/src/mistelix.glade b/src/mistelix.glade
index cb4803f..45d0908 100644
--- a/src/mistelix.glade
+++ b/src/mistelix.glade
@@ -901,13 +901,14 @@
 			  <child>
 			    <widget class="GtkButton" id="preview">
 			      <property name="visible">True</property>
-			      <property name="sensitive">False</property>
+			      <property name="sensitive">True</property>
 			      <property name="can_default">True</property>
 			      <property name="can_focus">True</property>
 			      <property name="label" translatable="yes">Preview</property>
 			      <property name="use_underline">True</property>
 			      <property name="relief">GTK_RELIEF_NORMAL</property>
 			      <property name="focus_on_click">True</property>
+			      <signal name="clicked" handler="OnPreview" last_modification_time="Sun, 09 Nov 2008 14:14:34 GMT"/>
 			    </widget>
 			  </child>
 			</widget>
diff --git a/src/widgets/ProjectElementView.cs b/src/widgets/ProjectElementView.cs
index a48bb28..9a13746 100644
--- a/src/widgets/ProjectElementView.cs
+++ b/src/widgets/ProjectElementView.cs
@@ -268,7 +268,7 @@ namespace Mistelix.Widgets
 			if (current.GetType () != typeof (SlideShow))
 				return;
 
-			AddSlideDialog dialog = new AddSlideDialog ();
+			AddSlideDialog dialog = new AddSlideDialog (this.project);
 			dialog.SlideShow = (SlideShow) current;
 
 			if (dialog.RunNoDestroy () == ResponseType.Ok) {
diff --git a/src/widgets/SlideShowView.cs b/src/widgets/SlideShowView.cs
new file mode 100644
index 0000000..0ab7f01
--- /dev/null
+++ b/src/widgets/SlideShowView.cs
@@ -0,0 +1,261 @@
+//
+// Copyright (C) 2009 Dani Hernandez Juarez, dhernandez0 gmail com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Media;
+
+using Cairo;
+using Gtk;
+using Gdk;
+using Mono.Unix;
+
+using Mistelix.Core;
+using Mistelix.DataModel;
+using Mistelix.Transitions;
+
+namespace Mistelix.Widgets
+{	
+	public class FullScreenWindow : Gtk.Window
+	{
+		SlideShowView slide_show_view;
+		static readonly string WindowTitle;
+		
+		static FullScreenWindow()
+		{
+			WindowTitle = Catalog.GetString("Slideshow preview");
+		}
+		
+		public FullScreenWindow(SlideShowView slide_show_view) : base(Gtk.WindowType.Toplevel)
+		{
+			if(slide_show_view == null)
+				throw new System.ArgumentException("SlideShowView shouldn't be null");
+			this.slide_show_view = slide_show_view;
+			Title = WindowTitle;
+			KeyPressEvent += HandleSlideViewKeyPressEvent;
+			Decorated = false;
+			Fullscreen();
+			Add(slide_show_view);
+			ShowAll();
+			this.slide_show_view.Start();
+		}
+		
+		[GLib.ConnectBefore]
+		protected virtual void HandleSlideViewKeyPressEvent (object sender, KeyPressEventArgs args)
+		{
+			switch(args.Event.Key) {
+			case Gdk.Key.Left:
+				slide_show_view.Pause();
+				slide_show_view.Previous();
+				args.RetVal = true;
+				break;
+			case Gdk.Key.Right:
+				slide_show_view.Pause();
+				slide_show_view.Next();
+				args.RetVal = true;
+				break;
+			case Gdk.Key.Escape:
+				slide_show_view.Stop();
+				slide_show_view.Destroy ();
+				args.RetVal = true;
+				this.Destroy ();
+				break;
+			}
+		}
+	}
+	
+	/// Displays a slideshow
+	public class SlideShowView : DrawingArea
+	{
+		#region fields
+		SlideShow slide;
+		int current_index_image;
+		SlideImage current_image;
+		Transition transition;
+		SoundPlayer player;
+		bool paused = false;
+		const uint MinTime = 100;
+		int CurrentIndex {
+			set {
+				if(current_index_image == value)
+					return;
+				current_index_image = value;
+				current_image = ResizeImage(current_index_image);
+				ShowImage(current_image);
+			}
+			get {
+				return current_index_image;
+			}
+		}
+		#endregion
+		
+		public SlideShowView(SlideShow slide)
+		{
+			if(slide == null || slide.images.Count == 0)
+				throw new System.ArgumentException("Slide cannot be null and should have an image at least");
+			this.slide = slide;
+			this.current_index_image = 0;
+			if(slide.AudioFile != null) {
+				player = new SoundPlayer(slide.AudioFile);
+				player.Load();
+			}
+		}
+		
+		#region public methods
+		public void Start() {
+			if(current_image == null)
+				CurrentIndex = 0;
+			if (player != null)
+				player.PlayLooping();
+			if(!PlayingTransition())
+				Forward();
+		}
+		
+		public void Pause() {
+			if (player != null)
+				player.Stop();
+			paused = true;
+		}
+		
+		public void Stop() {
+			CurrentIndex = 0;
+			ClearTransition();
+			Pause();
+		}
+
+		public void Next()
+		{
+			if(HasNext()) {
+				if(!PlayingTransition())
+					CurrentIndex++;
+				else {
+					int index = CurrentIndex;
+					CurrentIndex = index + 1;
+				}
+			}
+		}
+
+		public void Previous() {
+			if(HasPrevious())
+				CurrentIndex--;
+			else if(PlayingTransition())
+				CurrentIndex = 0;
+		}
+		
+		public override void Destroy()
+		{
+			ClearTransition();
+			base.Destroy();
+		}
+		#endregion
+		
+		#region methods
+		void Forward() {
+			if(HasNext()) {
+				transition = TransitionManager.CreateFromName (slide.images[CurrentIndex].Transition);
+				SlideImage source = ResizeImage(CurrentIndex);
+				transition.Source = source;
+				SlideImage target = ResizeImage(CurrentIndex + 1);
+				transition.Target = target;
+				transition.Frames = transition.Source.Project.Details.FramesPerSecond * slide.images[CurrentIndex].TransitionTime;
+				uint time = (uint)(1000/transition.Source.Project.Details.FramesPerSecond);
+				time = time < MinTime ? MinTime : time;
+				GLib.Timeout.Add(time, new GLib.TimeoutHandler(OnNextSlide));
+			} else {
+				Pause();
+			}
+		}
+		
+		void ClearTransition()
+		{
+			transition = null;
+		}
+		
+		bool PlayingTransition()
+		{
+			return transition != null;
+		}
+
+		bool HasNext() {
+			return this.CurrentIndex + 1 < this.slide.images.Count;
+		}
+
+		bool HasPrevious() {
+			return this.CurrentIndex - 1 >= 0;
+		}
+
+		void ShowImage(SlideImage imageToShow)
+		{
+			ShowImage(this.GdkWindow, imageToShow);
+		}
+		
+		void ShowImage(Gdk.Window window, SlideImage imageToShow)
+		{
+			using(ImageSurface newImage = imageToShow.ToDataImageSurface()) {
+				ShowImage(window, newImage);
+			}
+		}
+
+		void ShowImage(Gdk.Window window, ImageSurface imageToShow)
+		{
+			using(Cairo.Context context = Gdk.CairoHelper.Create(window)) {
+				context.Source = new Pattern (imageToShow);
+				context.Paint ();
+			}
+		}
+		
+		SlideImage ResizeImage(int index)
+		{
+			int width = this.GdkWindow.FrameExtents.Width;
+			int height = this.GdkWindow.FrameExtents.Height;
+			SlideImage oldImage = slide.images[index] as SlideImage;
+			oldImage.LoadSlide();
+			SlideImage newImage = oldImage.GetSlideThumbnail(width, height, true);
+			return newImage;
+		}
+		#endregion
+		
+		#region event callbacks
+		bool OnExposeEvent (Gdk.EventExpose args)
+		{
+			ShowImage(args.Window, current_image);
+			return base.OnExposeEvent(args);
+		}
+		
+		bool OnNextSlide()
+		{
+			if(paused)
+				return true;
+			else if(transition.MoveNext()) {
+				current_image = transition.Current as SlideImage;
+				ShowImage(current_image);
+				return true;
+			} else {
+				CurrentIndex++;
+				ClearTransition();
+				Forward();
+				return false;
+			}
+		}
+		#endregion
+	}
+}



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