background: add cookie clock style

This commit is contained in:
end-4
2025-09-22 20:25:46 +02:00
parent b90cf14228
commit 2237ec135c
6 changed files with 524 additions and 278 deletions
@@ -13,14 +13,14 @@ import Quickshell.Io
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Hyprland import Quickshell.Hyprland
Variants { Variants {
id: root id: root
readonly property bool fixedClockPosition: Config.options.background.fixedClockPosition readonly property bool fixedClockPosition: Config.options.background.clock.fixedPosition
readonly property real fixedClockX: Config.options.background.clockX readonly property real fixedClockX: Config.options.background.clock.x
readonly property real fixedClockY: Config.options.background.clockY readonly property real fixedClockY: Config.options.background.clock.y
readonly property real clockSizePadding: 20 readonly property real clockSizePadding: 20
readonly property real screenSizePadding: 50 readonly property real screenSizePadding: 50
readonly property string clockStyle: Config.options.background.clock.style
model: Quickshell.screens model: Quickshell.screens
PanelWindow { PanelWindow {
@@ -39,16 +39,9 @@ Variants {
property int firstWorkspaceId: relevantWindows[0]?.workspace.id || 1 property int firstWorkspaceId: relevantWindows[0]?.workspace.id || 1
property int lastWorkspaceId: relevantWindows[relevantWindows.length - 1]?.workspace.id || 10 property int lastWorkspaceId: relevantWindows[relevantWindows.length - 1]?.workspace.id || 10
// Wallpaper // Wallpaper
property bool wallpaperIsVideo: Config.options.background.wallpaperPath.endsWith(".mp4") property bool wallpaperIsVideo: Config.options.background.wallpaperPath.endsWith(".mp4") || Config.options.background.wallpaperPath.endsWith(".webm") || Config.options.background.wallpaperPath.endsWith(".mkv") || Config.options.background.wallpaperPath.endsWith(".avi") || Config.options.background.wallpaperPath.endsWith(".mov")
|| Config.options.background.wallpaperPath.endsWith(".webm")
|| Config.options.background.wallpaperPath.endsWith(".mkv")
|| Config.options.background.wallpaperPath.endsWith(".avi")
|| Config.options.background.wallpaperPath.endsWith(".mov")
property string wallpaperPath: wallpaperIsVideo ? Config.options.background.thumbnailPath : Config.options.background.wallpaperPath property string wallpaperPath: wallpaperIsVideo ? Config.options.background.thumbnailPath : Config.options.background.wallpaperPath
property bool wallpaperSafetyTriggered: Config.options.background.wallpaperSafety.enable && ( property bool wallpaperSafetyTriggered: Config.options.background.wallpaperSafety.enable && (CF.StringUtils.stringListContainsSubstring(wallpaperPath.toLowerCase(), Config.options.background.wallpaperSafety.triggerCondition.wallpaperKeywords) && CF.StringUtils.stringListContainsSubstring(Network.networkName.toLowerCase(), Config.options.background.wallpaperSafety.triggerCondition.networkNameKeywords))
CF.StringUtils.stringListContainsSubstring(wallpaperPath.toLowerCase(), Config.options.background.wallpaperSafety.triggerCondition.wallpaperKeywords) &&
CF.StringUtils.stringListContainsSubstring(Network.networkName.toLowerCase(), Config.options.background.wallpaperSafety.triggerCondition.networkNameKeywords)
)
property real wallpaperToScreenRatio: Math.min(wallpaperWidth / screen.width, wallpaperHeight / screen.height) property real wallpaperToScreenRatio: Math.min(wallpaperWidth / screen.width, wallpaperHeight / screen.height)
property real preferredWallpaperScale: Config.options.background.parallax.workspaceZoom property real preferredWallpaperScale: Config.options.background.parallax.workspaceZoom
property real effectiveWallpaperScale: 1 // Some reasonable init value, to be updated property real effectiveWallpaperScale: 1 // Some reasonable init value, to be updated
@@ -74,60 +67,14 @@ Variants {
property color dominantColor: Appearance.colors.colPrimary property color dominantColor: Appearance.colors.colPrimary
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5 property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
property color colText: { property color colText: {
if (wallpaperSafetyTriggered) return CF.ColorUtils.mix(Appearance.colors.colOnLayer0, Appearance.colors.colPrimary, 0.75); if (wallpaperSafetyTriggered)
return (GlobalStates.screenLocked && shouldBlur) ? Appearance.colors.colOnLayer0 : CF.ColorUtils.colorWithLightness(Appearance.colors.colPrimary, (dominantColorIsDark ? 0.8 : 0.12)) return CF.ColorUtils.mix(Appearance.colors.colOnLayer0, Appearance.colors.colPrimary, 0.75);
return (GlobalStates.screenLocked && shouldBlur) ? Appearance.colors.colOnLayer0 : CF.ColorUtils.colorWithLightness(Appearance.colors.colPrimary, (dominantColorIsDark ? 0.8 : 0.12));
} }
Behavior on colText { Behavior on colText {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
} }
// Components
component ClockText: StyledText {
Layout.fillWidth: true
horizontalAlignment: bgRoot.textHorizontalAlignment
font {
family: Appearance.font.family.expressive
pixelSize: 20
weight: Font.DemiBold
}
color: bgRoot.colText
style: Text.Raised
styleColor: Appearance.colors.colShadow
animateChange: true
}
component ClockStatusText: RowLayout {
id: statusTextRow
property alias statusIcon: statusIconWidget.text
property alias statusText: statusTextWidget.text
property bool shown: true
opacity: shown ? 1 : 0
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Layout.fillWidth: false
MaterialSymbol {
id: statusIconWidget
Layout.fillWidth: false
iconSize: Appearance.font.pixelSize.huge
color: bgRoot.colText
style: Text.Raised
styleColor: Appearance.colors.colShadow
}
ClockText {
id: statusTextWidget
Layout.fillWidth: false
color: bgRoot.colText
font {
family: Appearance.font.family.main
pixelSize: Appearance.font.pixelSize.large
weight: Font.Normal
}
style: Text.Raised
styleColor: Appearance.colors.colShadow
}
}
// Layer props // Layer props
screen: modelData screen: modelData
exclusionMode: ExclusionMode.Ignore exclusionMode: ExclusionMode.Ignore
@@ -140,19 +87,19 @@ Variants {
left: true left: true
right: true right: true
} }
color: CF.ColorUtils.mix(Appearance.colors.colLayer0, Appearance.colors.colPrimary, 0.75); color: CF.ColorUtils.transparentize(CF.ColorUtils.mix(Appearance.colors.colLayer0, Appearance.colors.colPrimary, 0.75), (bgRoot.wallpaperIsVideo ? 1 : 0))
Behavior on color { Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
} }
onWallpaperPathChanged: { onWallpaperPathChanged: {
bgRoot.updateZoomScale() bgRoot.updateZoomScale();
// Clock position gets updated after zoom scale is updated // Clock position gets updated after zoom scale is updated
} }
// Wallpaper zoom scale // Wallpaper zoom scale
function updateZoomScale() { function updateZoomScale() {
getWallpaperSizeProc.path = bgRoot.wallpaperPath getWallpaperSizeProc.path = bgRoot.wallpaperPath;
getWallpaperSizeProc.running = true; getWallpaperSizeProc.running = true;
} }
Process { Process {
@@ -162,23 +109,21 @@ Variants {
stdout: StdioCollector { stdout: StdioCollector {
id: wallpaperSizeOutputCollector id: wallpaperSizeOutputCollector
onStreamFinished: { onStreamFinished: {
const output = wallpaperSizeOutputCollector.text const output = wallpaperSizeOutputCollector.text;
const [width, height] = output.split(" ").map(Number); const [width, height] = output.split(" ").map(Number);
const [screenWidth, screenHeight] = [bgRoot.screen.width, bgRoot.screen.height]; const [screenWidth, screenHeight] = [bgRoot.screen.width, bgRoot.screen.height];
bgRoot.wallpaperWidth = width bgRoot.wallpaperWidth = width;
bgRoot.wallpaperHeight = height bgRoot.wallpaperHeight = height;
if (width <= screenWidth || height <= screenHeight) { // Undersized/perfectly sized wallpapers if (width <= screenWidth || height <= screenHeight) {
// Undersized/perfectly sized wallpapers
bgRoot.effectiveWallpaperScale = Math.max(screenWidth / width, screenHeight / height); bgRoot.effectiveWallpaperScale = Math.max(screenWidth / width, screenHeight / height);
} else { // Oversized = can be zoomed for parallax, yay } else {
bgRoot.effectiveWallpaperScale = Math.min( // Oversized = can be zoomed for parallax, yay
bgRoot.preferredWallpaperScale, bgRoot.effectiveWallpaperScale = Math.min(bgRoot.preferredWallpaperScale, width / screenWidth, height / screenHeight);
width / screenWidth, height / screenHeight
);
} }
bgRoot.updateClockPosition();
bgRoot.updateClockPosition()
} }
} }
} }
@@ -186,11 +131,11 @@ Variants {
// Clock positioning // Clock positioning
function updateClockPosition() { function updateClockPosition() {
// Somehow all this manual setting is needed to make the proc correctly use the new values // Somehow all this manual setting is needed to make the proc correctly use the new values
leastBusyRegionProc.path = bgRoot.wallpaperPath leastBusyRegionProc.path = bgRoot.wallpaperPath;
leastBusyRegionProc.contentWidth = clockLoader.implicitWidth + root.clockSizePadding * 2 leastBusyRegionProc.contentWidth = clockLoader.implicitWidth + root.clockSizePadding * 2;
leastBusyRegionProc.contentHeight = clockLoader.implicitHeight + root.clockSizePadding * 2 leastBusyRegionProc.contentHeight = clockLoader.implicitHeight + root.clockSizePadding * 2;
leastBusyRegionProc.horizontalPadding = bgRoot.movableXSpace + root.screenSizePadding * 2 leastBusyRegionProc.horizontalPadding = bgRoot.movableXSpace + root.screenSizePadding * 2;
leastBusyRegionProc.verticalPadding = bgRoot.movableYSpace + root.screenSizePadding * 2 leastBusyRegionProc.verticalPadding = bgRoot.movableYSpace + root.screenSizePadding * 2;
leastBusyRegionProc.running = false; leastBusyRegionProc.running = false;
leastBusyRegionProc.running = true; leastBusyRegionProc.running = true;
} }
@@ -201,31 +146,29 @@ Variants {
property int contentHeight: 300 property int contentHeight: 300
property int horizontalPadding: bgRoot.movableXSpace property int horizontalPadding: bgRoot.movableXSpace
property int verticalPadding: bgRoot.movableYSpace property int verticalPadding: bgRoot.movableYSpace
command: [Quickshell.shellPath("scripts/images/least_busy_region.py"), command: [Quickshell.shellPath("scripts/images/least_busy_region.py"), "--screen-width", Math.round(bgRoot.screen.width / bgRoot.effectiveWallpaperScale), "--screen-height", Math.round(bgRoot.screen.height / bgRoot.effectiveWallpaperScale), "--width", contentWidth, "--height", contentHeight, "--horizontal-padding", horizontalPadding, "--vertical-padding", verticalPadding, path
"--screen-width", Math.round(bgRoot.screen.width / bgRoot.effectiveWallpaperScale),
"--screen-height", Math.round(bgRoot.screen.height / bgRoot.effectiveWallpaperScale),
"--width", contentWidth,
"--height", contentHeight,
"--horizontal-padding", horizontalPadding,
"--vertical-padding", verticalPadding,
path,
// "--visual-output", // "--visual-output",
] ,]
stdout: StdioCollector { stdout: StdioCollector {
id: leastBusyRegionOutputCollector id: leastBusyRegionOutputCollector
onStreamFinished: { onStreamFinished: {
const output = leastBusyRegionOutputCollector.text const output = leastBusyRegionOutputCollector.text;
// console.log("[Background] Least busy region output:", output) // console.log("[Background] Least busy region output:", output)
if (output.length === 0) return; if (output.length === 0)
const parsedContent = JSON.parse(output) return;
bgRoot.clockX = parsedContent.center_x * bgRoot.effectiveWallpaperScale const parsedContent = JSON.parse(output);
bgRoot.clockY = parsedContent.center_y * bgRoot.effectiveWallpaperScale bgRoot.clockX = parsedContent.center_x * bgRoot.effectiveWallpaperScale;
bgRoot.dominantColor = parsedContent.dominant_color || Appearance.colors.colPrimary bgRoot.clockY = parsedContent.center_y * bgRoot.effectiveWallpaperScale;
bgRoot.dominantColor = parsedContent.dominant_color || Appearance.colors.colPrimary;
} }
} }
} }
// Wallpaper // Wallpaper
Item {
anchors.fill: parent
clip: true
Image { Image {
id: wallpaper id: wallpaper
visible: opacity > 0 && !blurLoader.active visible: opacity > 0 && !blurLoader.active
@@ -238,10 +181,10 @@ Variants {
retainWhileLoading: true retainWhileLoading: true
smooth: false smooth: false
// Range = groups that workspaces span on // Range = groups that workspaces span on
property int chunkSize: Config?.options.bar.workspaces.shown ?? 10; property int chunkSize: Config?.options.bar.workspaces.shown ?? 10
property int lower: Math.floor(bgRoot.firstWorkspaceId / chunkSize) * chunkSize; property int lower: Math.floor(bgRoot.firstWorkspaceId / chunkSize) * chunkSize
property int upper: Math.ceil(bgRoot.lastWorkspaceId / chunkSize) * chunkSize; property int upper: Math.ceil(bgRoot.lastWorkspaceId / chunkSize) * chunkSize
property int range: upper - lower; property int range: upper - lower
property real valueX: { property real valueX: {
let result = 0.5; let result = 0.5;
if (Config.options.background.parallax.enableWorkspace && !bgRoot.verticalParallax) { if (Config.options.background.parallax.enableWorkspace && !bgRoot.verticalParallax) {
@@ -314,7 +257,7 @@ Variants {
// The clock // The clock
Loader { Loader {
id: clockLoader id: clockLoader
active: Config.options.background.showClock active: Config.options.background.clock.show
anchors { anchors {
left: wallpaper.left left: wallpaper.left
top: wallpaper.top top: wallpaper.top
@@ -323,8 +266,8 @@ Variants {
leftMargin: bgRoot.movableXSpace + ((root.fixedClockPosition ? root.fixedClockX : bgRoot.clockX * bgRoot.effectiveWallpaperScale) - implicitWidth / 2) leftMargin: bgRoot.movableXSpace + ((root.fixedClockPosition ? root.fixedClockX : bgRoot.clockX * bgRoot.effectiveWallpaperScale) - implicitWidth / 2)
topMargin: { topMargin: {
if (bgRoot.shouldBlur) if (bgRoot.shouldBlur)
return bgRoot.modelData.height / 3 return bgRoot.modelData.height / 3;
return bgRoot.movableYSpace + ((root.fixedClockPosition ? root.fixedClockY : bgRoot.clockY * bgRoot.effectiveWallpaperScale) - implicitHeight / 2) return bgRoot.movableYSpace + ((root.fixedClockPosition ? root.fixedClockY : bgRoot.clockY * bgRoot.effectiveWallpaperScale) - implicitHeight / 2);
} }
Behavior on leftMargin { Behavior on leftMargin {
animation: Appearance.animation.elementMove.numberAnimation.createObject(this) animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
@@ -354,14 +297,16 @@ Variants {
easing.bezierCurve: Appearance.animation.elementMove.bezierCurve easing.bezierCurve: Appearance.animation.elementMove.bezierCurve
} }
} }
sourceComponent: Item { sourceComponent: ColumnLayout {
id: clock id: clock
implicitWidth: clockColumn.implicitWidth spacing: 8
implicitHeight: clockColumn.implicitHeight
ColumnLayout { Loader {
id: digitalClockLoader
visible: root.clockStyle === "digital"
active: visible
sourceComponent: ColumnLayout {
id: clockColumn id: clockColumn
anchors.centerIn: parent
spacing: 6 spacing: 6
ClockText { ClockText {
@@ -372,7 +317,8 @@ Variants {
Layout.topMargin: -5 Layout.topMargin: -5
text: DateTime.date text: DateTime.date
} }
StyledText { // Somehow gets fucked up if made a ClockText??? StyledText {
// Somehow gets fucked up if made a ClockText???
visible: Config.options.background.quote.length > 0 visible: Config.options.background.quote.length > 0
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: bgRoot.textHorizontalAlignment horizontalAlignment: bgRoot.textHorizontalAlignment
@@ -388,33 +334,122 @@ Variants {
text: Config.options.background.quote text: Config.options.background.quote
} }
} }
}
Loader {
id: cookieClockLoader
visible: root.clockStyle === "cookie"
active: visible
sourceComponent: CookieClock {}
}
Item {
Layout.alignment: Qt.AlignHCenter
implicitWidth: statusTextBg.implicitWidth
implicitHeight: statusTextBg.implicitHeight
StyledRectangularShadow {
target: statusTextBg
visible: statusTextBg.visible
opacity: statusTextBg.opacity
}
Rectangle {
id: statusTextBg
opacity: (safetyStatusText.shown || lockStatusText.shown) ? 1 : 0
visible: opacity > 0
implicitHeight: statusTextRow.implicitHeight + 5 * 2
implicitWidth: statusTextRow.implicitWidth + 10 * 2
radius: Appearance.rounding.small
color: CF.ColorUtils.transparentize(Appearance.colors.colSecondaryContainer, cookieClockLoader.active ? 0 : 1)
Behavior on implicitWidth {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
Behavior on implicitHeight {
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
}
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
RowLayout { RowLayout {
anchors { id: statusTextRow
top: clockColumn.bottom anchors.centerIn: parent
left: bgRoot.textHorizontalAlignment === Text.AlignLeft ? clockColumn.left : undefined
right: bgRoot.textHorizontalAlignment === Text.AlignRight ? clockColumn.right : undefined
horizontalCenter: bgRoot.textHorizontalAlignment === Text.AlignHCenter ? clockColumn.horizontalCenter : undefined
topMargin: 14
leftMargin: -6
rightMargin: -6
}
spacing: 16 spacing: 16
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft; implicitWidth: 1 } Item {
Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft
implicitWidth: 1
}
ClockStatusText { ClockStatusText {
id: safetyStatusText
shown: bgRoot.wallpaperSafetyTriggered shown: bgRoot.wallpaperSafetyTriggered
statusIcon: "hide_image" statusIcon: "hide_image"
statusText: qsTr("Wallpaper safety enforced") statusText: qsTr("Wallpaper safety enforced")
} }
ClockStatusText { ClockStatusText {
id: lockStatusText
shown: GlobalStates.screenLocked && (!Config.options.background.lockBlur.enable || Config.options.background.lockBlur.showLockedText) shown: GlobalStates.screenLocked && (!Config.options.background.lockBlur.enable || Config.options.background.lockBlur.showLockedText)
statusIcon: "lock" statusIcon: "lock"
statusText: qsTr("Locked") statusText: qsTr("Locked")
} }
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignRight; implicitWidth: 1 } Item {
Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignRight
implicitWidth: 1
}
}
}
}
}
}
}
}
} // Components
} component ClockText: StyledText {
Layout.fillWidth: true
horizontalAlignment: bgRoot.textHorizontalAlignment
font {
family: Appearance.font.family.expressive
pixelSize: 20
weight: Font.DemiBold
}
color: bgRoot.colText
style: Text.Raised
styleColor: Appearance.colors.colShadow
animateChange: true
}
component ClockStatusText: RowLayout {
id: statusTextRow
property alias statusIcon: statusIconWidget.text
property alias statusText: statusTextWidget.text
property bool shown: true
property color textColor: root.clockStyle === "cookie" ? Appearance.colors.colOnSecondaryContainer : bgRoot.colText
opacity: shown ? 1 : 0
visible: opacity > 0
Behavior on opacity {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
Layout.fillWidth: false
MaterialSymbol {
id: statusIconWidget
Layout.fillWidth: false
iconSize: Appearance.font.pixelSize.huge
color: statusTextRow.textColor
style: Text.Raised
styleColor: Appearance.colors.colShadow
}
ClockText {
id: statusTextWidget
Layout.fillWidth: false
color: statusTextRow.textColor
font {
family: Appearance.font.family.main
pixelSize: Appearance.font.pixelSize.large
weight: Font.Normal
}
style: Text.Raised
styleColor: Appearance.colors.colShadow
} }
} }
} }
@@ -0,0 +1,136 @@
pragma ComponentBehavior: Bound
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
import QtQuick.Layouts
import Quickshell
import Qt5Compat.GraphicalEffects
Item {
id: root
property real implicitSize: 230
property real hourHandLength: 72
property real hourHandWidth: 16
property real minuteHandLength: 95
property real minuteHandWidth: 8
property real centerDotSize: 10
property real hourDotSize: minuteHandWidth
property color colOnBackground: ColorUtils.mix(Appearance.colors.colPrimary, Appearance.colors.colSecondaryContainer, 0.5)
property list<string> clockNumbers: DateTime.time.split(/[: ]/)
property int clockHour: parseInt(clockNumbers[0]) % 12
property int clockMinute: parseInt(clockNumbers[1])
implicitWidth: implicitSize
implicitHeight: implicitSize
DropShadow {
source: cookie
anchors.fill: source
horizontalOffset: 0
verticalOffset: 2
radius: 8
samples: radius * 2 + 1
color: Appearance.colors.colShadow
transparentBorder: true
}
MaterialCookie {
id: cookie
z: 0
implicitSize: root.implicitSize
amplitude: implicitSize / 70
sides: 12
color: Appearance.colors.colSecondaryContainer
// 12 dots around the cookie
Repeater {
model: 12
Item {
required property int index
rotation: 360 / 12 * index
anchors.fill: parent
Rectangle {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: 10
}
implicitWidth: root.hourDotSize
implicitHeight: implicitWidth
radius: implicitWidth / 2
color: root.colOnBackground
opacity: 0.5
}
}
}
}
Column {
id: timeIndicators
z: 1
anchors.centerIn: cookie
spacing: -16
// Numbers
Repeater {
model: root.clockNumbers
delegate: StyledText {
required property string modelData
anchors.horizontalCenter: parent.horizontalCenter
font {
pixelSize: modelData.match(/am|pm/i) ? 26 : 68
family: Appearance.font.family.expressive
weight: Font.Bold
}
color: root.colOnBackground
text: modelData.padStart(2, "0")
}
}
}
// Hour hand
Item {
anchors.fill: parent
z: 2
rotation: -90 + (360 / 12) * (root.clockHour + root.clockMinute / 60)
Rectangle {
anchors.verticalCenter: parent.verticalCenter
x: parent.width / 2 - hourHandWidth / 2
width: hourHandLength
height: hourHandWidth
radius: hourHandWidth / 2
color: Appearance.colors.colPrimary
}
}
// Minute hand
Item {
anchors.fill: parent
z: 3
rotation: -90 + (360 / 60) * root.clockMinute
Rectangle {
anchors.verticalCenter: parent.verticalCenter
x: parent.width / 2 - minuteHandWidth / 2
width: minuteHandLength
height: minuteHandWidth
radius: minuteHandWidth / 2
color: Appearance.colors.colSecondary
}
}
// Center dot
Rectangle {
z: 4
color: Appearance.colors.colOnPrimary
anchors.centerIn: parent
implicitWidth: centerDotSize
implicitHeight: implicitWidth
radius: implicitWidth / 2
}
}
@@ -122,10 +122,13 @@ Singleton {
} }
property JsonObject background: JsonObject { property JsonObject background: JsonObject {
property bool fixedClockPosition: false property JsonObject clock: JsonObject {
property real clockX: -500 property bool fixedPosition: false
property real clockY: -500 property real x: -500
property bool showClock: true property real y: -500
property bool show: true
property string style: "cookie" // Options: "cookie", "digital"
}
property string wallpaperPath: "" property string wallpaperPath: ""
property string thumbnailPath: "" property string thumbnailPath: ""
property string quote: "" property string quote: ""
@@ -0,0 +1,50 @@
import QtQuick
import QtQuick.Shapes
import Quickshell
Item {
id: root
property int sides: 12
property int implicitSize: 100
property real amplitude: implicitSize / 50
property int renderPoints: 360
property color color: "#605790"
property alias strokeWidth: shapePath.strokeWidth
implicitWidth: implicitSize
implicitHeight: implicitSize
Shape {
id: shape
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
ShapePath {
id: shapePath
strokeWidth: 0
fillColor: root.color
pathHints: ShapePath.PathSolid & ShapePath.PathNonIntersecting
PathPolyline {
property var pointsList: {
var points = []
var cx = shape.width / 2 // center x
var cy = shape.height / 2 // center y
var steps = root.renderPoints
var radius = root.implicitSize / 2 - root.amplitude
for (var i = 0; i <= steps; i++) {
var angle = (i / steps) * 2 * Math.PI
var wave = Math.sin(angle * root.sides + Math.PI/2) * root.amplitude
var x = Math.cos(angle) * (radius + wave) + cx
var y = Math.sin(angle) * (radius + wave) + cy
points.push(Qt.point(x, y))
}
return points
}
path: pointsList
}
}
}
}
@@ -5,7 +5,7 @@ import qs.modules.common
RectangularShadow { RectangularShadow {
required property var target required property var target
anchors.fill: target anchors.fill: target
radius: target.radius radius: 20
blur: 0.9 * Appearance.sizes.elevationMargin blur: 0.9 * Appearance.sizes.elevationMargin
offset: Qt.vector2d(0.0, 1.0) offset: Qt.vector2d(0.0, 1.0)
spread: 1 spread: 1
@@ -14,9 +14,31 @@ ContentPage {
ConfigSwitch { ConfigSwitch {
text: Translation.tr("Show clock") text: Translation.tr("Show clock")
checked: Config.options.background.showClock checked: Config.options.background.clock.show
onCheckedChanged: { onCheckedChanged: {
Config.options.background.showClock = checked; Config.options.background.clock.show = checked;
}
}
ContentSubsection {
title: Translation.tr("Clock style")
ConfigSelectionArray {
currentValue: Config.options.background.clock.style
onSelected: newValue => {
Config.options.background.clock.style = newValue;
}
options: [
{
displayName: Translation.tr("Simple digital"),
icon: "timer_10",
value: "digital"
},
{
displayName: Translation.tr("Material cookie"),
icon: "cookie",
value: "cookie"
},
]
} }
} }