NPopupContextMenu: add dynamic width calculation

This commit is contained in:
Ly-sec
2025-11-24 14:13:02 +01:00
parent 54cd3d74e5
commit c7116827a4

View File

@@ -18,26 +18,77 @@ PopupWindow {
property var anchorItem: null property var anchorItem: null
property real anchorX: 0 property real anchorX: 0
property real anchorY: 0 property real anchorY: 0
property real calculatedWidth: 180
signal triggered(string action) signal triggered(string action)
implicitWidth: 180 implicitWidth: calculatedWidth
implicitHeight: Math.min(600, flickable.contentHeight + (Style.marginS * 2)) implicitHeight: Math.min(600, flickable.contentHeight + (Style.marginS * 2))
visible: false visible: false
color: Color.transparent color: Color.transparent
NText {
id: textMeasure
visible: false
pointSize: Style.fontSizeS
wrapMode: Text.NoWrap
elide: Text.ElideNone
width: undefined
}
NIcon {
id: iconMeasure
visible: false
icon: "bell"
pointSize: Style.fontSizeS
applyUiScale: false
}
onModelChanged: {
Qt.callLater(calculateWidth);
}
function calculateWidth() {
let maxWidth = 0;
if (model && model.length) {
for (let i = 0; i < model.length; i++) {
const item = model[i];
if (item && item.visible !== false) {
const label = item.label || item.text || "";
textMeasure.text = label;
textMeasure.forceLayout();
let itemWidth = textMeasure.contentWidth + 8;
if (item.icon !== undefined) {
itemWidth += iconMeasure.width + Style.marginS;
}
itemWidth += Style.marginM * 2;
if (itemWidth > maxWidth) {
maxWidth = itemWidth;
}
}
}
}
calculatedWidth = Math.max(maxWidth + (Style.marginS * 2), 120);
}
anchor.item: anchorItem anchor.item: anchorItem
anchor.rect.x: anchorX anchor.rect.x: anchorX
anchor.rect.y: anchorY anchor.rect.y: anchorY
// Handle Escape key to close menu Component.onCompleted: {
Qt.callLater(calculateWidth);
}
Item { Item {
anchors.fill: parent anchors.fill: parent
focus: true focus: true
Keys.onEscapePressed: root.close() Keys.onEscapePressed: root.close()
} }
// Background
Rectangle { Rectangle {
id: menuBackground id: menuBackground
anchors.fill: parent anchors.fill: parent
@@ -45,8 +96,6 @@ PopupWindow {
border.color: Color.mOutline border.color: Color.mOutline
border.width: Style.borderS border.width: Style.borderS
radius: Style.radiusM radius: Style.radiusM
// Fade-in animation
opacity: root.visible ? 1.0 : 0.0 opacity: root.visible ? 1.0 : 0.0
Behavior on opacity { Behavior on opacity {
@@ -57,15 +106,12 @@ PopupWindow {
} }
} }
// Content - Use Flickable + ColumnLayout like TrayMenu for consistency
Flickable { Flickable {
id: flickable id: flickable
anchors.fill: parent anchors.fill: parent
anchors.margins: Style.marginS anchors.margins: Style.marginS
contentHeight: columnLayout.implicitHeight contentHeight: columnLayout.implicitHeight
interactive: true interactive: true
// Fade-in animation
opacity: root.visible ? 1.0 : 0.0 opacity: root.visible ? 1.0 : 0.0
Behavior on opacity { Behavior on opacity {
@@ -112,7 +158,6 @@ PopupWindow {
anchors.rightMargin: Style.marginM anchors.rightMargin: Style.marginM
spacing: Style.marginS spacing: Style.marginS
// Optional icon
NIcon { NIcon {
visible: modelData.icon !== undefined visible: modelData.icon !== undefined
icon: modelData.icon || "" icon: modelData.icon || ""
@@ -170,13 +215,13 @@ PopupWindow {
return; return;
} }
calculateWidth();
anchorItem = item; anchorItem = item;
anchorX = x; anchorX = x;
anchorY = y; anchorY = y;
visible = true; visible = true;
// Force update after showing
Qt.callLater(() => { Qt.callLater(() => {
if (root.anchor) { if (root.anchor) {
root.anchor.updateAnchor(); root.anchor.updateAnchor();
@@ -184,17 +229,14 @@ PopupWindow {
}); });
} }
// Helper function to open at item (compatible with NContextMenu API)
function openAtItem(item, mouseX, mouseY) { function openAtItem(item, mouseX, mouseY) {
openAt(mouseX || 0, mouseY || 0, item); openAt(mouseX || 0, mouseY || 0, item);
} }
// Helper function to close menu (compatible with PopupMenuWindow)
function close() { function close() {
visible = false; visible = false;
} }
// Alias for backward compatibility
function closeMenu() { function closeMenu() {
close(); close();
} }