Introduces a dedicated layer-shell `WindowChromeSurface` that renders macOS-style traffic-light controls over the focused Sway window titlebar, replacing the old top-bar window controls. Adds theme tokens and a reusable `TrafficLightButton` component, updates shell QML/CMake wiring, and adjusts Sway titlebar padding/title format so window titles do not overlap the overlay. Window tracking was extended with focused-window geometry/deco/fullscreen properties plus backend refresh support so the chrome follows window movement and state changes in near real time.
124 lines
3.3 KiB
QML
124 lines
3.3 KiB
QML
import QtQuick
|
|
import Nebula.UI
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property string label: ""
|
|
property color fill: Theme.trafficClose
|
|
property string glyph: "close"
|
|
property bool showGlyph: false
|
|
readonly property bool hovered: hover.containsMouse
|
|
readonly property bool pressed: hover.pressed
|
|
|
|
signal clicked()
|
|
|
|
implicitWidth: Theme.trafficLightSize + 2
|
|
implicitHeight: Theme.trafficLightSize + 2
|
|
Accessible.role: Accessible.Button
|
|
Accessible.name: root.label
|
|
Accessible.onPressAction: root.clicked()
|
|
|
|
Rectangle {
|
|
id: disc
|
|
anchors.centerIn: parent
|
|
width: Theme.trafficLightSize
|
|
height: Theme.trafficLightSize
|
|
radius: width / 2
|
|
color: hover.pressed ? Qt.darker(root.fill, 1.18) : root.fill
|
|
border.width: 1
|
|
border.color: Qt.rgba(0, 0, 0, 0.22)
|
|
|
|
Behavior on color {
|
|
ColorAnimation {
|
|
duration: Theme.animationFast
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 1
|
|
width: parent.width - 4
|
|
height: Math.max(2, parent.height * 0.38)
|
|
radius: height / 2
|
|
color: Qt.rgba(1, 1, 1, 0.28)
|
|
Accessible.ignored: true
|
|
}
|
|
}
|
|
|
|
Canvas {
|
|
id: glyph
|
|
anchors.centerIn: parent
|
|
width: 8
|
|
height: 8
|
|
antialiasing: true
|
|
opacity: root.showGlyph ? 1 : 0
|
|
visible: opacity > 0.01
|
|
onPaint: {
|
|
const ctx = getContext("2d")
|
|
ctx.reset()
|
|
ctx.strokeStyle = Qt.rgba(0.18, 0.12, 0.1, 0.78)
|
|
ctx.fillStyle = ctx.strokeStyle
|
|
ctx.lineWidth = 1.15
|
|
ctx.lineCap = "round"
|
|
ctx.lineJoin = "round"
|
|
|
|
switch (root.glyph) {
|
|
case "minimize":
|
|
ctx.beginPath()
|
|
ctx.moveTo(1.2, 4)
|
|
ctx.lineTo(6.8, 4)
|
|
ctx.stroke()
|
|
break
|
|
case "zoom":
|
|
ctx.beginPath()
|
|
ctx.moveTo(1.4, 4)
|
|
ctx.lineTo(6.6, 4)
|
|
ctx.moveTo(4, 1.4)
|
|
ctx.lineTo(4, 6.6)
|
|
ctx.stroke()
|
|
break
|
|
case "restore":
|
|
ctx.beginPath()
|
|
ctx.rect(2.3, 0.7, 4.3, 4.3)
|
|
ctx.stroke()
|
|
ctx.beginPath()
|
|
ctx.rect(0.7, 2.3, 4.3, 4.3)
|
|
ctx.stroke()
|
|
break
|
|
default:
|
|
ctx.beginPath()
|
|
ctx.moveTo(1.6, 1.6)
|
|
ctx.lineTo(6.4, 6.4)
|
|
ctx.moveTo(6.4, 1.6)
|
|
ctx.lineTo(1.6, 6.4)
|
|
ctx.stroke()
|
|
break
|
|
}
|
|
}
|
|
|
|
Behavior on opacity {
|
|
NumberAnimation {
|
|
duration: Theme.animationFast
|
|
}
|
|
}
|
|
}
|
|
|
|
onGlyphChanged: glyph.requestPaint()
|
|
onShowGlyphChanged: if (showGlyph) glyph.requestPaint()
|
|
|
|
MouseArea {
|
|
id: hover
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: root.clicked()
|
|
}
|
|
|
|
NebulaToolTip {
|
|
text: root.label
|
|
active: hover.containsMouse && !hover.pressed && root.label.length > 0
|
|
}
|
|
}
|