more hacking friendly widgets

This commit is contained in:
end-4
2025-05-26 11:40:13 +02:00
parent 6c1b27bac9
commit a2ab9d2877
9 changed files with 100 additions and 101 deletions
@@ -8,6 +8,9 @@ import QtQuick.Layouts
import Quickshell.Io import Quickshell.Io
import Quickshell.Widgets import Quickshell.Widgets
/**
* A button with ripple effect similar to in Material Design.
*/
Button { Button {
id: root id: root
property bool toggled property bool toggled
@@ -19,12 +22,12 @@ Button {
property bool rippleEnabled: true property bool rippleEnabled: true
property var altAction property var altAction
property color colBackground: ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1) property color colBackground: ColorUtils.transparentize(Appearance?.colors.colLayer1Hover, 1) || "#00000000"
property color colBackgroundHover: Appearance.colors.colLayer1Hover property color colBackgroundHover: Appearance?.colors.colLayer1Hover ?? "#E5DFED"
property color colBackgroundToggled: Appearance.m3colors.m3primary property color colBackgroundToggled: Appearance?.m3colors.m3primary ?? "#65558F"
property color colBackgroundToggledHover: Appearance.colors.colPrimaryHover property color colBackgroundToggledHover: Appearance?.colors.colPrimaryHover ?? "#77699C"
property color colRipple: Appearance.colors.colLayer1Active property color colRipple: Appearance?.colors.colLayer1Active ?? "#D6CEE2"
property color colRippleToggled: Appearance.colors.colPrimaryActive property color colRippleToggled: Appearance?.colors.colPrimaryActive ?? "#D6CEE2"
property color buttonColor: root.enabled ? (root.toggled ? property color buttonColor: root.enabled ? (root.toggled ?
(root.hovered ? colBackgroundToggledHover : (root.hovered ? colBackgroundToggledHover :
@@ -48,8 +51,8 @@ Button {
component RippleAnim: NumberAnimation { component RippleAnim: NumberAnimation {
duration: rippleDuration duration: rippleDuration
easing.type: Appearance.animation.elementMoveEnter.type easing.type: Appearance?.animation.elementMoveEnter.type
easing.bezierCurve: Appearance.animationCurves.standardDecel easing.bezierCurve: Appearance?.animationCurves.standardDecel
} }
MouseArea { MouseArea {
@@ -125,7 +128,7 @@ Button {
color: root.buttonColor color: root.buttonColor
Behavior on color { Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) animation: Appearance?.animation.elementMoveFast.colorAnimation.createObject(this)
} }
layer.enabled: true layer.enabled: true
@@ -140,11 +143,11 @@ Button {
Rectangle { Rectangle {
id: ripple id: ripple
radius: Appearance.rounding.full radius: Appearance?.rounding.full ?? 9999
opacity: 0 opacity: 0
color: root.rippleColor color: root.rippleColor
Behavior on color { Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) animation: Appearance?.animation.elementMoveFast.colorAnimation.createObject(this)
} }
transform: Translate { transform: Translate {
@@ -58,11 +58,7 @@ Item {
} }
Behavior on size { Behavior on size {
NumberAnimation { animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
duration: root.animationDuration
easing.type: Easing.OutCubic
}
} }
} }
@@ -9,7 +9,7 @@ import Quickshell.Io
import Quickshell.Widgets import Quickshell.Widgets
TabButton { TabButton {
id: button id: root
property string buttonText property string buttonText
property string buttonIcon property string buttonIcon
property bool selected: false property bool selected: false
@@ -17,6 +17,10 @@ TabButton {
height: buttonBackground.height height: buttonBackground.height
property int tabContentWidth: buttonBackground.width - buttonBackground.radius*2 property int tabContentWidth: buttonBackground.width - buttonBackground.radius*2
property color colBackground: ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1)
property color colBackgroundHover: Appearance.colors.colLayer1Hover
property color colRipple: Appearance.colors.colLayer1Active
PointingHandInteraction {} PointingHandInteraction {}
component RippleAnim: NumberAnimation { component RippleAnim: NumberAnimation {
@@ -42,7 +46,7 @@ TabButton {
rippleAnim.restart(); rippleAnim.restart();
} }
onReleased: (event) => { onReleased: (event) => {
button.click() // Because the MouseArea already consumed the event root.click() // Because the MouseArea already consumed the event
rippleFadeAnim.restart(); rippleFadeAnim.restart();
} }
} }
@@ -88,9 +92,9 @@ TabButton {
background: Rectangle { background: Rectangle {
id: buttonBackground id: buttonBackground
radius: Appearance.rounding.small radius: Appearance?.rounding.small ?? 7
implicitHeight: 37 implicitHeight: 37
color: (button.hovered ? Appearance.colors.colLayer1Hover : ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1)) color: (root.hovered ? root.colBackgroundHover : root.colBackground)
layer.enabled: true layer.enabled: true
layer.effect: OpacityMask { layer.effect: OpacityMask {
maskSource: Rectangle { maskSource: Rectangle {
@@ -108,7 +112,7 @@ TabButton {
id: ripple id: ripple
radius: Appearance.rounding.full radius: Appearance.rounding.full
color: Appearance.colors.colLayer1Active color: root.colRipple
opacity: 0 opacity: 0
transform: Translate { transform: Translate {
@@ -9,7 +9,10 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Hyprland import Quickshell.Hyprland
ListView { // Scrollable window /**
* A ListView with animations.
*/
ListView {
id: root id: root
spacing: 5 spacing: 5
property real removeOvershoot: 20 // Account for gaps and bouncy animations property real removeOvershoot: 20 // Account for gaps and bouncy animations
@@ -23,7 +26,7 @@ ListView { // Scrollable window
add: Transition { add: Transition {
animations: [ animations: [
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
properties: "opacity,scale", properties: "opacity,scale",
from: 0, from: 0,
to: 1, to: 1,
@@ -33,10 +36,10 @@ ListView { // Scrollable window
addDisplaced: Transition { addDisplaced: Transition {
animations: [ animations: [
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "y", property: "y",
}), }),
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
properties: "opacity,scale", properties: "opacity,scale",
to: 1, to: 1,
}), }),
@@ -45,10 +48,10 @@ ListView { // Scrollable window
displaced: Transition { displaced: Transition {
animations: [ animations: [
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "y", property: "y",
}), }),
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
properties: "opacity,scale", properties: "opacity,scale",
to: 1, to: 1,
}), }),
@@ -57,10 +60,10 @@ ListView { // Scrollable window
move: Transition { move: Transition {
animations: [ animations: [
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "y", property: "y",
}), }),
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
properties: "opacity,scale", properties: "opacity,scale",
to: 1, to: 1,
}), }),
@@ -68,10 +71,10 @@ ListView { // Scrollable window
} }
moveDisplaced: Transition { moveDisplaced: Transition {
animations: [ animations: [
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "y", property: "y",
}), }),
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
properties: "opacity,scale", properties: "opacity,scale",
to: 1, to: 1,
}), }),
@@ -80,11 +83,11 @@ ListView { // Scrollable window
remove: Transition { remove: Transition {
animations: [ animations: [
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "x", property: "x",
to: root.width + root.removeOvershoot, to: root.width + root.removeOvershoot,
}), }),
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "opacity", property: "opacity",
to: 0, to: 0,
}) })
@@ -94,10 +97,10 @@ ListView { // Scrollable window
// This is movement when something is removed, not removing animation! // This is movement when something is removed, not removing animation!
removeDisplaced: Transition { removeDisplaced: Transition {
animations: [ animations: [
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
property: "y", property: "y",
}), }),
Appearance.animation.elementMove.numberAnimation.createObject(this, { Appearance?.animation.elementMove.numberAnimation.createObject(this, {
properties: "opacity,scale", properties: "opacity,scale",
to: 1, to: 1,
}), }),
@@ -8,22 +8,25 @@ import Quickshell
import Quickshell.Widgets import Quickshell.Widgets
import Qt5Compat.GraphicalEffects import Qt5Compat.GraphicalEffects
/**
* Material 3 progress bar. See https://m3.material.io/components/progress-indicators/overview
*/
ProgressBar { ProgressBar {
id: root id: root
property real valueBarWidth: 120 property real valueBarWidth: 120
property real valueBarHeight: 4 property real valueBarHeight: 4
property real valueBarGap: 4 property real valueBarGap: 4
property color highlightColor: Appearance.m3colors.m3primary property color highlightColor: Appearance?.m3colors.m3primary ?? "#685496"
property color trackColor: Appearance.m3colors.m3secondaryContainer property color trackColor: Appearance?.m3colors.m3secondaryContainer ?? "#F1D3F9"
Behavior on value { Behavior on value {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) animation: Appearance?.animation.elementMoveEnter.numberAnimation.createObject(this)
} }
background: Rectangle { background: Rectangle {
anchors.fill: parent anchors.fill: parent
color: "transparent" color: "transparent"
radius: Appearance.rounding.full radius: Appearance?.rounding.full ?? 9999
implicitHeight: valueBarHeight implicitHeight: valueBarHeight
implicitWidth: valueBarWidth implicitWidth: valueBarWidth
} }
@@ -35,21 +38,21 @@ ProgressBar {
Rectangle { // Left progress fill Rectangle { // Left progress fill
width: root.visualPosition * parent.width width: root.visualPosition * parent.width
height: parent.height height: parent.height
radius: Appearance.rounding.full radius: Appearance?.rounding.full ?? 9999
color: root.highlightColor color: root.highlightColor
} }
Rectangle { // Right remaining part fill Rectangle { // Right remaining part fill
anchors.right: parent.right anchors.right: parent.right
width: (1 - root.visualPosition) * parent.width - valueBarGap width: (1 - root.visualPosition) * parent.width - valueBarGap
height: parent.height height: parent.height
radius: Appearance.rounding.full radius: Appearance?.rounding.full ?? 9999
color: root.trackColor color: root.trackColor
} }
Rectangle { // Stop point Rectangle { // Stop point
anchors.right: parent.right anchors.right: parent.right
width: valueBarGap width: valueBarGap
height: valueBarGap height: valueBarGap
radius: Appearance.rounding.full radius: Appearance?.rounding.full ?? 9999
color: root.highlightColor color: root.highlightColor
} }
} }
@@ -8,22 +8,23 @@ import Quickshell.Widgets
// Material 3 slider. See https://m3.material.io/components/sliders/overview // Material 3 slider. See https://m3.material.io/components/sliders/overview
Slider { Slider {
id: slider id: root
property real scale: 0.85 property real scale: 0.85
property real backgroundDotSize: 4 * scale property real backgroundDotSize: 4 * scale
property real backgroundDotMargins: 4 * scale property real backgroundDotMargins: 4 * scale
// property real handleMargins: 0 * scale // property real handleMargins: 0 * scale
property real handleMargins: (slider.pressed ? 0 : 2) * scale property real handleMargins: (root.pressed ? 0 : 2) * scale
property real handleWidth: (slider.pressed ? 3 : 5) * scale property real handleWidth: (root.pressed ? 3 : 5) * scale
property real handleHeight: 44 * scale property real handleHeight: 44 * scale
property real handleLimit: slider.backgroundDotMargins property real handleLimit: root.backgroundDotMargins
property real trackHeight: 30 * scale property real trackHeight: 30 * scale
property color highlightColor: Appearance.m3colors.m3primary property color highlightColor: Appearance.m3colors.m3primary
property color trackColor: Appearance.m3colors.m3secondaryContainer property color trackColor: Appearance.m3colors.m3secondaryContainer
property color handleColor: Appearance.m3colors.m3onSecondaryContainer property color handleColor: Appearance.m3colors.m3onSecondaryContainer
property real trackRadius: Appearance.rounding.verysmall * scale property real trackRadius: Appearance.rounding.verysmall * scale
property real unsharpenRadius: Appearance.rounding.unsharpen
property real limitedHandleRangeWidth: (slider.availableWidth - handleWidth - slider.handleLimit * 2) property real limitedHandleRangeWidth: (root.availableWidth - handleWidth - root.handleLimit * 2)
property string tooltipContent: `${Math.round(value * 100)}%` property string tooltipContent: `${Math.round(value * 100)}%`
Layout.fillWidth: true Layout.fillWidth: true
from: 0 from: 0
@@ -46,7 +47,7 @@ Slider {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onPressed: (mouse) => mouse.accepted = false onPressed: (mouse) => mouse.accepted = false
cursorShape: slider.pressed ? Qt.ClosedHandCursor : Qt.PointingHandCursor cursorShape: root.pressed ? Qt.ClosedHandCursor : Qt.PointingHandCursor
} }
background: Item { background: Item {
@@ -57,60 +58,56 @@ Slider {
Rectangle { Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
width: slider.handleLimit * 2 + slider.visualPosition * slider.limitedHandleRangeWidth - (slider.handleMargins + slider.handleWidth / 2) width: root.handleLimit * 2 + root.visualPosition * root.limitedHandleRangeWidth - (root.handleMargins + root.handleWidth / 2)
height: trackHeight height: trackHeight
color: slider.highlightColor color: root.highlightColor
topLeftRadius: slider.trackRadius topLeftRadius: root.trackRadius
bottomLeftRadius: slider.trackRadius bottomLeftRadius: root.trackRadius
topRightRadius: Appearance.rounding.unsharpen topRightRadius: root.unsharpenRadius
bottomRightRadius: Appearance.rounding.unsharpen bottomRightRadius: root.unsharpenRadius
} }
// Fill right // Fill right
Rectangle { Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right
width: slider.handleLimit * 2 + (1 - slider.visualPosition) * slider.limitedHandleRangeWidth - (slider.handleMargins + slider.handleWidth / 2) width: root.handleLimit * 2 + (1 - root.visualPosition) * root.limitedHandleRangeWidth - (root.handleMargins + root.handleWidth / 2)
height: trackHeight height: trackHeight
color: slider.trackColor color: root.trackColor
topLeftRadius: Appearance.rounding.unsharpen topLeftRadius: root.unsharpenRadius
bottomLeftRadius: Appearance.rounding.unsharpen bottomLeftRadius: root.unsharpenRadius
topRightRadius: slider.trackRadius topRightRadius: root.trackRadius
bottomRightRadius: slider.trackRadius bottomRightRadius: root.trackRadius
} }
// Dot at the end // Dot at the end
Rectangle { Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: slider.backgroundDotMargins anchors.rightMargin: root.backgroundDotMargins
width: slider.backgroundDotSize width: root.backgroundDotSize
height: slider.backgroundDotSize height: root.backgroundDotSize
radius: Appearance.rounding.full radius: Appearance.rounding.full
color: slider.handleColor color: root.handleColor
} }
} }
handle: Rectangle { handle: Rectangle {
id: handle id: handle
x: slider.leftPadding + slider.handleLimit + slider.visualPosition * slider.limitedHandleRangeWidth x: root.leftPadding + root.handleLimit + root.visualPosition * root.limitedHandleRangeWidth
y: slider.topPadding + slider.availableHeight / 2 - height / 2 y: root.topPadding + root.availableHeight / 2 - height / 2
implicitWidth: slider.handleWidth implicitWidth: root.handleWidth
implicitHeight: slider.handleHeight implicitHeight: root.handleHeight
radius: Appearance.rounding.full radius: Appearance.rounding.full
color: slider.handleColor color: root.handleColor
Behavior on implicitWidth { Behavior on implicitWidth {
NumberAnimation { animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
duration: Appearance.animation.elementMoveFast.duration
easing.type: Appearance.animation.elementMoveFast.type
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
}
} }
StyledToolTip { StyledToolTip {
extraVisibleCondition: slider.pressed extraVisibleCondition: root.pressed
content: slider.tooltipContent content: root.tooltipContent
} }
} }
} }
@@ -4,11 +4,16 @@ import QtQuick.Layouts
import QtQuick.Controls import QtQuick.Controls
import Qt5Compat.GraphicalEffects import Qt5Compat.GraphicalEffects
/**
* Material 3 switch. See https://m3.material.io/components/switch/overview
*/
Switch { Switch {
id: root id: root
property real scale: 1 property real scale: 1
implicitHeight: 32 * root.scale implicitHeight: 32 * root.scale
implicitWidth: 52 * root.scale implicitWidth: 52 * root.scale
property color activeColor: Appearance?.m3colors.m3primary ?? "#685496"
property color inactiveColor: Appearance?.m3colors.m3surfaceContainerHighest ?? "#45464F"
PointingHandInteraction {} PointingHandInteraction {}
@@ -16,10 +21,10 @@ Switch {
background: Rectangle { background: Rectangle {
width: parent.width width: parent.width
height: parent.height height: parent.height
radius: Appearance.rounding.full radius: Appearance?.rounding.full ?? 9999
color: root.checked ? Appearance.m3colors.m3primary : Appearance.m3colors.m3surfaceContainerHighest color: root.checked ? root.activeColor : root.inactiveColor
border.width: 2 * root.scale border.width: 2 * root.scale
border.color: root.checked ? Appearance.m3colors.m3primary : Appearance.m3colors.m3outline border.color: root.checked ? root.activeColor : Appearance.m3colors.m3outline
Behavior on color { Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this) animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
@@ -6,7 +6,7 @@ Text {
renderType: Text.NativeRendering renderType: Text.NativeRendering
font.hintingPreference: Font.PreferFullHinting font.hintingPreference: Font.PreferFullHinting
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
font.family: Appearance.font.family.main font.family: Appearance?.font.family.main ?? "sans-serif"
font.pixelSize: Appearance.font.pixelSize.small font.pixelSize: Appearance?.font.pixelSize.small ?? 15
color: Appearance.m3colors.m3onBackground color: Appearance?.m3colors.m3onBackground ?? "black"
} }
@@ -19,11 +19,7 @@ ToolTip {
visible: opacity > 0 visible: opacity > 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
duration: Appearance.animation.elementMoveFast.duration
easing.type: Appearance.animation.elementMoveFast.type
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
}
} }
background: null background: null
@@ -37,34 +33,26 @@ ToolTip {
id: backgroundRectangle id: backgroundRectangle
anchors.bottom: contentItemBackground.bottom anchors.bottom: contentItemBackground.bottom
anchors.horizontalCenter: contentItemBackground.horizontalCenter anchors.horizontalCenter: contentItemBackground.horizontalCenter
color: Appearance.colors.colTooltip color: Appearance?.colors.colTooltip ?? "#3C4043"
radius: Appearance.rounding.verysmall radius: Appearance?.rounding.verysmall ?? 7
width: internalVisibleCondition ? (tooltipTextObject.width + 2 * padding) : 0 width: internalVisibleCondition ? (tooltipTextObject.width + 2 * padding) : 0
height: internalVisibleCondition ? (tooltipTextObject.height + 2 * padding) : 0 height: internalVisibleCondition ? (tooltipTextObject.height + 2 * padding) : 0
clip: true clip: true
Behavior on width { Behavior on width {
NumberAnimation { animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
duration: Appearance.animation.elementMoveFast.duration
easing.type: Appearance.animation.elementMoveFast.type
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
}
} }
Behavior on height { Behavior on height {
NumberAnimation { animation: Appearance?.animation.elementMoveFast.numberAnimation.createObject(this)
duration: Appearance.animation.elementMoveFast.duration
easing.type: Appearance.animation.elementMoveFast.type
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
}
} }
StyledText { StyledText {
id: tooltipTextObject id: tooltipTextObject
anchors.centerIn: parent anchors.centerIn: parent
text: content text: content
font.pixelSize: Appearance.font.pixelSize.smaller font.pixelSize: Appearance?.font.pixelSize.smaller ?? 14
font.hintingPreference: Font.PreferNoHinting // Prevent shaky text font.hintingPreference: Font.PreferNoHinting // Prevent shaky text
color: Appearance.colors.colOnTooltip color: Appearance?.colors.colOnTooltip ?? "#FFFFFF"
wrapMode: Text.Wrap wrapMode: Text.Wrap
} }
} }