[gnome-shell/wip/swarm: 16/22] appDisplay: Animate folder view items



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

    appDisplay: Animate folder view items
    
    Add a new animation  to folder view based on designers mockups that
    emulates pulsating icons.
    The code on iconGrid is though to work well for the upcoming patches to
    animate AllView and FrequentView.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=734726

 js/ui/appDisplay.js |   21 +++++++++-
 js/ui/iconGrid.js   |  103 +++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 115 insertions(+), 9 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 0bf435e..e1edf43 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -964,6 +964,10 @@ const FolderView = new Lang.Class({
         Util.ensureActorVisibleInScrollView(this.actor, actor);
     },
 
+    animate: function(animationType, animationDirection) {
+        this._grid.animate(animationType, animationDirection);
+    },
+
     createFolderIcon: function(size) {
         let layout = new Clutter.GridLayout();
         let icon = new St.Widget({ layout_manager: layout,
@@ -1339,8 +1343,20 @@ 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.AnimationType.PULSE,
+                                   IconGrid.AnimationDirection.IN);
+            }));
 
         this.emit('open-state-changed', true);
     },
@@ -1352,7 +1368,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 4c555ac..d37c663 100644
--- a/js/ui/iconGrid.js
+++ b/js/ui/iconGrid.js
@@ -10,12 +10,26 @@ const St = imports.gi.St;
 const Lang = imports.lang;
 const Params = imports.misc.params;
 const Tweener = imports.ui.tweener;
+const Main = imports.ui.main;
 
 const ICON_SIZE = 96;
 const MIN_ICON_SIZE = 16;
 
 const EXTRA_SPACE_ANIMATION_TIME = 0.25;
 
+const ANIMATION_TIME_IN = 0.350;
+const ANIMATION_MAX_DELAY_FOR_ITEM = 2/3 * ANIMATION_TIME_IN;
+
+const ANIMATION_BOUNCE_ICON_SCALE = 1.1;
+
+const AnimationType = {
+    PULSE: 0
+};
+
+const AnimationDirection = {
+    IN: 0
+};
+
 const BaseIcon = new Lang.Class({
     Name: 'BaseIcon',
 
@@ -338,15 +352,90 @@ const IconGrid = new Lang.Class({
         }
     },
 
-    _calculateChildBox: function(child, x, y, box) {
-        let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight] =
-             child.get_preferred_size();
+    /**
+     * Intended to be override by subclasses if they need a diferent
+     * set of items to be animated.
+     */
+    _getChildrenToAnimate: function() {
+        return this._getVisibleChildren();
+    },
+
+    animate: function(animationType, animationDirection) {
+        let actors = this._getChildrenToAnimate();
+        if (this._animating || actors.length == 0)
+            return;
+        this._animating = true;
+
+        for (let index = 0; index < actors.length; index++)
+            actors[index].opacity = 0;
 
+        switch (animationType) {
+            case AnimationType.PULSE:
+                this._animatePulse(actors, animationDirection);
+                break;
+            default:
+                log("animation doesn't exist. Icongrid won\'t work");
+        }
+    },
+
+    _animatePulse: function(actors, animationDirection) {
+        for (let index = 0; index < actors.length; index++) {
+            let delay = index / actors.length * ANIMATION_MAX_DELAY_FOR_ITEM;
+            let [originalX, originalY] = actors[index].get_transformed_position();
+            let [originalWidth, originalHeight,,] = this._getAllocatedChildSizeAndSpacing(actors[index]);
+
+            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);
+            actorClone.set_size(originalWidth, originalHeight);
+
+            // 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_BOUNCE_ICON_SCALE,
+                              scale_y: ANIMATION_BOUNCE_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;
+                                                            this.emit('animation-done');
+                                                        }
+                                                        actor.opacity = 255;
+                                                        actorClone.destroy();
+                                                    })
+                                                   });
+                              })
+                            });
+        }
+    },
+
+    _getAllocatedChildSizeAndSpacing: function(child) {
+        let [,, natWidth, natHeight] = child.get_preferred_size();
+        let width = Math.min(this._getHItemSize(), natWidth);
+        let xSpacing = Math.max(0, width - natWidth) / 2;
+        let height = Math.min(this._getVItemSize(), natHeight);
+        let ySpacing = Math.max(0, height - natHeight) / 2;
+        return [width, height, xSpacing, ySpacing];
+    },
+
+    _calculateChildBox: function(child, x, y, box) {
         /* Center the item in its allocation horizontally */
-        let width = Math.min(this._getHItemSize(), childNaturalWidth);
-        let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
-        let height = Math.min(this._getVItemSize(), childNaturalHeight);
-        let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
+        let [width, height, childXSpacing, childYSpacing] =
+            this._getAllocatedChildSizeAndSpacing(child);
 
         let childBox = new Clutter.ActorBox();
         if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {


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