mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-17 00:34:01 -04:00
* feat(island): add system tray slot and overflow menu to compact home
- Add system tray slot and overflow expander menu in Dynamic Island
- Share tray icon path resolution and DBus context menu fallback in TrayMenuManager
- Support edge-anchored context menu positioning across top, bottom, left, and right
- Lock bottom and edge anchoring in DContextMenu to prevent animation jitter
* fix(island): only instantiate tray menus when tray slot is enabled
* feat(island): expand tray item and caret click area to slot height
* fix(island): use Theme.surfaceTextHover and restore DContextMenu height behavior
* refactor(tray): extract shared TrayMenuContent and TrayOverflowGrid, support tray order and IPC in island
* Revert "refactor(tray): extract shared TrayMenuContent and TrayOverflowGrid, support tray order and IPC in island"
This reverts commit 29888f89cd.
* refactor(tray): use shared TrayMenuManager helpers and TrayItemIcon, support tray order and IPC in island
* refactor(tray): extract shared TrayMenuContent and TrayOverflowGrid
* feat(island): support tray item drag and drop reordering
* fix(island): prevent re-entrant tray drag reordering on model destruction
* fix(tray): remove native submenu anchor hydration to prevent popup stutter
* fix(tray): decouple submenu hydrator from anchor window to avoid stutter
* fix(tray): restore anchor window on submenu hydrator and disable on island
* tray: fix bar overflow surface & reuse max visible items on the island
97 lines
2.6 KiB
QML
97 lines
2.6 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import qs.Common
|
|
import qs.Widgets
|
|
|
|
DContextMenu {
|
|
id: root
|
|
|
|
property var trayItem: null
|
|
property var bar: null
|
|
readonly property var menuHandle: trayItem?.menu ?? null
|
|
|
|
layerNamespace: "dms:tray-context-menu"
|
|
customContentWidth: Theme.fieldDefaultWidth
|
|
|
|
onOpenStateChanged: {
|
|
const screenName = root.targetScreen?.name;
|
|
if (!screenName)
|
|
return;
|
|
if (openState) {
|
|
TrayMenuManager.registerMenu(screenName, { close: () => root.hide() });
|
|
customContentItem?.clearState?.();
|
|
} else {
|
|
TrayMenuManager.unregisterMenu(screenName);
|
|
customContentItem?.clearState?.();
|
|
}
|
|
}
|
|
|
|
Component.onDestruction: {
|
|
if (openState && root.targetScreen?.name)
|
|
TrayMenuManager.unregisterMenu(root.targetScreen.name);
|
|
}
|
|
|
|
onBackdropRightClicked: root.hide()
|
|
|
|
function openFor(item, targetX, targetY, screen, edgeOrBottom) {
|
|
let edge = "top";
|
|
if (typeof edgeOrBottom === "string")
|
|
edge = edgeOrBottom;
|
|
else if (edgeOrBottom === true)
|
|
edge = "bottom";
|
|
root.menuEdge = edge;
|
|
trayItem = item;
|
|
const h = item?.menu ?? null;
|
|
if (h && typeof h.updateLayout === "function")
|
|
h.updateLayout();
|
|
|
|
let menuX = targetX;
|
|
let menuY = targetY;
|
|
|
|
switch (edge) {
|
|
case "bottom":
|
|
menuX = targetX - effectiveMenuWidth / 2;
|
|
menuY = targetY - Theme.spacingXS;
|
|
break;
|
|
case "left":
|
|
menuX = targetX + Theme.spacingXS;
|
|
menuY = targetY;
|
|
break;
|
|
case "right":
|
|
menuX = targetX - Theme.spacingXS;
|
|
menuY = targetY;
|
|
break;
|
|
case "top":
|
|
default:
|
|
menuX = targetX - effectiveMenuWidth / 2;
|
|
menuY = targetY + Theme.spacingXS;
|
|
break;
|
|
}
|
|
|
|
root.open(screen, menuX, menuY, false);
|
|
root.originX = targetX;
|
|
root.originY = targetY;
|
|
customContentItem?.clearState?.();
|
|
}
|
|
|
|
Timer {
|
|
id: pendingActionCloseTimer
|
|
interval: 80
|
|
repeat: false
|
|
onTriggered: root.hide()
|
|
}
|
|
|
|
customContent: Component {
|
|
TrayMenuContent {
|
|
id: contentRoot
|
|
width: root.customContentWidth
|
|
trayItem: root.trayItem
|
|
menuHandle: root.menuHandle
|
|
bar: root.bar
|
|
onCloseRequested: root.hide()
|
|
onActionTriggered: pendingActionCloseTimer.restart()
|
|
}
|
|
}
|
|
}
|