wbar: tray

This commit is contained in:
end-4
2025-11-16 12:05:09 +01:00
parent c71a2498d0
commit 5b69995945
12 changed files with 264 additions and 40 deletions
@@ -0,0 +1 @@
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M4.293 8.293a1 1 0 0 1 1.414 0L12 14.586l6.293-6.293a1 1 0 1 1 1.414 1.414l-7 7a1 1 0 0 1-1.414 0l-7-7a1 1 0 0 1 0-1.414Z" fill="#212121"/></svg>

After

Width:  |  Height:  |  Size: 249 B

@@ -75,7 +75,7 @@ BarButton {
component BackgroundAcrylicRectangle: AcrylicRectangle {
shiny: ((root.hovered && !root.down) || root.checked)
color: root.colBackground
color: root.color
border.width: 1
border.color: root.colBackgroundBorder
@@ -11,8 +11,11 @@ Button {
property var altAction: () => {}
property var middleClickAction: () => {}
property color colBackground
property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
property color colBackgroundHover: Looks.colors.bg1Hover
property color colBackgroundActive: Looks.colors.bg1Active
property color colBackgroundBorder
property color color
Layout.fillHeight: true
topInset: 4
bottomInset: 4
@@ -37,14 +40,14 @@ Button {
}
}
colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, root.checked ? Looks.contentTransparency : 1)
colBackground: {
colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, (root.checked || root.hovered) ? Looks.contentTransparency : 1)
color: {
if (root.down) {
return Looks.colors.bg1Active
return root.colBackgroundActive
} else if ((root.hovered && !root.down) || root.checked) {
return Looks.colors.bg1Hover
return root.colBackgroundHover
} else {
return ColorUtils.transparentize(Looks.colors.bg1)
return root.colBackground
}
}
@@ -66,7 +69,7 @@ Button {
background: AcrylicRectangle {
shiny: ((root.hovered && !root.down) || root.checked)
color: root.colBackground
color: root.color
radius: Looks.radius.medium
border.width: 1
border.color: root.colBackgroundBorder
@@ -0,0 +1,40 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.waffle.looks
import qs.modules.waffle.bar
BarButton {
id: root
property alias iconName: iconContent.icon
property alias iconSource: iconContent.source
property alias iconSize: iconContent.implicitSize
property alias iconRotation: iconContent.rotation
property alias iconMonochrome: iconContent.monochrome
property alias tooltipText: tooltip.text
property alias overlayingItems: iconContent.data
implicitWidth: 32
contentItem: Item {
anchors.centerIn: parent
implicitWidth: iconContent.implicitWidth
implicitHeight: iconContent.implicitHeight
FluentIcon {
id: iconContent
anchors.centerIn: parent
implicitSize: 16
icon: root.iconName
monochrome: false
}
}
BarToolTip {
id: tooltip
extraVisibleCondition: root.shouldShowTooltip && text !== ""
}
}
@@ -13,12 +13,23 @@ Loader {
required property var contentItem
property real padding: Looks.radius.large - Looks.radius.medium
property bool noSmoothClosing: !Config.options.waffles.smootherAnimations
property bool closeOnFocusLost: true
signal focusCleared()
property Item anchorItem: parent
property real visualMargin: 12
readonly property bool barAtBottom: Config.options.waffles.bar.bottom
property real ambientShadowWidth: 1
onFocusCleared: {
if (!root.closeOnFocusLost) return;
root.close()
}
function grabFocus() { // Doesn't work
item.grabFocus();
}
function close() {
item.close();
}
@@ -43,9 +54,7 @@ Loader {
id: focusGrab
active: true
windows: [popupWindow]
onCleared: {
root.close()
}
onCleared: root.focusCleared();
}
function close() {
@@ -53,6 +62,10 @@ Loader {
else closeAnim.start();
}
function grabFocus() {
focusGrab.active = true; // Doesn't work
}
implicitWidth: realContent.implicitWidth + (ambientShadow.border.width * 2) + (root.visualMargin * 2)
implicitHeight: realContent.implicitHeight + (ambientShadow.border.width * 2) + (root.visualMargin * 2)
@@ -4,43 +4,30 @@ import qs
import qs.services
import qs.modules.common
import qs.modules.waffle.looks
import qs.modules.waffle.bar.tray
BarButton {
BarIconButton {
id: root
visible: Updates.available && Updates.updateAdvised
visible: Updates.updateAdvised || Updates.updateStronglyAdvised
padding: 4
iconName: "arrow-sync"
iconSize: 20 // Needed because the icon appears to have some padding
tooltipText: Translation.tr("Get the latest features and security improvements with\nthe newest feature update.\n\n%1 packages").arg(Updates.count)
onClicked: {
Quickshell.execDetached(["bash", "-c", Config.options.apps.update]);
}
contentItem: Item {
anchors.centerIn: parent
implicitWidth: iconContent.implicitWidth
implicitHeight: iconContent.implicitHeight
FluentIcon {
id: iconContent
anchors.centerIn: parent
icon: "arrow-sync"
Rectangle {
anchors {
right: parent.right
bottom: parent.bottom
margins: 1
}
implicitWidth: 8
implicitHeight: implicitWidth
radius: height / 2
color: Updates.updateStronglyAdvised ? Looks.colors.warning : Looks.colors.accent
}
overlayingItems: Rectangle {
anchors {
right: parent.right
bottom: parent.bottom
margins: 1
}
}
BarToolTip {
extraVisibleCondition: root.shouldShowTooltip
text: Translation.tr("Get the latest features and security improvements with\nthe newest feature update.\n\n%1 packages").arg(Updates.count)
implicitWidth: 8
implicitHeight: implicitWidth
radius: height / 2
color: Updates.updateStronglyAdvised ? Looks.colors.warning : Looks.colors.accent
}
}
@@ -4,6 +4,7 @@ import qs.modules.common
import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.bar.tasks
import qs.modules.waffle.bar.tray
Rectangle {
id: root
@@ -68,6 +69,7 @@ Rectangle {
shown: Config.options.waffles.bar.leftAlignApps
sourceComponent: WidgetsButton {}
}
Tray {}
UpdatesButton {}
SystemButton {}
TimeButton {}
@@ -17,10 +17,17 @@ MouseArea {
previewPopup.show(appEntry, button);
}
Behavior on implicitWidth {
animation: Looks.transition.move.createObject(this)
}
// Apps row
RowLayout {
id: row
anchors.fill: parent
anchors {
top: parent.top
bottom: parent.bottom
}
spacing: 0
Repeater {
@@ -0,0 +1,59 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt.labs.synchronizer
import Quickshell
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.bar
RowLayout {
id: root
property bool overflowOpen: false
Layout.fillHeight: true
spacing: 0
BarIconButton {
id: overflowButton
visible: TrayService.unpinnedItems.length > 0
checked: root.overflowOpen
iconName: "chevron-down"
iconMonochrome: true
iconRotation: (Config.options.waffles.bar.bottom ? 180 : 0) + (root.overflowOpen ? 180 : 0)
Behavior on iconRotation {
animation: Looks.transition.rotate.createObject(this)
}
onClicked: {
root.overflowOpen = !root.overflowOpen;
}
TrayOverflowMenu {
id: trayOverflowLayout
Synchronizer on active {
property alias source: root.overflowOpen
}
}
BarToolTip {
extraVisibleCondition: overflowButton.shouldShowTooltip
text: qsTr("Show hidden icons")
}
}
Repeater {
model: ScriptModel {
values: TrayService.pinnedItems
}
delegate: TrayButton {
required property var modelData
item: modelData
}
}
}
@@ -0,0 +1,45 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.SystemTray
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.waffle.looks
import qs.modules.waffle.bar
BarIconButton {
id: root
required property SystemTrayItem item
property alias menuOpen: menu.visible
readonly property bool barAtBottom: Config.options.waffles.bar.bottom
iconSource: item.icon
onClicked: {
item.activate();
}
altAction: () => {
if (item.hasMenu) menu.open()
}
// This is lazy, but it's not like tray menus on Windoes are consistent...
// TODO: Figure out how to do cascading menus then use a custom menu
QsMenuAnchor {
id: menu
menu: root.item.menu
anchor {
adjustment: PopupAdjustment.ResizeY | PopupAdjustment.SlideX
item: root
gravity: root.barAtBottom ? Edges.Top : Edges.Bottom
edges: root.barAtBottom ? Edges.Top : Edges.Bottom
}
}
BarToolTip {
extraVisibleCondition: root.shouldShowTooltip
text: TrayService.getTooltipForItem(root.item)
}
}
@@ -0,0 +1,59 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
import qs.modules.waffle.bar
BarPopup {
id: root
closeOnFocusLost: false
onFocusCleared: {
print("uwu")
print(contentItem.children)
const hasMenuOpen = contentItem.children.some(c => (c.menuOpen));
if (!hasMenuOpen) root.close();
else root.grabFocus();
}
contentItem: GridLayout {
id: contentItem
anchors.centerIn: parent
columns: Math.ceil(Math.sqrt(TrayService.unpinnedItems.length))
columnSpacing: 0
rowSpacing: 0
Repeater {
model: TrayService.unpinnedItems
delegate: TrayButton {
required property var modelData
item: modelData
topInset: 0
bottomInset: 0
implicitWidth: 40
implicitHeight: 40
colBackground: ColorUtils.transparentize(Looks.colors.bg2)
colBackgroundHover: Looks.colors.bg2Hover
colBackgroundActive: Looks.colors.bg2Active
onMenuOpenChanged: {
// The overflow menu should only be closed when the user clicks outside
// However the focus grab refuses to reactivate, so we can't have that
// But most of the time the user dismisses the menu by clicking outside anyway,
// so this is acceptable.
if (!menuOpen) {
root.close();
}
}
}
}
}
}
@@ -117,6 +117,14 @@ Singleton {
}
}
property Component rotate: Component {
NumberAnimation {
duration: 170
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeInOut
}
}
property Component anchor: Component {
AnchorAnimation {
duration: 160