waffles: power menu and user account menu

This commit is contained in:
end-4
2025-12-01 13:27:01 +01:00
parent 61b5cf8cb6
commit 8d2c8bd38e
13 changed files with 611 additions and 61 deletions
@@ -7,6 +7,10 @@ import qs.services
Singleton {
id: root
function pathForName(iconName) {
return Quickshell.shellPath(`assets/icons/fluent/${iconName}.svg`);
}
function wifiIconForStrength(strength) {
if (strength > 75)
return "wifi-1";
@@ -0,0 +1,83 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Menu {
id: root
property bool downDirection: false
property bool hasIcons: false // TODO: implement
implicitWidth: background.implicitWidth + root.padding * 2
implicitHeight: background.implicitHeight + root.padding * 2
padding: 3
property real sourceEdgeMargin: -implicitHeight
clip: true
enter: Transition {
NumberAnimation {
property: "sourceEdgeMargin"
from: -root.implicitHeight
to: root.padding
duration: 200
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
}
}
exit: Transition {
NumberAnimation {
property: "sourceEdgeMargin"
from: root.padding
to: -root.implicitHeight
duration: 150
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut
}
}
background: WPane {
anchors {
left: parent.left
right: parent.right
top: root.downDirection ? parent.top : undefined
bottom: root.downDirection ? undefined : parent.bottom
margins: root.padding
topMargin: root.downDirection ? root.sourceEdgeMargin : root.padding
bottomMargin: root.downDirection ? root.padding : root.sourceEdgeMargin
}
contentItem: Rectangle {
color: Looks.colors.bg1Base
implicitWidth: menuListView.implicitWidth + root.padding * 2
implicitHeight: root.contentItem.implicitHeight + root.padding * 2
}
}
contentItem: ListView {
id: menuListView
anchors {
left: parent.left
right: parent.right
top: root.downDirection ? parent.top : undefined
bottom: root.downDirection ? undefined : parent.bottom
margins: root.padding * 2
topMargin: root.downDirection ? root.sourceEdgeMargin : root.padding
bottomMargin: root.downDirection ? root.padding : root.sourceEdgeMargin
}
implicitHeight: contentHeight
implicitWidth: Array.from({
length: count
}, (_, i) => itemAtIndex(i)?.implicitWidth ?? 0).reduce((a, b) => a > b ? a : b)
model: root.contentModel
}
delegate: WMenuItem {
id: menuItemDelegate
}
}
@@ -0,0 +1,93 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
MenuItem {
id: root
property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
property color colBackgroundHover: Looks.colors.bg2Hover
property color colBackgroundActive: Looks.colors.bg2Active
property color colBackgroundToggled: Looks.colors.accent
property color colBackgroundToggledHover: Looks.colors.accentHover
property color colBackgroundToggledActive: Looks.colors.accentActive
property color colForeground: Looks.colors.fg
property color colForegroundToggled: Looks.colors.accentFg
property color colForegroundDisabled: ColorUtils.transparentize(Looks.colors.subfg, 0.4)
property color color: {
if (!root.enabled)
return colBackground;
if (root.checked) {
if (root.down) {
return root.colBackgroundToggledActive;
} else if (root.hovered) {
return root.colBackgroundToggledHover;
} else {
return root.colBackgroundToggled;
}
}
if (root.down) {
return root.colBackgroundActive;
} else if (root.hovered) {
return root.colBackgroundHover;
} else {
return root.colBackground;
}
}
property color fgColor: {
if (root.checked)
return root.colForegroundToggled;
if (root.enabled)
return root.colForeground;
return root.colForegroundDisabled;
}
property real inset: 2
topInset: inset
bottomInset: inset
leftInset: inset
rightInset: inset
horizontalPadding: 11
background: Rectangle {
id: backgroundRect
radius: Looks.radius.medium
color: root.color
Behavior on color {
animation: Looks.transition.color.createObject(this)
}
}
implicitHeight: Math.max(28, contentItem.implicitHeight) + topInset + bottomInset
implicitWidth: contentItem.implicitWidth + leftInset + rightInset + leftPadding + rightPadding
contentItem: RowLayout {
id: contentLayout
spacing: 12
FluentIcon {
id: buttonIcon
monochrome: true
implicitSize: 20
Layout.fillWidth: false
Layout.alignment: Qt.AlignVCenter
color: root.fgColor
visible: root.icon.name !== "";
icon: root.icon.name
}
WText {
id: buttonText
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
text: root.text
horizontalAlignment: Text.AlignLeft
font.pixelSize: Looks.font.pixelSize.large
color: root.fgColor
}
}
}
@@ -10,7 +10,7 @@ import qs.modules.waffle.looks
Item {
id: root
required property Item contentItem
property Item contentItem
property real radius: Looks.radius.large
property alias border: borderRect
property alias borderColor: borderRect.border.color
@@ -25,6 +25,8 @@ StyledToolTip {
verticalPadding: 8
horizontalPadding: 10
delay: 400
contentItem: WToolTipContent {
id: tooltipContent
realContentItem: root.realContentItem
@@ -6,6 +6,7 @@ Item {
id: root
anchors.centerIn: parent
required property Item realContentItem
property alias radius: realContent.radius
property real verticalPadding: 8
property real horizontalPadding: 10
implicitWidth: realContent.implicitWidth + 2 * 2
@@ -0,0 +1,27 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks
StyledImage {
id: avatar
Layout.alignment: Qt.AlignTop
sourceSize: Qt.size(32, 32)
source: Directories.userAvatarPathAccountsService
fallbacks: [Directories.userAvatarPathRicersAndWeirdSystems, Directories.userAvatarPathRicersAndWeirdSystems2]
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Circle {
diameter: avatar.height
}
}
}