[gnome-shell/wip/swarm: 20/30] appDisplay: Animate folder view items



commit ba5517d05f902fdcd3c6095e03c0149da0bb9506
Author: Carlos Soriano <carlos soriano89 gmail com>
Date:   Tue Jun 17 12:47:00 2014 +0200

    appDisplay: Animate folder view items

 js/ui/appDisplay.js |   23 +++++++++++++-
 js/ui/iconGrid.js   |   84 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+), 2 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 10965e3..3944e27 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -947,6 +947,10 @@ const FolderView = new Lang.Class({
     _keyFocusIn: function(actor) {
         Util.ensureActorVisibleInScrollView(this.actor, actor);
     },
+    
+    animate: function(animationType, animationDirection, params) {
+        this._grid.animate(animationType, animationDirection, params);
+    },
 
     createFolderIcon: function(size) {
         let layout = new Clutter.TableLayout();
@@ -1278,8 +1282,22 @@ const AppFolderPopup = new Lang.Class({
         this.actor.show();
 
         this._boxPointer.setArrowActor(this._source.actor);
+        // We need to hide the icons of the view until the boxpointer animation 
+        // is completed so we can animate the icons after as we like withouth
+        // showing them while boxpointer is animating.
+        this._view.actor.opacity = 0;
         this._boxPointer.show(BoxPointer.PopupAnimation.FADE |
-                              BoxPointer.PopupAnimation.SLIDE);
+                              BoxPointer.PopupAnimation.SLIDE,
+                              Lang.bind(this, 
+            function() {
+                // Restore the view opacity, so now we show the icons and animate
+                // them
+                this._view.actor.opacity = 255;
+                this._view.animate(IconGrid.ANIMATION_TYPE_APPEAR,
+                                   IconGrid.ANIMATION_DIRECTION_IN,
+                                   { sourcePosition: this._source.actor.get_transformed_position(),
+                                     sourceSize: this._source.actor.get_transformed_size() });
+            }));
 
         this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
 
@@ -1293,7 +1311,8 @@ const AppFolderPopup = new Lang.Class({
         this._grabHelper.ungrab({ actor: this.actor });
 
         this._boxPointer.hide(BoxPointer.PopupAnimation.FADE |
-                              BoxPointer.PopupAnimation.SLIDE);
+                              BoxPointer.PopupAnimation.SLIDE,
+                              this._view.animateOut);
         this._isOpen = false;
         this.emit('open-state-changed', false);
     },
diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js
index 9cf9f2f..e88c173 100644
--- a/js/ui/iconGrid.js
+++ b/js/ui/iconGrid.js
@@ -16,6 +16,15 @@ const MIN_ICON_SIZE = 16;
 
 const EXTRA_SPACE_ANIMATION_TIME = 0.25;
 
+const ANIMATION_TIME_IN = 0.400;
+const ANIMATION_MAX_DELAY_FOR_ITEM = 0.250;
+
+const ANIMATION_APPEAR_ICON_SCALE = 1.1;
+
+const ANIMATION_TYPE_APPEAR = 1;
+
+const ANIMATION_DIRECTION_IN = 1;
+
 const BaseIcon = new Lang.Class({
     Name: 'BaseIcon',
 
@@ -338,6 +347,81 @@ const IconGrid = new Lang.Class({
         }
     },
 
+    /**
+     * Intended to be override by subclasses if they need a diferent
+     * set of items to be animated.
+     */
+    animate: function(animationType, animationDirection, params) {
+        params = Params.parse(params, { sourcePosition: null,
+                                        sourceSize: null });
+
+        this._animateReal(this._getVisibleChildren(), animationType, animationDirection, params);
+    },
+
+    _animateReal: function(actors, animationType, animationDirection, params) {
+        if (this._animating || actors.length == 0)
+            return;
+        this._animating = true;
+
+        switch (animationType) {
+            case ANIMATION_TYPE_APPEAR:
+                this._animateAppear(actors, animationDirection);
+                break;
+            default:
+                break;
+        }
+    },
+
+    _animateAppear: function(actors, animationDirection) {
+        for (let index = 0; index < actors.length; index++) {
+            // FIXME? Seems that putting the items at opacity 0
+            // for animating seems like it doesn't belongs here.
+            // But works well.
+            actors[index].opacity = 0;
+            let delay = index / actors.length * ANIMATION_MAX_DELAY_FOR_ITEM;
+
+            let [originalX, originalY] = actors[index].get_transformed_position();
+            let [originalWidth, originalHeight] = actors[index].get_transformed_size();
+
+            let actorClone = new Clutter.Clone({ source: actors[index],
+                                                reactive: false });
+            Main.uiGroup.add_actor(actorClone);
+
+            actorClone.reactive = false;
+            actorClone.set_position(originalX, originalY);
+            actorClone.set_scale(0, 0);
+            actorClone.set_pivot_point(0.5, 0.5);
+            let [width, height] = actors[index].get_transformed_size();
+            actorClone.set_size(width, height);
+
+            // Defeat onComplete anonymous function closure
+            let actor= actors[index];
+            let isLastActor= index == actors.length - 1;
+            Tweener.addTween(actorClone,
+                            { time: ANIMATION_TIME_IN / 4,
+                              transition: 'easeInOutQuad',
+                              delay: delay,
+                              scale_x: ANIMATION_APPEAR_ICON_SCALE,
+                              scale_y: ANIMATION_APPEAR_ICON_SCALE,
+                              onComplete: Lang.bind(this, function() {
+                                  Tweener.addTween(actorClone,
+                                                   { time: ANIMATION_TIME_IN - ANIMATION_TIME_IN / 4,
+                                                     transition: 'easeInOutQuad',
+                                                     scale_x: 1,
+                                                     scale_y: 1,
+                                                     onComplete: Lang.bind(this, function() {
+                                                        if (isLastActor)
+                                                            this._animating = false;
+                                                        actor.opacity = 255;
+                                                        actorClone.destroy();
+                                                        this.emit('animation-done');
+                                                    })
+                                                   });
+                              })
+                            });
+        }
+    },
+
     _calculateChildBox: function(child, x, y, box) {
         let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight] =
              child.get_preferred_size();


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