status/network: Add NMSectionItem subclass

The class implements a menu item that contains a section which
can be collapsed into a submenu.

It is very common for network devices to only have one associated
connection, so hiding away a single item in a submenu is fairly
inconvenient.

This class will address this, by only using a submenu when it is
actually needed.

Although the main issue it addresses is that menus (including
sections) aren't GObjects. This gives us a GObject that can
be added to a menu, and that can itself contain other menu
items.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2407>
This commit is contained in:
Florian Müllner 2022-08-02 14:04:46 +02:00 committed by Marge Bot
parent b4da69d474
commit ad1a32749e

View File

@ -200,6 +200,78 @@ const NMMenuItem = GObject.registerClass({
} }
}); });
/**
* Item that contains a section, and can be collapsed
* into a submenu
*/
const NMSectionItem = GObject.registerClass({
Properties: {
'use-submenu': GObject.ParamSpec.boolean('use-submenu', '', '',
GObject.ParamFlags.READWRITE,
false),
},
}, class NMSectionItem extends NMMenuItem {
constructor() {
super({
activate: false,
can_focus: false,
});
this._useSubmenu = false;
// Turn into an empty container with no padding
this.styleClass = '';
this.setOrnament(PopupMenu.Ornament.HIDDEN);
// Add intermediate section; we need this for submenu support
this._mainSection = new PopupMenu.PopupMenuSection();
this.add_child(this._mainSection.actor);
this._submenuItem = new PopupMenu.PopupSubMenuMenuItem('', true);
this._mainSection.addMenuItem(this._submenuItem);
this._submenuItem.hide();
this.section = new PopupMenu.PopupMenuSection();
this._mainSection.addMenuItem(this.section);
// Represents the item as a whole when shown
this.bind_property('name',
this._submenuItem.label, 'text',
GObject.BindingFlags.DEFAULT);
this.bind_property('icon-name',
this._submenuItem.icon, 'icon-name',
GObject.BindingFlags.DEFAULT);
}
_setParent(parent) {
super._setParent(parent);
this._mainSection._setParent(parent);
parent?.connect('menu-closed',
() => this._mainSection.emit('menu-closed'));
}
get use_submenu() {
return this._useSubmenu;
}
set use_submenu(useSubmenu) {
if (this._useSubmenu === useSubmenu)
return;
this._useSubmenu = useSubmenu;
this._submenuItem.visible = useSubmenu;
if (useSubmenu) {
this._mainSection.box.remove_child(this.section.actor);
this._submenuItem.menu.box.add_child(this.section.actor);
} else {
this._submenuItem.menu.box.remove_child(this.section.actor);
this._mainSection.box.add_child(this.section.actor);
}
}
});
const NMConnectionItem = GObject.registerClass( const NMConnectionItem = GObject.registerClass(
class NMConnectionItem extends NMMenuItem { class NMConnectionItem extends NMMenuItem {
constructor(section, connection) { constructor(section, connection) {