Rearrange for tidier structure (#2212)

This commit is contained in:
clsty
2025-10-16 07:19:55 +08:00
parent 13065d7e5a
commit 8b493e091d
529 changed files with 165 additions and 138 deletions
@@ -0,0 +1,224 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
Scope {
id: root
property string protectionMessage: ""
property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name)
property string currentIndicator: "volume"
property var indicators: [
{
id: "volume",
sourceUrl: "indicators/VolumeIndicator.qml"
},
{
id: "brightness",
sourceUrl: "indicators/BrightnessIndicator.qml"
},
]
function triggerOsd() {
GlobalStates.osdVolumeOpen = true;
osdTimeout.restart();
}
Timer {
id: osdTimeout
interval: Config.options.osd.timeout
repeat: false
running: false
onTriggered: {
GlobalStates.osdVolumeOpen = false;
root.protectionMessage = "";
}
}
Connections {
target: Brightness
function onBrightnessChanged() {
root.protectionMessage = "";
root.currentIndicator = "brightness";
root.triggerOsd();
}
}
Connections {
// Listen to volume changes
target: Audio.sink?.audio ?? null
function onVolumeChanged() {
if (!Audio.ready)
return;
root.currentIndicator = "volume";
root.triggerOsd();
}
function onMutedChanged() {
if (!Audio.ready)
return;
root.currentIndicator = "volume";
root.triggerOsd();
}
}
Connections {
// Listen to protection triggers
target: Audio
function onSinkProtectionTriggered(reason) {
root.protectionMessage = reason;
root.currentIndicator = "volume";
root.triggerOsd();
}
}
Loader {
id: osdLoader
active: GlobalStates.osdVolumeOpen
sourceComponent: PanelWindow {
id: osdRoot
color: "transparent"
Connections {
target: root
function onFocusedScreenChanged() {
osdRoot.screen = root.focusedScreen;
}
}
WlrLayershell.namespace: "quickshell:onScreenDisplay"
WlrLayershell.layer: WlrLayer.Overlay
anchors {
top: !Config.options.bar.bottom
bottom: Config.options.bar.bottom
}
mask: Region {
item: osdValuesWrapper
}
exclusionMode: ExclusionMode.Ignore
exclusiveZone: 0
margins {
top: Appearance.sizes.barHeight
bottom: Appearance.sizes.barHeight
}
implicitWidth: columnLayout.implicitWidth
implicitHeight: columnLayout.implicitHeight
visible: osdLoader.active
ColumnLayout {
id: columnLayout
anchors.horizontalCenter: parent.horizontalCenter
Item {
id: osdValuesWrapper
// Extra space for shadow
implicitHeight: contentColumnLayout.implicitHeight
implicitWidth: contentColumnLayout.implicitWidth
clip: true
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: GlobalStates.osdVolumeOpen = false
}
Column {
id: contentColumnLayout
anchors {
top: parent.top
left: parent.left
right: parent.right
}
spacing: 0
Loader {
id: osdIndicatorLoader
source: root.indicators.find(i => i.id === root.currentIndicator)?.sourceUrl
}
Item {
id: protectionMessageWrapper
anchors.horizontalCenter: parent.horizontalCenter
implicitHeight: protectionMessageBackground.implicitHeight
implicitWidth: protectionMessageBackground.implicitWidth
opacity: root.protectionMessage !== "" ? 1 : 0
StyledRectangularShadow {
target: protectionMessageBackground
}
Rectangle {
id: protectionMessageBackground
anchors.centerIn: parent
color: Appearance.m3colors.m3error
property real padding: 10
implicitHeight: protectionMessageRowLayout.implicitHeight + padding * 2
implicitWidth: protectionMessageRowLayout.implicitWidth + padding * 2
radius: Appearance.rounding.normal
RowLayout {
id: protectionMessageRowLayout
anchors.centerIn: parent
MaterialSymbol {
id: protectionMessageIcon
text: "dangerous"
iconSize: Appearance.font.pixelSize.hugeass
color: Appearance.m3colors.m3onError
}
StyledText {
id: protectionMessageTextWidget
horizontalAlignment: Text.AlignHCenter
color: Appearance.m3colors.m3onError
wrapMode: Text.Wrap
text: root.protectionMessage
}
}
}
}
}
}
}
}
}
IpcHandler {
target: "osdVolume"
function trigger() {
root.triggerOsd();
}
function hide() {
GlobalStates.osdVolumeOpen = false;
}
function toggle() {
GlobalStates.osdVolumeOpen = !GlobalStates.osdVolumeOpen;
}
}
GlobalShortcut {
name: "osdVolumeTrigger"
description: "Triggers volume OSD on press"
onPressed: {
root.triggerOsd();
}
}
GlobalShortcut {
name: "osdVolumeHide"
description: "Hides volume OSD on press"
onPressed: {
GlobalStates.osdVolumeOpen = false;
}
}
}
@@ -0,0 +1,104 @@
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
Item {
id: root
required property real value
required property string icon
required property string name
property bool rotateIcon: false
property bool scaleIcon: false
property real valueIndicatorVerticalPadding: 9
property real valueIndicatorLeftPadding: 10
property real valueIndicatorRightPadding: 20 // An icon is circle ish, a column isn't, hence the extra padding
implicitWidth: Appearance.sizes.osdWidth + 2 * Appearance.sizes.elevationMargin
implicitHeight: valueIndicator.implicitHeight + 2 * Appearance.sizes.elevationMargin
StyledRectangularShadow {
target: valueIndicator
}
Rectangle {
id: valueIndicator
anchors {
fill: parent
margins: Appearance.sizes.elevationMargin
}
radius: Appearance.rounding.full
color: Appearance.colors.colLayer0
implicitWidth: valueRow.implicitWidth
implicitHeight: valueRow.implicitHeight
RowLayout { // Icon on the left, stuff on the right
id: valueRow
Layout.margins: 10
anchors.fill: parent
spacing: 10
Item {
implicitWidth: 30
implicitHeight: 30
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: valueIndicatorLeftPadding
Layout.topMargin: valueIndicatorVerticalPadding
Layout.bottomMargin: valueIndicatorVerticalPadding
MaterialSymbol { // Icon
anchors {
centerIn: parent
alignWhenCentered: !root.rotateIcon
}
color: Appearance.colors.colOnLayer0
renderType: Text.QtRendering
text: root.icon
iconSize: 20 + 10 * (root.scaleIcon ? value : 1)
rotation: 180 * (root.rotateIcon ? value : 0)
Behavior on iconSize {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
}
Behavior on rotation {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
}
}
}
ColumnLayout { // Stuff
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: valueIndicatorRightPadding
spacing: 5
RowLayout { // Name fill left, value on the right end
Layout.leftMargin: valueProgressBar.height / 2 // Align text with progressbar radius curve's left end
Layout.rightMargin: valueProgressBar.height / 2 // Align text with progressbar radius curve's left end
StyledText {
color: Appearance.colors.colOnLayer0
font.pixelSize: Appearance.font.pixelSize.small
Layout.fillWidth: true
text: root.name
}
StyledText {
color: Appearance.colors.colOnLayer0
font.pixelSize: Appearance.font.pixelSize.small
Layout.fillWidth: false
text: Math.round(root.value * 100)
}
}
StyledProgressBar {
id: valueProgressBar
Layout.fillWidth: true
value: root.value
}
}
}
}
}
@@ -0,0 +1,17 @@
import qs.services
import QtQuick
import Quickshell
import Quickshell.Hyprland
import "../"
OsdValueIndicator {
id: root
property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name)
property var brightnessMonitor: Brightness.getMonitorForScreen(focusedScreen)
value: root.brightnessMonitor?.brightness ?? 50
icon: "light_mode"
rotateIcon: true
scaleIcon: true
name: Translation.tr("Brightness")
}
@@ -0,0 +1,10 @@
import qs.services
import QtQuick
import "../"
OsdValueIndicator {
id: osdValues
value: Audio.sink?.audio.volume ?? 0
icon: Audio.sink?.audio.muted ? "volume_off" : "volume_up"
name: Translation.tr("Volume")
}