[gnome-shell/user-status-update: 1/9] popup-menu: Add support for child menus



commit 37647636d00ed80e41fc59169d885b427d7ee156
Author: Florian MÃllner <fmuellner gnome org>
Date:   Tue Jul 12 21:47:37 2011 +0200

    popup-menu: Add support for child menus
    
    Allow opening a popup menu from another menu. While the child menu
    is open, events on the parent menu are blocked. The parent menu
    is kept open when the child menu is closed; the child menu on the
    other hand is closed with the parent, e.g. when the focus moves
    to another toplevel menu.
    This feature will be used to implement combo box menu items.

 js/ui/popupMenu.js |   68 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 67 insertions(+), 1 deletions(-)
---
diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
index 9e256b5..478fe49 100644
--- a/js/ui/popupMenu.js
+++ b/js/ui/popupMenu.js
@@ -800,6 +800,7 @@ PopupMenuBase.prototype = {
         this.passEvents = false;
 
         this._activeMenuItem = null;
+        this._childMenus = [];
     },
 
     addAction: function(title, callback) {
@@ -810,6 +811,28 @@ PopupMenuBase.prototype = {
         }));
     },
 
+    isChildMenu: function(menu) {
+        return this._childMenus.indexOf(menu) != -1;
+    },
+
+    addChildMenu: function(menu) {
+        if (this.isChildMenu(menu))
+            return;
+
+        this._childMenus.push(menu);
+        this.emit('child-menu-added', menu);
+    },
+
+    removeChildMenu: function(menu) {
+        let index = this._childMenus.indexOf(menu);
+
+        if (index == -1)
+            return;
+
+        this._childMenus.splice(index, 1);
+        this.emit('child-menu-removed', menu);
+    },
+
     /**
      * _connectSubMenuSignals:
      * @object: a menu item, or a menu section
@@ -1337,6 +1360,7 @@ PopupMenuManager.prototype = {
         this._keyFocusNotifyId = 0;
         this._activeMenu = null;
         this._menus = [];
+        this._menuStack = [];
         this._preGrabInputMode = null;
         this._grabbedFromKeynav = false;
     },
@@ -1345,6 +1369,8 @@ PopupMenuManager.prototype = {
         let menudata = {
             menu:              menu,
             openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
+            childMenuAddedId:  menu.connect('child-menu-added', Lang.bind(this, this._onChildMenuAdded)),
+            childMenuRemovedId: menu.connect('child-menu-removed', Lang.bind(this, this._onChildMenuRemoved)),
             destroyId:         menu.connect('destroy', Lang.bind(this, this._onMenuDestroy)),
             enterId:           0,
             focusInId:         0
@@ -1372,6 +1398,8 @@ PopupMenuManager.prototype = {
 
         let menudata = this._menus[position];
         menu.disconnect(menudata.openStateChangeId);
+        menu.disconnect(menudata.childMenuAddedId);
+        menu.disconnect(menudata.childMenuRemovedId);
         menu.disconnect(menudata.destroyId);
 
         if (menudata.enterId)
@@ -1409,8 +1437,20 @@ PopupMenuManager.prototype = {
     },
 
     _onMenuOpenState: function(menu, open) {
-        if (open)
+        if (open) {
+            if (this._activeMenu && this._activeMenu.isChildMenu(menu)) {
+                this._menuStack.push(this._activeMenu);
+                menu.actor.grab_key_focus();
+            }
             this._activeMenu = menu;
+        } else {
+            if (this._menuStack.length > 0) {
+                this._activeMenu = this._menuStack.pop();
+                if (menu.sourceActor)
+                    menu.sourceActor.grab_key_focus();
+                this._didPop = true;
+            }
+        }
 
         // Check what the focus was before calling pushModal/popModal
         let focus = global.stage.key_focus;
@@ -1443,6 +1483,14 @@ PopupMenuManager.prototype = {
         }
     },
 
+    _onChildMenuAdded: function(menu, childMenu) {
+        this.addMenu(childMenu);
+    },
+
+    _onChildMenuRemoved: function(menu, childMenu) {
+        this.removeMenu(childMenu);
+    },
+
     // change the currently-open menu without dropping grab
     _changeMenu: function(newMenu) {
         if (this._activeMenu) {
@@ -1451,6 +1499,8 @@ PopupMenuManager.prototype = {
             // before closing it to keep that from happening
             let oldMenu = this._activeMenu;
             this._activeMenu = null;
+            for (let i = this._menuStack.length - 1; i >= 0; i--)
+                this._menuStack[i].close(false);
             oldMenu.close(false);
             newMenu.open(false);
         } else
@@ -1461,6 +1511,15 @@ PopupMenuManager.prototype = {
         if (!this.grabbed || menu == this._activeMenu)
             return false;
 
+        if (this._activeMenu && this._activeMenu.isChildMenu(menu))
+            return false;
+
+        if (this._menuStack.indexOf(menu) != -1)
+            return false;
+
+        if (this._menuStack.length > 0 && this._menuStack[0].isChildMenu(menu))
+            return false;
+
         this._changeMenu(menu);
         return false;
     },
@@ -1473,6 +1532,8 @@ PopupMenuManager.prototype = {
         if (focus) {
             if (this._activeMenuContains(focus))
                 return;
+            if (this._menuStack.length > 0)
+                return;
             if (focus._delegate && focus._delegate.menu &&
                 this._findMenu(focus._delegate.menu) != -1)
                 return;
@@ -1531,6 +1592,11 @@ PopupMenuManager.prototype = {
         if (this._activeMenu != null && this._activeMenu.passEvents)
             return false;
 
+        if (this._didPop) {
+            this._didPop = false;
+            return true;
+        }
+
         let activeMenuContains = this._eventIsOnActiveMenu(event);
         let eventType = event.type();
 



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