RemoteMenu: add support for section labels

According to the GIO docs, sections can have labels too. We support
them by inserting a non reactive menu item at the beginning of the
section. This item is specially flagged to be ignored while processing
changed signals from the model (since it does not correspond to any
model item)

https://bugzilla.gnome.org/show_bug.cgi?id=666681
This commit is contained in:
Giovanni Campagna 2011-12-21 23:11:40 +01:00
parent 64baea1693
commit b087191d2b
2 changed files with 44 additions and 11 deletions

View File

@ -1398,12 +1398,23 @@ const PopupMenuSection = new Lang.Class({
this.actor = this.box; this.actor = this.box;
this.actor._delegate = this; this.actor._delegate = this;
this.isOpen = true; this.isOpen = true;
// an array of externally managed separators
this.separators = [];
}, },
// deliberately ignore any attempt to open() or close(), but emit the // deliberately ignore any attempt to open() or close(), but emit the
// corresponding signal so children can still pick it up // corresponding signal so children can still pick it up
open: function(animate) { this.emit('open-state-changed', true); }, open: function(animate) { this.emit('open-state-changed', true); },
close: function() { this.emit('open-state-changed', false); }, close: function() { this.emit('open-state-changed', false); },
destroy: function() {
for (let i = 0; i < this.separators.length; i++)
this.separators[i].destroy();
this.separators = [];
this.parent();
}
}); });
const PopupSubMenuMenuItem = new Lang.Class({ const PopupSubMenuMenuItem = new Lang.Class({
@ -1737,17 +1748,25 @@ const RemoteMenu = new Lang.Class({
}, },
_createMenuItem: function(model, index) { _createMenuItem: function(model, index) {
let labelValue = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_LABEL, null);
let label = labelValue ? labelValue.deep_unpack() : '';
// remove all underscores that are not followed by another underscore
label = label.replace(/_([^_])/, '$1');
let section_link = model.get_item_link(index, Gio.MENU_LINK_SECTION); let section_link = model.get_item_link(index, Gio.MENU_LINK_SECTION);
if (section_link) { if (section_link) {
let item = new PopupMenuSection(); let item = new PopupMenuSection();
if (label) {
let title = new PopupMenuItem(label, { reactive: false,
style_class: 'popup-subtitle-menu-item' });
item._titleMenuItem = title;
title._ignored = true;
item.addMenuItem(title);
}
this._modelChanged(section_link, 0, 0, section_link.get_n_items(), item); this._modelChanged(section_link, 0, 0, section_link.get_n_items(), item);
return [item, true, '']; return [item, true, ''];
} }
// labels are not checked for existance, as they're required for all items
let label = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_LABEL, null).deep_unpack();
// remove all underscores that are not followed by another underscore
label = label.replace(/_([^_])/, '$1');
let submenu_link = model.get_item_link(index, Gio.MENU_LINK_SUBMENU); let submenu_link = model.get_item_link(index, Gio.MENU_LINK_SUBMENU);
if (submenu_link) { if (submenu_link) {
@ -1831,8 +1850,13 @@ const RemoteMenu = new Lang.Class({
let currentItems = target._getMenuItems(); let currentItems = target._getMenuItems();
for (j0 = 0, k0 = 0; j0 < position; j0++, k0++) { k0 = 0;
if (currentItems[k0] instanceof PopupSeparatorMenuItem) // skip ignored items at the beginning
while (k0 < currentItems.length && currentItems[k0]._ignored)
k0++;
// find the right menu item matching the model item
for (j0 = 0; j0 < position; j0++, k0++) {
if (currentItems[k0]._ignored)
k0++; k0++;
} }
@ -1844,7 +1868,7 @@ const RemoteMenu = new Lang.Class({
for (j = j0, k = k0; j < j0 + removed; j++, k++) { for (j = j0, k = k0; j < j0 + removed; j++, k++) {
currentItems[k].destroy(); currentItems[k].destroy();
if (currentItems[k] instanceof PopupSeparatorMenuItem) if (currentItems[k]._ignored)
j--; j--;
} }
} }
@ -1855,14 +1879,20 @@ const RemoteMenu = new Lang.Class({
if (item) { if (item) {
// separators must be added in the parent to make autohiding work // separators must be added in the parent to make autohiding work
if (addSeparator) { if (addSeparator) {
target.addMenuItem(new PopupSeparatorMenuItem(), k+1); let separator = new PopupSeparatorMenuItem();
item.separators.push(separator);
separator._ignored = true;
target.addMenuItem(separator, k+1);
k++; k++;
} }
target.addMenuItem(item, k); target.addMenuItem(item, k);
if (addSeparator) { if (addSeparator) {
target.addMenuItem(new PopupSeparatorMenuItem(), k+1); let separator = new PopupSeparatorMenuItem();
item.separators.push(separator);
separator._ignored = true;
target.addMenuItem(separator, k+1);
k++; k++;
} }
} else if (changeSignal) { } else if (changeSignal) {
@ -1888,7 +1918,10 @@ const RemoteMenu = new Lang.Class({
} }
if (target instanceof PopupMenuSection) { if (target instanceof PopupMenuSection) {
target.actor.visible = target.numMenuItems != 0; if (target._titleMenuItem)
target.actor.visible = target.numMenuItems != 1;
else
target.actor.visible = target.numMenuItems != 0;
} else { } else {
let sourceItem = target.sourceActor._delegate; let sourceItem = target.sourceActor._delegate;
if (sourceItem instanceof PopupSubMenuMenuItem) if (sourceItem instanceof PopupSubMenuMenuItem)

View File

@ -68,7 +68,7 @@ function main() {
section = new Gio.Menu(); section = new Gio.Menu();
section.append('Checkbox', 'app.toggle'); section.append('Checkbox', 'app.toggle');
section.append('Disabled', 'app.disable'); section.append('Disabled', 'app.disable');
menu.append_section(null, section); menu.append_section('Subsection', section);
// empty sections or submenus should be invisible // empty sections or submenus should be invisible
menu.append_section('Empty section', new Gio.Menu()); menu.append_section('Empty section', new Gio.Menu());