forked from Shinonome/dots-hyprland
background: add cookie clock style
This commit is contained in:
@@ -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 {
|
||||||
@@ -29,8 +29,8 @@ Variants {
|
|||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
||||||
// Hide when fullscreen
|
// Hide when fullscreen
|
||||||
property list<HyprlandWorkspace> workspacesForMonitor: Hyprland.workspaces.values.filter(workspace=>workspace.monitor && workspace.monitor.name == monitor.name)
|
property list<HyprlandWorkspace> workspacesForMonitor: Hyprland.workspaces.values.filter(workspace => workspace.monitor && workspace.monitor.name == monitor.name)
|
||||||
property var activeWorkspaceWithFullscreen: workspacesForMonitor.filter(workspace=>((workspace.toplevels.values.filter(window=>window.wayland?.fullscreen)[0] != undefined) && workspace.active))[0]
|
property var activeWorkspaceWithFullscreen: workspacesForMonitor.filter(workspace => ((workspace.toplevels.values.filter(window => window.wayland?.fullscreen)[0] != undefined) && workspace.active))[0]
|
||||||
visible: GlobalStates.screenLocked || (!(activeWorkspaceWithFullscreen != undefined)) || !Config?.options.background.hideWhenFullscreen
|
visible: GlobalStates.screenLocked || (!(activeWorkspaceWithFullscreen != undefined)) || !Config?.options.background.hideWhenFullscreen
|
||||||
|
|
||||||
// Workspaces
|
// Workspaces
|
||||||
@@ -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,45 +87,43 @@ 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 {
|
||||||
id: getWallpaperSizeProc
|
id: getWallpaperSizeProc
|
||||||
property string path: bgRoot.wallpaperPath
|
property string path: bgRoot.wallpaperPath
|
||||||
command: [ "magick", "identify", "-format", "%w %h", path ]
|
command: ["magick", "identify", "-format", "%w %h", path]
|
||||||
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,220 +146,310 @@ 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
|
||||||
Image {
|
Item {
|
||||||
id: wallpaper
|
anchors.fill: parent
|
||||||
visible: opacity > 0 && !blurLoader.active
|
clip: true
|
||||||
opacity: (status === Image.Ready && !bgRoot.wallpaperIsVideo) ? 1 : 0
|
|
||||||
Behavior on opacity {
|
|
||||||
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
cache: false
|
|
||||||
asynchronous: true
|
|
||||||
retainWhileLoading: true
|
|
||||||
smooth: false
|
|
||||||
// Range = groups that workspaces span on
|
|
||||||
property int chunkSize: Config?.options.bar.workspaces.shown ?? 10;
|
|
||||||
property int lower: Math.floor(bgRoot.firstWorkspaceId / chunkSize) * chunkSize;
|
|
||||||
property int upper: Math.ceil(bgRoot.lastWorkspaceId / chunkSize) * chunkSize;
|
|
||||||
property int range: upper - lower;
|
|
||||||
property real valueX: {
|
|
||||||
let result = 0.5;
|
|
||||||
if (Config.options.background.parallax.enableWorkspace && !bgRoot.verticalParallax) {
|
|
||||||
result = ((bgRoot.monitor.activeWorkspace?.id - lower) / range);
|
|
||||||
}
|
|
||||||
if (Config.options.background.parallax.enableSidebar) {
|
|
||||||
result += (0.15 * GlobalStates.sidebarRightOpen - 0.15 * GlobalStates.sidebarLeftOpen);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
property real valueY: {
|
|
||||||
let result = 0.5;
|
|
||||||
if (Config.options.background.parallax.enableWorkspace && bgRoot.verticalParallax) {
|
|
||||||
result = ((bgRoot.monitor.activeWorkspace?.id - lower) / range);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
property real effectiveValueX: Math.max(0, Math.min(1, valueX))
|
|
||||||
property real effectiveValueY: Math.max(0, Math.min(1, valueY))
|
|
||||||
x: -(bgRoot.movableXSpace) - (effectiveValueX - 0.5) * 2 * bgRoot.movableXSpace
|
|
||||||
y: -(bgRoot.movableYSpace) - (effectiveValueY - 0.5) * 2 * bgRoot.movableYSpace
|
|
||||||
source: bgRoot.wallpaperSafetyTriggered ? "" : bgRoot.wallpaperPath
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
Behavior on x {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 600
|
|
||||||
easing.type: Easing.OutCubic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on y {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: 600
|
|
||||||
easing.type: Easing.OutCubic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sourceSize {
|
|
||||||
width: bgRoot.screen.width * bgRoot.effectiveWallpaperScale * bgRoot.monitor.scale
|
|
||||||
height: bgRoot.screen.height * bgRoot.effectiveWallpaperScale * bgRoot.monitor.scale
|
|
||||||
}
|
|
||||||
width: bgRoot.wallpaperWidth / bgRoot.wallpaperToScreenRatio * bgRoot.effectiveWallpaperScale
|
|
||||||
height: bgRoot.wallpaperHeight / bgRoot.wallpaperToScreenRatio * bgRoot.effectiveWallpaperScale
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
Image {
|
||||||
id: blurLoader
|
id: wallpaper
|
||||||
active: Config.options.background.lockBlur.enable && (GlobalStates.screenLocked || scaleAnim.running)
|
visible: opacity > 0 && !blurLoader.active
|
||||||
anchors.fill: wallpaper
|
opacity: (status === Image.Ready && !bgRoot.wallpaperIsVideo) ? 1 : 0
|
||||||
scale: GlobalStates.screenLocked ? Config.options.background.lockBlur.extraZoom : 1
|
Behavior on opacity {
|
||||||
Behavior on scale {
|
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
|
||||||
NumberAnimation {
|
|
||||||
id: scaleAnim
|
|
||||||
duration: 400
|
|
||||||
easing.type: Easing.BezierSpline
|
|
||||||
easing.bezierCurve: Appearance.animationCurves.expressiveDefaultSpatial
|
|
||||||
}
|
}
|
||||||
|
cache: false
|
||||||
|
asynchronous: true
|
||||||
|
retainWhileLoading: true
|
||||||
|
smooth: false
|
||||||
|
// Range = groups that workspaces span on
|
||||||
|
property int chunkSize: Config?.options.bar.workspaces.shown ?? 10
|
||||||
|
property int lower: Math.floor(bgRoot.firstWorkspaceId / chunkSize) * chunkSize
|
||||||
|
property int upper: Math.ceil(bgRoot.lastWorkspaceId / chunkSize) * chunkSize
|
||||||
|
property int range: upper - lower
|
||||||
|
property real valueX: {
|
||||||
|
let result = 0.5;
|
||||||
|
if (Config.options.background.parallax.enableWorkspace && !bgRoot.verticalParallax) {
|
||||||
|
result = ((bgRoot.monitor.activeWorkspace?.id - lower) / range);
|
||||||
|
}
|
||||||
|
if (Config.options.background.parallax.enableSidebar) {
|
||||||
|
result += (0.15 * GlobalStates.sidebarRightOpen - 0.15 * GlobalStates.sidebarLeftOpen);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
property real valueY: {
|
||||||
|
let result = 0.5;
|
||||||
|
if (Config.options.background.parallax.enableWorkspace && bgRoot.verticalParallax) {
|
||||||
|
result = ((bgRoot.monitor.activeWorkspace?.id - lower) / range);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
property real effectiveValueX: Math.max(0, Math.min(1, valueX))
|
||||||
|
property real effectiveValueY: Math.max(0, Math.min(1, valueY))
|
||||||
|
x: -(bgRoot.movableXSpace) - (effectiveValueX - 0.5) * 2 * bgRoot.movableXSpace
|
||||||
|
y: -(bgRoot.movableYSpace) - (effectiveValueY - 0.5) * 2 * bgRoot.movableYSpace
|
||||||
|
source: bgRoot.wallpaperSafetyTriggered ? "" : bgRoot.wallpaperPath
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
Behavior on x {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 600
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on y {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 600
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sourceSize {
|
||||||
|
width: bgRoot.screen.width * bgRoot.effectiveWallpaperScale * bgRoot.monitor.scale
|
||||||
|
height: bgRoot.screen.height * bgRoot.effectiveWallpaperScale * bgRoot.monitor.scale
|
||||||
|
}
|
||||||
|
width: bgRoot.wallpaperWidth / bgRoot.wallpaperToScreenRatio * bgRoot.effectiveWallpaperScale
|
||||||
|
height: bgRoot.wallpaperHeight / bgRoot.wallpaperToScreenRatio * bgRoot.effectiveWallpaperScale
|
||||||
}
|
}
|
||||||
sourceComponent: GaussianBlur {
|
|
||||||
source: wallpaper
|
|
||||||
radius: GlobalStates.screenLocked ? Config.options.background.lockBlur.radius : 0
|
|
||||||
samples: radius * 2 + 1
|
|
||||||
|
|
||||||
Rectangle {
|
Loader {
|
||||||
opacity: GlobalStates.screenLocked ? 1 : 0
|
id: blurLoader
|
||||||
anchors.fill: parent
|
active: Config.options.background.lockBlur.enable && (GlobalStates.screenLocked || scaleAnim.running)
|
||||||
color: CF.ColorUtils.transparentize(Appearance.colors.colLayer0, 0.7)
|
anchors.fill: wallpaper
|
||||||
|
scale: GlobalStates.screenLocked ? Config.options.background.lockBlur.extraZoom : 1
|
||||||
|
Behavior on scale {
|
||||||
|
NumberAnimation {
|
||||||
|
id: scaleAnim
|
||||||
|
duration: 400
|
||||||
|
easing.type: Easing.BezierSpline
|
||||||
|
easing.bezierCurve: Appearance.animationCurves.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
sourceComponent: GaussianBlur {
|
||||||
}
|
source: wallpaper
|
||||||
|
radius: GlobalStates.screenLocked ? Config.options.background.lockBlur.radius : 0
|
||||||
|
samples: radius * 2 + 1
|
||||||
|
|
||||||
// The clock
|
Rectangle {
|
||||||
Loader {
|
opacity: GlobalStates.screenLocked ? 1 : 0
|
||||||
id: clockLoader
|
anchors.fill: parent
|
||||||
active: Config.options.background.showClock
|
color: CF.ColorUtils.transparentize(Appearance.colors.colLayer0, 0.7)
|
||||||
anchors {
|
|
||||||
left: wallpaper.left
|
|
||||||
top: wallpaper.top
|
|
||||||
horizontalCenter: undefined
|
|
||||||
verticalCenter: undefined
|
|
||||||
leftMargin: bgRoot.movableXSpace + ((root.fixedClockPosition ? root.fixedClockX : bgRoot.clockX * bgRoot.effectiveWallpaperScale) - implicitWidth / 2)
|
|
||||||
topMargin: {
|
|
||||||
if (bgRoot.shouldBlur)
|
|
||||||
return bgRoot.modelData.height / 3
|
|
||||||
return bgRoot.movableYSpace + ((root.fixedClockPosition ? root.fixedClockY : bgRoot.clockY * bgRoot.effectiveWallpaperScale) - implicitHeight / 2)
|
|
||||||
}
|
|
||||||
Behavior on leftMargin {
|
|
||||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
Behavior on topMargin {
|
|
||||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
states: State {
|
|
||||||
name: "centered"
|
|
||||||
when: (bgRoot.shouldBlur && Config.options.background.lockBlur.centerClock) || bgRoot.wallpaperSafetyTriggered
|
|
||||||
AnchorChanges {
|
|
||||||
target: clockLoader
|
|
||||||
anchors {
|
|
||||||
left: undefined
|
|
||||||
right: undefined
|
|
||||||
top: undefined
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transitions: Transition {
|
|
||||||
AnchorAnimation {
|
// The clock
|
||||||
duration: Appearance.animation.elementMove.duration
|
Loader {
|
||||||
easing.type: Appearance.animation.elementMove.type
|
id: clockLoader
|
||||||
easing.bezierCurve: Appearance.animation.elementMove.bezierCurve
|
active: Config.options.background.clock.show
|
||||||
|
anchors {
|
||||||
|
left: wallpaper.left
|
||||||
|
top: wallpaper.top
|
||||||
|
horizontalCenter: undefined
|
||||||
|
verticalCenter: undefined
|
||||||
|
leftMargin: bgRoot.movableXSpace + ((root.fixedClockPosition ? root.fixedClockX : bgRoot.clockX * bgRoot.effectiveWallpaperScale) - implicitWidth / 2)
|
||||||
|
topMargin: {
|
||||||
|
if (bgRoot.shouldBlur)
|
||||||
|
return bgRoot.modelData.height / 3;
|
||||||
|
return bgRoot.movableYSpace + ((root.fixedClockPosition ? root.fixedClockY : bgRoot.clockY * bgRoot.effectiveWallpaperScale) - implicitHeight / 2);
|
||||||
|
}
|
||||||
|
Behavior on leftMargin {
|
||||||
|
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
|
Behavior on topMargin {
|
||||||
|
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
states: State {
|
||||||
sourceComponent: Item {
|
name: "centered"
|
||||||
id: clock
|
when: (bgRoot.shouldBlur && Config.options.background.lockBlur.centerClock) || bgRoot.wallpaperSafetyTriggered
|
||||||
implicitWidth: clockColumn.implicitWidth
|
AnchorChanges {
|
||||||
implicitHeight: clockColumn.implicitHeight
|
target: clockLoader
|
||||||
|
anchors {
|
||||||
ColumnLayout {
|
left: undefined
|
||||||
id: clockColumn
|
right: undefined
|
||||||
anchors.centerIn: parent
|
top: undefined
|
||||||
spacing: 6
|
verticalCenter: parent.verticalCenter
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
ClockText {
|
|
||||||
font.pixelSize: 90
|
|
||||||
text: DateTime.time
|
|
||||||
}
|
|
||||||
ClockText {
|
|
||||||
Layout.topMargin: -5
|
|
||||||
text: DateTime.date
|
|
||||||
}
|
|
||||||
StyledText { // Somehow gets fucked up if made a ClockText???
|
|
||||||
visible: Config.options.background.quote.length > 0
|
|
||||||
Layout.fillWidth: true
|
|
||||||
horizontalAlignment: bgRoot.textHorizontalAlignment
|
|
||||||
font {
|
|
||||||
family: Appearance.font.family.main
|
|
||||||
pixelSize: Appearance.font.pixelSize.normal
|
|
||||||
weight: 350
|
|
||||||
italic: true
|
|
||||||
}
|
}
|
||||||
color: bgRoot.colText
|
|
||||||
style: Text.Raised
|
|
||||||
styleColor: Appearance.colors.colShadow
|
|
||||||
text: Config.options.background.quote
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
transitions: Transition {
|
||||||
|
AnchorAnimation {
|
||||||
|
duration: Appearance.animation.elementMove.duration
|
||||||
|
easing.type: Appearance.animation.elementMove.type
|
||||||
|
easing.bezierCurve: Appearance.animation.elementMove.bezierCurve
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sourceComponent: ColumnLayout {
|
||||||
|
id: clock
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
RowLayout {
|
Loader {
|
||||||
anchors {
|
id: digitalClockLoader
|
||||||
top: clockColumn.bottom
|
visible: root.clockStyle === "digital"
|
||||||
left: bgRoot.textHorizontalAlignment === Text.AlignLeft ? clockColumn.left : undefined
|
active: visible
|
||||||
right: bgRoot.textHorizontalAlignment === Text.AlignRight ? clockColumn.right : undefined
|
sourceComponent: ColumnLayout {
|
||||||
horizontalCenter: bgRoot.textHorizontalAlignment === Text.AlignHCenter ? clockColumn.horizontalCenter : undefined
|
id: clockColumn
|
||||||
topMargin: 14
|
spacing: 6
|
||||||
leftMargin: -6
|
|
||||||
rightMargin: -6
|
|
||||||
}
|
|
||||||
spacing: 16
|
|
||||||
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft; implicitWidth: 1 }
|
|
||||||
ClockStatusText {
|
|
||||||
shown: bgRoot.wallpaperSafetyTriggered
|
|
||||||
statusIcon: "hide_image"
|
|
||||||
statusText: qsTr("Wallpaper safety enforced")
|
|
||||||
}
|
|
||||||
ClockStatusText {
|
|
||||||
shown: GlobalStates.screenLocked && (!Config.options.background.lockBlur.enable || Config.options.background.lockBlur.showLockedText)
|
|
||||||
statusIcon: "lock"
|
|
||||||
statusText: qsTr("Locked")
|
|
||||||
}
|
|
||||||
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignRight; implicitWidth: 1 }
|
|
||||||
|
|
||||||
|
ClockText {
|
||||||
|
font.pixelSize: 90
|
||||||
|
text: DateTime.time
|
||||||
|
}
|
||||||
|
ClockText {
|
||||||
|
Layout.topMargin: -5
|
||||||
|
text: DateTime.date
|
||||||
|
}
|
||||||
|
StyledText {
|
||||||
|
// Somehow gets fucked up if made a ClockText???
|
||||||
|
visible: Config.options.background.quote.length > 0
|
||||||
|
Layout.fillWidth: true
|
||||||
|
horizontalAlignment: bgRoot.textHorizontalAlignment
|
||||||
|
font {
|
||||||
|
family: Appearance.font.family.main
|
||||||
|
pixelSize: Appearance.font.pixelSize.normal
|
||||||
|
weight: 350
|
||||||
|
italic: true
|
||||||
|
}
|
||||||
|
color: bgRoot.colText
|
||||||
|
style: Text.Raised
|
||||||
|
styleColor: Appearance.colors.colShadow
|
||||||
|
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 {
|
||||||
|
id: statusTextRow
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 16
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft
|
||||||
|
implicitWidth: 1
|
||||||
|
}
|
||||||
|
ClockStatusText {
|
||||||
|
id: safetyStatusText
|
||||||
|
shown: bgRoot.wallpaperSafetyTriggered
|
||||||
|
statusIcon: "hide_image"
|
||||||
|
statusText: qsTr("Wallpaper safety enforced")
|
||||||
|
}
|
||||||
|
ClockStatusText {
|
||||||
|
id: lockStatusText
|
||||||
|
shown: GlobalStates.screenLocked && (!Config.options.background.lockBlur.enable || Config.options.background.lockBlur.showLockedText)
|
||||||
|
statusIcon: "lock"
|
||||||
|
statusText: qsTr("Locked")
|
||||||
|
}
|
||||||
|
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"
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user