TRAY
This commit is contained in:
@@ -3,28 +3,13 @@ pragma ComponentBehavior: Bound
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick.Window // for Window, flags
|
import QtQuick.Window // for Window, flags
|
||||||
|
import qs.Modules
|
||||||
|
|
||||||
PopupWindow {
|
PopupWindow {
|
||||||
id: popup
|
id: popup
|
||||||
|
color: "#FF202020"
|
||||||
|
|
||||||
property QsMenuHandle menuHandle
|
required property QsMenuOpener trayMenu
|
||||||
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 {
|
Column {
|
||||||
id: contentColumn
|
id: contentColumn
|
||||||
@@ -32,11 +17,10 @@ PopupWindow {
|
|||||||
spacing: 4
|
spacing: 4
|
||||||
Repeater {
|
Repeater {
|
||||||
id: repeater
|
id: repeater
|
||||||
model: menuModel
|
model: popup.trayMenu.children
|
||||||
Row {
|
Row {
|
||||||
id: entryRow
|
id: entryRow
|
||||||
height: 30
|
anchors.fill: parent
|
||||||
width: parent.implicitWidth
|
|
||||||
property var entry: modelData
|
property var entry: modelData
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -54,33 +38,10 @@ PopupWindow {
|
|||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: entryRow.entry.text
|
text: entryRow.entry.text
|
||||||
color: "white"
|
color: "black"
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-25
@@ -2,12 +2,10 @@ import QtQuick
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import Quickshell.Services.SystemTray
|
import Quickshell.Services.SystemTray
|
||||||
import qs.Modules
|
|
||||||
|
|
||||||
IconImage {
|
IconImage {
|
||||||
id: root
|
id: root
|
||||||
required property SystemTrayItem item
|
required property SystemTrayItem item
|
||||||
property var customMenu
|
|
||||||
|
|
||||||
source: root.item.icon
|
source: root.item.icon
|
||||||
implicitSize: 15
|
implicitSize: 15
|
||||||
@@ -19,34 +17,19 @@ IconImage {
|
|||||||
case Qt.LeftButton: root.item.activate(); break;
|
case Qt.LeftButton: root.item.activate(); break;
|
||||||
case Qt.RightButton:
|
case Qt.RightButton:
|
||||||
if (root.item.hasMenu) {
|
if (root.item.hasMenu) {
|
||||||
|
|
||||||
root.customMenu = menuComponent.createObject(root);
|
|
||||||
root.customMenu.menuHandle = root.item.menu;
|
|
||||||
|
|
||||||
const window = QsWindow.window;
|
const window = QsWindow.window;
|
||||||
const widgetRect = window.contentItem.mapFromItem(root, 0, root.height + 4, root.width, root.height);
|
const widgetRect = window.contentItem.mapFromItem(root, 0, root.height + 10 , root.width, root.height);
|
||||||
root.customMenu.anchor.rect = widgetRect
|
menuAnchor.anchor.rect = widgetRect;
|
||||||
root.customMenu.anchor.window = window
|
menuAnchor.open();
|
||||||
root.customMenu.anchor.adjustment = PopupAdjustment.Flip
|
|
||||||
root.customMenu.visible = true;
|
|
||||||
root.customMenu.rebuild();
|
|
||||||
// menuAnchor.anchor.rect = widgetRect;
|
|
||||||
// menuAnchor.open();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
QsMenuAnchor {
|
||||||
Component {
|
id: menuAnchor
|
||||||
id: menuComponent
|
menu: root.item.menu
|
||||||
CustomTrayMenu {}
|
anchor.window: root.QsWindow.window?? null
|
||||||
|
anchor.adjustment: PopupAdjustment.Flip
|
||||||
}
|
}
|
||||||
|
|
||||||
// QsMenuAnchor {
|
|
||||||
// id: menuAnchor
|
|
||||||
// menu: root.item.menu
|
|
||||||
// anchor.window: root.QsWindow.window?? null
|
|
||||||
// anchor.adjustment: PopupAdjustment.Flip
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
import qs.Data as Dat
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
property var current: (true) ? dark : light
|
||||||
|
property alias dark: dark
|
||||||
|
property alias light: light
|
||||||
|
|
||||||
|
function withAlpha(color: color, alpha: real): color {
|
||||||
|
return Qt.rgba(color.r, color.g, color.b, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
path: {
|
||||||
|
const colors_location = (Quickshell.env("KURU_COLORS"));
|
||||||
|
if (colors_location) {
|
||||||
|
colors_location;
|
||||||
|
} else {
|
||||||
|
Dat.Paths.config + "/colors.json";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watchChanges: true
|
||||||
|
|
||||||
|
onAdapterUpdated: writeAdapter()
|
||||||
|
onFileChanged: reload()
|
||||||
|
|
||||||
|
// writes the defualt values if file not found
|
||||||
|
onLoadFailed: err => {
|
||||||
|
if (err == FileViewError.FileNotFound) {
|
||||||
|
writeAdapter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonAdapter {
|
||||||
|
id: adapter
|
||||||
|
|
||||||
|
property JsonObject colors: JsonObject {
|
||||||
|
property JsonObject dark: JsonObject {
|
||||||
|
id: dark
|
||||||
|
|
||||||
|
property string background: "#121318"
|
||||||
|
property string error: "#ffb4ab"
|
||||||
|
property string error_container: "#93000a"
|
||||||
|
property string inverse_on_surface: "#2f3036"
|
||||||
|
property string inverse_primary: "#4d5c92"
|
||||||
|
property string inverse_surface: "#e3e1e9"
|
||||||
|
property string on_background: "#e3e1e9"
|
||||||
|
property string on_error: "#690005"
|
||||||
|
property string on_error_container: "#ffdad6"
|
||||||
|
property string on_primary: "#1d2d61"
|
||||||
|
property string on_primary_container: "#dce1ff"
|
||||||
|
property string on_primary_fixed: "#04174b"
|
||||||
|
property string on_primary_fixed_variant: "#354479"
|
||||||
|
property string on_secondary: "#2b3042"
|
||||||
|
property string on_secondary_container: "#dee1f9"
|
||||||
|
property string on_secondary_fixed: "#161b2c"
|
||||||
|
property string on_secondary_fixed_variant: "#424659"
|
||||||
|
property string on_surface: "#e3e1e9"
|
||||||
|
property string on_surface_variant: "#c6c5d0"
|
||||||
|
property string on_tertiary: "#432740"
|
||||||
|
property string on_tertiary_container: "#ffd7f5"
|
||||||
|
property string on_tertiary_fixed: "#2c122a"
|
||||||
|
property string on_tertiary_fixed_variant: "#5b3d57"
|
||||||
|
property string outline: "#90909a"
|
||||||
|
property string outline_variant: "#45464f"
|
||||||
|
property string primary: "#b6c4ff"
|
||||||
|
property string primary_container: "#354479"
|
||||||
|
property string primary_fixed: "#dce1ff"
|
||||||
|
property string primary_fixed_dim: "#b6c4ff"
|
||||||
|
property string scrim: "#000000"
|
||||||
|
property string secondary: "#c2c5dd"
|
||||||
|
property string secondary_container: "#424659"
|
||||||
|
property string secondary_fixed: "#dee1f9"
|
||||||
|
property string secondary_fixed_dim: "#c2c5dd"
|
||||||
|
property string shadow: "#000000"
|
||||||
|
property string surface: "#121318"
|
||||||
|
property string surface_bright: "#38393f"
|
||||||
|
property string surface_container: "#1e1f25"
|
||||||
|
property string surface_container_high: "#292a2f"
|
||||||
|
property string surface_container_highest: "#34343a"
|
||||||
|
property string surface_container_low: "#1a1b21"
|
||||||
|
property string surface_container_lowest: "#0d0e13"
|
||||||
|
property string surface_dim: "#121318"
|
||||||
|
property string surface_tint: "#b6c4ff"
|
||||||
|
property string tertiary: "#e3bada"
|
||||||
|
property string tertiary_container: "#5b3d57"
|
||||||
|
property string tertiary_fixed: "#ffd7f5"
|
||||||
|
property string tertiary_fixed_dim: "#e3bada"
|
||||||
|
}
|
||||||
|
property JsonObject light: JsonObject {
|
||||||
|
id: light
|
||||||
|
|
||||||
|
property string background: "#f4fafb"
|
||||||
|
property string error: "#ba1a1a"
|
||||||
|
property string error_container: "#ffdad6"
|
||||||
|
property string inverse_on_surface: "#ecf2f2"
|
||||||
|
property string inverse_primary: "#80d4da"
|
||||||
|
property string inverse_surface: "#2b3232"
|
||||||
|
property string on_background: "#161d1d"
|
||||||
|
property string on_error: "#ffffff"
|
||||||
|
property string on_error_container: "#410002"
|
||||||
|
property string on_primary: "#ffffff"
|
||||||
|
property string on_primary_container: "#002022"
|
||||||
|
property string on_primary_fixed: "#002022"
|
||||||
|
property string on_primary_fixed_variant: "#004f53"
|
||||||
|
property string on_secondary: "#ffffff"
|
||||||
|
property string on_secondary_container: "#041f21"
|
||||||
|
property string on_secondary_fixed: "#041f21"
|
||||||
|
property string on_secondary_fixed_variant: "#324b4d"
|
||||||
|
property string on_surface: "#161d1d"
|
||||||
|
property string on_surface_variant: "#3f4949"
|
||||||
|
property string on_tertiary: "#ffffff"
|
||||||
|
property string on_tertiary_container: "#091b36"
|
||||||
|
property string on_tertiary_fixed: "#091b36"
|
||||||
|
property string on_tertiary_fixed_variant: "#374764"
|
||||||
|
property string outline: "#6f7979"
|
||||||
|
property string outline_variant: "#bec8c9"
|
||||||
|
property string primary: "#00696e"
|
||||||
|
property string primary_container: "#9cf0f6"
|
||||||
|
property string primary_fixed: "#9cf0f6"
|
||||||
|
property string primary_fixed_dim: "#80d4da"
|
||||||
|
property string scrim: "#000000"
|
||||||
|
property string secondary: "#4a6365"
|
||||||
|
property string secondary_container: "#cce8e9"
|
||||||
|
property string secondary_fixed: "#cce8e9"
|
||||||
|
property string secondary_fixed_dim: "#b1cccd"
|
||||||
|
property string shadow: "#000000"
|
||||||
|
property string source_color: "#478185"
|
||||||
|
property string surface: "#f4fafb"
|
||||||
|
property string surface_bright: "#f4fafb"
|
||||||
|
property string surface_container: "#e9efef"
|
||||||
|
property string surface_container_high: "#e3e9e9"
|
||||||
|
property string surface_container_highest: "#dde4e4"
|
||||||
|
property string surface_container_low: "#eff5f5"
|
||||||
|
property string surface_container_lowest: "#ffffff"
|
||||||
|
property string surface_dim: "#d5dbdb"
|
||||||
|
property string surface_tint: "#00696e"
|
||||||
|
property string surface_variant: "#dae4e5"
|
||||||
|
property string tertiary: "#4e5f7d"
|
||||||
|
property string tertiary_container: "#d6e3ff"
|
||||||
|
property string tertiary_fixed: "#d6e3ff"
|
||||||
|
property string tertiary_fixed_dim: "#b6c7e9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// thanks to Soramane :>
|
||||||
|
// expressive curves => thanks end cutie ;)
|
||||||
|
readonly property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1]
|
||||||
|
readonly property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1]
|
||||||
|
readonly property int emphasizedAccelTime: 200
|
||||||
|
readonly property list<real> emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1]
|
||||||
|
readonly property int emphasizedDecelTime: 400
|
||||||
|
readonly property int emphasizedTime: 500
|
||||||
|
readonly property list<real> expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1.00, 1, 1]
|
||||||
|
readonly property int expressiveDefaultSpatialTime: 500
|
||||||
|
readonly property list<real> expressiveEffects: [0.34, 0.80, 0.34, 1.00, 1, 1]
|
||||||
|
readonly property int expressiveEffectsTime: 200
|
||||||
|
readonly property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.90, 1, 1]
|
||||||
|
readonly property int expressiveFastSpatialTime: 350
|
||||||
|
readonly property list<real> standard: [0.2, 0, 0, 1, 1, 1]
|
||||||
|
readonly property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1]
|
||||||
|
readonly property int standardAccelTime: 200
|
||||||
|
readonly property list<real> standardDecel: [0, 0, 0, 1, 1, 1]
|
||||||
|
readonly property int standardDecelTime: 250
|
||||||
|
readonly property int standardTime: 300
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Qt.labs.platform
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// refer https://doc.qt.io/qt-6/qstandardpaths.html#StandardLocation-enum
|
||||||
|
// god fucking knows how soramane found this
|
||||||
|
readonly property url cache: `${StandardPaths.standardLocations(StandardPaths.GenericCacheLocation)[0]}/kurukurubar`
|
||||||
|
readonly property url config: `${StandardPaths.standardLocations(StandardPaths.GenericConfigLocation)[0]}/kurukurubar`
|
||||||
|
|
||||||
|
function getPath(caller, url: string): string {
|
||||||
|
let filename = url.split('/').pop();
|
||||||
|
let filepath = root.cache + "/" + filename;
|
||||||
|
let script = root.urlToPath(Qt.resolvedUrl("../scripts/cacheImg.sh"));
|
||||||
|
|
||||||
|
let process = cacheImg.incubateObject(root, {
|
||||||
|
"command": ["bash", script, url, root.urlToPath(root.cache)],
|
||||||
|
"running": true
|
||||||
|
});
|
||||||
|
|
||||||
|
process.onStatusChanged = function (status) {
|
||||||
|
if (status != Component.Ready) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.object.exited.connect((eCode, eStat) => {
|
||||||
|
if (eCode == 0) {
|
||||||
|
caller.source = filepath;
|
||||||
|
} else {
|
||||||
|
console.log("[ERROR] cacheImg exited with error code: " + eCode);
|
||||||
|
}
|
||||||
|
process.object.destroy();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function urlToPath(url: url): string {
|
||||||
|
return url.toString().replace("file://", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: cacheImg
|
||||||
|
|
||||||
|
Process {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// https://m3.material.io/styles/typography/editorial-treatments#a8196c1e-387e-4303-b0bf-b9bac44e4e72
|
||||||
|
// a thin wrapper for placing using Material Symbols
|
||||||
|
// credit to end for leading me down this route
|
||||||
|
import QtQuick
|
||||||
|
import qs.Data as Dat
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property real fill: 0
|
||||||
|
property int grad: 0
|
||||||
|
required property string icon
|
||||||
|
|
||||||
|
font.family: "Material Symbols Rounded"
|
||||||
|
font.hintingPreference: Font.PreferFullHinting
|
||||||
|
font.variableAxes: {
|
||||||
|
"FILL": root.fill,
|
||||||
|
"opsz": root.fontInfo.pixelSize,
|
||||||
|
"GRAD": root.grad,
|
||||||
|
"wght": root.fontInfo.weight
|
||||||
|
}
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
text: root.icon
|
||||||
|
|
||||||
|
Behavior on fill {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Dat.MaterialEasing.standardTime
|
||||||
|
easing.bezierCurve: Dat.MaterialEasing.standard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import QtQuick
|
||||||
|
|
||||||
|
import qs.Data as Dat
|
||||||
|
import qs.Generics as Gen
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property bool active
|
||||||
|
property color activeColor: Dat.Colors.current.primary
|
||||||
|
property color activeIconColor: Dat.Colors.current.on_primary
|
||||||
|
property alias icon: matIcon
|
||||||
|
property alias mArea: mouseArea
|
||||||
|
property color passiveColor: Dat.Colors.current.surface_container
|
||||||
|
property color passiveIconColor: Dat.Colors.current.on_surface
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
state: (root.active) ? "ACTIVE" : "PASSIVE"
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "ACTIVE"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
bgToggle.color: root.activeColor
|
||||||
|
bgToggle.opacity: 1
|
||||||
|
bgToggle.visible: true
|
||||||
|
bgToggle.width: bgToggle.parent.width
|
||||||
|
matIcon.color: root.activeIconColor
|
||||||
|
matIcon.fill: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "PASSIVE"
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
bgToggle.color: root.passiveColor
|
||||||
|
bgToggle.opacity: 0
|
||||||
|
bgToggle.visible: false
|
||||||
|
bgToggle.width: 0
|
||||||
|
matIcon.color: root.passiveIconColor
|
||||||
|
matIcon.fill: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
transitions: [
|
||||||
|
Transition {
|
||||||
|
from: "PASSIVE"
|
||||||
|
to: "ACTIVE"
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
property: "visible"
|
||||||
|
target: bgToggle
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Dat.MaterialEasing.standardTime
|
||||||
|
easing.bezierCurve: Dat.MaterialEasing.standard
|
||||||
|
properties: "width, opacity"
|
||||||
|
target: bgToggle
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Dat.MaterialEasing.standardTime
|
||||||
|
targets: [bgToggle, matIcon]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Transition {
|
||||||
|
from: "ACTIVE"
|
||||||
|
to: "PASSIVE"
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
ParallelAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Dat.MaterialEasing.standardTime
|
||||||
|
easing.bezierCurve: Dat.MaterialEasing.standard
|
||||||
|
properties: "width, opacity"
|
||||||
|
target: bgToggle
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Dat.MaterialEasing.standardTime
|
||||||
|
targets: [bgToggle, matIcon]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
property: "visible"
|
||||||
|
target: bgToggle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: bgToggle
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
height: this.width
|
||||||
|
radius: this.width
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen.MatIcon {
|
||||||
|
id: matIcon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
icon: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Gen.MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
|
||||||
|
layerColor: matIcon.color
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property int index
|
||||||
|
property var menu: TrayItemMenu {
|
||||||
|
height: trayMenu.children.values.length * 30
|
||||||
|
trayMenu: trayMenu
|
||||||
|
width: 500
|
||||||
|
}
|
||||||
|
required property SystemTrayItem modelData
|
||||||
|
|
||||||
|
implicitHeight: trayItemIcon.width
|
||||||
|
implicitWidth: this.implicitHeight
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: trayItemIcon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
antialiasing: true
|
||||||
|
height: this.width
|
||||||
|
mipmap: true
|
||||||
|
smooth: true
|
||||||
|
source: {
|
||||||
|
// adapted from soramanew
|
||||||
|
const icon = root.modelData?.icon;
|
||||||
|
if (icon.includes("?path=")) {
|
||||||
|
const [name, path] = icon.split("?path=");
|
||||||
|
return `file://${path}/${name.slice(name.lastIndexOf("/") + 1)}`;
|
||||||
|
}
|
||||||
|
return root.modelData.icon;
|
||||||
|
}
|
||||||
|
width: 18
|
||||||
|
|
||||||
|
// too blurry for now
|
||||||
|
// layer.enabled: true
|
||||||
|
// layer.effect: MultiEffect {
|
||||||
|
// colorizationColor: Dat.Colors.current.secondary
|
||||||
|
// colorization: 1.0
|
||||||
|
// antialiasing: true
|
||||||
|
// smooth: true
|
||||||
|
// }
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onClicked: mevent => {
|
||||||
|
if (mevent.button == Qt.LeftButton) {
|
||||||
|
root.modelData.activate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!root.modelData.hasMenu) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
root.menu.visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QsMenuOpener {
|
||||||
|
id: trayMenu
|
||||||
|
|
||||||
|
menu: root.modelData?.menu
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
import qs.Data as Dat
|
||||||
|
import qs.Generics as Gen
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property QsMenuOpener trayMenu
|
||||||
|
|
||||||
|
color: Dat.Colors.current.surface_container
|
||||||
|
anchor.window: QsWindow.window
|
||||||
|
|
||||||
|
Behavior on trayMenu {
|
||||||
|
SequentialAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Dat.MaterialEasing.standardTime
|
||||||
|
easing.bezierCurve: Dat.MaterialEasing.standard
|
||||||
|
from: 1
|
||||||
|
property: "opacity"
|
||||||
|
target: root
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
property: "trayMenu"
|
||||||
|
target: root
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Dat.MaterialEasing.standardDecelTime
|
||||||
|
easing.bezierCurve: Dat.MaterialEasing.standardDecel
|
||||||
|
from: 0
|
||||||
|
property: "opacity"
|
||||||
|
target: root
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: view
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 3
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: entry
|
||||||
|
|
||||||
|
property var child: QsMenuOpener {
|
||||||
|
menu: entry.modelData
|
||||||
|
}
|
||||||
|
required property QsMenuEntry modelData
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
height: (modelData?.isSeparator) ? 2 : 28
|
||||||
|
radius: 20
|
||||||
|
width: root.width
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
visible: (entry.modelData?.enabled && !entry.modelData?.isSeparator) ?? true
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (entry.modelData.hasChildren) {
|
||||||
|
root.trayMenu = entry.child;
|
||||||
|
view.positionViewAtBeginning();
|
||||||
|
} else {
|
||||||
|
entry.modelData.triggered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: (entry.modelData?.buttonType == QsMenuButtonType.None) ? 10 : 2
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
implicitWidth: this.height
|
||||||
|
visible: entry.modelData?.buttonType == QsMenuButtonType.CheckBox
|
||||||
|
|
||||||
|
Gen.MatIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: Dat.Colors.current.primary
|
||||||
|
fill: entry.modelData?.checkState == Qt.Checked
|
||||||
|
font.pixelSize: parent.width * 0.8
|
||||||
|
icon: (entry.modelData?.checkState != Qt.Checked) ? "check_box_outline_blank" : "check_box"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// untested cause nothing I use have radio buttons
|
||||||
|
// if you use this and find somethings wrong / "yes rexi everything is fine" lemme know by opening an issue
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
implicitWidth: this.height
|
||||||
|
visible: entry.modelData?.buttonType == QsMenuButtonType.RadioButton
|
||||||
|
|
||||||
|
Gen.MatIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: Dat.Colors.current.primary
|
||||||
|
fill: entry.modelData?.checkState == Qt.Checked
|
||||||
|
font.pixelSize: parent.width * 0.8
|
||||||
|
icon: (entry.modelData?.checkState != Qt.Checked) ? "radio_button_unchecked" : "radio_button_checked"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: text
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
color: (entry.modelData?.enabled) ? Dat.Colors.current.on_surface : Dat.Colors.current.primary
|
||||||
|
font.pointSize: 11
|
||||||
|
text: entry.modelData?.text ?? ""
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
implicitWidth: this.height
|
||||||
|
visible: entry.modelData?.icon ?? false
|
||||||
|
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 3
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
source: entry.modelData?.icon ?? ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
implicitWidth: this.height
|
||||||
|
visible: entry.modelData?.hasChildren ?? false
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: Dat.Colors.current.on_surface
|
||||||
|
font.pointSize: 11
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model: ScriptModel {
|
||||||
|
values: [...root.trayMenu?.children.values]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+102
@@ -0,0 +1,102 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import qs.Data as Dat
|
||||||
|
import qs.Generics as Gen
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: root
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
right: true
|
||||||
|
left: true
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitHeight: 35
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: trayLayout
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: trayItemRow
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
orientation: ListView.Horizontal
|
||||||
|
snapMode: ListView.SnapToItem
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
add: Transition {
|
||||||
|
SequentialAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 0
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PauseAnimation {
|
||||||
|
duration: addDisAni.duration / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Dat.MaterialEasing.emphasizedTime
|
||||||
|
easing.bezierCurve: Dat.MaterialEasing.emphasized
|
||||||
|
from: 0
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addDisplaced: Transition {
|
||||||
|
SequentialAnimation {
|
||||||
|
NumberAnimation {
|
||||||
|
id: addDisAni
|
||||||
|
|
||||||
|
duration: Dat.MaterialEasing.emphasizedDecelTime
|
||||||
|
easing.bezierCurve: Dat.MaterialEasing.emphasizedDecel
|
||||||
|
properties: "x"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delegate: TrayItem {
|
||||||
|
}
|
||||||
|
model: ScriptModel {
|
||||||
|
values: [...SystemTray.items.values]
|
||||||
|
}
|
||||||
|
remove: Transition {
|
||||||
|
NumberAnimation {
|
||||||
|
id: removeAni
|
||||||
|
|
||||||
|
duration: Dat.MaterialEasing.emphasizedTime
|
||||||
|
easing.bezierCurve: Dat.MaterialEasing.emphasized
|
||||||
|
from: 1
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeDisplaced: Transition {
|
||||||
|
SequentialAnimation {
|
||||||
|
PauseAnimation {
|
||||||
|
duration: removeAni.duration / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Dat.MaterialEasing.emphasizedDecelTime
|
||||||
|
easing.bezierCurve: Dat.MaterialEasing.emphasizedDecel
|
||||||
|
properties: "x"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user