feat: bar popouts

Create active window popout
This commit is contained in:
2 * r + 2 * t 2025-06-02 16:31:26 +08:00
parent e52c3d82a0
commit 24a3da8138
10 changed files with 263 additions and 0 deletions

View file

@ -12,6 +12,18 @@ StyledRect {
required property ShellScreen screen
function checkPopout(y: real): var {
const aw = activeWindow.child
const awy = activeWindow.y + aw.y
if (y >= awy && y <= awy + aw.implicitHeight) {
Popouts.currentName = "activewindow"
Popouts.currentCenter = Qt.binding(() => activeWindow.y + aw.y + aw.implicitHeight / 2);
Popouts.hasCurrent = true;
} else {
Popouts.hasCurrent = false;
}
}
anchors.top: parent.top
anchors.bottom: parent.bottom
@ -21,6 +33,19 @@ StyledRect {
Component.onCompleted: Visibilities.bars[screen] = this
MouseArea {
anchors.fill: parent
hoverEnabled: true
onPositionChanged: event => root.checkPopout(event.y)
onContainsMouseChanged: {
if (!containsMouse)
Popouts.hasCurrent = false;
}
}
Item {
id: child

View file

@ -10,6 +10,7 @@ Item {
id: root
property color colour: Colours.palette.m3primary
readonly property Item child: child
implicitWidth: child.implicitWidth
implicitHeight: child.implicitHeight

View file

@ -0,0 +1,33 @@
import "root:/widgets"
import "root:/services"
import "root:/utils"
import "root:/config"
import Quickshell.Wayland
import QtQuick
Item {
id: root
implicitWidth: child.implicitWidth
implicitHeight: child.implicitHeight
Column {
id: child
anchors.centerIn: parent
StyledText {
text: Hyprland.activeClient?.title ?? ""
}
StyledText {
text: Hyprland.activeClient?.wmClass ?? ""
}
ScreencopyView {
}
}
}

View file

@ -0,0 +1,63 @@
import "root:/services"
import "root:/config"
import QtQuick
import QtQuick.Shapes
ShapePath {
id: root
required property Wrapper wrapper
readonly property real rounding: BorderConfig.rounding
readonly property bool flatten: wrapper.width < rounding * 2
readonly property real roundingX: flatten ? wrapper.width / 2 : rounding
strokeWidth: -1
fillColor: BorderConfig.colour
PathArc {
relativeX: root.roundingX
relativeY: root.rounding
radiusX: Math.min(root.rounding, root.wrapper.width)
radiusY: root.rounding
direction: PathArc.Counterclockwise
}
PathLine {
relativeX: root.wrapper.width - root.roundingX * 2
relativeY: 0
}
PathArc {
relativeX: root.roundingX
relativeY: root.rounding
radiusX: Math.min(root.rounding, root.wrapper.width)
radiusY: root.rounding
}
PathLine {
relativeX: 0
relativeY: root.wrapper.height - root.rounding * 4
}
PathArc {
relativeX: -root.roundingX
relativeY: root.rounding
radiusX: Math.min(root.rounding, root.wrapper.width)
radiusY: root.rounding
}
PathLine {
relativeX: -(root.wrapper.width - root.roundingX * 2)
relativeY: 0
}
PathArc {
relativeX: -root.roundingX
relativeY: root.rounding
radiusX: Math.min(root.rounding, root.wrapper.width)
radiusY: root.rounding
direction: PathArc.Counterclockwise
}
Behavior on fillColor {
ColorAnimation {
duration: Appearance.anim.durations.normal
easing.type: Easing.BezierSpline
easing.bezierCurve: Appearance.anim.curves.standard
}
}
}

View file

@ -0,0 +1,79 @@
import "root:/services"
import "root:/config"
import Quickshell
import Quickshell.Widgets
import QtQuick
Item {
id: root
required property ShellScreen screen
anchors.centerIn: parent
implicitWidth: Popouts.hasCurrent ? content.children.find(c => c.shouldBeActive).implicitWidth + Appearance.padding.large * 2 : 0
implicitHeight: Popouts.hasCurrent ? content.children.find(c => c.shouldBeActive).implicitHeight + Appearance.padding.large * 2 : 0
clip: true
Item {
id: content
anchors.fill: parent
anchors.margins: Appearance.padding.large
clip: true
Popout {
name: "activewindow"
sourceComponent: ActiveWindow {}
}
}
Behavior on implicitWidth {
Anim {
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
Behavior on implicitHeight {
Anim {
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
component Popout: Loader {
id: popout
required property string name
property bool shouldBeActive: Popouts.currentName === name
active: shouldBeActive
asynchronous: true
Behavior on active {
SequentialAnimation {
Anim {
target: popout
property: "opacity"
from: popout.shouldBeActive ? 1 : 0
to: popout.shouldBeActive ? 0 : 1
duration: popout.shouldBeActive ? 0 : Appearance.anim.durations.normal
}
PropertyAction {}
Anim {
target: popout
property: "opacity"
from: popout.shouldBeActive ? 0 : 1
to: popout.shouldBeActive ? 1 : 0
duration: popout.shouldBeActive ? Appearance.anim.durations.normal : 0
}
}
}
}
component Anim: NumberAnimation {
duration: Appearance.anim.durations.normal
easing.type: Easing.BezierSpline
easing.bezierCurve: Appearance.anim.curves.standard
}
}

View file

@ -0,0 +1,19 @@
import "root:/services"
import "root:/config"
import Quickshell
import QtQuick
Item {
id: root
required property ShellScreen screen
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight + BorderConfig.rounding * 2
Content {
id: content
screen: root.screen
}
}

View file

@ -5,6 +5,7 @@ import "root:/modules/notifications" as Notifications
import "root:/modules/session" as Session
import "root:/modules/launcher" as Launcher
import "root:/modules/dashboard" as Dashboard
import "root:/modules/bar/popouts" as BarPopouts
import QtQuick.Shapes
Shape {
@ -51,4 +52,11 @@ Shape {
startX: (root.width - wrapper.width) / 2
startY: 0
}
BarPopouts.Background {
wrapper: panels.popouts
startX: 0
startY: wrapper.y
}
}

View file

@ -37,6 +37,7 @@ MouseArea {
visibilities.osd = false;
osdHovered = false;
visibilities.dashboard = false;
Popouts.hasCurrent = false;
}
}
@ -58,6 +59,18 @@ MouseArea {
// Show dashboard on hover
const showDashboard = root.inTopPanel(panels.dashboard, x, y);
visibilities.dashboard = showDashboard;
// Show popouts on hover
const popout = panels.popouts;
if (x < BorderConfig.thickness + popout.width) {
if (x < BorderConfig.thickness)
// Handle like part of bar
Visibilities.bars[screen].checkPopout(y);
else
// Keep on hover
Popouts.hasCurrent = withinPanelHeight(popout, x, y);
} else
Popouts.hasCurrent = false;
}
Osd.Interactions {

View file

@ -5,6 +5,7 @@ import "root:/modules/notifications" as Notifications
import "root:/modules/session" as Session
import "root:/modules/launcher" as Launcher
import "root:/modules/dashboard" as Dashboard
import "root:/modules/bar/popouts" as BarPopouts
import Quickshell
import QtQuick
@ -19,6 +20,7 @@ Item {
readonly property Session.Wrapper session: session
readonly property Launcher.Wrapper launcher: launcher
readonly property Dashboard.Wrapper dashboard: dashboard
readonly property BarPopouts.Wrapper popouts: popouts
anchors.fill: parent
anchors.margins: BorderConfig.thickness
@ -70,4 +72,14 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
}
BarPopouts.Wrapper {
id: popouts
screen: root.screen
anchors.left: parent.left
anchors.verticalCenter: parent.top
anchors.verticalCenterOffset: Popouts.currentCenter - BorderConfig.thickness
}
}

10
services/Popouts.qml Normal file
View file

@ -0,0 +1,10 @@
pragma Singleton
import Quickshell
import QtQuick
Singleton {
property string currentName
property real currentCenter
property bool hasCurrent
}