[gnome-shell-extensions] apps-menu: Improve submenu navigation



commit 802c70e14cf4300fb0dccc7a76b1185dea972e13
Author: Debarshi Ray <debarshir gnome org>
Date:   Fri Feb 1 22:01:45 2013 +0100

    apps-menu: Improve submenu navigation
    
    Implement a keep-up triangle to keep submenus from changing if the
    pointer strays a bit when mousing towards the application list on the
    right. The keep-up triangle is only used if the mouse movement is more
    horizontal than vertical.
    
    This is similar to the behaviour of GtkMenu, but much more simple
    because we are only dealing one specific kind of menu, and hence don't
    need to be as generic.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=692913

 extensions/apps-menu/extension.js |   81 +++++++++++++++++++++++++++++++++++++
 1 files changed, 81 insertions(+), 0 deletions(-)
---
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index 0f4b95d..e88bbdc 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -25,7 +25,9 @@ const Convenience = Me.imports.convenience;
 const appSys = Shell.AppSystem.get_default();
 
 const APPLICATION_ICON_SIZE = 32;
+const HORIZ_FACTOR = 5;
 const MENU_HEIGHT_OFFSET = 132;
+const NAVIGATION_REGION_OVERSHOOT = 50;
 
 const ActivitiesMenuItem = new Lang.Class({
     Name: 'ActivitiesMenuItem',
@@ -88,6 +90,9 @@ const CategoryMenuItem = new Lang.Class({
        this._category = category;
         this._button = button;
 
+        this._oldX = -1;
+        this._oldY = -1;
+
         let name;
         if (this._category)
             name = this._category.get_name();
@@ -95,6 +100,7 @@ const CategoryMenuItem = new Lang.Class({
             name = _("Favorites");
 
         this.addActor(new St.Label({ text: name }));
+        this.actor.connect('motion-event', Lang.bind(this, this._onMotionEvent));
     },
 
     activate: function(event) {
@@ -103,6 +109,81 @@ const CategoryMenuItem = new Lang.Class({
        this.parent(event);
     },
 
+    _isNavigatingSubmenu: function([x, y]) {
+        let [posX, posY] = this.actor.get_transformed_position();
+
+        if (this._oldX == -1) {
+            this._oldX = x;
+            this._oldY = y;
+            return true;
+        }
+
+        let deltaX = Math.abs(x - this._oldX);
+        let deltaY = Math.abs(y - this._oldY);
+
+        this._oldX = x;
+        this._oldY = y;
+
+        // If it lies outside the x-coordinates then it is definitely outside.
+        if (posX > x || posX + this.actor.width < x)
+            return false;
+
+        // If it lies inside the menu item then it is definitely inside.
+        if (posY <= y && posY + this.actor.height >= y)
+            return true;
+
+        // We want the keep-up triangle only if the movement is more
+        // horizontal than vertical.
+        if (deltaX * HORIZ_FACTOR < deltaY)
+            return false;
+
+        // Check whether the point lies inside triangle ABC, and a similar
+        // triangle on the other side of the menu item.
+        //
+        //   +---------------------+
+        //   | menu item           |
+        // A +---------------------+ C
+        //              P          |
+        //                         B
+
+        // Ensure that the point P always lies below line AC so that we can
+        // only check for triangle ABC.
+        if (posY > y) {
+            let offset = posY - y;
+            y = posY + this.actor.height + offset;
+        }
+
+        // Ensure that A is (0, 0).
+        x -= posX;
+        y -= posY + this.actor.height;
+
+        // Check which side of line AB the point P lies on by taking the
+        // cross-product of AB and AP. See:
+        // http://stackoverflow.com/questions/3461453/determine-which-side-of-a-line-a-point-lies
+        if (((this.actor.width * y) - (NAVIGATION_REGION_OVERSHOOT * x)) <= 0)
+             return true;
+
+        return false;
+    },
+
+    _onMotionEvent: function(actor, event) {
+        if (!Clutter.get_pointer_grab()) {
+            this._oldX = -1;
+            this._oldY = -1;
+            Clutter.grab_pointer(this.actor);
+        }
+        this.actor.hover = true;
+
+        if (this._isNavigatingSubmenu(event.get_coords()))
+            return true;
+
+        this._oldX = -1;
+        this._oldY = -1;
+        this.actor.hover = false;
+        Clutter.ungrab_pointer();
+        return false;
+    },
+
     setActive: function(active, params) {
         if (active) {
             this._button.selectCategory(this._category, this);


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