[gnome-shell] [panel] Scale up, center and fade application icon in app menu



commit c17e1249d5a00cd52ceaf903179571e8480e59f3
Author: Colin Walters <walters verbum org>
Date:   Sat Dec 26 12:00:36 2009 -0500

    [panel] Scale up, center and fade application icon in app menu
    
    Per 20091114 design.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=605491

 data/theme/gnome-shell.css |    4 +
 js/ui/panel.js             |  135 +++++++++++++++++++++++++++++++++++++++----
 src/shell-drawing.c        |   65 +++++++++++++++++++++
 src/shell-drawing.h        |    2 +
 4 files changed, 193 insertions(+), 13 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index ce2d109..b8c3881 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -26,6 +26,10 @@
     color: #0000e0;
 }
 
+.label-shadow {
+    color: rgba(0,0,0,0.5);
+}
+
 StScrollBar
 {
   padding: 0px;
diff --git a/js/ui/panel.js b/js/ui/panel.js
index a07075d..510a328 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -13,6 +13,7 @@ const Signals = imports.signals;
 const Gettext = imports.gettext.domain('gnome-shell');
 const _ = Gettext.gettext;
 
+const AppDisplay = imports.ui.appDisplay;
 const Calendar = imports.ui.calendar;
 const Main = imports.ui.main;
 const StatusMenu = imports.ui.statusMenu;
@@ -46,6 +47,99 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
     'gnome-power-manager': 'battery'
 };
 
+function TextShadower() {
+    this._init();
+}
+
+TextShadower.prototype = {
+    _init: function() {
+        this.actor = new Shell.GenericContainer();
+        this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
+        this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
+        this.actor.connect('allocate', Lang.bind(this, this._allocate));
+
+        this._label = new St.Label();
+        this.actor.add_actor(this._label);
+        for (let i = 0; i < 4; i++) {
+            let actor = new St.Label({ style_class: 'label-shadow' });
+            this.actor.add_actor(actor);
+        }
+        this._label.raise_top();
+    },
+
+    setText: function(text) {
+        let children = this.actor.get_children();
+        for (let i = 0; i < children.length; i++)
+            children[i].set_text(text);
+    },
+
+    _getPreferredWidth: function(actor, forHeight, alloc) {
+        let [minWidth, natWidth] = this._label.get_preferred_width(forHeight);
+        alloc.min_size = minWidth;
+        alloc.natural_size = natWidth;
+    },
+
+    _getPreferredHeight: function(actor, forWidth, alloc) {
+        let [minHeight, natHeight] = this._label.get_preferred_height(forWidth);
+        alloc.min_size = minHeight;
+        alloc.natural_size = natHeight;
+    },
+
+    _allocate: function(actor, box, flags) {
+        let children = this.actor.get_children();
+
+        let availWidth = box.x2 - box.x1;
+        let availHeight = box.y2 - box.y1;
+
+        let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] =
+            this._label.get_preferred_size();
+
+        let childWidth = Math.min(natChildWidth, availWidth);
+        let childHeight = Math.min(natChildHeight, availHeight);
+
+        for (let i = 0; i < children.length; i++) {
+            let child = children[i];
+            let childBox = new Clutter.ActorBox();
+            // The order of the labels here is arbitrary, except
+            // we know the "real" label is at the end because Clutter.Group
+            // sorts by Z order
+            switch (i) {
+                case 0: // top
+                    childBox.x1 = 1;
+                    childBox.y1 = 0;
+                    break;
+                case 1: // right
+                    childBox.x1 = 2;
+                    childBox.y1 = 1;
+                    break;
+                case 2: // bottom
+                    childBox.x1 = 1;
+                    childBox.y1 = 2;
+                    break;
+                case 3: // left
+                    childBox.x1 = 0;
+                    childBox.y1 = 1;
+                    break;
+                case 4: // center
+                    childBox.x1 = 1;
+                    childBox.y1 = 1;
+                    break;
+            }
+            childBox.x2 = childBox.x1 + childWidth;
+            childBox.y2 = childBox.y1 + childHeight;
+            child.allocate(childBox, flags);
+        }
+    }
+}
+
+/**
+ * AppPanelMenu:
+ *
+ * This class manages the "application menu" component.  It tracks the
+ * currently focused application.  However, when an app is launched,
+ * this menu also handles startup notification for it.  So when we
+ * have an active startup notification, we switch modes to display that.
+ */
 function AppPanelMenu() {
     this._init();
 }
@@ -59,10 +153,11 @@ AppPanelMenu.prototype = {
         this._startupSequences = {};
 
         this.actor = new St.BoxLayout({ name: 'appMenu' });
-        this._iconBox = new St.Bin({ name: 'appMenuIcon' });
+        this._iconBox = new Shell.Slicer({ name: 'appMenuIcon' });
         this.actor.add(this._iconBox);
-        this._label = new St.Label();
-        this.actor.add(this._label, { expand: true, y_fill: false });
+        this._label = new TextShadower();
+        this.actor.add(this._label.actor, { expand: true, y_fill: true });
+        this.actor.connect('notify::allocation', Lang.bind(this, this._repositionLabel));
 
         this._startupBox = new St.BoxLayout();
         this.actor.add(this._startupBox);
@@ -86,6 +181,16 @@ AppPanelMenu.prototype = {
         this._sync();
     },
 
+    _repositionLabel: function() {
+        this._label.actor.x = Math.floor(AppDisplay.APPICON_SIZE / 2);
+        let actorAlloc = this.actor.allocation;
+        let actorHeight = actorAlloc.y2 - actorAlloc.y1;
+        let labelAlloc = this._label.actor.allocation;
+        let labelHeight = labelAlloc.y2 - labelAlloc.y1;
+        this._label.actor.y = Math.floor((actorHeight - labelHeight) / 2);
+        this._label.actor.fixed_position_set = true;
+    },
+
     _sync: function() {
         let tracker = Shell.WindowTracker.get_default();
 
@@ -112,20 +217,24 @@ AppPanelMenu.prototype = {
         if (this._iconBox.child != null)
             this._iconBox.child.destroy();
         this._iconBox.hide();
-        this._label.set_text('');
+        this._label.setText('');
+        let icon;
         if (this._focusedApp != null) {
-            let icon = this._focusedApp.create_icon_texture(PANEL_ICON_SIZE);
-            this._iconBox.set_child(icon);
-            this._iconBox.show();
-            let appName = this._focusedApp.get_name();
-            // Use _set_text to work around http://bugzilla.openedhand.com/show_bug.cgi?id=1851
-            this._label.set_text(appName);
+            icon = this._focusedApp.create_icon_texture(AppDisplay.APPICON_SIZE);
+            this._label.setText(this._focusedApp.get_name());
         } else if (this._activeSequence != null) {
-            let icon = this._activeSequence.create_icon(PANEL_ICON_SIZE);
-            this._iconBox.set_child(icon);
+            icon = this._activeSequence.create_icon(AppDisplay.APPICON_SIZE);
+            this._label.setText(this._activeSequence.get_name());
+        } else {
+            icon = null;
+        }
+        
+        if (icon != null) {
+            let faded = Shell.fade_app_icon(icon); /* TODO consider caching */
+            this._iconBox.set_child(faded);
             this._iconBox.show();
-            this._label.set_text(this._activeSequence.get_name());
         }
+        this._repositionLabel();
 
         this.emit('changed');
     }
diff --git a/src/shell-drawing.c b/src/shell-drawing.c
index 21f7129..a4c8930 100644
--- a/src/shell-drawing.c
+++ b/src/shell-drawing.c
@@ -52,6 +52,71 @@ shell_draw_clock (ClutterCairoTexture *texture,
   cairo_destroy (cr);
 }
 
+/**
+ * shell_fade_app_icon:
+ * @source: Source #ClutterTexture
+ *
+ * Create a new texture by modifying the alpha channel of the
+ * source texture, adding a horizontal gradient fade.
+ *
+ * Returns: (transfer none): A new #ClutterTexture
+ */
+ClutterTexture *
+shell_fade_app_icon (ClutterTexture *source)
+{
+  CoglHandle  texture;
+  guchar     *pixels;
+  gint        width, height, rowstride;
+  gint        fade_start;
+  gint        fade_range;
+  guint       i, j;
+  ClutterTexture *result;
+
+  texture = clutter_texture_get_cogl_texture (source);
+  if (texture == COGL_INVALID_HANDLE)
+    return NULL;
+
+  width  = cogl_texture_get_width  (texture);
+  height = cogl_texture_get_height (texture);
+  rowstride = (width * 4 + 3) & ~3;
+
+  pixels = g_malloc0 (rowstride * height);
+
+  cogl_texture_get_data (texture, COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+                         rowstride, pixels);
+  cogl_texture_unref (texture);
+  
+  fade_start = width / 2;
+  fade_range = width - fade_start;
+  for (i = fade_start; i < width; i++)
+    {
+      for (j = 0; j < height; j++)
+        {
+          guchar *pixel = &pixels[j * rowstride + i * 4];
+          float fade = 1.0 - ((float) i - fade_start) / fade_range;
+          pixel[0] = 0.5 + pixel[0] * fade;
+          pixel[1] = 0.5 + pixel[1] * fade;
+          pixel[2] = 0.5 + pixel[2] * fade;
+          pixel[3] = 0.5 + pixel[3] * fade;
+        }   
+    }
+
+  texture = cogl_texture_new_from_data (width,
+                                        height,
+                                        COGL_TEXTURE_NONE,
+                                        COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+                                        COGL_PIXEL_FORMAT_ANY,
+                                        rowstride,
+                                        pixels);
+  g_free (pixels);
+    
+  result = (ClutterTexture*)clutter_texture_new ();
+  clutter_texture_set_cogl_texture (result, texture);
+  cogl_texture_unref (texture);
+  
+  return result;
+}
+
 void
 shell_draw_box_pointer (ClutterCairoTexture   *texture,
                         ShellPointerDirection  direction,
diff --git a/src/shell-drawing.h b/src/shell-drawing.h
index 4b48d11..f60adf4 100644
--- a/src/shell-drawing.h
+++ b/src/shell-drawing.h
@@ -23,6 +23,8 @@ void shell_draw_clock (ClutterCairoTexture *texture,
 	               int                  hour,
 	               int                  minute);
 
+ClutterTexture * shell_fade_app_icon (ClutterTexture *source);
+
 guint shell_add_hook_paint_red_border (ClutterActor *actor);
 
 G_END_DECLS



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