Watch
1
0
Fork
You've already forked souveraine
0

publish: the public projection begins here

This is a projection, not a development branch. The tree above was constructed
from the internal source named below under a manifest that decides which paths
may leave, then scanned as a whole tree rather than as a series of patches, and
only then published.

Public history starts here because the history before it was not admissible,
and neither was the tree. What used to stand in this repository included a
rescue copy of another machine, a directory of phone handoffs, deployment
wired to one house, and a submodule pointing at a forge no stranger can reach.
None of that was ever the product. It stays in the private forge, which is
allowed to hold the whole working organism, and this is what was deliberately
sent out instead.

Three mechanisms produced this tree, in decreasing order of trust. A top-level
path the manifest does not name never arrives at all, which is the one that
catches directories nobody has thought of yet. Named internal files inside
admitted roots are dropped. A short, reviewed table replaces deployment
defaults that a public build must not carry -- an endpoint aimed at one LAN, a
VPN profile belonging to one phone, packaging built from one checkout path.

Everything after this commit is an ordinary publication with the same three
trailers, so a force push stops being routine and starts meaning that
something deliberate happened. The trailers bind the projection to its source
without pretending the public SHA is the private one: same lineage, different
tree, and the record says so.

Source-Sha: 8f27b1e76a8fef560a336aba18e6990713ff1047
Policy-Sha: 6b261d2f3e6e1fb19874846ba4bb1dfe15565d25b8618c1c1afba0419c101d27
Tree-Digest: 18ec3563c5e5ef9a414993a9f6734b251ff9ed3cd56eebdd6cac01e45c6e3067
This commit is contained in:
Fimeg 2026-09-04 15:55:48 -04:00
commit 8f42fc953d
1476 changed files with 238455 additions and 0 deletions

View file

@ -0,0 +1,42 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
WButton {
id: root
colBackground: Looks.colors.bg1
colBackgroundHover: Looks.colors.bg1Hover
colBackgroundActive: Looks.colors.bg1Active
property color colBackgroundBorder
property color color
property alias border: background.border
property alias shinyColor: background.borderColor
colBackgroundBorder: ColorUtils.transparentize(color, (root.checked || root.hovered) ? Looks.backgroundTransparency : 0)
color: {
if (root.down) {
return root.colBackgroundActive
} else if ((root.hovered && !root.down) || root.checked) {
return root.colBackgroundHover
} else {
return root.colBackground
}
}
background: AcrylicRectangle {
id: background
shiny: ((root.hovered && !root.down) || root.checked)
color: root.color
radius: Looks.radius.medium
border.width: 1
border.color: root.colBackgroundBorder
Behavior on border.color {
animation: Looks.transition.color.createObject(this)
}
}
}

View file

@ -0,0 +1,66 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Rectangle {
id: root
property bool shiny: true // Top border
property color borderColor: ColorUtils.transparentize(Looks.colors.bg1Hover, 0.7)
property color internalBorderColor: ColorUtils.transparentize(borderColor, shiny ? 0.0 : 1)
color: Looks.colors.bg1Hover
radius: Looks.radius.medium
Behavior on color {
animation: Looks.transition.color.createObject(this)
}
Behavior on internalBorderColor {
animation: Looks.transition.color.createObject(this)
}
onInternalBorderColorChanged: {
borderCanvas.requestPaint();
}
// 1px border at the top or bottom
Canvas {
id: borderCanvas
anchors.fill: parent
// For dark mode we have a shiny top border, and for light mode we have sort of a shadow
rotation: Looks.dark ? 0 : 180
onPaint: {
var ctx = getContext("2d");
ctx.clearRect(0, 0, width, height);
var borderColor = root.internalBorderColor;
var r = root.radius;
var fadeLength = Math.max(1, r);
var fadeLengthPercent = fadeLength / width;
// Compute normalized stops
var leftFadeStop = fadeLengthPercent;
var rightFadeStop = 1 - fadeLengthPercent;
var grad = ctx.createLinearGradient(0, 0, width, 0);
grad.addColorStop(0, Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0));
grad.addColorStop(leftFadeStop, borderColor);
grad.addColorStop(rightFadeStop, borderColor);
grad.addColorStop(1, Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0));
ctx.strokeStyle = grad;
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(r, 0.5);
ctx.lineTo(width - r, 0.5);
// Top-right curve
ctx.arcTo(width, 0.5, width, r + 0.5, r);
// Top-left curve
ctx.moveTo(width - r, 0.5);
ctx.arcTo(0, 0.5, 0, r + 0.5, r);
ctx.stroke();
}
}
}

View file

@ -0,0 +1,14 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Rectangle {
Layout.fillHeight: true
Layout.fillWidth: true
color: Looks.colors.bgPanelBody
}

View file

@ -0,0 +1,48 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
import qs.modules.waffle.bar
import Quickshell
Button {
id: reusableCloseButton
implicitHeight: 30
implicitWidth: 30
property alias radius: closeButtonBg.radius
Rectangle {
z: 0
color: "transparent"
anchors.fill: closeButtonBg
anchors.margins: -1
opacity: closeButtonBg.opacity
border.width: 1
radius: closeButtonBg.radius + 1
border.color: Looks.colors.bg2Border
}
background: Rectangle {
id: closeButtonBg
z: 1
opacity: reusableCloseButton.hovered ? 1 : 0
color: reusableCloseButton.pressed ? Looks.colors.dangerActive : Looks.colors.danger
Behavior on opacity {
animation: Looks.transition.opacity.createObject(this)
}
Behavior on color {
animation: Looks.transition.color.createObject(this)
}
}
contentItem: FluentIcon {
z: 2
anchors.centerIn: parent
icon: "dismiss"
implicitSize: 10
}
}

View file

@ -0,0 +1,23 @@
import QtQuick
import org.kde.kirigami as Kirigami
import qs.modules.common
import qs.modules.waffle.looks
Kirigami.Icon {
id: root
required property string icon
property bool filled: false
property alias monochrome: root.isMask
// Should be 16, but it appears the icons have some padding,
// Unlike the Windows-only Segoe UI icons, the open source FluentUI ones are hella small
property int implicitSize: 20
implicitWidth: implicitSize
implicitHeight: implicitSize
source: icon === "" ? "" : `${Looks.iconsPath}/${root.icon}${filled ? "-filled" : ""}.svg`
fallback: root.icon
roundToIconSize: false
color: Looks.colors.fg
isMask: true
animated: true
}

View file

@ -0,0 +1,17 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Rectangle {
Layout.fillHeight: false
Layout.fillWidth: true
color: "transparent"
implicitWidth: 358
implicitHeight: 47
}

View file

@ -0,0 +1,266 @@
pragma ComponentBehavior: Bound
pragma Singleton
import QtQuick
import Quickshell
import qs.modules.common
import qs.modules.common.functions
Singleton {
id: root
property QtObject darkColors
property QtObject lightColors
property QtObject colors
property QtObject radius
property QtObject font
property QtObject transition
property string iconsPath: `${Directories.assetsPath}/icons/fluent`
property bool dark: Appearance.m3colors.darkmode
readonly property bool transparencyEnabled: Config.options.appearance.transparency.enable
property real backgroundTransparency: transparencyEnabled ? 0.16 : 0
property real panelBackgroundTransparency: transparencyEnabled ? 0.14 : 0
property real panelLayerTransparency: root.dark ? 0.9 : 0.7
property real contentTransparency: root.dark ? 0.87 : 0.5
function applyBackgroundTransparency(col) {
return ColorUtils.applyAlpha(col, 1 - root.backgroundTransparency)
}
function applyContentTransparency(col) {
return ColorUtils.applyAlpha(col, 1 - root.contentTransparency)
}
lightColors: QtObject {
id: lightColors
property color bgPanelBody: "#F2F2F2"
property color bgPanelSeparator: "#E0E0E0"
property color bg0: "#EEEEEE"
property color bg0Border: '#BEBEBE'
property color bg1Base: "#F7F7F7"
property color bg1: "#F7F7F7"
property color bg1Hover: "#F7F7F7"
property color bg1Active: '#EFEFEF'
property color bg1Border: '#E9E9E9'
property color bg2: "#FBFBFB"
property color bg2Base: "#FBFBFB"
property color bg2Hover: '#ffffff'
property color bg2Active: '#eeeeee'
property color bg2Border: '#E0E0E0'
property color subfg: "#5C5C5C"
property color fg: "#000000"
property color fg1: "#626262"
property color inactiveIcon: "#C4C4C4"
property color controlBgInactive: '#555458'
property color controlBg: '#807F85'
property color controlBgHover: '#57575B'
property color controlFg: "#FFFFFF"
property color accentUnfocused: "#848484"
property color link: "#235CCF"
property color inputBg: ColorUtils.transparentize(bg0, 0.4)
}
darkColors: QtObject {
id: darkColors
property color bgPanelBody: '#242424'
property color bgPanelSeparator: "#191919"
property color bg0: "#1C1C1C"
property color bg0Border: "#404040"
property color bg1Base: '#2C2C2C'
property color bg1: '#2C2C2C'
property color bg1Hover: "#292929"
property color bg1Active: '#252525'
property color bg1Border: '#bebebe'
property color bg2Base: "#313131"
property color bg2: '#313131'
property color bg2Hover: '#363636'
property color bg2Active: '#2B2B2B'
property color bg2Border: '#404040'
property color subfg: "#CED1D7"
property color fg: "#FFFFFF"
property color fg1: "#D1D1D1"
property color inactiveIcon: "#494949"
property color controlBgInactive: "#CDCECF"
property color controlBg: "#9B9B9B"
property color controlBgHover: "#CFCED1"
property color controlFg: "#454545"
property color accentUnfocused: "#989898"
property color link: "#A7C9FC"
property color inputBg: ColorUtils.transparentize(darkColors.bg0, 0.5)
}
colors: QtObject {
id: colors
// Special
property color shadow: ColorUtils.transparentize('#161616', 0.62)
property color ambientShadow: ColorUtils.transparentize("#000000", 0.75)
property color bgPanelFooterBase: root.dark ? root.darkColors.bg0 : root.lightColors.bg0
property color bgPanelFooterBackground: ColorUtils.transparentize(root.dark ? root.darkColors.bg0 : root.lightColors.bg0, root.panelBackgroundTransparency)
property color bgPanelFooter: ColorUtils.transparentize(bgPanelFooterBackground, root.panelLayerTransparency)
property color bgPanelBodyBase: root.dark ? root.darkColors.bgPanelBody : root.lightColors.bgPanelBody
property color bgPanelBody: ColorUtils.solveOverlayColor(bgPanelFooterBackground,bgPanelBodyBase, 1 - root.panelLayerTransparency)
property color bgPanelSeparator: ColorUtils.solveOverlayColor(bgPanelBodyBase, root.dark ? root.darkColors.bgPanelSeparator : root.lightColors.bgPanelSeparator, 1 - root.panelBackgroundTransparency)
// Layer 0
property color bg0Base: root.dark ? root.darkColors.bg0 : root.lightColors.bg0
property color bg0: ColorUtils.transparentize(bg0Base, root.backgroundTransparency)
property color bg0Border: ColorUtils.transparentize(root.dark ? root.darkColors.bg0Border : root.lightColors.bg0Border, root.backgroundTransparency)
// Layer 1
property color bg1Base: root.dark ? root.darkColors.bg1 : root.lightColors.bg1
property color bg1: ColorUtils.solveOverlayColor(bg0Base, bg1Base, 1 - root.contentTransparency)
property color bg1Hover: ColorUtils.solveOverlayColor(bg0Base, root.dark ? root.darkColors.bg1Hover : root.lightColors.bg1Hover, 1 - root.contentTransparency)
property color bg1Active: ColorUtils.solveOverlayColor(bg0Base, root.dark ? root.darkColors.bg1Active : root.lightColors.bg1Active, 1 - root.contentTransparency)
property color bg1Border: ColorUtils.solveOverlayColor(bg0Base, root.dark ? root.darkColors.bg1Border : root.lightColors.bg1Border, 1 - root.contentTransparency)
// Layer 2
property color bg2Base: root.dark ? root.darkColors.bg2 : root.lightColors.bg2
property color bg2: ColorUtils.solveOverlayColor(bgPanelBodyBase, bg2Base, 1 - root.contentTransparency)
property color bg2Hover: ColorUtils.solveOverlayColor(bgPanelBodyBase, root.dark ? root.darkColors.bg2Hover : root.lightColors.bg2Hover, 1 - root.contentTransparency)
property color bg2Active: ColorUtils.solveOverlayColor(bgPanelBodyBase, root.dark ? root.darkColors.bg2Active : root.lightColors.bg2Active, 1 - root.contentTransparency)
property color bg2Border: ColorUtils.solveOverlayColor(bgPanelBodyBase, root.dark ? root.darkColors.bg2Border : root.lightColors.bg2Border, 1 - root.contentTransparency)
// Foreground / Text
property color subfg: root.dark ? root.darkColors.subfg : root.lightColors.subfg
property color fg: root.dark ? root.darkColors.fg : root.lightColors.fg
property color fg1: root.dark ? root.darkColors.fg1 : root.lightColors.fg1
property color inactiveIcon: root.dark ? root.darkColors.inactiveIcon : root.lightColors.inactiveIcon
property color link: root.dark ? root.darkColors.link : root.lightColors.link
// Controls
property color controlBgInactive: root.dark ? root.darkColors.controlBgInactive : root.lightColors.controlBgInactive
property color controlBg: root.dark ? root.darkColors.controlBg : root.lightColors.controlBg
property color controlBgHover: root.dark ? root.darkColors.controlBgHover : root.lightColors.controlBgHover
property color controlFg: root.dark ? root.darkColors.controlFg : root.lightColors.controlFg
property color inputBg: root.dark ? root.darkColors.inputBg : root.lightColors.inputBg
property color danger: "#C42B1C"
property color dangerActive: "#B62D1F"
property color warning: "#FF9900"
// Accent
property color accent: Appearance.colors.colPrimary
property color accentHover: Appearance.colors.colPrimaryHover
property color accentActive: Appearance.colors.colPrimaryActive
property color accentUnfocused: root.dark ? root.darkColors.accentUnfocused : root.lightColors.accentUnfocused
property color accentFg: ColorUtils.isDark(accent) ? "#FFFFFF" : "#000000"
property color selection: Appearance.colors.colPrimaryContainer
property color selectionFg: Appearance.colors.colOnPrimaryContainer
}
radius: QtObject {
id: radius
property int none: 0
property int small: 2
property int medium: 4
property int large: 8
property int xLarge: 12
}
font: QtObject {
id: font
property QtObject family: QtObject {
property string ui: "Noto Sans"
}
property QtObject weight: QtObject { // Noto is not Segoe, so we might use slightly different weights
property int thin: Font.Normal
property int regular: Font.Medium
property int strong: Font.DemiBold
property int stronger: (Font.DemiBold + 2*Font.Bold) / 3
property int strongest: Font.Bold
}
property QtObject pixelSize: QtObject {
property real normal: 11
property real large: 13
property real larger: 15
property real xlarger: 17
}
property QtObject variableAxes: QtObject {
property var ui: ({
"wdth": 25
})
}
}
transition: QtObject {
id: transition
property int velocity: 850
property QtObject easing: QtObject {
property QtObject bezierCurve: QtObject {
readonly property list<real> easeInOut: [0.42,0.00,0.58,1.00,1,1]
readonly property list<real> easeIn: [0,1,1,1,1,1]
readonly property list<real> easeOut: [1,0,1,1,1,1]
}
}
property Component color: Component {
ColorAnimation {
duration: 80
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeIn
}
}
property Component opacity: Component {
NumberAnimation {
duration: 120
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeIn
}
}
property Component resize: Component { // TODO: better curve needed
NumberAnimation {
duration: 200
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeIn
}
}
property Component enter: Component {
NumberAnimation {
duration: 250
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeIn
}
}
property Component exit: Component {
NumberAnimation {
duration: 250
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeOut
}
}
property Component move: Component {
NumberAnimation {
duration: 170
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeInOut
}
}
property Component rotate: Component {
NumberAnimation {
duration: 170
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeInOut
}
}
property Component anchor: Component {
AnchorAnimation {
duration: 160
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeIn
}
}
property Component longMovement: Component {
NumberAnimation {
duration: 1000
easing.type: Easing.BezierSpline
easing.bezierCurve: transition.easing.bezierCurve.easeIn
}
}
property Component scroll: Component {
NumberAnimation {
duration: 250
easing.type: Easing.BezierSpline
easing.bezierCurve: [0.0, 0.0, 0.25, 1.0, 1, 1]
}
}
}
}

View file

@ -0,0 +1,73 @@
pragma ComponentBehavior: Bound
import Qt.labs.synchronizer
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import qs.modules.waffle.looks
Column {
id: root
property bool showArrows: true
property int currentIndex: 0
property int count: 1
signal clicked(int index)
signal increasePage()
signal decreasePage()
visible: count > 1
spacing: 6
NavigationArrow {
visible: root.showArrows
down: false
}
Repeater {
model: root.count
delegate: MouseArea {
id: pageIndicator
required property int index
hoverEnabled: true
onClicked: root.clicked(index);
anchors.horizontalCenter: parent.horizontalCenter
implicitWidth: 6
implicitHeight: 6
Circle {
anchors.centerIn: parent
diameter: (index === root.currentIndex || pageIndicator.containsMouse) && !pageIndicator.pressed ? 6 : 4
color: pageIndicator.containsMouse ? Looks.colors.controlBgHover : Looks.colors.controlBg
}
}
}
NavigationArrow {
visible: root.showArrows
down: true
}
component NavigationArrow: FluentIcon {
id: navArrow
required property bool down
anchors.horizontalCenter: parent.horizontalCenter
implicitHeight: 12
implicitWidth: 12 - (2 * upArea.containsPress)
icon: down ? "caret-down" : "caret-up"
color: upArea.containsMouse ? Looks.colors.controlBgHover : Looks.colors.controlBg
filled: true
opacity: ((down && root.currentIndex < root.count - 1) || (!down && root.currentIndex > 0)) ? 1 : 0
MouseArea {
id: upArea
anchors.fill: parent
hoverEnabled: true
onClicked: navArrow.down ? root.increasePage() : root.decreasePage();
}
}
}

View file

@ -0,0 +1,25 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Rectangle {
id: root
required property var target
z: 0
anchors {
fill: target
margins: -border.width
}
border.color: Looks.colors.ambientShadow
border.width: 1
color: "transparent"
radius: target.radius + border.width
}

View file

@ -0,0 +1,22 @@
import QtQuick
import org.kde.kirigami as Kirigami
import qs.services
import qs.modules.common
Kirigami.Icon {
id: root
required property string iconName
property bool separateLightDark: false
property bool tryCustomIcon: true
property real implicitSize: 26
implicitWidth: implicitSize
implicitHeight: implicitSize
animated: true
roundToIconSize: false
fallback: root.iconName
source: tryCustomIcon ? `${Looks.iconsPath}/${root.iconName}${!root.separateLightDark ? "" : Looks.dark ? "-dark" : "-light"}.svg` : fallback
color: Looks.colors.fg
}

View file

@ -0,0 +1,98 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.waffle.looks
Item {
id: root
signal closed
required property Item contentItem
property real visualMargin: 12
property int closeAnimDuration: 150
property bool revealFromSides: false
property bool revealFromLeft: true
function close() {
closeAnim.start();
}
readonly property bool barAtBottom: Config.options.waffles.bar.bottom
implicitHeight: contentItem.implicitHeight + visualMargin * 2
implicitWidth: contentItem.implicitWidth + visualMargin * 2
focus: true
Keys.onPressed: event => { // Esc to close
if (event.key === Qt.Key_Escape) {
content.close();
}
}
Item {
id: panelContent
anchors {
left: (root.revealFromSides && !root.revealFromLeft) ? undefined : parent.left
right: (root.revealFromSides && root.revealFromLeft) ? undefined : parent.right
top: (!root.revealFromSides && root.barAtBottom) ? undefined : parent.top
bottom: (!root.revealFromSides && !root.barAtBottom) ? undefined : parent.bottom
// Opening anim
bottomMargin: (!root.revealFromSides && root.barAtBottom) ? sourceEdgeMargin : root.visualMargin
topMargin: (!root.revealFromSides && !root.barAtBottom) ? sourceEdgeMargin : root.visualMargin
leftMargin: (root.revealFromSides && root.revealFromLeft) ? sideEdgeMargin : root.visualMargin
rightMargin: (root.revealFromSides && !root.revealFromLeft) ? sideEdgeMargin : root.visualMargin
}
Component.onCompleted: {
openAnim.start();
}
property real sourceEdgeMargin: -(implicitHeight + root.visualMargin)
property real sideEdgeMargin: -(implicitWidth + root.visualMargin)
OpenAnim {
id: openAnim
properties: "sourceEdgeMargin, sideEdgeMargin"
}
SequentialAnimation {
id: closeAnim
ParallelAnimation {
CloseAnim {
property: "sourceEdgeMargin"
to: -(implicitHeight + root.visualMargin)
}
CloseAnim {
property: "sideEdgeMargin"
to: -(implicitWidth + root.visualMargin)
}
}
ScriptAction {
script: {
root.closed();
}
}
}
implicitWidth: root.contentItem.implicitWidth
implicitHeight: root.contentItem.implicitHeight
children: [root.contentItem]
}
component OpenAnim: PropertyAnimation {
target: panelContent
to: root.visualMargin
duration: 200
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
}
component CloseAnim: PropertyAnimation {
target: panelContent
duration: root.closeAnimDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut
}
}

View file

@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
WButton {
id: root
colBackground: Looks.colors.bg2
colBackgroundHover: Looks.colors.bg2Hover
colBackgroundActive: Looks.colors.bg2Active
property color colBorder: Looks.colors.bg2Border
property color colBorderToggled: Looks.colors.accent
border.color: checked ? colBorderToggled : colBorder
border.width: root.pressed ? 2 : 1
}

View file

@ -0,0 +1,35 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Button {
id: root
implicitHeight: 36
property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
property color colBackgroundHover: Looks.colors.bg1Hover
property color colBackgroundActive: Looks.colors.bg1Active
property color color
property color colForeground: Looks.colors.fg
color: {
if (!root.enabled) return colBackground;
if (root.down) {
return root.colBackgroundActive
} else if ((root.hovered && !root.down) || root.checked) {
return root.colBackgroundHover
} else {
return root.colBackground
}
}
property alias radius: background.radius
background: Rectangle {
id: background
radius: Looks.radius.medium
color: root.color
}
}

View file

@ -0,0 +1,158 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
// Generic button with background
Button {
id: root
property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
property color colBackgroundHover: Looks.colors.bg2Hover
property color colBackgroundActive: Looks.colors.bg2Active
property color colBackgroundToggled: Looks.colors.accent
property color colBackgroundToggledHover: Looks.colors.accentHover
property color colBackgroundToggledActive: Looks.colors.accentActive
property color colForeground: Looks.colors.fg
property color colForegroundToggled: Looks.colors.accentFg
property color colForegroundDisabled: ColorUtils.transparentize(Looks.colors.subfg, 0.4)
property alias backgroundOpacity: backgroundRect.opacity
property color color: {
if (!root.enabled) return colBackground;
if (root.checked) {
if (root.down) {
return root.colBackgroundToggledActive;
} else if (root.hovered) {
return root.colBackgroundToggledHover;
} else {
return root.colBackgroundToggled;
}
}
if (root.down) {
return root.colBackgroundActive;
} else if (root.hovered) {
return root.colBackgroundHover;
} else {
return root.colBackground;
}
}
property color fgColor: {
if (!root.enabled) return root.colForegroundDisabled
if (root.checked) return root.colForegroundToggled
if (root.enabled) return root.colForeground
return root.colForeground
}
property alias horizontalAlignment: buttonText.horizontalAlignment
font {
family: Looks.font.family.ui
pixelSize: Looks.font.pixelSize.large
weight: Looks.font.weight.regular
}
// Hover stuff
signal hoverTimedOut
property bool shouldShowTooltip: false
ToolTip.delay: 400
property Timer hoverTimer: Timer {
id: hoverTimer
running: root.hovered
interval: root.ToolTip.delay
onTriggered: {
root.hoverTimedOut();
}
}
onHoverTimedOut: {
root.shouldShowTooltip = true;
}
onHoveredChanged: {
if (!root.hovered) {
root.shouldShowTooltip = false;
root.hoverTimer.stop();
}
}
property alias monochromeIcon: buttonIcon.monochrome
property alias buttonSpacing: contentLayout.spacing
property bool forceShowIcon: false
property var altAction: () => {}
property var middleClickAction: () => {}
property real inset: 0
topInset: inset
bottomInset: inset
leftInset: inset
rightInset: inset
property alias radius: backgroundRect.radius
property alias topLeftRadius: backgroundRect.topLeftRadius
property alias topRightRadius: backgroundRect.topRightRadius
property alias bottomLeftRadius: backgroundRect.bottomLeftRadius
property alias bottomRightRadius: backgroundRect.bottomRightRadius
property alias border: backgroundRect.border
horizontalPadding: 10
verticalPadding: 6
implicitHeight: contentItem.implicitHeight + verticalPadding * 2 + topInset + bottomInset
implicitWidth: contentItem.implicitWidth + horizontalPadding * 2 + leftInset + rightInset
background: Rectangle {
id: backgroundRect
radius: Looks.radius.medium
color: root.color
Behavior on color {
animation: Looks.transition.color.createObject(this)
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton | Qt.MiddleButton
onClicked: event => {
if (event.button === Qt.LeftButton)
root.clicked();
if (event.button === Qt.RightButton)
root.altAction();
if (event.button === Qt.MiddleButton)
root.middleClickAction();
}
}
contentItem: Item {
anchors {
fill: parent
margins: root.inset
}
implicitWidth: contentLayout.implicitWidth
implicitHeight: contentLayout.implicitHeight
RowLayout {
id: contentLayout
anchors {
fill: parent
leftMargin: root.horizontalPadding
rightMargin: root.horizontalPadding
}
spacing: 12
FluentIcon {
id: buttonIcon
monochrome: true
implicitSize: 18
Layout.leftMargin: root.iconLeftMargin
Layout.fillWidth: false
Layout.alignment: Qt.AlignVCenter
icon: root.icon.name
color: root.fgColor
visible: root.icon.name !== ""
}
WText {
id: buttonText
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
text: root.text
horizontalAlignment: Text.AlignLeft
font: root.font
color: root.fgColor
}
}
}
}

View file

@ -0,0 +1,73 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks
WButton {
id: root
property bool animateChoiceHighlight: true
Layout.fillWidth: true
implicitWidth: contentItem.implicitWidth
horizontalPadding: 10
verticalPadding: 11
buttonSpacing: 8
color: {
if (root.checked) {
if (root.down) {
return root.colBackgroundHover;
} else if (root.hovered && !root.down) {
return root.colBackgroundActive;
} else {
return root.colBackgroundHover;
}
}
if (root.down) {
return root.colBackgroundActive;
} else if (root.hovered && !root.down) {
return root.colBackgroundHover;
} else {
return root.colBackground;
}
}
fgColor: colForeground
background: Rectangle {
id: backgroundRect
radius: Looks.radius.medium
color: root.color
Behavior on color {
enabled: root.animateChoiceHighlight
animation: Looks.transition.color.createObject(this)
}
WFadeLoader {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
shown: root.checked
sourceComponent: Rectangle {
implicitWidth: 3
implicitHeight: 3
radius: width / 2
color: Looks.colors.accent
property bool forceZeroHeight: true
height: forceZeroHeight ? 0 : Math.max(16, root.background.height - 18 * 2)
Component.onCompleted: {
forceZeroHeight = false;
}
Behavior on height {
enabled: root.animateChoiceHighlight
animation: Looks.transition.opacity.createObject(this)
}
}
}
}
}

View file

@ -0,0 +1,19 @@
import QtQuick
import qs.modules.common
// Yes, this is (mostly) a copy of FadeLoader.
// The animation of a Behavior cannot be changed... I'd love to be proven wrong.
Loader {
id: root
property bool shown: true
property alias fade: opacityBehavior.enabled
property alias animation: opacityBehavior.animation
opacity: shown ? 1 : 0
visible: opacity > 0
active: opacity > 0
Behavior on opacity {
id: opacityBehavior
animation: Looks.transition.opacity.createObject(null)
}
}

View file

@ -0,0 +1,187 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Services.UPower
import qs.services
Singleton {
id: root
function pathForName(iconName) {
return Quickshell.shellPath(`assets/icons/fluent/${iconName}.svg`);
}
function wifiIconForStrength(strength) {
if (strength > 75)
return "wifi-1";
if (strength > 50)
return "wifi-2";
if (strength > 25)
return "wifi-3";
return "wifi-4";
}
property string internetIcon: {
if (Network.ethernet)
return "ethernet";
if (Network.wifiEnabled) {
const strength = Network.networkStrength;
return wifiIconForStrength(strength);
}
if (Network.wifiStatus === "connecting")
return "wifi-4";
if (Network.wifiStatus === "disconnected")
return "wifi-off";
if (Network.wifiStatus === "disabled")
return "wifi-off";
return "wifi-warning";
}
property string batteryIcon: {
if (Battery.isCharging)
return "battery-charge";
if (Battery.isCriticalAndNotCharging)
return "battery-warning";
if (Battery.percentage >= 0.9)
return "battery-full";
return `battery-0`;
}
property string batteryLevelIcon: {
const discreteLevel = Math.ceil(Battery.percentage * 10);
return `battery-${discreteLevel > 9 ? "full" : discreteLevel}`;
}
property string volumeIcon: {
const muted = Audio.sink?.audio.muted ?? false;
const volume = Audio.sink?.audio.volume ?? 0;
if (muted)
return "speaker-mute";
if (volume == 0)
return "speaker-none";
if (volume < 0.5)
return "speaker-1";
return "speaker";
}
property string micIcon: {
const muted = Audio.source?.audio.muted ?? false;
return muted ? "mic-off" : "mic";
}
property string bluetoothIcon: BluetoothStatus.connected ? "bluetooth-connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth-disabled"
property string nightLightIcon: Hyprsunset.temperatureActive ? "weather-moon" : "weather-moon-off"
property string notificationsIcon: Notifications.silent ? "alert-snooze" : "alert"
property string powerProfileIcon: {
switch (PowerProfiles.profile) {
case PowerProfile.PowerSaver:
return "leaf-two";
case PowerProfile.Balanced:
return "flash-on";
case PowerProfile.Performance:
return "fire";
}
}
function audioDeviceIcon(node) {
if (!node.isSink)
return "mic-on";
const monitor = /monitor|hdmi/i;
const headphones = /headset|headphone|bluez|wireless/i;
const speakers = /speaker|output/i;
if (monitor.test(node.nickname) || monitor.test(node.description) || monitor.test(node.name)) {
return "desktop-speaker";
}
if (headphones.test(node.nickname) || headphones.test(node.description) || headphones.test(node.name)) {
return "headphones";
}
if (speakers.test(node.nickname) || speakers.test(node.description) || speakers.test(node.name)) {
return "speaker";
}
return "speaker";
}
function audioAppIcon(node) {
let icon;
icon = AppSearch.guessIcon(node?.properties["application.icon-name"] ?? "");
if (AppSearch.iconExists(icon))
return icon;
icon = AppSearch.guessIcon(node?.properties["node.name"] ?? "");
return icon;
}
function bluetoothDeviceIcon(device) {
const systemIconName = device?.icon || "";
if (systemIconName.includes("headset") || systemIconName.includes("headphones"))
return "headphones";
if (systemIconName.includes("audio"))
return "speaker";
if (systemIconName.includes("phone"))
return "phone";
if (systemIconName.includes("mouse"))
return "bluetooth";
if (systemIconName.includes("keyboard"))
return "keyboard";
return "bluetooth";
}
function fluentFromMaterial(icon) {
switch (icon) {
case "calculate":
return "calculator";
case "keyboard_return":
return "arrow-enter-left";
case "open_in_new":
return "open";
case "settings_suggest":
return "wand";
case "terminal":
return "app-generic";
case "travel_explore":
return "globe-search";
case "keep":
return "pin";
case "keep_off":
return "pin-off";
default:
return "apps";
}
}
function guessIconForName(name) {
const lowerName = name.toLowerCase();
if (lowerName.includes("app") || lowerName.includes("desktop"))
return "apps";
if (lowerName.includes("news"))
return "news";
if (lowerName.includes("new") || lowerName.includes("create") || lowerName.includes("add"))
return "add";
if (lowerName.includes("open"))
return "open";
if (lowerName.includes("friends") || lowerName.includes("contact") || lowerName.includes("family"))
return "people";
if (lowerName.includes("community"))
return "people-team";
if (lowerName.includes("library"))
return "library";
if (lowerName.includes("setting"))
return "settings";
if (lowerName.includes("gallery"))
return "image-copy";
if (lowerName.includes("server"))
return "server";
if (lowerName.includes("picture") || lowerName.includes("photo") || lowerName.includes("image"))
return "image";
if (lowerName.includes("store") || lowerName.includes("shop"))
return "store-microsoft";
if (lowerName.includes("record") || lowerName.includes("capture"))
return "record";
if (lowerName.includes("screen") || lowerName.includes("display") || lowerName.includes("monitor") || lowerName.includes("desktop"))
return "desktop";
return "apps";
}
}

View file

@ -0,0 +1,22 @@
import QtQuick
import Qt5Compat.GraphicalEffects
import qs
import qs.services
import qs.services.network
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.waffle.looks
StyledIndeterminateProgressBar {
id: progressBar
implicitHeight: 3
background: null
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: progressBar.width
height: progressBar.height
radius: progressBar.height / 2
}
}
}

View file

@ -0,0 +1,19 @@
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Controls
ListView {
id: root
boundsBehavior: Flickable.DragOverBounds
ScrollBar.vertical: WScrollBar {}
displaced: Transition {
animations: [Looks.transition.enter.createObject(this, {
property: "y"
})]
}
}

View file

@ -0,0 +1,104 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
Menu {
id: root
property bool downDirection: false
property bool hasIcons: false // TODO: implement
property color color: Looks.colors.bg1Base
property alias backgroundPane: bgPane
implicitWidth: background.implicitWidth + margins * 2
implicitHeight: background.implicitHeight + margins * 2
margins: 10
padding: 3
property real sourceEdgeMargin: -implicitHeight
clip: true
enter: Transition {
NumberAnimation {
property: "sourceEdgeMargin"
from: -root.implicitHeight
to: root.margins
duration: 200
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
}
}
exit: Transition {
NumberAnimation {
property: "sourceEdgeMargin"
from: root.margins
to: -root.implicitHeight
duration: 150
easing.type: Easing.BezierSpline
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut
}
}
background: Item {
id: bgItem
implicitWidth: bgPane.implicitWidth
implicitHeight: bgPane.implicitHeight
WPane {
id: bgPane
anchors {
left: parent.left
right: parent.right
top: root.downDirection ? parent.top : undefined
bottom: root.downDirection ? undefined : parent.bottom
margins: root.margins
topMargin: root.downDirection ? root.sourceEdgeMargin : root.margins
bottomMargin: root.downDirection ? root.margins : root.sourceEdgeMargin
}
contentItem: Rectangle {
color: root.color
implicitWidth: menuListView.implicitWidth + root.padding * 2
implicitHeight: root.contentItem.implicitHeight + root.padding * 2
}
}
}
Component.onCompleted: {
menuListView.itemAtIndex(0)?.forceActiveFocus();
}
contentItem: Item {
implicitWidth: menuListView.implicitWidth
implicitHeight: menuListView.implicitHeight
WListView {
id: menuListView
interactive: contentHeight > height
anchors {
left: parent.left
right: parent.right
top: root.downDirection ? parent.top : undefined
bottom: root.downDirection ? undefined : parent.bottom
margins: root.margins // ????
topMargin: root.downDirection ? root.sourceEdgeMargin : root.margins
bottomMargin: root.downDirection ? root.margins : root.sourceEdgeMargin
}
clip: true
implicitHeight: contentHeight
implicitWidth: Array.from({
length: count
}, (_, i) => itemAtIndex(i)?.implicitWidth ?? 0).reduce((a, b) => a > b ? a : b)
model: root.contentModel
}
}
delegate: WMenuItem {
id: menuItemDelegate
}
}

View file

@ -0,0 +1,127 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks
MenuItem {
id: root
property color colBackground: ColorUtils.transparentize(Looks.colors.bg1)
property color colBackgroundHover: Looks.colors.bg2Hover
property color colBackgroundActive: Looks.colors.bg2Active
property color colBackgroundToggled: Looks.colors.bg2Hover
property color colBackgroundToggledHover: Looks.colors.bg2Active
property color colBackgroundToggledActive: Looks.colors.bg2Hover
property color colForeground: Looks.colors.fg
property color colForegroundToggled: Looks.colors.fg
property color colForegroundDisabled: ColorUtils.transparentize(Looks.colors.subfg, 0.4)
property color color: {
if (!root.enabled)
return colBackground;
if (root.checked) {
if (root.down) {
return root.colBackgroundToggledActive;
} else if (root.hovered) {
return root.colBackgroundToggledHover;
} else {
return root.colBackgroundToggled;
}
}
if (root.down) {
return root.colBackgroundActive;
} else if (root.hovered) {
return root.colBackgroundHover;
} else {
return root.colBackground;
}
}
property color fgColor: {
if (root.checked)
return root.colForegroundToggled;
if (root.enabled)
return root.colForeground;
return root.colForegroundDisabled;
}
property real inset: 2
topInset: inset
bottomInset: inset
leftInset: inset
rightInset: inset
horizontalPadding: 11
width: ListView.view?.width
height: visible ? implicitHeight : 0
background: Rectangle {
id: backgroundRect
radius: Looks.radius.medium
color: root.color
Behavior on color {
animation: Looks.transition.color.createObject(this)
}
}
implicitHeight: Math.max(28, contentItem.implicitHeight) + topInset + bottomInset
implicitWidth: contentItem.implicitWidth + leftInset + rightInset + leftPadding + rightPadding
contentItem: Item {
implicitWidth: contentLayout.implicitWidth
implicitHeight: contentLayout.implicitHeight
RowLayout {
id: contentLayout
anchors.fill: parent
spacing: 12
FluentIcon {
id: buttonIcon
monochrome: true
implicitSize: 20
Layout.fillWidth: false
Layout.alignment: Qt.AlignVCenter
color: root.fgColor
visible: root.icon.name !== ""
icon: root.icon.name
}
WText {
id: buttonText
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
text: root.text
horizontalAlignment: Text.AlignLeft
font.pixelSize: Looks.font.pixelSize.large
color: root.fgColor
}
}
WFadeLoader {
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: -root.leftPadding + width
}
shown: root.checked
sourceComponent: Rectangle {
implicitWidth: 3
implicitHeight: 3
radius: width / 2
color: Looks.colors.accent
property bool forceZeroHeight: true
height: forceZeroHeight ? 0 : Math.max(root.down ? 10 : 16, root.background.height - 18 * 2)
Component.onCompleted: {
forceZeroHeight = false;
}
Behavior on height {
animation: Looks.transition.resize.createObject(this)
}
}
}
}
}

View file

@ -0,0 +1,45 @@
import QtQuick
import qs
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
MouseArea {
id: root
property real radius: Looks.radius.medium
hoverEnabled: true
property color colBackground: ColorUtils.transparentize(Looks.colors.bg2)
property color colBackgroundHover: Looks.colors.bg2Hover
property color colBackgroundActive: Looks.colors.bg2Active
property color colBorder: ColorUtils.transparentize(Looks.colors.bg2Border)
property color colBorderHover: Looks.colors.bg2Border
property color color: {
if (containsMouse) {
return pressed ? colBackgroundActive : colBackgroundHover;
} else {
return colBackground;
}
}
property color borderColor: {
if (containsMouse) {
return colBorderHover;
} else {
return colBorder;
}
}
property Item background: Rectangle {
id: bgRect
parent: root
anchors.fill: parent
color: root.color
radius: root.radius
border.color: root.borderColor
border.width: 1
}
}

View file

@ -0,0 +1,60 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.waffle.looks
Item {
id: root
property Item contentItem
property real radius: Looks.radius.large
property alias color: contentRect.color
property alias border: borderRect
property alias borderColor: borderRect.border.color
property alias borderWidth: borderRect.border.width
implicitWidth: borderRect.implicitWidth
implicitHeight: borderRect.implicitHeight
WRectangularShadow {
target: borderRect
}
Rectangle {
id: borderRect
z: 1
color: "transparent"
radius: root.radius
border.color: Looks.colors.bg2Border
border.width: 1
implicitWidth: contentItem.implicitWidth + border.width * 2
implicitHeight: contentItem.implicitHeight + border.width * 2
anchors.fill: contentRect
anchors.margins: -border.width
}
Rectangle {
id: contentRect
anchors.centerIn: parent
z: 0
color: Looks.colors.bgPanelFooterBackground
implicitWidth: contentItem.implicitWidth
implicitHeight: contentItem.implicitHeight
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
id: contentAreaMask
width: contentRect.width
height: contentRect.height
radius: root.radius - borderRect.border.width
}
}
children: [root.contentItem]
}
}

View file

@ -0,0 +1,26 @@
import QtQuick
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.waffle.looks
import qs.modules.waffle.bar
WButton {
id: root
property alias iconName: iconContent.icon
property alias iconSize: iconContent.implicitSize
property alias monochrome: iconContent.monochrome
implicitWidth: 40
implicitHeight: 40
contentItem: Item {
FluentIcon {
id: iconContent
anchors.centerIn: parent
implicitSize: 18
icon: root.iconName
}
}
}

View file

@ -0,0 +1,6 @@
import QtQuick
import QtQuick.Layouts
ColumnLayout {
spacing: 0
}

View file

@ -0,0 +1,10 @@
import QtQuick
import QtQuick.Layouts
import qs.modules.waffle.looks
Rectangle {
Layout.fillHeight: false
Layout.fillWidth: true
color: Looks.colors.bgPanelSeparator
implicitHeight: 1
}

View file

@ -0,0 +1,31 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks
PopupToolTip {
id: root
required property Item realContentItem
realContentItem: WText {
text: root.text
anchors.centerIn: parent
}
property real visualMargin: 11
verticalPadding: 8
horizontalPadding: 10
verticalMargin: visualMargin
horizontalMargin: visualMargin
contentItem: WToolTipContent {
id: tooltipContent
realContentItem: root.realContentItem
horizontalPadding: root.horizontalPadding
verticalPadding: root.verticalPadding
}
}

View file

@ -0,0 +1,49 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Widgets
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.waffle.looks
ProgressBar {
id: root
Behavior on value {
SmoothedAnimation {
velocity: Looks.transition.velocity
}
}
implicitHeight: 4
background: null
contentItem: Item {
id: background
Rectangle {
id: trackTrough
anchors {
left: parent.left
right: parent.right
verticalCenter: parent.verticalCenter
}
radius: root.implicitHeight / 2
color: Looks.colors.controlBg
implicitHeight: root.implicitHeight
}
Rectangle {
id: trackHighlight
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
radius: root.implicitHeight / 2
color: Looks.colors.accent
implicitHeight: root.implicitHeight
width: background.width * root.value
}
}
}

View file

@ -0,0 +1,11 @@
import QtQuick
import QtQuick.Effects
import qs.modules.common
import qs.modules.common.widgets
StyledRectangularShadow {
blur: 10
spread: 2
offset: Qt.vector2d(0.0, 4)
color: Looks.colors.shadow
}

View file

@ -0,0 +1,15 @@
import QtQuick
import QtQuick.Effects
import qs.modules.common
import qs.modules.common.widgets
Item {
default property Item contentItem
property Item shadow: WRectangularShadow {
target: contentItem
}
implicitWidth: contentItem.implicitWidth
implicitHeight: contentItem.implicitHeight
children: [shadow, contentItem]
}

View file

@ -0,0 +1,25 @@
import QtQuick
import QtQuick.Controls
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
ScrollBar {
id: root
policy: ScrollBar.AsNeeded
active: hovered || pressed
property color color: Looks.colors.controlBg
contentItem: Rectangle {
implicitWidth: root.active ? 4 : 2
implicitHeight: root.visualSize
radius: 9999
color: root.color
opacity: root.policy === ScrollBar.AlwaysOn || (root.active && root.size < 1.0) ? 0.5 : 0
Behavior on opacity {
animation: Looks.transition.opacity.createObject(this)
}
}
}

View file

@ -0,0 +1,105 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Widgets
import qs.modules.common
import qs.modules.common.widgets
Slider {
id: root
property real trackWidth: 4
property string tooltipContent: `${Math.round(value * 100)}`
property bool scrollable: false
stepSize: 0.02
leftPadding: 0
rightPadding: 0
implicitHeight: handle.implicitHeight
Behavior on value { // This makes the adjusted value (like volume) shift smoothly
SmoothedAnimation {
velocity: Looks.transition.velocity
}
}
background: MouseArea {
id: background
anchors.fill: parent
onWheel: (event) => {
if (!root.scrollable) {
event.accepted = false;
return;
}
if (event.angleDelta.y > 0) {
root.value = Math.min(root.value + root.stepSize, 1)
root.moved()
} else {
root.value = Math.max(root.value - root.stepSize, 0)
root.moved()
}
}
Rectangle {
id: trackHighlight
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
topLeftRadius: root.trackWidth / 2
bottomLeftRadius: root.trackWidth / 2
color: Looks.colors.accent
implicitHeight: root.trackWidth
width: background.width * root.visualPosition
}
Rectangle {
id: trackTrough
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
topRightRadius: root.trackWidth / 2
bottomRightRadius: root.trackWidth / 2
color: Looks.colors.controlBg
implicitHeight: root.trackWidth
width: background.width * (1 - root.visualPosition)
}
}
handle: Circle {
id: handle
anchors.verticalCenter: parent.verticalCenter
x: (diameter / 2) + root.visualPosition * (root.width - diameter) - (diameter / 2)
diameter: 20
color: Looks.colors.controlFg
MouseArea {
id: handleMouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
}
Circle {
anchors.centerIn: parent
diameter: root.pressed ? 10 : handleMouseArea.containsMouse ? 14 : 12
color: Looks.colors.accent
Behavior on diameter {
animation: Looks.transition.enter.createObject(this)
}
}
WToolTip {
id: tooltip
extraVisibleCondition: root.pressed
text: root.tooltipContent
font.pixelSize: Looks.font.pixelSize.larger
verticalPadding: 3
horizontalPadding: 8
}
}
}

View file

@ -0,0 +1,84 @@
import QtQuick
import QtQuick.Controls
import qs.modules.waffle.looks
StackView {
id: root
property real moveDistance: 30
property int pushDuration: 200
property int fadeDuration: 80
property list<real> bezierCurve: Looks.transition.easing.bezierCurve.easeIn
property list<real> fadeBezierCurve: Looks.transition.easing.bezierCurve.easeInOut
clip: true
background: null
pushEnter: Transition {
XAnimator {
from: -root.moveDistance
to: 0
duration: root.pushDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: root.bezierCurve
}
NumberAnimation {
properties: "opacity"
from: 0
to: 1
duration: root.fadeDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: root.fadeBezierCurve
}
}
pushExit: Transition {
XAnimator {
from: 0
to: root.moveDistance
duration: root.pushDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: root.bezierCurve
}
NumberAnimation {
properties: "opacity"
from: 1
to: 0
duration: root.fadeDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: root.fadeBezierCurve
}
}
popEnter: Transition {
XAnimator {
from: root.moveDistance
to: 0
duration: root.pushDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: root.bezierCurve
}
NumberAnimation {
properties: "opacity"
from: 0
to: 1
duration: root.fadeDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: root.fadeBezierCurve
}
}
popExit: Transition {
XAnimator {
from: 0
to: -root.moveDistance
duration: root.pushDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: root.bezierCurve
}
NumberAnimation {
properties: "opacity"
from: 1
to: 0
duration: root.fadeDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: root.fadeBezierCurve
}
}
}

View file

@ -0,0 +1,66 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import qs.modules.common
import qs.modules.waffle.looks
Switch {
id: root
implicitWidth: 40
implicitHeight: 20
property real indicatorHeight: 12
property real indicatorPressedHeight: 14
property real indicatorPressedWidth: 17
property color checkedColor: Looks.colors.accent
property color uncheckedColor: Looks.colors.bg1
property color borderColor: Looks.colors.controlBgInactive
readonly property real indicatorPressedWidthDiff: indicatorPressedWidth - indicatorHeight
background: Rectangle {
width: parent.width
height: parent.height
radius: height / 2
color: root.checked ? root.checkedColor : root.uncheckedColor
border.width: 1
border.color: root.checked ? root.checkedColor : root.borderColor
Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
Behavior on border.color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
}
// Custom thumb styling
indicator: Rectangle {
implicitWidth: (root.pressed || root.down) ? root.indicatorPressedWidth : root.indicatorHeight
implicitHeight: (root.pressed || root.down) ? root.indicatorPressedHeight : root.indicatorHeight
radius: height / 2
color: root.checked ? Looks.colors.accentFg : root.borderColor
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: {
if (root.checked) {
return 24 - (root.pressed || root.down ? root.indicatorPressedWidthDiff : 0);
} else {
return (root.pressed || root.down) ? 3 : (Config.options.waffles.tweaks.switchHandlePositionFix ? 4 : 3);
}
}
Behavior on anchors.leftMargin {
animation: Looks.transition.enter.createObject(this)
}
Behavior on implicitWidth {
animation: Looks.transition.resize.createObject(this)
}
Behavior on implicitHeight {
animation: Looks.transition.resize.createObject(this)
}
Behavior on color {
animation: Looks.transition.color.createObject(this)
}
}
}

View file

@ -0,0 +1,19 @@
import QtQuick
Text {
id: root
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
color: Looks.colors.fg
font {
hintingPreference: Font.PreferDefaultHinting
family: Looks.font.family.ui
pixelSize: Looks.font.pixelSize.normal
weight: Looks.font.weight.regular
variableAxes: Looks.font.variableAxes.ui
}
linkColor: Looks.colors.link
}

View file

@ -0,0 +1,23 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs.modules.waffle.looks
WButton {
id: root
implicitHeight: 40
implicitWidth: contentItem.implicitWidth + 30
color: "transparent"
contentItem: Item {
id: contentItem
anchors.centerIn: parent
implicitWidth: buttonText.implicitWidth
WText {
id: buttonText
anchors.centerIn: parent
color: root.pressed ? Looks.colors.fg : Looks.colors.fg1
text: root.text
}
}
}

View file

@ -0,0 +1,31 @@
import qs.modules.common
import QtQuick
import QtQuick.Controls.FluentWinUI3
import QtQuick.Controls
TextField {
id: root
clip: true
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
color: Looks.colors.fg
palette {
active: Looks.colors.accent
}
font {
hintingPreference: Font.PreferDefaultHinting
family: Looks.font.family.ui
pixelSize: Looks.font.pixelSize.normal
weight: Looks.font.weight.regular
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
hoverEnabled: true
cursorShape: Qt.IBeamCursor
}
}

View file

@ -0,0 +1,19 @@
import QtQuick
import QtQuick.Controls
TextInput {
id: root
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
color: Looks.colors.fg
font {
hintingPreference: Font.PreferFullHinting
family: Looks.font.family.ui
pixelSize: Looks.font.pixelSize.large
weight: Looks.font.weight.regular
}
selectionColor: Looks.colors.selection
selectedTextColor: Looks.colors.selectionFg
}

View file

@ -0,0 +1,31 @@
import QtQuick
Item {
id: root
property string longestText
property alias text: textItem.text
property alias font: textItem.font
property alias horizontalAlignment: textItem.horizontalAlignment
property alias verticalAlignment: textItem.verticalAlignment
property alias color: textItem.color
implicitWidth: longestTextMetrics.width
implicitHeight: longestTextMetrics.height
TextMetrics {
id: longestTextMetrics
text: root.longestText
font {
family: Looks.font.family.ui
pixelSize: Looks.font.pixelSize.large
weight: Looks.font.weight.regular
}
}
WText {
id: textItem
anchors.fill: parent
font.pixelSize: Looks.font.pixelSize.large
}
}

View file

@ -0,0 +1,36 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks
StyledToolTip {
id: root
required property Item realContentItem
font {
family: Looks.font.family.ui
pixelSize: Looks.font.pixelSize.normal
weight: Looks.font.weight.regular
}
realContentItem: WText {
text: root.text
font: root.font
anchors.centerIn: parent
}
verticalPadding: 8
horizontalPadding: 10
delay: 400
contentItem: WToolTipContent {
id: tooltipContent
realContentItem: root.realContentItem
horizontalPadding: root.horizontalPadding
verticalPadding: root.verticalPadding
}
}

View file

@ -0,0 +1,30 @@
import QtQuick
import Quickshell
import qs.modules.waffle.looks
Item {
id: root
anchors.centerIn: parent
required property Item realContentItem
property alias radius: realContent.radius
property real verticalPadding: 8
property real horizontalPadding: 10
implicitWidth: realContent.implicitWidth + 2 * 2
implicitHeight: realContent.implicitHeight + 2 * 2
WAmbientShadow {
target: realContent
}
Rectangle {
id: realContent
z: 1
anchors.centerIn: parent
implicitWidth: root.realContentItem.implicitWidth + root.horizontalPadding * 2
implicitHeight: root.realContentItem.implicitHeight + root.verticalPadding * 2
color: Looks.colors.bg1Base
radius: Looks.radius.medium
children: [root.realContentItem]
}
}

View file

@ -0,0 +1,38 @@
import QtQuick
import QtQuick.Layouts
import qs.modules.common
import qs.modules.common.widgets
Item {
id: root
property real padding: 9
property alias colBackground: background.color
property alias spacing: toolbarLayout.spacing
property alias radius: background.radius
default property alias toolbarData: toolbarLayout.data
implicitWidth: background.implicitWidth
implicitHeight: background.implicitHeight
Rectangle {
id: background
anchors.fill: parent
implicitHeight: 50
implicitWidth: toolbarLayout.implicitWidth + root.padding * 2
radius: Looks.radius.large
color: Looks.colors.bg0Base
border.width: 1
border.color: Looks.colors.bg1Border
RowLayout {
id: toolbarLayout
spacing: 4
anchors {
fill: parent
margins: root.padding
}
}
}
}

View file

@ -0,0 +1,8 @@
import QtQuick
import QtQuick.Layouts
import qs.modules.common
WButton {
implicitHeight: 32
radius: Looks.radius.medium
}

View file

@ -0,0 +1,16 @@
import QtQuick
import QtQuick.Layouts
import qs.modules.common
WToolbarButton {
id: root
implicitWidth: height
contentItem: Item {
FluentIcon {
anchors.centerIn: parent
icon: root.icon.name
implicitSize: 18
color: root.fgColor
}
}
}

View file

@ -0,0 +1,21 @@
import QtQuick
import QtQuick.Controls
import qs.modules.common
TabButton {
id: root
implicitWidth: 38
implicitHeight: 32
padding: 0
background: null
contentItem: Item {
FluentIcon {
anchors.centerIn: parent
icon: root.icon.name
color: root.icon.color
implicitSize: 18
}
}
}

View file

@ -0,0 +1,11 @@
import QtQuick
import QtQuick.Layouts
import qs.modules.common
Rectangle {
Layout.leftMargin: 4
Layout.rightMargin: 4
implicitHeight: 24
implicitWidth: 1
color: Looks.colors.bg0Border
}

View file

@ -0,0 +1,53 @@
import QtQuick
import QtQuick.Controls
import qs.modules.common
import qs.modules.common.functions
TabBar {
id: root
implicitHeight: 32
background: Rectangle {
radius: Looks.radius.medium
color: Looks.colors.bgPanelFooter
border.color: ColorUtils.transparentize(Looks.colors.bg0Border, 0.7)
border.width: 1
// Indicator
Rectangle {
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
leftMargin: root.currentIndex * (root.width / root.count)
Behavior on leftMargin {
animation: Looks.transition.resize.createObject(this)
}
}
radius: Looks.radius.medium
color: Looks.colors.bg2Base
border.color: Looks.colors.bg0Border
border.width: 1
width: root.width / root.count
Rectangle {
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 1
}
implicitWidth: pressDetector.containsPress ? 16 : 12
implicitHeight: 3
radius: height / 2
color: Looks.colors.accent
}
}
}
MouseArea {
id: pressDetector
z: 9999
anchors.fill: parent
acceptedButtons: Qt.LeftButton
}
}

View file

@ -0,0 +1,27 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks
StyledImage {
id: avatar
Layout.alignment: Qt.AlignTop
sourceSize: Qt.size(32, 32)
source: Directories.userAvatarPathAccountsService
fallbacks: [Directories.userAvatarPathRicersAndWeirdSystems, Directories.userAvatarPathRicersAndWeirdSystems2]
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Circle {
diameter: avatar.height
}
}
}