[gnome-shell/user-status-update: 4/5] popup-menu: Add combo box menu item
- From: Florian MÃllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/user-status-update: 4/5] popup-menu: Add combo box menu item
- Date: Thu, 21 Jul 2011 06:14:08 +0000 (UTC)
commit cf736671ad4303febfd90df31bd3929cdcac35c4
Author: Florian MÃllner <fmuellner gnome org>
Date: Thu Jul 21 05:17:05 2011 +0200
popup-menu: Add combo box menu item
data/theme/gnome-shell.css | 13 +++
js/ui/popupMenu.js | 197 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 210 insertions(+), 0 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index edbd023..49c5114 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -139,6 +139,15 @@ StTooltip StLabel {
border-width: 0px;
}
+.popup-combo-menu {
+ background-color: rgba(0,0,0,0.9);
+ padding: 1em 0em;
+ color: #ffffff;
+ font-size: 10.5pt;
+ border: 1px solid #5f5f5f;
+ border-radius: 9px;
+}
+
/* The remaining popup-menu sizing is all done in ems, so that if you
* override .popup-menu.font-size, everything else will scale with it.
*/
@@ -158,6 +167,10 @@ StTooltip StLabel {
.popup-image-menu-item {
}
+.popup-combobox-item {
+ spacing: 1em;
+}
+
.popup-separator-menu-item {
-gradient-height: 2px;
-gradient-start: rgba(8,8,8,0);
diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
index e1c18b0..985d1f9 100644
--- a/js/ui/popupMenu.js
+++ b/js/ui/popupMenu.js
@@ -15,6 +15,19 @@ const Tweener = imports.ui.tweener;
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
+function _ensureStyle(actor) {
+ // Really want to test for Clutter.Container, but that's an interface,
+ // which we don't support :(
+ if (actor instanceof St.Container || actor instanceof Clutter.Group) {
+ let children = actor.get_children();
+ for (let i = 0; i < children.length; i++)
+ _ensureStyle(children[i]);
+ }
+
+ if (actor instanceof St.Widget)
+ actor.ensure_style();
+}
+
function PopupBaseMenuItem(params) {
this._init(params);
}
@@ -986,6 +999,10 @@ PopupMenuBase.prototype = {
return null;
},
+ get numMenuItems() {
+ return this._getMenuItems().length;
+ },
+
removeAll: function() {
let children = this._getMenuItems();
for (let i = 0; i < children.length; i++) {
@@ -1350,6 +1367,186 @@ PopupSubMenuMenuItem.prototype = {
}
};
+function PopupComboMenu() {
+ this._init.apply(this, arguments);
+}
+
+PopupComboMenu.prototype = {
+ __proto__: PopupMenuBase.prototype,
+
+ _init: function(sourceActor) {
+ PopupMenuBase.prototype._init.call(this,
+ sourceActor, 'popup-combo-menu');
+ this.actor = this.box;
+ this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
+ this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
+ this._activeItemPos = -1;
+ global.focus_manager.add_group(this.actor);
+ },
+
+ _onKeyPressEvent: function(actor, event) {
+ if (event.get_key_symbol() == Clutter.Escape) {
+ this.close(true);
+ return true;
+ }
+
+ return false;
+ },
+
+ _onKeyFocusIn: function(actor) {
+ let items = this._getMenuItems();
+ let activeItem = items[this._activeItemPos];
+ activeItem.actor.grab_key_focus();
+ },
+
+ open: function() {
+ if (this.isOpen)
+ return;
+
+ this.isOpen = true;
+
+ let [sourceX, sourceY] = this.sourceActor.get_transformed_position();
+ let items = this._getMenuItems();
+ let activeItem = items[this._activeItemPos];
+
+ this.actor.set_position(sourceX, sourceY - activeItem.actor.y);
+ this.actor.raise_top();
+
+ this.actor.opacity = 0;
+ this.actor.show();
+
+ Tweener.addTween(this.actor,
+ { opacity: 255,
+ transition: 'linear',
+ time: BoxPointer.POPUP_ANIMATION_TIME });
+
+ this.emit('open-state-changed', true);
+ },
+
+ close: function() {
+ if (!this.isOpen)
+ return;
+
+ this.isOpen = false;
+ Tweener.addTween(this.actor,
+ { opacity: 0,
+ transition: 'linear',
+ time: BoxPointer.POPUP_ANIMATION_TIME,
+ onComplete: Lang.bind(this,
+ function() {
+ this.actor.hide();
+ })
+ });
+
+ this.emit('open-state-changed', false);
+ },
+
+ setActiveItem: function(position) {
+ this._activeItemPos = position;
+ },
+
+ setItemVisible: function(position, visible) {
+ if (!visible && position == this._activeItemPos) {
+ log('Trying to hide the active menu item.');
+ return;
+ }
+
+ this._getMenuItems()[position].actor.visible = visible;
+ }
+};
+
+function PopupComboBoxMenuItem() {
+ this._init.apply(this, arguments);
+}
+
+PopupComboBoxMenuItem.prototype = {
+ __proto__: PopupBaseMenuItem.prototype,
+
+ _init: function (params) {
+ PopupBaseMenuItem.prototype._init.call(this, params);
+
+ this._itemBox = new Shell.Stack();
+ this.addActor(this._itemBox);
+
+ let expander = new St.Label({ text: '\u2304' });
+ this.addActor(expander, { align: St.Align.END });
+
+ this._menu = new PopupComboMenu(this.actor);
+ Main.chrome.addActor(this._menu.actor, { affectsStruts: false });
+ this._menu.actor.hide();
+
+ this._activeItemPos = -1;
+ this._items = [];
+ },
+
+ _getTopMenu: function() {
+ let actor = this.actor.get_parent();
+ while (actor) {
+ if (actor._delegate && actor._delegate instanceof PopupMenu)
+ return actor._delegate;
+
+ actor = actor.get_parent();
+ }
+
+ return null;
+ },
+
+ activate: function(event) {
+ let topMenu = this._getTopMenu();
+ if (!topMenu)
+ return;
+
+ topMenu.addChildMenu(this._menu);
+ this._menu.open(true);
+ },
+
+ addMenuItem: function(menuItem, position) {
+ if (position === undefined)
+ position = this._menu.numMenuItems;
+
+ this._menu.addMenuItem(menuItem, position);
+ _ensureStyle(this._menu.actor);
+
+ let item = new St.BoxLayout({ style_class: 'popup-combobox-item' });
+
+ let children = menuItem.actor.get_children();
+ for (let i = 0; i < children.length; i++) {
+ let clone = new Clutter.Clone({ source: children[i] });
+ item.add(clone, { y_fill: false });
+ }
+
+ let oldItem = this._items[position];
+ if (oldItem)
+ this._itemBox.remove_actor(oldItem);
+
+ this._items[position] = item;
+ this._itemBox.add_actor(item);
+
+ menuItem.connect('activate',
+ Lang.bind(this, this._itemActivated, position));
+ },
+
+ setActiveItem: function(position) {
+ let item = this._items[position];
+ if (!item)
+ return;
+ if (this._activeItemPos == position)
+ return;
+ this._menu.setActiveItem(position);
+ this._activeItemPos = position;
+ for (let i = 0; i < this._items.length; i++)
+ this._items[i].visible = (i == this._activeItemPos);
+ },
+
+ setItemVisible: function(position, visible) {
+ this._menu.setItemVisible(position, visible);
+ },
+
+ _itemActivated: function(menuItem, event, position) {
+ this.setActiveItem(position);
+ this.emit('active-item-changed', position);
+ }
+};
/* Basic implementation of a menu manager.
* Call addMenu to add menus
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]