mirror of
https://github.com/tuxdotrs/tshell.git
synced 2026-09-19 18:49:02 +05:30
Compare commits
5 Commits
ab5587fd90
...
3779974cb2
| Author | SHA1 | Date | |
|---|---|---|---|
|
3779974cb2
|
|||
|
2f122a9487
|
|||
|
494420d241
|
|||
|
ae6628f549
|
|||
|
a1533e73c7
|
306
Bar.qml
306
Bar.qml
@@ -1,306 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Effects
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import Quickshell.Services.UPower
|
|
||||||
import Quickshell.Services.SystemTray
|
|
||||||
import qs.config
|
|
||||||
|
|
||||||
Scope {
|
|
||||||
Variants {
|
|
||||||
model: Quickshell.screens
|
|
||||||
|
|
||||||
PanelWindow {
|
|
||||||
required property var modelData
|
|
||||||
screen: modelData
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: true
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitHeight: 50
|
|
||||||
implicitWidth: 1150
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.topMargin: 10
|
|
||||||
radius: Appearance.radius
|
|
||||||
color: Appearance.colors.background
|
|
||||||
|
|
||||||
FlexboxLayout {
|
|
||||||
id: flexLayout
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Appearance.margin
|
|
||||||
|
|
||||||
wrap: FlexboxLayout.Wrap
|
|
||||||
direction: FlexboxLayout.Row
|
|
||||||
justifyContent: FlexboxLayout.JustifySpaceBetween
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
color: 'transparent'
|
|
||||||
implicitHeight: parent.height
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
Row {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: parent.left
|
|
||||||
spacing: Appearance.spacing
|
|
||||||
|
|
||||||
Button {
|
|
||||||
padding: Appearance.padding
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
|
|
||||||
icon.color: Appearance.colors.foreground
|
|
||||||
icon.source: Quickshell.shellPath("assets") + "/icons/nix.svg"
|
|
||||||
onClicked: {
|
|
||||||
Quickshell.execDetached(["vicinae", "toggle"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
hoverEnabled: true
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Appearance.radius
|
|
||||||
color: parent.hovered ? Appearance.colors.inActive : Appearance.colors.background
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Appearance.duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
property real percentage: Math.round(UPower.displayDevice.percentage * 100)
|
|
||||||
property real energyRate: UPower.displayDevice.changeRate
|
|
||||||
property string iconBase: Quickshell.shellPath("assets") + "/icons/"
|
|
||||||
property string iconName: parent.percentage < 30 ? "battery-low.svg" : parent.percentage < 70 ? "battery-medium.svg" : "battery-full.svg"
|
|
||||||
|
|
||||||
padding: Appearance.padding
|
|
||||||
|
|
||||||
text: `${percentage}% ${energyRate}W`
|
|
||||||
palette.buttonText: Appearance.colors.foreground
|
|
||||||
font.family: Appearance.font.family
|
|
||||||
font.pointSize: Appearance.font.pointSize
|
|
||||||
|
|
||||||
icon.color: Appearance.colors.foreground
|
|
||||||
icon.source: iconBase + iconName
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Appearance.radius
|
|
||||||
color: Appearance.colors.inActive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
color: 'transparent'
|
|
||||||
implicitHeight: parent.height
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
Row {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
spacing: Appearance.spacing
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: 7
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
property var ws: Hyprland.workspaces.values.find(w => w.id === index + 1)
|
|
||||||
property bool isActive: Hyprland.focusedWorkspace?.id === (index + 1)
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
radius: 1000
|
|
||||||
implicitHeight: 15
|
|
||||||
|
|
||||||
implicitWidth: isActive ? this.implicitHeight * 2.3 : this.implicitHeight
|
|
||||||
|
|
||||||
color: {
|
|
||||||
if (handler.hovered) {
|
|
||||||
return Appearance.colors.accent;
|
|
||||||
} else if (isActive || ws) {
|
|
||||||
return Appearance.colors.accent;
|
|
||||||
} else {
|
|
||||||
return Appearance.colors.inActive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
hoverEnabled: true
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: Hyprland.dispatch("workspace " + (index + 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Appearance.duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HoverHandler {
|
|
||||||
id: handler
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on implicitWidth {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Appearance.duration
|
|
||||||
easing.type: Easing.OutQuad
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
color: 'transparent'
|
|
||||||
implicitHeight: parent.height
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
Row {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.right: parent.right
|
|
||||||
spacing: Appearance.spacing
|
|
||||||
|
|
||||||
Button {
|
|
||||||
padding: Appearance.padding
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
|
|
||||||
icon.color: Appearance.colors.foreground
|
|
||||||
icon.source: Quickshell.shellPath("assets") + "/icons/wifi.svg"
|
|
||||||
onClicked: {
|
|
||||||
Quickshell.execDetached(["vicinae", "vicinae://extensions/dagimg-dot/wifi-commander/scan-wifi"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
hoverEnabled: true
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Appearance.radius
|
|
||||||
color: parent.hovered ? Appearance.colors.inActive : Appearance.colors.background
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Appearance.duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
padding: Appearance.padding
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
|
|
||||||
icon.color: Appearance.colors.foreground
|
|
||||||
icon.source: Quickshell.shellPath("assets") + "/icons/bluetooth.svg"
|
|
||||||
onClicked: {
|
|
||||||
Quickshell.execDetached(["vicinae", "vicinae://extensions/Gelei/bluetooth/devices"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
hoverEnabled: true
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Appearance.radius
|
|
||||||
color: parent.hovered ? Appearance.colors.inActive : Appearance.colors.background
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Appearance.duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
implicitWidth: sysTrayRow.implicitWidth + 10
|
|
||||||
implicitHeight: parent.height
|
|
||||||
radius: Appearance.radius
|
|
||||||
color: Appearance.colors.inActive
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: sysTrayRow
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: Appearance.spacing
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: SystemTray.items.values.length
|
|
||||||
Image {
|
|
||||||
source: SystemTray.items.values[index].icon
|
|
||||||
height: parent.parent.height - 15
|
|
||||||
width: parent.parent.height - 15
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
padding: Appearance.padding
|
|
||||||
text: Time.time
|
|
||||||
|
|
||||||
palette.buttonText: Appearance.colors.foreground
|
|
||||||
font.family: Appearance.font.family
|
|
||||||
font.pointSize: Appearance.font.pointSize
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Appearance.radius
|
|
||||||
color: Appearance.colors.inActive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
padding: Appearance.padding
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
|
|
||||||
icon.color: Appearance.colors.foreground
|
|
||||||
icon.source: Quickshell.shellPath("assets") + "/icons/ghost.svg"
|
|
||||||
|
|
||||||
hoverEnabled: true
|
|
||||||
|
|
||||||
HoverHandler {
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: Appearance.radius
|
|
||||||
color: parent.hovered ? Appearance.colors.inActive : Appearance.colors.background
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Appearance.duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
assets/cava.conf
Normal file
14
assets/cava.conf
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[general]
|
||||||
|
bars = 12
|
||||||
|
framerate = 60
|
||||||
|
|
||||||
|
[input]
|
||||||
|
method = pulse
|
||||||
|
|
||||||
|
[output]
|
||||||
|
method = raw
|
||||||
|
raw_target = /dev/stdout
|
||||||
|
data_format = ascii
|
||||||
|
ascii_max_range = 100
|
||||||
|
bar_delimiter = 59
|
||||||
|
frame_delimiter = 10
|
||||||
29
config/BarLayout.qml
Normal file
29
config/BarLayout.qml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import qs.ui
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
function widget(name: string): url {
|
||||||
|
return `${Quickshell.shellPath("modules/bar")}/${name}.qml`;
|
||||||
|
}
|
||||||
|
|
||||||
|
property var left: [
|
||||||
|
root.widget("LauncherButton"),
|
||||||
|
root.widget("BatteryIndicator"),
|
||||||
|
root.widget("CavaVisualizer")
|
||||||
|
]
|
||||||
|
|
||||||
|
property var center: [
|
||||||
|
root.widget("Workspaces")
|
||||||
|
]
|
||||||
|
|
||||||
|
property var right: [
|
||||||
|
root.widget("SystemTrayWidget"),
|
||||||
|
root.widget("ClockWidget"),
|
||||||
|
root.widget("GhostButton")
|
||||||
|
]
|
||||||
|
}
|
||||||
41
flake.lock
generated
41
flake.lock
generated
@@ -2,15 +2,15 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1771848320,
|
"lastModified": 1787360063,
|
||||||
"narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=",
|
"narHash": "sha256-dt4WdcvsA8/RCe+VZZwqU0X+XMM3wBbGCWA0/sFWzGo=",
|
||||||
"owner": "nixos",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "2fc6539b481e1d2569f25f8799236694180c0993",
|
"rev": "2c423e03bbafcff28bfadc6781a4a8257f205cb5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-unstable",
|
"ref": "nixos-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
@@ -23,11 +23,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1771926182,
|
"lastModified": 1787279335,
|
||||||
"narHash": "sha256-QbXuSLhiSxOq6ydBL3+KGe1aiYWBW+e3J6qjJZaRMq0=",
|
"narHash": "sha256-CLX2Zp5i5BuLbOxNOkwRd9YY84IOrACNxBV79o9/F9Y=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "cddb4f061bab495f4473ca5f2c571b6c710efef7",
|
"rev": "1a4716cde794a59928d9d9fc15f2afc7a95de360",
|
||||||
"revCount": 744,
|
"revCount": 846,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
||||||
},
|
},
|
||||||
@@ -39,7 +39,28 @@
|
|||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"quickshell": "quickshell"
|
"quickshell": "quickshell",
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"treefmt-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1786901030,
|
||||||
|
"narHash": "sha256-WSFCsDSE5ffgD2MqzkM2CYjeFiKhRF/dJUN8uedb6YE=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "27b3b12a8e6375f28ebe122f07d230ca5459bbfa",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
46
flake.nix
46
flake.nix
@@ -2,30 +2,54 @@
|
|||||||
description = "tux's widgets for wayland";
|
description = "tux's widgets for wayland";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
quickshell = {
|
quickshell = {
|
||||||
url = "git+https://git.outfoxxed.me/outfoxxed/quickshell";
|
url = "git+https://git.outfoxxed.me/outfoxxed/quickshell";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
treefmt-nix = {
|
||||||
|
url = "github:numtide/treefmt-nix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs =
|
||||||
|
{
|
||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
quickshell,
|
quickshell,
|
||||||
}: let
|
treefmt-nix,
|
||||||
|
}:
|
||||||
|
let
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
in {
|
|
||||||
devShells.${system} = {
|
quickshellWithModules = quickshell.packages.${system}.default.withModules [
|
||||||
default = pkgs.mkShell {
|
pkgs.qt6.qtbase
|
||||||
buildInputs = [
|
pkgs.qt6.qtdeclarative
|
||||||
quickshell.packages.${system}.default
|
pkgs.qt6.qtmultimedia
|
||||||
pkgs.kdePackages.qtdeclarative
|
pkgs.qt6.qttranslations
|
||||||
pkgs.kdePackages.qt5compat
|
];
|
||||||
|
|
||||||
|
treefmtEval = treefmt-nix.lib.evalModule pkgs {
|
||||||
|
projectRootFile = "flake.nix";
|
||||||
|
|
||||||
|
programs = {
|
||||||
|
nixfmt.enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
formatter.${system} = treefmtEval.config.build.wrapper;
|
||||||
|
|
||||||
|
devShells.${system}.default = pkgs.mkShell {
|
||||||
|
packages = [
|
||||||
|
quickshellWithModules
|
||||||
|
pkgs.cava
|
||||||
|
pkgs.wallust
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
modules/bar/BatteryIndicator.qml
Normal file
11
modules/bar/BatteryIndicator.qml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import qs.ui
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
BarButton {
|
||||||
|
hoverHighlight: false
|
||||||
|
pointerCursor: false
|
||||||
|
label: `${Battery.percentage}% ${Battery.energyRate}W`
|
||||||
|
iconSource: Battery.icon
|
||||||
|
}
|
||||||
51
modules/bar/CavaVisualizer.qml
Normal file
51
modules/bar/CavaVisualizer.qml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.config
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int barCount: 14
|
||||||
|
property real maxValue: 100
|
||||||
|
readonly property bool shouldVisualize: barCount > 0 && Cava.values.some(v => v >= 0.001)
|
||||||
|
|
||||||
|
implicitWidth: 96
|
||||||
|
implicitHeight: 32
|
||||||
|
radius: Appearance.radius
|
||||||
|
color: Appearance.colors.inActive
|
||||||
|
visible: shouldVisualize
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: barRow
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 8
|
||||||
|
spacing: 3
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.barCount
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: bar
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
readonly property real value: Cava.values[index] ?? 0
|
||||||
|
|
||||||
|
width: (barRow.width - barRow.spacing * (root.barCount - 1)) / root.barCount
|
||||||
|
height: Math.max(2, (bar.value / root.maxValue) * barRow.height)
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
radius: bar.width / 2
|
||||||
|
color: Appearance.colors.accent
|
||||||
|
antialiasing: true
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
modules/bar/ClockWidget.qml
Normal file
10
modules/bar/ClockWidget.qml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import qs.ui
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
BarButton {
|
||||||
|
hoverHighlight: false
|
||||||
|
pointerCursor: false
|
||||||
|
label: Time.time
|
||||||
|
}
|
||||||
9
modules/bar/GhostButton.qml
Normal file
9
modules/bar/GhostButton.qml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import qs.ui
|
||||||
|
|
||||||
|
BarButton {
|
||||||
|
iconOnly: true
|
||||||
|
iconSource: `${Quickshell.shellPath("assets")}/icons/ghost.svg`
|
||||||
|
}
|
||||||
10
modules/bar/LauncherButton.qml
Normal file
10
modules/bar/LauncherButton.qml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import qs.ui
|
||||||
|
|
||||||
|
BarButton {
|
||||||
|
iconOnly: true
|
||||||
|
iconSource: `${Quickshell.shellPath("assets")}/icons/nix.svg`
|
||||||
|
onClicked: Quickshell.execDetached(["vicinae", "toggle"])
|
||||||
|
}
|
||||||
32
modules/bar/SystemTrayWidget.qml
Normal file
32
modules/bar/SystemTrayWidget.qml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
import qs.config
|
||||||
|
import qs.ui
|
||||||
|
|
||||||
|
BarButton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int iconSize: 16
|
||||||
|
|
||||||
|
hoverHighlight: false
|
||||||
|
pointerCursor: false
|
||||||
|
visible: SystemTray.items.values.length > 0
|
||||||
|
|
||||||
|
contentItem: Row {
|
||||||
|
spacing: Appearance.spacing
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: SystemTray.items.values
|
||||||
|
|
||||||
|
Image {
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
source: modelData.icon
|
||||||
|
width: root.iconSize
|
||||||
|
height: root.iconSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
modules/bar/Workspaces.qml
Normal file
60
modules/bar/Workspaces.qml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import qs.config
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int count: 7
|
||||||
|
|
||||||
|
spacing: Appearance.spacing
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.count
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: pill
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
property var ws: Hyprland.workspaces.values.find(w => w.id === pill.index + 1)
|
||||||
|
property bool isActive: Hyprland.focusedWorkspace?.id === (pill.index + 1)
|
||||||
|
|
||||||
|
radius: 1000
|
||||||
|
implicitHeight: 15
|
||||||
|
implicitWidth: pill.isActive ? pill.implicitHeight * 2.3 : pill.implicitHeight
|
||||||
|
color: {
|
||||||
|
if (handler.hovered)
|
||||||
|
return Appearance.colors.accent;
|
||||||
|
if (pill.isActive || pill.ws)
|
||||||
|
return Appearance.colors.accent;
|
||||||
|
return Appearance.colors.inActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
hoverEnabled: true
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: Hyprland.dispatch("workspace " + (pill.index + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
id: handler
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Appearance.duration
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
services/Battery.qml
Normal file
13
services/Battery.qml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell.Services.UPower
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
readonly property int percentage: Math.round(UPower.displayDevice.percentage * 100)
|
||||||
|
readonly property real energyRate: UPower.displayDevice.changeRate
|
||||||
|
readonly property string iconName: root.percentage < 30 ? "battery-low.svg" : root.percentage < 70 ? "battery-medium.svg" : "battery-full.svg"
|
||||||
|
readonly property url icon: `${Quickshell.shellPath("assets")}/icons/${root.iconName}`
|
||||||
|
}
|
||||||
26
services/Cava.qml
Normal file
26
services/Cava.qml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property string configPath: {
|
||||||
|
const url = Quickshell.shellPath("assets/cava.conf").toString();
|
||||||
|
return url.startsWith("file://") ? decodeURIComponent(url.substring(7)) : url;
|
||||||
|
}
|
||||||
|
property var values: []
|
||||||
|
|
||||||
|
Process {
|
||||||
|
running: true
|
||||||
|
command: ["cava", "-p", root.configPath]
|
||||||
|
|
||||||
|
stdout: SplitParser {
|
||||||
|
onRead: line => {
|
||||||
|
root.values = line.split(";").map(Number).filter(v => !Number.isNaN(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
|
import qs.windows
|
||||||
|
|
||||||
Scope {
|
Scope {
|
||||||
Bar {}
|
Bar {}
|
||||||
|
|||||||
46
ui/BarButton.qml
Normal file
46
ui/BarButton.qml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import qs.config
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string label: ""
|
||||||
|
property url iconSource: ""
|
||||||
|
property bool iconOnly: false
|
||||||
|
property bool hoverHighlight: true
|
||||||
|
property bool pointerCursor: true
|
||||||
|
|
||||||
|
padding: Appearance.padding
|
||||||
|
display: iconOnly ? AbstractButton.IconOnly : AbstractButton.TextBesideIcon
|
||||||
|
|
||||||
|
text: label
|
||||||
|
font.family: Appearance.font.family
|
||||||
|
font.pointSize: Appearance.font.pointSize
|
||||||
|
palette.buttonText: Appearance.colors.foreground
|
||||||
|
icon.color: Appearance.colors.foreground
|
||||||
|
icon.source: iconSource
|
||||||
|
|
||||||
|
HoverHandler {
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
enabled: root.pointerCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Appearance.radius
|
||||||
|
color: {
|
||||||
|
if (!root.hoverHighlight)
|
||||||
|
return Appearance.colors.inActive;
|
||||||
|
return root.hovered ? Appearance.colors.inActive : Appearance.colors.background;
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Appearance.duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
ui/ExclusionZone.qml
Normal file
12
ui/ExclusionZone.qml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
property string name
|
||||||
|
|
||||||
|
implicitWidth: 0
|
||||||
|
implicitHeight: 0
|
||||||
|
WlrLayershell.namespace: `quickshell:${name}ExclusionZone`
|
||||||
|
}
|
||||||
66
ui/RoundedCorner.qml
Normal file
66
ui/RoundedCorner.qml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import qs.config
|
||||||
|
|
||||||
|
WrapperItem {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int corner
|
||||||
|
property real radius: Appearance.radius
|
||||||
|
property color color
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
switch (corner) {
|
||||||
|
case 0:
|
||||||
|
anchors.left = parent.left;
|
||||||
|
anchors.top = parent.top;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
anchors.top = parent.top;
|
||||||
|
anchors.right = parent.right;
|
||||||
|
rotation = 90;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
anchors.right = parent.right;
|
||||||
|
anchors.bottom = parent.bottom;
|
||||||
|
rotation = 180;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
anchors.left = parent.left;
|
||||||
|
anchors.bottom = parent.bottom;
|
||||||
|
rotation = -90;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Shape {
|
||||||
|
preferredRendererType: Shape.CurveRenderer
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
strokeWidth: 0
|
||||||
|
fillColor: root.color
|
||||||
|
startX: root.radius
|
||||||
|
|
||||||
|
PathArc {
|
||||||
|
relativeX: -root.radius
|
||||||
|
relativeY: root.radius
|
||||||
|
radiusX: root.radius
|
||||||
|
radiusY: radiusX
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
|
||||||
|
PathLine {
|
||||||
|
relativeX: 0
|
||||||
|
relativeY: -root.radius
|
||||||
|
}
|
||||||
|
|
||||||
|
PathLine {
|
||||||
|
relativeX: root.radius
|
||||||
|
relativeY: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
158
windows/Bar.qml
Normal file
158
windows/Bar.qml
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import qs.config
|
||||||
|
import qs.ui
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: window
|
||||||
|
|
||||||
|
property color barColor: Appearance.colors.background
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
exclusionMode: ExclusionMode.Ignore
|
||||||
|
mask: Region {
|
||||||
|
item: cornersArea
|
||||||
|
intersection: Intersection.Subtract
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
left: true
|
||||||
|
top: true
|
||||||
|
right: true
|
||||||
|
bottom: true
|
||||||
|
}
|
||||||
|
|
||||||
|
component BarSection: Rectangle {
|
||||||
|
id: section
|
||||||
|
|
||||||
|
property var widgets: []
|
||||||
|
property int alignment: Qt.AlignLeft
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
implicitHeight: parent.height
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Row {
|
||||||
|
x: section.alignment === Qt.AlignLeft ? 0 : section.alignment === Qt.AlignRight ? parent.width - width : (parent.width - width) / 2
|
||||||
|
y: (section.height - height) / 2
|
||||||
|
spacing: Appearance.spacing
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: section.widgets
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
source: modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclusions
|
||||||
|
Scope {
|
||||||
|
ExclusionZone {
|
||||||
|
name: "left"
|
||||||
|
exclusiveZone: leftBar.implicitWidth
|
||||||
|
anchors.left: true
|
||||||
|
}
|
||||||
|
ExclusionZone {
|
||||||
|
name: "top"
|
||||||
|
exclusiveZone: topBar.implicitHeight
|
||||||
|
anchors.top: true
|
||||||
|
}
|
||||||
|
ExclusionZone {
|
||||||
|
name: "right"
|
||||||
|
exclusiveZone: rightBar.implicitWidth
|
||||||
|
anchors.right: true
|
||||||
|
}
|
||||||
|
ExclusionZone {
|
||||||
|
name: "bottom"
|
||||||
|
exclusiveZone: bottomBar.implicitHeight
|
||||||
|
anchors.bottom: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bars
|
||||||
|
Rectangle {
|
||||||
|
id: leftBar
|
||||||
|
|
||||||
|
implicitWidth: 10
|
||||||
|
implicitHeight: QsWindow.window?.height ?? 0
|
||||||
|
color: window.barColor
|
||||||
|
anchors.left: parent.left
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: rightBar
|
||||||
|
|
||||||
|
implicitWidth: 10
|
||||||
|
implicitHeight: QsWindow.window?.height ?? 0
|
||||||
|
color: window.barColor
|
||||||
|
anchors.right: parent.right
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: bottomBar
|
||||||
|
|
||||||
|
implicitWidth: QsWindow.window?.width ?? 0
|
||||||
|
implicitHeight: 10
|
||||||
|
color: window.barColor
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: topBar
|
||||||
|
|
||||||
|
implicitWidth: QsWindow.window?.width ?? 0
|
||||||
|
implicitHeight: 50
|
||||||
|
color: window.barColor
|
||||||
|
anchors.top: parent.top
|
||||||
|
|
||||||
|
FlexboxLayout {
|
||||||
|
id: flexLayout
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Appearance.margin
|
||||||
|
|
||||||
|
wrap: FlexboxLayout.Wrap
|
||||||
|
direction: FlexboxLayout.Row
|
||||||
|
justifyContent: FlexboxLayout.JustifySpaceBetween
|
||||||
|
|
||||||
|
BarSection {
|
||||||
|
widgets: BarLayout.left
|
||||||
|
alignment: Qt.AlignLeft
|
||||||
|
}
|
||||||
|
BarSection {
|
||||||
|
widgets: BarLayout.center
|
||||||
|
alignment: Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
BarSection {
|
||||||
|
widgets: BarLayout.right
|
||||||
|
alignment: Qt.AlignRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: cornersArea
|
||||||
|
|
||||||
|
implicitWidth: QsWindow.window?.width - (leftBar.implicitWidth + rightBar.implicitWidth)
|
||||||
|
implicitHeight: QsWindow.window?.height - (topBar.implicitHeight + bottomBar.implicitHeight)
|
||||||
|
color: "transparent"
|
||||||
|
x: leftBar.implicitWidth
|
||||||
|
y: topBar.implicitHeight
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: 4
|
||||||
|
|
||||||
|
RoundedCorner {
|
||||||
|
required property int modelData
|
||||||
|
|
||||||
|
corner: modelData
|
||||||
|
color: window.barColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user