banshee r3469 - in trunk/banshee: . src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.ServiceStack src/Core/Banshee.ThickClient/Banshee.Gui.Widgets src/Libraries/Hyena.Gui src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics src/Libraries/Hyena.Gui/Hyena.Widgets



Author: abock
Date: Sun Mar 16 21:15:54 2008
New Revision: 3469
URL: http://svn.gnome.org/viewvc/banshee?rev=3469&view=rev

Log:
2008-03-16  Scott Peterson  <lunchtimemama gmail com>

    Added animated layout widgets to Hyena.Gui

    * src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs:
    Cast the shutdown handlers in the foreach statement.

    * src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/UserJobTileHost.
    cs: User jobs now use the fancy fancy AnimatedVBox.

    * src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Actor.cs:
    Added an overload for Rest which takes a new duration.

    * src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Choreographer.cs:
    A static class which provides math-o-magical easing equations.

    * src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Stage.cs:
    Added an overload for Rest which takes a new duration and &= the
    ActorStepHandlers together to fix a theoretical bug.

    * src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedBox.cs:
    A base class for doing animated packing.
    * src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedHBox.cs:
    A container for animatedly packing widgets into a horizontal box.

    * src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedVBox.cs:
    A container for animatedly packing widgets into a vertical box.

    * src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedWidget.cs:
    An internal class used by the AnimatedBox classes

    * src/Libraries/Hyena.Gui/Makefile.am:
    * src/Core/Banshee.Services/Banshee.Services.mdp:
    * src/Libraries/Hyena.Gui/Hyena.Gui.mdp:



Added:
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Choreographer.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedBox.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedHBox.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedVBox.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedWidget.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/UserJobTileHost.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Actor.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Stage.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.mdp
   trunk/banshee/src/Libraries/Hyena.Gui/Makefile.am

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs	Sun Mar 16 21:15:54 2008
@@ -1,3 +1,4 @@
+
 //
 // Application.cs
 //
@@ -87,8 +88,8 @@
         {
             ShutdownRequestHandler handler = ShutdownRequested;
             if (handler != null) {
-                foreach (Delegate d in handler.GetInvocationList ()) {
-                    if(!(bool)d.DynamicInvoke (null)) {
+                foreach (ShutdownRequestHandler del in handler.GetInvocationList ()) {
+                    if(!del ()) {
                         return false;
                     }
                 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp	Sun Mar 16 21:15:54 2008
@@ -12,7 +12,6 @@
     <File name="Banshee.Database/BansheeDbFormatMigrator.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Collection.Database/AlbumListDatabaseModel.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Collection.Database/ArtistListDatabaseModel.cs" subtype="Code" buildaction="Compile" />
-    <File name="Banshee.Collection.Database/LibraryAlbumInfo.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Collection.Database/LibraryArtistInfo.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Collection.Database/DatabaseTrackInfo.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Collection.Database/TrackListDatabaseModel.cs" subtype="Code" buildaction="Compile" />
@@ -127,6 +126,7 @@
     <File name="Banshee.ServiceStack/IInitializeService.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Query/PlaylistQueryValue.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Collection/SelectAllSelection.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Collection.Database/DatabaseAlbumInfo.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/UserJobTileHost.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/UserJobTileHost.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/UserJobTileHost.cs	Sun Mar 16 21:15:54 2008
@@ -31,6 +31,7 @@
 
 using Gtk;
 
+using Hyena.Gui;
 using Banshee.Base;
 using Banshee.ServiceStack;
 
@@ -38,12 +39,12 @@
 {
     public class UserJobTileHost : Alignment
     {
-        private VBox box;
+        private AnimatedVBox box;
         private Dictionary<IUserJob, UserJobTile> job_tiles = new Dictionary<IUserJob, UserJobTile> ();
         
         public UserJobTileHost () : base (0.0f, 0.0f, 1.0f, 1.0f)
         {
-            box = new VBox ();
+            box = new AnimatedVBox ();
             box.Spacing = 8;
             box.Show ();
 
@@ -85,7 +86,7 @@
             if ((job.DelayShow && job.Progress < 0.33) || !job.DelayShow) {
                 UserJobTile tile = new UserJobTile (job);
                 job_tiles.Add (job, tile);
-                box.PackStart (tile, false, false, 0);
+                box.PackEnd (tile, Easing.QuadraticOut);
                 tile.Show ();
                 Show ();
             }

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Actor.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Actor.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Actor.cs	Sun Mar 16 21:15:54 2008
@@ -49,9 +49,15 @@
         
         public void Reset ()
         {
+            Reset (duration);
+        }
+        
+        public void Reset (uint duration)
+        {
             start_time = DateTime.Now;
             frames = 0.0;
             percent = 0.0;
+            this.duration = duration;
         }
         
         public virtual void Step ()

Added: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Choreographer.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Choreographer.cs	Sun Mar 16 21:15:54 2008
@@ -0,0 +1,78 @@
+//
+// Choreographer.cs
+//
+// Authors:
+//   Scott Peterson <lunchtimemama gmail com>
+//
+// Copyright (C) 2008 Scott Peterson
+//
+// 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;
+
+namespace Hyena.Gui
+{
+    public enum Blocking
+    {
+        Upstage,
+        Downstage
+    }
+    
+    public enum Easing
+    {
+        Linear,
+        QuadraticIn,
+        QuadraticOut,
+        QuadraticInOut,
+        ExponentialIn,
+        ExponentialOut,
+        ExponentialInOut
+    }
+    
+    public static class Choreographer
+    {
+        public static int Compose (double percent, int size, Easing easing)
+        {
+            switch (easing) {
+                case Easing.QuadraticIn:
+                    return (int)(percent * percent * size);
+                case Easing.QuadraticOut:
+                    return (int)(-size * percent * (percent - 2));
+                case Easing.QuadraticInOut:
+                    percent *= 2;
+                    return (percent < 1)
+                        ? (int)(percent * percent * (size / 2))
+                        : (int)((-size / 2) * (--percent * (percent - 2) - 1));
+                case Easing.ExponentialIn:
+                    return (int)(size * Math.Pow (2, 10 * (percent - 1)));
+                case Easing.ExponentialOut:
+                    return (int)(size * (-Math.Pow (2, -10 * percent) + 1));
+                case Easing.ExponentialInOut:
+                    percent *= 2;
+                    return (percent < 1)
+                        ? (int)(size/2 * Math.Pow (2, 10 * (percent - 1)))
+                        : (int)(size/2 * (-Math.Pow (2, -10 * --percent) + 2));
+                default:
+                    return (int)(percent * size);
+            }
+        }
+    }
+}
\ No newline at end of file

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Stage.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Stage.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.Theatrics/Stage.cs	Sun Mar 16 21:15:54 2008
@@ -99,9 +99,28 @@
         public Actor<T> AddOrReset (T target)
         {
             lock (this) {
+                return AddOrResetCore (target, null);
+            }
+        }
+        
+        public Actor<T> AddOrReset (T target, uint duration)
+        {
+            lock (this) {
+                return AddOrResetCore (target, duration);
+            }
+        }
+        
+        private Actor<T> AddOrResetCore (T target, uint? duration)
+        {
+            lock (this) {
                 if (Contains (target)) {
                     Actor<T> actor = this[target];
-                    actor.Reset ();
+                    
+                    if (duration == null) {
+                        actor.Reset ();
+                    } else {
+                        actor.Reset (duration.Value);
+                    }
                     
                     CheckTimeout ();
                     
@@ -115,13 +134,31 @@
         public void Reset (T target)
         {
             lock (this) {
+                ResetCore (target, null);
+            }
+        }
+        
+        public void Reset (T target, uint duration)
+        {
+            lock (this) {
+                ResetCore (target, duration);
+            }
+        }
+        
+        private void ResetCore (T target, uint? duration)
+        {
+            lock (this) {
                 if (!Contains (target)) {
                     throw new InvalidOperationException ("Stage does not contain this actor");
                 }
                 
                 CheckTimeout ();
                 
-                this[target].Reset ();
+                if (duration == null) {
+                    this [target].Reset ();
+                } else {
+                    this [target].Reset (duration.Value);
+                }
             }
         }
         
@@ -139,26 +176,21 @@
         
         private bool OnTimeout ()
         {
-            if (!Playing || actors.Count == 0) {
+            if (!Playing || this.actors.Count == 0) {
                 timeout_id = 0;
                 return false;
             }
             
-            Queue<Actor<T>> expired_actors = new Queue<Actor<T>> ();
-            Dictionary<T, Actor<T>> actors_copy = new Dictionary<T, Actor<T>> (actors);
-            
-            foreach (KeyValuePair<T, Actor<T>> entry in actors_copy) {
-                entry.Value.Step ();
+            Queue<Actor<T>> actors = new Queue<Actor<T>> (this.actors.Values);
+            while (actors.Count > 0) {
+                Actor<T> actor = actors.Dequeue ();
+                actor.Step ();
                 
-                if (!OnActorStep (entry.Value) || entry.Value.Expired) {
-                    expired_actors.Enqueue (entry.Value);
+                if (!OnActorStep (actor) || actor.Expired) {
+                    this.actors.Remove (actor.Target);
                 }
             }
             
-            while (expired_actors.Count > 0) {
-                actors.Remove (expired_actors.Dequeue ().Target);
-            }
-            
             OnIteration ();
             
             return true;
@@ -168,7 +200,11 @@
         {
             ActorStepHandler handler = ActorStep;
             if (handler != null) {
-                return handler (actor);
+                bool result = true;
+                foreach (ActorStepHandler del in handler.GetInvocationList ()) {
+                    result &= del (actor);
+                }
+                return result;
             }
             return false;
         }

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.mdp
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.mdp	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Gui.mdp	Sun Mar 16 21:15:54 2008
@@ -54,6 +54,11 @@
     <File name="Hyena.Gui.Theming/GtkTheme.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Data.Gui/ListView/ListView_DragAndDrop.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Gui/PangoCairoHelper.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Widgets/AnimatedBox.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Widgets/AnimatedHBox.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Widgets/AnimatedVBox.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Widgets/AnimatedWidget.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Gui.Theatrics/AnimationHelper.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

Added: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedBox.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedBox.cs	Sun Mar 16 21:15:54 2008
@@ -0,0 +1,401 @@
+//
+// AnimatedBox.cs
+//
+// Authors:
+//   Scott Peterson <lunchtimemama gmail com>
+//
+// Copyright (C) 2008 Scott Peterson
+//
+// 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.Collections;
+using System.Collections.Generic;
+using Gdk;
+using Gtk;
+
+using Hyena.Gui.Theatrics;
+
+namespace Hyena.Gui
+{
+    public abstract class AnimatedBox : Container, IEnumerable<Widget>
+    {
+        private readonly Stage<AnimatedWidget> stage = new Stage<AnimatedWidget> ();
+        private readonly Queue<AnimatedWidget> expired = new Queue<AnimatedWidget> ();
+        private readonly LinkedList<AnimatedWidget> children = new LinkedList<AnimatedWidget> ();
+        private readonly object childrenMutex = new object ();
+        
+        protected int spacing;
+        protected int startSpacing;
+        protected int endSpacing;
+        
+        private uint duration = 500;
+        private Easing easing = Easing.Linear;
+        private Blocking blocking = Blocking.Upstage;
+        
+        protected AnimatedBox ()
+        {
+            stage.ActorStep += OnActorStep;
+            stage.Iteration += OnIteration;
+        }
+        
+#region Private Methods
+        
+        private bool OnActorStep (Actor<AnimatedWidget> actor)
+        {
+            lock (actor.Target) {
+                switch (actor.Target.AnimationState) {
+                case AnimationState.Coming:
+                    actor.Target.Percent = actor.Percent;
+                    if (actor.Expired) {
+                        actor.Target.AnimationState = AnimationState.Idle;
+                        return false;
+                    }
+                    break;
+                case AnimationState.IntendingToGo:
+                    actor.Target.AnimationState = AnimationState.Going;
+                    actor.Target.Bias = actor.Percent;
+                    actor.Reset ((uint)(actor.Target.Duration * actor.Percent));
+                    break;
+                case AnimationState.Going:
+                    if (actor.Expired) {
+                        lock (childrenMutex) {
+                            children.Remove (actor.Target.Node);
+                        }
+                        expired.Enqueue (actor.Target);
+                        return false;
+                    } else {
+                        actor.Target.Percent = 1.0 - actor.Percent;
+                    }
+                    break;
+                }
+            }
+            
+            return true;
+        }
+        
+        private void OnIteration (object sender, EventArgs args)
+        {
+            // When widgets are disposed, their hash code changes (zee uber lame).
+            // We would otherwise do this up in OnActorStep, but the has code needs
+            // to remain the same so that the actor can be removed from the stage.
+            while (expired.Count > 0) {
+                AnimatedWidget widget = expired.Dequeue ();
+                widget.Unparent ();
+                widget.Dispose ();
+            }
+            
+            QueueResizeNoRedraw ();
+        }
+        
+        private void OnWidgetDestroyed (object sender, EventArgs args)
+        {
+            RemoveCore ((AnimatedWidget)sender);
+        }
+        
+#endregion
+    
+#region Pack Methods
+        
+        public void PackStart (Widget widget)
+        {
+            PackStart (widget, duration, easing, blocking);
+        }
+        
+        public void PackStart (Widget widget, uint duration)
+        {
+            PackStart (widget, duration, easing, blocking);
+        }
+        
+        public void PackStart (Widget widget, Easing easing)
+        {
+            PackStart (widget, duration, easing, blocking);
+        }
+        
+        public void PackStart (Widget widget, uint duration, Easing easing)
+        {
+            PackStart (widget, duration, easing, blocking);
+        }
+        
+        public void PackStart (Widget widget, Blocking blocking)
+        {
+            PackStart (widget, duration, easing, blocking);
+        }
+        
+        public void PackStart (Widget widget, uint duration, Blocking blocking)
+        {
+            PackStart (widget, duration, easing, blocking);
+        }
+        
+        public void PackStart (Widget widget, Easing easing, Blocking blocking)
+        {
+            PackStart (widget, duration, easing, blocking);
+        }
+        
+        public void PackStart (Widget widget, uint duration, Easing easing, Blocking blocking)
+        {
+            AnimatedWidget animatedWidget = Pack (widget, duration, easing, blocking);
+            lock (childrenMutex) {
+                animatedWidget.Node = children.AddFirst (animatedWidget);
+            }
+        }
+        
+        public void PackEnd (Widget widget)
+        {
+            PackEnd (widget, duration, easing, blocking);
+        }
+        
+        public void PackEnd (Widget widget, uint duration)
+        {
+            PackEnd (widget, duration, easing, blocking);
+        }
+        
+        public void PackEnd (Widget widget, Easing easing)
+        {
+            PackEnd (widget, duration, easing, blocking);
+        }
+        
+        public void PackEnd (Widget widget, uint duration, Easing easing)
+        {
+            PackEnd (widget, duration, easing, blocking);
+        }
+        
+        public void PackEnd (Widget widget, Blocking blocking)
+        {
+            PackEnd (widget, duration, easing, blocking);
+        }
+        
+        public void PackEnd (Widget widget, uint duration, Blocking blocking)
+        {
+            PackEnd (widget, duration, easing, blocking);
+        }
+        
+        public void PackEnd (Widget widget, Easing easing, Blocking blocking)
+        {
+            PackEnd (widget, duration, easing, blocking);
+        }
+        
+        public void PackEnd (Widget widget, uint duration, Easing easing, Blocking blocking)
+        {
+            AnimatedWidget animatedWidget = Pack (widget, duration, easing, blocking);
+            lock (childrenMutex) {
+                animatedWidget.Node = children.AddLast (animatedWidget);
+            }
+        }
+        
+        private AnimatedWidget Pack (Widget widget, uint duration, Easing easing, Blocking blocking)
+        {
+            if (widget == null) {
+                throw new ArgumentNullException ("widget");
+            }
+            
+            AnimatedWidget animatedWidget = new AnimatedWidget (widget, duration, easing, blocking);
+            animatedWidget.Parent = this;
+            animatedWidget.WidgetDestroyed += OnWidgetDestroyed;
+            stage.Add (animatedWidget, duration);
+            return animatedWidget;
+        }
+        
+#endregion
+        
+#region Remove Methods
+        
+        public new void Remove (Widget widget)
+        {
+            RemoveCore (widget, null, null, null);
+        }
+        
+        public void Remove (Widget widget, uint duration)
+        {
+            RemoveCore (widget, duration, null, null);
+        }
+        
+        public void Remove (Widget widget, Easing easing)
+        {
+            RemoveCore (widget, null, easing, null);
+        }
+        
+        public void Remove (Widget widget, uint duration, Easing easing)
+        {
+            RemoveCore (widget, duration, easing, null);
+        }
+        
+        public void Remove (Widget widget, Blocking blocking)
+        {
+            RemoveCore (widget, null, null, blocking);
+        }
+        
+        public void Remove (Widget widget, uint duration, Blocking blocking)
+        {
+            RemoveCore (widget, duration, null, blocking);
+        }
+        
+        public void Remove (Widget widget, Easing easing, Blocking blocking)
+        {
+            RemoveCore (widget, null, easing, blocking);
+        }
+        
+        public void Remove (Widget widget, uint duration, Easing easing, Blocking blocking)
+        {
+            RemoveCore (widget, duration, easing, blocking);
+        }
+        
+        private void RemoveCore (Widget widget, uint? duration, Easing? easing, Blocking? blocking)
+        {
+            if (widget == null) {
+                throw new ArgumentNullException ("widget");
+            }
+            
+            AnimatedWidget animatedWidget = null;
+            foreach (AnimatedWidget child in this) {
+                if (child.Widget == widget) {
+                    animatedWidget = child;
+                    break;
+                }
+            }
+            if (animatedWidget == null) {
+                throw new ArgumentException ("Cannot remove the specified widget because it has not been added to this container or it has already been removed.", "widget");
+            }
+            RemoveCore (animatedWidget, duration, easing, blocking);
+        }
+        
+        private void RemoveCore (AnimatedWidget widget)
+        {
+            RemoveCore (widget, widget.Duration, widget.Easing, widget.Blocking);
+        }
+        
+        private void RemoveCore (AnimatedWidget widget, uint? duration, Easing? easing, Blocking? blocking)
+        {
+            lock (widget) {
+                if (duration != null) {
+                    widget.Duration = duration.Value;
+                }
+                if (easing != null) {
+                    widget.Easing = easing.Value;
+                }
+                if (blocking != null) {
+                    widget.Blocking = blocking.Value;
+                }
+            
+                if (widget.AnimationState == AnimationState.Coming) {
+                    widget.AnimationState = AnimationState.IntendingToGo;
+                } else {
+                    if (widget.Easing == Easing.QuadraticIn) {
+                        widget.Easing = Easing.QuadraticOut;
+                    } else if (widget.Easing == Easing.QuadraticOut) {
+                        widget.Easing = Easing.QuadraticIn;
+                    } else if (widget.Easing == Easing.ExponentialIn) {
+                        widget.Easing = Easing.ExponentialOut;
+                    } else if (widget.Easing == Easing.ExponentialOut) {
+                        widget.Easing = Easing.ExponentialIn;
+                    }
+                    widget.AnimationState = AnimationState.Going;
+                    stage.Add (widget, widget.Duration);
+                }
+            }
+        }
+        
+#endregion
+        
+#region Other Public Methods
+        
+        public bool Contains (Widget widget)
+        {
+            foreach (AnimatedWidget child in this) {
+                if (child.AnimationState != AnimationState.Going && child.Widget == widget) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        
+        public new IEnumerator<Widget> GetEnumerator ()
+        {
+            lock (childrenMutex) {
+                foreach (AnimatedWidget child in children) {
+                    yield return child;
+                }
+            }
+        }
+        
+        IEnumerator System.Collections.IEnumerable.GetEnumerator ()
+        {
+            return GetEnumerator ();
+        }
+        
+#endregion
+        
+#region Overrides
+        
+        protected override void OnAdded (Widget widget)
+        {
+            PackStart (widget, duration, easing, blocking);
+        }
+        
+        protected override void OnRealized ()
+        {
+            WidgetFlags |= WidgetFlags.Realized | WidgetFlags.NoWindow;
+            GdkWindow = Parent.GdkWindow;
+        }
+        
+        protected override void ForAll (bool include_internals, Callback callback)
+        {
+            foreach (AnimatedWidget child in this) {
+                callback (child);
+            }
+        }
+        
+#endregion
+        
+#region Properties
+        
+        public int Spacing {
+            get { return spacing; }
+            set {
+                if (value < 0) {
+                    throw new ArgumentOutOfRangeException ("value", "Spacing cannot be less than 0.");
+                }
+                spacing = value;
+                double half = (double)spacing / 2.0;
+                startSpacing = (int)Math.Floor (half);
+                endSpacing = (int)Math.Ceiling (half);
+            }
+        }
+        
+        public uint Duration {
+            get { return duration; }
+            set { duration = value; }
+        }
+        
+        public Easing Easing {
+            get { return easing; }
+            set { easing = value; }
+        }
+        
+        public Blocking Blocking {
+            get { return blocking; }
+            set { blocking = value; }
+        }
+        
+#endregion
+        
+    }
+}
\ No newline at end of file

Added: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedHBox.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedHBox.cs	Sun Mar 16 21:15:54 2008
@@ -0,0 +1,68 @@
+//
+// AnimatedHBox.cs
+//
+// Authors:
+//   Scott Peterson <lunchtimemama gmail com>
+//
+// Copyright (C) 2008 Scott Peterson
+//
+// 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 Gdk;
+using Gtk;
+
+namespace Hyena.Gui
+{
+    public class AnimatedHBox : AnimatedBox
+    {
+        protected override void OnSizeRequested (ref Requisition requisition)
+        {
+            int width = 0;
+            int height = 0;
+            foreach (AnimatedWidget widget in this) {
+                Requisition req = widget.SizeRequest ();
+                widget.Size = req.Width + spacing;
+                width += widget.Value;
+                if (req.Height > height) {
+                    height = req.Height;
+                }
+            }
+            requisition.Width = width;
+            requisition.Height = height;
+        }
+        
+        protected override void OnSizeAllocated (Rectangle allocation)
+        {
+            base.OnSizeAllocated (allocation);
+            foreach (AnimatedWidget widget in this) {
+                allocation.Width = widget.Value;
+                widget.Alloc.X = startSpacing;
+                if (widget.Blocking == Blocking.Downstage) {
+                    widget.Alloc.X += widget.Value - widget.Size;
+                }
+                widget.Alloc.Height = allocation.Height;
+                widget.SizeAllocate (allocation);
+                allocation.X += allocation.Width;
+            }
+        }
+    }
+}

Added: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedVBox.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedVBox.cs	Sun Mar 16 21:15:54 2008
@@ -0,0 +1,85 @@
+//
+// AnimatedVBox.cs
+//
+// Authors:
+//   Scott Peterson <lunchtimemama gmail com>
+//
+// Copyright (C) 2008 Scott Peterson
+//
+// 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 Gdk;
+using Gtk;
+
+namespace Hyena.Gui
+{
+    public class AnimatedVBox : AnimatedBox
+    {
+        protected override void OnSizeRequested (ref Requisition requisition)
+        {
+            int width = 0;
+            int height = 0;
+            int rolloverSpacing = 0;
+            foreach (AnimatedWidget widget in this) {
+                Requisition req = widget.SizeRequest ();
+                widget.Size = req.Height + rolloverSpacing;
+                widget.Alloc.Y = rolloverSpacing;
+                if (widget.IsFirst) {
+                    if (widget.Next != null) {
+                        if (widget.AnimationState != AnimationState.Idle) {
+                            widget.Size += spacing;
+                        } else {
+                            widget.Size += endSpacing;
+                            rolloverSpacing = startSpacing;
+                        }
+                    }
+                } else if (widget.Next != null && widget.Next.IsLast && widget.Next.AnimationState != AnimationState.Idle) {
+                    rolloverSpacing = spacing;
+                } else if (!widget.IsLast) {
+                    widget.Size += endSpacing;
+                    rolloverSpacing = startSpacing;
+                }
+                
+                height += widget.Value;
+                if (req.Width > width) {
+                    width = req.Width;
+                }
+            }
+            requisition.Width = width;
+            requisition.Height = height;
+        }
+        
+        protected override void OnSizeAllocated (Rectangle allocation)
+        {
+            base.OnSizeAllocated (allocation);
+            foreach (AnimatedWidget widget in this) {
+                allocation.Height = widget.Value;
+                if (widget.Blocking == Blocking.Downstage) {
+                    widget.Alloc.Y += widget.Value - widget.Size;
+                }
+                widget.Alloc.Width = allocation.Width;
+                widget.SizeAllocate (allocation);
+                allocation.Y += allocation.Height;
+            }
+        }
+    }
+}
\ No newline at end of file

Added: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedWidget.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/AnimatedWidget.cs	Sun Mar 16 21:15:54 2008
@@ -0,0 +1,209 @@
+//
+// AnimatedVboxActor.cs
+//
+// Authors:
+//   Scott Peterson <lunchtimemama gmail com>
+//
+// Copyright (C) 2008 Scott Peterson
+//
+// 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.Collections.Generic;
+using Gdk;
+using Gtk;
+
+namespace Hyena.Gui
+{
+    internal enum AnimationState
+    {
+        Coming,
+        Idle,
+        IntendingToGo,
+        Going
+    }
+    
+    internal sealed class AnimatedWidget : Container
+    {
+        public event EventHandler WidgetDestroyed;
+        
+        public Widget Widget;
+        public Rectangle Alloc;
+        public Easing Easing;
+        public Blocking Blocking;
+        public AnimationState AnimationState;
+        public uint Duration;
+        public double Bias = 1.0;
+        public LinkedListNode <AnimatedWidget> Node;
+        
+        private double percent;
+        private int size;
+        private int? value;
+        private Pixmap canvas;
+        
+        public AnimatedWidget (Widget widget, uint duration, Easing easing, Blocking blocking)
+        {
+            Widget = widget;
+            Duration = duration;
+            Easing = easing;
+            Blocking = blocking;
+            AnimationState = AnimationState.Coming;
+
+            Widget.Parent = this;
+            Widget.Destroyed += OnWidgetDestroyed;
+            ShowAll ();
+        }
+        
+        protected AnimatedWidget (IntPtr raw) : base (raw)
+        {
+        }
+        
+        private void OnWidgetDestroyed (object sender, EventArgs args)
+        {
+            if (!IsRealized) {
+                return;
+            }
+            
+            canvas = new Pixmap (GdkWindow, Alloc.Width, Alloc.Height);
+            canvas.DrawDrawable (Style.BackgroundGC (State), GdkWindow,
+                Alloc.X, Alloc.Y, 0, 0, Alloc.Width, Alloc.Height);
+            
+            if (AnimationState != AnimationState.Going) {
+                WidgetDestroyed (this, args);
+            }
+        }
+        
+#region Overrides
+        
+        protected override void OnRemoved (Widget widget)
+        {
+            if (widget == Widget) {
+                widget.Unparent ();
+                Widget = null;
+            }
+        }
+        
+        protected override void OnRealized ()
+        {
+            WidgetFlags |= WidgetFlags.Realized;
+            
+            Gdk.WindowAttr attributes = new Gdk.WindowAttr ();
+            attributes.WindowType = Gdk.WindowType.Child;
+            attributes.X = Allocation.X;
+            attributes.Y = Allocation.Y;
+            attributes.Width = Allocation.Width;
+            attributes.Height = Allocation.Height;
+            attributes.Wclass = Gdk.WindowClass.InputOutput;
+            attributes.EventMask = (int)Gdk.EventMask.ExposureMask;
+            
+            Gdk.WindowAttributesType attributes_mask = 
+                Gdk.WindowAttributesType.X | 
+                Gdk.WindowAttributesType.Y;
+                
+            GdkWindow = new Gdk.Window (Parent.GdkWindow, attributes, attributes_mask);
+            Style.Attach (GdkWindow);
+            GdkWindow.UserData = Handle;
+            GdkWindow.Background = Style.Background (State);
+        }
+        
+        protected override void OnSizeRequested (ref Requisition requisition)
+        {
+            if (Widget != null) {
+                Requisition req = Widget.SizeRequest ();
+                Alloc.Width = req.Width;
+                Alloc.Height = req.Height;
+            }
+            requisition.Width = Alloc.Width;
+            requisition.Height = Alloc.Height;
+        }
+        
+        protected override void OnSizeAllocated (Rectangle allocation)
+        {
+            if (Widget != null) {
+                Widget.SizeAllocate (Alloc);
+            }
+            base.OnSizeAllocated (allocation);
+        }
+
+        
+        protected override bool OnExposeEvent (EventExpose evnt)
+        {
+            if (canvas != null) {
+                GdkWindow.DrawDrawable (Style.BackgroundGC (State), canvas,
+                    0, 0, Alloc.X, Alloc.Y, Alloc.Width, Alloc.Height);
+                return true;
+            } else {
+                return base.OnExposeEvent (evnt);
+            }
+        }
+
+        protected override void ForAll (bool include_internals, Callback callback)
+        {
+            if (Widget != null) {
+                callback (Widget);
+            }
+        }
+        
+#endregion
+        
+#region Properties
+        
+        public int Size {
+            get { return size; }
+            set {
+                size = value;
+                this.value = null;
+            }
+        }
+        
+        public double Percent {
+            get { return percent; }
+            set {
+                percent = value * Bias;
+                this.value = null;
+            }
+        }
+        
+        public int Value {
+            get {
+                if (this.value == null) {
+                    this.value = Choreographer.Compose (percent, size, Easing);
+                }
+                return this.value.Value;
+            }
+        }
+        
+        public bool IsFirst {
+            get { return Node.Previous == null; }
+        }
+        
+        public bool IsLast {
+            get { return Node.Next == null; }
+        }
+        
+        public AnimatedWidget Next {
+            get { return Node.Next == null ? null : Node.Next.Value; }
+        }
+        
+#endregion
+        
+    }
+}
\ No newline at end of file

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Makefile.am
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Makefile.am	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Makefile.am	Sun Mar 16 21:15:54 2008
@@ -22,6 +22,7 @@
 	Hyena.Gui.Dialogs/ExceptionDialog.cs \
 	Hyena.Gui.Dialogs/VersionInformationDialog.cs \
 	Hyena.Gui.Theatrics/Actor.cs \
+	Hyena.Gui.Theatrics/Choreographer.cs \
 	Hyena.Gui.Theatrics/SingleActorStage.cs \
 	Hyena.Gui.Theatrics/Stage.cs \
 	Hyena.Gui.Theming/GtkColors.cs \
@@ -44,7 +45,11 @@
 	Hyena.Query.Gui/QueryTermsBox.cs \
 	Hyena.Query.Gui/QueryValueEntry.cs \
 	Hyena.Query.Gui/StringQueryValueEntry.cs \
+	Hyena.Widgets/AnimatedBox.cs \
+	Hyena.Widgets/AnimatedHBox.cs \
 	Hyena.Widgets/AnimatedImage.cs \
+	Hyena.Widgets/AnimatedVBox.cs \
+	Hyena.Widgets/AnimatedWidget.cs \
 	Hyena.Widgets/MessageBar.cs \
 	Hyena.Widgets/RoundedFrame.cs \
 	Hyena.Widgets/ScrolledWindow.cs



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