// // Copyright (C) 2009 Dani Hernandez Juarez, dhernandez0@gmail.com // 2009 Jordi Mas i Hernàndez, jmas@softcatala.org // // 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 Cairo; using Gtk; using Gdk; using Mono.Unix; using Mistelix.Core; using Mistelix.DataModel; using Mistelix.Transitions; using Mistelix.Dialogs; namespace Mistelix.Widgets { public class FullScreenWindow : Gtk.Window { SlideShowView slide_show_view; 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 = Catalog.GetString("Slideshow preview"); KeyPressEvent += HandleSlideViewKeyPressEvent; Decorated = false; Fullscreen(); Add(slide_show_view); ShowAll(); } [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 (); AddSlideDialogRunner.Dialog.Visible = true; AddSlideDialogRunner.Run (); AddSlideDialogRunner.ProcessResponse (); break; } } } /// Displays a slideshow public class SlideShowView : DrawingArea { #region fields SlideShow slide; int current_index_image; SlideImage current_image; Transition transition; bool paused = false; const uint MinTime = 100; bool started = false; bool destroyed = false; 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; } #region public methods public void Start() { if(current_image == null) CurrentIndex = 0; if (slide.images.Count == 1) // Single image, just show it current_image = ResizeImage (CurrentIndex); if(!PlayingTransition()) Forward(); } public void Pause() { paused = true; } public void Stop() { CurrentIndex = 0; Pause(); ClearTransition(); } 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() { destroyed = true; ClearTransition(); if(current_image != null) current_image.ReleasePixels(); 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() { if(transition != null) { transition.Source.ReleasePixels(); transition.Target.ReleasePixels(); 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) { using(DataImageSurface newImage = imageToShow.ToDataImageSurface()) { ShowImage(newImage); } } void ShowImage(DataImageSurface imageToShow) { using(Cairo.Context context = Gdk.CairoHelper.Create(this.GdkWindow)) { Pattern pattern = new Pattern (imageToShow); context.Source = pattern; context.Paint (); ((IDisposable)pattern).Dispose (); } } 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); oldImage.ReleasePixels(); return newImage; } #endregion #region event callbacks protected override bool OnExposeEvent (Gdk.EventExpose args) { if (started == false) { started = true; Start (); } if(current_image != null) { ShowImage(current_image); } return base.OnExposeEvent(args); } // Return true to restart the timeout. Returning false clears the timeout bool OnNextSlide() { if (destroyed) return false; if(paused) return true; else if(transition.MoveNext()) { SlideImage newImage = transition.Current as SlideImage; if(newImage != current_image) { if(current_image != null) current_image.ReleasePixels(); current_image = newImage; ShowImage(current_image); } return true; } else { ClearTransition(); CurrentIndex++; Forward(); return false; } } #endregion } }