added three new modules (Crypto.qml, Battery.qml, Network.qml), improved Stats.qml, improved Tray.qml, optimized code in general, added a polkit agent, configurations change (check configs)
This commit is contained in:
@@ -13,9 +13,9 @@ Item {
|
||||
property real panelRadius: Cfg.Config.radius / 2
|
||||
property int borderWidth: Cfg.Config.panelBorderWidth
|
||||
|
||||
property bool isTop: true
|
||||
property var targetScreen: null
|
||||
property string barSide: "right"
|
||||
property bool isTop: true
|
||||
|
||||
readonly property var t: Cfg.Config.theme
|
||||
|
||||
@@ -23,14 +23,24 @@ Item {
|
||||
property bool manuallyExpanded: false
|
||||
property var menuWindow: null
|
||||
|
||||
readonly property bool effectiveExpanded: expanded || trayMenuPopup.popupOpen
|
||||
|
||||
implicitWidth: bgRect.width
|
||||
implicitHeight: bgRect.height
|
||||
|
||||
readonly property color tmBg: t.trayMenuBg
|
||||
readonly property color tmBorder: t.trayMenuBorder
|
||||
readonly property color tmText: t.trayMenuText
|
||||
readonly property color tmDim: t.trayMenuDim
|
||||
readonly property color tmHover: t.trayMenuHover
|
||||
readonly property color tmCheck: t.trayMenuCheck
|
||||
readonly property color tmSeparator: t.trayMenuSeparator
|
||||
|
||||
Rectangle {
|
||||
id: bgRect
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
height: Cfg.Config.trayHeight
|
||||
height: parent.height
|
||||
width: mainRow.width
|
||||
radius: root.panelRadius
|
||||
|
||||
@@ -41,8 +51,8 @@ Item {
|
||||
Behavior on color { ColorAnimation { duration: 150 } }
|
||||
Behavior on border.color { ColorAnimation { duration: 150 } }
|
||||
|
||||
HoverHandler {
|
||||
id: bgHover
|
||||
HoverHandler {
|
||||
id: bgHover
|
||||
onHoveredChanged: {
|
||||
if (!root.manuallyExpanded) {
|
||||
root.expanded = hovered;
|
||||
@@ -54,21 +64,21 @@ Item {
|
||||
id: mainRow
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
leftPadding: root.expanded && root.barSide === "right" ? 8 : 0
|
||||
rightPadding: root.expanded && root.barSide === "left" ? 8 : 0
|
||||
leftPadding: root.effectiveExpanded && root.barSide === "right" ? 8 : 0
|
||||
rightPadding: root.effectiveExpanded && root.barSide === "left" ? 8 : 0
|
||||
|
||||
Behavior on leftPadding { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } }
|
||||
Behavior on rightPadding { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } }
|
||||
|
||||
layoutDirection: root.barSide === "left" ? Qt.LeftToRight : Qt.RightToLeft
|
||||
spacing: root.expanded ? 4 : 0
|
||||
spacing: root.effectiveExpanded ? 4 : 0
|
||||
|
||||
Behavior on spacing { NumberAnimation { duration: 180; easing.type: Easing.OutCubic } }
|
||||
|
||||
Item {
|
||||
id: toggleArea
|
||||
width: Cfg.Config.trayHeight
|
||||
height: Cfg.Config.trayHeight
|
||||
width: Cfg.Config.trayToggleSize
|
||||
height: Cfg.Config.trayToggleSize
|
||||
z: 10
|
||||
|
||||
TapHandler {
|
||||
@@ -80,11 +90,11 @@ Item {
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: root.expanded
|
||||
text: root.effectiveExpanded
|
||||
? (root.barSide === "left" ? "" : "")
|
||||
: (root.barSide === "left" ? "" : "")
|
||||
color: root.t.trayIcon
|
||||
font.pixelSize: Cfg.Config.trayHeight * 0.55
|
||||
font.pixelSize: Cfg.Config.trayToggleSize * 0.55
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,9 +104,9 @@ Item {
|
||||
clip: true
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
width: root.expanded ? implicitWidth : 0
|
||||
opacity: root.expanded ? 1 : 0
|
||||
|
||||
width: root.effectiveExpanded ? implicitWidth : 0
|
||||
opacity: root.effectiveExpanded ? 1 : 0
|
||||
|
||||
Behavior on width { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } }
|
||||
Behavior on opacity { NumberAnimation { duration: 150 } }
|
||||
|
||||
@@ -122,7 +132,9 @@ Item {
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
item.secondaryActivate()
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
menuAnchor.open()
|
||||
if (item.hasMenu) {
|
||||
trayMenuPopup.open(item, iconDelegate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,22 +147,462 @@ Item {
|
||||
anchors.fill: parent
|
||||
source: item.icon
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QsMenuAnchor {
|
||||
id: menuAnchor
|
||||
menu: item.menu
|
||||
anchor.window: root.menuWindow
|
||||
anchor.adjustment: PopupAdjustment.Flip
|
||||
anchor.onAnchoring: {
|
||||
if (!root.menuWindow) return
|
||||
const global = iconDelegate.mapToGlobal(0, iconDelegate.height)
|
||||
const local = root.menuWindow.contentItem.mapFromGlobal(
|
||||
global.x, global.y
|
||||
)
|
||||
menuAnchor.anchor.rect = Qt.rect(
|
||||
local.x, local.y,
|
||||
iconDelegate.width, 0
|
||||
)
|
||||
|
||||
|
||||
|
||||
PanelWindow {
|
||||
id: trayMenuPopup
|
||||
screen: root.targetScreen
|
||||
visible: false
|
||||
color: "transparent"
|
||||
|
||||
property bool popupOpen: false
|
||||
property bool _pendingOpen: false
|
||||
property var activeTrayItem: null
|
||||
property var activeDelegate: null
|
||||
|
||||
function open(item, delegate) {
|
||||
if (popupOpen) close()
|
||||
hideTimer.stop()
|
||||
_pendingOpen = false
|
||||
activeTrayItem = item
|
||||
activeDelegate = delegate
|
||||
rootMenuOpener.menu = item.menu
|
||||
visible = true
|
||||
|
||||
|
||||
if (menuCol.height > 0) {
|
||||
popupOpen = true
|
||||
} else {
|
||||
_pendingOpen = true
|
||||
openFallbackTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
_pendingOpen = false
|
||||
openFallbackTimer.stop()
|
||||
popupOpen = false
|
||||
hideTimer.restart()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Connections {
|
||||
target: menuCol
|
||||
function onHeightChanged() {
|
||||
if (trayMenuPopup._pendingOpen && menuCol.height > 0) {
|
||||
trayMenuPopup._pendingOpen = false
|
||||
openFallbackTimer.stop()
|
||||
trayMenuPopup.popupOpen = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Timer {
|
||||
id: openFallbackTimer
|
||||
interval: 400
|
||||
onTriggered: {
|
||||
if (trayMenuPopup._pendingOpen) {
|
||||
trayMenuPopup._pendingOpen = false
|
||||
trayMenuPopup.popupOpen = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: hideTimer
|
||||
interval: Cfg.Config.popupAnimDuration + 70
|
||||
onTriggered: {
|
||||
trayMenuPopup.visible = false
|
||||
rootMenuOpener.menu = null
|
||||
trayMenuPopup.activeTrayItem = null
|
||||
trayMenuPopup.activeDelegate = null
|
||||
}
|
||||
}
|
||||
|
||||
anchors { top: true; bottom: true; left: true; right: true }
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
WlrLayershell.namespace: "main-shell-tray-menu"
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
mask: popupOpen ? null : _trayMenuNoInput
|
||||
Region { id: _trayMenuNoInput }
|
||||
|
||||
TapHandler { onTapped: trayMenuPopup.close() }
|
||||
|
||||
QsMenuOpener { id: rootMenuOpener }
|
||||
|
||||
|
||||
Item {
|
||||
id: menuCardWrapper
|
||||
readonly property int cardW: 220
|
||||
readonly property int pad: 10
|
||||
|
||||
|
||||
x: {
|
||||
if (!trayMenuPopup.activeDelegate)
|
||||
return (parent.width - cardW) / 2
|
||||
var gp = trayMenuPopup.activeDelegate.mapToGlobal(0, 0)
|
||||
var cx = gp.x + trayMenuPopup.activeDelegate.width / 2
|
||||
return Math.max(pad,
|
||||
Math.min(cx - cardW / 2, parent.width - cardW - pad))
|
||||
}
|
||||
|
||||
width: cardW
|
||||
clip: true
|
||||
|
||||
|
||||
anchors.top: root.isTop ? parent.top : undefined
|
||||
anchors.bottom: root.isTop ? undefined : parent.bottom
|
||||
anchors.topMargin: root.isTop ? (Cfg.Config.barHeight + 8) : 0
|
||||
anchors.bottomMargin: root.isTop ? 0 : (Cfg.Config.barHeight + 8)
|
||||
height: parent.height - Cfg.Config.barHeight - 8
|
||||
|
||||
Rectangle {
|
||||
id: menuCard
|
||||
width: parent.width
|
||||
height: menuCol.height + 12
|
||||
|
||||
|
||||
anchors.top: root.isTop ? parent.top : undefined
|
||||
anchors.bottom: root.isTop ? undefined : parent.bottom
|
||||
|
||||
transform: Translate {
|
||||
y: trayMenuPopup.popupOpen ? 0
|
||||
: (root.isTop ? -menuCard.height : menuCard.height)
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: Cfg.Config.popupAnimDuration
|
||||
easing.type: Easing.OutExpo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
opacity: trayMenuPopup.popupOpen ? 1 : 0
|
||||
Behavior on opacity { NumberAnimation { duration: 200 } }
|
||||
|
||||
color: root.tmBg
|
||||
radius: Cfg.Config.popupRadius
|
||||
border.color: root.tmBorder
|
||||
border.width: Cfg.Config.popupBorderWidth
|
||||
|
||||
Column {
|
||||
id: menuCol
|
||||
anchors { left: parent.left; right: parent.right; top: parent.top }
|
||||
anchors.margins: 6
|
||||
spacing: 0
|
||||
|
||||
Repeater {
|
||||
model: rootMenuOpener.children
|
||||
|
||||
delegate: Item {
|
||||
id: menuDelegate
|
||||
required property var modelData
|
||||
property bool isSep: modelData.isSeparator
|
||||
|
||||
width: menuCol.width
|
||||
height: isSep ? 5 : 32
|
||||
|
||||
Rectangle {
|
||||
visible: isSep
|
||||
anchors {
|
||||
left: parent.left; right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
anchors.leftMargin: 8
|
||||
anchors.rightMargin: 8
|
||||
height: 1
|
||||
color: root.tmSeparator
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: itemBg
|
||||
visible: !isSep
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
radius: 10
|
||||
property bool active: itemMouse.containsMouse
|
||||
|| (submenuCard.visible
|
||||
&& trayMenuPopup._submenuParentRef === menuDelegate)
|
||||
color: active ? root.tmHover : "transparent"
|
||||
Behavior on color { ColorAnimation { duration: 120 } }
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 8
|
||||
anchors.rightMargin: 8
|
||||
spacing: 8
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: 16
|
||||
Layout.preferredHeight: 16
|
||||
visible: !isSep
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: modelData.buttonType === QsMenuButtonType.CheckBox
|
||||
&& modelData.checkState === Qt.Checked
|
||||
text: "✓"
|
||||
color: root.tmCheck
|
||||
font.pixelSize: 14
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: modelData.buttonType === QsMenuButtonType.RadioButton
|
||||
&& modelData.checkState === Qt.Checked
|
||||
text: "●"
|
||||
color: root.tmCheck
|
||||
font.pixelSize: 9
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: modelData.buttonType === QsMenuButtonType.RadioButton
|
||||
&& modelData.checkState !== Qt.Checked
|
||||
text: "○"
|
||||
color: root.tmDim
|
||||
font.pixelSize: 11
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
visible: !isSep && modelData.icon !== ""
|
||||
source: modelData.icon
|
||||
width: 16; height: 16
|
||||
sourceSize: Qt.size(16, 16)
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
|
||||
Text {
|
||||
text: modelData.text
|
||||
color: modelData.enabled ? root.tmText : root.tmDim
|
||||
font.pixelSize: 13
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Text {
|
||||
visible: !isSep && modelData.hasChildren
|
||||
text: "▶"
|
||||
color: root.tmDim
|
||||
font.pixelSize: 9
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: itemMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
enabled: !isSep && modelData.enabled
|
||||
|
||||
onClicked: {
|
||||
if (modelData.hasChildren) {
|
||||
closeSubmenuTimer.stop()
|
||||
submenuDelayTimer.itemRef = menuDelegate
|
||||
submenuDelayTimer.restart()
|
||||
} else {
|
||||
modelData.triggered()
|
||||
trayMenuPopup.close()
|
||||
}
|
||||
}
|
||||
onEntered: {
|
||||
if (modelData.hasChildren) {
|
||||
closeSubmenuTimer.stop()
|
||||
submenuDelayTimer.itemRef = menuDelegate
|
||||
submenuDelayTimer.restart()
|
||||
} else {
|
||||
closeSubmenuTimer.stop()
|
||||
submenuCard.visible = false
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
if (modelData.hasChildren)
|
||||
closeSubmenuTimer.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
property var _submenuParentRef: null
|
||||
|
||||
QsMenuOpener { id: subMenuOpener }
|
||||
|
||||
Timer {
|
||||
id: submenuDelayTimer
|
||||
interval: 250
|
||||
property var itemRef: null
|
||||
onTriggered: {
|
||||
if (!itemRef) return
|
||||
var entry = itemRef.modelData
|
||||
if (!entry || !entry.hasChildren) return
|
||||
subMenuOpener.menu = entry
|
||||
trayMenuPopup._submenuParentRef = itemRef
|
||||
submenuCard.visible = true
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: closeSubmenuTimer
|
||||
interval: 300
|
||||
onTriggered: {
|
||||
if (!submenuCard.containsMouse) {
|
||||
submenuCard.visible = false
|
||||
subMenuOpener.menu = null
|
||||
trayMenuPopup._submenuParentRef = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: submenuCard
|
||||
visible: false
|
||||
property bool containsMouse: false
|
||||
|
||||
property int subW: Math.max(submenuCol.width, 180)
|
||||
|
||||
x: {
|
||||
if (!trayMenuPopup._submenuParentRef) return 0
|
||||
var pItem = trayMenuPopup._submenuParentRef
|
||||
var gp = pItem.mapToGlobal(0, 0)
|
||||
var lp = trayMenuPopup.contentItem.mapFromGlobal(gp.x, gp.y)
|
||||
var fromLeft = lp.x + pItem.width + 4
|
||||
if (fromLeft + subW + 10 > trayMenuPopup.contentItem.width)
|
||||
return Math.max(2, lp.x - subW - 4)
|
||||
return fromLeft
|
||||
}
|
||||
|
||||
y: {
|
||||
if (!trayMenuPopup._submenuParentRef) return 0
|
||||
var pItem = trayMenuPopup._submenuParentRef
|
||||
var gp = pItem.mapToGlobal(0, 0)
|
||||
var lp = trayMenuPopup.contentItem.mapFromGlobal(gp.x, gp.y)
|
||||
return Math.max(2, lp.y - 2)
|
||||
}
|
||||
|
||||
width: subW
|
||||
height: submenuCol.height + 12
|
||||
|
||||
color: root.tmBg
|
||||
radius: Cfg.Config.popupRadius
|
||||
border.color: root.tmBorder
|
||||
border.width: Cfg.Config.popupBorderWidth
|
||||
|
||||
HoverHandler {
|
||||
onHoveredChanged: {
|
||||
submenuCard.containsMouse = hovered
|
||||
if (!hovered)
|
||||
closeSubmenuTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: submenuCol
|
||||
anchors { left: parent.left; right: parent.right; top: parent.top }
|
||||
anchors.margins: 6
|
||||
spacing: 0
|
||||
|
||||
Repeater {
|
||||
model: subMenuOpener.children
|
||||
|
||||
delegate: Item {
|
||||
required property var modelData
|
||||
property bool isSep: modelData.isSeparator
|
||||
|
||||
width: submenuCol.width
|
||||
height: isSep ? 5 : 32
|
||||
|
||||
Rectangle {
|
||||
visible: isSep
|
||||
anchors {
|
||||
left: parent.left; right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
anchors.leftMargin: 8; anchors.rightMargin: 8
|
||||
height: 1
|
||||
color: root.tmSeparator
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: subBg
|
||||
visible: !isSep
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
radius: 10
|
||||
color: subMouse.containsMouse ? root.tmHover : "transparent"
|
||||
Behavior on color { ColorAnimation { duration: 120 } }
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 8; anchors.rightMargin: 8
|
||||
spacing: 8
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: 16
|
||||
Layout.preferredHeight: 16
|
||||
visible: !isSep
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: modelData.buttonType === QsMenuButtonType.CheckBox
|
||||
&& modelData.checkState === Qt.Checked
|
||||
text: "✓"; color: root.tmCheck
|
||||
font.pixelSize: 14
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: modelData.buttonType === QsMenuButtonType.RadioButton
|
||||
&& modelData.checkState === Qt.Checked
|
||||
text: "●"; color: root.tmCheck
|
||||
font.pixelSize: 9
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: modelData.buttonType === QsMenuButtonType.RadioButton
|
||||
&& modelData.checkState !== Qt.Checked
|
||||
text: "○"; color: root.tmDim
|
||||
font.pixelSize: 11
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
visible: !isSep && modelData.icon !== ""
|
||||
source: modelData.icon
|
||||
width: 16; height: 16
|
||||
sourceSize: Qt.size(16, 16)
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
|
||||
Text {
|
||||
text: modelData.text
|
||||
color: modelData.enabled ? root.tmText : root.tmDim
|
||||
font.pixelSize: 13
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: subMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
enabled: !isSep && modelData.enabled
|
||||
onClicked: {
|
||||
modelData.triggered()
|
||||
trayMenuPopup.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user