From 4f68e9e61afb2a75452d26a6c0ec86830e005fee Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Thu, 6 Nov 2025 10:29:59 +0100 Subject: [PATCH] add overlay --- dots/.config/hypr/hyprland/keybinds.conf | 2 +- dots/.config/hypr/hyprland/rules.conf | 2 +- dots/.config/quickshell/ii/GlobalStates.qml | 1 + .../widgets/AbstractBackgroundWidget.qml | 4 +- .../ii/modules/common/Persistent.qml | 16 ++ .../widgetCanvas/AbstractOverlayWidget.qml | 13 + .../widgets/widgetCanvas/WidgetCanvas.qml | 2 +- .../ii/modules/crosshair/Crosshair.qml | 57 ----- .../quickshell/ii/modules/overlay/Overlay.qml | 69 ++++++ .../ii/modules/overlay/OverlayContent.qml | 66 +++++ .../ii/modules/overlay/OverlayContext.qml | 37 +++ .../ii/modules/overlay/OverlayTaskbar.qml | 113 +++++++++ .../overlay/OverlayWidgetDelegateChooser.qml | 18 ++ .../modules/overlay/StyledOverlayWidget.qml | 230 ++++++++++++++++++ .../modules/overlay/crosshair/Crosshair.qml | 9 + .../crosshair/CrosshairContent.qml | 0 .../overlay/volumeMixer/VolumeMixer.qml | 24 ++ .../ii/modules/settings/InterfaceConfig.qml | 2 +- dots/.config/quickshell/ii/shell.qml | 6 +- 19 files changed, 605 insertions(+), 66 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/common/widgets/widgetCanvas/AbstractOverlayWidget.qml delete mode 100644 dots/.config/quickshell/ii/modules/crosshair/Crosshair.qml create mode 100644 dots/.config/quickshell/ii/modules/overlay/Overlay.qml create mode 100644 dots/.config/quickshell/ii/modules/overlay/OverlayContent.qml create mode 100644 dots/.config/quickshell/ii/modules/overlay/OverlayContext.qml create mode 100644 dots/.config/quickshell/ii/modules/overlay/OverlayTaskbar.qml create mode 100644 dots/.config/quickshell/ii/modules/overlay/OverlayWidgetDelegateChooser.qml create mode 100644 dots/.config/quickshell/ii/modules/overlay/StyledOverlayWidget.qml create mode 100644 dots/.config/quickshell/ii/modules/overlay/crosshair/Crosshair.qml rename dots/.config/quickshell/ii/modules/{ => overlay}/crosshair/CrosshairContent.qml (100%) create mode 100644 dots/.config/quickshell/ii/modules/overlay/volumeMixer/VolumeMixer.qml diff --git a/dots/.config/hypr/hyprland/keybinds.conf b/dots/.config/hypr/hyprland/keybinds.conf index b77166eb2..294854d67 100644 --- a/dots/.config/hypr/hyprland/keybinds.conf +++ b/dots/.config/hypr/hyprland/keybinds.conf @@ -33,7 +33,7 @@ bindd = Super, N, Toggle right sidebar, global, quickshell:sidebarRightToggle # bindd = Super, Slash, Toggle cheatsheet, global, quickshell:cheatsheetToggle # Toggle cheatsheet bindd = Super, K, Toggle on-screen keyboard, global, quickshell:oskToggle # Toggle on-screen keyboard bindd = Super, M, Toggle media controls, global, quickshell:mediaControlsToggle # Toggle media controls -bind = Super, G, global, quickshell:crosshairToggle # Toggle crosshair +bind = Super, G, global, quickshell:overlayToggle # Toggle overlay bindd = Ctrl+Alt, Delete, Toggle session menu, global, quickshell:sessionToggle # Toggle session menu bindd = Super, J, Toggle bar, global, quickshell:barToggle # Toggle bar bind = Ctrl+Alt, Delete, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill wlogout || wlogout -p layer-shell # [hidden] Session menu (fallback) diff --git a/dots/.config/hypr/hyprland/rules.conf b/dots/.config/hypr/hyprland/rules.conf index 7eb985c94..01ac1056d 100644 --- a/dots/.config/hypr/hyprland/rules.conf +++ b/dots/.config/hypr/hyprland/rules.conf @@ -134,11 +134,11 @@ layerrule = blur, quickshell:.* layerrule = ignorealpha 0.79, quickshell:.* layerrule = animation slide, quickshell:bar layerrule = animation slide bottom, quickshell:cheatsheet -layerrule = noanim, quickshell:crosshair layerrule = animation slide bottom, quickshell:dock layerrule = animation popin 120%, quickshell:screenCorners layerrule = noanim, quickshell:lockWindowPusher layerrule = animation fade, quickshell:notificationPopup +layerrule = noanim, quickshell:overlay layerrule = noanim, quickshell:overview layerrule = animation slide bottom, quickshell:osk layerrule = noanim, quickshell:polkit diff --git a/dots/.config/quickshell/ii/GlobalStates.qml b/dots/.config/quickshell/ii/GlobalStates.qml index 5cee09d96..972495c64 100644 --- a/dots/.config/quickshell/ii/GlobalStates.qml +++ b/dots/.config/quickshell/ii/GlobalStates.qml @@ -17,6 +17,7 @@ Singleton { property bool osdBrightnessOpen: false property bool osdVolumeOpen: false property bool oskOpen: false + property bool overlayOpen: false property bool overviewOpen: false property bool regionSelectorOpen: false property bool screenLocked: false diff --git a/dots/.config/quickshell/ii/modules/background/widgets/AbstractBackgroundWidget.qml b/dots/.config/quickshell/ii/modules/background/widgets/AbstractBackgroundWidget.qml index 4f16c51cd..b24c33aaa 100644 --- a/dots/.config/quickshell/ii/modules/background/widgets/AbstractBackgroundWidget.qml +++ b/dots/.config/quickshell/ii/modules/background/widgets/AbstractBackgroundWidget.qml @@ -35,9 +35,9 @@ AbstractWidget { draggable: placementStrategy === "free" onReleased: { root.targetX = root.x; - root.targetY = root.y; + root.targetY = root.y; configEntry.x = root.targetX; - configEntry.y = root.targetY ; + configEntry.y = root.targetY; } property bool needsColText: false diff --git a/dots/.config/quickshell/ii/modules/common/Persistent.qml b/dots/.config/quickshell/ii/modules/common/Persistent.qml index a705de098..814938452 100644 --- a/dots/.config/quickshell/ii/modules/common/Persistent.qml +++ b/dots/.config/quickshell/ii/modules/common/Persistent.qml @@ -79,6 +79,22 @@ Singleton { property bool inhibit: false } + property JsonObject overlay: JsonObject { + property list open: ["crosshair"] + property JsonObject crosshair: JsonObject { + property bool pinned: false + property bool clickthrough: true + property real x: 100 + property real y: 100 + } + property JsonObject volumeMixer: JsonObject { + property bool pinned: false + property bool clickthrough: false + property real x: 55 + property real y: 188 + } + } + property JsonObject timer: JsonObject { property JsonObject pomodoro: JsonObject { property bool running: false diff --git a/dots/.config/quickshell/ii/modules/common/widgets/widgetCanvas/AbstractOverlayWidget.qml b/dots/.config/quickshell/ii/modules/common/widgets/widgetCanvas/AbstractOverlayWidget.qml new file mode 100644 index 000000000..10ce0f5cb --- /dev/null +++ b/dots/.config/quickshell/ii/modules/common/widgets/widgetCanvas/AbstractOverlayWidget.qml @@ -0,0 +1,13 @@ +import QtQuick +import Quickshell +import qs.modules.common + +/* + * Abstract widgets for an overlay. Doesn't contain any visuals. + */ +AbstractWidget { + id: root + + property bool pinned: false // Whether to stay visible when the overlay is dismissed + property bool clickthrough: true // When pinned, whether to allow clicks go through +} diff --git a/dots/.config/quickshell/ii/modules/common/widgets/widgetCanvas/WidgetCanvas.qml b/dots/.config/quickshell/ii/modules/common/widgets/widgetCanvas/WidgetCanvas.qml index b40091432..d348ffae4 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/widgetCanvas/WidgetCanvas.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/widgetCanvas/WidgetCanvas.qml @@ -1,6 +1,6 @@ import QtQuick -Item { +MouseArea { id: root // uh this is stupid turns out we don't need anything here diff --git a/dots/.config/quickshell/ii/modules/crosshair/Crosshair.qml b/dots/.config/quickshell/ii/modules/crosshair/Crosshair.qml deleted file mode 100644 index f47902132..000000000 --- a/dots/.config/quickshell/ii/modules/crosshair/Crosshair.qml +++ /dev/null @@ -1,57 +0,0 @@ -import qs -import qs.modules.common -import qs.modules.common.widgets -import qs.services -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Quickshell -import Quickshell.Io -import Quickshell.Wayland -import Quickshell.Hyprland - -Scope { - id: root - - Loader { - id: crosshairLoader - active: GlobalStates.crosshairOpen - sourceComponent: PanelWindow { - id: crosshairWindow - exclusionMode: ExclusionMode.Ignore - WlrLayershell.namespace: "quickshell:crosshair" - WlrLayershell.layer: WlrLayer.Overlay - visible: true - color: "transparent" - - mask: Region { // Crosshair should not block mouse input - item: null - } - - implicitWidth: crosshairContent.implicitWidth - implicitHeight: crosshairContent.implicitHeight - - CrosshairContent { - id: crosshairContent - anchors.centerIn: parent - } - } - } - - IpcHandler { - target: "crosshair" - - function toggle(): void { - GlobalStates.crosshairOpen = !GlobalStates.crosshairOpen; - } - } - - GlobalShortcut { - name: "crosshairToggle" - description: "Toggles crosshair on press" - - onPressed: { - GlobalStates.crosshairOpen = !GlobalStates.crosshairOpen; - } - } -} diff --git a/dots/.config/quickshell/ii/modules/overlay/Overlay.qml b/dots/.config/quickshell/ii/modules/overlay/Overlay.qml new file mode 100644 index 000000000..5054b9d1c --- /dev/null +++ b/dots/.config/quickshell/ii/modules/overlay/Overlay.qml @@ -0,0 +1,69 @@ +import qs +import qs.modules.common +import qs.modules.common.widgets +import qs.services +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Hyprland + +Scope { + id: root + + property Component regionComponent: Component { + Region {} + } + + Loader { + id: overlayLoader + active: GlobalStates.overlayOpen || OverlayContext.hasPinnedWidgets + sourceComponent: PanelWindow { + id: overlayWindow + exclusionMode: ExclusionMode.Ignore + WlrLayershell.namespace: "quickshell:overlay" + WlrLayershell.layer: WlrLayer.Overlay + WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand + visible: true + color: "transparent" + + mask: Region { + item: GlobalStates.overlayOpen ? overlayContent : null + regions: OverlayContext.clickableWidgets.map((widget) => regionComponent.createObject(this, { + item: widget + })); + } + + anchors { + top: true + bottom: true + left: true + right: true + } + + OverlayContent { + id: overlayContent + anchors.fill: parent + } + } + } + + IpcHandler { + target: "overlay" + + function toggle(): void { + GlobalStates.overlayOpen = !GlobalStates.overlayOpen; + } + } + + GlobalShortcut { + name: "overlayToggle" + description: "Toggles overlay on press" + + onPressed: { + GlobalStates.overlayOpen = !GlobalStates.overlayOpen; + } + } +} diff --git a/dots/.config/quickshell/ii/modules/overlay/OverlayContent.qml b/dots/.config/quickshell/ii/modules/overlay/OverlayContent.qml new file mode 100644 index 000000000..9322bd777 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/overlay/OverlayContent.qml @@ -0,0 +1,66 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Widgets +import qs +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.widgets.widgetCanvas + +import qs.modules.overlay.crosshair + +Item { + id: root + readonly property bool usePasswordChars: !PolkitService.flow?.responseVisible ?? true + + Keys.onPressed: (event) => { // Esc to close + if (event.key === Qt.Key_Escape) { + GlobalStates.overlayOpen = false; + } + } + + property real initScale: 1.08 + scale: initScale + Component.onCompleted: { + scale = 1 + } + Behavior on scale { + animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) + } + + Rectangle { + id: bg + anchors.fill: parent + color: Appearance.colors.colScrim + opacity: (GlobalStates.overlayOpen && root.scale !== initScale) ? 1 : 0 + Behavior on opacity { + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) + } + } + + WidgetCanvas { + anchors.fill: parent + onClicked: GlobalStates.overlayOpen = false + + OverlayTaskbar { + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + topMargin: 50 + } + } + + Repeater { + model: ScriptModel { + values: Persistent.states.overlay.open.map(identifier => { + return OverlayContext.availableWidgets.find(w => w.identifier === identifier); + }) + objectProp: "identifier" + } + delegate: OverlayWidgetDelegateChooser { + + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/overlay/OverlayContext.qml b/dots/.config/quickshell/ii/modules/overlay/OverlayContext.qml new file mode 100644 index 000000000..1417c8467 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/overlay/OverlayContext.qml @@ -0,0 +1,37 @@ +pragma Singleton +pragma ComponentBehavior: Bound +import Quickshell + +Singleton { + id: root + + readonly property list availableWidgets: [ + { identifier: "crosshair", materialSymbol: "point_scan" }, + { identifier: "volumeMixer", materialSymbol: "volume_up" } + ] + + readonly property bool hasPinnedWidgets: root.pinnedWidgetIdentifiers.length > 0 + + property list pinnedWidgetIdentifiers: [] + property list clickableWidgets: [] + + function pin(identifier: string, pin = true) { + if (pin) { + if (!root.pinnedWidgetIdentifiers.includes(identifier)) { + root.pinnedWidgetIdentifiers.push(identifier) + } + } else { + root.pinnedWidgetIdentifiers = root.pinnedWidgetIdentifiers.filter(id => id !== identifier) + } + } + + function registerClickableWidget(widget: var, clickable = true) { + if (clickable) { + if (!root.clickableWidgets.includes(widget)) { + root.clickableWidgets.push(widget) + } + } else { + root.clickableWidgets = root.clickableWidgets.filter(w => w !== widget) + } + } +} diff --git a/dots/.config/quickshell/ii/modules/overlay/OverlayTaskbar.qml b/dots/.config/quickshell/ii/modules/overlay/OverlayTaskbar.qml new file mode 100644 index 000000000..65bb2a27e --- /dev/null +++ b/dots/.config/quickshell/ii/modules/overlay/OverlayTaskbar.qml @@ -0,0 +1,113 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets +import qs.modules.common.widgets.widgetCanvas + +Rectangle { + id: root + + property real padding: 8 + + opacity: GlobalStates.overlayOpen ? 1 : 0 + implicitWidth: contentRow.implicitWidth + (padding * 2) + implicitHeight: contentRow.implicitHeight + (padding * 2) + color: Appearance.m3colors.m3surfaceContainer + radius: Appearance.rounding.large + border.color: Appearance.colors.colOutlineVariant + border.width: 1 + + Behavior on opacity { + animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this) + } + + RowLayout { + id: contentRow + anchors { + fill: parent + margins: root.padding + } + spacing: 6 + + Row { + spacing: 4 + Repeater { + model: ScriptModel { + values: OverlayContext.availableWidgets + } + delegate: WidgetButton { + required property var modelData + identifier: modelData.identifier + materialSymbol: modelData.materialSymbol + } + } + } + + Separator {} + + TimeWidget {} + } + + component Separator: Rectangle { + implicitWidth: 1 + color: Appearance.colors.colOutlineVariant + Layout.fillHeight: true + Layout.topMargin: 10 + Layout.bottomMargin: 10 + } + + component TimeWidget: StyledText { + Layout.alignment: Qt.AlignVCenter + Layout.leftMargin: 8 + Layout.rightMargin: 6 + + text: DateTime.time + font { + family: Appearance.font.family.numbers + variableAxes: Appearance.font.variableAxes.numbers + pixelSize: 22 + } + } + + component WidgetButton: RippleButton { + id: widgetButton + required property string identifier + required property string materialSymbol + + Layout.alignment: Qt.AlignVCenter + + toggled: Persistent.states.overlay.open.includes(identifier) + onClicked: { + if (widgetButton.toggled) { + Persistent.states.overlay.open = Persistent.states.overlay.open.filter(type => type !== identifier); + } else { + Persistent.states.overlay.open.push(identifier); + } + } + implicitWidth: implicitHeight + + colBackgroundToggled: Appearance.colors.colSecondaryContainer + colBackgroundToggledHover: Appearance.colors.colSecondaryContainerHover + colRippleToggled: Appearance.colors.colSecondaryContainerActive + + buttonRadius: root.radius - (root.height - height) / 2 + + contentItem: Item { + anchors.centerIn: parent + implicitWidth: 32 + implicitHeight: 32 + MaterialSymbol { + id: iconWidget + anchors.centerIn: parent + iconSize: 24 + text: widgetButton.materialSymbol + color: widgetButton.toggled ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnSurfaceVariant + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/overlay/OverlayWidgetDelegateChooser.qml b/dots/.config/quickshell/ii/modules/overlay/OverlayWidgetDelegateChooser.qml new file mode 100644 index 000000000..e7420f625 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/overlay/OverlayWidgetDelegateChooser.qml @@ -0,0 +1,18 @@ +pragma ComponentBehavior: Bound +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Bluetooth +import qs.modules.overlay.crosshair +import qs.modules.overlay.volumeMixer + +DelegateChooser { + id: root + role: "identifier" + + DelegateChoice { roleValue: "crosshair"; Crosshair {} } + DelegateChoice { roleValue: "volumeMixer"; VolumeMixer {} } +} diff --git a/dots/.config/quickshell/ii/modules/overlay/StyledOverlayWidget.qml b/dots/.config/quickshell/ii/modules/overlay/StyledOverlayWidget.qml new file mode 100644 index 000000000..9e00f6f92 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/overlay/StyledOverlayWidget.qml @@ -0,0 +1,230 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Layouts +import Quickshell +import Qt5Compat.GraphicalEffects +import qs +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets +import qs.modules.common.widgets.widgetCanvas + +/* + * To make an overlay widget: + * 1. Create a modules/overlay//.qml, using this as the base class + * 2. Add an entry to OverlayContext.availableWidgets with identifier= + * 3. Add an entry in Persistent.states.overlay. with x, y, pinned, clickthrough properties set to reasonable defaults + * 4. Add an entry in OverlayWidgetDelegateChooser with roleValue= and Declare your widget in there + * Use existing entries as reference. + */ +AbstractOverlayWidget { + id: root + + required property var modelData + required property Item contentItem + + readonly property string identifier: modelData.identifier + readonly property string materialSymbol: modelData.materialSymbol ?? "widgets" + property string title: identifier.replace(/([A-Z])/g, " $1").replace(/^./, function(str){ return str.toUpperCase(); }) + property var persistentStateEntry: Persistent.states.overlay[identifier] + property real radius: Appearance.rounding.windowRounding + property real minWidth: 250 + + draggable: GlobalStates.overlayOpen + x: Math.round(persistentStateEntry.x) // Round or it'll be blurry + y: Math.round(persistentStateEntry.y) // Round or it'll be blurry + pinned: persistentStateEntry.pinned + clickthrough: persistentStateEntry.clickthrough + drag { + minimumX: 0 + minimumY: 0 + maximumX: root.parent.width - root.width + maximumY: root.parent.height - root.height + } + + // Guarded states & registration funcs + property bool open: Persistent.states.overlay.open + property bool actuallyPinned: pinned && open + property bool actuallyClickable: !clickthrough && actuallyPinned && open + onActuallyPinnedChanged: reportPinnedState(); + onActuallyClickableChanged: reportClickableState(); + function reportPinnedState() { + OverlayContext.pin(identifier, actuallyPinned); + } + function reportClickableState() { + OverlayContext.registerClickableWidget(contentItem, actuallyClickable); + } + + // Self-registeration with OverlayContext + Component.onCompleted: { + reportPinnedState(); + reportClickableState(); + } + + // Hooks + onReleased: savePosition(); + + function close() { + Persistent.states.overlay.open = Persistent.states.overlay.open.filter(type => type !== root.identifier); + } + + function togglePinned() { + persistentStateEntry.pinned = !persistentStateEntry.pinned; + } + + function toggleClickthrough() { + persistentStateEntry.clickthrough = !persistentStateEntry.clickthrough; + } + + function savePosition(xPos = root.x, yPos = root.y) { + persistentStateEntry.x = xPos; + persistentStateEntry.y = yPos; + } + + function center() { + const targetX = (root.parent.width - contentColumn.width) / 2 + const targetY = (root.parent.height - contentItem.height) / 2 - titleBar.implicitHeight + root.x = targetX + root.y = targetY + root.savePosition(targetX, targetY) + } + + visible: GlobalStates.overlayOpen || actuallyPinned + implicitWidth: Math.max(contentColumn.implicitWidth, minWidth) + implicitHeight: contentColumn.implicitHeight + + Rectangle { + id: border + anchors.fill: parent + color: "transparent" + radius: root.radius + border.color: ColorUtils.transparentize(Appearance.colors.colOutlineVariant, GlobalStates.overlayOpen ? 0 : 1) + border.width: 1 + + layer.enabled: GlobalStates.overlayOpen + layer.effect: OpacityMask { + maskSource: Rectangle { + width: border.width + height: border.height + radius: root.radius + } + } + + Column { + id: contentColumn + z: -1 + anchors.fill: parent + + // Title bar + Rectangle { + id: titleBar + opacity: GlobalStates.overlayOpen ? 1 : 0 + anchors { + left: parent.left + right: parent.right + } + property real padding: 2 + implicitWidth: titleBarRow.implicitWidth + padding * 2 + implicitHeight: titleBarRow.implicitHeight + padding * 2 + color: Appearance.m3colors.m3surfaceContainer + border.color: Appearance.colors.colOutlineVariant + border.width: 1 + + RowLayout { + id: titleBarRow + anchors { + fill: parent + margins: titleBar.padding + leftMargin: titleBar.padding + 8 + } + spacing: 0 + + MaterialSymbol { + text: root.materialSymbol + iconSize: 20 + Layout.alignment: Qt.AlignVCenter + Layout.rightMargin: 4 + } + + StyledText { + text: root.title + Layout.fillWidth: true + elide: Text.ElideRight + } + + TitlebarButton { + materialSymbol: "recenter" + onClicked: root.center() + StyledToolTip { + text: "Center" + } + } + + TitlebarButton { + materialSymbol: "mouse" + toggled: !root.clickthrough + onClicked: root.toggleClickthrough() + StyledToolTip { + text: "Clickable when pinned" + } + } + + TitlebarButton { + materialSymbol: "keep" + toggled: root.pinned + onClicked: root.togglePinned() + StyledToolTip { + text: "Pin" + } + } + + TitlebarButton { + materialSymbol: "close" + onClicked: root.close() + StyledToolTip { + text: "Close" + } + } + } + } + + // Content + Item { + id: contentContainer + anchors.horizontalCenter: parent.horizontalCenter + implicitWidth: root.contentItem.implicitWidth + implicitHeight: root.contentItem.implicitHeight + children: [root.contentItem] + } + } + } + + + component TitlebarButton: RippleButton { + id: titlebarButton + required property string materialSymbol + buttonRadius: height / 2 + implicitHeight: contentItem.implicitHeight + implicitWidth: implicitHeight + padding: 0 + + colBackgroundToggled: Appearance.colors.colSecondaryContainer + colBackgroundToggledHover: Appearance.colors.colSecondaryContainerHover + colRippleToggled: Appearance.colors.colSecondaryContainerActive + + contentItem: Item { + anchors.centerIn: parent + implicitWidth: 30 + implicitHeight: 30 + + MaterialSymbol { + id: iconWidget + anchors.centerIn: parent + iconSize: 20 + text: titlebarButton.materialSymbol + fill: titlebarButton.toggled + color: titlebarButton.toggled ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnSurface + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/overlay/crosshair/Crosshair.qml b/dots/.config/quickshell/ii/modules/overlay/crosshair/Crosshair.qml new file mode 100644 index 000000000..abb1cbf26 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/overlay/crosshair/Crosshair.qml @@ -0,0 +1,9 @@ +import QtQuick +import Quickshell +import qs.modules.common +import qs.modules.overlay + +StyledOverlayWidget { + id: root + contentItem: CrosshairContent {} +} diff --git a/dots/.config/quickshell/ii/modules/crosshair/CrosshairContent.qml b/dots/.config/quickshell/ii/modules/overlay/crosshair/CrosshairContent.qml similarity index 100% rename from dots/.config/quickshell/ii/modules/crosshair/CrosshairContent.qml rename to dots/.config/quickshell/ii/modules/overlay/crosshair/CrosshairContent.qml diff --git a/dots/.config/quickshell/ii/modules/overlay/volumeMixer/VolumeMixer.qml b/dots/.config/quickshell/ii/modules/overlay/volumeMixer/VolumeMixer.qml new file mode 100644 index 000000000..433a2e11f --- /dev/null +++ b/dots/.config/quickshell/ii/modules/overlay/volumeMixer/VolumeMixer.qml @@ -0,0 +1,24 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.modules.common +import qs.modules.overlay +import qs.modules.sidebarRight.volumeMixer + +StyledOverlayWidget { + id: root + contentItem: Rectangle { + anchors.centerIn: parent + color: Appearance.m3colors.m3surfaceContainer + property real padding: 16 + implicitHeight: 700 + implicitWidth: 400 + + VolumeDialogContent { + anchors.fill: parent + anchors.margins: parent.padding + isSink: true + } + + } +} diff --git a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml index b7bff73b1..a373e9959 100644 --- a/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml +++ b/dots/.config/quickshell/ii/modules/settings/InterfaceConfig.qml @@ -26,7 +26,7 @@ ContentPage { Layout.leftMargin: 10 color: Appearance.colors.colSubtext font.pixelSize: Appearance.font.pixelSize.smallie - text: Translation.tr("Press Super+G to toggle appearance") + text: Translation.tr("Press Super+G to open the overlay and pin the crosshair") } Item { Layout.fillWidth: true diff --git a/dots/.config/quickshell/ii/shell.qml b/dots/.config/quickshell/ii/shell.qml index d50f6640f..209597fcf 100644 --- a/dots/.config/quickshell/ii/shell.qml +++ b/dots/.config/quickshell/ii/shell.qml @@ -11,7 +11,6 @@ import qs.modules.common import qs.modules.background import qs.modules.bar import qs.modules.cheatsheet -import qs.modules.crosshair import qs.modules.dock import qs.modules.lock import qs.modules.mediaControls @@ -25,6 +24,7 @@ import qs.modules.screenCorners import qs.modules.sessionScreen import qs.modules.sidebarLeft import qs.modules.sidebarRight +import qs.modules.overlay import qs.modules.verticalBar import qs.modules.wallpaperSelector @@ -39,7 +39,6 @@ ShellRoot { property bool enableBar: true property bool enableBackground: true property bool enableCheatsheet: true - property bool enableCrosshair: true property bool enableDock: true property bool enableLock: true property bool enableMediaControls: true @@ -47,6 +46,7 @@ ShellRoot { property bool enablePolkit: true property bool enableOnScreenDisplay: true property bool enableOnScreenKeyboard: true + property bool enableOverlay: true property bool enableOverview: true property bool enableRegionSelector: true property bool enableReloadPopup: true @@ -70,13 +70,13 @@ ShellRoot { LazyLoader { active: enableBar && Config.ready && !Config.options.bar.vertical; component: Bar {} } LazyLoader { active: enableBackground; component: Background {} } LazyLoader { active: enableCheatsheet; component: Cheatsheet {} } - LazyLoader { active: enableCrosshair; component: Crosshair {} } LazyLoader { active: enableDock && Config.options.dock.enable; component: Dock {} } LazyLoader { active: enableLock; component: Lock {} } LazyLoader { active: enableMediaControls; component: MediaControls {} } LazyLoader { active: enableNotificationPopup; component: NotificationPopup {} } LazyLoader { active: enableOnScreenDisplay; component: OnScreenDisplay {} } LazyLoader { active: enableOnScreenKeyboard; component: OnScreenKeyboard {} } + LazyLoader { active: enableOverlay; component: Overlay {} } LazyLoader { active: enableOverview; component: Overview {} } LazyLoader { active: enablePolkit; component: Polkit {} } LazyLoader { active: enableRegionSelector; component: RegionSelector {} }