121 lines
3.0 KiB
QML
121 lines
3.0 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Hyprland
|
|
import Quickshell.Io
|
|
import Quickshell.Wayland
|
|
import qs.Commons
|
|
import qs.Services.UI
|
|
import qs.Widgets
|
|
|
|
// Universal selection context menu that appears at cursor position
|
|
PanelWindow {
|
|
id: root
|
|
|
|
required property ShellScreen screen
|
|
property var pluginApi: null
|
|
property var menuItems: []
|
|
|
|
signal itemSelected(string action)
|
|
signal cancelled
|
|
|
|
anchors.top: true
|
|
anchors.left: true
|
|
anchors.right: true
|
|
anchors.bottom: true
|
|
visible: false
|
|
color: "transparent"
|
|
|
|
WlrLayershell.layer: WlrLayer.Overlay
|
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
|
WlrLayershell.namespace: "noctalia-selection-menu-" + (screen?.name || "unknown")
|
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
|
|
|
property int cursorX: 0
|
|
property int cursorY: 0
|
|
|
|
function show(items) {
|
|
menuItems = items || [];
|
|
visible = true;
|
|
getCursorPositionProcess.running = true;
|
|
}
|
|
|
|
function close() {
|
|
visible = false;
|
|
contextMenu.visible = false;
|
|
}
|
|
|
|
// Get cursor position from hyprctl
|
|
Process {
|
|
id: getCursorPositionProcess
|
|
command: ["hyprctl", "cursorpos", "-j"]
|
|
running: false
|
|
|
|
stdout: StdioCollector {
|
|
id: cursorStdout
|
|
}
|
|
|
|
onExited: (exitCode, exitStatus) => {
|
|
if (exitCode === 0) {
|
|
try {
|
|
const data = JSON.parse(cursorStdout.text);
|
|
root.cursorX = data.x || 0;
|
|
root.cursorY = data.y || 0;
|
|
|
|
// Position menu at cursor
|
|
anchorPoint.x = root.cursorX;
|
|
anchorPoint.y = root.cursorY;
|
|
contextMenu.model = root.menuItems;
|
|
contextMenu.anchorItem = anchorPoint;
|
|
contextMenu.visible = true;
|
|
} catch (e) {
|
|
ToastService.showError(pluginApi?.tr("toast.failed-to-get-cursor-position"));
|
|
root.close();
|
|
}
|
|
} else {
|
|
root.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Context menu
|
|
NPopupContextMenu {
|
|
id: contextMenu
|
|
visible: false
|
|
screen: root.screen
|
|
minWidth: 200
|
|
|
|
onTriggered: (action, item) => {
|
|
root.itemSelected(action);
|
|
root.close();
|
|
}
|
|
}
|
|
|
|
// Anchor point for menu positioning
|
|
Item {
|
|
id: anchorPoint
|
|
width: 1
|
|
height: 1
|
|
x: 0
|
|
y: 0
|
|
}
|
|
|
|
// Fullscreen mouse area to capture outside clicks
|
|
MouseArea {
|
|
id: mouseCapture
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
|
|
onClicked: mouse => {
|
|
root.cancelled();
|
|
root.close();
|
|
}
|
|
}
|
|
|
|
Component.onDestruction: {
|
|
if (getCursorPositionProcess.running) {
|
|
getCursorPositionProcess.terminate();
|
|
}
|
|
close();
|
|
}
|
|
}
|