Build the Panama Hyprland desktop
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
// Quiet transient Signal Glass content. It acknowledges one meaningful state
|
||||
// transition and then leaves; it is not a notification and has no history.
|
||||
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
import qs.widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
required property var event
|
||||
readonly property color toneColor: {
|
||||
if (event?.tone === "danger")
|
||||
return Theme.danger;
|
||||
if (event?.tone === "warn")
|
||||
return Theme.warn;
|
||||
if (event?.tone === "ok")
|
||||
return Theme.ok;
|
||||
return Theme.accent;
|
||||
}
|
||||
|
||||
radius: Theme.popoverRadius
|
||||
color: Theme.alpha(Theme.bgPopover, 0.86)
|
||||
border.width: 1
|
||||
border.color: Theme.alpha(Theme.fg, 0.09)
|
||||
|
||||
PrismEdge {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 1
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
inset: parent.radius
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: mark
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 38
|
||||
height: 38
|
||||
radius: 19
|
||||
border.width: 0
|
||||
color: Theme.alpha(root.toneColor, 0.14)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: root.event?.glyph !== ""
|
||||
text: root.event?.glyph ?? ""
|
||||
color: root.toneColor
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 19
|
||||
}
|
||||
|
||||
ThemedIcon {
|
||||
anchors.centerIn: parent
|
||||
visible: root.event?.glyph === ""
|
||||
size: 19
|
||||
icon: root.event?.icon ?? "dialog-information-symbolic"
|
||||
tint: root.toneColor
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: mark.right
|
||||
anchors.leftMargin: 11
|
||||
anchors.right: closeButton.left
|
||||
anchors.rightMargin: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: root.event?.title ?? ""
|
||||
color: Theme.fg
|
||||
elide: Text.ElideRight
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
visible: text !== ""
|
||||
text: root.event?.detail ?? ""
|
||||
color: Theme.fgDim
|
||||
elide: Text.ElideRight
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: closeButton
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 28
|
||||
height: 28
|
||||
radius: 14
|
||||
border.width: 0
|
||||
color: closeMouse.containsMouse ? Theme.alpha(Theme.fg, Theme.hoverAlpha) : "transparent"
|
||||
|
||||
ThemedIcon {
|
||||
anchors.centerIn: parent
|
||||
size: 14
|
||||
icon: "window-close-symbolic"
|
||||
tint: Theme.fgDim
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: StatusEvents.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.left: parent.left
|
||||
anchors.right: closeButton.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
cursorShape: root.event?.actionId ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
onClicked: {
|
||||
if (root.event?.actionId)
|
||||
StatusEvents.invoke();
|
||||
else
|
||||
StatusEvents.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// Rich persistent mode of Signal Glass. Dismiss hides controls only; the
|
||||
// compact bar timer remains until the session ends.
|
||||
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.modules.focus
|
||||
import qs.services
|
||||
import qs.widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
radius: Theme.popoverRadius
|
||||
color: Theme.alpha(Theme.bgPopover, 0.88)
|
||||
border.width: 1
|
||||
border.color: Theme.alpha(Theme.fg, 0.1)
|
||||
|
||||
PrismEdge {
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 1
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
inset: parent.radius
|
||||
}
|
||||
|
||||
Item {
|
||||
id: primary
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 12
|
||||
height: 54
|
||||
|
||||
Rectangle {
|
||||
id: focusMark
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 38
|
||||
height: 38
|
||||
radius: 19
|
||||
border.width: 0
|
||||
color: Theme.alpha(Theme.accent, 0.16)
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "\u{F051F}"
|
||||
color: Theme.accent
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 20
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: focusMark.right
|
||||
anchors.leftMargin: 11
|
||||
anchors.right: remaining.left
|
||||
anchors.rightMargin: 12
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: FocusSession.workspaceLabel || "Focus session"
|
||||
color: Theme.fg
|
||||
elide: Text.ElideRight
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: FocusSession.statusText
|
||||
color: FocusSession.paused ? Theme.warn : Theme.fgDim
|
||||
elide: Text.ElideRight
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: remaining
|
||||
anchors.right: closeButton.left
|
||||
anchors.rightMargin: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: FocusSession.remainingText
|
||||
color: FocusSession.paused ? Theme.warn : Theme.fg
|
||||
font.family: Theme.fontFamily
|
||||
font.features: Theme.tabularFigures
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.DemiBold
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: closeButton
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 28
|
||||
height: 28
|
||||
radius: 14
|
||||
border.width: 0
|
||||
color: closeMouse.containsMouse ? Theme.alpha(Theme.fg, Theme.hoverAlpha) : "transparent"
|
||||
|
||||
ThemedIcon {
|
||||
anchors.centerIn: parent
|
||||
size: 14
|
||||
icon: "window-close-symbolic"
|
||||
tint: Theme.fgDim
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: closeMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: FocusSession.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.left: parent.left
|
||||
anchors.right: closeButton.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
z: -1
|
||||
onClicked: {
|
||||
FocusSession.activateWorkspace();
|
||||
FocusSession.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.leftMargin: 12
|
||||
anchors.rightMargin: 12
|
||||
anchors.bottomMargin: 12
|
||||
spacing: Theme.itemSpacing
|
||||
|
||||
FocusAction {
|
||||
width: (parent.width - parent.spacing * 2) / 3
|
||||
icon: FocusSession.paused ? "media-playback-start-symbolic" : "media-playback-pause-symbolic"
|
||||
label: FocusSession.paused ? "Resume" : "Pause"
|
||||
onActivated: FocusSession.pauseOrResume()
|
||||
}
|
||||
|
||||
FocusAction {
|
||||
width: (parent.width - parent.spacing * 2) / 3
|
||||
icon: "view-grid-symbolic"
|
||||
iconFallback: "view-app-grid-symbolic"
|
||||
label: "Workspace"
|
||||
onActivated: {
|
||||
ShellState.openOverview(FocusSession.workspaceId);
|
||||
FocusSession.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
FocusAction {
|
||||
width: (parent.width - parent.spacing * 2) / 3
|
||||
icon: "process-stop-symbolic"
|
||||
label: "End"
|
||||
destructive: true
|
||||
onActivated: FocusSession.end(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// The one Signal Glass layer surface. Transient curated events briefly take
|
||||
// precedence; when they expire, an explicitly revealed focus session returns.
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Wayland
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
property var modelData: null
|
||||
readonly property var event: StatusEvents.activeEvent
|
||||
readonly property string eventMonitor: root.event?.monitorName ?? Hyprland.focusedMonitor?.name ?? ""
|
||||
readonly property bool eventBelongsHere: StatusEvents.active && (!root.eventMonitor || !root.modelData || root.modelData.name === root.eventMonitor)
|
||||
readonly property bool focusBelongsHere: FocusSession.active && FocusSession.capsuleVisible
|
||||
&& (!FocusSession.monitorName || !root.modelData || root.modelData.name === FocusSession.monitorName)
|
||||
readonly property bool showingEvent: root.eventBelongsHere
|
||||
readonly property bool requestedVisible: root.showingEvent || root.focusBelongsHere
|
||||
|
||||
screen: root.modelData
|
||||
anchors.top: true
|
||||
margins.top: Theme.barHeight + Theme.barGap * 2
|
||||
exclusiveZone: 0
|
||||
implicitWidth: root.showingEvent ? 388 : 438
|
||||
implicitHeight: root.showingEvent ? 76 : 132
|
||||
color: "transparent"
|
||||
|
||||
WlrLayershell.namespace: "qs-signal-glass"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
property bool mapped: false
|
||||
visible: root.mapped
|
||||
|
||||
onRequestedVisibleChanged: {
|
||||
if (root.requestedVisible) {
|
||||
unmapTimer.stop();
|
||||
root.mapped = true;
|
||||
entrance.restart();
|
||||
} else if (root.mapped) {
|
||||
unmapTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
onShowingEventChanged: {
|
||||
if (root.requestedVisible)
|
||||
entrance.restart();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (root.requestedVisible)
|
||||
root.mapped = true;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: unmapTimer
|
||||
interval: Theme.durNormal
|
||||
onTriggered: root.mapped = false
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
sourceComponent: root.showingEvent ? eventComponent : focusComponent
|
||||
opacity: root.requestedVisible ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: Theme.durNormal; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
transform: Translate {
|
||||
id: slide
|
||||
y: root.requestedVisible ? 0 : -6
|
||||
Behavior on y {
|
||||
NumberAnimation { duration: Theme.durNormal; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: eventComponent
|
||||
EventCard { event: root.event }
|
||||
}
|
||||
|
||||
Component {
|
||||
id: focusComponent
|
||||
FocusCard {}
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
id: entrance
|
||||
NumberAnimation { target: content; property: "opacity"; from: 0; to: 1; duration: Theme.durNormal; easing.type: Easing.OutCubic }
|
||||
NumberAnimation { target: slide; property: "y"; from: -6; to: 0; duration: Theme.durNormal; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
module qs.modules.signals
|
||||
EventCard 1.0 EventCard.qml
|
||||
FocusCard 1.0 FocusCard.qml
|
||||
SignalGlass 1.0 SignalGlass.qml
|
||||
Reference in New Issue
Block a user