Something went wrong. Try again.
The agentic engineering control plane for the posthuman future
Something went wrong. Try again.
4.1 kB · 107 lines
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107import QtQuickimport QtQuick.Controls
import Xenomorphic
// A Menu generated from a named slice of the command registry. Every// registry-driven menu (pane context menu, sidebar row menu,// AddWorkspaceMenu) is a CommandMenu, so the item styling, separator// placement, enabled/visible semantics, and trigger routing stay identical// across all of them.//// The menu builds its items once from `menuName` (Commands.byMenu).// When `useContext` is true, the owning surface must call refresh(context)// before showing the menu: enabled/visible are evaluated per-target (the// pane under the pointer, the workspace row). When false, items bind live to// the command's global `enabled` / visibleFor(context).Menu { id: menu
property string menuName: "" property bool useContext: false property var context: null // The command registry. Defaults to the Commands singleton; overridable // for tests. property var registry: Commands
// The registry is a singleton created before the Shell, so its // `commands` array is stable; rebuild only if the registry object or // menu name changes. property var _builtRegistry: null property string _builtName: "" // The CommandMenuItem objects this menu created, in order (refresh // iterates these; itemAt() loses the concrete type for qmllint). property var _items: []
onRegistryChanged: rebuild() onMenuNameChanged: rebuild() // onXChanged handlers do not fire for the initial property assignment, // so the menu builds its items once the component is complete. Component.onCompleted: rebuild()
function rebuild() { // Remove any previous items (removeItem takes a MenuItem object). while (count > 0) { removeItem(itemAt(0)) } _items = [] if (!registry || !menuName) return var cmds = registry.byMenu(menuName) for (var i = 0; i < cmds.length; ++i) { var cmd = cmds[i] if (cmd.separators && cmd.separators.indexOf(menuName) >= 0) { addItem(separatorComponent.createObject(menu.contentItem)) } var item = itemComponent.createObject(menu.contentItem, { command: cmd, context: menu.context, useContext: menu.useContext }) // Initial state (refresh() re-evaluates per-target before show). item.enabledState = Commands.commandEnabledFor(cmd.commandId, menu.context) _items.push(item) addItem(item) } _builtRegistry = registry _builtName = menuName }
// Refresh per-target enabled state (useContext mode). Call before // popup() when the target is not a tracked QML property chain. The // item's `context` is an initial value, not a binding, so push the // target in explicitly alongside the state. function refresh(target) { context = target for (var i = 0; i < _items.length; ++i) { var obj = _items[i] if (obj && obj.command) { obj.context = target obj.enabledState = Commands.commandEnabledFor(obj.command.commandId, target) } } }
Component { id: itemComponent CommandMenuItem {} } Component { id: separatorComponent CommandMenuSeparator {} }
// Themed popup background (mirrors the original per-menu Rectangle). // Declared inline (not created dynamically) so it does not become a // contentItem child and inflate Menu.count. Every CommandMenu instance // is a themed popup. background: Rectangle { color: XenoTheme.hibernation radius: XenoTheme.controlRadius border.color: XenoTheme.castIron border.width: 1 // The built-in Basic Menu width comes from this background's // implicitWidth (the content ListView has no implicit width). // The custom Rectangle must restore it or the menu opens at 0px. implicitWidth: 200 }}