PopupContextMenu: fixed popup positionning on wlroots and hyprland

This commit is contained in:
Lemmy
2025-12-19 19:09:52 -05:00
parent 6b407f0b9b
commit 9402655381
23 changed files with 108 additions and 108 deletions
+1 -2
View File
@@ -450,8 +450,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
contextMenu.openAtItem(root, screen);
}
}
}
+1 -2
View File
@@ -154,8 +154,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
contextMenu.openAtItem(root, screen);
}
} else {
const types = ["linear", "mirrored", "wave"];
+1 -2
View File
@@ -248,8 +248,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(pill, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(pill, pos.x, pos.y);
contextMenu.openAtItem(pill, screen);
}
}
}
+1 -2
View File
@@ -93,8 +93,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(pill, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(pill, pos.x, pos.y);
contextMenu.openAtItem(pill, screen);
}
}
tooltipText: {
+1 -2
View File
@@ -151,8 +151,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(pill, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(pill, pos.x, pos.y);
contextMenu.openAtItem(pill, screen);
}
}
}
+1 -2
View File
@@ -169,8 +169,7 @@ Rectangle {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
contextMenu.openAtItem(root, screen);
}
} else {
PanelService.getPanel("clockPanel", screen)?.toggle(this);
+1 -2
View File
@@ -149,8 +149,7 @@ NIconButton {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
contextMenu.openAtItem(root, screen);
}
}
onMiddleClicked: PanelService.getPanel("launcherPanel", screen)?.toggle()
+1 -2
View File
@@ -83,8 +83,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(pill, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(pill, pos.x, pos.y);
contextMenu.openAtItem(pill, screen);
}
}
}
+1 -2
View File
@@ -83,8 +83,7 @@ Rectangle {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
contextMenu.openAtItem(root, screen);
}
}
}
+1 -2
View File
@@ -366,8 +366,7 @@ Item {
var popupWindow = PanelService.getPopupMenuWindow(screen);
if (popupWindow) {
popupWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(container, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(container, pos.x, pos.y);
contextMenu.openAtItem(container, screen);
}
} else if (mouse.button === Qt.MiddleButton && hasPlayer && MediaService.canGoPrevious) {
MediaService.previous();
+1 -2
View File
@@ -170,8 +170,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(pill, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(pill, pos.x, pos.y);
contextMenu.openAtItem(pill, screen);
}
}
onMiddleClicked: root.openExternalMixer()
+1 -2
View File
@@ -106,8 +106,7 @@ NIconButton {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
contextMenu.openAtItem(root, screen);
}
}
+1 -2
View File
@@ -89,8 +89,7 @@ NIconButton {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
contextMenu.openAtItem(root, screen);
}
}
}
+1 -2
View File
@@ -151,8 +151,7 @@ Rectangle {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
contextMenu.openAtItem(root, screen);
}
}
}
+1 -1
View File
@@ -687,7 +687,7 @@ Rectangle {
menuY = globalPos.y + (item.height / 2) - (contextMenu.implicitHeight / 2);
}
popupMenuWindow.showContextMenu(contextMenu);
contextMenu.openAtItem(root, menuX, menuY);
contextMenu.openAtItem(root, screen);
}
}
}
+1 -2
View File
@@ -125,8 +125,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(pill, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(pill, pos.x, pos.y);
contextMenu.openAtItem(pill, screen);
}
}
tooltipText: {
+1 -2
View File
@@ -154,8 +154,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(pill, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(pill, pos.x, pos.y);
contextMenu.openAtItem(pill, screen);
}
}
onMiddleClicked: root.openExternalMixer()
+1 -2
View File
@@ -61,8 +61,7 @@ NIconButton {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(root, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(root, pos.x, pos.y);
contextMenu.openAtItem(root, screen);
}
}
}
+1 -2
View File
@@ -115,8 +115,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(pill, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(pill, pos.x, pos.y);
contextMenu.openAtItem(pill, screen);
}
}
tooltipText: {
+1 -2
View File
@@ -333,8 +333,7 @@ Item {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.showContextMenu(contextMenu);
const pos = BarService.getContextMenuPosition(workspaceBackground, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(workspaceBackground, pos.x, pos.y);
contextMenu.openAtItem(workspaceBackground, screen);
}
}
}
-50
View File
@@ -286,56 +286,6 @@ Singleton {
}
}
// Calculate context menu position based on bar position
// Parameters:
// anchorItem: The widget item to anchor the menu to
// menuWidth: Width of the context menu (optional, defaults to 180)
// menuHeight: Height of the context menu (optional, defaults to 100)
// Returns: { x: number, y: number }
// Note: Anchor position is top-left corner, so we calculate from center
function getContextMenuPosition(anchorItem, menuWidth, menuHeight) {
if (!anchorItem) {
Logger.w("BarService", "getContextMenuPosition: anchorItem is null");
return {
"x": 0,
"y": 0
};
}
const mWidth = menuWidth || 180;
const mHeight = menuHeight || 100;
const barPosition = Settings.data.bar.position;
let menuX = 0;
let menuY = 0;
// Calculate center-based positioning for consistent spacing
const anchorCenterX = anchorItem.width / 2;
const anchorCenterY = anchorItem.height / 2;
if (barPosition === "left") {
// For left bar: position menu to the right of anchor, vertically centered
menuX = anchorItem.width + Style.marginM;
menuY = anchorCenterY - (mHeight / 2);
} else if (barPosition === "right") {
// For right bar: position menu to the left of anchor, vertically centered
menuX = -mWidth - Style.marginM;
menuY = anchorCenterY - (mHeight / 2);
} else if (barPosition === "top") {
// For top bar: position menu below bar, horizontally centered
menuX = anchorCenterX - (mWidth / 2);
menuY = Style.barHeight;
} else {
// For bottom bar: position menu above, horizontally centered
menuX = anchorCenterX - (mWidth / 2);
menuY = -mHeight - Style.marginM;
}
return {
"x": menuX,
"y": menuY
};
}
// Open widget settings dialog for a bar widget
// Parameters:
// screen: The screen to show the dialog on
+3
View File
@@ -3,6 +3,9 @@ import QtQuick.Controls
import QtQuick.Layouts
import qs.Commons
/*
This component could probably be deleted and replaced by NPopupContextMenu
*/
Popup {
id: root
+85 -19
View File
@@ -6,20 +6,22 @@ import qs.Commons
// Simple context menu PopupWindow (similar to TrayMenu)
// Designed to be rendered inside a PopupMenuWindow for click-outside-to-close
// Automatically positions itself to respect screen boundaries
PopupWindow {
id: root
property alias model: repeater.model
property real itemHeight: 28 // Match TrayMenu
property real itemHeight: 28 // Match TrayMenu
property real itemPadding: Style.marginM
property int verticalPolicy: ScrollBar.AsNeeded
property int horizontalPolicy: ScrollBar.AsNeeded
property var anchorItem: null
property real anchorX: 0
property real anchorY: 0
property ShellScreen screen: null
property real calculatedWidth: 180
readonly property string barPosition: Settings.data.bar.position
signal triggered(string action, var item)
implicitWidth: calculatedWidth
@@ -76,8 +78,82 @@ PopupWindow {
}
anchor.item: anchorItem
anchor.rect.x: anchorX
anchor.rect.y: anchorY
anchor.rect.x: {
if (anchorItem && screen) {
const anchorGlobalPos = anchorItem.mapToItem(null, 0, 0);
// For right bar: position menu to the left of anchor
if (root.barPosition === "right") {
let baseX = -implicitWidth - Style.marginM;
return baseX;
}
// For left bar: position menu to the right of anchor
if (root.barPosition === "left") {
let baseX = anchorItem.width + Style.marginM;
return baseX;
}
// For top/bottom bar: center horizontally on anchor
const anchorCenterX = anchorItem.width / 2;
let baseX = anchorCenterX - (implicitWidth / 2);
// Calculate menu position on screen
const menuScreenX = anchorGlobalPos.x + baseX;
const menuRight = menuScreenX + implicitWidth;
// Adjust if menu would clip on the right
if (menuRight > screen.width - Style.marginM) {
const overflow = menuRight - (screen.width - Style.marginM);
return baseX - overflow;
}
// Adjust if menu would clip on the left
if (menuScreenX < Style.marginM) {
return baseX + (Style.marginM - menuScreenX);
}
return baseX;
}
return 0;
}
anchor.rect.y: {
if (anchorItem && screen) {
const anchorCenterY = anchorItem.height / 2;
// Calculate base Y position based on bar orientation
let baseY;
if (root.barPosition === "bottom") {
// For bottom bar: position menu above the bar
baseY = -(implicitHeight + Style.marginM);
} else if (root.barPosition === "top") {
// For top bar: position menu below bar
baseY = Style.barHeight + Style.marginM;
} else {
// For left/right bar: vertically center on anchor
baseY = anchorCenterY - (implicitHeight / 2);
}
// Calculate menu position on screen
const anchorGlobalPos = anchorItem.mapToItem(null, 0, 0);
const menuScreenY = anchorGlobalPos.y + baseY;
const menuBottom = menuScreenY + implicitHeight;
// Adjust if menu would clip at bottom
if (menuBottom > screen.height - Style.marginM) {
const overflow = menuBottom - (screen.height - Style.marginM);
return baseY - overflow;
}
return baseY;
}
// Fallback if no screen
if (root.barPosition === "bottom") {
return -implicitHeight - Style.marginM;
}
return Style.barHeight;
}
Component.onCompleted: {
Qt.callLater(calculateWidth);
@@ -208,8 +284,9 @@ PopupWindow {
}
}
// Helper function to open at specific position relative to anchor item
function openAt(x, y, item) {
// Helper function to open context menu anchored to an item
// Position is calculated automatically based on bar position and screen boundaries
function openAtItem(item, itemScreen) {
if (!item) {
Logger.w("NPopupContextMenu", "anchorItem is undefined, won't show menu.");
return;
@@ -218,19 +295,8 @@ PopupWindow {
calculateWidth();
anchorItem = item;
anchorX = x;
anchorY = y;
screen = itemScreen || null;
visible = true;
Qt.callLater(() => {
if (root.anchor) {
root.anchor.updateAnchor();
}
});
}
function openAtItem(item, mouseX, mouseY) {
openAt(mouseX || 0, mouseY || 0, item);
}
function close() {