[mistelix] Slideshow preview
- From: Jordi Mas <jmas src gnome org>
- To: svn-commits-list gnome org
- Subject: [mistelix] Slideshow preview
- Date: Thu, 14 May 2009 14:45:17 -0400 (EDT)
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]