still broken but getting there

This commit is contained in:
kossLAN 2025-08-05 12:12:32 -04:00
parent 189144099b
commit 446d83ce2c
Signed by: kossLAN
SSH key fingerprint: SHA256:bdV0x+wdQHGJ6LgmstH3KV8OpWY+OOFmJcPcB0wQPV8
20 changed files with 143 additions and 1219 deletions

3
.gitignore vendored
View file

@ -1,2 +1 @@
.stfolder ./shell/.qmlls.ini
.stversions

1
shell/.qmlls.ini Symbolic link
View file

@ -0,0 +1 @@
/run/user/1000/quickshell/vfs/99445c8565c70898bc0c842af0f02bb1/.qmlls.ini

View file

@ -12,17 +12,15 @@ Singleton {
FileView { FileView {
path: `${Quickshell.dataPath("settings")}/quickshell/settings.json` path: `${Quickshell.dataPath("settings")}/quickshell/settings.json`
watchChanges: true watchChanges: true
onFileChanged: reload() // onFileChanged: reload()
onAdapterUpdated: writeAdapter() // onAdapterUpdated: writeAdapter()
blockLoading: true blockLoading: true
JsonAdapter { JsonAdapter {
id: jsonAdapter id: jsonAdapter
property JsonObject settings: JsonObject { property JsonObject settings: JsonObject {
property string wallpaperUrl: Qt.resolvedUrl("root:resources/wallpapers/pixelart0.jpg") property string wallpaperUrl: Qt.resolvedUrl("root:resources/wallpapers/pixelart0.jpg")
property string colorScheme: "scheme-fruit-salad"
property string screenshotPath: "/home/koss/Pictures" property string screenshotPath: "/home/koss/Pictures"
property real opacity: 0.55 property real opacity: 0.55
} }
@ -32,73 +30,18 @@ Singleton {
} }
property JsonObject colors: JsonObject { property JsonObject colors: JsonObject {
property color surface: "#111111" property color surface: Qt.rgba(1.0, 1.0, 1.0, 1.0)
property color surface_container: "#191919" property color surface_translucent: Qt.rgba(0.0, 0.0, 0.0, 0.15)
property color primary: "#52DBCB" property color surface_container: Qt.rgba(0.25, 0.25, 0.25, 1.0)
property color active: "#FFFFFF" property color surface_container_translucent: Qt.rgba(0.25, 0.25, 0.25, 0.25)
property color inactive: "#6F6F6F" property color highlight: Qt.rgba(1.0, 1.0, 1.0, 0.85)
} // property color primary: "#2EADC6"
property color active: Qt.rgba(1.0, 1.0, 1.0, 1.0)
// property var colors: { property color active_translucent: Qt.rgba(1.0, 1.0, 1.0, 0.15)
// "surface": "#111111", property color border_translucent: Qt.rgba(1.0, 1.0, 1.0, 0.05)
// "surface_container": "#191919", property color inactive: Qt.rgba(0.25, 0.25, 0.25, 1.0)
// "primary": "#52DBCB", property color inactive_translucent: Qt.rgba(0.25, 0.25, 0.25, 0.15)
// "active": "#FFFFFF", }
// "inactive": "#6F6F6F",
// }
// property var colors: {
// "background": "#131313",
// "error": "#ffb4ab",
// "error_container": "#93000a",
// "inverse_on_surface": "#303030",
// "inverse_primary": "#9c4236",
// "inverse_surface": "#e2e2e2",
// "on_background": "#e2e2e2",
// "on_error": "#690005",
// "on_error_container": "#ffdad6",
// "on_primary": "#5f150d",
// "on_primary_container": "#ffdad4",
// "on_primary_fixed": "#410000",
// "on_primary_fixed_variant": "#7d2b21",
// "on_secondary": "#442925",
// "on_secondary_container": "#ffdad4",
// "on_secondary_fixed": "#2c1512",
// "on_secondary_fixed_variant": "#5d3f3b",
// "on_surface": "#e2e2e2",
// "on_surface_variant": "#c6c6c6",
// "on_tertiary": "#3e2e04",
// "on_tertiary_container": "#fbdfa6",
// "on_tertiary_fixed": "#251a00",
// "on_tertiary_fixed_variant": "#564419",
// "outline": "#919191",
// "outline_variant": "#474747",
// "primary": "#ffb4a8",
// "primary_container": "#7d2b21",
// "primary_fixed": "#ffdad4",
// "primary_fixed_dim": "#ffb4a8",
// "scrim": "#000000",
// "secondary": "#e7bdb6",
// "secondary_container": "#5d3f3b",
// "secondary_fixed": "#ffdad4",
// "secondary_fixed_dim": "#e7bdb6",
// "shadow": "#000000",
// "source_color": "#df4332",
// "surface": "#131313",
// "surface_bright": "#393939",
// "surface_container": "#1f1f1f",
// "surface_container_high": "#2a2a2a",
// "surface_container_highest": "#353535",
// "surface_container_low": "#1b1b1b",
// "surface_container_lowest": "#0e0e0e",
// "surface_dim": "#131313",
// "surface_tint": "#ffb4a8",
// "surface_variant": "#474747",
// "tertiary": "#dec38c",
// "tertiary_container": "#564419",
// "tertiary_fixed": "#fbdfa6",
// "tertiary_fixed_dim": "#dec38c"
// }
} }
} }
} }

View file

@ -5,7 +5,7 @@ import ".."
Text { Text {
id: windowText id: windowText
text: ToplevelManager.activeToplevel?.title ?? "" text: ToplevelManager.activeToplevel?.title ?? ""
color: ShellSettings.colors["inverse_surface"] color: ShellSettings.colors.active
font.pointSize: 11 font.pointSize: 11
visible: text !== "" visible: text !== ""
elide: Text.ElideRight elide: Text.ElideRight

View file

@ -1,18 +1,17 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
import "power" // import "power"
// import "volume" // import "volume"
import "systray" as SysTray import "systray"
import "popups" as Popup // import qs.widgets
import "../widgets" as Widgets import qs
import ".."
PanelWindow { PanelWindow {
id: root id: root
color: "transparent" color: "transparent"
implicitHeight: ShellSettings.sizing.barHeight implicitHeight: ShellSettings.sizing.barHeight
property alias popup: popupWindow property alias popup: popupHandler
anchors { anchors {
top: true top: true
@ -21,14 +20,12 @@ PanelWindow {
} }
Rectangle { Rectangle {
color: ShellSettings.colors.surface color: ShellSettings.colors.surface_translucent
opacity: 0.15
anchors.fill: parent anchors.fill: parent
} }
// Popup window for all popups PopupHandler {
Popup.MenuWindow { id: popupHandler
id: popupWindow
bar: root bar: root
} }
@ -47,15 +44,15 @@ PanelWindow {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
// HyprWorkspaces { Workspaces {
// screen: root.screen screen: root.screen
// Layout.fillHeight: true Layout.fillHeight: true
// } }
// ActiveWindow { ActiveWindow {
// id: activeWindow id: activeWindow
// Layout.preferredWidth: 400 Layout.preferredWidth: 400
// } }
} }
// Right side of bar // Right side of bar
@ -65,10 +62,10 @@ PanelWindow {
Layout.fillHeight: true Layout.fillHeight: true
Layout.alignment: Qt.AlignRight Layout.alignment: Qt.AlignRight
SysTray.SysTray { SysTray {
id: sysTray id: sysTray
// popup: root.popup popup: root.popup
bar: root // bar: root
Layout.fillHeight: true Layout.fillHeight: true
} }
@ -94,7 +91,7 @@ PanelWindow {
Clock { Clock {
id: clock id: clock
color: ShellSettings.colors["active"] color: ShellSettings.colors.active
} }
} }
} }

View file

@ -2,8 +2,7 @@ import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.Widgets import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Effects import qs
import "../.."
PopupWindow { PopupWindow {
id: root id: root
@ -37,8 +36,6 @@ PopupWindow {
let itemPos = item.mapToItem(root.bar.contentItem, 0, root.bar.height, item.width, 0).x; let itemPos = item.mapToItem(root.bar.contentItem, 0, root.bar.height, item.width, 0).x;
position(itemPos); position(itemPos);
// popupContainer.opacity = 0;
// popupContent.opacity = 0;
popupContainer.visible = false; popupContainer.visible = false;
} }
@ -67,16 +64,12 @@ PopupWindow {
isOpen = true; isOpen = true;
root.visible = true; // set and leave open root.visible = true; // set and leave open
root.content.visible = true; root.content.visible = true;
// popupContainer.opacity = 1;
// popupContent.opacity = 1;
popupContainer.visible = true; popupContainer.visible = true;
} }
function hide() { function hide() {
grab.active = false; grab.active = false;
isOpen = false; isOpen = false;
// popupContainer.opacity = 0;
// popupContent.opacity = 0;
popupContainer.visible = false; popupContainer.visible = false;
root.item = undefined; root.item = undefined;
@ -92,18 +85,8 @@ PopupWindow {
} }
} }
// RectangularShadow {
// radius: popupContainer.radius
// anchors.fill: popupContainer
// opacity: popupContainer.opacity
// visible: popupContainer.visible
// blur: 10
// spread: 2
// }
Rectangle { Rectangle {
color: ShellSettings.colors.surface color: ShellSettings.colors.surface_translucent
// opacity: ShellSettings.settings.opacity
opacity: 0.15 opacity: 0.15
radius: 12 radius: 12
anchors.fill: popupContainer anchors.fill: popupContainer
@ -112,19 +95,9 @@ PopupWindow {
WrapperItem { WrapperItem {
id: popupContainer id: popupContainer
// color: ShellSettings.colors.surface
// radius: 12
margin: 8 margin: 8
clip: true clip: true
// opacity: 0.5
// visible: opacity > 0
x: root.bar.width x: root.bar.width
// spooky, likely to cause problems lol
width: implicitWidth
height: implicitHeight
onVisibleChanged: root.visible = visible onVisibleChanged: root.visible = visible
// needed to handle occurences where items are resized while open // needed to handle occurences where items are resized while open
@ -140,27 +113,7 @@ PopupWindow {
id: popupContent id: popupContent
implicitWidth: Math.max(root.content?.width, 60) implicitWidth: Math.max(root.content?.width, 60)
implicitHeight: Math.max(childrenRect.height, 60) implicitHeight: Math.max(childrenRect.height, 60)
Behavior on opacity {
NumberAnimation {
duration: 200
easing.type: Easing.InOutQuad
from: 0
to: 1
} }
}
}
// broken for elements in the popup that have hover/mousearea's
// HoverHandler {
// id: hover
// enabled: true
// acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
// onHoveredChanged: {
// if (hovered == false)
// root.hide();
// }
// }
HyprlandFocusGrab { HyprlandFocusGrab {
id: grab id: grab
@ -169,35 +122,5 @@ PopupWindow {
root.hide(); root.hide();
} }
} }
// Behavior on opacity {
// NumberAnimation {
// duration: 200
// easing.type: Easing.Linear
// }
// }
Behavior on width {
enabled: root.isOpen
SmoothedAnimation {
duration: 200
easing.type: Easing.InOutQuad
}
}
Behavior on height {
SmoothedAnimation {
duration: 200
easing.type: Easing.InOutQuad
}
}
Behavior on x {
enabled: root.isOpen
SmoothedAnimation {
duration: 200
easing.type: Easing.InOutQuad
}
}
} }
} }

View file

@ -2,7 +2,7 @@ import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import ".." import qs
RowLayout { RowLayout {
spacing: 6 spacing: 6
@ -14,15 +14,27 @@ RowLayout {
id: workspaceButtons id: workspaceButtons
model: ScriptModel { model: ScriptModel {
values: Hyprland.workspaces.values.slice().filter( values: Hyprland.workspaces.values.slice().filter(workspace => workspace.monitor === Hyprland.monitorFor(screen))
workspace => workspace.monitor === Hyprland.monitorFor(screen)
)
} }
Rectangle { Rectangle {
required property var modelData
radius: height / 2 radius: height / 2
color: {
let value = ShellSettings.colors.active_translucent;
if (!modelData?.id || !Hyprland.focusedMonitor?.activeWorkspace?.id)
return value;
if (workspaceButton.containsMouse) {
value = ShellSettings.colors.highlight;
} else if (Hyprland.focusedMonitor.activeWorkspace.id === modelData.id) {
value = ShellSettings.colors.highlight;
}
return value;
}
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
Layout.preferredHeight: 12 Layout.preferredHeight: 12
Layout.preferredWidth: { Layout.preferredWidth: {
@ -32,20 +44,7 @@ RowLayout {
return 12; return 12;
} }
color: { required property var modelData
let value = Qt.color(ShellSettings.colors["secondary"]).darker(2);
if (!modelData?.id || !Hyprland.focusedMonitor?.activeWorkspace?.id)
return value;
if (workspaceButton.containsMouse) {
value = ShellSettings.colors["on_primary"];
} else if (Hyprland.focusedMonitor.activeWorkspace.id === modelData.id) {
value = ShellSettings.colors["primary"];
}
return value;
}
Behavior on Layout.preferredWidth { Behavior on Layout.preferredWidth {
SmoothedAnimation { SmoothedAnimation {

View file

@ -1,33 +0,0 @@
import Quickshell
import QtQuick
import "../../widgets/" as Widgets
Widgets.IconButton {
id: root
required property var bar
required property var screen
implicitSize: 20
source: "root:/resources/general/nixos.svg"
padding: 2
onClicked: {
if (controlPanel.visible) {
controlPanel.hide();
} else {
controlPanel.show();
}
}
ControlPanel {
id: controlPanel
anchor {
window: root.screen
onAnchoring: {
anchor.rect = mapToItem(root.screen.contentItem, 0, root.screen.height, width, 0);
}
}
}
}

View file

@ -1,308 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import Quickshell.Services.Mpris
import Qt5Compat.GraphicalEffects
import "volume" as Volume
import "../../widgets/" as Widgets
import "../.."
// Change to PopupWindow
PopupWindow {
id: root
implicitWidth: 400
implicitHeight: container.height + 10
color: "transparent"
visible: container.opacity > 0
anchor.rect.x: 0
anchor.rect.y: parentWindow.implicitHeight
// anchors {
// top: true
// left: true
// }
function show() {
container.opacity = 1;
grab.active = true;
}
function hide() {
container.opacity = 0;
grab.active = false;
}
HyprlandFocusGrab {
id: grab
windows: [root]
onCleared: {
root.hide();
}
}
// Add drop shadow effect
// Rectangle {
// id: shadowSource
// color: ShellSettings.colors["surface"]
// radius: 8
// opacity: container.opacity
// width: container.width
// height: container.height
//
// anchors {
// top: parent.top
// left: parent.left
// margins: 5
// }
//
// layer.enabled: true
// layer.effect: DropShadow {
// horizontalOffset: 0
// verticalOffset: 2
// radius: 8.0
// samples: 17
// color: Qt.rgba(0, 0, 0, 0.5)
// transparentBorder: true
// }
// visible: false // Hide the source rectangle
// }
Item {
id: shadowItem
anchors.fill: container
z: container.z - 1
opacity: container.opacity
Rectangle {
id: shadowRect
anchors.fill: parent
color: "transparent"
layer.enabled: true
layer.effect: DropShadow {
horizontalOffset: 0
verticalOffset: 2
radius: 8.0
samples: 17
color: Qt.rgba(0, 0, 0, 0.5)
source: container
}
}
}
Rectangle {
id: container
color: ShellSettings.colors["surface"]
radius: 18
opacity: 0
width: parent.width - 10
height: contentColumn.implicitHeight + 20
anchors {
top: parent.top
left: parent.left
margins: 5
}
Behavior on opacity {
NumberAnimation {
duration: 300
easing.type: Easing.OutCubic
}
}
ColumnLayout {
id: contentColumn
spacing: 10
anchors {
top: parent.top
left: parent.left
right: parent.right
margins: 10
}
// RowLayout {
// Layout.fillWidth: true
// Layout.preferredHeight: 40
//
// Rectangle {
// radius: 20
// color: ShellSettings.colors["surface_container_high"]
// Layout.fillWidth: true
// Layout.fillHeight: true
//
// RowLayout {
// anchors {
// fill: parent
// leftMargin: 6
// }
//
// ProfileImage {
// id: profileImage
// Layout.preferredWidth: 25
// Layout.preferredHeight: 25
// // implicitWidth: 30
// // implicitHeight: 30
// }
//
// Text {
// text: "kossLAN"
// color: ShellSettings.colors["inverse_surface"]
// font.pointSize: 12
// verticalAlignment: Text.AlignVCenter
// Layout.fillWidth: true
// Layout.fillHeight: true
// Layout.margins: 4
// }
// }
// }
//
// Rectangle {
// radius: 20
// color: ShellSettings.colors["surface_container_high"]
// Layout.preferredWidth: powerButtons.implicitWidth + 10
// Layout.fillHeight: true
//
// RowLayout {
// id: powerButtons
// spacing: 10
//
// anchors {
// fill: parent
// leftMargin: 5
// rightMargin: 5
// }
//
// Widgets.IconButton {
// id: sleepButton
// implicitSize: 24
// radius: 20
// source: "root:resources/control/sleep.svg"
// onClicked: sleepProcess.running = true
// }
//
// Process {
// id: sleepProcess
// running: false
// command: ["hyprctl", "dispatch", "dpms", "off"]
// }
//
// Rectangle {
// radius: 20
// color: ShellSettings.colors["surface_bright"]
// Layout.preferredWidth: 2
// Layout.fillHeight: true
// Layout.topMargin: 4
// Layout.bottomMargin: 4
// }
//
// Widgets.IconButton {
// id: powerButton
// implicitSize: 24
// radius: 20
// source: "root:resources/control/shutdown.svg"
// }
// }
// }
// }
RowLayout {
spacing: 15
Layout.fillWidth: true
Rectangle {
color: ShellSettings.colors["surface_container_high"]
radius: 12
Layout.fillWidth: true
Layout.preferredHeight: 30
}
}
RowLayout {
spacing: 15
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Repeater {
model: [1, 2, 3, 4, 5]
delegate: Rectangle {
color: ShellSettings.colors["surface_container_high"]
radius: width / 2
Layout.preferredWidth: 45
Layout.preferredHeight: 45
}
}
}
ColumnLayout {
spacing: 10
Layout.fillWidth: true
RowLayout {
spacing: 10
Layout.fillWidth: true
Layout.preferredHeight: 55
Rectangle {
color: ShellSettings.colors["primary"]
radius: width / 2
Layout.fillWidth: true
Layout.fillHeight: true
}
Rectangle {
color: ShellSettings.colors["primary"]
radius: width / 2
Layout.fillWidth: true
Layout.fillHeight: true
}
}
RowLayout {
spacing: 10
Layout.fillWidth: true
Layout.preferredHeight: 55
Rectangle {
color: ShellSettings.colors["surface_container_high"]
radius: width / 2
Layout.fillWidth: true
Layout.fillHeight: true
}
Rectangle {
color: ShellSettings.colors["surface_container_high"]
radius: width / 2
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
Volume.Mixer {
id: sinkMixer
isSink: true
Layout.fillWidth: true
}
Volume.Mixer {
id: sourceMixer
isSink: false
Layout.fillWidth: true
}
MediaPlayer {
player: Mpris.players?.values[0]
visible: Mpris.players?.values.length != 0
Layout.fillWidth: true
Layout.preferredHeight: 150
}
}
}
}

View file

@ -1,248 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import Quickshell.Services.Mpris
import "../.."
import "../../widgets" as Widgets
Item {
id: root
required property var player
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: root.width
height: root.height
radius: 14
color: "black"
}
}
ColorQuantizer {
id: gradientQuantizer
source: root.player?.trackArtUrl ?? ""
depth: 2
rescaleSize: 64
}
ColorQuantizer {
id: accentQuantizer
source: root.player?.trackArtUrl ?? ""
depth: 0
rescaleSize: 64
}
ShaderEffect {
property color topLeftColor: gradientQuantizer?.colors[0] ?? "white"
property color topRightColor: gradientQuantizer?.colors[1] ?? "black"
property color bottomLeftColor: gradientQuantizer?.colors[2] ?? "white"
property color bottomRightColor: gradientQuantizer?.colors[3] ?? "black"
anchors.fill: parent
fragmentShader: "root:/shaders/vertexgradient.frag.qsb"
vertexShader: "root:/shaders/vertexgradient.vert.qsb"
Behavior on topLeftColor {
ColorAnimation {
duration: 500
easing.type: Easing.InOutQuad
}
}
Behavior on topRightColor {
ColorAnimation {
duration: 500
easing.type: Easing.InOutQuad
}
}
Behavior on bottomLeftColor {
ColorAnimation {
duration: 500
easing.type: Easing.InOutQuad
}
}
Behavior on bottomRightColor {
ColorAnimation {
duration: 500
easing.type: Easing.InOutQuad
}
}
}
RowLayout {
id: cardLayout
spacing: 15
anchors {
fill: parent
margins: 10
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 5
RowLayout {
Rectangle {
id: mprisImage
color: "transparent"
radius: 10
width: 50
height: 50
Layout.alignment: Qt.AlignVCenter
visible: true
layer.enabled: true
layer.effect: DropShadow {
transparentBorder: true
spread: 0.02
samples: 25
color: "#80000000"
}
Image {
anchors.fill: parent
source: root.player?.trackArtUrl ?? ""
sourceSize.width: 1024
sourceSize.height: 1024
fillMode: Image.PreserveAspectFit
layer.enabled: true
layer.effect: OpacityMask {
source: Rectangle {
width: mprisImage.width
height: mprisImage.height
radius: 10
color: "white"
}
maskSource: Rectangle {
width: mprisImage.width
height: mprisImage.height
radius: 10
color: "black"
}
}
}
}
ColumnLayout {
Layout.leftMargin: 7.5
Layout.alignment: Qt.AlignBottom
Text {
text: root.player?.trackArtist ?? "NA"
color: "white"
font.pointSize: 13
font.bold: true
horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true
elide: Text.ElideRight
}
Text {
text: root.player?.trackTitle ?? "NA"
color: "white"
font.pointSize: 13
horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true
elide: Text.ElideRight
}
}
}
RowLayout {
spacing: 6
Text {
text: timeStr(root.player?.position)
color: "white"
font {
pointSize: 9
bold: true
}
}
FrameAnimation {
running: root.player?.playbackState == MprisPlaybackState.Playing
onTriggered: root.player?.positionChanged()
}
Widgets.RoundSlider {
id: positionSlider
implicitHeight: 7
from: 0
to: root.player?.length
accentColor: accentQuantizer.colors[0]?.darker(1.2) ?? "purple"
value: root.player?.position ?? 0
Layout.fillWidth: true
onMoved: {
if (root.player == null)
return;
root.player.position = value;
}
}
Text {
text: timeStr(root.player?.length)
color: "white"
font {
pointSize: 9
bold: true
}
}
}
// Music Controls
RowLayout {
spacing: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Widgets.IconButton {
implicitSize: 40
activeRectangle: false
padding: 4
source: "root:resources/mpris/previous.svg"
onClicked: root.player?.previous()
}
Widgets.IconButton {
implicitSize: 40
activeRectangle: false
padding: 4
source: root.player?.isPlaying ? "root:resources/mpris/pause.svg" : "root:resources/mpris/play.svg"
onClicked: {
if (!root.player?.canPlay)
return;
player.isPlaying ? player.pause() : player.play();
}
}
Widgets.IconButton {
implicitSize: 40
activeRectangle: false
padding: 4
source: "root:resources/mpris/next.svg"
onClicked: root.player?.next()
}
}
}
}
function timeStr(time: int): string {
const seconds = time % 60;
const minutes = Math.floor(time / 60);
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
}
}

View file

@ -1,33 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import Qt5Compat.GraphicalEffects
Rectangle {
id: profileImage
color: "transparent"
Image {
anchors.fill: parent
source: "root:resources/general/pfp.png"
sourceSize.width: 100
sourceSize.height: 100
layer.enabled: true
layer.effect: OpacityMask {
source: Rectangle {
width: profileImage.width
height: profileImage.height
radius: 10
color: "white"
}
maskSource: Rectangle {
width: profileImage.width
height: profileImage.height
radius: 10
color: "black"
}
}
}
}

View file

@ -1,79 +0,0 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Pipewire
import "../../.."
import "../../../widgets" as Widgets
Rectangle {
id: root
required property PwNode node
required property var isSink
color: ShellSettings.colors["surface_container_high"]
PwObjectTracker {
id: defaultSourceTracker
objects: [root.node]
}
RowLayout {
anchors.fill: parent
spacing: 8
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: 2
spacing: 10
Text {
color: ShellSettings.colors["inverse_surface"]
text: {
// Taken from quickshell-examples
const app = root.node?.properties["application.name"] ?? (root.node?.description != "" ? root.node?.description : root.node?.name);
const media = root.node?.properties["media.name"];
const title = media != undefined ? `${app} - ${media}` : app;
return title != undefined ? title : "null";
}
font.bold: true
elide: Text.ElideRight
Layout.fillWidth: true
Layout.topMargin: 5
Layout.rightMargin: 5
}
Widgets.RoundSlider {
implicitHeight: 7
from: 0
to: 1
value: root.node?.audio.volume ?? 0
onValueChanged: root.node.audio.volume = value
Layout.fillWidth: true
Layout.bottomMargin: 7.5
}
}
Widgets.IconButton {
source: {
if (!root.isSink)
return root.node?.audio.muted ? "root:resources/volume/microphone-mute.svg" : "root:resources/volume/microphone-full.svg";
return root.node?.audio.muted ? "root:resources/volume/volume-mute.svg" : "root:resources/volume/volume-full.svg";
}
implicitSize: 36
padding: 4
radius: implicitSize / 2
Layout.rightMargin: 10
Layout.alignment: Qt.AlignLeft
onClicked: {
root.node.audio.muted = !root.node.audio.muted;
}
}
}
}

View file

@ -1,176 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell.Widgets
import Quickshell.Services.Pipewire
import "../../../widgets/" as Widgets
import "../../.."
// TODO: refactor this trash
Rectangle {
id: root
required property var isSink
color: "transparent"
radius: 10
property bool expanded: false
property int baseHeight: 60
property int contentHeight: expanded ? (applicationVolumes.count * baseHeight) : 0
implicitHeight: baseHeight + contentHeight
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: root.width
height: root.height
radius: root.baseHeight / 2
color: "black"
}
}
Item {
id: headerSection
width: parent.width
height: root.baseHeight
anchors.top: parent.top
RowLayout {
spacing: 0
anchors.fill: parent
Rectangle {
color: ShellSettings.colors["surface_container_high"]
Widgets.IconButton {
id: arrowButton
implicitSize: 44
activeRectangle: false
source: "root:resources/general/right-arrow.svg"
padding: 4
rotation: root.expanded ? 90 : 0
anchors.centerIn: parent
Behavior on rotation {
NumberAnimation {
duration: 150
easing.type: Easing.OutCubic
}
}
onClicked: {
root.expanded = !root.expanded;
}
}
Layout.preferredWidth: 40
Layout.preferredHeight: root.baseHeight
}
Card {
node: root.isSink ? Pipewire.defaultAudioSink : Pipewire.defaultAudioSource
isSink: root.isSink
Layout.fillWidth: true
Layout.preferredHeight: root.baseHeight
}
}
}
Rectangle {
id: divider
color: ShellSettings.colors["surface_bright"]
height: 2
width: parent.width
anchors.top: headerSection.bottom
opacity: root.expanded ? 1.0 : 0.0
// Behavior on opacity {
// NumberAnimation {
// duration: 150
// easing.type: Easing.OutCubic
// }
// }
}
Item {
id: contentSection
width: parent.width
anchors.top: divider.bottom
height: root.contentHeight
clip: true
// Behavior on height {
// SmoothedAnimation {
// duration: 150
// velocity: 200
// easing.type: Easing.OutCubic
// }
// }
Column {
id: applicationsColumn
width: parent.width
anchors.top: parent.top
opacity: root.expanded ? 1.0 : 0.0
// Behavior on opacity {
// NumberAnimation {
// duration: 100
// easing.type: Easing.OutCubic
// }
// }
PwNodeLinkTracker {
id: linkTracker
node: root.isSink ? Pipewire.defaultAudioSink : Pipewire.defaultAudioSource
}
Repeater {
id: applicationVolumes
model: linkTracker.linkGroups
delegate: RowLayout {
id: cardRow
required property PwLinkGroup modelData
spacing: 0
width: applicationsColumn.width
height: root.baseHeight
Rectangle {
color: ShellSettings.colors["surface_container_high"]
IconImage {
implicitSize: 32
source: {
if (cardRow.modelData.source?.properties["application.icon-name"] == null) {
return "root:resources/general/placeholder.svg";
}
return `image://icon/${cardRow.modelData.source?.properties["application.icon-name"]}`;
}
anchors {
fill: parent
leftMargin: 8
rightMargin: 8
}
}
Layout.preferredWidth: 40
Layout.preferredHeight: root.baseHeight
}
Card {
node: cardRow.modelData.source
isSink: root.isSink
Layout.fillWidth: true
Layout.preferredHeight: root.baseHeight
}
}
}
}
}
}

View file

@ -5,15 +5,14 @@ import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Widgets import Quickshell.Widgets
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
import "../../widgets" as Widgets import qs.widgets
RowLayout { RowLayout {
id: root id: root
spacing: 5 spacing: 5
visible: SystemTray.items.values.length > 0 visible: SystemTray.items.values.length > 0
// required property var popup required property var popup
required property var bar
Repeater { Repeater {
model: SystemTray.items model: SystemTray.items
@ -24,32 +23,29 @@ RowLayout {
Layout.fillHeight: true Layout.fillHeight: true
required property SystemTrayItem modelData required property SystemTrayItem modelData
Widgets.StyledMouseArea { StyledMouseArea {
id: trayButton id: trayButton
hoverEnabled: true hoverEnabled: true
onClicked: { onClicked: {
menuOpener.menu = trayField.modelData.menu; menuOpener.menu = trayField.modelData.menu;
if (trayMenu.visible) { if (root.popup.content == trayMenu) {
trayMenu.visible = false; root.popup.hide();
// root.popup.hide();
return; return;
} }
trayMenu.visible = true; root.popup.set(this, trayMenu);
root.popup.show();
// root.popup.set(this, trayMenu);
// root.popup.show();
} }
anchors { anchors {
fill: parent fill: parent
// margins: 2 margins: 2
} }
IconImage { IconImage {
id: trayIcon id: trayIcon
anchors.fill: parent
source: { source: {
// console.log(trayField.modelData.id); // console.log(trayField.modelData.id);
switch (trayField.modelData.id) { switch (trayField.modelData.id) {
@ -59,11 +55,6 @@ RowLayout {
return trayField.modelData.icon; return trayField.modelData.icon;
} }
} }
anchors {
fill: parent
margins: 2
}
} }
} }
@ -71,19 +62,13 @@ RowLayout {
id: menuOpener id: menuOpener
} }
Widgets.StyledPopup { WrapperItem {
id: trayMenu id: trayMenu
// visible: false visible: false
property var leftItem: false property var leftItem: false
property var rightItem: false property var rightItem: false
anchor {
window: root.bar
item: trayButton
margins.top: root.bar.height + 5
}
ColumnLayout { ColumnLayout {
id: menuContainer id: menuContainer
spacing: 2 spacing: 2

View file

@ -31,8 +31,7 @@ ColumnLayout {
return "transparent"; return "transparent";
if (entryArea.containsMouse) { if (entryArea.containsMouse) {
let base = ShellSettings.colors.active; return ShellSettings.colors.active_translucent;
return Qt.rgba(base.r, base.g, base.b, 0.15);
} }
return "transparent"; return "transparent";
@ -141,9 +140,15 @@ ColumnLayout {
WrapperRectangle { WrapperRectangle {
id: subTrayMenu id: subTrayMenu
color: ShellSettings.colors.surface_container color: ShellSettings.colors.surface_container_translucent
radius: 8 radius: 8
visible: false visible: false
border {
width: 1
color: ShellSettings.colors.active_translucent
}
Layout.fillWidth: true Layout.fillWidth: true
QsMenuOpener { QsMenuOpener {

View file

@ -1,7 +1,7 @@
import Quickshell import Quickshell
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import "../.." import qs
ColumnLayout { ColumnLayout {
id: root id: root
@ -12,8 +12,8 @@ ColumnLayout {
Rectangle { Rectangle {
visible: (root.modelData?.isSeparator ?? false) visible: (root.modelData?.isSeparator ?? false)
color: ShellSettings.colors.inactive color: ShellSettings.colors.inactive_translucent
opacity: 0.1 // opacity: 0.1
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 2 Layout.preferredHeight: 2
Layout.leftMargin: 8 Layout.leftMargin: 8

View file

@ -33,15 +33,10 @@ Scope {
onTriggered: root.shouldShowOsd = false onTriggered: root.shouldShowOsd = false
} }
// The OSD window will be created and destroyed based on shouldShowOsd.
// PanelWindow.visible could be set instead of using a loader, but using
// a loader will reduce the memory overhead when the window isn't open.
LazyLoader { LazyLoader {
active: root.shouldShowOsd active: root.shouldShowOsd
PanelWindow { PopupWindow {
anchors.right: true
margins.right: 5
implicitWidth: 50 implicitWidth: 50
implicitHeight: 275 implicitHeight: 275
color: "transparent" color: "transparent"
@ -51,124 +46,57 @@ Scope {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
radius: width / 2 radius: 8
color: ShellSettings.colors["surface"] color: {
let color = ShellSettings.colors["surface"];
ColumnLayout { return Qt.rgba(color.r, color.g, color.b, 0.8);
spacing: 10 }
RowLayout {
anchors { anchors {
fill: parent fill: parent
margins: 8 leftMargin: 10
rightMargin: 15
}
IconImage {
implicitSize: 30
source: "root:resources/volume/volume-full.svg"
} }
Rectangle { Rectangle {
radius: width / 2 id: sliderBackground
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: width implicitHeight: 10
radius: 20
color: {
let color = ShellSettings.colors["inverse_surface"];
return Qt.rgba(color.r, color.g, color.b, 0.5);
} }
Rectangle {
id: sliderContainer
color: "gray"
Layout.fillWidth: true
Layout.fillHeight: true
layer.enabled: true layer.enabled: true
layer.effect: OpacityMask { layer.effect: OpacityMask {
source: Rectangle {
width: sliderContainer.width
height: sliderContainer.height
radius: sliderContainer.width / 2
color: "white"
}
maskSource: Rectangle { maskSource: Rectangle {
width: sliderContainer.width width: sliderBackground.width
height: sliderContainer.height height: sliderBackground.height
radius: sliderContainer.width / 2 radius: sliderBackground.radius
color: "black" color: "black"
} }
} }
Rectangle { Rectangle {
radius: width / 2
color: ShellSettings.colors["primary"] color: ShellSettings.colors["primary"]
implicitHeight: Math.max(parent.width, parent.height * (Pipewire.defaultAudioSink?.audio.volume ?? 0))
anchors { anchors {
bottom: parent.bottom
left: parent.left left: parent.left
right: parent.right top: parent.top
bottom: parent.bottom
} }
// replace with material icon implicitWidth: parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0)
// IconImage {
// implicitSize: parent.width - 4
// source: "root:resources/volume/volume-full.svg"
//
// anchors {
// horizontalCenter: parent.horizontalCenter
// }
// }
} }
} }
} }
} }
// Rectangle {
// anchors.fill: parent
// radius: 8
// color: {
// let color = ShellSettings.colors["surface"];
// return Qt.rgba(color.r, color.g, color.b, 0.8);
// }
//
// RowLayout {
// anchors {
// fill: parent
// leftMargin: 10
// rightMargin: 15
// }
//
// IconImage {
// implicitSize: 30
// source: "root:resources/volume/volume-full.svg"
// }
//
// Rectangle {
// id: sliderBackground
// Layout.fillWidth: true
// implicitHeight: 10
// radius: 20
// color: {
// let color = ShellSettings.colors["inverse_surface"];
// return Qt.rgba(color.r, color.g, color.b, 0.5);
// }
//
// layer.enabled: true
// layer.effect: OpacityMask {
// maskSource: Rectangle {
// width: sliderBackground.width
// height: sliderBackground.height
// radius: sliderBackground.radius
// color: "black"
// }
// }
//
// Rectangle {
// color: ShellSettings.colors["primary"]
// anchors {
// left: parent.left
// top: parent.top
// bottom: parent.bottom
// }
//
// implicitWidth: parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0)
// }
// }
// }
// }
} }
} }
} }

View file

@ -1,6 +1,6 @@
import QtQuick import QtQuick
import Quickshell.Widgets import Quickshell.Widgets
import ".." import qs
Item { Item {
id: root id: root
@ -9,8 +9,8 @@ Item {
property var padding: 0 property var padding: 0
property var radius: 20 property var radius: 20
property var activeRectangle: true property var activeRectangle: true
property var color: ShellSettings.colors["inverse_surface"] property var color: ShellSettings.colors.inactive_translucent
property var activeColor: ShellSettings.colors["inverse_primary"] property var activeColor: ShellSettings.colors.active_translucent
signal clicked signal clicked
implicitWidth: implicitSize implicitWidth: implicitSize
@ -18,7 +18,7 @@ Item {
Rectangle { Rectangle {
id: iconBackground id: iconBackground
color: ShellSettings.colors["primary"] color: ShellSettings.colors.active_translucent
radius: root.radius radius: root.radius
visible: iconButton.containsMouse && root.activeRectangle visible: iconButton.containsMouse && root.activeRectangle
anchors.fill: parent anchors.fill: parent

View file

@ -1,5 +1,5 @@
import QtQuick import QtQuick
import ".." import qs
MouseArea { MouseArea {
id: root id: root
@ -7,7 +7,7 @@ MouseArea {
property real radius: width / 2 property real radius: width / 2
property bool checked: false property bool checked: false
property var activeColor: ShellSettings.colors["primary"] property var activeColor: ShellSettings.colors.active_translucent
property var inactiveColor: "transparent" property var inactiveColor: "transparent"
Rectangle { Rectangle {

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Widgets import Quickshell.Widgets
import Quickshell.Hyprland
import ".." import ".."
PopupWindow { PopupWindow {
@ -11,22 +12,42 @@ PopupWindow {
default property alias contentItem: container.children default property alias contentItem: container.children
function open() {
// root.anchor.rect.y = -root.implicitHeight;
root.visible = true;
grab.active = true;
// slideAnimation.start();
}
function hide() {
root.visible = false;
grab.active = false;
}
// PropertyAnimation {
// id: slideAnimation
// target: root.anchor.rect
// property: "y"
// from: -root.implicitHeight // Off-screen position
// to: 0 // On-screen position
// duration: 300 // Animation duration in milliseconds
// }
HyprlandFocusGrab {
id: grab
windows: [root]
onCleared: root.hide()
}
WrapperRectangle { WrapperRectangle {
id: container id: container
margin: 5 margin: 5
radius: 12 radius: 12
color: ShellSettings.colors.surface_translucent
color: {
let base = ShellSettings.colors.surface;
return Qt.rgba(base.r, base.g, base.b, 0.15);
}
border { border {
width: 1 width: 1
color: { color: ShellSettings.colors.active_translucent
let base = ShellSettings.colors.active;
return Qt.rgba(base.r, base.g, base.b, 0.05);
}
} }
} }
} }