forked from Shinonome/dots-hyprland
wbar: tray
This commit is contained in:
@@ -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 {
|
component BackgroundAcrylicRectangle: AcrylicRectangle {
|
||||||
shiny: ((root.hovered && !root.down) || root.checked)
|
shiny: ((root.hovered && !root.down) || root.checked)
|
||||||
color: root.colBackground
|
color: root.color
|
||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: root.colBackgroundBorder
|
border.color: root.colBackgroundBorder
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,11 @@ Button {
|
|||||||
property var altAction: () => {}
|
property var altAction: () => {}
|
||||||
property var middleClickAction: () => {}
|
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 colBackgroundBorder
|
||||||
|
property color color
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
topInset: 4
|
topInset: 4
|
||||||
bottomInset: 4
|
bottomInset: 4
|
||||||
@@ -37,14 +40,14 @@ Button {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, root.checked ? Looks.contentTransparency : 1)
|
colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, (root.checked || root.hovered) ? Looks.contentTransparency : 1)
|
||||||
colBackground: {
|
color: {
|
||||||
if (root.down) {
|
if (root.down) {
|
||||||
return Looks.colors.bg1Active
|
return root.colBackgroundActive
|
||||||
} else if ((root.hovered && !root.down) || root.checked) {
|
} else if ((root.hovered && !root.down) || root.checked) {
|
||||||
return Looks.colors.bg1Hover
|
return root.colBackgroundHover
|
||||||
} else {
|
} else {
|
||||||
return ColorUtils.transparentize(Looks.colors.bg1)
|
return root.colBackground
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +69,7 @@ Button {
|
|||||||
|
|
||||||
background: AcrylicRectangle {
|
background: AcrylicRectangle {
|
||||||
shiny: ((root.hovered && !root.down) || root.checked)
|
shiny: ((root.hovered && !root.down) || root.checked)
|
||||||
color: root.colBackground
|
color: root.color
|
||||||
radius: Looks.radius.medium
|
radius: Looks.radius.medium
|
||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: root.colBackgroundBorder
|
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
|
required property var contentItem
|
||||||
property real padding: Looks.radius.large - Looks.radius.medium
|
property real padding: Looks.radius.large - Looks.radius.medium
|
||||||
property bool noSmoothClosing: !Config.options.waffles.smootherAnimations
|
property bool noSmoothClosing: !Config.options.waffles.smootherAnimations
|
||||||
|
property bool closeOnFocusLost: true
|
||||||
|
signal focusCleared()
|
||||||
|
|
||||||
property Item anchorItem: parent
|
property Item anchorItem: parent
|
||||||
property real visualMargin: 12
|
property real visualMargin: 12
|
||||||
readonly property bool barAtBottom: Config.options.waffles.bar.bottom
|
readonly property bool barAtBottom: Config.options.waffles.bar.bottom
|
||||||
property real ambientShadowWidth: 1
|
property real ambientShadowWidth: 1
|
||||||
|
|
||||||
|
onFocusCleared: {
|
||||||
|
if (!root.closeOnFocusLost) return;
|
||||||
|
root.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
function grabFocus() { // Doesn't work
|
||||||
|
item.grabFocus();
|
||||||
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
item.close();
|
item.close();
|
||||||
}
|
}
|
||||||
@@ -43,9 +54,7 @@ Loader {
|
|||||||
id: focusGrab
|
id: focusGrab
|
||||||
active: true
|
active: true
|
||||||
windows: [popupWindow]
|
windows: [popupWindow]
|
||||||
onCleared: {
|
onCleared: root.focusCleared();
|
||||||
root.close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
@@ -53,6 +62,10 @@ Loader {
|
|||||||
else closeAnim.start();
|
else closeAnim.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function grabFocus() {
|
||||||
|
focusGrab.active = true; // Doesn't work
|
||||||
|
}
|
||||||
|
|
||||||
implicitWidth: realContent.implicitWidth + (ambientShadow.border.width * 2) + (root.visualMargin * 2)
|
implicitWidth: realContent.implicitWidth + (ambientShadow.border.width * 2) + (root.visualMargin * 2)
|
||||||
implicitHeight: realContent.implicitHeight + (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.services
|
||||||
import qs.modules.common
|
import qs.modules.common
|
||||||
import qs.modules.waffle.looks
|
import qs.modules.waffle.looks
|
||||||
|
import qs.modules.waffle.bar.tray
|
||||||
|
|
||||||
BarButton {
|
BarIconButton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
visible: Updates.available && Updates.updateAdvised
|
visible: Updates.updateAdvised || Updates.updateStronglyAdvised
|
||||||
padding: 4
|
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: {
|
onClicked: {
|
||||||
Quickshell.execDetached(["bash", "-c", Config.options.apps.update]);
|
Quickshell.execDetached(["bash", "-c", Config.options.apps.update]);
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Item {
|
overlayingItems: Rectangle {
|
||||||
anchors.centerIn: parent
|
anchors {
|
||||||
implicitWidth: iconContent.implicitWidth
|
right: parent.right
|
||||||
implicitHeight: iconContent.implicitHeight
|
bottom: parent.bottom
|
||||||
|
margins: 1
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
implicitWidth: 8
|
||||||
|
implicitHeight: implicitWidth
|
||||||
BarToolTip {
|
radius: height / 2
|
||||||
extraVisibleCondition: root.shouldShowTooltip
|
color: Updates.updateStronglyAdvised ? Looks.colors.warning : Looks.colors.accent
|
||||||
text: Translation.tr("Get the latest features and security improvements with\nthe newest feature update.\n\n%1 packages").arg(Updates.count)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import qs.modules.common
|
|||||||
import qs.modules.common.widgets
|
import qs.modules.common.widgets
|
||||||
import qs.modules.waffle.looks
|
import qs.modules.waffle.looks
|
||||||
import qs.modules.waffle.bar.tasks
|
import qs.modules.waffle.bar.tasks
|
||||||
|
import qs.modules.waffle.bar.tray
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
@@ -68,6 +69,7 @@ Rectangle {
|
|||||||
shown: Config.options.waffles.bar.leftAlignApps
|
shown: Config.options.waffles.bar.leftAlignApps
|
||||||
sourceComponent: WidgetsButton {}
|
sourceComponent: WidgetsButton {}
|
||||||
}
|
}
|
||||||
|
Tray {}
|
||||||
UpdatesButton {}
|
UpdatesButton {}
|
||||||
SystemButton {}
|
SystemButton {}
|
||||||
TimeButton {}
|
TimeButton {}
|
||||||
|
|||||||
@@ -17,10 +17,17 @@ MouseArea {
|
|||||||
previewPopup.show(appEntry, button);
|
previewPopup.show(appEntry, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
animation: Looks.transition.move.createObject(this)
|
||||||
|
}
|
||||||
|
|
||||||
// Apps row
|
// Apps row
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: row
|
id: row
|
||||||
anchors.fill: parent
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Repeater {
|
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 {
|
property Component anchor: Component {
|
||||||
AnchorAnimation {
|
AnchorAnimation {
|
||||||
duration: 160
|
duration: 160
|
||||||
|
|||||||
Reference in New Issue
Block a user