Compare commits
10
Commits
abef1eb259
...
v0.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f544981c1 | ||
|
|
02bb7e43d8 | ||
|
|
fb0c75a2ba | ||
|
|
5efa0de3a5 | ||
|
|
858ef68565 | ||
|
|
5e97ea6867 | ||
|
|
9823c66299 | ||
|
|
0092b41a05 | ||
|
|
abf7382771
|
||
|
|
a1a8a6e695
|
@@ -97,7 +97,7 @@ jobs:
|
|||||||
py3-pip
|
py3-pip
|
||||||
python3 -m venv .venv
|
python3 -m venv .venv
|
||||||
. .venv/bin/activate
|
. .venv/bin/activate
|
||||||
pip install --no-cache-dir basedpyright
|
pip install --no-cache-dir basedpyright typer pillow materialyoucolor jinja2
|
||||||
|
|
||||||
- name: Type check
|
- name: Type check
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+147
-129
@@ -18,13 +18,14 @@ Item {
|
|||||||
property real leftFadeStrength: overflowing && leftFadeEnabled ? fadeStrengthMoving : fadeStrengthIdle
|
property real leftFadeStrength: overflowing && leftFadeEnabled ? fadeStrengthMoving : fadeStrengthIdle
|
||||||
property int leftFadeWidth: 28
|
property int leftFadeWidth: 28
|
||||||
property bool marqueeEnabled: true
|
property bool marqueeEnabled: true
|
||||||
readonly property bool overflowing: metrics.width > root.width
|
readonly property bool overflowing: metrics.width > content.width
|
||||||
property int pauseMs: 1200
|
property int pauseMs: 1200
|
||||||
property real pixelsPerSecond: 40
|
property real pixelsPerSecond: 40
|
||||||
property real rightFadeStrength: overflowing ? fadeStrengthMoving : fadeStrengthIdle
|
property real rightFadeStrength: overflowing ? fadeStrengthMoving : fadeStrengthIdle
|
||||||
property int rightFadeWidth: 28
|
property int rightFadeWidth: 28
|
||||||
property bool sliding: false
|
property bool sliding: false
|
||||||
property alias text: elideText.text
|
property alias text: elideText.text
|
||||||
|
property bool vertical: false
|
||||||
|
|
||||||
function durationForDistance(px): int {
|
function durationForDistance(px): int {
|
||||||
return Math.max(1, Math.round(Math.abs(px) / root.pixelsPerSecond * 1000));
|
return Math.max(1, Math.round(Math.abs(px) / root.pixelsPerSecond * 1000));
|
||||||
@@ -42,7 +43,8 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clip: false
|
clip: false
|
||||||
implicitHeight: elideText.implicitHeight
|
implicitHeight: vertical ? elideText.implicitWidth : elideText.implicitHeight
|
||||||
|
implicitWidth: vertical ? elideText.implicitHeight : elideText.implicitWidth
|
||||||
|
|
||||||
Behavior on leftFadeStrength {
|
Behavior on leftFadeStrength {
|
||||||
Anim {
|
Anim {
|
||||||
@@ -53,171 +55,187 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onHeightChanged: resetMarquee()
|
||||||
onTextChanged: resetMarquee()
|
onTextChanged: resetMarquee()
|
||||||
|
onVerticalChanged: resetMarquee()
|
||||||
onVisibleChanged: if (!visible)
|
onVisibleChanged: if (!visible)
|
||||||
resetMarquee()
|
resetMarquee()
|
||||||
onWidthChanged: resetMarquee()
|
onWidthChanged: resetMarquee()
|
||||||
|
|
||||||
TextMetrics {
|
|
||||||
id: metrics
|
|
||||||
|
|
||||||
font: elideText.font
|
|
||||||
text: elideText.text
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
id: elideText
|
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
animate: root.animate
|
|
||||||
animateProp: "scale,opacity"
|
|
||||||
color: root.color
|
|
||||||
elide: Text.ElideNone
|
|
||||||
visible: !root.overflowing
|
|
||||||
width: root.width
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: marqueeViewport
|
id: content
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.centerIn: parent
|
||||||
clip: false
|
height: root.vertical ? root.width : root.height
|
||||||
layer.enabled: true
|
width: root.vertical ? root.height : root.width
|
||||||
visible: root.overflowing
|
|
||||||
|
|
||||||
layer.effect: OpacityMask {
|
transform: Rotation {
|
||||||
maskSource: rightFadeMask
|
angle: root.vertical ? -90 : 0
|
||||||
|
origin.x: content.width / 2
|
||||||
|
origin.y: content.height / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: metrics
|
||||||
|
|
||||||
|
font: elideText.font
|
||||||
|
text: elideText.text
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: elideText
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
animate: root.animate
|
||||||
|
animateProp: "scale,opacity"
|
||||||
|
color: root.color
|
||||||
|
elide: Text.ElideNone
|
||||||
|
visible: !root.overflowing
|
||||||
|
width: content.width
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: strip
|
id: marqueeViewport
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.fill: parent
|
||||||
height: t1.implicitHeight
|
clip: false
|
||||||
width: t1.width + root.gap + t2.width
|
layer.enabled: true
|
||||||
x: 0
|
visible: root.overflowing
|
||||||
|
|
||||||
CustomText {
|
layer.effect: OpacityMask {
|
||||||
id: t1
|
maskSource: rightFadeMask
|
||||||
|
|
||||||
animate: root.animate
|
|
||||||
animateProp: "opacity"
|
|
||||||
color: root.color
|
|
||||||
font.pointSize: elideText.font.pointSize
|
|
||||||
text: elideText.text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomText {
|
Item {
|
||||||
id: t2
|
id: strip
|
||||||
|
|
||||||
animate: root.animate
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
animateProp: "opacity"
|
height: t1.implicitHeight
|
||||||
color: root.color
|
width: t1.width + root.gap + t2.width
|
||||||
font.pointSize: elideText.font.pointSize
|
x: 0
|
||||||
text: t1.text
|
|
||||||
x: t1.width + root.gap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SequentialAnimation {
|
CustomText {
|
||||||
id: marqueeAnim
|
id: t1
|
||||||
|
|
||||||
running: false
|
animate: root.animate
|
||||||
|
animateProp: "opacity"
|
||||||
|
color: root.color
|
||||||
|
font.pointSize: elideText.font.pointSize
|
||||||
|
text: elideText.text
|
||||||
|
}
|
||||||
|
|
||||||
onFinished: pauseTimer.restart()
|
CustomText {
|
||||||
|
id: t2
|
||||||
|
|
||||||
ScriptAction {
|
animate: root.animate
|
||||||
script: {
|
animateProp: "opacity"
|
||||||
root.sliding = true;
|
color: root.color
|
||||||
root.leftFadeEnabled = true;
|
font.pointSize: elideText.font.pointSize
|
||||||
|
text: t1.text
|
||||||
|
x: t1.width + root.gap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Anim {
|
SequentialAnimation {
|
||||||
duration: root.durationForDistance(t1.width)
|
id: marqueeAnim
|
||||||
easing.bezierCurve: Easing.Linear
|
|
||||||
easing.type: Easing.Linear
|
|
||||||
from: 0
|
|
||||||
property: "x"
|
|
||||||
target: strip
|
|
||||||
to: -t1.width
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptAction {
|
running: false
|
||||||
script: {
|
|
||||||
root.leftFadeEnabled = false;
|
onFinished: pauseTimer.restart()
|
||||||
|
|
||||||
|
ScriptAction {
|
||||||
|
script: {
|
||||||
|
root.sliding = true;
|
||||||
|
root.leftFadeEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
duration: root.durationForDistance(t1.width)
|
||||||
|
easing.bezierCurve: Easing.Linear
|
||||||
|
easing.type: Easing.Linear
|
||||||
|
from: 0
|
||||||
|
property: "x"
|
||||||
|
target: strip
|
||||||
|
to: -t1.width
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptAction {
|
||||||
|
script: {
|
||||||
|
root.leftFadeEnabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
duration: root.durationForDistance(root.gap)
|
||||||
|
easing.bezierCurve: Easing.Linear
|
||||||
|
easing.type: Easing.Linear
|
||||||
|
from: -t1.width
|
||||||
|
property: "x"
|
||||||
|
target: strip
|
||||||
|
to: -(t1.width + root.gap)
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptAction {
|
||||||
|
script: {
|
||||||
|
root.sliding = false;
|
||||||
|
strip.x = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Anim {
|
Timer {
|
||||||
duration: root.durationForDistance(root.gap)
|
id: pauseTimer
|
||||||
easing.bezierCurve: Easing.Linear
|
|
||||||
easing.type: Easing.Linear
|
|
||||||
from: -t1.width
|
|
||||||
property: "x"
|
|
||||||
target: strip
|
|
||||||
to: -(t1.width + root.gap)
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptAction {
|
interval: root.pauseMs
|
||||||
script: {
|
repeat: false
|
||||||
root.sliding = false;
|
running: true
|
||||||
strip.x = 0;
|
|
||||||
|
onTriggered: {
|
||||||
|
if (root.marqueeEnabled)
|
||||||
|
marqueeAnim.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Rectangle {
|
||||||
id: pauseTimer
|
id: rightFadeMask
|
||||||
|
|
||||||
interval: root.pauseMs
|
readonly property real fadeStartPos: {
|
||||||
repeat: false
|
const w = Math.max(1, width);
|
||||||
running: true
|
return Math.max(0, Math.min(1, (w - root.rightFadeWidth) / w));
|
||||||
|
|
||||||
onTriggered: {
|
|
||||||
if (root.marqueeEnabled)
|
|
||||||
marqueeAnim.start();
|
|
||||||
}
|
}
|
||||||
}
|
readonly property real leftFadeEndPos: {
|
||||||
}
|
const w = Math.max(1, width);
|
||||||
|
return Math.max(0, Math.min(1, root.leftFadeWidth / w));
|
||||||
Rectangle {
|
|
||||||
id: rightFadeMask
|
|
||||||
|
|
||||||
readonly property real fadeStartPos: {
|
|
||||||
const w = Math.max(1, width);
|
|
||||||
return Math.max(0, Math.min(1, (w - root.rightFadeWidth) / w));
|
|
||||||
}
|
|
||||||
readonly property real leftFadeEndPos: {
|
|
||||||
const w = Math.max(1, width);
|
|
||||||
return Math.max(0, Math.min(1, root.leftFadeWidth / w));
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.fill: marqueeViewport
|
|
||||||
layer.enabled: true
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
gradient: Gradient {
|
|
||||||
orientation: Gradient.Horizontal
|
|
||||||
|
|
||||||
GradientStop {
|
|
||||||
color: Qt.rgba(1, 1, 1, 1.0 - root.leftFadeStrength)
|
|
||||||
position: 0.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GradientStop {
|
anchors.fill: marqueeViewport
|
||||||
color: Qt.rgba(1, 1, 1, 1.0)
|
layer.enabled: true
|
||||||
position: rightFadeMask.leftFadeEndPos
|
visible: false
|
||||||
}
|
|
||||||
|
|
||||||
GradientStop {
|
gradient: Gradient {
|
||||||
color: Qt.rgba(1, 1, 1, 1.0)
|
orientation: Gradient.Horizontal
|
||||||
position: rightFadeMask.fadeStartPos
|
|
||||||
}
|
|
||||||
|
|
||||||
GradientStop {
|
GradientStop {
|
||||||
color: Qt.rgba(1, 1, 1, 1.0 - root.rightFadeStrength)
|
color: Qt.rgba(1, 1, 1, 1.0 - root.leftFadeStrength)
|
||||||
position: 1.0
|
position: 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(1, 1, 1, 1.0)
|
||||||
|
position: rightFadeMask.leftFadeEndPos
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(1, 1, 1, 1.0)
|
||||||
|
position: rightFadeMask.fadeStartPos
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
color: Qt.rgba(1, 1, 1, 1.0 - root.rightFadeStrength)
|
||||||
|
position: 1.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -126,7 +126,7 @@ MouseArea {
|
|||||||
CustomRect {
|
CustomRect {
|
||||||
id: item
|
id: item
|
||||||
|
|
||||||
readonly property bool active: modelData === root.active
|
readonly property bool active: modelData === root?.active
|
||||||
required property int index
|
required property int index
|
||||||
required property MenuItem modelData
|
required property MenuItem modelData
|
||||||
|
|
||||||
@@ -163,19 +163,19 @@ MouseArea {
|
|||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant
|
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurfaceVariant
|
||||||
text: item.modelData.icon
|
text: item.modelData?.icon ?? ""
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomText {
|
CustomText {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface
|
color: item.active ? Colors.palette.m3onTertiaryContainer : Colors.palette.m3onSurface
|
||||||
text: item.modelData.text
|
text: item.modelData?.text ?? ""
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
active: item.modelData.trailingIcon.length > 0
|
active: item.modelData?.trailingIcon.length > 0
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
visible: active
|
visible: active
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,6 @@ Variants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
function onConfigDashboardPositionChanged(): void {
|
|
||||||
Qt.callLater(scope.rebuild);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onConfigPositionChanged(): void {
|
function onConfigPositionChanged(): void {
|
||||||
Qt.callLater(scope.rebuild);
|
Qt.callLater(scope.rebuild);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import QtQuick
|
|||||||
import qs.Components
|
import qs.Components
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Modules as BarPopouts
|
import qs.Modules.Bar.Popouts
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -15,7 +15,7 @@ Item {
|
|||||||
required property EdgeGeometry geometry
|
required property EdgeGeometry geometry
|
||||||
property bool osdShortcutActive
|
property bool osdShortcutActive
|
||||||
required property Panels panels
|
required property Panels panels
|
||||||
required property BarPopouts.Wrapper popouts
|
required property Wrapper popouts
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
property bool singleGestureTriggered: false
|
property bool singleGestureTriggered: false
|
||||||
property bool utilitiesShortcutActive
|
property bool utilitiesShortcutActive
|
||||||
@@ -302,8 +302,6 @@ Item {
|
|||||||
root.visibilities.sidebar = false;
|
root.visibilities.sidebar = false;
|
||||||
root.panels.popouts.hasCurrent = false;
|
root.panels.popouts.hasCurrent = false;
|
||||||
root.visibilities.launcher = false;
|
root.visibilities.launcher = false;
|
||||||
} else {
|
|
||||||
Config.save();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-7
@@ -1,7 +1,7 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Modules as Modules
|
import qs.Modules.Bar.Popouts as Popouts
|
||||||
import qs.Modules.Notifications as Notifications
|
import qs.Modules.Notifications as Notifications
|
||||||
import qs.Modules.Notifications.Sidebar as Sidebar
|
import qs.Modules.Notifications.Sidebar as Sidebar
|
||||||
import qs.Modules.Notifications.Sidebar.Utils as Utils
|
import qs.Modules.Notifications.Sidebar.Utils as Utils
|
||||||
@@ -53,8 +53,9 @@ Item {
|
|||||||
Item {
|
Item {
|
||||||
id: resourcesWrapper
|
id: resourcesWrapper
|
||||||
|
|
||||||
|
anchors.bottom: root.geometry.position === "bottom" ? parent.bottom : undefined
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.top: parent.top
|
anchors.top: root.geometry.position !== "bottom" ? parent.top : undefined
|
||||||
clip: true
|
clip: true
|
||||||
implicitHeight: root.geometry.horizontal ? resources.implicitHeight * (1 - resources.offsetScale) : resources.implicitHeight
|
implicitHeight: root.geometry.horizontal ? resources.implicitHeight * (1 - resources.offsetScale) : resources.implicitHeight
|
||||||
implicitWidth: root.geometry.horizontal ? resources.implicitWidth : resources.implicitWidth * (1 - resources.offsetScale)
|
implicitWidth: root.geometry.horizontal ? resources.implicitWidth : resources.implicitWidth * (1 - resources.offsetScale)
|
||||||
@@ -62,9 +63,7 @@ Item {
|
|||||||
Resources.Wrapper {
|
Resources.Wrapper {
|
||||||
id: resources
|
id: resources
|
||||||
|
|
||||||
anchors.left: parent.left
|
position: root.geometry.position
|
||||||
anchors.top: parent.top
|
|
||||||
horizontal: root.geometry.horizontal
|
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,7 +99,7 @@ Item {
|
|||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
}
|
}
|
||||||
|
|
||||||
Modules.ClipWrapper {
|
Popouts.ClipWrapper {
|
||||||
id: popouts
|
id: popouts
|
||||||
|
|
||||||
borderThickness: root.borderThickness
|
borderThickness: root.borderThickness
|
||||||
@@ -169,8 +168,8 @@ Item {
|
|||||||
Dashboard.Wrapper {
|
Dashboard.Wrapper {
|
||||||
id: dashboard
|
id: dashboard
|
||||||
|
|
||||||
horizontal: root.geometry.horizontal
|
|
||||||
offsetScale: dashboardWrapper.offsetScale
|
offsetScale: dashboardWrapper.offsetScale
|
||||||
|
position: root.geometry.position
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -221,7 +221,7 @@ CustomWindow {
|
|||||||
panel: panels.dashboardWrapper
|
panel: panels.dashboardWrapper
|
||||||
radius: Tokens.rounding.normal
|
radius: Tokens.rounding.normal
|
||||||
x: panels.dashboardWrapper.x + panels.dashboard.x + geometry.insetLeft(root.borderThickness) - (geometry.horizontal ? 0 : panels.dashboard.width * extraExtent)
|
x: panels.dashboardWrapper.x + panels.dashboard.x + geometry.insetLeft(root.borderThickness) - (geometry.horizontal ? 0 : panels.dashboard.width * extraExtent)
|
||||||
y: panels.dashboardWrapper.y + panels.dashboard.y + geometry.insetTop(root.borderThickness) - (geometry.horizontal ? panels.dashboard.height * extraExtent : 0)
|
y: panels.dashboardWrapper.y + panels.dashboard.y + geometry.insetTop(root.borderThickness) - (geometry.horizontal && geometry.position !== "bottom" ? panels.dashboard.height * extraExtent : 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelBg {
|
PanelBg {
|
||||||
|
|||||||
+51
-2
@@ -1,9 +1,8 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
|
||||||
import ZShell.Config
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Services.Notifications
|
import Quickshell.Services.Notifications
|
||||||
import QtQuick
|
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
@@ -95,6 +94,15 @@ Singleton {
|
|||||||
return Quickshell.iconPath(icon);
|
return Quickshell.iconPath(icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getBatteryIcon(percentage: real, charging = false): string {
|
||||||
|
if (percentage === 1)
|
||||||
|
return charging ? "battery_charging_full" : "battery_full";
|
||||||
|
let level = Math.floor(percentage * 7);
|
||||||
|
if (charging && (level === 4 || level === 1))
|
||||||
|
level--;
|
||||||
|
return charging ? `battery_charging_${(level + 3) * 10}` : `battery_${level}_bar`;
|
||||||
|
}
|
||||||
|
|
||||||
function getBluetoothIcon(icon: string): string {
|
function getBluetoothIcon(icon: string): string {
|
||||||
if (icon.includes("headset") || icon.includes("headphones"))
|
if (icon.includes("headset") || icon.includes("headphones"))
|
||||||
return "headphones";
|
return "headphones";
|
||||||
@@ -168,6 +176,32 @@ Singleton {
|
|||||||
return "chat";
|
return "chat";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSpecialWsIcon(name: string): string {
|
||||||
|
name = name.toLowerCase().slice("special:".length);
|
||||||
|
|
||||||
|
if (name === "special")
|
||||||
|
return "star";
|
||||||
|
if (name === "communication")
|
||||||
|
return "forum";
|
||||||
|
if (name === "music")
|
||||||
|
return "music_cast";
|
||||||
|
if (name === "todo")
|
||||||
|
return "checklist";
|
||||||
|
if (name === "sysmon")
|
||||||
|
return "monitor_heart";
|
||||||
|
return name[0].toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTrayIcon(id: string, icon: string): string {
|
||||||
|
if (icon.includes("?path=")) {
|
||||||
|
const [name, path] = icon.split("?path=");
|
||||||
|
const file = name.slice(name.lastIndexOf("/") + 1);
|
||||||
|
const themed = Quickshell.iconPath(file, true);
|
||||||
|
icon = themed ? themed : Qt.resolvedUrl(`${path}/${file}`);
|
||||||
|
}
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
function getVolumeIcon(volume: real, isMuted: bool): string {
|
function getVolumeIcon(volume: real, isMuted: bool): string {
|
||||||
if (isMuted)
|
if (isMuted)
|
||||||
return "no_sound";
|
return "no_sound";
|
||||||
@@ -183,4 +217,19 @@ Singleton {
|
|||||||
return weatherIcons[code];
|
return weatherIcons[code];
|
||||||
return "air";
|
return "air";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function matchIconConfig(name: string, iconConfig: var): bool {
|
||||||
|
if (!iconConfig.icon)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (iconConfig.regex) {
|
||||||
|
const re = new RegExp(iconConfig.regex, iconConfig.flags ?? "");
|
||||||
|
if (re.test(name))
|
||||||
|
return true;
|
||||||
|
} else if (iconConfig.name === name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ Singleton {
|
|||||||
|
|
||||||
Config.dock.pinnedApps = pinnedApps;
|
Config.dock.pinnedApps = pinnedApps;
|
||||||
root.unpinnedOrder = visibleUnpinned.concat(root.unpinnedOrder.map(normalizeId).filter(id => !pinnedApps.includes(id) && !visibleUnpinned.includes(id)));
|
root.unpinnedOrder = visibleUnpinned.concat(root.unpinnedOrder.map(normalizeId).filter(id => !pinnedApps.includes(id) && !visibleUnpinned.includes(id)));
|
||||||
Config.saveNoToast();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPinned(appId) {
|
function isPinned(appId) {
|
||||||
|
|||||||
+2
-4
@@ -3,11 +3,9 @@ pragma ComponentBehavior: Bound
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Modules
|
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
import qs.Modules.SysTray
|
import qs.Modules.Bar.Components
|
||||||
import qs.Modules.Network
|
import qs.Modules.Bar.Popouts
|
||||||
import qs.Modules.Updates
|
|
||||||
|
|
||||||
GridLayout {
|
GridLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|||||||
@@ -3,18 +3,14 @@ pragma ComponentBehavior: Bound
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
|
import qs.Modules.Bar.Popouts
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Modules
|
|
||||||
import qs.Helpers
|
|
||||||
import qs.Modules.SysTray
|
|
||||||
import qs.Modules.SysTray.Widgets
|
|
||||||
import qs.Modules.Network
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property int clampedExtent: Math.max(Config.bar.border, extent)
|
readonly property int clampedExtent: Math.max(Config.bar.border, extent)
|
||||||
readonly property int contentThickness: Math.max(Config.bar.height, 30) + padding * 2
|
readonly property int contentThickness: Math.floor(Math.max(Config.bar.height, Tokens.bar.innerSize * (horizontal ? 1 : 1.5))) + padding * 2
|
||||||
readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentThickness
|
readonly property int exclusiveZone: Config.bar.autoHide ? Config.bar.border : contentThickness
|
||||||
property real extent: fullscreen ? 0 : Config.bar.border
|
property real extent: fullscreen ? 0 : Config.bar.border
|
||||||
required property bool fullscreen
|
required property bool fullscreen
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import ZShell.Config
|
||||||
|
import qs.Modules.Bar.Popouts
|
||||||
|
import qs.Modules.Bar.Components.Common
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Components
|
||||||
|
import qs.Services
|
||||||
|
|
||||||
|
WidgetBase {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property color contentColor: visibilities.dashboard ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||||
|
readonly property string effectiveFormat: {
|
||||||
|
let fmt = Config.general.dateFormat;
|
||||||
|
if (!root.horizontal)
|
||||||
|
fmt = fmt.replace("dddd", "ddd");
|
||||||
|
return fmt;
|
||||||
|
}
|
||||||
|
readonly property var formatParts: {
|
||||||
|
const segments = root.effectiveFormat.split(" - ");
|
||||||
|
let datePart = "";
|
||||||
|
let timePart = "";
|
||||||
|
|
||||||
|
if (segments.length > 1) {
|
||||||
|
datePart = segments[0];
|
||||||
|
timePart = segments[1];
|
||||||
|
} else if (/[hms]/.test(segments[0])) {
|
||||||
|
timePart = segments[0];
|
||||||
|
} else {
|
||||||
|
datePart = segments[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const dateTokens = datePart.trim().length ? datePart.trim().split(/\s+/) : [];
|
||||||
|
const timeTokens = timePart.trim().length ? timePart.trim().split(":") : [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
dateTokens: dateTokens,
|
||||||
|
timeTokens: timeTokens
|
||||||
|
};
|
||||||
|
}
|
||||||
|
required property GridLayout loader
|
||||||
|
required property Wrapper popouts
|
||||||
|
readonly property real size: horizontal ? timeText.contentWidth + Tokens.padding.normal * 2 : verticalColumn.implicitHeight + Tokens.padding.larger * 2
|
||||||
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
|
color: visibilities.dashboard ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: horizontal ? baseSize : size
|
||||||
|
implicitWidth: horizontal ? size : baseSize
|
||||||
|
radius: Tokens.rounding.full
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
id: timeText
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: root.contentColor
|
||||||
|
font: Config.appearance.font.family.mono // qmllint disable incompatible-type
|
||||||
|
height: implicitHeight
|
||||||
|
text: Time.dateStr
|
||||||
|
visible: root.horizontal
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: verticalColumn
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Tokens.padding.small ?? 2
|
||||||
|
visible: !root.horizontal
|
||||||
|
width: root.baseSize
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.formatParts.dateTokens
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
required property string modelData
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: root.contentColor
|
||||||
|
font: Config.appearance.font.family.mono // qmllint disable incompatible-type
|
||||||
|
text: Qt.formatDateTime(Time.date, modelData)
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.bottomMargin: Tokens.padding.small ?? 2
|
||||||
|
Layout.topMargin: Tokens.padding.small ?? 2
|
||||||
|
color: root.contentColor
|
||||||
|
height: 1
|
||||||
|
implicitWidth: root.baseSize * 0.5
|
||||||
|
opacity: 0.4
|
||||||
|
radius: 1
|
||||||
|
visible: root.formatParts.dateTokens.length > 0 && root.formatParts.timeTokens.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.formatParts.timeTokens
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
required property string modelData
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: root.contentColor
|
||||||
|
font: Config.appearance.font.family.mono // qmllint disable incompatible-type
|
||||||
|
text: {
|
||||||
|
if (modelData.includes("h"))
|
||||||
|
return Time.hourStr;
|
||||||
|
if (modelData.includes("m"))
|
||||||
|
return Time.minuteStr;
|
||||||
|
if (modelData.includes("s"))
|
||||||
|
return Time.secondStr;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
color: root.contentColor
|
||||||
|
font: Config.appearance.font.family.mono // qmllint disable incompatible-type
|
||||||
|
text: Qt.formatDateTime(Time.date, "AP")
|
||||||
|
visible: Config.services.useTwelveHourClock && root.formatParts.timeTokens.length > 0
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
color: root.contentColor
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.visibilities.dashboard = !root.visibilities.dashboard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import QtQuick
|
||||||
|
import ZShell.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Services
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property int baseSize: horizontal ? Math.max(Config.bar.height, Tokens.bar.innerSize) : Math.max(Config.bar.height, Math.floor(Tokens.bar.innerSize * 1.5))
|
||||||
|
required property bool horizontal
|
||||||
|
|
||||||
|
color: Colors.tPalette.m3surfaceContainer
|
||||||
|
implicitHeight: horizontal ? baseSize : width
|
||||||
|
implicitWidth: horizontal ? height : baseSize
|
||||||
|
radius: Tokens.rounding.full
|
||||||
|
}
|
||||||
@@ -1,18 +1,16 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
import qs.Components
|
import qs.Components
|
||||||
|
import qs.Modules.Bar.Components.Common
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
CustomRect {
|
WidgetBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property bool horizontal
|
|
||||||
property bool tempEnabled: Hyprsunset.enabled
|
property bool tempEnabled: Hyprsunset.enabled
|
||||||
|
|
||||||
color: root.tempEnabled ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
|
color: root.tempEnabled ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: horizontal ? Config.bar.height : width
|
|
||||||
implicitWidth: horizontal ? height : Config.bar.height
|
|
||||||
radius: Tokens.rounding.full
|
radius: Tokens.rounding.full
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
@@ -27,7 +25,7 @@ CustomRect {
|
|||||||
animate: true
|
animate: true
|
||||||
color: root.tempEnabled ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
color: root.tempEnabled ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||||
fill: root.tempEnabled ? 1 : 0
|
fill: root.tempEnabled ? 1 : 0
|
||||||
font.pointSize: root.horizontal ? Tokens.font.size.larger : Tokens.font.size.large
|
font.pointSize: Tokens.font.size.larger
|
||||||
text: root.tempEnabled ? "lightbulb" : "light_off"
|
text: root.tempEnabled ? "lightbulb" : "light_off"
|
||||||
|
|
||||||
Behavior on fill {
|
Behavior on fill {
|
||||||
@@ -1,24 +1,30 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Components
|
|
||||||
import qs.Daemons
|
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.Bar.Components.Common
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
CustomRect {
|
WidgetBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property string currentMedia: (Players.active?.trackTitle ?? qsTr("No media")) || qsTr("Unknown title")
|
readonly property string currentMedia: (Players.active?.trackTitle ?? qsTr("No media")) || qsTr("Unknown title")
|
||||||
required property bool horizontal
|
|
||||||
readonly property int textWidth: Math.min(metrics.width, 200)
|
readonly property int textWidth: Math.min(metrics.width, 200)
|
||||||
|
|
||||||
color: Colors.tPalette.m3surfaceContainer
|
implicitHeight: horizontal ? baseSize : layout.implicitHeight + Tokens.padding.normal * 2
|
||||||
implicitHeight: horizontal ? Config.bar.height : layout.implicitHeight + Tokens.padding.normal * 2
|
implicitWidth: horizontal ? layout.implicitWidth + Tokens.padding.normal * 2 : baseSize
|
||||||
implicitWidth: horizontal ? layout.implicitWidth + Tokens.padding.normal * 2 : Config.bar.height
|
|
||||||
radius: Tokens.rounding.full
|
radius: Tokens.rounding.full
|
||||||
|
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
enabled: !root.horizontal
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
}
|
||||||
|
}
|
||||||
Behavior on implicitWidth {
|
Behavior on implicitWidth {
|
||||||
|
enabled: root.horizontal
|
||||||
|
|
||||||
Anim {
|
Anim {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,7 +39,11 @@ CustomRect {
|
|||||||
GridLayout {
|
GridLayout {
|
||||||
id: layout
|
id: layout
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.bottomMargin: root.horizontal ? 0 : Tokens.padding.normal
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: root.horizontal ? Tokens.padding.normal : 0
|
||||||
|
anchors.rightMargin: root.horizontal ? Tokens.padding.normal : 0
|
||||||
|
anchors.topMargin: root.horizontal ? 0 : Tokens.padding.normal
|
||||||
columns: root.horizontal ? -1 : 1
|
columns: root.horizontal ? -1 : 1
|
||||||
|
|
||||||
Behavior on implicitWidth {
|
Behavior on implicitWidth {
|
||||||
@@ -53,39 +63,29 @@ CustomRect {
|
|||||||
id: mediatext
|
id: mediatext
|
||||||
|
|
||||||
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
|
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
|
||||||
Layout.preferredHeight: root.horizontal ? root.height : root.textWidth
|
|
||||||
animate: true
|
animate: true
|
||||||
color: Players.active?.isPlaying ? Colors.palette.m3primary : Colors.palette.m3onSurface
|
color: Players.active?.isPlaying ? Colors.palette.m3primary : Colors.palette.m3onSurface
|
||||||
font.pointSize: Tokens.font.size.normal
|
font.pointSize: Tokens.font.size.normal
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
implicitHeight: root.horizontal ? root.implicitHeight : root.textWidth
|
||||||
|
implicitWidth: root.horizontal ? root.textWidth : root.implicitWidth
|
||||||
marqueeEnabled: false
|
marqueeEnabled: false
|
||||||
pauseMs: 4000
|
pauseMs: 4000
|
||||||
text: root.currentMedia
|
text: root.currentMedia
|
||||||
width: root.textWidth
|
vertical: !root.horizontal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
transform: [
|
CustomMouseArea {
|
||||||
Translate {
|
anchors.fill: parent
|
||||||
x: !root.horizontal ? -root.textWidth + mediatext.implicitHeight : 0
|
hoverEnabled: true
|
||||||
},
|
|
||||||
Rotation {
|
|
||||||
angle: root.horizontal ? 0 : 270
|
|
||||||
origin.x: mediatext.implicitHeight / 2
|
|
||||||
origin.y: mediatext.implicitHeight / 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
CustomMouseArea {
|
onContainsMouseChanged: {
|
||||||
anchors.fill: parent
|
if (!containsMouse) {
|
||||||
hoverEnabled: true
|
mediatext.marqueeEnabled = false;
|
||||||
|
} else {
|
||||||
onContainsMouseChanged: {
|
mediatext.marqueeEnabled = true;
|
||||||
if (!containsMouse) {
|
mediatext.anim.start();
|
||||||
mediatext.marqueeEnabled = false;
|
|
||||||
} else {
|
|
||||||
mediatext.marqueeEnabled = true;
|
|
||||||
mediatext.anim.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,19 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
|
import qs.Modules.Bar.Components.Common
|
||||||
|
import qs.Modules.Bar.Popouts
|
||||||
import qs.Daemons
|
import qs.Daemons
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
CustomRect {
|
WidgetBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property bool horizontal
|
|
||||||
required property Wrapper popouts
|
required property Wrapper popouts
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
color: visibilities.sidebar ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
|
color: visibilities.sidebar ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: horizontal ? Config.bar.height : width
|
|
||||||
implicitWidth: horizontal ? height : Config.bar.height
|
|
||||||
radius: Tokens.rounding.full
|
radius: Tokens.rounding.full
|
||||||
|
|
||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
@@ -23,7 +22,7 @@ CustomRect {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
color: root.visibilities.sidebar ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
color: root.visibilities.sidebar ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||||
fill: root.visibilities.sidebar ? 1 : 0
|
fill: root.visibilities.sidebar ? 1 : 0
|
||||||
font.pointSize: root.horizontal ? Tokens.font.size.larger : Tokens.font.size.large
|
font.pointSize: Tokens.font.size.larger
|
||||||
text: NotifServer.list.length ? "\uf4fe" : "\ue7f4"
|
text: NotifServer.list.length ? "\uf4fe" : "\ue7f4"
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
@@ -49,7 +49,7 @@ GridLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CustomClippingRect {
|
CustomClippingRect {
|
||||||
Layout.preferredHeight: root.horizontal ? icon.implicitHeight : 4
|
Layout.preferredHeight: root.horizontal ? icon.implicitHeight - Tokens.padding.small : 4
|
||||||
Layout.preferredWidth: root.horizontal ? 4 : icon.implicitWidth
|
Layout.preferredWidth: root.horizontal ? 4 : icon.implicitWidth
|
||||||
color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
|
color: Colors.layer(Colors.palette.m3surfaceContainerHigh, 2)
|
||||||
radius: Tokens.rounding.full
|
radius: Tokens.rounding.full
|
||||||
@@ -63,7 +63,7 @@ GridLayout {
|
|||||||
anchors.top: root.horizontal ? undefined : parent.top
|
anchors.top: root.horizontal ? undefined : parent.top
|
||||||
color: root.mainColor
|
color: root.mainColor
|
||||||
implicitHeight: root.horizontal ? Math.ceil(root.percentage * parent.height) : 0
|
implicitHeight: root.horizontal ? Math.ceil(root.percentage * parent.height) : 0
|
||||||
implicitWidth: root.horizontal ? 0 : Math.ceil(root.percentage * parent.height)
|
implicitWidth: root.horizontal ? 0 : Math.ceil(root.percentage * parent.width)
|
||||||
|
|
||||||
// Behavior on implicitHeight {
|
// Behavior on implicitHeight {
|
||||||
// Anim {
|
// Anim {
|
||||||
@@ -6,19 +6,18 @@ import QtQuick.Layouts
|
|||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
import ZShell.Services
|
import ZShell.Services
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Modules
|
import qs.Modules.Bar.Components.Common
|
||||||
import qs.Components
|
import qs.Components
|
||||||
|
|
||||||
CustomRect {
|
WidgetBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property bool horizontal
|
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
color: visibilities.resources ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
|
color: visibilities.resources ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: horizontal ? Math.max(Config.bar.height, 24) : gridLayout.implicitHeight + Tokens.padding.normal * 2
|
implicitHeight: horizontal ? baseSize : gridLayout.implicitHeight + Tokens.padding.normal * 2
|
||||||
implicitWidth: horizontal ? gridLayout.implicitWidth + Tokens.padding.larger * 2 : Config.bar.height
|
implicitWidth: horizontal ? gridLayout.implicitWidth + Tokens.padding.larger * 2 : baseSize
|
||||||
radius: Tokens.rounding.full
|
radius: Tokens.rounding.full
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
@@ -3,13 +3,14 @@ pragma ComponentBehavior: Bound
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Helpers
|
|
||||||
import qs.Modules.SysTray.Widgets
|
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Modules.Bar.Components.StatusIcons
|
||||||
|
import qs.Modules.Bar.Components.Common
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
CustomClippingRect {
|
WidgetBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property int firstPresent: {
|
readonly property int firstPresent: {
|
||||||
@@ -19,7 +20,6 @@ CustomClippingRect {
|
|||||||
return i;
|
return i;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
required property bool horizontal
|
|
||||||
|
|
||||||
// Index of the first/last entry that isn't collapsed, for edge margin gating
|
// Index of the first/last entry that isn't collapsed, for edge margin gating
|
||||||
readonly property alias items: grid
|
readonly property alias items: grid
|
||||||
@@ -30,7 +30,6 @@ CustomClippingRect {
|
|||||||
return i;
|
return i;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
readonly property real shortSize: Config.bar.height
|
|
||||||
readonly property real size: horizontal ? grid.implicitWidth + Tokens.padding.small * 2 : grid.implicitHeight + Tokens.padding.small * 2
|
readonly property real size: horizontal ? grid.implicitWidth + Tokens.padding.small * 2 : grid.implicitHeight + Tokens.padding.small * 2
|
||||||
readonly property int spacing: Tokens.spacing.normal / 2
|
readonly property int spacing: Tokens.spacing.normal / 2
|
||||||
|
|
||||||
@@ -43,8 +42,8 @@ CustomClippingRect {
|
|||||||
|
|
||||||
bottomLeftRadius: horizontal ? Tokens.rounding.smallest / 2 : Tokens.rounding.full
|
bottomLeftRadius: horizontal ? Tokens.rounding.smallest / 2 : Tokens.rounding.full
|
||||||
color: Colors.tPalette.m3surfaceContainer
|
color: Colors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: horizontal ? shortSize : size
|
implicitHeight: horizontal ? baseSize : size
|
||||||
implicitWidth: horizontal ? size : shortSize
|
implicitWidth: horizontal ? size : baseSize
|
||||||
radius: Tokens.rounding.full
|
radius: Tokens.rounding.full
|
||||||
topLeftRadius: Tokens.rounding.smallest / 2
|
topLeftRadius: Tokens.rounding.smallest / 2
|
||||||
topRightRadius: horizontal ? Tokens.rounding.full : Tokens.rounding.smallest / 2
|
topRightRadius: horizontal ? Tokens.rounding.full : Tokens.rounding.smallest / 2
|
||||||
+1
-1
@@ -13,7 +13,7 @@ MaterialIcon {
|
|||||||
animate: true
|
animate: true
|
||||||
color: Audio.muted ? Colors.palette.m3error : Colors.palette.m3onSurface
|
color: Audio.muted ? Colors.palette.m3error : Colors.palette.m3onSurface
|
||||||
fill: 1
|
fill: 1
|
||||||
font.pointSize: horizontal ? Tokens.font.size.larger : Tokens.font.size.large
|
font.pointSize: Tokens.font.size.larger
|
||||||
text: Audio.muted ? "volume_off" : "volume_up"
|
text: Audio.muted ? "volume_off" : "volume_up"
|
||||||
|
|
||||||
Behavior on Layout.maximumWidth {
|
Behavior on Layout.maximumWidth {
|
||||||
+1
-1
@@ -13,7 +13,7 @@ MaterialIcon {
|
|||||||
animate: true
|
animate: true
|
||||||
color: (Audio.sourceMuted ?? false) ? Colors.palette.m3error : Colors.palette.m3onSurface
|
color: (Audio.sourceMuted ?? false) ? Colors.palette.m3error : Colors.palette.m3onSurface
|
||||||
fill: 1
|
fill: 1
|
||||||
font.pointSize: horizontal ? Tokens.font.size.larger : Tokens.font.size.large
|
font.pointSize: Tokens.font.size.larger
|
||||||
text: Audio.sourceMuted ? "mic_off" : "mic"
|
text: Audio.sourceMuted ? "mic_off" : "mic"
|
||||||
|
|
||||||
Behavior on Layout.maximumWidth {
|
Behavior on Layout.maximumWidth {
|
||||||
+1
-1
@@ -125,7 +125,7 @@ Item {
|
|||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
animate: true
|
animate: true
|
||||||
fill: 1
|
fill: 1
|
||||||
font.pointSize: root.horizontal ? Tokens.font.size.larger : Tokens.font.size.large
|
font.pointSize: Tokens.font.size.larger
|
||||||
text: {
|
text: {
|
||||||
if (PowerProfiles.profile === PowerProfile.PowerSaver)
|
if (PowerProfiles.profile === PowerProfile.PowerSaver)
|
||||||
return "energy_savings_leaf";
|
return "energy_savings_leaf";
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.VectorImage
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Services.SystemTray
|
import Quickshell.Services.SystemTray
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Modules
|
import qs.Modules.Bar.Popouts
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -3,28 +3,28 @@ pragma ComponentBehavior: Bound
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell.Services.SystemTray
|
import Quickshell.Services.SystemTray
|
||||||
import qs.Components
|
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
import qs.Modules
|
import qs.Components
|
||||||
|
import qs.Modules.Bar.Components.Common
|
||||||
|
import qs.Modules.Bar.Components.Tray
|
||||||
|
import qs.Modules.Bar.Popouts
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
CustomClippingRect {
|
WidgetBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property bool horizontal
|
|
||||||
readonly property alias items: repeater
|
readonly property alias items: repeater
|
||||||
readonly property alias layout: sysGrid
|
readonly property alias layout: sysGrid
|
||||||
required property GridLayout loader
|
required property GridLayout loader
|
||||||
readonly property int padding: Tokens.padding.small
|
readonly property int padding: Tokens.padding.small
|
||||||
required property Wrapper popouts
|
required property Wrapper popouts
|
||||||
readonly property real shortSize: Config.bar.height
|
|
||||||
readonly property real size: horizontal ? sysGrid.implicitWidth + Tokens.padding.small : sysGrid.implicitHeight + Tokens.padding.small
|
readonly property real size: horizontal ? sysGrid.implicitWidth + Tokens.padding.small : sysGrid.implicitHeight + Tokens.padding.small
|
||||||
|
|
||||||
bottomLeftRadius: horizontal ? Tokens.rounding.full : Tokens.rounding.smallest / 2
|
bottomLeftRadius: horizontal ? Tokens.rounding.full : Tokens.rounding.smallest / 2
|
||||||
bottomRightRadius: Tokens.rounding.smallest / 2
|
bottomRightRadius: Tokens.rounding.smallest / 2
|
||||||
color: Colors.tPalette.m3surfaceContainer
|
color: Colors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: horizontal ? shortSize : size
|
implicitHeight: horizontal ? baseSize : size
|
||||||
implicitWidth: horizontal ? size : shortSize
|
implicitWidth: horizontal ? size : baseSize
|
||||||
radius: Tokens.rounding.full
|
radius: Tokens.rounding.full
|
||||||
topRightRadius: horizontal ? Tokens.rounding.smallest / 2 : Tokens.rounding.full
|
topRightRadius: horizontal ? Tokens.rounding.smallest / 2 : Tokens.rounding.full
|
||||||
|
|
||||||
@@ -1,21 +1,20 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Components
|
|
||||||
import qs.Modules
|
|
||||||
import qs.Helpers
|
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules.Bar.Components.Common
|
||||||
|
import qs.Helpers
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
CustomRect {
|
WidgetBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property int countUpdates: Updates.availableUpdates
|
property int countUpdates: Updates.availableUpdates
|
||||||
required property bool horizontal
|
|
||||||
property color textColor: Colors.palette.m3onSurface
|
property color textColor: Colors.palette.m3onSurface
|
||||||
|
|
||||||
color: Colors.tPalette.m3surfaceContainer
|
color: Colors.tPalette.m3surfaceContainer
|
||||||
implicitHeight: horizontal ? Config.bar.height : content.implicitHeight + Tokens.spacing.small * 2
|
implicitHeight: horizontal ? baseSize : content.implicitHeight + Tokens.spacing.small
|
||||||
implicitWidth: horizontal ? content.implicitWidth + Tokens.spacing.small * 2 : Config.bar.height
|
implicitWidth: horizontal ? content.implicitWidth + Tokens.spacing.small * 2 : baseSize
|
||||||
radius: Tokens.rounding.full
|
radius: Tokens.rounding.full
|
||||||
|
|
||||||
GridLayout {
|
GridLayout {
|
||||||
@@ -24,6 +23,7 @@ CustomRect {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
columnSpacing: Tokens.spacing.small
|
columnSpacing: Tokens.spacing.small
|
||||||
columns: root.horizontal ? -1 : 1
|
columns: root.horizontal ? -1 : 1
|
||||||
|
rowSpacing: -Tokens.spacing.extraSmall / 2
|
||||||
|
|
||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
|
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
|
||||||
@@ -34,7 +34,7 @@ CustomRect {
|
|||||||
CustomText {
|
CustomText {
|
||||||
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
|
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
|
||||||
color: root.textColor
|
color: root.textColor
|
||||||
font.pointSize: root.horizontal ? Tokens.font.size.normal : Tokens.font.size.larger
|
font.pointSize: Tokens.font.size.normal
|
||||||
text: root.countUpdates
|
text: root.countUpdates
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Components
|
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
|
import qs.Components
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
@@ -17,13 +17,12 @@ Item {
|
|||||||
readonly property int maxSize: {
|
readonly property int maxSize: {
|
||||||
const otherModules = bar.children.filter(c => c.enabled && c.entryId && c.item !== this && c.entryId !== "spacer");
|
const otherModules = bar.children.filter(c => c.enabled && c.entryId && c.item !== this && c.entryId !== "spacer");
|
||||||
const otherSize = otherModules.reduce((acc, curr) => acc + (horizontal ? (curr.item?.nonAnimWidth ?? curr.width ?? 0) : (curr.item.nonAnimHeight ?? curr.height ?? 0)), 0);
|
const otherSize = otherModules.reduce((acc, curr) => acc + (horizontal ? (curr.item?.nonAnimWidth ?? curr.width ?? 0) : (curr.item.nonAnimHeight ?? curr.height ?? 0)), 0);
|
||||||
return horizontal ? bar.width - otherSize - bar.spacing * (bar.children.length - 1) - bar.vPadding * 2 : bar.height - otherSize - bar.vPadding * (bar.children.length - 1) - bar.vPadding * 4;
|
return horizontal ? (bar.width - otherSize - bar.columnSpacing * (bar.children.length - 1) - bar.vPadding * 2) : (bar.height - otherSize - bar.rowSpacing * (bar.children.length - 1) - bar.vPadding * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
clip: true
|
clip: true
|
||||||
implicitHeight: horizontal ? current.implicitHeight : current.implicitWidth + current.anchors.topMargin
|
implicitHeight: horizontal ? current.implicitHeight : current.implicitWidth + current.anchors.topMargin
|
||||||
implicitWidth: horizontal ? Math.min(current.implicitWidth, root.maxSize) : current.implicitHeight + current.anchors.topMargin
|
implicitWidth: horizontal ? current.implicitWidth + current.anchors.leftMargin : current.implicitHeight + current.anchors.topMargin
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
Behavior on implicitHeight {
|
||||||
enabled: !root.horizontal
|
enabled: !root.horizontal
|
||||||
@@ -36,6 +35,7 @@ Item {
|
|||||||
enabled: root.horizontal
|
enabled: root.horizontal
|
||||||
|
|
||||||
Anim {
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2,10 +2,10 @@ pragma ComponentBehavior: Bound
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Effects
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
|
import qs.Modules.Bar.Components.Workspaces
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ Item {
|
|||||||
required property bool horizontal
|
required property bool horizontal
|
||||||
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen)
|
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen)
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
readonly property real shortSize: Math.max(Config.bar.height, 24)
|
readonly property real shortSize: Math.max(Config.bar.height, Tokens.bar.innerSize)
|
||||||
readonly property real size: (workspaceButtonWidth * workspacesShown) + activeWorkspaceMargin * 2
|
readonly property real size: (workspaceButtonWidth * workspacesShown) + activeWorkspaceMargin * 2
|
||||||
property int workspaceButtonWidth: (horizontal ? bgRect.implicitHeight : bgRect.implicitWidth) - root.activeWorkspaceMargin * 2
|
property int workspaceButtonWidth: (horizontal ? bgRect.implicitHeight : bgRect.implicitWidth) - root.activeWorkspaceMargin * 2
|
||||||
property int workspaceIndexInGroup: (effectiveActiveWorkspaceId - 1) % root.workspacesShown
|
property int workspaceIndexInGroup: (effectiveActiveWorkspaceId - 1) % root.workspacesShown
|
||||||
@@ -90,7 +90,7 @@ Item {
|
|||||||
color: Colors.palette.m3onSecondaryContainer
|
color: Colors.palette.m3onSecondaryContainer
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
text: button.modelData.name
|
text: button.modelData?.name ?? ""
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,10 +5,6 @@ import Quickshell.Services.SystemTray
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Modules.WSOverview
|
|
||||||
import qs.Modules.Network
|
|
||||||
import qs.Modules.SysTray.Popouts
|
|
||||||
import qs.Modules.Updates
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import ZShell.Config
|
|
||||||
import qs.Modules
|
|
||||||
import qs.Helpers
|
|
||||||
import qs.Components
|
|
||||||
import qs.Services
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property bool horizontal
|
|
||||||
required property GridLayout loader
|
|
||||||
required property Wrapper popouts
|
|
||||||
readonly property real shortSize: Config.bar.height
|
|
||||||
readonly property real size: timeText.contentWidth + (horizontal ? Tokens.padding.normal : Tokens.padding.larger) * 2
|
|
||||||
required property PersistentProperties visibilities
|
|
||||||
|
|
||||||
color: visibilities.dashboard ? Colors.palette.m3primary : Colors.tPalette.m3surfaceContainer
|
|
||||||
implicitHeight: horizontal ? shortSize : size
|
|
||||||
implicitWidth: horizontal ? size : shortSize
|
|
||||||
radius: Tokens.rounding.full
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
id: timeText
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
// anchors.horizontalCenter: root.horizontal ? undefined : parent.horizontalCenter
|
|
||||||
// anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined
|
|
||||||
color: root.visibilities.dashboard ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
|
||||||
font: Config.appearance.font.family.mono // qmllint disable incompatible-type
|
|
||||||
height: root.horizontal ? implicitHeight : implicitWidth
|
|
||||||
text: Time.dateStr
|
|
||||||
width: root.horizontal ? implicitWidth : implicitHeight
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
CAnim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
transform: [
|
|
||||||
Translate {
|
|
||||||
x: !root.horizontal ? -timeText.implicitWidth + timeText.implicitHeight : 0
|
|
||||||
},
|
|
||||||
Rotation {
|
|
||||||
angle: root.horizontal ? 0 : 270
|
|
||||||
origin.x: timeText.implicitHeight / 2
|
|
||||||
origin.y: timeText.implicitHeight / 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
StateLayer {
|
|
||||||
acceptedButtons: Qt.LeftButton
|
|
||||||
color: root.visibilities.dashboard ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
root.visibilities.dashboard = !root.visibilities.dashboard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,16 +14,18 @@ Item {
|
|||||||
|
|
||||||
reloadableId: "dashboardState"
|
reloadableId: "dashboardState"
|
||||||
}
|
}
|
||||||
required property bool horizontal
|
|
||||||
readonly property real nonAnimHeight: state === "visible" ? (content.item?.nonAnimHeight ?? 0) : 0
|
readonly property real nonAnimHeight: state === "visible" ? (content.item?.nonAnimHeight ?? 0) : 0
|
||||||
required property real offsetScale
|
required property real offsetScale
|
||||||
|
required property string position
|
||||||
readonly property bool shouldBeActive: root.visibilities.dashboard && Config.dashboard.enabled
|
readonly property bool shouldBeActive: root.visibilities.dashboard && Config.dashboard.enabled
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
anchors.left: horizontal ? undefined : parent.left
|
anchors.bottom: position === "bottom" ? parent.bottom : undefined
|
||||||
anchors.leftMargin: horizontal ? 0 : (-implicitWidth - 5) * offsetScale
|
anchors.bottomMargin: position === "bottom" ? (-implicitHeight - 5) * offsetScale : 0
|
||||||
anchors.top: horizontal ? parent.top : undefined
|
anchors.left: position === "left" ? parent.left : undefined
|
||||||
anchors.topMargin: horizontal ? (-implicitHeight - 5) * offsetScale : 0
|
anchors.leftMargin: position === "left" ? (-implicitWidth - 5) * offsetScale : 0
|
||||||
|
anchors.top: position === "top" ? parent.top : undefined
|
||||||
|
anchors.topMargin: position === "top" ? (-implicitHeight - 5) * offsetScale : 0
|
||||||
implicitHeight: content.implicitHeight
|
implicitHeight: content.implicitHeight
|
||||||
implicitWidth: content.implicitWidth || 854
|
implicitWidth: content.implicitWidth || 854
|
||||||
opacity: 1 - offsetScale
|
opacity: 1 - offsetScale
|
||||||
@@ -33,10 +35,11 @@ Item {
|
|||||||
id: content
|
id: content
|
||||||
|
|
||||||
active: root.shouldBeActive || root.visible
|
active: root.shouldBeActive || root.visible
|
||||||
anchors.bottom: root.horizontal ? parent.bottom : undefined
|
anchors.bottom: root.position === "top" ? parent.bottom : undefined
|
||||||
anchors.horizontalCenter: root.horizontal ? parent.horizontalCenter : undefined
|
anchors.horizontalCenter: root.position !== "left" ? parent.horizontalCenter : undefined
|
||||||
anchors.right: root.horizontal ? undefined : parent.right
|
anchors.right: root.position !== "left" ? undefined : parent.right
|
||||||
anchors.verticalCenter: root.horizontal ? undefined : parent.verticalCenter
|
anchors.top: root.position === "bottom" ? parent.top : undefined
|
||||||
|
anchors.verticalCenter: root.position === "left" ? undefined : parent.verticalCenter
|
||||||
|
|
||||||
sourceComponent: Content {
|
sourceComponent: Content {
|
||||||
dashState: root.dashState
|
dashState: root.dashState
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ Searcher {
|
|||||||
list.visibilities.launcher = false;
|
list.visibilities.launcher = false;
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--scheme", variant]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--scheme", variant]);
|
||||||
Config.colors.schemeType = variant;
|
Config.colors.schemeType = variant;
|
||||||
Config.save();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,18 @@ import ZShell.Config
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property bool horizontal
|
|
||||||
readonly property real nonAnimHeight: content.item?.nonAnimHeight ?? 0
|
readonly property real nonAnimHeight: content.item?.nonAnimHeight ?? 0
|
||||||
property real offsetScale: shouldBeActive ? 0 : 1
|
property real offsetScale: shouldBeActive ? 0 : 1
|
||||||
|
required property string position
|
||||||
readonly property bool shouldBeActive: root.visibilities.resources
|
readonly property bool shouldBeActive: root.visibilities.resources
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
anchors.leftMargin: horizontal ? 0 : (-implicitWidth - 5) * offsetScale
|
anchors.bottom: position === "bottom" ? parent.bottom : undefined
|
||||||
anchors.topMargin: horizontal ? (-implicitHeight - 5) * offsetScale : 0
|
anchors.bottomMargin: position === "bottom" ? (-implicitHeight - 5) * offsetScale : 0
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: position === "left" ? (-implicitWidth - 5) * offsetScale : 0
|
||||||
|
anchors.top: position !== "bottom" ? parent.top : undefined
|
||||||
|
anchors.topMargin: position === "top" ? (-implicitHeight - 5) * offsetScale : 0
|
||||||
clip: true
|
clip: true
|
||||||
implicitHeight: content.implicitHeight
|
implicitHeight: content.implicitHeight
|
||||||
implicitWidth: content.implicitWidth || 854 // Hard coded fallback for first open
|
implicitWidth: content.implicitWidth || 854 // Hard coded fallback for first open
|
||||||
@@ -33,7 +37,11 @@ Item {
|
|||||||
id: content
|
id: content
|
||||||
|
|
||||||
active: root.shouldBeActive || root.visible
|
active: root.shouldBeActive || root.visible
|
||||||
anchors.centerIn: parent
|
anchors.bottom: root.position === "top" ? parent.bottom : undefined
|
||||||
|
anchors.horizontalCenter: root.position !== "left" ? parent.horizontalCenter : undefined
|
||||||
|
anchors.right: root.position !== "left" ? undefined : parent.right
|
||||||
|
anchors.top: root.position === "bottom" ? parent.top : undefined
|
||||||
|
anchors.verticalCenter: root.position === "left" ? undefined : parent.verticalCenter
|
||||||
|
|
||||||
sourceComponent: Content {
|
sourceComponent: Content {
|
||||||
wrapper: root
|
wrapper: root
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ PageBase {
|
|||||||
active: Config.bar.position === "top" ? menuItems[0] : Config.bar.position === "left" ? menuItems[1] : menuItems[2]
|
active: Config.bar.position === "top" ? menuItems[0] : Config.bar.position === "left" ? menuItems[1] : menuItems[2]
|
||||||
last: true
|
last: true
|
||||||
settingAnchor: "bar-position"
|
settingAnchor: "bar-position"
|
||||||
subtext: qsTr("Automatic or manual effect values")
|
subtext: qsTr("Change which edge the bar appears on")
|
||||||
text: qsTr("Effects mode")
|
text: qsTr("Position")
|
||||||
|
|
||||||
menuItems: [
|
menuItems: [
|
||||||
MenuItem {
|
MenuItem {
|
||||||
@@ -58,10 +58,7 @@ PageBase {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
onSelected: item => {
|
onSelected: item => Config.bar.position = item.value
|
||||||
Config.bar.position = item.value;
|
|
||||||
Config.save();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
|
|||||||
@@ -70,10 +70,7 @@ PageBase {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
onSelected: item => {
|
onSelected: item => Config.screenshot.mode = item.value
|
||||||
Config.screenshot.mode = item.value;
|
|
||||||
Config.save();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionHeader {
|
SectionHeader {
|
||||||
|
|||||||
@@ -104,7 +104,6 @@ PageBase {
|
|||||||
onApplySettings: (start, end) => {
|
onApplySettings: (start, end) => {
|
||||||
Config.general.color.scheduleDarkStart = start;
|
Config.general.color.scheduleDarkStart = start;
|
||||||
Config.general.color.scheduleDarkEnd = end;
|
Config.general.color.scheduleDarkEnd = end;
|
||||||
Config.save();
|
|
||||||
ModeScheduler.checkStartup();
|
ModeScheduler.checkStartup();
|
||||||
PopupManager.requestClose();
|
PopupManager.requestClose();
|
||||||
}
|
}
|
||||||
@@ -146,7 +145,6 @@ PageBase {
|
|||||||
onApplySettings: (start, end) => {
|
onApplySettings: (start, end) => {
|
||||||
Config.general.color.scheduleHyprsunsetStart = start;
|
Config.general.color.scheduleHyprsunsetStart = start;
|
||||||
Config.general.color.scheduleHyprsunsetEnd = end;
|
Config.general.color.scheduleHyprsunsetEnd = end;
|
||||||
Config.save();
|
|
||||||
Hyprsunset.checkStartup();
|
Hyprsunset.checkStartup();
|
||||||
PopupManager.requestClose();
|
PopupManager.requestClose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,159 +0,0 @@
|
|||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Quickshell.Services.SystemTray
|
|
||||||
import qs.Components
|
|
||||||
import ZShell.Config
|
|
||||||
import qs.Modules.SysTray.Widgets
|
|
||||||
import qs.Modules
|
|
||||||
import qs.Services
|
|
||||||
|
|
||||||
GridLayout {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property bool horizontal
|
|
||||||
readonly property alias items: repeater
|
|
||||||
required property GridLayout loader
|
|
||||||
required property Wrapper popouts
|
|
||||||
readonly property real shortSize: Config.bar.height + Tokens.padding.smallest * 2
|
|
||||||
readonly property real size: horizontal ? sysTray.implicitWidth + sysTrayMod.implicitWidth + Tokens.padding.small : sysTray.implicitHeight + sysTrayMod.implicitHeight + Tokens.padding.small
|
|
||||||
|
|
||||||
function closestRowChild(row, x) {
|
|
||||||
let child = row.childAt(x, row.height / 2);
|
|
||||||
if (child)
|
|
||||||
return child;
|
|
||||||
|
|
||||||
let closest = null;
|
|
||||||
let closestDistance = Infinity;
|
|
||||||
|
|
||||||
for (let i = 0; i < row.children.length; ++i) {
|
|
||||||
let c = row.children[i];
|
|
||||||
|
|
||||||
if (!c.visible || c.width <= 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let centerX = c.x + c.width / 2;
|
|
||||||
let dist = Math.abs(x - centerX);
|
|
||||||
|
|
||||||
if (dist < closestDistance) {
|
|
||||||
closestDistance = dist;
|
|
||||||
closest = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return closest;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHoveredSubItem(localX, localY) {
|
|
||||||
let modPos = mapToItem(sysTrayMod, localX, localY);
|
|
||||||
if (sysTrayMod.contains(Qt.point(modPos.x, modPos.y))) {
|
|
||||||
let modRowPos = sysTrayMod.mapToItem(sysIcons, modPos.x, modPos.y);
|
|
||||||
let child = closestRowChild(sysIcons, modRowPos.x);
|
|
||||||
if (child) {
|
|
||||||
if (child.objectName === "audio" && Config.bar.popouts.audio)
|
|
||||||
return {
|
|
||||||
id: "audio",
|
|
||||||
item: child
|
|
||||||
};
|
|
||||||
if (child.objectName === "microphone" && Config.bar.popouts.audio)
|
|
||||||
return {
|
|
||||||
id: "audio",
|
|
||||||
item: child
|
|
||||||
};
|
|
||||||
if (child.objectName === "upower" && Config.bar.popouts.upower)
|
|
||||||
return {
|
|
||||||
id: "upower",
|
|
||||||
item: child
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let trayPos = mapToItem(sysTray, localX, localY);
|
|
||||||
if (Config.bar.tray.showOnHover && sysTray.contains(Qt.point(trayPos.x, trayPos.y))) {
|
|
||||||
let trayRowPos = sysTray.mapToItem(sysRow, trayPos.x, trayPos.y);
|
|
||||||
let child = sysRow.childAt(trayRowPos.x, trayRowPos.y);
|
|
||||||
if (child && child.hasOwnProperty("ind")) {
|
|
||||||
return {
|
|
||||||
id: `traymenu${child.ind}`,
|
|
||||||
item: child
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
columnSpacing: Tokens.padding.small
|
|
||||||
columns: horizontal ? -1 : 1
|
|
||||||
height: horizontal ? shortSize : size
|
|
||||||
rowSpacing: Tokens.padding.small
|
|
||||||
width: horizontal ? size : shortSize
|
|
||||||
|
|
||||||
CustomClippingRect {
|
|
||||||
id: sysTray
|
|
||||||
|
|
||||||
Layout.fillHeight: true
|
|
||||||
bottomRightRadius: Tokens.rounding.smallest / 2
|
|
||||||
color: Colors.tPalette.m3surfaceContainer
|
|
||||||
implicitWidth: sysRow.width + Tokens.padding.small * 2
|
|
||||||
radius: Tokens.rounding.full
|
|
||||||
topRightRadius: Tokens.rounding.smallest / 2
|
|
||||||
|
|
||||||
GridLayout {
|
|
||||||
id: sysRow
|
|
||||||
|
|
||||||
anchors.bottom: root.horizontal ? undefined : parent.bottom
|
|
||||||
anchors.centerIn: parent
|
|
||||||
anchors.horizontalCenter: root.horizontal ? parent.horizontalCenter : undefined
|
|
||||||
anchors.left: root.horizontal ? undefined : parent.left
|
|
||||||
anchors.right: root.horizontal ? undefined : parent.right
|
|
||||||
anchors.verticalCenter: root.horizontal ? parent.verticalCenter : undefined
|
|
||||||
columnSpacing: Tokens.spacing.small / 2
|
|
||||||
columns: root.horizontal ? -1 : 1
|
|
||||||
rowSpacing: Tokens.spacing.small / 2
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
id: repeater
|
|
||||||
|
|
||||||
model: SystemTray.items
|
|
||||||
|
|
||||||
TrayItem {
|
|
||||||
id: trayItem
|
|
||||||
|
|
||||||
required property int index
|
|
||||||
required property SystemTrayItem modelData
|
|
||||||
|
|
||||||
implicitHeight: 34
|
|
||||||
implicitWidth: 34
|
|
||||||
ind: index
|
|
||||||
item: modelData
|
|
||||||
loader: root.loader
|
|
||||||
popouts: root.popouts
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomClippingRect {
|
|
||||||
id: sysTrayMod
|
|
||||||
|
|
||||||
Layout.fillHeight: root.horizontal
|
|
||||||
Layout.fillWidth: !root.horizontal
|
|
||||||
bottomLeftRadius: Tokens.rounding.smallest / 2
|
|
||||||
color: Colors.tPalette.m3surfaceContainer
|
|
||||||
implicitHeight: root.horizontal ? sysIcons.implicitHeight : sysIcons.implicitHeight + Tokens.padding.smaller + Tokens.padding.normal
|
|
||||||
implicitWidth: root.horizontal ? sysIcons.implicitWidth + Tokens.padding.smaller + Tokens.padding.normal : sysIcons.implicitWidth
|
|
||||||
radius: Tokens.rounding.full
|
|
||||||
topLeftRadius: Tokens.rounding.smallest / 2
|
|
||||||
|
|
||||||
StatusIcons {
|
|
||||||
id: sysIcons
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: Tokens.padding.smaller
|
|
||||||
anchors.rightMargin: Tokens.padding.normal
|
|
||||||
horizontal: root.horizontal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import ZShell.Config
|
|
||||||
import qs.Components
|
|
||||||
import qs.Modules
|
|
||||||
import qs.Helpers
|
|
||||||
import qs.Services
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property ShellScreen screen
|
|
||||||
required property Item wrapper
|
|
||||||
|
|
||||||
implicitHeight: layout.implicitHeight + 16
|
|
||||||
implicitWidth: layout.implicitWidth + 16
|
|
||||||
|
|
||||||
GridLayout {
|
|
||||||
id: layout
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
columnSpacing: 8
|
|
||||||
rowSpacing: 8
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: Hypr.workspaces
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
id: workspacePreview
|
|
||||||
|
|
||||||
required property HyprlandWorkspace modelData
|
|
||||||
|
|
||||||
Layout.preferredHeight: 180 + 10
|
|
||||||
Layout.preferredWidth: 320 + 10
|
|
||||||
border.color: "white"
|
|
||||||
border.width: 1
|
|
||||||
radius: Tokens.rounding.smallest
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: workspacePreview.modelData.toplevels
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: preview
|
|
||||||
|
|
||||||
property rect appPosition: {
|
|
||||||
let {
|
|
||||||
at: [cx, cy],
|
|
||||||
size: [cw, ch]
|
|
||||||
} = modelData.lastIpcObject;
|
|
||||||
|
|
||||||
cx -= modelData.monitor.x;
|
|
||||||
cy -= modelData.monitor.y;
|
|
||||||
|
|
||||||
return Qt.rect((cx / 8), (cy / 8), (cw / 8), (ch / 8));
|
|
||||||
}
|
|
||||||
required property HyprlandToplevel modelData
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: 5
|
|
||||||
|
|
||||||
CustomRect {
|
|
||||||
border.color: Colors.tPalette.m3outline
|
|
||||||
border.width: 1
|
|
||||||
implicitHeight: preview.appPosition.height
|
|
||||||
implicitWidth: preview.appPosition.width
|
|
||||||
radius: Tokens.rounding.smallest / 2
|
|
||||||
x: preview.appPosition.x
|
|
||||||
y: preview.appPosition.y - 3.4
|
|
||||||
|
|
||||||
ScreencopyView {
|
|
||||||
id: previewCopy
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
captureSource: preview.modelData.wayland
|
|
||||||
live: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "configlist.hpp"
|
#include "configlist.hpp"
|
||||||
#include "configobject.hpp"
|
#include "configobject.hpp"
|
||||||
#include <qcontainerfwd.h>
|
#include <qcontainerfwd.h>
|
||||||
|
#include <qhashfunctions.h>
|
||||||
#include <qqmlregistration.h>
|
#include <qqmlregistration.h>
|
||||||
|
|
||||||
namespace ZShell::config {
|
namespace ZShell::config {
|
||||||
@@ -62,7 +63,7 @@ class Bar : public ConfigObject {
|
|||||||
CFG_PROPERTY(int, revealDelay, 100)
|
CFG_PROPERTY(int, revealDelay, 100)
|
||||||
CFG_PROPERTY(int, rounding, 14)
|
CFG_PROPERTY(int, rounding, 14)
|
||||||
CFG_PROPERTY(int, smoothing, 32)
|
CFG_PROPERTY(int, smoothing, 32)
|
||||||
CFG_PROPERTY(QString, position, "top")
|
CFG_PROPERTY(QString, position, QStringLiteral("top"))
|
||||||
CONFIG_SUBOBJECT(Tray, tray)
|
CONFIG_SUBOBJECT(Tray, tray)
|
||||||
CONFIG_LIST(
|
CONFIG_LIST(
|
||||||
EntryList,
|
EntryList,
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ Config::Config(QObject* parent)
|
|||||||
m_reloadTimer.setInterval(50);
|
m_reloadTimer.setInterval(50);
|
||||||
connect(&m_reloadTimer, &QTimer::timeout, this, &Config::reloadAsync);
|
connect(&m_reloadTimer, &QTimer::timeout, this, &Config::reloadAsync);
|
||||||
|
|
||||||
|
connectAutoSave(this);
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
&m_watcher,
|
&m_watcher,
|
||||||
&QFileSystemWatcher::directoryChanged,
|
&QFileSystemWatcher::directoryChanged,
|
||||||
@@ -93,15 +95,31 @@ QString Config::filePath() const {
|
|||||||
|
|
||||||
void Config::loadSync() {
|
void Config::loadSync() {
|
||||||
m_loading = true;
|
m_loading = true;
|
||||||
|
|
||||||
QFile f(filePath());
|
QFile f(filePath());
|
||||||
|
QJsonObject before;
|
||||||
|
|
||||||
|
bool existed = false;
|
||||||
|
|
||||||
if (f.open(QIODevice::ReadOnly)) {
|
if (f.open(QIODevice::ReadOnly)) {
|
||||||
const auto doc = QJsonDocument::fromJson(f.readAll());
|
const auto doc = QJsonDocument::fromJson(f.readAll());
|
||||||
if (doc.isObject()) loadFromJson(QJsonValue(doc.object()));
|
if (doc.isObject()) {
|
||||||
|
before = doc.object();
|
||||||
|
existed = true;
|
||||||
|
} else {
|
||||||
|
qInfo() << "Config: existing config at" << filePath()
|
||||||
|
<< "is empty or not a valid JSON object - using defaults";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
qInfo() << "Config: no existing config at" << filePath()
|
qInfo() << "Config: no existing config at" << filePath()
|
||||||
<< "- using defaults";
|
<< "- using defaults";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadFromJson(QJsonValue(before));
|
||||||
m_loading = false;
|
m_loading = false;
|
||||||
|
|
||||||
|
const auto after = toJson().toObject();
|
||||||
|
if (!existed || after != before) saveNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::updateWatch() {
|
void Config::updateWatch() {
|
||||||
@@ -146,27 +164,21 @@ void Config::loadAsync() {
|
|||||||
|
|
||||||
if (f.open(QIODevice::ReadOnly)) {
|
if (f.open(QIODevice::ReadOnly)) {
|
||||||
const auto doc = QJsonDocument::fromJson(f.readAll());
|
const auto doc = QJsonDocument::fromJson(f.readAll());
|
||||||
|
const bool valid = doc.isObject();
|
||||||
|
const QJsonObject before = valid ? doc.object() : QJsonObject();
|
||||||
|
|
||||||
if (doc.isObject()) {
|
QMetaObject::invokeMethod(
|
||||||
QMetaObject::invokeMethod(
|
this,
|
||||||
this,
|
[this, valid, before]() {
|
||||||
[this, doc]() {
|
loadFromJson(QJsonValue(before));
|
||||||
loadFromJson(QJsonValue(doc.object()));
|
m_loading = false;
|
||||||
m_loading = false;
|
|
||||||
|
|
||||||
if (m_reloadPending) m_reloadTimer.start();
|
const auto after = toJson().toObject();
|
||||||
},
|
if (!valid || after != before) saveNow();
|
||||||
Qt::QueuedConnection);
|
|
||||||
} else {
|
|
||||||
QMetaObject::invokeMethod(
|
|
||||||
this,
|
|
||||||
[this]() {
|
|
||||||
m_loading = false;
|
|
||||||
|
|
||||||
if (m_reloadPending) m_reloadTimer.start();
|
if (m_reloadPending) m_reloadTimer.start();
|
||||||
},
|
},
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
qInfo() << "Config: failed to reload from" << filePath()
|
qInfo() << "Config: failed to reload from" << filePath()
|
||||||
<< "- using in-memory values";
|
<< "- using in-memory values";
|
||||||
@@ -232,6 +244,15 @@ void Config::saveNow() {
|
|||||||
flushAsync();
|
flushAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Config::connectAutoSave(ConfigNode* node) {
|
||||||
|
connect(node, &ConfigNode::propertiesChanged, this, [this] {
|
||||||
|
scheduleSave();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto* child : node->childNodes())
|
||||||
|
connectAutoSave(child);
|
||||||
|
}
|
||||||
|
|
||||||
bool Config::writeAtomically(const QByteArray& data) {
|
bool Config::writeAtomically(const QByteArray& data) {
|
||||||
QSaveFile f(filePath());
|
QSaveFile f(filePath());
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ class Config : public ConfigObject {
|
|||||||
void updateWatch();
|
void updateWatch();
|
||||||
void loadSync();
|
void loadSync();
|
||||||
void loadAsync();
|
void loadAsync();
|
||||||
|
void connectAutoSave(ConfigNode* node);
|
||||||
|
|
||||||
QTimer m_saveTimer;
|
QTimer m_saveTimer;
|
||||||
QTimer m_reloadTimer;
|
QTimer m_reloadTimer;
|
||||||
|
|||||||
@@ -79,13 +79,14 @@ void ConfigList::loadFromJson(const QJsonValue& json) {
|
|||||||
if (!json.isArray()) {
|
if (!json.isArray()) {
|
||||||
qCWarning(
|
qCWarning(
|
||||||
lcConfig,
|
lcConfig,
|
||||||
"Option '%s' must be a list, ignoring",
|
"Option '%s' must be a list, resetting to default",
|
||||||
qUtf8Printable(propertyPath()));
|
qUtf8Printable(propertyPath()));
|
||||||
m_rejectedJson = json;
|
|
||||||
|
resetToDefaults();
|
||||||
|
materializeDefaults();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rejectedJson = QJsonValue::Undefined;
|
|
||||||
populate(json.toArray());
|
populate(json.toArray());
|
||||||
m_loaded = true;
|
m_loaded = true;
|
||||||
}
|
}
|
||||||
@@ -93,12 +94,11 @@ void ConfigList::loadFromJson(const QJsonValue& json) {
|
|||||||
QJsonValue ConfigList::toJson() const {
|
QJsonValue ConfigList::toJson() const {
|
||||||
if (m_loaded) return elementsToJson();
|
if (m_loaded) return elementsToJson();
|
||||||
|
|
||||||
return m_rejectedJson;
|
return QJsonValue::Undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigList::clearLoadedKeys() {
|
void ConfigList::clearLoadedKeys() {
|
||||||
m_loaded = false;
|
m_loaded = false;
|
||||||
m_rejectedJson = QJsonValue::Undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ConfigList::unknownKeys() const {
|
QStringList ConfigList::unknownKeys() const {
|
||||||
@@ -113,6 +113,15 @@ QStringList ConfigList::unknownKeys() const {
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigList::materializeDefaults() {
|
||||||
|
for (auto* const item : m_items)
|
||||||
|
item->materializeDefaults();
|
||||||
|
|
||||||
|
if (m_global) return;
|
||||||
|
|
||||||
|
m_loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigList::resyncFromGlobal() {
|
void ConfigList::resyncFromGlobal() {
|
||||||
syncValuesFromGlobal();
|
syncValuesFromGlobal();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class ConfigList : public ConfigNode {
|
|||||||
[[nodiscard]] QJsonValue toJson() const override;
|
[[nodiscard]] QJsonValue toJson() const override;
|
||||||
void clearLoadedKeys() override;
|
void clearLoadedKeys() override;
|
||||||
[[nodiscard]] QStringList unknownKeys() const override;
|
[[nodiscard]] QStringList unknownKeys() const override;
|
||||||
|
void materializeDefaults() override;
|
||||||
void resyncFromGlobal() override;
|
void resyncFromGlobal() override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -71,7 +72,6 @@ class ConfigList : public ConfigNode {
|
|||||||
QJsonArray m_defaults;
|
QJsonArray m_defaults;
|
||||||
QList<ConfigObject*> m_items;
|
QList<ConfigObject*> m_items;
|
||||||
bool m_loaded = false;
|
bool m_loaded = false;
|
||||||
QJsonValue m_rejectedJson = QJsonValue::Undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZShell::config
|
} // namespace ZShell::config
|
||||||
@@ -103,7 +103,6 @@ class ConfigList : public ConfigNode {
|
|||||||
} \
|
} \
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define CONFIG_LIST(Type, name, ...) \
|
#define CONFIG_LIST(Type, name, ...) \
|
||||||
Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \
|
Q_PROPERTY(ZShell::config::Type* name READ name CONSTANT) \
|
||||||
\
|
\
|
||||||
@@ -115,6 +114,8 @@ class ConfigList : public ConfigNode {
|
|||||||
private: \
|
private: \
|
||||||
Type* m_##name = new Type(this __VA_OPT__(, __VA_ARGS__));
|
Type* m_##name = new Type(this __VA_OPT__(, __VA_ARGS__));
|
||||||
|
|
||||||
|
#define LIST_ENTRY(id, enabled) \
|
||||||
|
vmap({{"id", QString::fromUtf8(#id)}, {"enabled", enabled}})
|
||||||
|
|
||||||
namespace ZShell::config {
|
namespace ZShell::config {
|
||||||
|
|
||||||
@@ -136,6 +137,3 @@ class ListEntry : public ConfigObject {
|
|||||||
CONFIG_LIST_TYPE(ListEntry, EntryList)
|
CONFIG_LIST_TYPE(ListEntry, EntryList)
|
||||||
|
|
||||||
} // namespace ZShell::config
|
} // namespace ZShell::config
|
||||||
|
|
||||||
#define LIST_ENTRY(id, enabled) \
|
|
||||||
vmap({{"id", QString::fromUtf8(#id)}, {"enabled", enabled}})
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ class ConfigNode : public QObject {
|
|||||||
[[nodiscard]] virtual QStringList unknownKeys() const = 0;
|
[[nodiscard]] virtual QStringList unknownKeys() const = 0;
|
||||||
[[nodiscard]] virtual QList<ConfigNode*> childNodes() const;
|
[[nodiscard]] virtual QList<ConfigNode*> childNodes() const;
|
||||||
|
|
||||||
|
virtual void materializeDefaults() = 0;
|
||||||
|
|
||||||
void syncFromGlobal(ConfigNode* global);
|
void syncFromGlobal(ConfigNode* global);
|
||||||
virtual void resyncFromGlobal() = 0;
|
virtual void resyncFromGlobal() = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,51 @@
|
|||||||
|
|
||||||
namespace ZShell::config {
|
namespace ZShell::config {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool isStringArray(const QJsonArray& arr) {
|
||||||
|
for (const auto& v : arr) {
|
||||||
|
if (!v.isString()) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jsonValueMatchesType(const QJsonValue& val, QMetaType type) {
|
||||||
|
switch (val.type()) {
|
||||||
|
case QJsonValue::Bool:
|
||||||
|
return type.id() == QMetaType::Bool;
|
||||||
|
|
||||||
|
case QJsonValue::Double:
|
||||||
|
switch (type.id()) {
|
||||||
|
case QMetaType::Int:
|
||||||
|
case QMetaType::UInt:
|
||||||
|
case QMetaType::LongLong:
|
||||||
|
case QMetaType::ULongLong:
|
||||||
|
case QMetaType::Double:
|
||||||
|
case QMetaType::Float:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QJsonValue::String:
|
||||||
|
return type.id() == QMetaType::QString;
|
||||||
|
|
||||||
|
case QJsonValue::Array:
|
||||||
|
if (type.id() == QMetaType::QStringList)
|
||||||
|
return isStringArray(val.toArray());
|
||||||
|
return type.id() == QMetaType::QVariantList;
|
||||||
|
|
||||||
|
case QJsonValue::Object:
|
||||||
|
case QJsonValue::Null:
|
||||||
|
case QJsonValue::Undefined:
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
ConfigObject::ConfigObject(QObject* parent) : ConfigNode(parent) {}
|
ConfigObject::ConfigObject(QObject* parent) : ConfigNode(parent) {}
|
||||||
|
|
||||||
void ConfigObject::loadFromJson(const QJsonValue& json) {
|
void ConfigObject::loadFromJson(const QJsonValue& json) {
|
||||||
@@ -14,6 +59,7 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
|
|||||||
const auto* meta = metaObject();
|
const auto* meta = metaObject();
|
||||||
|
|
||||||
QSet<QString> known;
|
QSet<QString> known;
|
||||||
|
QSet<QString> invalid;
|
||||||
|
|
||||||
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||||
auto prop = meta->property(i);
|
auto prop = meta->property(i);
|
||||||
@@ -34,6 +80,15 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
|
|||||||
|
|
||||||
if (!prop.isWritable()) continue;
|
if (!prop.isWritable()) continue;
|
||||||
|
|
||||||
|
if (!jsonValueMatchesType(jsonVal, prop.metaType())) {
|
||||||
|
qWarning() << "Config: type mismatch for" << key << "in"
|
||||||
|
<< meta->className() << "- expected"
|
||||||
|
<< prop.metaType().name() << "got value" << jsonVal
|
||||||
|
<< "- resetting to default";
|
||||||
|
invalid.insert(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (prop.metaType().id() == QMetaType::QStringList) {
|
if (prop.metaType().id() == QMetaType::QStringList) {
|
||||||
QStringList list;
|
QStringList list;
|
||||||
const auto jsonArr = jsonVal.toArray();
|
const auto jsonArr = jsonVal.toArray();
|
||||||
@@ -56,10 +111,12 @@ void ConfigObject::loadFromJson(const QJsonValue& json) {
|
|||||||
|
|
||||||
m_extras = {};
|
m_extras = {};
|
||||||
for (auto it = obj.begin(); it != obj.end(); ++it) {
|
for (auto it = obj.begin(); it != obj.end(); ++it) {
|
||||||
if (!known.contains(it.key())) {
|
if (!known.contains(it.key()) || invalid.contains(it.key())) {
|
||||||
m_extras.insert(it.key(), it.value());
|
m_extras.insert(it.key(), it.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
materializeDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonValue ConfigObject::toJson() const {
|
QJsonValue ConfigObject::toJson() const {
|
||||||
@@ -104,9 +161,6 @@ QJsonValue ConfigObject::toJson() const {
|
|||||||
obj.insert(key, QJsonValue::fromVariant(value));
|
obj.insert(key, QJsonValue::fromVariant(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it = m_extras.begin(); it != m_extras.end(); ++it)
|
|
||||||
obj.insert(it.key(), it.value());
|
|
||||||
|
|
||||||
if (obj.isEmpty()) return QJsonValue::Undefined;
|
if (obj.isEmpty()) return QJsonValue::Undefined;
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
@@ -159,6 +213,26 @@ QList<ConfigNode*> ConfigObject::childNodes() const {
|
|||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigObject::materializeDefaults() {
|
||||||
|
const auto* meta = metaObject();
|
||||||
|
|
||||||
|
for (int i = basePropertyOffset(); i < meta->propertyCount(); ++i) {
|
||||||
|
const auto prop = meta->property(i);
|
||||||
|
const auto key = QString::fromUtf8(prop.name());
|
||||||
|
|
||||||
|
if (auto* const node = prop.read(this).value<ConfigNode*>()) {
|
||||||
|
node->materializeDefaults();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prop.isWritable()) continue;
|
||||||
|
|
||||||
|
if (m_global) continue;
|
||||||
|
|
||||||
|
m_loadedKeys.insert(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigObject::syncValuesFromGlobal() {
|
void ConfigObject::syncValuesFromGlobal() {
|
||||||
const auto* meta = metaObject();
|
const auto* meta = metaObject();
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class ConfigObject : public ConfigNode {
|
|||||||
void clearLoadedKeys() override;
|
void clearLoadedKeys() override;
|
||||||
[[nodiscard]] QStringList unknownKeys() const override;
|
[[nodiscard]] QStringList unknownKeys() const override;
|
||||||
[[nodiscard]] QList<ConfigNode*> childNodes() const override;
|
[[nodiscard]] QList<ConfigNode*> childNodes() const override;
|
||||||
|
void materializeDefaults() override;
|
||||||
void resyncFromGlobal() override;
|
void resyncFromGlobal() override;
|
||||||
|
|
||||||
[[nodiscard]] virtual QStringList identityKeys() const;
|
[[nodiscard]] virtual QStringList identityKeys() const;
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
#include "configobject.hpp"
|
#include "configobject.hpp"
|
||||||
|
|
||||||
#include <QVariantList>
|
#include <QVariantList>
|
||||||
|
#include <qobject.h>
|
||||||
#include <qqmlengine.h>
|
#include <qqmlengine.h>
|
||||||
|
#include <qqmlintegration.h>
|
||||||
#include <qqmlregistration.h>
|
#include <qqmlregistration.h>
|
||||||
|
|
||||||
namespace ZShell::config {
|
namespace ZShell::config {
|
||||||
@@ -195,6 +197,16 @@ class AnimTokens : public ConfigObject {
|
|||||||
, m_durations(new AnimDurations(this)) {}
|
, m_durations(new AnimDurations(this)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BarTokens : public ConfigObject {
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ANONYMOUS
|
||||||
|
|
||||||
|
CFG_PROPERTY(int, innerSize, 28)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BarTokens(QObject* parent = nullptr) : ConfigObject(parent) {}
|
||||||
|
};
|
||||||
|
|
||||||
class Tokens : public ConfigObject {
|
class Tokens : public ConfigObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QML_ELEMENT
|
QML_ELEMENT
|
||||||
@@ -205,6 +217,7 @@ class Tokens : public ConfigObject {
|
|||||||
CONFIG_SUBOBJECT(AppearanceSpacing, spacing)
|
CONFIG_SUBOBJECT(AppearanceSpacing, spacing)
|
||||||
CONFIG_SUBOBJECT(FontTokens, font)
|
CONFIG_SUBOBJECT(FontTokens, font)
|
||||||
CONFIG_SUBOBJECT(AnimTokens, anim)
|
CONFIG_SUBOBJECT(AnimTokens, anim)
|
||||||
|
CONFIG_SUBOBJECT(BarTokens, bar)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Tokens(QObject* parent = nullptr)
|
explicit Tokens(QObject* parent = nullptr)
|
||||||
@@ -213,7 +226,8 @@ class Tokens : public ConfigObject {
|
|||||||
, m_padding(new AppearancePadding(this))
|
, m_padding(new AppearancePadding(this))
|
||||||
, m_spacing(new AppearanceSpacing(this))
|
, m_spacing(new AppearanceSpacing(this))
|
||||||
, m_font(new FontTokens(this))
|
, m_font(new FontTokens(this))
|
||||||
, m_anim(new AnimTokens(this)) {}
|
, m_anim(new AnimTokens(this))
|
||||||
|
, m_bar(new BarTokens(this)) {}
|
||||||
|
|
||||||
static Tokens* create(QQmlEngine*, QJSEngine*) { return new Tokens(); }
|
static Tokens* create(QQmlEngine*, QJSEngine*) { return new Tokens(); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -113,7 +113,6 @@ Singleton {
|
|||||||
function setMode(mode: string): void {
|
function setMode(mode: string): void {
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
|
||||||
Config.general.color.mode = mode;
|
Config.general.color.mode = mode;
|
||||||
Config.save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function swapRG(c: color): color {
|
function swapRG(c: color): color {
|
||||||
|
|||||||
+17
-7
@@ -30,14 +30,24 @@ RUN pacman -S --noconfirm \
|
|||||||
glib2
|
glib2
|
||||||
|
|
||||||
# AUR: libcava (provides development headers for cava)
|
# AUR: libcava (provides development headers for cava)
|
||||||
RUN pacman -S --needed --noconfirm sudo && \
|
RUN pacman -Syu --noconfirm && \
|
||||||
|
pacman -S --needed --noconfirm \
|
||||||
|
sudo \
|
||||||
|
meson \
|
||||||
|
autoconf-archive \
|
||||||
|
python-tqdm && \
|
||||||
useradd -m builder && \
|
useradd -m builder && \
|
||||||
echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
|
echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||||
su builder -c " \
|
|
||||||
git clone https://aur.archlinux.org/libcava.git /tmp/libcava && \
|
RUN for i in 1 2 3 4 5; do \
|
||||||
cd /tmp/libcava && \
|
rm -rf /tmp/libcava && \
|
||||||
makepkg -si --noconfirm \
|
git clone --depth 1 https://aur.archlinux.org/libcava.git /tmp/libcava && \
|
||||||
" && \
|
break || sleep 5; \
|
||||||
|
done && \
|
||||||
|
test -d /tmp/libcava/.git && \
|
||||||
|
chown -R builder /tmp/libcava
|
||||||
|
|
||||||
|
RUN su builder -c "cd /tmp/libcava && makepkg -si --noconfirm" && \
|
||||||
rm -rf /tmp/libcava && \
|
rm -rf /tmp/libcava && \
|
||||||
userdel -r builder && \
|
userdel -r builder && \
|
||||||
sed -i '/^builder/d' /etc/sudoers
|
sed -i '/^builder/d' /etc/sudoers
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ dependencies = [
|
|||||||
"materialyoucolor"
|
"materialyoucolor"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = ["pytest"]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
zshell-cli = "zshell:main"
|
zshell-cli = "zshell:main"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user