mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2025-12-06 06:36:15 +00:00
NPopupContextMenu: add dynamic width calculation
This commit is contained in:
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user