[gnome-shell] [panel] add keyboard navigation of menus
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] [panel] add keyboard navigation of menus
- Date: Wed, 19 May 2010 17:17:45 +0000 (UTC)
commit 9b3e16595bf3ac583b0133a519da6ca9f0493d18
Author: Dan Winship <danw gnome org>
Date: Tue May 18 13:15:19 2010 -0400
[panel] add keyboard navigation of menus
https://bugzilla.gnome.org/show_bug.cgi?id=619008
js/ui/panel.js | 110 +++++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 97 insertions(+), 13 deletions(-)
---
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 9c311a5..75cb755 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -138,6 +138,7 @@ PanelBaseMenuItem.prototype = {
x_fill: true,
y_fill: true,
x_align: St.Align.START });
+ this.actor._delegate = this;
this.active = false;
if (reactive) {
@@ -280,6 +281,28 @@ PanelImageMenuItem.prototype = {
}
};
+function mod(a, b) {
+ return (a + b) % b;
+}
+
+function findNextInCycle(items, current, direction) {
+ let cur;
+
+ if (items.length == 0)
+ return current;
+ else if (items.length == 1)
+ return items[0];
+
+ if (current)
+ cur = items.indexOf(current);
+ else if (direction == 1)
+ cur = items.length - 1;
+ else
+ cur = 0;
+
+ return items[mod(cur + direction, items.length)];
+}
+
function PanelMenu(sourceButton) {
this._init(sourceButton);
}
@@ -294,6 +317,8 @@ PanelMenu.prototype = {
vertical: true });
this._boxPointer.bin.set_child(this._box);
this.actor.add_style_class_name('panel-menu');
+
+ this._activeMenuItem = null;
},
addAction: function(title, callback) {
@@ -306,6 +331,15 @@ PanelMenu.prototype = {
addMenuItem: function(menuItem) {
this._box.add(menuItem.actor);
+ menuItem.connect('active-changed', Lang.bind(this, function (menuItem, active) {
+ if (active && this._activeMenuItem != menuItem) {
+ if (this._activeMenuItem)
+ this._activeMenuItem.setActive(false);
+ this._activeMenuItem = menuItem;
+ } else if (!active && this._activeMenuItem == menuItem) {
+ this._activeMenuItem = null;
+ }
+ }));
menuItem.connect('activate', Lang.bind(this, function (menuItem, event) {
this.emit('activate');
}));
@@ -317,6 +351,50 @@ PanelMenu.prototype = {
setArrowOrigin: function(origin) {
this._boxPointer.setArrowOrigin(origin);
+ },
+
+ open: function() {
+ let panelActor = Main.panel.actor;
+ this.actor.lower(panelActor);
+
+ this.actor.show();
+ this.actor.opacity = 0;
+ this.actor.reactive = true;
+ Tweener.addTween(this.actor, { opacity: 255,
+ transition: "easeOutQuad",
+ time: POPUP_ANIMATION_TIME });
+ },
+
+ close: function() {
+ this.actor.reactive = false;
+ Tweener.addTween(this.actor, { opacity: 0,
+ transition: "easeOutQuad",
+ time: POPUP_ANIMATION_TIME,
+ onComplete: Lang.bind(this, function () { this.actor.hide(); })});
+ if (this._activeMenuItem)
+ this._activeMenuItem.setActive(false);
+ },
+
+ handleKeyPress: function(event) {
+ if (event.get_key_symbol() == Clutter.space ||
+ event.get_key_symbol() == Clutter.Return) {
+ if (this._activeMenuItem)
+ this._activeMenuItem.activate(event);
+ return true;
+ } else if (event.get_key_symbol() == Clutter.Down
+ || event.get_key_symbol() == Clutter.Up) {
+ let items = this._box.get_children().filter(function (child) { return child.visible && child.reactive; });
+ let current = this._activeMenuItem ? this._activeMenuItem.actor : null;
+ let direction = event.get_key_symbol() == Clutter.Down ? 1 : -1;
+
+ let next = findNextInCycle(items, current, direction);
+ if (next) {
+ next._delegate.setActive(true);
+ return true;
+ }
+ }
+
+ return false;
}
};
Signals.addSignalMethods(PanelMenu.prototype);
@@ -339,6 +417,7 @@ PanelMenuButton.prototype = {
x_fill: true,
y_fill: true,
track_hover: true });
+ this.actor._delegate = this;
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
// FIXME - this will trigger a warning about a queued allocation from inside
// allocate; hard to solve without a way to express a high level positioning
@@ -358,14 +437,7 @@ PanelMenuButton.prototype = {
return;
this._state = this.State.OPEN;
- let panelActor = Main.panel.actor;
- this.menu.actor.lower(panelActor);
- this.menu.actor.show();
- this.menu.actor.opacity = 0;
- this.menu.actor.reactive = true;
- Tweener.addTween(this.menu.actor, { opacity: 255,
- transition: "easeOutQuad",
- time: POPUP_ANIMATION_TIME });
+ this.menu.open();
this._repositionMenu();
this.actor.add_style_pseudo_class('pressed');
@@ -428,11 +500,7 @@ PanelMenuButton.prototype = {
if (this._state != this.State.OPEN)
return;
this._state = this.State.CLOSED;
- this.menu.actor.reactive = false;
- Tweener.addTween(this.menu.actor, { opacity: 0,
- transition: "easeOutQuad",
- time: POPUP_ANIMATION_TIME,
- onComplete: Lang.bind(this, function () { this.menu.actor.hide(); })});
+ this.menu.close();
this.actor.remove_style_pseudo_class('pressed');
this.emit('open-state-changed', false);
},
@@ -558,9 +626,25 @@ PanelMenuBar.prototype = {
this._activeMenuButton.close();
this._closeMenu();
return true;
+ } else if (eventType == Clutter.EventType.KEY_PRESS
+ && this._activeMenuButton != null
+ && this._activeMenuButton.menu.handleKeyPress(event)) {
+ return true;
+ } else if (eventType == Clutter.EventType.KEY_PRESS
+ && this._activeMenuButton != null
+ && (event.get_key_symbol() == Clutter.Left
+ || event.get_key_symbol() == Clutter.Right)) {
+ let direction = event.get_key_symbol() == Clutter.Right ? 1 : -1;
+ let next = findNextInCycle(this._menus, this._activeMenuButton, direction);
+ if (next != this._activeMenuButton) {
+ this._activeMenuButton.close();
+ next.open();
+ }
+ return true;
} else if (activeMenuContains || this._eventIsOnAnyMenuButton(event)) {
return false;
}
+
return true;
},
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]