first commit
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
.qmlls.ini
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Qt5Compat.GraphicalEffects
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import qs.Modules
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
Variants {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: bar
|
||||||
|
required property var modelData
|
||||||
|
screen: modelData
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
left: true
|
||||||
|
right: true
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitHeight: 34
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#801a1a1a"
|
||||||
|
radius: 0
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 5
|
||||||
|
anchors.rightMargin: 5
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: leftSection
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
|
||||||
|
Workspaces {
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.topMargin: 6
|
||||||
|
Layout.bottomMargin: 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: centerSection
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: rightSection
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||||
|
|
||||||
|
TrayWidget {
|
||||||
|
id: systemTrayModule
|
||||||
|
bar: bar
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Clock {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
SwayNC {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WindowTitle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: Math.min( 300, parent.width * 0.4 )
|
||||||
|
height: parent.height
|
||||||
|
z: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
property string activeWindow: Hyprland.activeToplevel?.lastIpcObject.class || ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
// CustomTrayMenu.qml
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick.Window // for Window, flags
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: popup
|
||||||
|
|
||||||
|
property QsMenuHandle menuHandle
|
||||||
|
property alias entries: menuModel
|
||||||
|
|
||||||
|
QsMenuOpener {
|
||||||
|
id: menu
|
||||||
|
menu: popup.menuHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
ListModel { id: menuModel }
|
||||||
|
|
||||||
|
implicitWidth: contentColumn.implicitWidth + 16
|
||||||
|
implicitHeight: contentColumn.implicitHeight + 16
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: "#202020CC"
|
||||||
|
radius: 4
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: contentColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 4
|
||||||
|
Repeater {
|
||||||
|
id: repeater
|
||||||
|
model: menuModel
|
||||||
|
Row {
|
||||||
|
id: entryRow
|
||||||
|
height: 30
|
||||||
|
width: parent.implicitWidth
|
||||||
|
property var entry: modelData
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
if (entryRow.entry.triggered) {
|
||||||
|
entryRow.entry.triggered()
|
||||||
|
}
|
||||||
|
popup.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
source: entryRow.entry.icon
|
||||||
|
width: 20; height: 20
|
||||||
|
visible: entryRow.entry.icon !== ""
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: entryRow.entry.text
|
||||||
|
color: "white"
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rebuild() {
|
||||||
|
menuModel.clear()
|
||||||
|
console.log(menu.children.count)
|
||||||
|
if (!menu) return
|
||||||
|
for (let i = 0; i < menu.children.count; ++i) {
|
||||||
|
let e = menu.children.get(i)
|
||||||
|
menuModel.append({
|
||||||
|
text: e.text,
|
||||||
|
icon: e.icon,
|
||||||
|
triggered: e.triggered,
|
||||||
|
entryObject: e
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuHandleChanged: rebuild
|
||||||
|
Connections {
|
||||||
|
target: menu
|
||||||
|
function onCountChanged() {
|
||||||
|
popup.rebuild
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
implicitWidth: notificationButton.implicitWidth
|
||||||
|
implicitHeight: notificationButton.implicitHeight
|
||||||
|
|
||||||
|
property var notificationState: ({})
|
||||||
|
|
||||||
|
function updateState(output) {
|
||||||
|
try {
|
||||||
|
notificationState = JSON.parse(output.trim())
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to parse swaync state:", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIcon() {
|
||||||
|
let count = notificationState["text"] || 0
|
||||||
|
let hasNotification = count > 0
|
||||||
|
if (hasNotification) return "notification"
|
||||||
|
return "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDisplayText() {
|
||||||
|
let icon = getIcon()
|
||||||
|
let count = notificationState["count"] || 0
|
||||||
|
|
||||||
|
if (icon.includes("notification")) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: swayNcMonitor
|
||||||
|
running: true
|
||||||
|
command: ["swaync-client", "-swb"]
|
||||||
|
|
||||||
|
stdout: SplitParser {
|
||||||
|
onRead: data => root.updateState(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: swayncProcess
|
||||||
|
command: ["swaync-client", "-t", "-sw"]
|
||||||
|
running: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: notificationButton
|
||||||
|
flat: true
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
radius: 4
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.getDisplayText()
|
||||||
|
color: "white"
|
||||||
|
font.pixelSize: 16
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "●"
|
||||||
|
color: "red"
|
||||||
|
font.pixelSize: 6
|
||||||
|
visible: root.getIcon().includes("notification")
|
||||||
|
Layout.alignment: Qt.AlignTop | Qt.AlignRight
|
||||||
|
Layout.topMargin: 0
|
||||||
|
Layout.rightMargin: -6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
swayncProcess.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
import qs.Modules
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
id: root
|
||||||
|
required property SystemTrayItem item
|
||||||
|
property var customMenu
|
||||||
|
|
||||||
|
source: root.item.icon
|
||||||
|
implicitSize: 15
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onClicked: event => {
|
||||||
|
switch (event.button) {
|
||||||
|
case Qt.LeftButton: root.item.activate(); break;
|
||||||
|
case Qt.RightButton:
|
||||||
|
if (root.item.hasMenu) {
|
||||||
|
|
||||||
|
root.customMenu = menuComponent.createObject(root);
|
||||||
|
root.customMenu.menuHandle = root.item.menu;
|
||||||
|
|
||||||
|
const window = QsWindow.window;
|
||||||
|
const widgetRect = window.contentItem.mapFromItem(root, 0, root.height + 4, root.width, root.height);
|
||||||
|
root.customMenu.anchor.rect = widgetRect
|
||||||
|
root.customMenu.anchor.window = window
|
||||||
|
root.customMenu.anchor.adjustment = PopupAdjustment.Flip
|
||||||
|
root.customMenu.visible = true;
|
||||||
|
root.customMenu.rebuild();
|
||||||
|
// menuAnchor.anchor.rect = widgetRect;
|
||||||
|
// menuAnchor.open();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: menuComponent
|
||||||
|
CustomTrayMenu {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// QsMenuAnchor {
|
||||||
|
// id: menuAnchor
|
||||||
|
// menu: root.item.menu
|
||||||
|
// anchor.window: root.QsWindow.window?? null
|
||||||
|
// anchor.adjustment: PopupAdjustment.Flip
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
required property PanelWindow bar
|
||||||
|
implicitHeight: parent.height
|
||||||
|
implicitWidth: rowL.implicitWidth + 20
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: 10
|
||||||
|
id: rowL
|
||||||
|
anchors.centerIn: parent
|
||||||
|
Repeater {
|
||||||
|
model: SystemTray.items
|
||||||
|
TrayItem {
|
||||||
|
required property SystemTrayItem modelData
|
||||||
|
item: modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.preferredWidth: Math.max( titleText1.implicitWidth, titleText2.implicitWidth ) + 10
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
property string currentTitle: ActiveWindow.activeWindow
|
||||||
|
property bool showFirst: true
|
||||||
|
|
||||||
|
onCurrentTitleChanged: {
|
||||||
|
if (showFirst) {
|
||||||
|
titleText2.text = currentTitle
|
||||||
|
showFirst = false
|
||||||
|
} else {
|
||||||
|
titleText1.text = currentTitle
|
||||||
|
showFirst = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: titleText1
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 5
|
||||||
|
text: root.currentTitle
|
||||||
|
color: "white"
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pixelSize: 16
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
opacity: root.showFirst ? 1 : 0
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: titleText2
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 5
|
||||||
|
color: "white"
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.pixelSize: 16
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
opacity: root.showFirst ? 0 : 1
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
implicitWidth: workspacesRow.implicitWidth + 12
|
||||||
|
implicitHeight: workspacesRow.implicitHeight + 8
|
||||||
|
|
||||||
|
color: "#40000000"
|
||||||
|
radius: height / 2
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 100
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: workspacesRow
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: 6
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Hyprland.workspaces
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
width: 12
|
||||||
|
height: 12
|
||||||
|
radius: 6
|
||||||
|
|
||||||
|
color: modelData.id === Hyprland.focusedWorkspace.id ? "#4080ff" : "#606060"
|
||||||
|
|
||||||
|
border.color: modelData.id === Hyprland.focusedWorkspace.id ? "#60a0ff" : "#808080"
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
scale: 1.0
|
||||||
|
opacity: 1.0
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: 150
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on border.color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: 150
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation on scale {
|
||||||
|
from: 0.0
|
||||||
|
to: 1.0
|
||||||
|
duration: 300
|
||||||
|
easing.type: Easing.OutBack
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation on opacity {
|
||||||
|
from: 0.0
|
||||||
|
to: 1.0
|
||||||
|
duration: 200
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
Hyprland.dispatch("workspace " + modelData.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// Time.qml
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
readonly property string time: {
|
||||||
|
Qt.formatDateTime(clock.date, "ddd d MMM - hh:mm:ss")
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemClock {
|
||||||
|
id: clock
|
||||||
|
precision: SystemClock.Seconds
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user