progress save

This commit is contained in:
kossLAN 2025-08-10 01:41:30 -04:00
parent fa7d012416
commit d32bedda31
Signed by: kossLAN
SSH key fingerprint: SHA256:bdV0x+wdQHGJ6LgmstH3KV8OpWY+OOFmJcPcB0wQPV8
9 changed files with 293 additions and 249 deletions

View file

@ -7,13 +7,26 @@ import Quickshell.Io
Singleton { Singleton {
property alias settings: jsonAdapter.settings property alias settings: jsonAdapter.settings
property alias sizing: jsonAdapter.sizing property alias sizing: jsonAdapter.sizing
property alias colors: jsonAdapter.colors
property QtObject colors: QtObject {
property color surface: Qt.rgba(1.0, 1.0, 1.0, 1.0)
property color surface_translucent: Qt.rgba(0.0, 0.0, 0.0, 0.15)
property color surface_container: Qt.rgba(0.25, 0.25, 0.25, 1.0)
property color surface_container_translucent: Qt.rgba(0.25, 0.25, 0.25, 0.25)
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 color active_translucent: Qt.rgba(1.0, 1.0, 1.0, 0.15)
property color border_translucent: Qt.rgba(1.0, 1.0, 1.0, 0.05)
property color inactive: Qt.rgba(0.25, 0.25, 0.25, 1.0)
property color inactive_translucent: Qt.rgba(0.25, 0.25, 0.25, 0.15)
}
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 {
@ -28,20 +41,6 @@ Singleton {
property JsonObject sizing: JsonObject { property JsonObject sizing: JsonObject {
property int barHeight: 25 property int barHeight: 25
} }
property JsonObject colors: JsonObject {
property color surface: Qt.rgba(1.0, 1.0, 1.0, 1.0)
property color surface_translucent: Qt.rgba(0.0, 0.0, 0.0, 0.15)
property color surface_container: Qt.rgba(0.25, 0.25, 0.25, 1.0)
property color surface_container_translucent: Qt.rgba(0.25, 0.25, 0.25, 0.25)
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 color active_translucent: Qt.rgba(1.0, 1.0, 1.0, 0.15)
property color border_translucent: Qt.rgba(1.0, 1.0, 1.0, 0.05)
property color inactive: Qt.rgba(0.25, 0.25, 0.25, 1.0)
property color inactive_translucent: Qt.rgba(0.25, 0.25, 0.25, 0.15)
}
} }
} }
} }

View file

@ -7,91 +7,120 @@ import "systray"
// import qs.widgets // import qs.widgets
import qs import qs
PanelWindow { Variants {
id: root model: Quickshell.screens
color: "transparent"
implicitHeight: ShellSettings.sizing.barHeight
property alias popup: popupHandler
anchors { delegate: PanelWindow {
top: true id: root
left: true
right: true
}
Rectangle {
color: ShellSettings.colors.surface_translucent color: ShellSettings.colors.surface_translucent
anchors.fill: parent implicitHeight: ShellSettings.sizing.barHeight
} screen: modelData
PopupHandler { required property var modelData
id: popupHandler
bar: root
}
RowLayout {
spacing: 0
anchors { anchors {
fill: parent top: true
leftMargin: 5 left: true
rightMargin: 5 right: true
} }
// Left side of bar PopupHandler {
RowLayout { id: popupHandler
spacing: 15 bar: root
Layout.fillWidth: true
Layout.fillHeight: true
Workspaces {
screen: root.screen
Layout.fillHeight: true
}
ActiveWindow {
id: activeWindow
Layout.preferredWidth: 400
}
} }
// Right side of bar
RowLayout { RowLayout {
spacing: 10 spacing: 0
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignRight
SysTray { anchors {
id: sysTray fill: parent
popup: root.popup leftMargin: 5
// bar: root rightMargin: 5
Layout.fillHeight: true
} }
// VolumeIndicator { // Left side of bar
// id: volumeIndicator RowLayout {
// popup: root.popup spacing: 15
// Layout.preferredWidth: this.height Layout.fillWidth: true
// Layout.fillHeight: true Layout.fillHeight: true
// Layout.topMargin: 2
// Layout.bottomMargin: 2
// }
// BatteryIndicator { Workspaces {
// id: batteryIndicator screen: root.screen
// popup: root.popup Layout.fillHeight: true
// Layout.fillHeight: true }
// }
// Widgets.Separator { ActiveWindow {
// Layout.leftMargin: 5 id: activeWindow
// Layout.rightMargin: 5 Layout.preferredWidth: 400
// } }
}
Clock { // Right side of bar
id: clock RowLayout {
color: ShellSettings.colors.active spacing: 10
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignRight
SysTray {
id: sysTray
popup: popupHandler
Layout.fillHeight: true
}
PopupItem {
id: test
Layout.preferredWidth: 20
Layout.fillHeight: true
onClicked: {
popupHandler.set(test);
}
menu: Rectangle {
implicitWidth: 100
implicitHeight: 100
}
}
PopupItem {
id: test2
Layout.preferredWidth: 20
Layout.fillHeight: true
onClicked: {
popupHandler.set(test2);
}
menu: Rectangle {
implicitWidth: 200
implicitHeight: 200
}
}
// VolumeIndicator {
// id: volumeIndicator
// popup: root.popup
// Layout.preferredWidth: this.height
// Layout.fillHeight: true
// Layout.topMargin: 2
// Layout.bottomMargin: 2
// }
// BatteryIndicator {
// id: batteryIndicator
// Layout.fillHeight: true
// }
// Widgets.Separator {
// Layout.leftMargin: 5
// Layout.rightMargin: 5
// }
Clock {
id: clock
color: ShellSettings.colors.active
}
} }
} }
} }

View file

@ -1,10 +0,0 @@
import Quickshell
Variants {
model: Quickshell.screens
Bar {
required property var modelData
screen: modelData
}
}

View file

@ -1,17 +1,19 @@
pragma ComponentBehavior: Bound
import Quickshell import Quickshell
import Quickshell.Hyprland
import Quickshell.Widgets import Quickshell.Widgets
import Quickshell.Hyprland
import QtQuick import QtQuick
import qs import qs
PopupWindow { PopupWindow {
id: root id: root
visible: false
color: "transparent" color: "transparent"
implicitWidth: bar.width implicitWidth: bar.width
implicitHeight: Math.max(popupContainer.height, 800) + 20 implicitHeight: Math.max(1000, bar.height)
mask: Region { mask: Region {
item: popupContainer item: surface
} }
anchor { anchor {
@ -23,103 +25,126 @@ PopupWindow {
} }
required property var bar required property var bar
property var isOpen: false property var currentMenu
property var padding: 5 property real padding: 5
property var item
property var content
function set(item, content) { function set(item) {
root.item = item;
root.content = content; // Clear surface
popupContent.data = content; if (content.children.includes(item.menu)) {
console.log("Clearing popup surface.");
root.currentMenu = undefined;
content.children = [];
// surface.implicitHeight = 0;
surface.opacity = 0;
contentOpacity.restart();
grab.active = false;
return;
}
// Set surface
console.log("Setting popup surface.");
root.visible = true;
root.currentMenu = item.menu
content.children = [item.menu];
// content.implicitWidth = item.menu.implicitWidth;
// content.implicitHeight = item.menu.implicitHeight;
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);
popupContainer.visible = false; // Check right edge
} let rightEdge = itemPos + surface.implicitWidth;
function position(itemPos) {
if (itemPos === undefined)
return;
let rightEdge = itemPos + popupContainer.implicitWidth;
let maxRightEdge = root.width - padding; let maxRightEdge = root.width - padding;
let isTouchingRightEdge = rightEdge > maxRightEdge; let isTouchingRightEdge = rightEdge > maxRightEdge;
if (isTouchingRightEdge) { if (isTouchingRightEdge) {
// touching right edge, reposition // touching right edge, reposition
// console.log("touching right edge"); surface.x = maxRightEdge - surface.implicitWidth;
popupContainer.x = maxRightEdge - popupContainer.implicitWidth; surface.y = padding;
popupContainer.y = padding;
} else { } else {
// not touching right edge // not touching right edge
popupContainer.x = itemPos; surface.x = itemPos;
popupContainer.y = padding; surface.y = padding;
} }
}
function show() { surface.opacity = 1;
contentOpacity.restart();
grab.active = true; grab.active = true;
isOpen = true;
root.visible = true; // set and leave open
root.content.visible = true;
popupContainer.visible = true;
} }
function hide() { HyprlandFocusGrab {
grab.active = false; id: grab
isOpen = false; windows: [root, root.bar]
popupContainer.visible = false; onCleared: {
surface.opacity = 0;
root.item = undefined; contentOpacity.restart();
root.content = undefined; root.currentMenu = undefined;
popupContent.data = []; content.children = [];
}
function toggle() {
if (isOpen) {
hide();
} else {
show();
} }
} }
Rectangle { WrapperRectangle {
id: surface
opacity: 0
visible: opacity > 0
color: ShellSettings.colors.surface_translucent color: ShellSettings.colors.surface_translucent
opacity: 0.15
radius: 12
anchors.fill: popupContainer
border.color: ShellSettings.colors.active
}
WrapperItem {
id: popupContainer
margin: 8
clip: true clip: true
x: root.bar.width margin: 5
onVisibleChanged: root.visible = visible radius: 12
// needed to handle occurences where items are resized while open border {
onImplicitWidthChanged: { width: 1
if (root.isOpen && popupContent.data !== []) { color: ShellSettings.colors.active_translucent
// console.log("repositioning popup"); }
let itemPos = root.item.mapToItem(root.bar.contentItem, 0, root.bar.height, root.item.width, 0).x;
root.position(itemPos); // Animating implicit widht/height causes issues, this works but
// is kind of cursed, but fuck it. Better solutions welcome.
width: implicitWidth
height: implicitHeight
Item {
id: content
implicitWidth: Math.max(root.currentMenu?.width, 60)
implicitHeight: root.currentMenu?.height ?? 0
NumberAnimation {
id: contentOpacity
target: content
property: "opacity"
from: 0
to: 1
duration: 300
easing.type: Easing.InOutQuad
} }
} }
Item { Behavior on opacity {
id: popupContent NumberAnimation {
implicitWidth: Math.max(root.content?.width, 60) duration: 250
implicitHeight: Math.max(childrenRect.height, 60) easing.type: Easing.InOutQuad
}
} }
HyprlandFocusGrab { Behavior on width {
id: grab enabled: root.visible
windows: [root, root.bar] SmoothedAnimation {
onCleared: { duration: 250
root.hide(); easing.type: Easing.InOutQuad
}
}
Behavior on height {
SmoothedAnimation {
duration: 250
easing.type: Easing.InOutQuad
}
}
Behavior on x {
enabled: root.visible
SmoothedAnimation {
duration: 250
easing.type: Easing.InOutQuad
} }
} }
} }

8
shell/bar/PopupItem.qml Normal file
View file

@ -0,0 +1,8 @@
import QtQuick
import qs.widgets
StyledMouseArea {
id: root
property QtObject menu
}

View file

@ -26,7 +26,6 @@ Item {
} }
root.popup.set(this, powerMenu); root.popup.set(this, powerMenu);
root.popup.show();
} }
anchors { anchors {

View file

@ -2,95 +2,27 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
import qs.widgets import ".."
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 PopupHandler popup
Repeater { Repeater {
id: repeater
model: SystemTray.items model: SystemTray.items
delegate: Item { delegate: TrayMenuLauncher {
id: trayField id: trayItem
required property SystemTrayItem modelData
trayItem: modelData
popup: root.popup
Layout.preferredWidth: parent.height Layout.preferredWidth: parent.height
Layout.fillHeight: true Layout.fillHeight: true
required property SystemTrayItem modelData
StyledMouseArea {
id: trayButton
hoverEnabled: true
onClicked: {
menuOpener.menu = trayField.modelData.menu;
if (root.popup.content == trayMenu) {
root.popup.hide();
return;
}
root.popup.set(this, trayMenu);
root.popup.show();
}
anchors {
fill: parent
margins: 2
}
IconImage {
id: trayIcon
anchors.fill: parent
source: {
// console.log(trayField.modelData.id);
switch (trayField.modelData.id) {
case "obs":
return "image://icon/obs-tray";
default:
return trayField.modelData.icon;
}
}
}
}
QsMenuOpener {
id: menuOpener
}
WrapperItem {
id: trayMenu
visible: false
property var leftItem: false
property var rightItem: false
ColumnLayout {
id: menuContainer
spacing: 2
Repeater {
model: menuOpener.children
delegate: TrayMenuItem {
id: sysTrayContent
Layout.fillWidth: true
Layout.fillHeight: true
rootMenu: trayMenu
onInteracted: {
root.popup.hide();
menuOpener.menu = null;
}
}
}
}
}
} }
} }
} }

View file

@ -0,0 +1,62 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import Quickshell.Services.SystemTray
import ".."
PopupItem {
id: root
onClicked: {
menuOpener.menu = trayItem.menu;
popup.set(menu);
}
required property PopupHandler popup
required property SystemTrayItem trayItem
menu: ColumnLayout {
id: trayMenu
spacing: 2
// visible: false
property var leftItem: false
property var rightItem: false
Repeater {
model: menuOpener.children
delegate: TrayMenuItem {
id: sysTrayContent
Layout.fillWidth: true
Layout.fillHeight: true
rootMenu: trayMenu
onInteracted: {
menuOpener.menu = null;
}
}
}
}
QsMenuOpener {
id: menuOpener
}
IconImage {
id: trayIcon
anchors.fill: parent
source: {
// console.log(trayField.modelData.id);
switch (root.trayItem.id) {
case "obs":
return "image://icon/obs-tray";
default:
return root.trayItem.icon;
}
}
}
}

View file

@ -3,7 +3,7 @@
import Quickshell import Quickshell
import QtQuick import QtQuick
import "bar" as Bar import "bar"
import "notifications" as Notifications import "notifications" as Notifications
import "mpris" as Mpris import "mpris" as Mpris
import "volume-osd" as VolumeOSD import "volume-osd" as VolumeOSD
@ -14,7 +14,7 @@ import "wallpaper" as Wallpaper
import "screencapture" as ScreenCapture import "screencapture" as ScreenCapture
ShellRoot { ShellRoot {
Bar.Controller {} Bar {}
Wallpaper.Controller {} Wallpaper.Controller {}
Notifications.Controller {} Notifications.Controller {}
VolumeOSD.Controller {} VolumeOSD.Controller {}