major updates
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import qs.Modules
|
||||
import qs.Modules.Bar
|
||||
import qs.Config
|
||||
import qs.Helpers
|
||||
import qs.Drawers
|
||||
|
||||
Scope {
|
||||
Variants {
|
||||
@@ -16,11 +20,12 @@ Scope {
|
||||
required property var modelData
|
||||
property bool trayMenuVisible: false
|
||||
screen: modelData
|
||||
color: "transparent"
|
||||
property var root: Quickshell.shellDir
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
|
||||
PanelWindow {
|
||||
id: wrapper
|
||||
id: exclusionZone
|
||||
screen: bar.screen
|
||||
WlrLayershell.layer: WlrLayer.Bottom
|
||||
anchors {
|
||||
@@ -49,99 +54,89 @@ Scope {
|
||||
bottom: true
|
||||
}
|
||||
|
||||
mask: Region { item: backgroundRect }
|
||||
mask: Region {
|
||||
x: 0
|
||||
y: 34
|
||||
|
||||
color: "transparent"
|
||||
width: bar.width
|
||||
height: bar.screen.height - backgroundRect.implicitHeight
|
||||
intersection: Intersection.Xor
|
||||
|
||||
Rectangle {
|
||||
id: backgroundRect
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
implicitHeight: 34
|
||||
color: Config.useDynamicColors ? DynamicColors.tPalette.m3surface : Config.baseBgColor
|
||||
radius: 0
|
||||
regions: popoutRegions.instances
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
Variants {
|
||||
id: popoutRegions
|
||||
model: panels.children
|
||||
|
||||
Region {
|
||||
required property Item modelData
|
||||
|
||||
x: modelData.x
|
||||
y: modelData.y + backgroundRect.implicitHeight
|
||||
width: modelData.width
|
||||
height: modelData.height
|
||||
intersection: Intersection.Subtract
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
Backgrounds {
|
||||
panels: panels
|
||||
bar: backgroundRect
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onContainsMouseChanged: {
|
||||
if ( !containsMouse ) {
|
||||
panels.popouts.hasCurrent = false;
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 5
|
||||
anchors.rightMargin: 5
|
||||
|
||||
RowLayout {
|
||||
id: leftSection
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: leftSection.childrenRect.width
|
||||
|
||||
Workspaces {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
bar: bar
|
||||
}
|
||||
|
||||
AudioWidget {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
}
|
||||
|
||||
Resources {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
}
|
||||
|
||||
UpdatesWidget {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
countUpdates: Updates.availableUpdates
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
Text {
|
||||
id: notificationCenterIcon
|
||||
property color iconColor: Config.useDynamicColors ? DynamicColors.palette.m3tertiaryFixed : "white"
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: HasNotifications.hasNotifications ? "\uf4fe" : "\ue7f4"
|
||||
font.family: "Material Symbols Rounded"
|
||||
font.pixelSize: 20
|
||||
color: iconColor
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
ncProcess.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
onPositionChanged: event => {
|
||||
if ( mouseY < backgroundRect.implicitHeight ) {
|
||||
barLoader.checkPopout(mouseX);
|
||||
}
|
||||
}
|
||||
WindowTitle {
|
||||
anchors.centerIn: parent
|
||||
width: Math.min( 300, parent.width * 0.4 )
|
||||
height: parent.height
|
||||
z: 1
|
||||
|
||||
Panels {
|
||||
id: panels
|
||||
screen: bar.modelData
|
||||
bar: backgroundRect
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: backgroundRect
|
||||
property Wrapper popouts: panels.popouts
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
implicitHeight: 34
|
||||
color: Config.useDynamicColors ? DynamicColors.tPalette.m3surface : Config.baseBgColor
|
||||
radius: 0
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
|
||||
BarLoader {
|
||||
id: barLoader
|
||||
anchors.fill: parent
|
||||
popouts: panels.popouts
|
||||
bar: bar
|
||||
}
|
||||
|
||||
WindowTitle {
|
||||
anchors.centerIn: parent
|
||||
width: Math.min( 300, parent.width * 0.4 )
|
||||
height: parent.height
|
||||
z: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import Quickshell.Io
|
||||
|
||||
JsonObject {
|
||||
property Popouts popouts: Popouts {}
|
||||
|
||||
property list<var> entries: [
|
||||
{
|
||||
id: "workspaces",
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: "audio",
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: "resources",
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: "updates",
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: "spacer",
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: "activeWindow",
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: "spacer",
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: "tray",
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: "clock",
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
id: "notifBell",
|
||||
enabled: true
|
||||
},
|
||||
]
|
||||
|
||||
component Popouts: JsonObject {
|
||||
property bool tray: true
|
||||
property bool audio: true
|
||||
property bool activeWindow: false
|
||||
property bool resources: true
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ Singleton {
|
||||
property alias gpuType: adapter.gpuType
|
||||
property alias background: adapter.background
|
||||
property alias useDynamicColors: adapter.useDynamicColors
|
||||
property alias barConfig: adapter.barConfig
|
||||
|
||||
FileView {
|
||||
id: root
|
||||
@@ -44,6 +45,7 @@ Singleton {
|
||||
property string gpuType: ""
|
||||
property BackgroundConfig background: BackgroundConfig {}
|
||||
property bool useDynamicColors: false
|
||||
property BarConfig barConfig: BarConfig {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import qs.Modules as Modules
|
||||
|
||||
Shape {
|
||||
id: root
|
||||
|
||||
required property Panels panels
|
||||
required property Item bar
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
anchors.topMargin: bar.implicitHeight
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
|
||||
Modules.Background {
|
||||
wrapper: root.panels.popouts
|
||||
|
||||
startX: Math.floor(wrapper.x - rounding)
|
||||
startY: wrapper.y
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import qs.Modules as Modules
|
||||
import qs.Config
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property ShellScreen screen
|
||||
required property Item bar
|
||||
|
||||
readonly property alias popouts: popouts
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
anchors.topMargin: bar.implicitHeight
|
||||
|
||||
Modules.Wrapper {
|
||||
id: popouts
|
||||
|
||||
screen: root.screen
|
||||
|
||||
anchors.top: parent.top
|
||||
x: {
|
||||
const off = currentCenter - 8 - nonAnimWidth / 2;
|
||||
const diff = root.width - Math.floor(off + nonAnimWidth);
|
||||
if (diff < 0)
|
||||
return off + diff;
|
||||
return Math.max(off, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
-35
@@ -9,34 +9,13 @@ import qs.Config
|
||||
import qs.Components
|
||||
import qs.Daemons
|
||||
|
||||
CustomRect {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
implicitWidth: layout.implicitWidth + 10 * 2
|
||||
implicitHeight: 0
|
||||
color: Config.useDynamicColors ? DynamicColors.tPalette.m3surface : "#40000000"
|
||||
clip: true
|
||||
implicitHeight: layout.implicitHeight + 10 * 2
|
||||
|
||||
property alias expanded: root.isExpanded
|
||||
property bool isExpanded: false
|
||||
|
||||
Anim {
|
||||
id: expandAnim
|
||||
running: root.isExpanded
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
to: layout.implicitHeight + 10 * 2
|
||||
duration: MaterialEasing.standardTime
|
||||
}
|
||||
|
||||
Anim {
|
||||
id: collapseAnim
|
||||
running: !root.isExpanded
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
to: 0
|
||||
duration: MaterialEasing.standardTime
|
||||
}
|
||||
required property var wrapper
|
||||
|
||||
ButtonGroup {
|
||||
id: sinks
|
||||
@@ -49,8 +28,8 @@ CustomRect {
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 12
|
||||
|
||||
CustomText {
|
||||
@@ -95,7 +74,7 @@ CustomRect {
|
||||
CustomText {
|
||||
Layout.topMargin: 10
|
||||
Layout.bottomMargin: -7 / 2
|
||||
text: qsTr("Volume (%1)").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`)
|
||||
text: qsTr("Output Volume (%1)").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`)
|
||||
font.weight: 500
|
||||
}
|
||||
|
||||
@@ -103,13 +82,6 @@ CustomRect {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: 10 * 3
|
||||
|
||||
onWheel: event => {
|
||||
if (event.angleDelta.y > 0)
|
||||
Audio.incrementVolume();
|
||||
else if (event.angleDelta.y < 0)
|
||||
Audio.decrementVolume();
|
||||
}
|
||||
|
||||
CustomSlider {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
@@ -124,6 +96,31 @@ CustomRect {
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
Layout.topMargin: 10
|
||||
Layout.bottomMargin: -7 / 2
|
||||
text: qsTr("Input Volume (%1)").arg(Audio.sourceMuted ? qsTr("Muted") : `${Math.round(Audio.sourceVolume * 100)}%`)
|
||||
font.weight: 500
|
||||
}
|
||||
|
||||
CustomMouseArea {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: 10 * 3
|
||||
|
||||
CustomSlider {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
implicitHeight: parent.implicitHeight
|
||||
|
||||
value: Audio.sourceVolume
|
||||
onMoved: Audio.setSourceVolume(value)
|
||||
|
||||
Behavior on value {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
Layout.topMargin: 12
|
||||
visible: true
|
||||
@@ -138,7 +135,6 @@ CustomRect {
|
||||
color: DynamicColors.palette.m3onPrimaryContainer
|
||||
|
||||
function onClicked(): void {
|
||||
root.isExpanded = !root.isExpanded;
|
||||
Quickshell.execDetached(["app2unit", "--", "pavucontrol"]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,19 +53,11 @@ Item {
|
||||
border.width: 0
|
||||
}
|
||||
|
||||
AudioPopup {
|
||||
id: audioPopup
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.bottom
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: audioPopup.expanded = true
|
||||
onExited: audioPopup.expanded = false
|
||||
|
||||
RowLayout {
|
||||
anchors {
|
||||
|
||||
+44
-59
@@ -1,79 +1,64 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Helpers
|
||||
import QtQuick.Shapes
|
||||
import qs.Config
|
||||
|
||||
Item {
|
||||
ShapePath {
|
||||
id: root
|
||||
|
||||
property string source: SearchWallpapers.current
|
||||
property Image current: one
|
||||
required property Wrapper wrapper
|
||||
readonly property real rounding: 8
|
||||
readonly property bool flatten: wrapper.height < rounding * 2
|
||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||
|
||||
anchors.fill: parent
|
||||
strokeWidth: -1
|
||||
fillColor: DynamicColors.tPalette.m3surface
|
||||
|
||||
onSourceChanged: {
|
||||
if (!source) {
|
||||
current = null;
|
||||
} else if (current === one) {
|
||||
two.update();
|
||||
} else {
|
||||
one.update();
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log(root.source)
|
||||
if (source)
|
||||
Qt.callLater(() => one.update());
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: root.wrapper.height - root.roundingY * 2
|
||||
}
|
||||
|
||||
Img {
|
||||
id: one
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
direction: PathArc.Counterclockwise
|
||||
}
|
||||
|
||||
Img {
|
||||
id: two
|
||||
PathLine {
|
||||
relativeX: root.wrapper.width - root.rounding * 2
|
||||
relativeY: 0
|
||||
}
|
||||
|
||||
component Img: CachingImage {
|
||||
id: img
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
direction: PathArc.Counterclockwise
|
||||
}
|
||||
|
||||
function update(): void {
|
||||
if (path === root.source) {
|
||||
root.current = this;
|
||||
} else {
|
||||
path = root.source;
|
||||
}
|
||||
}
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: -(root.wrapper.height - root.roundingY * 2)
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
}
|
||||
|
||||
opacity: 0
|
||||
scale: SearchWallpapers.showPreview ? 1 : 0.8
|
||||
asynchronous: true
|
||||
onStatusChanged: {
|
||||
if (status === Image.Ready) {
|
||||
root.current = this;
|
||||
}
|
||||
}
|
||||
|
||||
states: State {
|
||||
name: "visible"
|
||||
when: root.current === img
|
||||
|
||||
PropertyChanges {
|
||||
img.opacity: 1
|
||||
img.scale: 1
|
||||
}
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
Anim {
|
||||
target: img
|
||||
properties: "opacity,scale"
|
||||
duration: Config.background.wallFadeDuration
|
||||
}
|
||||
}
|
||||
Behavior on fillColor {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Modules
|
||||
import qs.Config
|
||||
import qs.Helpers
|
||||
import qs.Daemons
|
||||
|
||||
RowLayout {
|
||||
id: root
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 5
|
||||
anchors.rightMargin: 5
|
||||
|
||||
readonly property int vPadding: 6
|
||||
required property Wrapper popouts
|
||||
required property PanelWindow bar
|
||||
|
||||
function checkPopout(x: real): void {
|
||||
const ch = childAt(x, height / 2) as WrappedLoader;
|
||||
|
||||
if (!ch) {
|
||||
popouts.hasCurrent = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const id = ch.id;
|
||||
const top = ch.x;
|
||||
const item = ch.item;
|
||||
const itemWidth = item.implicitWidth;
|
||||
|
||||
|
||||
if (id === "audio" && Config.barConfig.popouts.audio) {
|
||||
popouts.currentName = "audio";
|
||||
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
||||
popouts.hasCurrent = true;
|
||||
} else if ( id === "resources" && Config.barConfig.popouts.resources ) {
|
||||
popouts.currentName = "resources";
|
||||
popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x);
|
||||
popouts.hasCurrent = true;
|
||||
} else if (id === "tray" && Config.barConfig.popouts.tray) {
|
||||
const index = Math.floor(((x - top - 6) / item.implicitWidth) * item.items.count);
|
||||
const trayItem = item.items.itemAt(index);
|
||||
if (trayItem) {
|
||||
popouts.currentName = `traymenu${index}`;
|
||||
popouts.currentCenter = Qt.binding(() => trayItem.mapToItem(root, trayItem.implicitWidth / 2, 0).x);
|
||||
popouts.hasCurrent = true;
|
||||
} else {
|
||||
popouts.hasCurrent = false;
|
||||
}
|
||||
} else if (id === "activeWindow" && Config.barConfig.popouts.activeWindow) {
|
||||
popouts.currentName = id.toLowerCase();
|
||||
popouts.currentCenter = item.mapToItem(root, 0, itemHeight / 2).y;
|
||||
popouts.hasCurrent = true;
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: Config.barConfig.entries
|
||||
|
||||
DelegateChooser {
|
||||
role: "id"
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: "spacer"
|
||||
delegate: WrappedLoader {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
DelegateChoice {
|
||||
roleValue: "workspaces"
|
||||
delegate: WrappedLoader {
|
||||
sourceComponent: Workspaces {
|
||||
bar: root.bar
|
||||
}
|
||||
}
|
||||
}
|
||||
DelegateChoice {
|
||||
roleValue: "audio"
|
||||
delegate: WrappedLoader {
|
||||
sourceComponent: AudioWidget {}
|
||||
}
|
||||
}
|
||||
DelegateChoice {
|
||||
roleValue: "tray"
|
||||
delegate: WrappedLoader {
|
||||
sourceComponent: TrayWidget {
|
||||
bar: root.bar
|
||||
}
|
||||
}
|
||||
}
|
||||
DelegateChoice {
|
||||
roleValue: "resources"
|
||||
delegate: WrappedLoader {
|
||||
sourceComponent: Resources {}
|
||||
}
|
||||
}
|
||||
DelegateChoice {
|
||||
roleValue: "updates"
|
||||
delegate: WrappedLoader {
|
||||
sourceComponent: UpdatesWidget {}
|
||||
}
|
||||
}
|
||||
DelegateChoice {
|
||||
roleValue: "notifBell"
|
||||
delegate: WrappedLoader {
|
||||
sourceComponent: NotifBell {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
DelegateChoice {
|
||||
roleValue: "clock"
|
||||
delegate: WrappedLoader {
|
||||
sourceComponent: Clock {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
DelegateChoice {
|
||||
roleValue: "activeWindow"
|
||||
delegate: WrappedLoader {
|
||||
sourceComponent: WindowTitle {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component WrappedLoader: Loader {
|
||||
required property bool enabled
|
||||
required property string id
|
||||
required property int index
|
||||
|
||||
function findFirstEnabled(): Item {
|
||||
const count = repeater.count;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const item = repeater.itemAt(i);
|
||||
if (item?.enabled)
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findLastEnabled(): Item {
|
||||
for (let i = repeater.count - 1; i >= 0; i--) {
|
||||
const item = repeater.itemAt(i);
|
||||
if (item?.enabled)
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
// Cursed ahh thing to add padding to first and last enabled components
|
||||
Layout.topMargin: findFirstEnabled() === this ? root.vPadding : 0
|
||||
Layout.bottomMargin: findLastEnabled() === this ? root.vPadding : 0
|
||||
|
||||
visible: enabled
|
||||
active: enabled
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import QtQuick
|
||||
import qs.Config
|
||||
import qs.Modules
|
||||
|
||||
Item {
|
||||
implicitWidth: timeText.contentWidth
|
||||
implicitHeight: timeText.contentHeight
|
||||
Text {
|
||||
id: timeText
|
||||
text: Time.time
|
||||
color: Config.useDynamicColors ? DynamicColors.palette.m3tertiary : "white"
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Services.SystemTray
|
||||
import QtQuick
|
||||
import qs.Config
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property Item wrapper
|
||||
readonly property Popout currentPopout: content.children.find(c => c.shouldBeActive) ?? null
|
||||
readonly property Item current: currentPopout?.item ?? null
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
implicitWidth: (currentPopout?.implicitWidth ?? 0) + 10 * 2
|
||||
implicitHeight: (currentPopout?.implicitHeight ?? 0) + 10 * 2
|
||||
|
||||
Item {
|
||||
id: content
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
|
||||
Popout {
|
||||
name: "audio"
|
||||
sourceComponent: AudioPopup {
|
||||
wrapper: root.wrapper
|
||||
}
|
||||
}
|
||||
|
||||
Popout {
|
||||
name: "resources"
|
||||
sourceComponent: ResourcePopout {
|
||||
wrapper: root.wrapper
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
values: [ ...SystemTray.items.values ]
|
||||
}
|
||||
|
||||
Popout {
|
||||
id: trayMenu
|
||||
|
||||
required property SystemTrayItem modelData
|
||||
required property int index
|
||||
|
||||
name: `traymenu${index}`
|
||||
sourceComponent: trayMenuComponent
|
||||
|
||||
Connections {
|
||||
target: root.wrapper
|
||||
|
||||
function onHasCurrentChanged(): void {
|
||||
if ( root.wrapper.hasCurrent && trayMenu.shouldBeActive ) {
|
||||
trayMenu.sourceComponent = null;
|
||||
trayMenu.sourceComponent = trayMenuComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: trayMenuComponent
|
||||
|
||||
TrayMenuPopout {
|
||||
popouts: root.wrapper
|
||||
trayItem: trayMenu.modelData.menu
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component Popout: Loader {
|
||||
id: popout
|
||||
|
||||
required property string name
|
||||
readonly property bool shouldBeActive: root.wrapper.currentName === name
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
opacity: 0
|
||||
scale: 0.8
|
||||
active: false
|
||||
|
||||
states: State {
|
||||
name: "active"
|
||||
when: popout.shouldBeActive
|
||||
|
||||
PropertyChanges {
|
||||
popout.active: true
|
||||
popout.opacity: 1
|
||||
popout.scale: 1
|
||||
}
|
||||
}
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "active"
|
||||
to: ""
|
||||
|
||||
SequentialAnimation {
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
}
|
||||
PropertyAction {
|
||||
target: popout
|
||||
property: "active"
|
||||
}
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: ""
|
||||
to: "active"
|
||||
|
||||
SequentialAnimation {
|
||||
PropertyAction {
|
||||
target: popout
|
||||
property: "active"
|
||||
}
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ 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
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import QtQuick
|
||||
import qs.Config
|
||||
import qs.Helpers
|
||||
|
||||
Item {
|
||||
implicitWidth: 20
|
||||
implicitHeight: 18
|
||||
Text {
|
||||
id: notificationCenterIcon
|
||||
property color iconColor: Config.useDynamicColors ? DynamicColors.palette.m3tertiaryFixed : "white"
|
||||
text: HasNotifications.hasNotifications ? "\uf4fe" : "\ue7f4"
|
||||
font.family: "Material Symbols Rounded"
|
||||
font.pixelSize: 20
|
||||
color: iconColor
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
ncProcess.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,8 @@ Item {
|
||||
property color warningBarColor: Config.useDynamicColors ? DynamicColors.palette.m3error : Config.accentColor.accents.warning
|
||||
property color textColor: Config.useDynamicColors ? DynamicColors.palette.m3onSurface : "#ffffff"
|
||||
|
||||
height: columnLayout.childrenRect.height
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.preferredWidth: 158
|
||||
Layout.preferredHeight: columnLayout.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: columnLayout
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Config
|
||||
|
||||
Item {
|
||||
id: popoutWindow
|
||||
implicitWidth: contentColumn.implicitWidth + 10 * 2
|
||||
implicitHeight: contentColumn.implicitHeight + 10
|
||||
required property var wrapper
|
||||
|
||||
// ShadowRect {
|
||||
// anchors.fill: contentRect
|
||||
// radius: 8
|
||||
// }
|
||||
|
||||
ColumnLayout {
|
||||
id: contentColumn
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 10
|
||||
|
||||
ResourceDetail {
|
||||
resourceName: qsTr( "Memory Usage" )
|
||||
iconString: "\uf7a3"
|
||||
percentage: ResourceUsage.memoryUsedPercentage
|
||||
warningThreshold: 95
|
||||
details: qsTr( "%1 of %2 MB used" )
|
||||
.arg( Math.round( ResourceUsage.memoryUsed * 0.001 ))
|
||||
.arg( Math.round( ResourceUsage.memoryTotal * 0.001 ))
|
||||
}
|
||||
|
||||
ResourceDetail {
|
||||
resourceName: qsTr( "CPU Usage" )
|
||||
iconString: "\ue322"
|
||||
percentage: ResourceUsage.cpuUsage
|
||||
warningThreshold: 95
|
||||
details: qsTr( "%1% used" )
|
||||
.arg( Math.round( ResourceUsage.cpuUsage * 100 ))
|
||||
}
|
||||
|
||||
ResourceDetail {
|
||||
resourceName: qsTr( "GPU Usage" )
|
||||
iconString: "\ue30f"
|
||||
percentage: ResourceUsage.gpuUsage
|
||||
warningThreshold: 95
|
||||
details: qsTr( "%1% used" )
|
||||
.arg( Math.round( ResourceUsage.gpuUsage * 100 ))
|
||||
}
|
||||
|
||||
ResourceDetail {
|
||||
resourceName: qsTr( "VRAM Usage" )
|
||||
iconString: "\ue30d"
|
||||
percentage: ResourceUsage.gpuMemUsage
|
||||
warningThreshold: 95
|
||||
details: qsTr( "%1% used" )
|
||||
.arg( Math.round( ResourceUsage.gpuMemUsage * 100 ))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,111 +94,4 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: popoutWindow
|
||||
z: 0
|
||||
property int rectHeight: contentRect.implicitHeight
|
||||
anchors.fill: parent
|
||||
visible: true
|
||||
|
||||
// ShadowRect {
|
||||
// anchors.fill: contentRect
|
||||
// radius: 8
|
||||
// }
|
||||
|
||||
ParallelAnimation {
|
||||
id: openAnim
|
||||
Anim {
|
||||
target: contentRect
|
||||
property: "implicitHeight"
|
||||
to: contentColumn.childrenRect.height + 20
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: closeAnim
|
||||
Anim {
|
||||
target: contentRect
|
||||
property: "implicitHeight"
|
||||
to: 0
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: contentRect
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.bottom
|
||||
color: Config.useDynamicColors ? DynamicColors.tPalette.m3surface : Config.baseBgColor
|
||||
border.color: Config.useDynamicColors ? "transparent" : Config.baseBorderColor
|
||||
border.width: 1
|
||||
bottomLeftRadius: 8
|
||||
bottomRightRadius: 8
|
||||
clip: true
|
||||
|
||||
Column {
|
||||
id: contentColumn
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
spacing: 10
|
||||
|
||||
ResourceDetail {
|
||||
resourceName: qsTr( "Memory Usage" )
|
||||
iconString: "\uf7a3"
|
||||
percentage: ResourceUsage.memoryUsedPercentage
|
||||
warningThreshold: 95
|
||||
details: qsTr( "%1 of %2 MB used" )
|
||||
.arg( Math.round( ResourceUsage.memoryUsed * 0.001 ))
|
||||
.arg( Math.round( ResourceUsage.memoryTotal * 0.001 ))
|
||||
}
|
||||
|
||||
ResourceDetail {
|
||||
resourceName: qsTr( "CPU Usage" )
|
||||
iconString: "\ue322"
|
||||
percentage: ResourceUsage.cpuUsage
|
||||
warningThreshold: 95
|
||||
details: qsTr( "%1% used" )
|
||||
.arg( Math.round( ResourceUsage.cpuUsage * 100 ))
|
||||
}
|
||||
|
||||
ResourceDetail {
|
||||
resourceName: qsTr( "GPU Usage" )
|
||||
iconString: "\ue30f"
|
||||
percentage: ResourceUsage.gpuUsage
|
||||
warningThreshold: 95
|
||||
details: qsTr( "%1% used" )
|
||||
.arg( Math.round( ResourceUsage.gpuUsage * 100 ))
|
||||
}
|
||||
|
||||
ResourceDetail {
|
||||
resourceName: qsTr( "VRAM Usage" )
|
||||
iconString: "\ue30d"
|
||||
percentage: ResourceUsage.gpuMemUsage
|
||||
warningThreshold: 95
|
||||
details: qsTr( "%1% used" )
|
||||
.arg( Math.round( ResourceUsage.gpuMemUsage * 100 ))
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: widgetMouseArea
|
||||
z: 1
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: contentRect.bottom
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
openAnim.start();
|
||||
}
|
||||
onExited: {
|
||||
closeAnim.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-44
@@ -8,39 +8,13 @@ import qs.Config
|
||||
import Caelestia
|
||||
import QtQuick.Effects
|
||||
|
||||
MouseArea {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property SystemTrayItem item
|
||||
required property PanelWindow bar
|
||||
property point globalPos
|
||||
property bool hasLoaded: false
|
||||
|
||||
implicitWidth: 24
|
||||
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
onPositionChanged: {
|
||||
globalPos = root.mapToItem(root.bar.backgroundRect, 0, 0);
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
implicitHeight: 28
|
||||
implicitWidth: 28
|
||||
radius: 6
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: root.containsMouse ? Config.colors.backgrounds.hover : "transparent"
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: MaterialEasing.expressiveEffectsTime
|
||||
easing.bezierCurve: MaterialEasing.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: icon
|
||||
|
||||
@@ -58,22 +32,5 @@ MouseArea {
|
||||
sourceSize.height: ( batteryHDPI || nmHDPI ) ? 16 : 22
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
TrayMenu {
|
||||
id: trayMenu
|
||||
trayMenu: root.item?.menu
|
||||
trayItemRect: root.globalPos
|
||||
bar: root.bar
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if ( mouse.button === Qt.LeftButton ) {
|
||||
root.item.activate();
|
||||
} else if ( mouse.button === Qt.RightButton ) {
|
||||
trayMenu.trayMenu = null;
|
||||
trayMenu.trayMenu = root.item?.menu;
|
||||
trayMenu.visible = !trayMenu.visible;
|
||||
trayMenu.focusGrab = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-4
@@ -8,6 +8,8 @@ import Qt5Compat.GraphicalEffects
|
||||
import Quickshell.Hyprland
|
||||
import QtQml
|
||||
import qs.Effects
|
||||
import qs.Config
|
||||
import qs.Modules
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
@@ -24,6 +26,12 @@ PanelWindow {
|
||||
property int biggestWidth: 0
|
||||
property int menuItemCount: menuOpener.children.values.length
|
||||
|
||||
property color backgroundColor: Config.useDynamicColors ? DynamicColors.tPalette.m3surface : Config.baseBgColor
|
||||
property color highlightColor: Config.useDynamicColors ? DynamicColors.tPalette.m3primaryContainer : "#15FFFFFF"
|
||||
property color textColor: Config.useDynamicColors ? DynamicColors.palette.m3onSurface : "white"
|
||||
property color disabledHighlightColor: Config.useDynamicColors ? DynamicColors.layer(DynamicColors.palette.m3primaryContainer, 0) : "#08FFFFFF"
|
||||
property color disabledTextColor: Config.useDynamicColors ? DynamicColors.layer(DynamicColors.palette.m3onSurface, 0) : "#80FFFFFF"
|
||||
|
||||
QsMenuOpener {
|
||||
id: menuOpener
|
||||
menu: root.trayMenu
|
||||
@@ -183,8 +191,9 @@ PanelWindow {
|
||||
y: Math.round( root.trayItemRect.y - 5 )
|
||||
implicitWidth: listLayout.contentWidth + 10
|
||||
implicitHeight: listLayout.contentHeight + ( root.menuStack.length > 0 ? root.entryHeight + 10 : 10 )
|
||||
color: "#80151515"
|
||||
color: root.backgroundColor
|
||||
radius: 8
|
||||
border.width: Config.useDynamicColors ? 0 : 1
|
||||
border.color: "#40FFFFFF"
|
||||
clip: true
|
||||
|
||||
@@ -218,7 +227,7 @@ PanelWindow {
|
||||
id: listLayout
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: contentHeight
|
||||
spacing: 2
|
||||
spacing: 0
|
||||
contentWidth: root.biggestWidth
|
||||
contentHeight: contentItem.childrenRect.height
|
||||
model: menuOpener.children
|
||||
@@ -236,10 +245,16 @@ PanelWindow {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: menuItem.modelData.isSeparator ? 1 : root.entryHeight
|
||||
color: menuItem.modelData.isSeparator ? "#20FFFFFF" : containsMouseAndEnabled ? "#15FFFFFF" : containsMouseAndNotEnabled ? "#08FFFFFF" : "transparent"
|
||||
color: menuItem.modelData.isSeparator ? "#20FFFFFF" : containsMouseAndEnabled ? root.highlightColor : containsMouseAndNotEnabled ? root.disabledHighlightColor : "transparent"
|
||||
radius: 4
|
||||
visible: true
|
||||
|
||||
Behavior on color {
|
||||
CAnim {
|
||||
duration: 150
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
var biggestWidth = root.biggestWidth;
|
||||
var currentWidth = widthMetrics.width + (menuItem.modelData.icon ?? "" ? 30 : 0) + (menuItem.modelData.hasChildren ? 30 : 0) + 20;
|
||||
@@ -284,7 +299,7 @@ PanelWindow {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.leftMargin: 10
|
||||
text: menuItem.modelData.text
|
||||
color: menuItem.modelData.enabled ? "white" : "gray"
|
||||
color: menuItem.modelData.enabled ? root.textColor : root.disabledTextColor
|
||||
}
|
||||
Image {
|
||||
id: iconImage
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.Components
|
||||
import qs.Config
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
StackView {
|
||||
id: root
|
||||
|
||||
required property Item popouts
|
||||
required property QsMenuHandle trayItem
|
||||
|
||||
property int biggestWidth: 0
|
||||
|
||||
implicitWidth: currentItem.implicitWidth
|
||||
implicitHeight: currentItem.implicitHeight
|
||||
|
||||
initialItem: SubMenu {
|
||||
handle: root.trayItem
|
||||
}
|
||||
|
||||
pushEnter: NoAnim {}
|
||||
pushExit: NoAnim {}
|
||||
popEnter: NoAnim {}
|
||||
popExit: NoAnim {}
|
||||
|
||||
component NoAnim: Transition {
|
||||
NumberAnimation {
|
||||
duration: 0
|
||||
}
|
||||
}
|
||||
|
||||
component SubMenu: Column {
|
||||
id: menu
|
||||
|
||||
required property QsMenuHandle handle
|
||||
property bool isSubMenu
|
||||
property bool shown
|
||||
|
||||
padding: 0
|
||||
spacing: 4
|
||||
|
||||
opacity: shown ? 1 : 0
|
||||
scale: shown ? 1 : 0.8
|
||||
|
||||
Component.onCompleted: shown = true
|
||||
StackView.onActivating: shown = true
|
||||
StackView.onDeactivating: shown = false
|
||||
StackView.onRemoved: destroy()
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
QsMenuOpener {
|
||||
id: menuOpener
|
||||
|
||||
menu: menu.handle
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: menuOpener.children
|
||||
|
||||
CustomRect {
|
||||
id: item
|
||||
|
||||
required property QsMenuEntry modelData
|
||||
|
||||
implicitWidth: root.biggestWidth
|
||||
implicitHeight: modelData.isSeparator ? 1 : children.implicitHeight
|
||||
|
||||
radius: 4
|
||||
color: modelData.isSeparator ? DynamicColors.palette.m3outlineVariant : "transparent"
|
||||
|
||||
Loader {
|
||||
id: children
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
active: !item.modelData.isSeparator
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: Item {
|
||||
implicitHeight: 30
|
||||
|
||||
StateLayer {
|
||||
radius: item.radius
|
||||
disabled: !item.modelData.enabled
|
||||
|
||||
function onClicked(): void {
|
||||
const entry = item.modelData;
|
||||
if (entry.hasChildren)
|
||||
root.push(subMenuComp.createObject(null, {
|
||||
handle: entry,
|
||||
isSubMenu: true
|
||||
}));
|
||||
else {
|
||||
item.modelData.triggered();
|
||||
root.popouts.hasCurrent = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: icon
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.rightMargin: 10
|
||||
|
||||
active: item.modelData.icon !== ""
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: IconImage {
|
||||
implicitSize: label.implicitHeight
|
||||
|
||||
source: item.modelData.icon
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: label
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: 10
|
||||
|
||||
text: labelMetrics.elidedText
|
||||
color: item.modelData.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3outline
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: labelMetrics
|
||||
|
||||
text: item.modelData.text
|
||||
font.pointSize: label.font.pointSize
|
||||
font.family: label.font.family
|
||||
|
||||
Component.onCompleted: {
|
||||
var biggestWidth = root.biggestWidth;
|
||||
var currentWidth = labelMetrics.width + (item.modelData.icon ?? "" ? 30 : 0) + (item.modelData.hasChildren ? 30 : 0) + 20;
|
||||
if ( currentWidth > biggestWidth ) {
|
||||
root.biggestWidth = currentWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: expand
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
|
||||
active: item.modelData.hasChildren
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: MaterialIcon {
|
||||
text: "chevron_right"
|
||||
color: item.modelData.enabled ? DynamicColors.palette.m3onSurface : DynamicColors.palette.m3outline
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: menu.isSubMenu
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: Item {
|
||||
implicitWidth: back.implicitWidth
|
||||
implicitHeight: back.implicitHeight + 2 / 2
|
||||
|
||||
Item {
|
||||
anchors.bottom: parent.bottom
|
||||
implicitWidth: back.implicitWidth
|
||||
implicitHeight: back.implicitHeight
|
||||
|
||||
CustomRect {
|
||||
anchors.fill: parent
|
||||
radius: 1000
|
||||
color: DynamicColors.palette.m3secondaryContainer
|
||||
|
||||
StateLayer {
|
||||
radius: parent.radius
|
||||
color: DynamicColors.palette.m3onSecondaryContainer
|
||||
|
||||
function onClicked(): void {
|
||||
root.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: back
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MaterialIcon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "chevron_left"
|
||||
color: DynamicColors.palette.m3onSecondaryContainer
|
||||
}
|
||||
|
||||
CustomText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Back")
|
||||
color: DynamicColors.palette.m3onSecondaryContainer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: subMenuComp
|
||||
|
||||
SubMenu {}
|
||||
}
|
||||
}
|
||||
+13
-19
@@ -5,27 +5,21 @@ import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Services.SystemTray
|
||||
|
||||
Rectangle {
|
||||
Row {
|
||||
id: root
|
||||
required property PanelWindow bar
|
||||
implicitHeight: parent.height
|
||||
implicitWidth: rowL.implicitWidth + 10
|
||||
color: "transparent"
|
||||
|
||||
RowLayout {
|
||||
spacing: 5
|
||||
id: rowL
|
||||
anchors.centerIn: parent
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: SystemTray.items
|
||||
TrayItem {
|
||||
id: trayItem
|
||||
required property SystemTrayItem modelData
|
||||
implicitHeight: root.implicitHeight
|
||||
item: modelData
|
||||
bar: root.bar
|
||||
}
|
||||
readonly property alias items: repeater
|
||||
spacing: 0
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: SystemTray.items
|
||||
TrayItem {
|
||||
id: trayItem
|
||||
required property SystemTrayItem modelData
|
||||
implicitHeight: 34
|
||||
implicitWidth: 28
|
||||
item: modelData
|
||||
bar: root.bar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import qs.Config
|
||||
|
||||
Item {
|
||||
id: root
|
||||
required property int countUpdates
|
||||
property int countUpdates: Updates.availableUpdates
|
||||
implicitWidth: contentRow.childrenRect.width + 10
|
||||
implicitHeight: 22
|
||||
property color textColor: Config.useDynamicColors ? DynamicColors.palette.m3tertiaryFixed : "#ffffff"
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Helpers
|
||||
import qs.Config
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string source: SearchWallpapers.current
|
||||
property Image current: one
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
onSourceChanged: {
|
||||
if (!source) {
|
||||
current = null;
|
||||
} else if (current === one) {
|
||||
two.update();
|
||||
} else {
|
||||
one.update();
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log(root.source)
|
||||
if (source)
|
||||
Qt.callLater(() => one.update());
|
||||
}
|
||||
|
||||
Img {
|
||||
id: one
|
||||
}
|
||||
|
||||
Img {
|
||||
id: two
|
||||
}
|
||||
|
||||
component Img: CachingImage {
|
||||
id: img
|
||||
|
||||
function update(): void {
|
||||
if (path === root.source) {
|
||||
root.current = this;
|
||||
} else {
|
||||
path = root.source;
|
||||
}
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: 0
|
||||
scale: SearchWallpapers.showPreview ? 1 : 0.8
|
||||
asynchronous: true
|
||||
onStatusChanged: {
|
||||
if (status === Image.Ready) {
|
||||
root.current = this;
|
||||
}
|
||||
}
|
||||
|
||||
states: State {
|
||||
name: "visible"
|
||||
when: root.current === img
|
||||
|
||||
PropertyChanges {
|
||||
img.opacity: 1
|
||||
img.scale: 1
|
||||
}
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
Anim {
|
||||
target: img
|
||||
properties: "opacity,scale"
|
||||
duration: Config.background.wallFadeDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+82
-77
@@ -8,106 +8,111 @@ import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import qs.Config
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
Item {
|
||||
id: itemRoot
|
||||
required property PanelWindow bar
|
||||
property HyprlandMonitor monitor: Hyprland.monitorFor( root.bar?.screen )
|
||||
implicitHeight: 28
|
||||
implicitWidth: root.implicitWidth
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
implicitWidth: workspacesRow.implicitWidth + 6
|
||||
implicitHeight: 22
|
||||
property HyprlandMonitor monitor: Hyprland.monitorFor( itemRoot.bar?.screen )
|
||||
|
||||
function shouldShow(monitor) {
|
||||
Hyprland.refreshWorkspaces();
|
||||
Hyprland.refreshMonitors();
|
||||
if ( monitor === root.monitor ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
implicitWidth: workspacesRow.implicitWidth + 6
|
||||
implicitHeight: 22
|
||||
|
||||
function shouldShow(monitor) {
|
||||
Hyprland.refreshWorkspaces();
|
||||
Hyprland.refreshMonitors();
|
||||
if ( monitor === root.monitor ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color: Config.useDynamicColors ? DynamicColors.tPalette.m3surfaceContainer : "#40000000"
|
||||
radius: height / 2
|
||||
color: Config.useDynamicColors ? DynamicColors.tPalette.m3surfaceContainer : "#40000000"
|
||||
radius: height / 2
|
||||
|
||||
Behavior on implicitWidth {
|
||||
NumberAnimation {
|
||||
duration: 100
|
||||
easing.type: Easing.InOutQuad
|
||||
Behavior on implicitWidth {
|
||||
NumberAnimation {
|
||||
duration: 100
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: workspacesRow
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: 3
|
||||
spacing: 8
|
||||
RowLayout {
|
||||
id: workspacesRow
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: 3
|
||||
spacing: 8
|
||||
|
||||
Repeater {
|
||||
model: Hyprland.workspaces
|
||||
Repeater {
|
||||
model: Hyprland.workspaces
|
||||
|
||||
Rectangle {
|
||||
id: workspaceIndicator
|
||||
required property var modelData
|
||||
Rectangle {
|
||||
id: workspaceIndicator
|
||||
required property var modelData
|
||||
|
||||
width: 16
|
||||
height: 16
|
||||
radius: height / 2
|
||||
width: 16
|
||||
height: 16
|
||||
radius: height / 2
|
||||
|
||||
color: modelData.id === Hyprland.focusedWorkspace.id ? ( Config.useDynamicColors ? DynamicColors.palette.m3primary : Config.accentColor.accents.primary ) : ( Config.useDynamicColors ? DynamicColors.palette.m3inverseOnSurface : "#606060" )
|
||||
color: modelData.id === Hyprland.focusedWorkspace.id ? ( Config.useDynamicColors ? DynamicColors.palette.m3primary : Config.accentColor.accents.primary ) : ( Config.useDynamicColors ? DynamicColors.palette.m3inverseOnSurface : "#606060" )
|
||||
|
||||
border.color: modelData.id === Hyprland.focusedWorkspace.id ? ( Config.useDynamicColors ? DynamicColors.palette.m3onPrimary : Config.accentColor.accents.primaryAlt ) : ( Config.useDynamicColors ? DynamicColors.palette.m3inverseOnSurface : "#808080" )
|
||||
border.width: 1
|
||||
border.color: modelData.id === Hyprland.focusedWorkspace.id ? ( Config.useDynamicColors ? DynamicColors.palette.m3onPrimary : Config.accentColor.accents.primaryAlt ) : ( Config.useDynamicColors ? DynamicColors.palette.m3inverseOnSurface : "#808080" )
|
||||
border.width: 1
|
||||
|
||||
visible: root.shouldShow( modelData.monitor )
|
||||
visible: root.shouldShow( modelData.monitor )
|
||||
|
||||
scale: 1.0
|
||||
opacity: 1.0
|
||||
scale: 1.0
|
||||
opacity: 1.0
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 150
|
||||
easing.type: Easing.InOutQuad
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 150
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// Text {
|
||||
// anchors.centerIn: parent
|
||||
// text: modelData.id
|
||||
// font.pixelSize: 10
|
||||
// font.family: "Rubik"
|
||||
// color: modelData.id === Hyprland.focusedWorkspace.id ? Config.workspaceWidget.textColor : Config.workspaceWidget.inactiveTextColor
|
||||
// }
|
||||
// Text {
|
||||
// anchors.centerIn: parent
|
||||
// text: modelData.id
|
||||
// font.pixelSize: 10
|
||||
// font.family: "Rubik"
|
||||
// color: modelData.id === Hyprland.focusedWorkspace.id ? Config.workspaceWidget.textColor : Config.workspaceWidget.inactiveTextColor
|
||||
// }
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
Hyprland.dispatch("workspace " + modelData.id)
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
Hyprland.dispatch("workspace " + modelData.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import QtQuick
|
||||
import qs.Config
|
||||
import qs.Helpers
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property ShellScreen screen
|
||||
|
||||
readonly property real nonAnimWidth: children.find(c => c.shouldBeActive)?.implicitWidth ?? content.implicitWidth
|
||||
readonly property real nonAnimHeight: hasCurrent ? children.find(c => c.shouldBeActive)?.implicitHeight ?? content.implicitHeight : 0
|
||||
readonly property Item current: content.item?.current ?? null
|
||||
|
||||
property string currentName
|
||||
property real currentCenter
|
||||
property bool hasCurrent
|
||||
|
||||
property string detachedMode
|
||||
property string queuedMode
|
||||
readonly property bool isDetached: detachedMode.length > 0
|
||||
|
||||
property int animLength: 400
|
||||
property list<real> animCurve: MaterialEasing.emphasized
|
||||
|
||||
function detach(mode: string): void {
|
||||
animLength = 600;
|
||||
if (mode === "winfo") {
|
||||
detachedMode = mode;
|
||||
} else {
|
||||
detachedMode = "any";
|
||||
queuedMode = mode;
|
||||
}
|
||||
focus = true;
|
||||
}
|
||||
|
||||
function close(): void {
|
||||
hasCurrent = false;
|
||||
animCurve = MaterialEasing.emphasizedDecel;
|
||||
animLength = 400;
|
||||
detachedMode = "";
|
||||
animCurve = MaterialEasing.emphasized;
|
||||
}
|
||||
|
||||
visible: width > 0 && height > 0
|
||||
clip: true
|
||||
|
||||
implicitWidth: nonAnimWidth
|
||||
implicitHeight: nonAnimHeight
|
||||
|
||||
Keys.onEscapePressed: close()
|
||||
|
||||
HyprlandFocusGrab {
|
||||
active: root.isDetached
|
||||
windows: [QsWindow.window]
|
||||
onCleared: root.close()
|
||||
}
|
||||
|
||||
Binding {
|
||||
when: root.isDetached
|
||||
|
||||
target: QsWindow.window
|
||||
property: "WlrLayershell.keyboardFocus"
|
||||
value: WlrKeyboardFocus.OnDemand
|
||||
}
|
||||
|
||||
Comp {
|
||||
id: content
|
||||
|
||||
shouldBeActive: root.hasCurrent
|
||||
asynchronous: true
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
sourceComponent: Content {
|
||||
wrapper: root
|
||||
}
|
||||
}
|
||||
|
||||
// Comp {
|
||||
// shouldBeActive: root.detachedMode === "winfo"
|
||||
// asynchronous: true
|
||||
// anchors.centerIn: parent
|
||||
//
|
||||
// sourceComponent: WindowInfo {
|
||||
// screen: root.screen
|
||||
// client: Hypr.activeToplevel
|
||||
// }
|
||||
// }
|
||||
|
||||
// Comp {
|
||||
// shouldBeActive: root.detachedMode === "any"
|
||||
// asynchronous: true
|
||||
// anchors.centerIn: parent
|
||||
//
|
||||
// sourceComponent: ControlCenter {
|
||||
// screen: root.screen
|
||||
// active: root.queuedMode
|
||||
//
|
||||
// function close(): void {
|
||||
// root.close();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Behavior on x {
|
||||
enabled: root.implicitHeight > 0
|
||||
Anim {
|
||||
duration: root.animLength
|
||||
easing.bezierCurve: root.animCurve
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
Anim {
|
||||
duration: root.animLength
|
||||
easing.bezierCurve: root.animCurve
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitWidth {
|
||||
enabled: root.implicitHeight > 0
|
||||
Anim {
|
||||
duration: root.animLength
|
||||
easing.bezierCurve: root.animCurve
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
duration: root.animLength
|
||||
easing.bezierCurve: root.animCurve
|
||||
}
|
||||
}
|
||||
|
||||
component Comp: Loader {
|
||||
id: comp
|
||||
|
||||
property bool shouldBeActive
|
||||
|
||||
asynchronous: true
|
||||
active: false
|
||||
opacity: 0
|
||||
|
||||
states: State {
|
||||
name: "active"
|
||||
when: comp.shouldBeActive
|
||||
|
||||
PropertyChanges {
|
||||
comp.opacity: 1
|
||||
comp.active: true
|
||||
}
|
||||
}
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: ""
|
||||
to: "active"
|
||||
|
||||
SequentialAnimation {
|
||||
PropertyAction {
|
||||
property: "active"
|
||||
}
|
||||
Anim {
|
||||
property: "opacity"
|
||||
}
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "active"
|
||||
to: ""
|
||||
|
||||
SequentialAnimation {
|
||||
Anim {
|
||||
property: "opacity"
|
||||
}
|
||||
PropertyAction {
|
||||
property: "active"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -26,7 +26,7 @@ Loader {
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
Background {}
|
||||
WallBackground {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user