forked from Shinonome/dots-hyprland
qs: move panels into modules/ii
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.common.widgets.widgetCanvas
|
||||
import qs.modules.common.functions as CF
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
|
||||
import qs.modules.ii.background.widgets
|
||||
import qs.modules.ii.background.widgets.clock
|
||||
import qs.modules.ii.background.widgets.weather
|
||||
|
||||
Variants {
|
||||
id: root
|
||||
model: Quickshell.screens
|
||||
|
||||
PanelWindow {
|
||||
id: bgRoot
|
||||
|
||||
required property var modelData
|
||||
|
||||
// Hide when fullscreen
|
||||
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]
|
||||
visible: GlobalStates.screenLocked || (!(activeWorkspaceWithFullscreen != undefined)) || !Config?.options.background.hideWhenFullscreen
|
||||
|
||||
// Workspaces
|
||||
property HyprlandMonitor monitor: Hyprland.monitorFor(modelData)
|
||||
property list<var> relevantWindows: HyprlandData.windowList.filter(win => win.monitor == monitor?.id && win.workspace.id >= 0).sort((a, b) => a.workspace.id - b.workspace.id)
|
||||
property int firstWorkspaceId: relevantWindows[0]?.workspace.id || 1
|
||||
property int lastWorkspaceId: relevantWindows[relevantWindows.length - 1]?.workspace.id || 10
|
||||
// Wallpaper
|
||||
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")
|
||||
property string wallpaperPath: wallpaperIsVideo ? Config.options.background.thumbnailPath : Config.options.background.wallpaperPath
|
||||
property bool wallpaperSafetyTriggered: {
|
||||
const enabled = Config.options.workSafety.enable.wallpaper;
|
||||
const sensitiveWallpaper = (CF.StringUtils.stringListContainsSubstring(wallpaperPath.toLowerCase(), Config.options.workSafety.triggerCondition.fileKeywords));
|
||||
const sensitiveNetwork = (CF.StringUtils.stringListContainsSubstring(Network.networkName.toLowerCase(), Config.options.workSafety.triggerCondition.networkNameKeywords));
|
||||
return enabled && sensitiveWallpaper && sensitiveNetwork;
|
||||
}
|
||||
property real wallpaperToScreenRatio: Math.min(wallpaperWidth / screen.width, wallpaperHeight / screen.height)
|
||||
property real preferredWallpaperScale: Config.options.background.parallax.workspaceZoom
|
||||
property real effectiveWallpaperScale: 1 // Some reasonable init value, to be updated
|
||||
property int wallpaperWidth: modelData.width // Some reasonable init value, to be updated
|
||||
property int wallpaperHeight: modelData.height // Some reasonable init value, to be updated
|
||||
property real movableXSpace: ((wallpaperWidth / wallpaperToScreenRatio * effectiveWallpaperScale) - screen.width) / 2
|
||||
property real movableYSpace: ((wallpaperHeight / wallpaperToScreenRatio * effectiveWallpaperScale) - screen.height) / 2
|
||||
readonly property bool verticalParallax: (Config.options.background.parallax.autoVertical && wallpaperHeight > wallpaperWidth) || Config.options.background.parallax.vertical
|
||||
// Colors
|
||||
property bool shouldBlur: (GlobalStates.screenLocked && Config.options.lock.blur.enable)
|
||||
property color dominantColor: Appearance.colors.colPrimary // Default, to be changed
|
||||
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
|
||||
property color colText: {
|
||||
if (wallpaperSafetyTriggered)
|
||||
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 {
|
||||
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
|
||||
}
|
||||
|
||||
// Layer props
|
||||
screen: modelData
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
WlrLayershell.layer: (GlobalStates.screenLocked && !scaleAnim.running) ? WlrLayer.Overlay : WlrLayer.Bottom
|
||||
// WlrLayershell.layer: WlrLayer.Bottom
|
||||
WlrLayershell.namespace: "quickshell:background"
|
||||
anchors {
|
||||
top: true
|
||||
bottom: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
color: {
|
||||
if (!bgRoot.wallpaperSafetyTriggered || bgRoot.wallpaperIsVideo)
|
||||
return "transparent";
|
||||
return CF.ColorUtils.mix(Appearance.colors.colLayer0, Appearance.colors.colPrimary, 0.75);
|
||||
}
|
||||
Behavior on color {
|
||||
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
|
||||
}
|
||||
|
||||
onWallpaperPathChanged: {
|
||||
bgRoot.updateZoomScale();
|
||||
// Clock position gets updated after zoom scale is updated
|
||||
}
|
||||
|
||||
// Wallpaper zoom scale
|
||||
function updateZoomScale() {
|
||||
getWallpaperSizeProc.path = bgRoot.wallpaperPath;
|
||||
getWallpaperSizeProc.running = true;
|
||||
}
|
||||
Process {
|
||||
id: getWallpaperSizeProc
|
||||
property string path: bgRoot.wallpaperPath
|
||||
command: ["magick", "identify", "-format", "%w %h", path]
|
||||
stdout: StdioCollector {
|
||||
id: wallpaperSizeOutputCollector
|
||||
onStreamFinished: {
|
||||
const output = wallpaperSizeOutputCollector.text;
|
||||
const [width, height] = output.split(" ").map(Number);
|
||||
const [screenWidth, screenHeight] = [bgRoot.screen.width, bgRoot.screen.height];
|
||||
bgRoot.wallpaperWidth = width;
|
||||
bgRoot.wallpaperHeight = height;
|
||||
|
||||
if (width <= screenWidth || height <= screenHeight) {
|
||||
// Undersized/perfectly sized wallpapers
|
||||
bgRoot.effectiveWallpaperScale = Math.max(screenWidth / width, screenHeight / height);
|
||||
} else {
|
||||
// Oversized = can be zoomed for parallax, yay
|
||||
bgRoot.effectiveWallpaperScale = Math.min(bgRoot.preferredWallpaperScale, width / screenWidth, height / screenHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
|
||||
// Wallpaper
|
||||
StyledImage {
|
||||
id: wallpaper
|
||||
visible: opacity > 0 && !blurLoader.active
|
||||
opacity: (status === Image.Ready && !bgRoot.wallpaperIsVideo) ? 1 : 0
|
||||
cache: false
|
||||
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 {
|
||||
id: blurLoader
|
||||
active: Config.options.lock.blur.enable && (GlobalStates.screenLocked || scaleAnim.running)
|
||||
anchors.fill: wallpaper
|
||||
scale: GlobalStates.screenLocked ? Config.options.lock.blur.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.lock.blur.radius : 0
|
||||
samples: radius * 2 + 1
|
||||
|
||||
Rectangle {
|
||||
opacity: GlobalStates.screenLocked ? 1 : 0
|
||||
anchors.fill: parent
|
||||
color: CF.ColorUtils.transparentize(Appearance.colors.colLayer0, 0.7)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WidgetCanvas {
|
||||
id: widgetCanvas
|
||||
anchors {
|
||||
left: wallpaper.left
|
||||
right: wallpaper.right
|
||||
top: wallpaper.top
|
||||
bottom: wallpaper.bottom
|
||||
horizontalCenter: undefined
|
||||
verticalCenter: undefined
|
||||
readonly property real parallaxFactor: Config.options.background.parallax.widgetsFactor
|
||||
leftMargin: {
|
||||
const xOnWallpaper = bgRoot.movableXSpace;
|
||||
const extraMove = (wallpaper.effectiveValueX * 2 * bgRoot.movableXSpace) * (parallaxFactor - 1);
|
||||
return xOnWallpaper - extraMove;
|
||||
}
|
||||
topMargin: {
|
||||
const yOnWallpaper = bgRoot.movableYSpace;
|
||||
const extraMove = (wallpaper.effectiveValueY * 2 * bgRoot.movableYSpace) * (parallaxFactor - 1);
|
||||
return yOnWallpaper - extraMove;
|
||||
}
|
||||
Behavior on leftMargin {
|
||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
||||
}
|
||||
Behavior on topMargin {
|
||||
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
|
||||
}
|
||||
}
|
||||
width: wallpaper.width
|
||||
height: wallpaper.height
|
||||
states: State {
|
||||
name: "centered"
|
||||
when: GlobalStates.screenLocked || bgRoot.wallpaperSafetyTriggered
|
||||
PropertyChanges {
|
||||
target: widgetCanvas
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
}
|
||||
AnchorChanges {
|
||||
target: widgetCanvas
|
||||
anchors {
|
||||
left: undefined
|
||||
right: undefined
|
||||
top: undefined
|
||||
bottom: undefined
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
transitions: Transition {
|
||||
PropertyAnimation {
|
||||
properties: "width,height"
|
||||
duration: Appearance.animation.elementMove.duration
|
||||
easing.type: Appearance.animation.elementMove.type
|
||||
easing.bezierCurve: Appearance.animation.elementMove.bezierCurve
|
||||
}
|
||||
AnchorAnimation {
|
||||
duration: Appearance.animation.elementMove.duration
|
||||
easing.type: Appearance.animation.elementMove.type
|
||||
easing.bezierCurve: Appearance.animation.elementMove.bezierCurve
|
||||
}
|
||||
}
|
||||
|
||||
FadeLoader {
|
||||
shown: Config.options.background.widgets.weather.enable
|
||||
sourceComponent: WeatherWidget {
|
||||
screenWidth: bgRoot.screen.width
|
||||
screenHeight: bgRoot.screen.height
|
||||
scaledScreenWidth: bgRoot.screen.width / bgRoot.effectiveWallpaperScale
|
||||
scaledScreenHeight: bgRoot.screen.height / bgRoot.effectiveWallpaperScale
|
||||
wallpaperScale: bgRoot.effectiveWallpaperScale
|
||||
}
|
||||
}
|
||||
|
||||
FadeLoader {
|
||||
shown: Config.options.background.widgets.clock.enable
|
||||
sourceComponent: ClockWidget {
|
||||
screenWidth: bgRoot.screen.width
|
||||
screenHeight: bgRoot.screen.height
|
||||
scaledScreenWidth: bgRoot.screen.width / bgRoot.effectiveWallpaperScale
|
||||
scaledScreenHeight: bgRoot.screen.height / bgRoot.effectiveWallpaperScale
|
||||
wallpaperScale: bgRoot.effectiveWallpaperScale
|
||||
wallpaperSafetyTriggered: bgRoot.wallpaperSafetyTriggered
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets.widgetCanvas
|
||||
|
||||
AbstractWidget {
|
||||
id: root
|
||||
|
||||
required property string configEntryName
|
||||
required property int screenWidth
|
||||
required property int screenHeight
|
||||
required property int scaledScreenWidth
|
||||
required property int scaledScreenHeight
|
||||
required property real wallpaperScale
|
||||
property bool visibleWhenLocked: false
|
||||
property var configEntry: Config.options.background.widgets[configEntryName]
|
||||
property string placementStrategy: configEntry.placementStrategy
|
||||
property real targetX: Math.max(0, Math.min(configEntry.x, scaledScreenWidth - width))
|
||||
property real targetY : Math.max(0, Math.min(configEntry.y, scaledScreenHeight - height))
|
||||
x: targetX
|
||||
y: targetY
|
||||
visible: opacity > 0
|
||||
opacity: (GlobalStates.screenLocked && !visibleWhenLocked) ? 0 : 1
|
||||
Behavior on opacity {
|
||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||
}
|
||||
scale: (draggable && containsPress) ? 1.05 : 1
|
||||
Behavior on scale {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
draggable: placementStrategy === "free"
|
||||
onReleased: {
|
||||
root.targetX = root.x;
|
||||
root.targetY = root.y;
|
||||
configEntry.x = root.targetX;
|
||||
configEntry.y = root.targetY;
|
||||
}
|
||||
|
||||
property bool needsColText: false
|
||||
property color dominantColor: Appearance.colors.colPrimary
|
||||
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
|
||||
property color colText: {
|
||||
const onNormalBackground = (GlobalStates.screenLocked && Config.options.lock.blur.enable)
|
||||
const adaptiveColor = ColorUtils.colorWithLightness(Appearance.colors.colPrimary, (dominantColorIsDark ? 0.8 : 0.12))
|
||||
return onNormalBackground ? Appearance.colors.colOnLayer0 : adaptiveColor;
|
||||
}
|
||||
|
||||
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")
|
||||
property string wallpaperPath: wallpaperIsVideo ? Config.options.background.thumbnailPath : Config.options.background.wallpaperPath
|
||||
|
||||
onWallpaperPathChanged: refreshPlacementIfNeeded()
|
||||
onPlacementStrategyChanged: refreshPlacementIfNeeded()
|
||||
Connections {
|
||||
target: Config
|
||||
function onReadyChanged() { refreshPlacementIfNeeded() }
|
||||
}
|
||||
function refreshPlacementIfNeeded() {
|
||||
if (!Config.ready || (root.placementStrategy === "free" && root.needsColText)) return;
|
||||
leastBusyRegionProc.wallpaperPath = root.wallpaperPath;
|
||||
leastBusyRegionProc.running = false;
|
||||
leastBusyRegionProc.running = true;
|
||||
}
|
||||
Process {
|
||||
id: leastBusyRegionProc
|
||||
property string wallpaperPath: root.wallpaperPath
|
||||
// TODO: make these less arbitrary
|
||||
property int contentWidth: 300
|
||||
property int contentHeight: 300
|
||||
property int horizontalPadding: 200
|
||||
property int verticalPadding: 200
|
||||
command: [Quickshell.shellPath("scripts/images/least-busy-region-venv.sh") // Comments to force the formatter to break lines
|
||||
, "--screen-width", Math.round(root.scaledScreenWidth) //
|
||||
, "--screen-height", Math.round(root.scaledScreenHeight) //
|
||||
, "--width", contentWidth //
|
||||
, "--height", contentHeight //
|
||||
, "--horizontal-padding", horizontalPadding //
|
||||
, "--vertical-padding", verticalPadding //
|
||||
, wallpaperPath //
|
||||
, ...(root.placementStrategy === "mostBusy" ? ["--busiest"] : [])
|
||||
// "--visual-output",
|
||||
]
|
||||
stdout: StdioCollector {
|
||||
id: leastBusyRegionOutputCollector
|
||||
onStreamFinished: {
|
||||
const output = leastBusyRegionOutputCollector.text;
|
||||
// console.log("[Background] Least busy region output:", output)
|
||||
if (output.length === 0) return;
|
||||
const parsedContent = JSON.parse(output);
|
||||
root.dominantColor = parsedContent.dominant_color || Appearance.colors.colPrimary;
|
||||
if (root.placementStrategy === "free") return;
|
||||
root.targetX = parsedContent.center_x * root.wallpaperScale - root.width / 2;
|
||||
root.targetY = parsedContent.center_y * root.wallpaperScale - root.height / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.common.widgets.widgetCanvas
|
||||
import qs.modules.ii.background.widgets
|
||||
|
||||
AbstractBackgroundWidget {
|
||||
id: root
|
||||
|
||||
configEntryName: "clock"
|
||||
|
||||
implicitHeight: contentColumn.implicitHeight
|
||||
implicitWidth: contentColumn.implicitWidth
|
||||
|
||||
property string clockStyle: Config.options.background.widgets.clock.style
|
||||
property bool forceCenter: (GlobalStates.screenLocked && Config.options.lock.centerClock)
|
||||
property bool wallpaperSafetyTriggered: false
|
||||
needsColText: clockStyle === "digital"
|
||||
x: forceCenter ? ((root.screenWidth - root.width) / 2) : targetX
|
||||
y: forceCenter ? ((root.screenHeight - root.height) / 2) : targetY
|
||||
visibleWhenLocked: true
|
||||
|
||||
property var textHorizontalAlignment: {
|
||||
if (root.forceCenter)
|
||||
return Text.AlignHCenter;
|
||||
if (root.x < root.scaledScreenWidth / 3)
|
||||
return Text.AlignLeft;
|
||||
if (root.x > root.scaledScreenWidth * 2 / 3)
|
||||
return Text.AlignRight;
|
||||
return Text.AlignHCenter;
|
||||
}
|
||||
|
||||
Column {
|
||||
id: contentColumn
|
||||
anchors.centerIn: parent
|
||||
spacing: 6
|
||||
|
||||
FadeLoader {
|
||||
id: cookieClockLoader
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
shown: root.clockStyle === "cookie"
|
||||
sourceComponent: Column {
|
||||
CookieClock {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
FadeLoader {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
shown: Config.options.background.widgets.clock.quote.enable && Config.options.background.widgets.clock.quote.text !== ""
|
||||
sourceComponent: CookieQuote {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FadeLoader {
|
||||
id: digitalClockLoader
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
shown: root.clockStyle === "digital"
|
||||
sourceComponent: ColumnLayout {
|
||||
id: clockColumn
|
||||
spacing: 6
|
||||
|
||||
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.widgets.clock.quote.enable && Config.options.background.widgets.clock.quote.text.length > 0
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: root.textHorizontalAlignment
|
||||
font {
|
||||
pixelSize: Appearance.font.pixelSize.normal
|
||||
weight: 350
|
||||
}
|
||||
color: root.colText
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
text: Config.options.background.widgets.clock.quote.text
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id: statusText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
implicitHeight: statusTextBg.implicitHeight
|
||||
implicitWidth: statusTextBg.implicitWidth
|
||||
StyledRectangularShadow {
|
||||
target: statusTextBg
|
||||
visible: statusTextBg.visible && root.clockStyle === "cookie"
|
||||
opacity: statusTextBg.opacity
|
||||
}
|
||||
Rectangle {
|
||||
id: statusTextBg
|
||||
anchors.centerIn: parent
|
||||
clip: true
|
||||
opacity: (safetyStatusText.shown || lockStatusText.shown) ? 1 : 0
|
||||
visible: opacity > 0
|
||||
implicitHeight: statusTextRow.implicitHeight + 5 * 2
|
||||
implicitWidth: statusTextRow.implicitWidth + 5 * 2
|
||||
radius: Appearance.rounding.small
|
||||
color: ColorUtils.transparentize(Appearance.colors.colSecondaryContainer, root.clockStyle === "cookie" ? 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: 14
|
||||
Item {
|
||||
Layout.fillWidth: root.textHorizontalAlignment !== Text.AlignLeft
|
||||
implicitWidth: 1
|
||||
}
|
||||
ClockStatusText {
|
||||
id: safetyStatusText
|
||||
shown: root.wallpaperSafetyTriggered
|
||||
statusIcon: "hide_image"
|
||||
statusText: Translation.tr("Wallpaper safety enforced")
|
||||
}
|
||||
ClockStatusText {
|
||||
id: lockStatusText
|
||||
shown: GlobalStates.screenLocked && Config.options.lock.showLockedText
|
||||
statusIcon: "lock"
|
||||
statusText: Translation.tr("Locked")
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: root.textHorizontalAlignment !== Text.AlignRight
|
||||
implicitWidth: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component ClockText: StyledText {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: root.textHorizontalAlignment
|
||||
font {
|
||||
family: Appearance.font.family.expressive
|
||||
pixelSize: 20
|
||||
weight: Font.DemiBold
|
||||
}
|
||||
color: root.colText
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
animateChange: Config.options.background.widgets.clock.digital.animateChange
|
||||
}
|
||||
component ClockStatusText: Row {
|
||||
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 : root.colText
|
||||
opacity: shown ? 1 : 0
|
||||
visible: opacity > 0
|
||||
Behavior on opacity {
|
||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||
}
|
||||
spacing: 4
|
||||
MaterialSymbol {
|
||||
id: statusIconWidget
|
||||
anchors.verticalCenter: statusTextRow.verticalCenter
|
||||
iconSize: Appearance.font.pixelSize.huge
|
||||
color: statusTextRow.textColor
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
}
|
||||
ClockText {
|
||||
id: statusTextWidget
|
||||
color: statusTextRow.textColor
|
||||
anchors.verticalCenter: statusTextRow.verticalCenter
|
||||
font {
|
||||
pixelSize: Appearance.font.pixelSize.large
|
||||
weight: Font.Normal
|
||||
}
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.common.functions
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import Quickshell.Io
|
||||
|
||||
import qs.modules.ii.background.widgets.clock.dateIndicator
|
||||
import qs.modules.ii.background.widgets.clock.minuteMarks
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property string clockStyle: Config.options.background.widgets.clock.style
|
||||
|
||||
property real implicitSize: 230
|
||||
|
||||
property color colShadow: Appearance.colors.colShadow
|
||||
property color colBackground: Appearance.colors.colPrimaryContainer
|
||||
property color colOnBackground: ColorUtils.mix(Appearance.colors.colSecondary, Appearance.colors.colPrimaryContainer, 0.15)
|
||||
property color colBackgroundInfo: ColorUtils.mix(Appearance.colors.colPrimary, Appearance.colors.colPrimaryContainer, 0.55)
|
||||
property color colHourHand: Appearance.colors.colPrimary
|
||||
property color colMinuteHand: Appearance.colors.colTertiary
|
||||
property color colSecondHand: Appearance.colors.colPrimary
|
||||
|
||||
readonly property list<string> clockNumbers: DateTime.time.split(/[: ]/)
|
||||
readonly property int clockHour: parseInt(clockNumbers[0]) % 12
|
||||
readonly property int clockMinute: DateTime.clock.minutes
|
||||
readonly property int clockSecond: DateTime.clock.seconds
|
||||
|
||||
implicitWidth: implicitSize
|
||||
implicitHeight: implicitSize
|
||||
|
||||
function applyStyle(sides, dialStyle, hourHandStyle, minuteHandStyle, secondHandStyle, dateStyle) {
|
||||
Config.options.background.widgets.clock.cookie.sides = sides
|
||||
Config.options.background.widgets.clock.cookie.dialNumberStyle = dialStyle
|
||||
Config.options.background.widgets.clock.cookie.hourHandStyle = hourHandStyle
|
||||
Config.options.background.widgets.clock.cookie.minuteHandStyle = minuteHandStyle
|
||||
Config.options.background.widgets.clock.cookie.secondHandStyle = secondHandStyle
|
||||
Config.options.background.widgets.clock.cookie.dateStyle = dateStyle
|
||||
}
|
||||
|
||||
function setClockPreset(category) {
|
||||
if (!Config.options.background.widgets.clock.cookie.aiStyling) return;
|
||||
if (category === "") return;
|
||||
print("[Cookie clock] Setting clock preset for category: " + category)
|
||||
// "abstract", "anime", "city", "minimalist", "landscape", "plants", "person", "space"
|
||||
if (category == "abstract") {
|
||||
applyStyle(9, "none", "fill", "medium", "dot", "bubble")
|
||||
} else if (category == "anime") {
|
||||
applyStyle(7, "none", "fill", "bold", "dot", "bubble")
|
||||
} else if (category == "city" || category == "space") {
|
||||
applyStyle(23, "full", "hollow", "thin", "classic", "bubble")
|
||||
} else if (category == "minimalist") {
|
||||
applyStyle(6, "none", "fill", "bold", "dot", "hide")
|
||||
} else if (category == "landscape") {
|
||||
applyStyle(14, "full", "hollow", "medium", "classic", "bubble")
|
||||
} else if (category == "plants") {
|
||||
applyStyle(9, "dots", "fill", "bold", "dot", "border")
|
||||
} else if (category == "person") {
|
||||
applyStyle(14, "full", "classic", "classic", "classic", "rect")
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Config
|
||||
function onReadyChanged() {
|
||||
categoryFileView.path = Directories.generatedWallpaperCategoryPath
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: categoryFileView
|
||||
path: ""
|
||||
watchChanges: true
|
||||
onFileChanged: reload()
|
||||
onLoaded: {
|
||||
root.setClockPreset(categoryFileView.text().trim())
|
||||
}
|
||||
}
|
||||
|
||||
property bool useSineCookie: Config.options.background.widgets.clock.cookie.useSineCookie
|
||||
StyledDropShadow {
|
||||
target: useSineCookie ? sineCookieLoader : roundedPolygonCookieLoader
|
||||
|
||||
RotationAnimation on rotation {
|
||||
running: Config.options.background.widgets.clock.cookie.constantlyRotate
|
||||
duration: 30000
|
||||
easing.type: Easing.Linear
|
||||
loops: Animation.Infinite
|
||||
from: 360
|
||||
to: 0
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: sineCookieLoader
|
||||
z: 0
|
||||
visible: false // The DropShadow already draws it
|
||||
active: useSineCookie
|
||||
sourceComponent: SineCookie {
|
||||
implicitSize: root.implicitSize
|
||||
sides: Config.options.background.widgets.clock.cookie.sides
|
||||
color: root.colBackground
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: roundedPolygonCookieLoader
|
||||
z: 0
|
||||
visible: false // The DropShadow already draws it
|
||||
active: !useSineCookie
|
||||
sourceComponent: MaterialCookie {
|
||||
implicitSize: root.implicitSize
|
||||
sides: Config.options.background.widgets.clock.cookie.sides
|
||||
color: root.colBackground
|
||||
}
|
||||
}
|
||||
|
||||
// Hour/minutes numbers/dots/lines
|
||||
MinuteMarks {
|
||||
anchors.fill: parent
|
||||
color: root.colOnBackground
|
||||
}
|
||||
|
||||
// Stupid extra hour marks in the middle
|
||||
FadeLoader {
|
||||
id: hourMarksLoader
|
||||
anchors.centerIn: parent
|
||||
shown: Config.options.background.widgets.clock.cookie.hourMarks
|
||||
sourceComponent: HourMarks {
|
||||
implicitSize: 135 * (1.75 - 0.75 * hourMarksLoader.opacity)
|
||||
color: root.colOnBackground
|
||||
colOnBackground: ColorUtils.mix(root.colBackgroundInfo, root.colOnBackground, 0.5)
|
||||
}
|
||||
}
|
||||
|
||||
// Number column in the middle
|
||||
FadeLoader {
|
||||
id: timeColumnLoader
|
||||
anchors.centerIn: parent
|
||||
shown: Config.options.background.widgets.clock.cookie.timeIndicators
|
||||
scale: 1.4 - 0.4 * timeColumnLoader.shown
|
||||
Behavior on scale {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
sourceComponent: TimeColumn {
|
||||
color: root.colBackgroundInfo
|
||||
}
|
||||
}
|
||||
|
||||
// Minute hand
|
||||
FadeLoader {
|
||||
anchors.fill: parent
|
||||
z: 1
|
||||
shown: Config.options.background.widgets.clock.cookie.minuteHandStyle !== "hide"
|
||||
sourceComponent: MinuteHand {
|
||||
anchors.fill: parent
|
||||
clockMinute: root.clockMinute
|
||||
style: Config.options.background.widgets.clock.cookie.minuteHandStyle
|
||||
color: root.colMinuteHand
|
||||
}
|
||||
}
|
||||
|
||||
// Hour hand
|
||||
FadeLoader {
|
||||
anchors.fill: parent
|
||||
z: item?.style === "hollow" ? 0 : 2
|
||||
shown: Config.options.background.widgets.clock.cookie.hourHandStyle !== "hide"
|
||||
sourceComponent: HourHand {
|
||||
clockHour: root.clockHour
|
||||
clockMinute: root.clockMinute
|
||||
style: Config.options.background.widgets.clock.cookie.hourHandStyle
|
||||
color: root.colHourHand
|
||||
}
|
||||
}
|
||||
|
||||
// Second hand
|
||||
FadeLoader {
|
||||
id: secondHandLoader
|
||||
z: (Config.options.background.widgets.clock.cookie.secondHandStyle === "line") ? 2 : 3
|
||||
shown: Config.options.time.secondPrecision && Config.options.background.widgets.clock.cookie.secondHandStyle !== "hide"
|
||||
anchors.fill: parent
|
||||
sourceComponent: SecondHand {
|
||||
id: secondHand
|
||||
clockSecond: root.clockSecond
|
||||
style: Config.options.background.widgets.clock.cookie.secondHandStyle
|
||||
color: root.colSecondHand
|
||||
}
|
||||
}
|
||||
|
||||
// Center dot
|
||||
FadeLoader {
|
||||
z: 4
|
||||
anchors.centerIn: parent
|
||||
shown: Config.options.background.widgets.clock.cookie.minuteHandStyle !== "bold"
|
||||
sourceComponent: Rectangle {
|
||||
color: Config.options.background.widgets.clock.cookie.minuteHandStyle === "medium" ? root.colBackground : root.colMinuteHand
|
||||
implicitWidth: 6
|
||||
implicitHeight: implicitWidth
|
||||
radius: width / 2
|
||||
}
|
||||
}
|
||||
|
||||
// Date
|
||||
FadeLoader {
|
||||
anchors.fill: parent
|
||||
shown: Config.options.background.widgets.clock.cookie.dateStyle !== "hide"
|
||||
|
||||
sourceComponent: DateIndicator {
|
||||
color: root.colBackgroundInfo
|
||||
style: Config.options.background.widgets.clock.cookie.dateStyle
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property string quoteText: Config.options.background.widgets.clock.quote.text
|
||||
|
||||
implicitWidth: quoteBox.implicitWidth
|
||||
implicitHeight: quoteBox.implicitHeight
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: -24
|
||||
|
||||
DropShadow {
|
||||
source: quoteBox
|
||||
anchors.fill: quoteBox
|
||||
horizontalOffset: 0
|
||||
verticalOffset: 2
|
||||
radius: 12
|
||||
samples: radius * 2 + 1
|
||||
color: Appearance.colors.colShadow
|
||||
transparentBorder: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: quoteBox
|
||||
|
||||
implicitWidth: quoteStyledText.width + quoteIcon.width + 16 // for spacing on both sides
|
||||
implicitHeight: quoteStyledText.height + 8
|
||||
radius: Appearance.rounding.small
|
||||
color: Appearance.colors.colSecondaryContainer
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: 4
|
||||
MaterialSymbol {
|
||||
id: quoteIcon
|
||||
anchors.top: parent.top
|
||||
iconSize: Appearance.font.pixelSize.huge
|
||||
text: "format_quote"
|
||||
color: Appearance.colors.colOnSecondaryContainer
|
||||
}
|
||||
StyledText {
|
||||
id: quoteStyledText
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
text: Config.options.background.widgets.clock.quote.text
|
||||
color: Appearance.colors.colOnSecondaryContainer
|
||||
font {
|
||||
family: Appearance.font.family.reading
|
||||
pixelSize: Appearance.font.pixelSize.large
|
||||
weight: Font.Normal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.modules.common
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property int clockHour
|
||||
required property int clockMinute
|
||||
property real handLength: 72
|
||||
property real handWidth: 20
|
||||
property string style: "fill"
|
||||
property color color: Appearance.colors.colPrimary
|
||||
|
||||
property real fillColorAlpha: root.style === "hollow" ? 0 : 1
|
||||
Behavior on fillColorAlpha {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
rotation: -90 + (360 / 12) * (root.clockHour + root.clockMinute / 60)
|
||||
Behavior on rotation {
|
||||
animation: RotationAnimation {
|
||||
direction: RotationAnimation.Clockwise
|
||||
duration: 300
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Appearance.animationCurves.emphasized
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: (parent.width - root.handWidth) / 2 - 15 * (root.style === "classic")
|
||||
width: root.handLength
|
||||
height: root.style === "classic" ? 8 : root.handWidth
|
||||
radius: root.style === "classic" ? 2 : root.handWidth / 2
|
||||
color : Qt.rgba(root.color.r, root.color.g, root.color.b, root.fillColorAlpha)
|
||||
border.color: root.color
|
||||
border.width: 4
|
||||
|
||||
Behavior on x {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.common.functions
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property real implicitSize: 135
|
||||
property real markLength: 12
|
||||
property real markWidth: 4
|
||||
property color color: Appearance.colors.colOnSecondaryContainer
|
||||
property color colOnBackground: Appearance.colors.colSecondaryContainer
|
||||
property real padding: 8
|
||||
|
||||
Rectangle {
|
||||
color: root.color
|
||||
anchors.centerIn: parent
|
||||
implicitWidth: root.implicitSize
|
||||
implicitHeight: root.implicitSize
|
||||
radius: width / 2
|
||||
|
||||
// Hour mark lines
|
||||
Repeater {
|
||||
model: 12
|
||||
|
||||
Item {
|
||||
required property int index
|
||||
anchors.fill: parent
|
||||
rotation: 360 / 12 * index
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
leftMargin: root.padding
|
||||
}
|
||||
implicitWidth: root.markLength
|
||||
implicitHeight: root.markWidth
|
||||
|
||||
radius: width / 2
|
||||
color: root.colOnBackground
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.modules.common
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
anchors.fill: parent
|
||||
|
||||
required property int clockMinute
|
||||
property string style: "medium"
|
||||
property real handLength: 95
|
||||
property real handWidth: style === "bold" ? 20 : style === "medium" ? 12 : 5
|
||||
property color color: Appearance.colors.colTertiary
|
||||
|
||||
rotation: -90 + (360 / 60) * root.clockMinute
|
||||
Behavior on rotation {
|
||||
animation: RotationAnimation {
|
||||
direction: RotationAnimation.Clockwise
|
||||
duration: 300
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Appearance.animationCurves.emphasized
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: {
|
||||
let position = parent.width / 2 - root.handWidth / 2;
|
||||
if (root.style === "classic") position -= 15;
|
||||
return position;
|
||||
}
|
||||
width: root.handLength
|
||||
height: root.handWidth
|
||||
|
||||
radius: root.style === "classic" ? 2 : root.handWidth / 2
|
||||
color: root.color
|
||||
|
||||
Behavior on height {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
Behavior on x {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
anchors.fill: parent
|
||||
|
||||
required property int clockSecond
|
||||
property real handWidth: 2
|
||||
property real handLength: 95
|
||||
property real dotSize: 20
|
||||
property string style: "hide"
|
||||
property color color: Appearance.colors.colSecondary
|
||||
|
||||
rotation: (360 / 60 * clockSecond) + 90
|
||||
|
||||
Behavior on rotation {
|
||||
enabled: Config.options.background.widgets.clock.cookie.constantlyRotate // Animating every second is expensive...
|
||||
animation: RotationAnimation {
|
||||
direction: RotationAnimation.Clockwise
|
||||
duration: 1000 // 1 second
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
leftMargin: 10 + (root.style === "dot" ? root.dotSize : 0)
|
||||
}
|
||||
implicitWidth: root.style === "dot" ? root.dotSize : root.handLength
|
||||
implicitHeight: root.style === "dot" ? root.dotSize : root.handWidth
|
||||
radius: Math.min(width, height) / 2
|
||||
color: root.color
|
||||
Behavior on implicitHeight {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
Behavior on implicitWidth {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
}
|
||||
|
||||
// Classic style dot in the middle of the hand
|
||||
FadeLoader {
|
||||
id: classicDotLoader
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
shown: root.style === "classic"
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
leftMargin: 40
|
||||
}
|
||||
implicitWidth: root.style === "classic" ? 14 : 0
|
||||
implicitHeight: implicitWidth
|
||||
color: root.color
|
||||
radius: Appearance.rounding.small
|
||||
|
||||
Behavior on implicitWidth {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
|
||||
Column {
|
||||
id: root
|
||||
property list<string> clockNumbers: DateTime.time.split(/[: ]/)
|
||||
property bool isEnabled: Config.options.background.widgets.clock.cookie.timeIndicators
|
||||
property color color: Appearance.colors.colOnSecondaryContainer
|
||||
|
||||
property bool hourMarksEnabled: Config.options.background.widgets.clock.cookie.hourMarks
|
||||
spacing: -16
|
||||
|
||||
Repeater {
|
||||
model: root.clockNumbers
|
||||
|
||||
delegate: StyledText {
|
||||
required property string modelData
|
||||
text: modelData.padStart(2, "0")
|
||||
property bool isAmPm: !text.match(/\d{2}/i)
|
||||
property real numberSizeWithoutGlow: isAmPm ? 26 : 68
|
||||
property real numberSizeWithGlow: isAmPm ? 20 : 40
|
||||
property real numberSize: root.hourMarksEnabled ? numberSizeWithGlow : numberSizeWithoutGlow
|
||||
|
||||
anchors.horizontalCenter: root.horizontalCenter
|
||||
color: root.color
|
||||
font {
|
||||
family: Appearance.font.family.expressive
|
||||
weight: Font.Bold
|
||||
pixelSize: numberSize
|
||||
}
|
||||
|
||||
Behavior on numberSize {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property bool isMonth: false
|
||||
property real targetSize: 0
|
||||
property alias text: bubbleText.text
|
||||
|
||||
text: Qt.locale().toString(DateTime.clock.date, root.isMonth ? "MM" : "d")
|
||||
|
||||
MaterialShape {
|
||||
id: bubble
|
||||
z: 5
|
||||
// sides: root.isMonth ? 1 : 4
|
||||
shape: root.isMonth ? MaterialShape.Shape.Pill : MaterialShape.Shape.Pentagon
|
||||
anchors.centerIn: parent
|
||||
color: root.isMonth ? Appearance.colors.colSecondaryContainer : Appearance.colors.colTertiaryContainer
|
||||
implicitSize: targetSize
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: bubbleText
|
||||
z: 6
|
||||
anchors.centerIn: parent
|
||||
color: root.isMonth ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnTertiaryContainer
|
||||
font {
|
||||
family: Appearance.font.family.expressive
|
||||
pixelSize: 30
|
||||
weight: Font.Black
|
||||
}
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.common.functions
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property string style: "bubble"
|
||||
property color color: Appearance.colors.colOnSecondaryContainer
|
||||
property real dateSquareSize: 64
|
||||
|
||||
// Rotating date
|
||||
FadeLoader {
|
||||
anchors.fill: parent
|
||||
shown: Config.options.background.widgets.clock.cookie.dateStyle === "border"
|
||||
sourceComponent: RotatingDate {
|
||||
color: root.color
|
||||
}
|
||||
}
|
||||
|
||||
// Rectangle date (only today's number) in right side of the clock
|
||||
FadeLoader {
|
||||
id: rectLoader
|
||||
shown: root.style === "rect"
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
right: parent.right
|
||||
rightMargin: 40 - rectLoader.opacity * 30
|
||||
}
|
||||
|
||||
sourceComponent: RectangleDate {
|
||||
color: ColorUtils.mix(root.color, Appearance.colors.colSecondaryContainerHover, 0.5)
|
||||
radius: Appearance.rounding.small
|
||||
implicitWidth: 45 * rectLoader.opacity
|
||||
implicitHeight: 30 * rectLoader.opacity
|
||||
}
|
||||
}
|
||||
|
||||
// Bubble style: day of month
|
||||
FadeLoader {
|
||||
id: dayBubbleLoader
|
||||
shown: root.style === "bubble"
|
||||
property real targetSize: root.dateSquareSize * opacity
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
}
|
||||
|
||||
sourceComponent: BubbleDate {
|
||||
implicitWidth: dayBubbleLoader.targetSize
|
||||
implicitHeight: dayBubbleLoader.targetSize
|
||||
isMonth: false
|
||||
targetSize: dayBubbleLoader.targetSize
|
||||
}
|
||||
}
|
||||
|
||||
// Bubble style: month
|
||||
FadeLoader {
|
||||
id: monthBubbleLoader
|
||||
shown: root.style === "bubble"
|
||||
property real targetSize: root.dateSquareSize * opacity
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
sourceComponent: BubbleDate {
|
||||
implicitWidth: monthBubbleLoader.targetSize
|
||||
implicitHeight: monthBubbleLoader.targetSize
|
||||
isMonth: true
|
||||
targetSize: monthBubbleLoader.targetSize
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
|
||||
Rectangle {
|
||||
id: rect
|
||||
readonly property string dialStyle: Config.options.background.widgets.clock.cookie.dialNumberStyle
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
color: Appearance.colors.colSecondaryHover
|
||||
text: Qt.locale().toString(DateTime.clock.date, "dd")
|
||||
font {
|
||||
family: Appearance.font.family.expressive
|
||||
pixelSize: 20
|
||||
weight: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string style: Config.options.background.widgets.clock.cookie.dateStyle
|
||||
property color color: Appearance.colors.colOnSecondaryContainer
|
||||
property real angleStep: 12 * Math.PI / 180
|
||||
property string dateText: Qt.locale().toString(DateTime.clock.date, "ddd dd")
|
||||
|
||||
readonly property int clockSecond: DateTime.clock.seconds
|
||||
readonly property string dialStyle: Config.options.background.widgets.clock.cookie.dialNumberStyle
|
||||
readonly property bool timeIndicators: Config.options.background.widgets.clock.cookie.timeIndicators
|
||||
|
||||
property real radius: style === "border" ? 90 : 0
|
||||
Behavior on radius {
|
||||
animation: Appearance.animation.elementResize.numberAnimation.createObject(this)
|
||||
}
|
||||
|
||||
rotation: {
|
||||
if (!Config.options.time.secondPrecision) return 0
|
||||
else return (360 / 60 * clockSecond) + 180 - (angleStep / Math.PI * 180 * dateText.length) / 2
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: root.dateText.length
|
||||
|
||||
delegate: Text {
|
||||
required property int index
|
||||
property real angle: index * root.angleStep - Math.PI / 2
|
||||
x: root.width / 2 + root.radius * Math.cos(angle) - width / 2
|
||||
y: root.height / 2 + root.radius * Math.sin(angle) - height / 2
|
||||
rotation: angle * 180 / Math.PI + 90
|
||||
|
||||
color: root.color
|
||||
font {
|
||||
family: Appearance.font.family.title
|
||||
pixelSize: 30
|
||||
variableAxes: Appearance.font.variableAxes.title
|
||||
}
|
||||
|
||||
text: root.dateText.charAt(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property real numberSize: 80
|
||||
property real margins: 10
|
||||
property color color: Appearance.colors.colOnSecondaryContainer
|
||||
|
||||
property int hours: 12
|
||||
property int numbers: 4
|
||||
property int fontSize: 80
|
||||
|
||||
Repeater {
|
||||
model: root.numbers
|
||||
|
||||
Item {
|
||||
id: numberItem
|
||||
required property int index
|
||||
rotation: 360 / root.numbers * (index + 1)
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
implicitWidth: root.numberSize
|
||||
implicitHeight: implicitWidth
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
topMargin: root.margins
|
||||
}
|
||||
StyledText {
|
||||
color: root.color
|
||||
anchors.centerIn: parent
|
||||
text: root.hours / root.numbers * (numberItem.index + 1)
|
||||
rotation: -numberItem.rotation
|
||||
|
||||
font {
|
||||
family: Appearance.font.family.reading
|
||||
pixelSize: root.fontSize
|
||||
weight: Font.Black
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property real implicitSize: 12
|
||||
property real margins: 10
|
||||
property color color: Appearance.colors.colOnSecondaryContainer
|
||||
|
||||
Repeater {
|
||||
model: 12
|
||||
|
||||
Item {
|
||||
required property int index
|
||||
anchors.fill: parent // Ensures rotation works properly
|
||||
rotation: 360 / 12 * index
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
leftMargin: root.margins
|
||||
}
|
||||
implicitWidth: root.implicitSize
|
||||
implicitHeight: implicitWidth
|
||||
radius: implicitWidth / 2
|
||||
color: root.color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property real numberSize: 80
|
||||
property real margins: 10
|
||||
property color color: Appearance.colors.colOnSecondaryContainer
|
||||
|
||||
property real hourLineSize: 4
|
||||
property real minuteLineSize: 2
|
||||
property real hourLineLength: 18
|
||||
property real minuteLineLength: 7
|
||||
|
||||
property int hours: 12
|
||||
property int minutes: 60
|
||||
|
||||
// Full dial style hour lines
|
||||
Repeater {
|
||||
model: root.hours
|
||||
|
||||
Item {
|
||||
required property int index
|
||||
rotation: 360 / root.hours * index
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
leftMargin: root.margins
|
||||
}
|
||||
implicitWidth: root.hourLineLength
|
||||
implicitHeight: root.hourLineSize
|
||||
radius: implicitWidth / 2
|
||||
color: root.color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Minute lines
|
||||
Repeater {
|
||||
model: root.minutes
|
||||
|
||||
Item {
|
||||
required property int index
|
||||
rotation: 360 / root.minutes * index
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
leftMargin: root.margins
|
||||
}
|
||||
implicitWidth: root.minuteLineLength
|
||||
implicitHeight: root.minuteLineSize
|
||||
radius: implicitWidth / 2
|
||||
color: root.color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property color color: Appearance.colors.colOnSecondaryContainer
|
||||
property string style: Config.options.background.widgets.clock.cookie.dialNumberStyle // "dots", "numbers", "full", "hide"
|
||||
property string dateStyle : Config.options.background.widgets.clock.cookie.dateStyle
|
||||
|
||||
// 12 Dots
|
||||
FadeLoader {
|
||||
id: dotsLoader
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 10
|
||||
}
|
||||
shown: root.style === "dots"
|
||||
sourceComponent: Dots {
|
||||
color: root.color
|
||||
margins: 46 - dotsLoader.opacity * 34
|
||||
}
|
||||
}
|
||||
|
||||
// 3-6-9-12 hour numbers (pls don't realize you can have more than 4 numbers)
|
||||
FadeLoader {
|
||||
id: bigHourNumbersLoader
|
||||
anchors.fill: parent
|
||||
shown: root.style === "numbers"
|
||||
sourceComponent: BigHourNumbers {
|
||||
numberSize: 80
|
||||
color: root.color
|
||||
margins: 20 - 10 * bigHourNumbersLoader.opacity
|
||||
}
|
||||
}
|
||||
|
||||
// Lines
|
||||
FadeLoader {
|
||||
id: linesLoader
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 10
|
||||
}
|
||||
shown: root.style === "full"
|
||||
sourceComponent: Lines {
|
||||
color: root.color
|
||||
margins: 46 - linesLoader.opacity * 34
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import QtQuick
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.common.widgets.widgetCanvas
|
||||
import qs.modules.ii.background.widgets
|
||||
|
||||
AbstractBackgroundWidget {
|
||||
id: root
|
||||
|
||||
configEntryName: "weather"
|
||||
|
||||
implicitHeight: backgroundShape.implicitHeight
|
||||
implicitWidth: backgroundShape.implicitWidth
|
||||
|
||||
StyledDropShadow {
|
||||
target: backgroundShape
|
||||
}
|
||||
|
||||
MaterialShape {
|
||||
id: backgroundShape
|
||||
anchors.fill: parent
|
||||
shape: MaterialShape.Shape.Pill
|
||||
color: Appearance.colors.colPrimaryContainer
|
||||
implicitSize: 200
|
||||
|
||||
StyledText {
|
||||
font {
|
||||
pixelSize: 80
|
||||
family: Appearance.font.family.expressive
|
||||
weight: Font.Medium
|
||||
}
|
||||
color: Appearance.colors.colPrimary
|
||||
text: Weather.data?.temp.substring(0,Weather.data?.temp.length - 1) ?? "--°"
|
||||
anchors {
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
rightMargin: 16
|
||||
topMargin: 20
|
||||
}
|
||||
}
|
||||
|
||||
MaterialSymbol {
|
||||
iconSize: 80
|
||||
color: Appearance.colors.colOnPrimaryContainer
|
||||
text: Icons.getWeatherIcon(Weather.data.wCode) ?? "cloud"
|
||||
anchors {
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
|
||||
leftMargin: 16
|
||||
bottomMargin: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user