fix: fixed screenshot tool not working

This commit is contained in:
kossLAN 2025-07-08 22:06:29 -04:00
parent 83a0ac8899
commit 1f2de51ad5
Signed by: kossLAN
SSH key fingerprint: SHA256:bdV0x+wdQHGJ6LgmstH3KV8OpWY+OOFmJcPcB0wQPV8
20 changed files with 68 additions and 1391 deletions

View file

@ -27,9 +27,7 @@ Singleton {
} }
property JsonObject sizing: JsonObject { property JsonObject sizing: JsonObject {
property int borderWidth: 5 property int barHeight: 25
property int topBorderWidth: 20
property int gaps: 5
} }
property var colors: { property var colors: {

View file

@ -1,19 +1,17 @@
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Widgets
import "power" import "power"
import "volume" import "volume"
import "systray" as SysTray import "systray" as SysTray
import "popups" as Popup import "popups" as Popup
import "mpris" as Mpris
import "../widgets" as Widgets import "../widgets" as Widgets
import ".." import ".."
PanelWindow { PanelWindow {
id: root id: root
color: ShellSettings.colors["surface"] color: ShellSettings.colors["surface"]
implicitHeight: ShellSettings.settings.barHeight implicitHeight: ShellSettings.sizing.barHeight
property alias popup: popupWindow property alias popup: popupWindow
anchors { anchors {
@ -38,14 +36,11 @@ PanelWindow {
} }
// Left side of bar // Left side of bar
Item { RowLayout {
spacing: 5
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
RowLayout {
spacing: 10
anchors.fill: parent
HyprWorkspaces { HyprWorkspaces {
screen: root.screen screen: root.screen
Layout.fillHeight: true Layout.fillHeight: true
@ -68,27 +63,13 @@ PanelWindow {
Layout.fillHeight: true Layout.fillHeight: true
} }
} }
}
// Center of bar
WrapperItem {
topMargin: 2
bottomMargin: 2
Layout.fillHeight: true
Mpris.Button {
bar: root
}
}
// Right side of bar // Right side of bar
Item { RowLayout {
spacing: 5
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
RowLayout {
anchors.fill: parent
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
@ -126,5 +107,4 @@ PanelWindow {
} }
} }
} }
}
} }

View file

@ -1,12 +0,0 @@
import QtQuick
import Quickshell.Wayland
import ".."
Text {
id: windowText
text: ToplevelManager.activeToplevel?.title ?? ""
color: ShellSettings.colors["inverse_surface"]
font.pointSize: 11
visible: text !== ""
elide: Text.ElideRight
}

View file

@ -1,117 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Effects
import Quickshell
import ".."
Scope {
id: root
required property var screen
property alias topWindow: topPanel
property alias top: topPanel.data
PanelWindow {
id: overlay
color: "transparent"
screen: root.modelData
mask: Region {}
anchors {
left: true
right: true
top: true
bottom: true
}
Item {
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: ShellSettings.colors["surface"]
// visible: false
layer.enabled: true
layer.effect: MultiEffect {
maskEnabled: true
maskSource: mask
maskInverted: true // Changed from true to false
maskThresholdMin: 0.5
maskSpreadAtMin: 1
}
}
Item {
id: mask
anchors.fill: parent
layer.enabled: true
visible: false
Rectangle {
color: "white"
radius: 15
anchors {
fill: parent
margins: ShellSettings.sizing.borderWidth
topMargin: ShellSettings.sizing.topBorderWidth
}
}
}
}
}
PanelWindow {
id: topPanel
screen: root.modelData
color: "transparent"
implicitHeight: ShellSettings.sizing.topBorderWidth
anchors {
top: true
left: true
right: true
}
}
PanelWindow {
id: bottomPanel
screen: root.modelData
color: "transparent"
implicitHeight: ShellSettings.sizing.borderWidth
anchors {
bottom: true
left: true
right: true
}
}
PanelWindow {
id: leftPanel
screen: root.modelData
color: "transparent"
implicitWidth: ShellSettings.sizing.borderWidth
anchors {
top: true
bottom: true
left: true
}
}
PanelWindow {
id: rightPanel
screen: root.modelData
color: "transparent"
implicitWidth: ShellSettings.sizing.borderWidth
anchors {
top: true
bottom: true
right: true
}
}
}

View file

@ -1,21 +0,0 @@
import QtQuick
import Quickshell
Text {
property string ap: sysClock.hours >= 12 ? "PM" : "AM"
property string minutes: sysClock.minutes.toString().padStart(2, '0')
property string hours: {
var value = sysClock.hours % 12;
if (value === 0)
return 12;
return value;
}
SystemClock {
id: sysClock
enabled: true
}
text: `${hours}:${minutes} ${ap}`
font.pointSize: 11
}

View file

@ -1,102 +0,0 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import "power"
import "volume"
import "systray" as SysTray
import "popups" as Popup
import "../widgets"
import ".."
Scope {
id: root
Variants {
model: Quickshell.screens
Border {
id: border
screen: modelData
required property var modelData
top: RowLayout {
id: top
spacing: 0
anchors {
fill: parent
leftMargin: 8
rightMargin: 8
}
Popup.MenuWindow {
id: popupWindow
bar: border.topWindow
}
RowLayout {
spacing: 5
Layout.fillWidth: true
Layout.fillHeight: true
Workspaces {
screen: border.screen
Layout.fillHeight: true
}
Separator {
visible: activeWindow.visible
Layout.leftMargin: 5
Layout.rightMargin: 5
}
ActiveWindow {
id: activeWindow
Layout.preferredWidth: 400
}
}
RowLayout {
spacing: 5
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignRight
SysTray.SysTray {
id: sysTray
popup: popupWindow
Layout.fillHeight: true
}
VolumeIndicator {
id: volumeIndicator
popup: popupWindow
Layout.preferredWidth: this.height
Layout.fillHeight: true
Layout.topMargin: 2
Layout.bottomMargin: 2
}
BatteryIndicator {
id: batteryIndicator
popup: popupWindow
Layout.fillHeight: true
}
Separator {
// Layout.leftMargin: 5
Layout.rightMargin: 5
}
Clock {
id: clock
color: ShellSettings.colors["inverse_surface"]
}
}
}
}
}
}

View file

@ -1,73 +0,0 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
import ".."
RowLayout {
spacing: 6
visible: Hyprland.monitors.values.length != 0
required property var screen
Repeater {
id: workspaceButtons
model: ScriptModel {
values: Hyprland.workspaces.values.slice().filter(
workspace => workspace.monitor === Hyprland.monitorFor(screen)
)
}
Rectangle {
required property var modelData
radius: height / 2
Layout.alignment: Qt.AlignVCenter
Layout.preferredHeight: 12
Layout.preferredWidth: {
if (Hyprland.focusedMonitor?.activeWorkspace?.id === modelData?.id)
return 25;
return 12;
}
color: {
let value = Qt.color(ShellSettings.colors["secondary"]).darker(2);
if (!modelData?.id || !Hyprland.focusedMonitor?.activeWorkspace?.id)
return value;
if (workspaceButton.containsMouse) {
value = ShellSettings.colors["on_primary"];
} else if (Hyprland.focusedMonitor.activeWorkspace.id === modelData.id) {
value = ShellSettings.colors["primary"];
}
return value;
}
Behavior on Layout.preferredWidth {
SmoothedAnimation {
duration: 150
velocity: 200
easing.type: Easing.OutCubic
}
}
Behavior on color {
ColorAnimation {
duration: 100
easing.type: Easing.OutQuad
}
}
MouseArea {
id: workspaceButton
anchors.fill: parent
hoverEnabled: true
onPressed: Hyprland.dispatch(`workspace ${parent.modelData.id}`)
}
}
}
}

View file

@ -1,70 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import Qt5Compat.GraphicalEffects
import Quickshell.Widgets
import "../.."
Item {
id: root
required property var bar
property var implicitSize: 0
readonly property real actualSize: Math.min(root.width, root.height)
implicitWidth: parent.height
implicitHeight: parent.height
NotificationCenter {
id: notificationCenter
}
Rectangle {
color: mouseArea.containsMouse ? ShellSettings.colors["primary"] : "transparent"
radius: 5
anchors {
fill: parent
margins: 1
}
}
MouseArea {
id: mouseArea
hoverEnabled: true
anchors.fill: parent
onPressed: {
if (notificationCenter.visible) {
notificationCenter.hide();
} else {
notificationCenter.show();
}
}
}
Item {
implicitWidth: root.implicitSize
implicitHeight: root.implicitSize
anchors.centerIn: parent
layer.enabled: true
layer.effect: OpacityMask {
source: Rectangle {
width: root.actualSize
height: root.actualSize
color: "white"
}
maskSource: IconImage {
implicitSize: root.actualSize
source: "root:resources/general/notification.svg"
}
}
Rectangle {
color: mouseArea.containsMouse ? ShellSettings.colors["inverse_primary"] : ShellSettings.colors["inverse_surface"]
anchors.fill: parent
}
}
// TODO: notification number overlay
}

View file

@ -1,233 +0,0 @@
import Quickshell
import Quickshell.Hyprland
import Quickshell.Widgets
import QtQuick
import QtQuick.Shapes
// import QtQuick.Effects
import "../.."
// In need of heavy refactor
PopupWindow {
id: root
color: "transparent"
implicitWidth: bar.width
implicitHeight: Math.max(popupContainer.height, 800) + 20
mask: Region {
item: popupContainer
}
anchor {
window: bar
rect: Qt.rect(0, 0, bar.width, bar.height)
edges: Edges.Bottom | Edges.Left
gravity: Edges.Bottom | Edges.Right
adjustment: PopupAdjustment.None
}
required property var bar
property var isOpen: false
property var padding: ShellSettings.sizing.borderWidth
property var radius: 12
property var item
property var content
function set(item, content) {
root.item = item;
root.content = content;
popupContent.data = content;
let itemPos = item.mapToItem(root.bar.contentItem, 0, root.bar.height, item.width, 0).x;
position(itemPos);
popupContainer.opacity = 0;
popupContent.opacity = 0;
}
function position(itemPos) {
if (itemPos === undefined)
return;
let rightEdge = itemPos + popupContainer.implicitWidth;
let maxRightEdge = root.width - padding;
let isTouchingRightEdge = rightEdge > maxRightEdge;
if (isTouchingRightEdge) {
// touching right edge, reposition
// console.log("touching right edge");
popupContainer.x = maxRightEdge - popupContainer.implicitWidth;
popupContainer.y = 0;
popupContainer.bottomLeftRadius = radius;
popupContainer.bottomRightRadius = 0;
} else {
// not touching right edge
popupContainer.x = itemPos;
popupContainer.y = 0;
popupContainer.bottomLeftRadius = radius;
popupContainer.bottomRightRadius = radius;
}
}
function show() {
grab.active = true;
isOpen = true;
root.visible = true; // set and leave open
root.content.visible = true;
popupContainer.opacity = 1;
popupContent.opacity = 1;
}
function hide() {
grab.active = false;
isOpen = false;
popupContainer.opacity = 0;
popupContent.opacity = 0;
root.item = undefined;
root.content = undefined;
popupContent.data = [];
}
function toggle() {
if (isOpen) {
hide();
} else {
show();
}
}
// RectangularShadow {
// radius: popupContainer.radius
// anchors.fill: popupContainer
// opacity: popupContainer.opacity
// visible: popupContainer.visible
// blur: 10
// spread: 2
// }
Shape {
id: shapeContainer
// anchors.fill: popupContainer
width: implicitWidth
height: implicitHeight
opacity: popupContainer.opacity
WrapperRectangle {
id: popupContainer
color: ShellSettings.colors["surface"]
margin: 8
clip: true
opacity: 0
// visible: opacity > 0
// x: root.bar.width
// spooky, likely to cause problems lol
width: implicitWidth
height: implicitHeight
onVisibleChanged: root.visible = visible
// needed to handle occurrences where items are resized while open
onImplicitWidthChanged: {
if (root.isOpen && popupContent.data !== []) {
// console.log("repositioning popup");
let itemPos = root.item.mapToItem(root.bar.contentItem, 0, root.bar.height, root.item.width, 0).x;
root.position(itemPos);
}
}
Item {
id: popupContent
implicitWidth: Math.max(root.content?.width, 60)
implicitHeight: Math.max(childrenRect.height, 60)
Behavior on opacity {
NumberAnimation {
duration: 200
easing.type: Easing.Linear
from: 0
to: 1
}
}
}
HyprlandFocusGrab {
id: grab
windows: [root, root.bar]
onCleared: {
root.hide();
}
}
Behavior on width {
enabled: root.isOpen
SmoothedAnimation {
duration: 200
easing.type: Easing.Linear
}
}
Behavior on height {
SmoothedAnimation {
duration: 200
easing.type: Easing.Linear
}
}
Behavior on x {
enabled: root.isOpen
SmoothedAnimation {
duration: 200
easing.type: Easing.OutQuad
}
}
}
ShapePath {
strokeWidth: -1
fillColor: ShellSettings.colors["surface"]
startX: popupContainer.x - 25
startY: popupContainer.y
PathLine {
relativeX: 25
relativeY: 0
}
PathLine {
relativeX: 0
relativeY: 25
}
PathArc {
direction: PathArc.Counterclockwise
relativeX: -25
relativeY: -25
radiusX: 25
radiusY: 25
useLargeArc: false
}
// PathLine {
// x: 0
// y: 12
// } // Vertical line down
// PathLine {
// x: 12
// y: 12
// } // Horizontal line to the right
// PathLine {
// x: 12
// y: 0
// } // Horizontal line back to the top
}
Behavior on opacity {
NumberAnimation {
duration: 200
easing.type: Easing.Linear
}
}
}
}

View file

@ -1,102 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell.Widgets
import Quickshell.Services.UPower
import "../../widgets" as Widgets
import "../.."
// todo: redo the tray icon handling
Item {
id: root
implicitWidth: height + 8 // for margin
visible: UPower.displayDevice.isLaptopBattery
required property var popup
Widgets.MaterialButton {
id: batteryButton
hoverEnabled: true
onClicked: {
if (root.popup.content == powerMenu) {
root.popup.hide();
return;
}
root.popup.set(this, powerMenu);
root.popup.show();
}
anchors {
fill: parent
margins: 1
}
Item {
implicitWidth: parent.height
implicitHeight: parent.height
anchors.centerIn: parent
layer.enabled: true
layer.effect: OpacityMask {
source: Rectangle {
width: root.width
height: root.height
color: "white"
}
maskSource: IconImage {
implicitSize: root.width
source: "root:resources/battery/battery.svg"
}
}
Rectangle {
id: batteryBackground
color: Qt.color(ShellSettings.colors["surface"]).lighter(4)
opacity: 0.75
anchors {
fill: parent
margins: 2
}
}
Rectangle {
id: batteryPercentage
width: (parent.width - 4) * UPower.displayDevice.percentage
color: ShellSettings.colors["inverse_surface"]
anchors {
left: batteryBackground.left
top: batteryBackground.top
bottom: batteryBackground.bottom
}
}
}
}
Item {
id: powerMenu
visible: false
implicitWidth: 250
implicitHeight: 80
RowLayout {
anchors.fill: parent
// ComboBox {
// model: ScriptModel {
// values: ["Power Save", "Balanced", "Performance"]
// }
//
// currentIndex: PowerProfiles.profile
// onCurrentIndexChanged: {
// PowerProfiles.profile = this.currentIndex;
// console.log(PowerProfile.toString(PowerProfiles.profile));
// }
// }
}
}
}

View file

@ -1,96 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import Quickshell.Services.SystemTray
import "../../widgets" as Widgets
RowLayout {
id: root
spacing: 5
visible: SystemTray.items.values.length > 0
required property var popup
Repeater {
model: SystemTray.items
delegate: Item {
id: trayField
Layout.preferredWidth: parent.height
Layout.fillHeight: true
required property SystemTrayItem modelData
Widgets.MaterialButton {
id: trayButton
hoverEnabled: true
onClicked: {
menuOpener.menu = trayField.modelData.menu;
if (root.popup.content == trayMenu) {
root.popup.hide();
return;
}
root.popup.set(this, trayMenu);
root.popup.show();
}
anchors {
fill: parent
margins: 2
}
IconImage {
id: trayIcon
anchors.fill: parent
source: {
// console.log(trayField.modelData.id);
switch (trayField.modelData.id) {
case "obs":
return "image://icon/obs-tray";
default:
return trayField.modelData.icon;
}
}
}
}
QsMenuOpener {
id: menuOpener
}
WrapperItem {
id: trayMenu
visible: false
property var leftItem: false
property var rightItem: false
ColumnLayout {
id: menuContainer
spacing: 2
Repeater {
model: menuOpener.children
delegate: TrayMenuItem {
id: sysTrayContent
Layout.fillWidth: true
Layout.fillHeight: true
rootMenu: trayMenu
onInteracted: {
root.popup.hide();
menuOpener.menu = null;
}
}
}
}
}
}
}
}

View file

@ -1,170 +0,0 @@
import Quickshell
import Quickshell.Widgets
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "../../widgets" as Widgets
import "../.."
ColumnLayout {
id: root
required property QsMenuEntry menuData
required property var rootMenu
signal interacted
Component.onCompleted: {
if (menuData?.buttonType !== QsMenuButtonType.None || menuData?.icon != "") {
rootMenu.leftItem = true;
}
if (menuData?.hasChildren) {
rootMenu.rightItem = true;
}
}
WrapperRectangle {
Layout.fillWidth: true
Layout.preferredHeight: 25
radius: 6
color: {
if (!root.menuData?.enabled)
return "transparent";
if (entryArea.containsMouse)
return ShellSettings.colors["primary"];
return "transparent";
}
WrapperMouseArea {
id: entryArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
if (!root.menuData?.enabled)
return;
if (root.menuData?.hasChildren) {
subTrayMenu.visible = !subTrayMenu.visible;
return;
}
root.menuData?.triggered();
root.interacted();
}
RowLayout {
id: menuEntry
spacing: 5
Layout.fillWidth: true
Item {
visible: root.rootMenu.leftItem
Layout.preferredWidth: 20
Layout.fillHeight: true
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 5
RadioButton {
id: radioButton
visible: (root.menuData?.buttonType === QsMenuButtonType.RadioButton) ?? false
checked: (root.menuData?.checkState) ?? false
anchors.centerIn: parent
}
CheckBox {
id: checkBox
visible: (root.menuData?.buttonType === QsMenuButtonType.CheckBox) ?? false
checked: (root.menuData?.checkState) ?? false
anchors.centerIn: parent
}
IconImage {
id: entryImage
visible: (root.menuData?.buttonType === QsMenuButtonType.None && root.menuData?.icon !== "") ?? false
source: (root.menuData?.icon) ?? ""
anchors.fill: parent
}
}
Text {
id: text
text: root.menuData?.text ?? ""
verticalAlignment: Text.AlignVCenter
color: {
let color = Qt.color(ShellSettings.colors["inverse_surface"]);
if (!root.menuData?.enabled)
return color.darker(2);
if (entryArea.containsMouse)
return Qt.color(ShellSettings.colors["inverse_primary"]);
return color;
}
Layout.fillWidth: true
Layout.fillHeight: true
}
Item {
visible: root.rootMenu.rightItem
Layout.preferredHeight: 20
Layout.preferredWidth: 20
Layout.rightMargin: 5
Widgets.IconButton {
id: arrowButton
visible: root.menuData?.hasChildren ?? false
activeRectangle: false
source: "root:resources/general/right-arrow.svg"
rotation: subTrayMenu.visible ? 90 : 0
anchors.fill: parent
Behavior on rotation {
NumberAnimation {
duration: 150
easing.type: Easing.OutCubic
}
}
onClicked: {
root.expanded = !root.expanded;
}
}
}
}
}
}
WrapperRectangle {
id: subTrayMenu
color: ShellSettings.colors["surface_container"]
radius: 8
visible: false
Layout.fillWidth: true
QsMenuOpener {
id: menuOpener
menu: root.menuData
}
ColumnLayout {
id: subTrayContainer
spacing: 2
Layout.fillWidth: true
Repeater {
model: menuOpener.children
delegate: BoundComponent {
id: subMenuEntry
source: "TrayMenuItem.qml"
Layout.fillWidth: true
required property var modelData
property var rootMenu: root.rootMenu
}
}
}
}
}

View file

@ -1,29 +0,0 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import "../.."
ColumnLayout {
id: root
required property QsMenuEntry modelData
required property var rootMenu
property var leftItem
signal interacted
Rectangle {
visible: (root.modelData?.isSeparator ?? false)
color: ShellSettings.colors["surface_container_high"]
Layout.fillWidth: true
Layout.preferredHeight: 2
Layout.leftMargin: 8
Layout.rightMargin: 8
}
TrayMenuEntry {
visible: !root.modelData?.isSeparator
rootMenu: root.rootMenu
menuData: root.modelData
Layout.fillWidth: true
onInteracted: root.interacted()
}
}

View file

@ -1,70 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import Quickshell.Services.Pipewire
import "../../widgets/" as Widgets
import "../.."
ColumnLayout {
id: root
Loader {
id: sinkLoader
active: sink
property PwNode sink: Pipewire.defaultAudioSink
sourceComponent: WrapperItem {
PwNodeLinkTracker {
id: linkTracker
node: sinkLoader.sink
}
ColumnLayout {
Repeater {
model: linkTracker.linkGroups
delegate: Loader {
id: nodeLoader
active: modelData.source !== null
Layout.preferredWidth: 350
Layout.preferredHeight: 45
required property PwLinkGroup modelData
sourceComponent: VolumeCard {
id: nodeCard
node: nodeLoader.modelData.source
text: node.properties["media.name"] ?? ""
// if icon-name is undefined, just gonna fallback on the application name
icon: IconImage {
source: {
if (nodeCard.node.properties["application.icon-name"] !== undefined)
return `image://icon/${nodeCard.node.properties["application.icon-name"]}`;
let applicationName = nodeCard.node.properties["application.name"];
return `image://icon/${applicationName?.toLowerCase() ?? "image-missing"}`;
}
}
button: Widgets.FontIconButton {
hoverEnabled: false
iconName: nodeCard.node.audio.muted ? "volume_off" : "volume_up"
checked: !nodeCard.node.audio.muted
inactiveColor: ShellSettings.colors["surface_container_highest"]
onClicked: {
nodeCard.node.audio.muted = !nodeCard.node.audio.muted;
}
}
anchors.fill: parent
}
}
}
}
}
}
}

View file

@ -1,64 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell.Services.Pipewire
import "../../widgets/" as Widgets
import "../.."
ColumnLayout {
id: root
// headphones
// don't load until the node is not null
Loader {
id: sinkLoader
active: sink !== null
Layout.preferredWidth: 350
Layout.preferredHeight: 45
property PwNode sink: Pipewire.defaultAudioSink
sourceComponent: VolumeCard {
id: sinkCard
node: sinkLoader.sink
button: Widgets.FontIconButton {
hoverEnabled: false
iconName: sinkCard.node.audio.muted ? "volume_off" : "volume_up"
checked: !sinkCard.node.audio.muted
inactiveColor: ShellSettings.colors["surface_container_highest"]
onClicked: {
sinkCard.node.audio.muted = !sinkCard.node.audio.muted;
}
}
anchors.fill: parent
}
}
// microphone, same as above
Loader {
id: sourceLoader
active: source !== null
Layout.preferredWidth: 350
Layout.preferredHeight: 45
property PwNode source: Pipewire.defaultAudioSource
sourceComponent: VolumeCard {
id: sourceCard
node: sourceLoader.source
button: Widgets.FontIconButton {
hoverEnabled: false
iconName: sourceCard.node.audio.muted ? "mic_off" : "mic"
checked: !sourceCard.node.audio.muted
inactiveColor: ShellSettings.colors["surface_container_highest"]
onClicked: {
sourceCard.node.audio.muted = !sourceCard.node.audio.muted;
}
}
anchors.fill: parent
}
}
}

View file

@ -1,50 +0,0 @@
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import Quickshell.Services.Pipewire
import "../../widgets/" as Widgets
import "../.."
WrapperRectangle {
id: root
color: ShellSettings.colors["surface_container"]
radius: width / 2
margin: 6
required property PwNode node
property string text
property Component button
property Component icon
PwObjectTracker {
id: tracker
objects: [root.node]
}
RowLayout {
Widgets.MaterialSlider {
value: root.node.audio.volume ?? 0
text: root.text
icon: root.icon
onValueChanged: {
// only allow changes when the node is ready other wise you will combust
if (!root.node.ready)
return;
root.node.audio.volume = value;
}
Layout.fillWidth: true
Layout.fillHeight: true
}
Loader {
id: buttonLoader
sourceComponent: root.button
Layout.preferredWidth: this.height
Layout.fillHeight: true
}
}
}

View file

@ -1,34 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import "../../widgets/" as Widgets
WrapperItem {
id: root
visible: false
ColumnLayout {
spacing: 10
Widgets.TabBar {
id: tabBar
model: ["headphones", "tune"]
Layout.fillWidth: true
Layout.preferredHeight: 35
}
StackLayout {
id: page
currentIndex: tabBar.currentIndex
Layout.fillWidth: true
Layout.preferredHeight: currentItem ? currentItem.implicitHeight : 0
readonly property Item currentItem: children[currentIndex]
DeviceMixer {}
ApplicationMixer {}
}
}
}

View file

@ -1,27 +0,0 @@
import QtQuick
import "../../widgets/" as Widgets
Item {
id: root
required property var popup
Widgets.FontIconButton {
id: button
iconName: "volume_up"
anchors.fill: parent
onClicked: {
if (root.popup.content == volumeMenu) {
root.popup.hide();
return;
}
root.popup.set(this, volumeMenu);
root.popup.show();
}
}
VolumeControl {
id: volumeMenu
}
}

View file

@ -20,9 +20,8 @@ Singleton {
} }
} }
// Just use this window to grab screen context
LazyLoader { LazyLoader {
activeAsync: root.windowOpen active: root.windowOpen
PanelWindow { PanelWindow {
id: focusedScreen id: focusedScreen
@ -43,56 +42,27 @@ Singleton {
focus: true focus: true
Keys.onEscapePressed: root.windowOpen = false Keys.onEscapePressed: root.windowOpen = false
// to get a freeze frame for now
ScreencopyView {
id: screenView
captureSource: focusedScreen.screen
anchors.fill: parent
SelectionRectangle { SelectionRectangle {
id: selection id: selection
anchors.fill: parent anchors.fill: parent
property string position
property bool running: false
onAreaSelected: selection => { onAreaSelected: selection => {
let screen = focusedScreen.screen; let screen = focusedScreen.screen;
const x = Math.floor(selection.x) + screen.x; const x = Math.floor(selection.x) + screen.x;
const y = Math.floor(selection.y) + screen.y; const y = Math.floor(selection.y) + screen.y;
const width = Math.floor(selection.width); const width = Math.floor(selection.width);
const height = Math.floor(selection.height); const height = Math.floor(selection.height);
position = `${x},${y} ${width}x${height}`;
running = true; let position = `${x},${y} ${width}x${height}`;
} let path = "/home/koss/Pictures/screenshot.png";
LazyLoader { Quickshell.execDetached({
activeAsync: selection.running command: ["grim", "-g", position, path]
});
Process {
id: grim
running: true
property var path: `${ShellSettings.settings.screenshotPath}/screenshot.png`
command: ["grim", "-g", selection.position, path]
onRunningChanged: {
if (!running) {
// Quickshell.clipboardText = `image://${path}`;
root.windowOpen = false; root.windowOpen = false;
} }
} }
stderr: SplitParser {
onRead: data => console.log(`line read: ${data}`)
}
}
}
}
}
} }
} }
} }

View file

@ -3,8 +3,7 @@
import Quickshell import Quickshell
import QtQuick import QtQuick
// import "bar" as Bar import "bar" as Bar
import "experimental-bar" as Bar
import "notifications" as Notifications import "notifications" as Notifications
import "mpris" as Mpris import "mpris" as Mpris
import "volume-osd" as VolumeOSD import "volume-osd" as VolumeOSD