aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-17 12:16:33 +0200
committerDanilo M. <danix@danix.xyz>2026-10-17 12:16:33 +0200
commite3bd8e9f637dc6bed732170153cb09a281b842e1 (patch)
tree76b05cc2737557b1da34a5b33188dcb067a2cbe4
parent2148f660256b93d3ff6efde70be11d19b0f823ae (diff)
downloadquickshell-e3bd8e9f637dc6bed732170153cb09a281b842e1.tar.gz
quickshell-e3bd8e9f637dc6bed732170153cb09a281b842e1.zip
island: OBS pill and its controls panel
-rw-r--r--desktop/island/ObsPill.qml125
1 files changed, 125 insertions, 0 deletions
diff --git a/desktop/island/ObsPill.qml b/desktop/island/ObsPill.qml
new file mode 100644
index 0000000..73b35b0
--- /dev/null
+++ b/desktop/island/ObsPill.qml
@@ -0,0 +1,125 @@
+// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+import QtQuick
+import ".."
+import "Logic.js" as Logic
+
+// At rest a record dot, with the elapsed time while recording. A click
+// morphs the capsule into the controls panel, as the status pill does for
+// sound: record, pause, webcam, and the scene list.
+Capsule {
+ id: pill
+
+ property string panel: ""
+ signal openPanel()
+
+ expanded: panel === "obs"
+ restWidth: rest.implicitWidth + 24
+ panelWidth: 260
+ panelHeight: controls.implicitHeight + 28
+
+ Row {
+ id: rest
+ anchors.centerIn: parent
+ spacing: 6
+ opacity: pill.expanded ? 0 : 1
+ visible: opacity > 0
+ Behavior on opacity { NumberAnimation { duration: 120 } }
+
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ text: "\uf111"
+ color: Obs.recording ? Theme.red : Theme.subtext
+ opacity: Obs.paused ? 0.5 : 1
+ font { family: Theme.iconFamily; pixelSize: 14 }
+ }
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ visible: Obs.recording
+ text: Logic.obsElapsed(Obs.duration)
+ color: Theme.text
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 }
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ enabled: !pill.expanded
+ cursorShape: Qt.PointingHandCursor
+ onClicked: pill.openPanel()
+ }
+
+ Column {
+ id: controls
+ x: 14
+ y: 14
+ width: pill.panelWidth - 28
+ spacing: 10
+ opacity: pill.expanded ? 1 : 0
+ visible: opacity > 0
+ Behavior on opacity { NumberAnimation { duration: 160 } }
+
+ Text {
+ text: Obs.recording ? (Obs.paused ? "Paused " : "Recording ") + Logic.obsElapsed(Obs.duration)
+ : "Not recording"
+ color: Obs.recording ? Theme.red : Theme.subtext
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 }
+ }
+
+ Row {
+ spacing: 8
+ Button {
+ text: Obs.recording ? "Stop" : "Record"
+ danger: Obs.recording
+ onClicked: Obs.toggleRecord()
+ }
+ Button {
+ visible: Obs.recording
+ text: Obs.paused ? "Resume" : "Pause"
+ onClicked: Obs.togglePause()
+ }
+ Button {
+ visible: Obs.camId >= 0
+ text: Obs.camOn ? "Hide webcam" : "Show webcam"
+ onClicked: Obs.toggleCam()
+ }
+ }
+
+ // ponytail: a plain Column, no scrolling; about ten scenes fit the
+ // island's 480px window. A ListView if a scene collection outgrows it.
+ Repeater {
+ model: Obs.scenes
+ delegate: Rectangle {
+ required property string modelData
+ readonly property bool current: modelData === Obs.scene
+ width: controls.width
+ height: 30
+ radius: 7
+ color: current ? Qt.alpha(Theme.accent, 0.25)
+ : area.containsMouse ? Qt.alpha(Theme.surface, 0.8) : "transparent"
+ Text {
+ anchors { left: parent.left; leftMargin: 10; verticalCenter: parent.verticalCenter }
+ text: modelData
+ color: current ? Theme.text : Theme.subtext
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 }
+ }
+ MouseArea {
+ id: area
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: Obs.setScene(modelData)
+ }
+ }
+ }
+ }
+}