From ad1a32749eea154aac789d53363dd2410b8482e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 2 Aug 2022 14:04:46 +0200 Subject: [PATCH] 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: --- js/ui/status/network.js | 72 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/js/ui/status/network.js b/js/ui/status/network.js index 394fd074e..4d5f73788 100644 --- a/js/ui/status/network.js +++ b/js/ui/status/network.js @@ -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( class NMConnectionItem extends NMMenuItem { constructor(section, connection) {