[gnome-shell/wip/fmuellner/notification-redux: 35/93] messageTray: Update notification banner



commit 3f7ff4e23cc9b7c2f8a1961a4310f533838aebf8
Author: Florian Müllner <fmuellner gnome org>
Date:   Wed Feb 11 20:20:03 2015 +0100

    messageTray: Update notification banner

 js/ui/messageTray.js |  275 +++++++-------------------------------------------
 1 files changed, 35 insertions(+), 240 deletions(-)
---
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
index 8a58963..b33b161 100644
--- a/js/ui/messageTray.js
+++ b/js/ui/messageTray.js
@@ -486,8 +486,6 @@ const Notification = new Lang.Class({
         this.bannerBodyText = null;
         this.bannerBodyMarkup = false;
         this._bannerBodyAdded = false;
-        this._titleFitsInBannerMode = true;
-        this._spacing = 0;
         this._scrollPolicy = Gtk.PolicyType.AUTOMATIC;
         this._soundName = null;
         this._soundFile = null;
@@ -499,40 +497,23 @@ const Notification = new Lang.Class({
         this.actor.connect('clicked', Lang.bind(this, this._onClicked));
         this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 
-        this._table = new St.Table({ style_class: 'notification',
-                                     reactive: true });
-        this._table.connect('style-changed', Lang.bind(this, this._styleChanged));
-        this.actor.set_child(this._table);
-
-        // The first line should have the title, followed by the
-        // banner text, but ellipsized if they won't both fit. We can't
-        // make St.Table or St.BoxLayout do this the way we want (don't
-        // show banner at all if title needs to be ellipsized), so we
-        // use Shell.GenericContainer.
-        this._bannerBox = new Shell.GenericContainer();
-        this._bannerBox.connect('get-preferred-width', Lang.bind(this, this._bannerBoxGetPreferredWidth));
-        this._bannerBox.connect('get-preferred-height', Lang.bind(this, this._bannerBoxGetPreferredHeight));
-        this._bannerBox.connect('allocate', Lang.bind(this, this._bannerBoxAllocate));
-        this._table.add(this._bannerBox, { row: 0,
-                                           col: 1,
-                                           col_span: 2,
-                                           x_expand: false,
-                                           y_expand: false,
-                                           y_fill: false });
-
-        // This is an empty cell that overlaps with this._bannerBox cell to ensure
-        // that this._bannerBox cell expands horizontally, while not forcing the
-        // this._imageBin that is also in col: 2 to expand horizontally.
-        this._table.add(new St.Bin(), { row: 0,
-                                        col: 2,
-                                        y_expand: false,
-                                        y_fill: false });
-
-        this._titleLabel = new St.Label();
-        this._bannerBox.add_actor(this._titleLabel);
-        this._bannerUrlHighlighter = new URLHighlighter();
-        this._bannerLabel = this._bannerUrlHighlighter.actor;
-        this._bannerBox.add_actor(this._bannerLabel);
+        let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
+        this._grid = new St.Widget({ style_class: 'notification', layout_manager: layout });
+        layout.hookup_style(this._grid);
+
+        this.actor.set_child(this._grid);
+
+        this._titleLabel = new St.Label({ x_expand: true });
+        layout.attach(this._titleLabel, 1, 0, 1, 1);
+        let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic',
+                                      icon_size: 16 });
+        this._closeButton = new St.Button({ child: closeIcon });
+        layout.attach(this._closeButton, 3, 0, 1, 1);
+
+        this._closeButton.connect('clicked', Lang.bind(this,
+            function() {
+                this.destroy(NotificationDestroyedReason.DISMISSED);
+            }));
 
         // If called with only one argument we assume the caller
         // will call .update() later on. This is the case of
@@ -593,7 +574,7 @@ const Notification = new Lang.Class({
             this._buttonBox = null;
         }
         if (!this._scrollArea && !this._actionArea)
-            this._table.remove_style_class_name('multi-line-notification');
+            this._grid.remove_style_class_name('multi-line-notification');
 
         if (params.gicon) {
             this._icon = new St.Icon({ gicon: params.gicon,
@@ -602,19 +583,16 @@ const Notification = new Lang.Class({
             this._icon = this.source.createIcon(this.ICON_SIZE);
         }
 
+        let layout = this._grid.layout_manager;
         if (this._icon) {
-            this._table.add(this._icon, { row: 0,
-                                          col: 0,
-                                          x_expand: false,
-                                          y_expand: false,
-                                          y_fill: false,
-                                          y_align: St.Align.START });
+            this._icon.set_y_align(Clutter.ActorAlign.START);
+            layout.attach(this._icon, 0, 0, 1, 1);
         }
 
         if (params.secondaryGIcon) {
             this._secondaryIcon = new St.Icon({ gicon: params.secondaryGIcon,
                                                 style_class: 'secondary-icon' });
-            this._bannerBox.add_actor(this._secondaryIcon);
+            layout.attach(this._secondaryGIcon, 2, 0, 1, 1);
         }
 
         this.title = title;
@@ -633,7 +611,7 @@ const Notification = new Lang.Class({
         // arguably for action buttons as well. Labels other than the title
         // will be allocated at the available width, so that their alignment
         // is done correctly automatically.
-        this._table.set_text_direction(titleDirection);
+        this._grid.set_text_direction(titleDirection);
 
         // Unless the notification has custom content, we save this.bannerBodyText
         // to add it to the content of the notification if the notification is
@@ -643,13 +621,8 @@ const Notification = new Lang.Class({
         this.bannerBodyMarkup = params.bannerMarkup;
         this._bannerBodyAdded = false;
 
-        banner = banner ? banner.replace(/\n/g, '  ') : '';
-
-        this._bannerUrlHighlighter.setMarkup(banner, params.bannerMarkup);
-        this._bannerLabel.queue_relayout();
-
         // Add the bannerBody now if we know for sure we'll need it
-        if (this.bannerBodyText && this.bannerBodyText.indexOf('\n') > -1)
+        if (this.bannerBodyText)
             this._addBannerBody();
 
         if (this._soundName != params.soundName ||
@@ -666,23 +639,14 @@ const Notification = new Lang.Class({
         this._icon.visible = visible;
     },
 
-    enableScrolling: function(enableScrolling) {
-        this._scrollPolicy = enableScrolling ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER;
-        if (this._scrollArea) {
-            this._scrollArea.vscrollbar_policy = this._scrollPolicy;
-            this._scrollArea.enable_mouse_scrolling = enableScrolling;
-        }
-    },
-
     _createScrollArea: function() {
-        this._table.add_style_class_name('multi-line-notification');
+        this._grid.add_style_class_name('multi-line-notification');
         this._scrollArea = new St.ScrollView({ style_class: 'notification-scrollview',
                                                vscrollbar_policy: this._scrollPolicy,
                                                hscrollbar_policy: Gtk.PolicyType.NEVER,
                                                visible: this.expanded });
-        this._table.add(this._scrollArea, { row: 1,
-                                            col: 2 });
-        this._updateLastColumnSettings();
+        let layout = this._grid.layout_manager;
+        layout.attach(this._scrollArea, 1, 1, 3, 1);
         this._contentArea = new St.BoxLayout({ style_class: 'notification-body',
                                                vertical: true });
         this._scrollArea.add_actor(this._contentArea);
@@ -740,11 +704,10 @@ const Notification = new Lang.Class({
 
     // setActionArea:
     // @actor: the actor
-    // @props: (option) St.Table child properties
     //
     // Puts @actor into the action area of the notification, replacing
     // the previous contents
-    setActionArea: function(actor, props) {
+    setActionArea: function(actor) {
         if (this._actionArea) {
             this._actionArea.destroy();
             this._actionArea = null;
@@ -756,35 +719,17 @@ const Notification = new Lang.Class({
         this._actionArea = actor;
         this._actionArea.visible = this.expanded;
 
-        if (!props)
-            props = {};
-        props.row = 2;
-        props.col = 2;
-
-        this._table.add_style_class_name('multi-line-notification');
-        this._table.add(this._actionArea, props);
-        this._updateLastColumnSettings();
+        let layout = this._grid.layout_manager;
+        this._grid.add_style_class_name('multi-line-notification');
+        layout.attach_next_to(this._actionArea, null,
+                              Clutter.GridPosition.BOTTOM, 4, 1);
         this.updated();
     },
 
-    _updateLastColumnSettings: function() {
-        if (this._scrollArea)
-            this._table.child_set(this._scrollArea, { col: 1,
-                                                      col_span: 2 });
-        if (this._actionArea)
-            this._table.child_set(this._actionArea, { col: 1,
-                                                      col_span: 2 });
-    },
-
     addButton: function(button, callback) {
         if (!this._buttonBox) {
-            let box = new St.BoxLayout({ style_class: 'notification-actions' });
-            this.setActionArea(box, { x_expand: false,
-                                      y_expand: false,
-                                      x_fill: false,
-                                      y_fill: false,
-                                      x_align: St.Align.END });
-            this._buttonBox = box;
+            this._buttonBox = new St.BoxLayout({ style_class: 'notification-actions' });
+            this.setActionArea(this._buttonBox);
             global.focus_manager.add_group(this._buttonBox);
         }
 
@@ -837,130 +782,8 @@ const Notification = new Lang.Class({
         this.forFeedback = forFeedback;
     },
 
-    _styleChanged: function() {
-        this._spacing = this._table.get_theme_node().get_length('spacing-columns');
-    },
-
-    _bannerBoxGetPreferredWidth: function(actor, forHeight, alloc) {
-        let [titleMin, titleNat] = this._titleLabel.get_preferred_width(forHeight);
-        let [bannerMin, bannerNat] = this._bannerLabel.get_preferred_width(forHeight);
-
-        if (this._secondaryIcon) {
-            let [secondaryIconMin, secondaryIconNat] = this._secondaryIcon.get_preferred_width(forHeight);
-
-            alloc.min_size = secondaryIconMin + this._spacing + titleMin;
-            alloc.natural_size = secondaryIconNat + this._spacing + titleNat + this._spacing + bannerNat;
-        } else {
-            alloc.min_size = titleMin;
-            alloc.natural_size = titleNat + this._spacing + bannerNat;
-        }
-    },
-
-    _bannerBoxGetPreferredHeight: function(actor, forWidth, alloc) {
-        [alloc.min_size, alloc.natural_size] =
-            this._titleLabel.get_preferred_height(forWidth);
-    },
-
-    _bannerBoxAllocate: function(actor, box, flags) {
-        let availWidth = box.x2 - box.x1;
-
-        let [titleMinW, titleNatW] = this._titleLabel.get_preferred_width(-1);
-        let [titleMinH, titleNatH] = this._titleLabel.get_preferred_height(availWidth);
-        let [bannerMinW, bannerNatW] = this._bannerLabel.get_preferred_width(availWidth);
-
-        let rtl = (this._table.text_direction == Clutter.TextDirection.RTL);
-        let x = rtl ? availWidth : 0;
-
-        if (this._secondaryIcon) {
-            let [iconMinW, iconNatW] = this._secondaryIcon.get_preferred_width(-1);
-            let [iconMinH, iconNatH] = this._secondaryIcon.get_preferred_height(availWidth);
-
-            let secondaryIconBox = new Clutter.ActorBox();
-            let secondaryIconBoxW = Math.min(iconNatW, availWidth);
-
-            // allocate secondary icon box
-            if (rtl) {
-                secondaryIconBox.x1 = x - secondaryIconBoxW;
-                secondaryIconBox.x2 = x;
-                x = x - (secondaryIconBoxW + this._spacing);
-            } else {
-                secondaryIconBox.x1 = x;
-                secondaryIconBox.x2 = x + secondaryIconBoxW;
-                x = x + secondaryIconBoxW + this._spacing;
-            }
-            secondaryIconBox.y1 = 0;
-            // Using titleNatH ensures that the secondary icon is centered vertically
-            secondaryIconBox.y2 = titleNatH;
-
-            availWidth = availWidth - (secondaryIconBoxW + this._spacing);
-            this._secondaryIcon.allocate(secondaryIconBox, flags);
-        }
-
-        let titleBox = new Clutter.ActorBox();
-        let titleBoxW = Math.min(titleNatW, availWidth);
-        if (rtl) {
-            titleBox.x1 = availWidth - titleBoxW;
-            titleBox.x2 = availWidth;
-        } else {
-            titleBox.x1 = x;
-            titleBox.x2 = titleBox.x1 + titleBoxW;
-        }
-        titleBox.y1 = 0;
-        titleBox.y2 = titleNatH;
-        this._titleLabel.allocate(titleBox, flags);
-        this._titleFitsInBannerMode = (titleNatW <= availWidth);
-
-        let bannerFits = true;
-        if (titleBoxW + this._spacing > availWidth) {
-            this._bannerLabel.opacity = 0;
-            bannerFits = false;
-        } else {
-            let bannerBox = new Clutter.ActorBox();
-
-            if (rtl) {
-                bannerBox.x1 = 0;
-                bannerBox.x2 = titleBox.x1 - this._spacing;
-
-                bannerFits = (bannerBox.x2 - bannerNatW >= 0);
-            } else {
-                bannerBox.x1 = titleBox.x2 + this._spacing;
-                bannerBox.x2 = availWidth;
-
-                bannerFits = (bannerBox.x1 + bannerNatW <= availWidth);
-            }
-            bannerBox.y1 = 0;
-            bannerBox.y2 = titleNatH;
-            this._bannerLabel.allocate(bannerBox, flags);
-
-            // Make _bannerLabel visible if the entire notification
-            // fits on one line, or if the notification is currently
-            // unexpanded and only showing one line anyway.
-            if (!this.expanded || (bannerFits && this._table.row_count == 1))
-                this._bannerLabel.opacity = 255;
-        }
-
-        // If the banner doesn't fully fit in the banner box, we possibly need to add the
-        // banner to the body. We can't do that from here though since that will force a
-        // relayout, so we add it to the main loop.
-        if (!bannerFits && this._canExpandContent())
-            Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
-                           Lang.bind(this,
-                                     function() {
-                                         if (this._destroyed)
-                                             return false;
-
-                                        if (this._canExpandContent()) {
-                                            this._addBannerBody();
-                                            this._table.add_style_class_name('multi-line-notification');
-                                            this.updated();
-                                        }
-                                        return false;
-                                     }));
-    },
-
     _canExpandContent: function() {
-        return (this.bannerBodyText && !this._bannerBodyAdded) ||
-               (!this._titleFitsInBannerMode && 
!this._table.has_style_class_name('multi-line-notification'));
+        return this.bannerBodyText && !this._bannerBodyAdded;
     },
 
     playSound: function() {
@@ -1010,30 +833,6 @@ const Notification = new Lang.Class({
         if (this._scrollArea)
             this._scrollArea.show();
 
-        // The banner is never shown when the title did not fit, so this
-        // can be an if-else statement.
-        if (!this._titleFitsInBannerMode) {
-            // Remove ellipsization from the title label and make it wrap so that
-            // we show the full title when the notification is expanded.
-            this._titleLabel.clutter_text.line_wrap = true;
-            this._titleLabel.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
-            this._titleLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
-        } else if (this._table.row_count > 1 && this._bannerLabel.opacity != 0) {
-            // We always hide the banner if the notification has additional content.
-            //
-            // We don't need to wrap the banner that doesn't fit the way we wrap the
-            // title that doesn't fit because we won't have a notification with
-            // row_count=1 that has a banner that doesn't fully fit. We'll either add
-            // that banner to the content of the notification in _bannerBoxAllocate()
-            // or the notification will have custom content.
-            if (animate)
-                Tweener.addTween(this._bannerLabel,
-                                 { opacity: 0,
-                                   time: ANIMATION_TIME,
-                                   transition: 'easeOutQuad' });
-            else
-                this._bannerLabel.opacity = 0;
-        }
         this.emit('expanded');
     },
 
@@ -1052,10 +851,6 @@ const Notification = new Lang.Class({
         this._titleLabel.clutter_text.line_wrap = false;
         this._titleLabel.clutter_text.ellipsize = Pango.EllipsizeMode.END;
 
-        // Restore banner opacity in case the notification is shown in the
-        // banner mode again on update.
-        this._bannerLabel.opacity = 255;
-
         // Restore height requisition
         this.actor.add_style_class_name('notification-unexpanded');
     },


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