init: working version
This commit is contained in:
commit
7d8d7dacae
109 changed files with 15066 additions and 0 deletions
8
custom/Anim.qml
Normal file
8
custom/Anim.qml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import qs.config
|
||||
import QtQuick
|
||||
|
||||
NumberAnimation {
|
||||
duration: Config.anim.durations.normal
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Config.anim.curves.standard
|
||||
}
|
||||
8
custom/CAnim.qml
Normal file
8
custom/CAnim.qml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import qs.config
|
||||
import QtQuick
|
||||
|
||||
ColorAnimation {
|
||||
duration: Config.anim.durations.normal
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Config.anim.curves.standard
|
||||
}
|
||||
29
custom/ColoredIcon.qml
Normal file
29
custom/ColoredIcon.qml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
|
||||
IconImage {
|
||||
id: root
|
||||
|
||||
required property color color
|
||||
property color dominantColor
|
||||
|
||||
asynchronous: true
|
||||
|
||||
/* layer.enabled: true */
|
||||
/* layer.effect: Colouriser { */
|
||||
/* sourceColor: root.dominantColour */
|
||||
/* colorizationColor: root.colour */
|
||||
/* } */
|
||||
|
||||
/* layer.onEnabledChanged: { */
|
||||
/* if (layer.enabled && status === Image.Ready) */
|
||||
/* CUtils.getDominantColour(this, c => dominantColour = c); */
|
||||
/* } */
|
||||
|
||||
/* onStatusChanged: { */
|
||||
/* if (layer.enabled && status === Image.Ready) */
|
||||
/* CUtils.getDominantColour(this, c => dominantColour = c); */
|
||||
/* } */
|
||||
}
|
||||
82
custom/CustomBusyIndicator.qml
Normal file
82
custom/CustomBusyIndicator.qml
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.config
|
||||
import qs.services
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Shapes
|
||||
|
||||
BusyIndicator {
|
||||
id: root
|
||||
|
||||
property color fg: Config.colors.primary
|
||||
property color bg: Config.colors.container
|
||||
|
||||
background: null
|
||||
|
||||
contentItem: Shape {
|
||||
id: shape
|
||||
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
asynchronous: true
|
||||
|
||||
RotationAnimator on rotation {
|
||||
from: 0
|
||||
to: 180
|
||||
running: root.visible && root.running
|
||||
loops: Animation.Infinite
|
||||
duration: Config.anim.durations.extraLarge
|
||||
easing.type: Easing.Linear
|
||||
easing.bezierCurve: Config.anim.curves.expressiveDefaultSpatial
|
||||
}
|
||||
|
||||
ShapePath {
|
||||
strokeWidth: Math.min(root.implicitWidth, root.implicitHeight) * 0.18
|
||||
strokeColor: root.bg
|
||||
fillColor: "transparent"
|
||||
capStyle: ShapePath.RoundCap
|
||||
|
||||
PathAngleArc {
|
||||
centerX: shape.width / 2
|
||||
centerY: shape.height / 2
|
||||
radiusX: root.implicitWidth / 2
|
||||
radiusY: root.implicitHeight / 2
|
||||
startAngle: 0
|
||||
sweepAngle: 360
|
||||
}
|
||||
|
||||
Behavior on strokeColor {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
|
||||
ShapePath {
|
||||
strokeWidth: Math.min(root.implicitWidth, root.implicitHeight) * 0.18
|
||||
strokeColor: root.fg
|
||||
fillColor: "transparent"
|
||||
capStyle: ShapePath.RoundCap
|
||||
|
||||
PathAngleArc {
|
||||
centerX: shape.width / 2
|
||||
centerY: shape.height / 2
|
||||
radiusX: root.implicitWidth / 2
|
||||
radiusY: root.implicitHeight / 2
|
||||
startAngle: -sweepAngle / 2
|
||||
sweepAngle: 60
|
||||
}
|
||||
|
||||
PathAngleArc {
|
||||
centerX: shape.width / 2
|
||||
centerY: shape.height / 2
|
||||
radiusX: root.implicitWidth / 2
|
||||
radiusY: root.implicitHeight / 2
|
||||
startAngle: 180 - sweepAngle / 2
|
||||
sweepAngle: 60
|
||||
}
|
||||
|
||||
Behavior on strokeColor {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
custom/CustomClippingRect.qml
Normal file
8
custom/CustomClippingRect.qml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
import QtQuick
|
||||
import Quickshell.Widgets
|
||||
import qs.config
|
||||
|
||||
ClippingRectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
156
custom/CustomFilledSlider.qml
Normal file
156
custom/CustomFilledSlider.qml
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
import qs.services
|
||||
import qs.config
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
Slider {
|
||||
id: root
|
||||
|
||||
required property string icon
|
||||
required property color color
|
||||
property real oldValue
|
||||
property bool initializing: true
|
||||
|
||||
Timer {
|
||||
id: initDelay
|
||||
running: true
|
||||
interval: 100
|
||||
onTriggered: root.initializing = false
|
||||
}
|
||||
|
||||
orientation: Qt.Vertical
|
||||
|
||||
background: CustomRect {
|
||||
color: Config.colors.container
|
||||
radius: 1000
|
||||
|
||||
CustomRect {
|
||||
implicitWidth: root.orientation === Qt.Horizontal ? root.handle.x + root.handle.width : root.handle.width
|
||||
y: root.orientation === Qt.Vertical ? root.handle.y : 0
|
||||
implicitHeight: root.orientation === Qt.Vertical ? parent.height - y : root.handle.height
|
||||
|
||||
color: root.color
|
||||
opacity: 0.8
|
||||
radius: parent.radius
|
||||
}
|
||||
}
|
||||
|
||||
handle: Item {
|
||||
id: handle
|
||||
|
||||
property bool moving: false
|
||||
|
||||
x: root.orientation === Qt.Horizontal ? root.visualPosition * (root.availableWidth - width) : 0
|
||||
y: root.orientation === Qt.Vertical ? root.visualPosition * (root.availableHeight - height) : 0
|
||||
implicitWidth: root.orientation === Qt.Horizontal ? root.height : root.width
|
||||
implicitHeight: implicitWidth
|
||||
|
||||
Elevation {
|
||||
anchors.fill: parent
|
||||
radius: rect.radius
|
||||
level: handleInteraction.containsMouse ? 2 : 1
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
id: rect
|
||||
anchors.fill: parent
|
||||
|
||||
color: root.color
|
||||
radius: 1000
|
||||
|
||||
MouseArea {
|
||||
id: handleInteraction
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
property bool moving: handle.moving
|
||||
property bool stoppingMove: false
|
||||
|
||||
function update(): void {
|
||||
text = moving ? Qt.binding(() => Math.round(root.value * 100)) : Qt.binding(() => root.icon);
|
||||
font.family = moving ? Config.font.family.sans : Config.font.family.material;
|
||||
font.pointSize = moving ? Config.font.size.smaller : Config.font.size.larger;
|
||||
}
|
||||
|
||||
animate: !moving && !stoppingMove
|
||||
animateDuration: Config.anim.durations.small
|
||||
text: root.icon
|
||||
font.pointSize: Config.font.size.larger
|
||||
color: Config.colors.primaryDark
|
||||
anchors.centerIn: parent
|
||||
|
||||
Behavior on moving {
|
||||
enabled: icon.moving !== targetValue
|
||||
SequentialAnimation {
|
||||
PropertyAction {
|
||||
target: icon
|
||||
property: "stoppingMove"
|
||||
value: true
|
||||
}
|
||||
Anim {
|
||||
target: icon
|
||||
property: "scale"
|
||||
from: 1
|
||||
to: 0
|
||||
duration: Config.anim.durations.small / 2
|
||||
easing.bezierCurve: Config.anim.curves.standardAccel
|
||||
}
|
||||
ScriptAction {
|
||||
script: icon.update()
|
||||
}
|
||||
Anim {
|
||||
target: icon
|
||||
property: "scale"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: Config.anim.durations.small / 2
|
||||
easing.bezierCurve: Config.anim.curves.standardDecel
|
||||
}
|
||||
PropertyAction {
|
||||
target: icon
|
||||
property: "stoppingMove"
|
||||
value: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onPressedChanged: handle.moving = pressed
|
||||
|
||||
onValueChanged: {
|
||||
if (Math.abs(value - oldValue) < 0.01)
|
||||
return;
|
||||
if (!initializing) {
|
||||
oldValue = value;
|
||||
handle.moving = true;
|
||||
stateChangeDelay.restart();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: stateChangeDelay
|
||||
|
||||
interval: 600
|
||||
onTriggered: {
|
||||
if (!root.pressed)
|
||||
handle.moving = false;
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on value {
|
||||
enabled: !root.initializing
|
||||
Anim {
|
||||
duration: Config.anim.durations.normal
|
||||
}
|
||||
}
|
||||
}
|
||||
14
custom/CustomListView.qml
Normal file
14
custom/CustomListView.qml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import qs.custom
|
||||
import QtQuick
|
||||
|
||||
ListView {
|
||||
id: root
|
||||
|
||||
maximumFlickVelocity: 3000
|
||||
|
||||
rebound: Transition {
|
||||
Anim {
|
||||
properties: "x,y"
|
||||
}
|
||||
}
|
||||
}
|
||||
22
custom/CustomMouseArea.qml
Normal file
22
custom/CustomMouseArea.qml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import QtQuick
|
||||
|
||||
MouseArea {
|
||||
property int scrollAccumulatedY: 0
|
||||
property int scrollThreshold: 160
|
||||
|
||||
function onWheel(event: WheelEvent): void {
|
||||
}
|
||||
|
||||
onWheel: event => {
|
||||
// Update accumulated scroll
|
||||
if (Math.sign(event.angleDelta.y) !== Math.sign(scrollAccumulatedY))
|
||||
scrollAccumulatedY = 0;
|
||||
scrollAccumulatedY += event.angleDelta.y;
|
||||
|
||||
// Trigger handler and reset if above threshold
|
||||
if (Math.abs(scrollAccumulatedY) >= scrollThreshold) {
|
||||
onWheel(event);
|
||||
scrollAccumulatedY = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
custom/CustomRect.qml
Normal file
7
custom/CustomRect.qml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
import QtQuick
|
||||
import qs.config
|
||||
|
||||
Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
107
custom/CustomScrollBar.qml
Normal file
107
custom/CustomScrollBar.qml
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import qs.services
|
||||
import qs.config
|
||||
import QtQuick
|
||||
import QtQuick.Templates
|
||||
|
||||
ScrollBar {
|
||||
id: root
|
||||
|
||||
required property Flickable flickable
|
||||
property bool shouldBeActive
|
||||
property real nonAnimPosition
|
||||
property bool animating
|
||||
|
||||
onHoveredChanged: {
|
||||
if (hovered)
|
||||
shouldBeActive = true;
|
||||
else
|
||||
shouldBeActive = flickable.moving;
|
||||
}
|
||||
|
||||
onPositionChanged: {
|
||||
if (position === nonAnimPosition)
|
||||
animating = false;
|
||||
else if (!animating)
|
||||
nonAnimPosition = position;
|
||||
}
|
||||
|
||||
position: nonAnimPosition
|
||||
implicitWidth: 5
|
||||
|
||||
contentItem: CustomRect {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
opacity: {
|
||||
if (root.size === 1)
|
||||
return 0;
|
||||
if (fullMouse.pressed)
|
||||
return 0.8;
|
||||
if (mouse.containsMouse)
|
||||
return 0.6;
|
||||
if (root.policy === ScrollBar.AlwaysOn || root.shouldBeActive)
|
||||
return 0.4;
|
||||
return 0;
|
||||
}
|
||||
radius: 1000
|
||||
color: Config.colors.secondary
|
||||
|
||||
MouseArea {
|
||||
id: mouse
|
||||
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.flickable
|
||||
|
||||
function onMovingChanged(): void {
|
||||
if (root.flickable.moving)
|
||||
root.shouldBeActive = true;
|
||||
else
|
||||
hideDelay.restart();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: hideDelay
|
||||
|
||||
interval: 600
|
||||
onTriggered: root.shouldBeActive = root.flickable.moving || root.hovered
|
||||
}
|
||||
|
||||
CustomMouseArea {
|
||||
id: fullMouse
|
||||
|
||||
anchors.fill: parent
|
||||
preventStealing: true
|
||||
|
||||
onPressed: event => {
|
||||
root.animating = true;
|
||||
root.nonAnimPosition = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2));
|
||||
}
|
||||
|
||||
onPositionChanged: event => root.nonAnimPosition = Math.max(0, Math.min(1 - root.size, event.y / root.height - root.size / 2))
|
||||
|
||||
function onWheel(event: WheelEvent): void {
|
||||
root.animating = true;
|
||||
if (event.angleDelta.y > 0)
|
||||
root.nonAnimPosition = Math.max(0, root.nonAnimPosition - 0.1);
|
||||
else if (event.angleDelta.y < 0)
|
||||
root.nonAnimPosition = Math.min(1 - root.size, root.nonAnimPosition + 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on position {
|
||||
enabled: !fullMouse.pressed
|
||||
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
5
custom/CustomShortcut.qml
Normal file
5
custom/CustomShortcut.qml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import Quickshell.Hyprland
|
||||
|
||||
GlobalShortcut {
|
||||
appid: "quickshell"
|
||||
}
|
||||
59
custom/CustomSlider.qml
Normal file
59
custom/CustomSlider.qml
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import qs.config
|
||||
import qs.custom
|
||||
import qs.services
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
Slider {
|
||||
id: root
|
||||
|
||||
property color progressColor: Config.colors.primary
|
||||
|
||||
background: Item {
|
||||
CustomRect {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.topMargin: root.implicitHeight / 4
|
||||
anchors.bottomMargin: root.implicitHeight / 4
|
||||
|
||||
implicitWidth: root.handle.x - root.implicitHeight / 6
|
||||
|
||||
color: root.progressColor
|
||||
radius: 1000
|
||||
topRightRadius: root.implicitHeight / 15
|
||||
bottomRightRadius: root.implicitHeight / 15
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: root.implicitHeight / 4
|
||||
anchors.bottomMargin: root.implicitHeight / 4
|
||||
|
||||
implicitWidth: parent.width - root.handle.x - root.handle.implicitWidth - root.implicitHeight / 6
|
||||
|
||||
color: Config.colors.container
|
||||
radius: 1000
|
||||
topLeftRadius: root.implicitHeight / 15
|
||||
bottomLeftRadius: root.implicitHeight / 15
|
||||
}
|
||||
}
|
||||
|
||||
handle: CustomRect {
|
||||
x: root.visualPosition * root.availableWidth - implicitWidth / 2
|
||||
|
||||
implicitWidth: root.implicitHeight / 3
|
||||
implicitHeight: root.implicitHeight
|
||||
|
||||
color: Config.colors.secondary
|
||||
radius: 1000
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
155
custom/CustomSwitch.qml
Normal file
155
custom/CustomSwitch.qml
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
import qs.config
|
||||
import qs.custom
|
||||
import qs.services
|
||||
import qs.util
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Shapes
|
||||
|
||||
Switch {
|
||||
id: root
|
||||
|
||||
property real size: Config.font.size.normal * 1.5
|
||||
property color bg: Config.colors.container
|
||||
property color accent: Color.mute(Config.colors.accent)
|
||||
|
||||
implicitWidth: implicitIndicatorWidth
|
||||
implicitHeight: implicitIndicatorHeight
|
||||
|
||||
indicator: CustomRect {
|
||||
radius: 1000
|
||||
color: root.checked ? root.accent : root.bg
|
||||
|
||||
implicitWidth: implicitHeight * 1.7
|
||||
implicitHeight: size
|
||||
|
||||
CustomRect {
|
||||
readonly property real nonAnimWidth: root.pressed ? implicitHeight * 1.3 : implicitHeight
|
||||
|
||||
radius: 1000
|
||||
color: root.checked ? Config.colors.secondary : Config.colors.tertiary
|
||||
|
||||
x: root.checked ? parent.implicitWidth - nonAnimWidth : 0
|
||||
implicitWidth: nonAnimWidth
|
||||
implicitHeight: parent.implicitHeight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
CustomRect {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
|
||||
color: root.checked ? Config.colors.tertiary : Config.colors.secondary
|
||||
opacity: root.pressed ? 0.4 : root.hovered ? 0.2 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
Shape {
|
||||
id: icon
|
||||
|
||||
property point start1: {
|
||||
if (root.pressed)
|
||||
return Qt.point(width * 0.2, height / 2);
|
||||
if (root.checked)
|
||||
return Qt.point(width * 0.2, height / 2);
|
||||
return Qt.point(width * 0.15, height * 0.15);
|
||||
}
|
||||
property point end1: {
|
||||
if (root.pressed) {
|
||||
if (root.checked)
|
||||
return Qt.point(width * 0.4, height / 2);
|
||||
return Qt.point(width * 0.8, height / 2);
|
||||
}
|
||||
if (root.checked)
|
||||
return Qt.point(width * 0.45, height * 0.7);
|
||||
return Qt.point(width * 0.85, height * 0.85);
|
||||
}
|
||||
property point start2: {
|
||||
if (root.pressed) {
|
||||
if (root.checked)
|
||||
return Qt.point(width * 0.4, height / 2);
|
||||
return Qt.point(width * 0.2, height / 2);
|
||||
}
|
||||
if (root.checked)
|
||||
return Qt.point(width * 0.45, height * 0.7);
|
||||
return Qt.point(width * 0.15, height * 0.85);
|
||||
}
|
||||
property point end2: {
|
||||
if (root.pressed)
|
||||
return Qt.point(width * 0.8, height / 2);
|
||||
if (root.checked)
|
||||
return Qt.point(width * 0.9, height * 0.2);
|
||||
return Qt.point(width * 0.85, height * 0.15);
|
||||
}
|
||||
|
||||
anchors.centerIn: parent
|
||||
width: height
|
||||
height: parent.implicitHeight * 0.45
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
asynchronous: true
|
||||
|
||||
ShapePath {
|
||||
strokeWidth: root.size * 0.1
|
||||
strokeColor: Config.colors.primaryDark
|
||||
fillColor: "transparent"
|
||||
capStyle: ShapePath.RoundCap
|
||||
|
||||
startX: icon.start1.x
|
||||
startY: icon.start1.y
|
||||
|
||||
PathLine {
|
||||
x: icon.end1.x
|
||||
y: icon.end1.y
|
||||
}
|
||||
PathMove {
|
||||
x: icon.start2.x
|
||||
y: icon.start2.y
|
||||
}
|
||||
PathLine {
|
||||
x: icon.end2.x
|
||||
y: icon.end2.y
|
||||
}
|
||||
|
||||
Behavior on strokeColor {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on start1 {
|
||||
PropAnim {}
|
||||
}
|
||||
Behavior on end1 {
|
||||
PropAnim {}
|
||||
}
|
||||
Behavior on start2 {
|
||||
PropAnim {}
|
||||
}
|
||||
Behavior on end2 {
|
||||
PropAnim {}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on x {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on implicitWidth {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
|
||||
component PropAnim: PropertyAnimation {
|
||||
duration: Config.anim.durations.normal
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Config.anim.curves.standard
|
||||
}
|
||||
}
|
||||
46
custom/CustomText.qml
Normal file
46
custom/CustomText.qml
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.config
|
||||
|
||||
Text {
|
||||
id: root
|
||||
|
||||
// Either boolean or function taking old and new text
|
||||
property var animate: false
|
||||
property string animateProp: "opacity"
|
||||
property real animateFrom: 0
|
||||
property real animateTo: 1
|
||||
property int animateDuration: Config.anim.durations.normal
|
||||
|
||||
renderType: Text.NativeRendering
|
||||
textFormat: Text.PlainText
|
||||
color: Config.colors.primary
|
||||
linkColor: Config.colors.highlight
|
||||
font.family: Config.font.family.sans
|
||||
font.pointSize: Config.font.size.smaller
|
||||
|
||||
Behavior on text {
|
||||
enabled: typeof root.animate === "boolean"
|
||||
? root.animate : root.animate(root.text, targetValue)
|
||||
|
||||
SequentialAnimation {
|
||||
Anim {
|
||||
to: root.animateFrom
|
||||
easing.bezierCurve: Config.anim.curves.standardAccel
|
||||
}
|
||||
PropertyAction {}
|
||||
Anim {
|
||||
to: root.animateTo
|
||||
easing.bezierCurve: Config.anim.curves.standardDecel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component Anim: NumberAnimation {
|
||||
target: root
|
||||
property: root.animateProp
|
||||
duration: root.animateDuration / 2
|
||||
easing.type: Easing.BezierSpline
|
||||
}
|
||||
}
|
||||
68
custom/CustomTextField.qml
Normal file
68
custom/CustomTextField.qml
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.config
|
||||
import qs.custom
|
||||
import qs.services
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
TextField {
|
||||
id: root
|
||||
|
||||
color: Config.colors.secondary
|
||||
placeholderTextColor: Config.colors.tertiary
|
||||
font.family: Config.font.family.sans
|
||||
font.pointSize: Config.font.size.smaller
|
||||
renderType: TextField.NativeRendering
|
||||
cursorVisible: !readOnly
|
||||
|
||||
background: null
|
||||
|
||||
cursorDelegate: CustomRect {
|
||||
id: cursor
|
||||
|
||||
property bool disableBlink
|
||||
|
||||
implicitWidth: 2
|
||||
color: Config.colors.primary
|
||||
radius: 20
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
|
||||
function onCursorPositionChanged(): void {
|
||||
if (root.activeFocus && root.cursorVisible) {
|
||||
cursor.opacity = 1;
|
||||
cursor.disableBlink = true;
|
||||
enableBlink.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: enableBlink
|
||||
|
||||
interval: 100
|
||||
onTriggered: cursor.disableBlink = false
|
||||
}
|
||||
|
||||
Timer {
|
||||
running: root.activeFocus && root.cursorVisible && !cursor.disableBlink
|
||||
repeat: true
|
||||
triggeredOnStart: true
|
||||
interval: 500
|
||||
onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1
|
||||
}
|
||||
|
||||
Binding {
|
||||
when: !root.activeFocus || !root.cursorVisible
|
||||
cursor.opacity: 0
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: Config.anim.durations.small
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
custom/CustomWindow.qml
Normal file
10
custom/CustomWindow.qml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
|
||||
PanelWindow {
|
||||
required property string name
|
||||
|
||||
WlrLayershell.namespace: `quickshell-${name}`
|
||||
color: "transparent"
|
||||
}
|
||||
17
custom/Elevation.qml
Normal file
17
custom/Elevation.qml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import qs.config
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
|
||||
RectangularShadow {
|
||||
property int level
|
||||
property real dp: [0, 1, 3, 6, 8, 12][level]
|
||||
|
||||
color: Qt.alpha(Config.colors.bg, 0.9)
|
||||
blur: (dp * 5) ** 0.7
|
||||
spread: -dp * 0.3 + (dp * 0.1) ** 2
|
||||
offset.y: dp / 2
|
||||
|
||||
Behavior on dp {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
49
custom/ExtraIndicator.qml
Normal file
49
custom/ExtraIndicator.qml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import qs.services
|
||||
import qs.config
|
||||
import QtQuick
|
||||
|
||||
CustomRect {
|
||||
required property int extra
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 12
|
||||
|
||||
color: Config.colors.inactive
|
||||
radius: 12
|
||||
|
||||
implicitWidth: count.implicitWidth + 20
|
||||
implicitHeight: count.implicitHeight + 10
|
||||
|
||||
opacity: extra > 0 ? 1 : 0
|
||||
scale: extra > 0 ? 1 : 0.5
|
||||
|
||||
Elevation {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
opacity: parent.opacity
|
||||
z: -1
|
||||
level: 2
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: count
|
||||
|
||||
anchors.centerIn: parent
|
||||
animate: false
|
||||
text: qsTr("+%1").arg(parent.extra)
|
||||
color: Config.colors.secondary
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {
|
||||
duration: Config.anim.durations.expressiveFastSpatial
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
Anim {
|
||||
duration: Config.anim.durations.expressiveFastSpatial
|
||||
easing.bezierCurve: Config.anim.curves.expressiveFastSpatial
|
||||
}
|
||||
}
|
||||
}
|
||||
18
custom/GlowEffect.qml
Normal file
18
custom/GlowEffect.qml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
|
||||
MultiEffect {
|
||||
id: root
|
||||
|
||||
anchors.fill: source
|
||||
|
||||
property alias glowColor: root.shadowColor
|
||||
shadowEnabled: true
|
||||
blurMultiplier: 0.3
|
||||
blurMax: 30
|
||||
|
||||
Behavior on shadowColor {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
32
custom/MaterialIcon.qml
Normal file
32
custom/MaterialIcon.qml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import qs.config
|
||||
import QtQuick
|
||||
|
||||
CustomText {
|
||||
id: root
|
||||
|
||||
property real fill
|
||||
property int grade: -25
|
||||
property bool animateAxes: true
|
||||
|
||||
Behavior on font.variableAxes {
|
||||
enabled: root.animateAxes && root.animate
|
||||
|
||||
SequentialAnimation {
|
||||
PauseAnimation {
|
||||
duration: root.animateDuration / 2
|
||||
}
|
||||
PropertyAction {}
|
||||
}
|
||||
}
|
||||
|
||||
color: Config.colors.secondary
|
||||
animateProp: "scale"
|
||||
font.family: "Material Symbols Rounded"
|
||||
font.pointSize: Config.font.size.normal
|
||||
font.variableAxes: ({
|
||||
FILL: fill,
|
||||
GRAD: grade,
|
||||
opsz: fontInfo.pixelSize,
|
||||
wght: fontInfo.weight
|
||||
})
|
||||
}
|
||||
101
custom/StateLayer.qml
Normal file
101
custom/StateLayer.qml
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.custom
|
||||
import qs.services
|
||||
|
||||
MouseArea {
|
||||
id: root
|
||||
|
||||
property bool disabled
|
||||
property color color: Config.colors.primary
|
||||
property real radius: 1000
|
||||
|
||||
function onClicked(): void {}
|
||||
|
||||
cursorShape: disabled ? undefined : Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
|
||||
onPressed: event => {
|
||||
rippleAnim.x = event.x;
|
||||
rippleAnim.y = event.y;
|
||||
|
||||
const dist = (ox, oy) => ox * ox + oy * oy;
|
||||
rippleAnim.radius = Math.sqrt(Math.max(dist(0, 0), dist(0, width), dist(width, 0), dist(width, height)));
|
||||
|
||||
rippleAnim.restart();
|
||||
}
|
||||
|
||||
onClicked: event => !disabled && onClicked(event)
|
||||
|
||||
SequentialAnimation {
|
||||
id: rippleAnim
|
||||
|
||||
property real x
|
||||
property real y
|
||||
property real radius
|
||||
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "x"
|
||||
value: rippleAnim.x
|
||||
}
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "y"
|
||||
value: rippleAnim.y
|
||||
}
|
||||
PropertyAction {
|
||||
target: ripple
|
||||
property: "opacity"
|
||||
value: 0.1
|
||||
}
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
target: ripple
|
||||
properties: "implicitWidth,implicitHeight"
|
||||
from: 0
|
||||
to: rippleAnim.radius * 2
|
||||
duration: Config.anim.durations.large
|
||||
easing.bezierCurve: Config.anim.curves.standardDecel
|
||||
}
|
||||
Anim {
|
||||
target: ripple
|
||||
property: "opacity"
|
||||
to: 0
|
||||
duration: Config.anim.durations.large
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Config.anim.curves.standardDecel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
id: hoverLayer
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
property real alpha: root.disabled ? 0 : root.pressed ? 0.1 : root.containsMouse ? 0.05 : 0
|
||||
color: Qt.alpha(root.color, alpha)
|
||||
radius: root.radius
|
||||
|
||||
Behavior on alpha {
|
||||
Anim {
|
||||
duration: Config.anim.durations.small
|
||||
}
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
id: ripple
|
||||
|
||||
radius: 1000
|
||||
color: root.color
|
||||
opacity: 0
|
||||
|
||||
transform: Translate {
|
||||
x: -ripple.width / 2
|
||||
y: -ripple.height / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue