extract shared PopupPanel for animated tray/power menus
This commit is contained in:
parent
77ce83462d
commit
b8ec39f2c9
6 changed files with 249 additions and 302 deletions
92
modules/PopupPanel.qml
Normal file
92
modules/PopupPanel.qml
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import "." as M
|
||||||
|
|
||||||
|
// Shared flyout popup window — slides down from the bar, dismisses on
|
||||||
|
// click outside. Created on demand via Loader; animates in on creation,
|
||||||
|
// animates out then emits dismissed() for the Loader to deactivate.
|
||||||
|
PanelWindow {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
default property alias content: contentCol.children
|
||||||
|
required property var screen
|
||||||
|
required property real anchorX
|
||||||
|
property real panelWidth: 220
|
||||||
|
|
||||||
|
signal dismissed()
|
||||||
|
|
||||||
|
visible: true
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
WlrLayershell.exclusiveZone: 0
|
||||||
|
WlrLayershell.namespace: "nova-popup"
|
||||||
|
|
||||||
|
anchors.top: true
|
||||||
|
anchors.left: true
|
||||||
|
anchors.right: true
|
||||||
|
anchors.bottom: true
|
||||||
|
|
||||||
|
Component.onCompleted: showAnim.start()
|
||||||
|
|
||||||
|
function dismiss() {
|
||||||
|
showAnim.stop();
|
||||||
|
hideAnim.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click outside → dismiss
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: root.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: panel
|
||||||
|
|
||||||
|
x: Math.max(0, Math.min(
|
||||||
|
Math.round(root.anchorX - contentCol.width / 2),
|
||||||
|
root.width - contentCol.width
|
||||||
|
))
|
||||||
|
y: 0
|
||||||
|
width: contentCol.width
|
||||||
|
height: contentCol.height
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
// Eat clicks inside the panel
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: M.Theme.base01
|
||||||
|
opacity: Math.max(M.Theme.barOpacity, 0.85)
|
||||||
|
topLeftRadius: 0
|
||||||
|
topRightRadius: 0
|
||||||
|
bottomLeftRadius: M.Theme.radius
|
||||||
|
bottomRightRadius: M.Theme.radius
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: contentCol
|
||||||
|
width: root.panelWidth
|
||||||
|
topPadding: 4
|
||||||
|
bottomPadding: 4
|
||||||
|
spacing: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
id: showAnim
|
||||||
|
NumberAnimation { target: panel; property: "opacity"; from: 0; to: 1; duration: 150; easing.type: Easing.OutCubic }
|
||||||
|
NumberAnimation { target: panel; property: "y"; from: -panel.height; to: 0; duration: 200; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
id: hideAnim
|
||||||
|
NumberAnimation { target: panel; property: "opacity"; to: 0; duration: 150; easing.type: Easing.InCubic }
|
||||||
|
NumberAnimation { target: panel; property: "y"; to: -panel.height; duration: 150; easing.type: Easing.InCubic }
|
||||||
|
onFinished: root.dismissed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,7 +27,7 @@ M.BarIcon {
|
||||||
sourceComponent: M.PowerMenu {
|
sourceComponent: M.PowerMenu {
|
||||||
screen: root.bar.screen
|
screen: root.bar.screen
|
||||||
anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)
|
anchorX: root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)
|
||||||
onMenuClosed: menuLoader.active = false
|
onDismissed: menuLoader.active = false
|
||||||
onRunCommand: cmd => {
|
onRunCommand: cmd => {
|
||||||
runner.command = cmd;
|
runner.command = cmd;
|
||||||
runner.running = true;
|
runner.running = true;
|
||||||
|
|
|
||||||
|
|
@ -1,152 +1,73 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import "." as M
|
import "." as M
|
||||||
|
|
||||||
PanelWindow {
|
M.PopupPanel {
|
||||||
id: menuWindow
|
id: menuWindow
|
||||||
|
|
||||||
required property var screen
|
panelWidth: 180
|
||||||
required property real anchorX
|
|
||||||
|
|
||||||
signal menuClosed
|
|
||||||
signal runCommand(var cmd)
|
signal runCommand(var cmd)
|
||||||
|
|
||||||
readonly property bool _isNiri: Quickshell.env("NIRI_SOCKET") !== ""
|
readonly property bool _isNiri: Quickshell.env("NIRI_SOCKET") !== ""
|
||||||
|
|
||||||
function _run(cmd) {
|
function _run(cmd) {
|
||||||
runCommand(cmd);
|
runCommand(cmd);
|
||||||
menuClosed();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
visible: true
|
Repeater {
|
||||||
color: "transparent"
|
model: [
|
||||||
|
{ label: "Lock", icon: "\uF023", cmd: ["loginctl", "lock-session"], color: M.Theme.base0D },
|
||||||
|
{ label: "Suspend", icon: "\uF186", cmd: ["systemctl", "suspend"], color: M.Theme.base0E },
|
||||||
|
{ label: "Logout", icon: "\uF2F5", cmd: menuWindow._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""], color: M.Theme.base0A },
|
||||||
|
{ label: "Reboot", icon: "\uF021", cmd: ["systemctl", "reboot"], color: M.Theme.base09 },
|
||||||
|
{ label: "Shutdown", icon: "\uF011", cmd: ["systemctl", "poweroff"], color: M.Theme.base08 }
|
||||||
|
]
|
||||||
|
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
delegate: Item {
|
||||||
WlrLayershell.exclusiveZone: 0
|
id: entry
|
||||||
WlrLayershell.namespace: "nova-powermenu"
|
|
||||||
|
|
||||||
anchors.top: true
|
required property var modelData
|
||||||
anchors.left: true
|
required property int index
|
||||||
anchors.right: true
|
|
||||||
anchors.bottom: true
|
|
||||||
|
|
||||||
MouseArea {
|
width: menuWindow.panelWidth
|
||||||
anchors.fill: parent
|
height: 32
|
||||||
onClicked: menuWindow.menuClosed()
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
Rectangle {
|
||||||
id: panel
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 4
|
||||||
|
anchors.rightMargin: 4
|
||||||
|
color: entryArea.containsMouse ? M.Theme.base02 : "transparent"
|
||||||
|
radius: M.Theme.radius
|
||||||
|
}
|
||||||
|
|
||||||
x: Math.max(0, Math.min(Math.round(menuWindow.anchorX - menuCol.width / 2), menuWindow.width - menuCol.width))
|
Text {
|
||||||
y: 0
|
id: entryIcon
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 12
|
||||||
|
text: entry.modelData.icon
|
||||||
|
color: entry.modelData.color
|
||||||
|
font.pixelSize: M.Theme.fontSize + 1
|
||||||
|
font.family: M.Theme.iconFontFamily
|
||||||
|
}
|
||||||
|
|
||||||
width: menuCol.width
|
Text {
|
||||||
height: menuCol.height
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: entryIcon.right
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
text: entry.modelData.label
|
||||||
|
color: M.Theme.base05
|
||||||
|
font.pixelSize: M.Theme.fontSize
|
||||||
|
font.family: M.Theme.fontFamily
|
||||||
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
id: entryArea
|
||||||
}
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
Rectangle {
|
onClicked: menuWindow._run(entry.modelData.cmd)
|
||||||
anchors.fill: parent
|
|
||||||
color: M.Theme.base01
|
|
||||||
opacity: Math.max(M.Theme.barOpacity, 0.85)
|
|
||||||
topLeftRadius: 0
|
|
||||||
topRightRadius: 0
|
|
||||||
bottomLeftRadius: M.Theme.radius
|
|
||||||
bottomRightRadius: M.Theme.radius
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: menuCol
|
|
||||||
|
|
||||||
width: 180
|
|
||||||
topPadding: 4
|
|
||||||
bottomPadding: 4
|
|
||||||
spacing: 2
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: [
|
|
||||||
{
|
|
||||||
label: "Lock",
|
|
||||||
icon: "\uF023",
|
|
||||||
cmd: ["loginctl", "lock-session"],
|
|
||||||
color: M.Theme.base0D
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Suspend",
|
|
||||||
icon: "\uF186",
|
|
||||||
cmd: ["systemctl", "suspend"],
|
|
||||||
color: M.Theme.base0E
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Logout",
|
|
||||||
icon: "\uF2F5",
|
|
||||||
cmd: menuWindow._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""],
|
|
||||||
color: M.Theme.base0A
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Reboot",
|
|
||||||
icon: "\uF021",
|
|
||||||
cmd: ["systemctl", "reboot"],
|
|
||||||
color: M.Theme.base09
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Shutdown",
|
|
||||||
icon: "\uF011",
|
|
||||||
cmd: ["systemctl", "poweroff"],
|
|
||||||
color: M.Theme.base08
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
delegate: Item {
|
|
||||||
id: entry
|
|
||||||
|
|
||||||
required property var modelData
|
|
||||||
required property int index
|
|
||||||
|
|
||||||
width: menuCol.width
|
|
||||||
height: 32
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: 4
|
|
||||||
anchors.rightMargin: 4
|
|
||||||
color: entryArea.containsMouse ? M.Theme.base02 : "transparent"
|
|
||||||
radius: M.Theme.radius
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: entryIcon
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: 12
|
|
||||||
text: entry.modelData.icon
|
|
||||||
color: entry.modelData.color
|
|
||||||
font.pixelSize: M.Theme.fontSize + 1
|
|
||||||
font.family: M.Theme.iconFontFamily
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: entryIcon.right
|
|
||||||
anchors.leftMargin: 10
|
|
||||||
text: entry.modelData.label
|
|
||||||
color: M.Theme.base05
|
|
||||||
font.pixelSize: M.Theme.fontSize
|
|
||||||
font.family: M.Theme.fontFamily
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: entryArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
onClicked: menuWindow._run(entry.modelData.cmd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ RowLayout {
|
||||||
handle: iconItem.modelData.menu
|
handle: iconItem.modelData.menu
|
||||||
screen: root.bar.screen
|
screen: root.bar.screen
|
||||||
anchorX: iconItem.mapToGlobal(iconItem.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)
|
anchorX: iconItem.mapToGlobal(iconItem.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)
|
||||||
onMenuClosed: {
|
onDismissed: {
|
||||||
menuLoader.active = false;
|
menuLoader.active = false;
|
||||||
root._activeMenu = null;
|
root._activeMenu = null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,204 +1,137 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
|
||||||
import "." as M
|
import "." as M
|
||||||
|
|
||||||
// Per-icon context menu popup window.
|
M.PopupPanel {
|
||||||
// Covers the screen on the Overlay layer so clicking anywhere outside
|
|
||||||
// the menu panel dismisses it. Created on demand by Tray.qml delegates.
|
|
||||||
PanelWindow {
|
|
||||||
id: menuWindow
|
id: menuWindow
|
||||||
|
|
||||||
required property var handle
|
required property var handle
|
||||||
required property var screen
|
|
||||||
required property real anchorX
|
|
||||||
|
|
||||||
signal menuClosed
|
|
||||||
|
|
||||||
// Current menu level — swapped when entering/leaving submenus
|
|
||||||
property var _currentHandle: handle
|
property var _currentHandle: handle
|
||||||
property var _handleStack: []
|
property var _handleStack: []
|
||||||
|
|
||||||
visible: true
|
QsMenuOpener {
|
||||||
color: "transparent"
|
id: opener
|
||||||
|
menu: menuWindow._currentHandle
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
|
||||||
WlrLayershell.exclusiveZone: 0
|
|
||||||
WlrLayershell.namespace: "nova-traymenu"
|
|
||||||
|
|
||||||
anchors.top: true
|
|
||||||
anchors.left: true
|
|
||||||
anchors.right: true
|
|
||||||
anchors.bottom: true
|
|
||||||
|
|
||||||
// Click outside the menu panel → dismiss
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: menuWindow.menuClosed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Menu panel
|
// Back button (submenus only)
|
||||||
Item {
|
Item {
|
||||||
id: panel
|
visible: menuWindow._handleStack.length > 0
|
||||||
|
width: menuWindow.panelWidth
|
||||||
x: Math.max(0, Math.min(Math.round(menuWindow.anchorX - menuCol.width / 2), menuWindow.width - menuCol.width))
|
height: visible ? 28 : 0
|
||||||
y: 0
|
|
||||||
|
|
||||||
width: menuCol.width
|
|
||||||
height: menuCol.height
|
|
||||||
|
|
||||||
// Eat clicks inside the panel
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: M.Theme.base01
|
anchors.leftMargin: 4
|
||||||
opacity: Math.max(M.Theme.barOpacity, 0.85)
|
anchors.rightMargin: 4
|
||||||
topLeftRadius: 0
|
color: backArea.containsMouse ? M.Theme.base02 : "transparent"
|
||||||
topRightRadius: 0
|
radius: M.Theme.radius
|
||||||
bottomLeftRadius: M.Theme.radius
|
|
||||||
bottomRightRadius: M.Theme.radius
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Text {
|
||||||
id: menuCol
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 12
|
||||||
|
text: "\u2039 Back"
|
||||||
|
color: M.Theme.base05
|
||||||
|
font.pixelSize: M.Theme.fontSize
|
||||||
|
font.family: M.Theme.fontFamily
|
||||||
|
}
|
||||||
|
|
||||||
width: 220
|
MouseArea {
|
||||||
topPadding: 4
|
id: backArea
|
||||||
bottomPadding: 4
|
anchors.fill: parent
|
||||||
spacing: 2
|
hoverEnabled: true
|
||||||
|
onClicked: {
|
||||||
|
const stack = menuWindow._handleStack.slice();
|
||||||
|
menuWindow._currentHandle = stack.pop();
|
||||||
|
menuWindow._handleStack = stack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QsMenuOpener {
|
Repeater {
|
||||||
id: opener
|
model: opener.children
|
||||||
menu: menuWindow._currentHandle
|
|
||||||
|
delegate: Item {
|
||||||
|
id: entryItem
|
||||||
|
|
||||||
|
required property QsMenuEntry modelData
|
||||||
|
|
||||||
|
width: menuWindow.panelWidth
|
||||||
|
height: modelData.isSeparator ? 9 : 28
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
visible: entryItem.modelData.isSeparator
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.leftMargin: 8
|
||||||
|
anchors.rightMargin: 8
|
||||||
|
height: 1
|
||||||
|
color: M.Theme.base03
|
||||||
}
|
}
|
||||||
|
|
||||||
// Back button (submenus only)
|
Rectangle {
|
||||||
Item {
|
visible: !entryItem.modelData.isSeparator
|
||||||
visible: menuWindow._handleStack.length > 0
|
anchors.fill: parent
|
||||||
width: menuCol.width
|
anchors.leftMargin: 4
|
||||||
height: visible ? 28 : 0
|
anchors.rightMargin: 4
|
||||||
|
color: rowArea.containsMouse && entryItem.modelData.enabled ? M.Theme.base02 : "transparent"
|
||||||
Rectangle {
|
radius: M.Theme.radius
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: 4
|
|
||||||
anchors.rightMargin: 4
|
|
||||||
color: backArea.containsMouse ? M.Theme.base02 : "transparent"
|
|
||||||
radius: M.Theme.radius
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: 12
|
|
||||||
text: "\u2039 Back"
|
|
||||||
color: M.Theme.base05
|
|
||||||
font.pixelSize: M.Theme.fontSize
|
|
||||||
font.family: M.Theme.fontFamily
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: backArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
onClicked: {
|
|
||||||
const stack = menuWindow._handleStack.slice();
|
|
||||||
menuWindow._currentHandle = stack.pop();
|
|
||||||
menuWindow._handleStack = stack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Image {
|
||||||
model: opener.children
|
id: entryIcon
|
||||||
|
visible: !entryItem.modelData.isSeparator && entryItem.modelData.icon !== ""
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 12
|
||||||
|
width: M.Theme.fontSize
|
||||||
|
height: M.Theme.fontSize
|
||||||
|
source: entryItem.modelData.icon
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
|
||||||
delegate: Item {
|
Text {
|
||||||
id: entryItem
|
visible: !entryItem.modelData.isSeparator
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: entryIcon.visible ? entryIcon.right : parent.left
|
||||||
|
anchors.leftMargin: entryIcon.visible ? 6 : 12
|
||||||
|
anchors.right: entryChevron.visible ? entryChevron.left : parent.right
|
||||||
|
anchors.rightMargin: entryChevron.visible ? 4 : 12
|
||||||
|
text: entryItem.modelData.text
|
||||||
|
color: entryItem.modelData.enabled ? M.Theme.base05 : M.Theme.base03
|
||||||
|
font.pixelSize: M.Theme.fontSize
|
||||||
|
font.family: M.Theme.fontFamily
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
required property QsMenuEntry modelData
|
Text {
|
||||||
|
id: entryChevron
|
||||||
|
visible: !entryItem.modelData.isSeparator && entryItem.modelData.hasChildren
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 12
|
||||||
|
text: "\u203A"
|
||||||
|
color: entryItem.modelData.enabled ? M.Theme.base05 : M.Theme.base03
|
||||||
|
font.pixelSize: M.Theme.fontSize
|
||||||
|
font.family: M.Theme.fontFamily
|
||||||
|
}
|
||||||
|
|
||||||
width: menuCol.width
|
MouseArea {
|
||||||
height: modelData.isSeparator ? 9 : 28
|
id: rowArea
|
||||||
|
anchors.fill: parent
|
||||||
// Separator
|
hoverEnabled: true
|
||||||
Rectangle {
|
enabled: !entryItem.modelData.isSeparator && entryItem.modelData.enabled
|
||||||
visible: entryItem.modelData.isSeparator
|
onClicked: {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
if (entryItem.modelData.hasChildren) {
|
||||||
anchors.left: parent.left
|
menuWindow._handleStack = menuWindow._handleStack.concat([menuWindow._currentHandle]);
|
||||||
anchors.right: parent.right
|
menuWindow._currentHandle = entryItem.modelData;
|
||||||
anchors.leftMargin: 8
|
} else {
|
||||||
anchors.rightMargin: 8
|
entryItem.modelData.triggered();
|
||||||
height: 1
|
menuWindow.dismiss();
|
||||||
color: M.Theme.base03
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hover highlight
|
|
||||||
Rectangle {
|
|
||||||
visible: !entryItem.modelData.isSeparator
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: 4
|
|
||||||
anchors.rightMargin: 4
|
|
||||||
color: rowArea.containsMouse && entryItem.modelData.enabled ? M.Theme.base02 : "transparent"
|
|
||||||
radius: M.Theme.radius
|
|
||||||
}
|
|
||||||
|
|
||||||
// Icon
|
|
||||||
Image {
|
|
||||||
id: entryIcon
|
|
||||||
visible: !entryItem.modelData.isSeparator && entryItem.modelData.icon !== ""
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: 12
|
|
||||||
width: M.Theme.fontSize
|
|
||||||
height: M.Theme.fontSize
|
|
||||||
source: entryItem.modelData.icon
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
}
|
|
||||||
|
|
||||||
// Label
|
|
||||||
Text {
|
|
||||||
visible: !entryItem.modelData.isSeparator
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: entryIcon.visible ? entryIcon.right : parent.left
|
|
||||||
anchors.leftMargin: entryIcon.visible ? 6 : 12
|
|
||||||
anchors.right: entryChevron.visible ? entryChevron.left : parent.right
|
|
||||||
anchors.rightMargin: entryChevron.visible ? 4 : 12
|
|
||||||
text: entryItem.modelData.text
|
|
||||||
color: entryItem.modelData.enabled ? M.Theme.base05 : M.Theme.base03
|
|
||||||
font.pixelSize: M.Theme.fontSize
|
|
||||||
font.family: M.Theme.fontFamily
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submenu chevron
|
|
||||||
Text {
|
|
||||||
id: entryChevron
|
|
||||||
visible: !entryItem.modelData.isSeparator && entryItem.modelData.hasChildren
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 12
|
|
||||||
text: "\u203A"
|
|
||||||
color: entryItem.modelData.enabled ? M.Theme.base05 : M.Theme.base03
|
|
||||||
font.pixelSize: M.Theme.fontSize
|
|
||||||
font.family: M.Theme.fontFamily
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: rowArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
enabled: !entryItem.modelData.isSeparator && entryItem.modelData.enabled
|
|
||||||
onClicked: {
|
|
||||||
if (entryItem.modelData.hasChildren) {
|
|
||||||
menuWindow._handleStack = menuWindow._handleStack.concat([menuWindow._currentHandle]);
|
|
||||||
menuWindow._currentHandle = entryItem.modelData;
|
|
||||||
} else {
|
|
||||||
entryItem.modelData.triggered();
|
|
||||||
menuWindow.menuClosed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ Clock 1.0 Clock.qml
|
||||||
Volume 1.0 Volume.qml
|
Volume 1.0 Volume.qml
|
||||||
Tray 1.0 Tray.qml
|
Tray 1.0 Tray.qml
|
||||||
TrayMenu 1.0 TrayMenu.qml
|
TrayMenu 1.0 TrayMenu.qml
|
||||||
|
PopupPanel 1.0 PopupPanel.qml
|
||||||
PowerMenu 1.0 PowerMenu.qml
|
PowerMenu 1.0 PowerMenu.qml
|
||||||
ScreenCorners 1.0 ScreenCorners.qml
|
ScreenCorners 1.0 ScreenCorners.qml
|
||||||
Osd 1.0 Osd.qml
|
Osd 1.0 Osd.qml
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue