hefty: bar: window info

This commit is contained in:
end-4
2026-03-20 23:38:14 +01:00
parent 36f01b78fe
commit 350f48a74b
6 changed files with 313 additions and 8 deletions
@@ -159,8 +159,8 @@ Singleton {
property JsonObject apps: JsonObject {
property string bluetooth: "kcmshell6 kcm_bluetooth"
property string changePassword: "kitty -1 --hold=yes fish -i -c 'passwd'"
property string network: "kcmshell6 kcm_networkmanagement"
property string manageUser: "kcmshell6 kcm_users"
property string network: "kcmshell6 kcm_networkmanagement"
property string networkEthernet: "kcmshell6 kcm_networkmanagement"
property string taskManager: "plasma-systemmonitor --page-name Processes"
property string terminal: "kitty -1" // This is only for shell actions
@@ -4,7 +4,7 @@ import Quickshell.Io
JsonObject {
property JsonObject bar: JsonObject {
property list<var> leftWidgets: ["HLeftSidebarButton"]
property list<var> leftWidgets: ["HLeftSidebarButton", "HWindowInfo"]
property list<var> centerLeftWidgets: ["HTime"]
property list<var> centerWidgets: ["HWorkspaces"]
property list<var> centerRightWidgets: ["HResources"]
@@ -11,6 +11,9 @@ Item {
property alias verticalAlignment: textWidget.verticalAlignment
property alias font: textWidget.font
property alias color: textWidget.color
property alias elide: textWidget.elide
property alias wrapMode: textWidget.wrapMode
property alias animateChange: textWidget.animateChange
// In many cases the baseline is a bit high to accomodate the dangling parts of "g" and "y",
// making most text (especiall number-only text) not well-balanced.
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.modules.common as C
import qs.modules.common.widgets as W
Item {
id: root
@@ -19,10 +20,17 @@ Item {
id: leftSide
anchors.left: parent.left
anchors.top: parent.top
anchors.right: !root.vertical ? centerLeftSide.left : parent.right
anchors.bottom: !root.vertical ? parent.bottom : centerLeftSide.top
HBarUserFallbackComponentRepeater {
componentNames: root.leftWidgets
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
}
Side {
@@ -56,12 +64,20 @@ Item {
id: rightSide
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.left: !root.vertical ? centerRightSide.right : parent.left
anchors.top: !root.vertical ? parent.top : centerRightSide.bottom
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
HBarUserFallbackComponentRepeater {
componentNames: root.rightWidgets
}
}
component Side: GridLayout {
component Side: W.BoxLayout {
anchors {
top: !root.vertical ? parent.top : undefined
bottom: !root.vertical ? parent.bottom : undefined
@@ -73,9 +89,7 @@ Item {
rightMargin: root.spacing * !root.vertical
}
columns: C.Config.options.bar.vertical ? 1 : -1
property real spacing: root.spacing
columnSpacing: spacing
rowSpacing: spacing
vertical: C.Config.options.bar.vertical
spacing: root.spacing
}
}
@@ -1,5 +1,6 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.modules.common as C
import qs.modules.common.widgets as W
@@ -48,6 +49,11 @@ Repeater {
context: root.context
property bool startSide: index === 0
property bool endSide: index === root.model.length - 1
Layout.fillWidth: item.Layout.fillWidth
Layout.fillHeight: item.Layout.fillHeight
Layout.maximumWidth: item.Layout.maximumWidth
Layout.maximumHeight: item.Layout.maximumHeight
}
}
@@ -74,4 +80,4 @@ Repeater {
}
}
}
}
}
@@ -0,0 +1,282 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import Quickshell.Hyprland
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import ".."
HBarWidgetWithPopout {
id: root
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.QsWindow.window?.screen)
readonly property Toplevel activeWindow: ToplevelManager.activeToplevel
readonly property var activeHyprlandClient: HyprlandData.clientForToplevel(activeWindow)
readonly property bool focusingThisMonitor: HyprlandData.activeWorkspace?.monitor == monitor?.name
readonly property var biggestWindow: HyprlandData.biggestWindowForWorkspace(HyprlandData.monitors[root.monitor?.id]?.activeWorkspace.id)
readonly property bool hasFocusedWindow: (focusingThisMonitor && activeWindow?.activated && biggestWindow) ?? false
readonly property string primaryText: {
if (root.hasFocusedWindow)
return root.activeWindow?.title;
return (root.biggestWindow?.title) ?? `${Translation.tr("Workspace")} ${root.monitor?.activeWorkspace?.id ?? 1}`;
}
readonly property string secondaryText: {
if (root.hasFocusedWindow && root.activeWindow?.appId != "" && root.activeWindow?.appId != primaryText)
return root.activeWindow?.appId;
return Translation.tr("Options")
}
property real fontPixelSize: Appearance.font.pixelSize.smaller
Layout.maximumWidth: implicitWidth
Layout.fillWidth: true
popupContentWidth: popupContent.implicitWidth
popupContentHeight: popupContent.implicitHeight
HBarWidgetContent {
id: contentRoot
Layout.fillWidth: true
Layout.fillHeight: true
vertical: root.vertical
atBottom: root.atBottom
contentImplicitWidth: winTitleContent.implicitWidth
contentImplicitHeight: winTitleContent.implicitHeight
showPopup: false
onClicked: root.showPopup = !root.showPopup;
WinTitleContent {
id: winTitleContent
}
WinOptionsPopup {
id: popupContent
anchors {
top: parent.top
topMargin: root.popupContentOffsetY
left: parent.left
leftMargin: root.popupContentOffsetX
}
shown: root.showPopup
}
}
component WinTitleContent: BoxLayout {
anchors.fill: parent
vertical: root.vertical
spacing: 4
Item {
Layout.leftMargin: 4 * !root.vertical
Layout.topMargin: 3 * root.vertical
Layout.bottomMargin: 4 * root.vertical
Layout.alignment: Qt.AlignCenter
implicitWidth: appIcon.implicitWidth
implicitHeight: appIcon.implicitHeight
AppIcon {
id: appIcon
anchors.centerIn: parent
opacity: 0
source: Quickshell.iconPath(AppSearch.guessIcon(root.activeWindow?.appId), "image-missing")
implicitSize: 16
animated: false
}
Circle {
id: iconMask
visible: false
layer.enabled: true
diameter: appIcon.implicitSize
}
Loader {
anchors.fill: appIcon
Colorizer {
id: renderedIcon
implicitWidth: appIcon.implicitWidth
implicitHeight: appIcon.implicitHeight
colorizationColor: Appearance.colors.colOnLayer0
// colorization: Config.options.bar.workspaces.monochromeIcons ? 0.8 : 0.5
colorization: 1
brightness: 0
source: appIcon
maskEnabled: true
maskSource: iconMask
maskThresholdMin: 0.5
maskSpreadAtMin: 1
visible: root.activeWindow
}
}
MaterialSymbol {
anchors.centerIn: parent
visible: !renderedIcon.visible
text: "overview_key"
iconSize: 16
}
}
Item {
visible: !root.vertical
Layout.rightMargin: 4
Layout.alignment: Qt.AlignCenter
Layout.fillHeight: true
// No overflow
Layout.maximumWidth: implicitWidth
Layout.fillWidth: true
// Size
implicitWidth: winText.implicitWidth
implicitHeight: winText.implicitHeight
FlyFadeEnterChoreographable {
anchors.fill: parent
progress: contentRoot.containsMouse ? 0 : 1
reverseDirection: true
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
VisuallyCenteredStyledText {
id: winText
height: parent.height
width: parent.width
elide: Text.ElideRight
// Styles & text
font.pixelSize: root.fontPixelSize
text: root.primaryText
}
}
FlyFadeEnterChoreographable {
anchors.fill: parent
progress: contentRoot.containsMouse ? 1 : 0
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
VisuallyCenteredStyledText {
height: parent.height
width: parent.width
elide: Text.ElideRight
horizontalAlignment: Text.AlignLeft
// Styles & text
font.pixelSize: root.fontPixelSize
text: root.secondaryText
}
}
}
}
component WinOptionsPopup: ChoreographerLoader {
sourceComponent: ChoreographerGridLayout {
id: popupRoot
columns: 3
rowSpacing: 8
columnSpacing: 6
FlyFadeEnterChoreographable {
Layout.fillWidth: true
Layout.columnSpan: 3
StyledText {
width: parent.width
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
text: root.hasFocusedWindow ? Translation.tr("Window options") : Translation.tr("Launch")
// font.pixelSize: Appearance.font.pixelSize.title
}
}
FlyFadeEnterChoreographable {
visible: !root.hasFocusedWindow
PopupLabeledIconButton {
materialSymbol: "terminal"
text: Translation.tr("Terminal")
onClicked: Quickshell.execDetached(["bash", "-c", Config.options.apps.terminal]);
}
}
FlyFadeEnterChoreographable {
visible: !root.hasFocusedWindow
PopupLabeledIconButton {
materialSymbol: "files"
text: Translation.tr("Files")
onClicked: Qt.openUrlExternally(Directories.home);
}
}
FlyFadeEnterChoreographable {
visible: !root.hasFocusedWindow
PopupLabeledIconButton {
materialSymbol: "language"
text: Translation.tr("Browser")
// Kinda hacky. Works with Google and DDG at least
onClicked: Qt.openUrlExternally(Config.options.search.engineBaseUrl);
}
}
FlyFadeEnterChoreographable {
visible: root.hasFocusedWindow
PopupLabeledIconButton {
materialSymbol: "content_copy"
text: Translation.tr("Address")
onClicked: Quickshell.clipboardText = root.activeHyprlandClient.address
}
}
FlyFadeEnterChoreographable {
visible: root.hasFocusedWindow
PopupLabeledIconButton {
property bool toFloat: !(root.activeHyprlandClient?.floating ?? false)
materialSymbol: toFloat ? "picture_in_picture_center" : "side_navigation"
text: toFloat ? Translation.tr("Float") : Translation.tr("Tile")
onClicked: {
Hyprland.dispatch(`togglefloating address:${root.activeHyprlandClient.address}`)
HyprlandData.updateWindowList()
}
}
}
FlyFadeEnterChoreographable {
visible: root.hasFocusedWindow
PopupLabeledIconButton {
materialSymbol: "warning"
text: Translation.tr("Kill")
colBackground: Appearance.colors.colError
colForeground: Appearance.colors.colOnError
onClicked: {
Hyprland.dispatch(`killwindow address:${root.activeHyprlandClient.address}`)
HyprlandData.updateWindowList()
}
}
}
}
}
component PopupLabeledIconButton: Column {
id: licobtn
property string materialSymbol: "circle"
property string text: "Label"
property alias colBackground: btn.colBackground
property alias colForeground: btn.colForeground
spacing: 4
signal clicked()
onClicked: root.showPopup = false
StyledIconButton {
id: btn
implicitWidth: 70
implicitHeight: 50
text: licobtn.materialSymbol
iconSize: 24
colBackground: Appearance.colors.colLayer4
colForeground: Appearance.colors.colOnLayer4
onClicked: licobtn.clicked()
}
StyledText {
anchors.horizontalCenter: parent.horizontalCenter
text: licobtn.text
}
}
}