Merge status bar and launcher into morphing top bar
This commit is contained in:
43
BarShape.qml
Normal file
43
BarShape.qml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Shapes
|
||||||
|
|
||||||
|
Shape {
|
||||||
|
id: background
|
||||||
|
preferredRendererType: Shape.CurveRenderer
|
||||||
|
required property var color
|
||||||
|
required property var radius
|
||||||
|
ShapePath {
|
||||||
|
strokeWidth: 0
|
||||||
|
fillColor: color
|
||||||
|
startX: 0
|
||||||
|
startY: 0
|
||||||
|
PathArc {
|
||||||
|
x: radius; y: Math.min(radius, background.height/2)
|
||||||
|
radiusX: radius; radiusY: y
|
||||||
|
direction: PathArc.Clockwise
|
||||||
|
}
|
||||||
|
PathLine { x: radius; y: background.height - Math.min(radius, background.height/2) }
|
||||||
|
PathArc {
|
||||||
|
x: radius * 2; y: background.height
|
||||||
|
radiusX: radius; radiusY: Math.min(radius, background.height/2)
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
PathLine { x: background.width - radius * 2; y: background.height }
|
||||||
|
PathArc {
|
||||||
|
x: background.width - radius; y: background.height - Math.min(radius, background.height/2)
|
||||||
|
radiusX: radius; radiusY: Math.min(radius, background.height/2)
|
||||||
|
direction: PathArc.Counterclockwise
|
||||||
|
}
|
||||||
|
PathLine { x: background.width - radius; y: Math.min(radius, background.height/2) }
|
||||||
|
PathArc {
|
||||||
|
x: background.width; y: 0
|
||||||
|
radiusX: radius; radiusY: Math.min(radius, background.height/2)
|
||||||
|
direction: PathArc.Clockwise
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: MultiEffect {
|
||||||
|
shadowEnabled: true
|
||||||
|
}
|
||||||
|
}
|
||||||
321
Launcher.qml
321
Launcher.qml
@@ -5,37 +5,10 @@ import QtQuick
|
|||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import "./emojis.mjs" as Emojis
|
import "./emojis.mjs" as Emojis
|
||||||
|
|
||||||
PanelWindow {
|
Item {
|
||||||
id: root
|
height: currentItems.length ? 180 : 60
|
||||||
anchors {
|
width: 700
|
||||||
top: true
|
property var show: input.text.length
|
||||||
}
|
|
||||||
visible: false
|
|
||||||
implicitHeight: 400
|
|
||||||
implicitWidth: 1000
|
|
||||||
exclusionMode: ExclusionMode.Ignore
|
|
||||||
color: "transparent"
|
|
||||||
WlrLayershell.layer: WlrLayershell.Overlay
|
|
||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
|
||||||
|
|
||||||
IpcHandler {
|
|
||||||
target: "launcher"
|
|
||||||
function open() {root.open()}
|
|
||||||
function clone() {root.close()}
|
|
||||||
function toggle() {root.visible ? root.close() : root.open()}
|
|
||||||
}
|
|
||||||
function open() {
|
|
||||||
input.text = ""
|
|
||||||
root.visible = true
|
|
||||||
exit.stop();
|
|
||||||
entry.start();
|
|
||||||
}
|
|
||||||
function close() {
|
|
||||||
input.text = ""
|
|
||||||
entry.stop();
|
|
||||||
exit.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
property var currentItems: {
|
property var currentItems: {
|
||||||
if (input.text.length === 0 || input.text === ":") {
|
if (input.text.length === 0 || input.text === ":") {
|
||||||
return []
|
return []
|
||||||
@@ -55,194 +28,142 @@ PanelWindow {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
anchors {
|
anchors {
|
||||||
top: parent.top
|
top: parent.top
|
||||||
horizontalCenter: parent.horizontalCenter
|
left: parent.left
|
||||||
topMargin: 100
|
right: parent.right
|
||||||
|
margins: 6
|
||||||
}
|
}
|
||||||
|
height: 48
|
||||||
color: "#181818"
|
color: "#181818"
|
||||||
height: currentItems.length ? 180 : 60
|
radius: 10
|
||||||
Behavior on height { NumberAnimation {
|
TextInput {
|
||||||
duration: 300
|
id: input
|
||||||
easing.type: Easing.OutQuint
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
x: parent.width/2 - this.width/2
|
||||||
|
Behavior on x {NumberAnimation {duration: 300; easing.type: Easing.OutQuint}}
|
||||||
|
focus: true
|
||||||
|
font.pixelSize: 20
|
||||||
|
color: "white"
|
||||||
|
cursorDelegate: Item {}
|
||||||
|
onCursorPositionChanged: cursorPosition = text.length
|
||||||
|
Keys.onPressed: (event) => { switch (event.key) {
|
||||||
|
case Qt.Key_Escape:
|
||||||
|
root.close();
|
||||||
|
break;
|
||||||
|
case Qt.Key_Return:
|
||||||
|
list.currentItem.execute();
|
||||||
|
root.close();
|
||||||
|
break;
|
||||||
|
case Qt.Key_Right:
|
||||||
|
list.incrementCurrentIndex();
|
||||||
|
break;
|
||||||
|
case Qt.Key_Left:
|
||||||
|
list.decrementCurrentIndex();
|
||||||
|
break;
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ListView {
|
||||||
|
id: list
|
||||||
|
anchors {
|
||||||
|
top: input.parent.bottom
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
margins: 6
|
||||||
|
}
|
||||||
|
height: 114
|
||||||
|
highlightFollowsCurrentItem: true
|
||||||
|
onCurrentIndexChanged: background.indexChanged()
|
||||||
|
orientation: ListView.Horizontal
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
add: Transition { NumberAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
duration: 150
|
||||||
}}
|
}}
|
||||||
width: 700
|
remove: Transition { NumberAnimation {
|
||||||
radius: 12
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
RectangularShadow {
|
to: 0
|
||||||
z: -1
|
duration: 150
|
||||||
anchors.fill: parent
|
}}
|
||||||
radius: 12
|
displaced: Transition {
|
||||||
blur: 10
|
NumberAnimation {
|
||||||
spread: 2
|
property: "x"
|
||||||
}
|
duration: 300
|
||||||
Rectangle {
|
easing.type: Easing.OutQuint
|
||||||
anchors {
|
onStarted: console.log("displaced")
|
||||||
top: parent.top
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
margins: 6
|
|
||||||
}
|
}
|
||||||
height: 48
|
NumberAnimation {
|
||||||
color: "#222222"
|
|
||||||
radius: 10
|
|
||||||
TextInput {
|
|
||||||
id: input
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
x: parent.width/2 - this.width/2
|
|
||||||
Behavior on x {NumberAnimation {duration: 300; easing.type: Easing.OutQuint}}
|
|
||||||
focus: true
|
|
||||||
font.pixelSize: 20
|
|
||||||
color: "white"
|
|
||||||
cursorDelegate: Item {}
|
|
||||||
onCursorPositionChanged: cursorPosition = text.length
|
|
||||||
Keys.onPressed: (event) => { switch (event.key) {
|
|
||||||
case Qt.Key_Escape:
|
|
||||||
root.close();
|
|
||||||
break;
|
|
||||||
case Qt.Key_Return:
|
|
||||||
list.currentItem.execute();
|
|
||||||
root.close();
|
|
||||||
break;
|
|
||||||
case Qt.Key_Right:
|
|
||||||
list.incrementCurrentIndex();
|
|
||||||
break;
|
|
||||||
case Qt.Key_Left:
|
|
||||||
list.decrementCurrentIndex();
|
|
||||||
break;
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ListView {
|
|
||||||
id: list
|
|
||||||
anchors {
|
|
||||||
top: input.parent.bottom
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
margins: 6
|
|
||||||
}
|
|
||||||
height: 114
|
|
||||||
highlightFollowsCurrentItem: true
|
|
||||||
orientation: ListView.Horizontal
|
|
||||||
spacing: 6
|
|
||||||
|
|
||||||
add: Transition { NumberAnimation {
|
|
||||||
property: "opacity"
|
property: "opacity"
|
||||||
from: 0
|
|
||||||
to: 1
|
to: 1
|
||||||
duration: 150
|
duration: 150
|
||||||
}}
|
|
||||||
remove: Transition { NumberAnimation {
|
|
||||||
property: "opacity"
|
|
||||||
from: 1
|
|
||||||
to: 0
|
|
||||||
duration: 150
|
|
||||||
}}
|
|
||||||
displaced: Transition {
|
|
||||||
NumberAnimation {
|
|
||||||
property: "x"
|
|
||||||
duration: 300
|
|
||||||
easing.type: Easing.OutQuint
|
|
||||||
onStarted: console.log("displaced")
|
|
||||||
}
|
|
||||||
NumberAnimation {
|
|
||||||
property: "opacity"
|
|
||||||
to: 1
|
|
||||||
duration: 150
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
model: ScriptModel {values: currentItems.slice(0, 5)}
|
model: ScriptModel {values: currentItems.slice(0, 5)}
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
id: item
|
id: item
|
||||||
|
anchors {
|
||||||
|
top: parent?.top
|
||||||
|
bottom: parent?.bottom
|
||||||
|
}
|
||||||
|
width: (700 - 6*6)/5
|
||||||
|
color: "#20181818"
|
||||||
|
ListView.onIsCurrentItemChanged: ListView.isCurrentItem ? selectAnim.start() : deselectAnim.start()
|
||||||
|
property var selectAnim: ColorAnimation {
|
||||||
|
target: item
|
||||||
|
property: "color"
|
||||||
|
to: "#10ffffff"
|
||||||
|
duration: 200
|
||||||
|
easing.type: Easing.OutQuint
|
||||||
|
}
|
||||||
|
property var deselectAnim: ColorAnimation {
|
||||||
|
target: item
|
||||||
|
onStarted: selectAnim.stop()
|
||||||
|
property: "color"
|
||||||
|
to: "#00181818"
|
||||||
|
duration: 200
|
||||||
|
easing.type: Easing.InQuint
|
||||||
|
}
|
||||||
|
radius: 10
|
||||||
|
function execute() {
|
||||||
|
modelData.emoji
|
||||||
|
? Quickshell.clipboardText = modelData.emoji
|
||||||
|
: modelData.execute()
|
||||||
|
}
|
||||||
|
Column {
|
||||||
anchors {
|
anchors {
|
||||||
top: parent?.top
|
left: parent.left
|
||||||
bottom: parent?.bottom
|
right: parent.right
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
width: (700 - 6*6)/5
|
Image {
|
||||||
color: "#20181818"
|
visible: !modelData.emoji
|
||||||
ListView.onIsCurrentItemChanged: ListView.isCurrentItem ? selectAnim.start() : deselectAnim.start()
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
property var selectAnim: ColorAnimation {
|
width: 64
|
||||||
target: item
|
height: width
|
||||||
property: "color"
|
source: Quickshell.iconPath(modelData.icon)
|
||||||
to: "#10ffffff"
|
|
||||||
duration: 200
|
|
||||||
easing.type: Easing.OutQuint
|
|
||||||
}
|
}
|
||||||
property var deselectAnim: ColorAnimation {
|
Text {
|
||||||
target: item
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
onStarted: selectAnim.stop()
|
font.pixelSize: 64
|
||||||
property: "color"
|
text: modelData.emoji ?? ""
|
||||||
to: "#00181818"
|
|
||||||
duration: 200
|
|
||||||
easing.type: Easing.InQuint
|
|
||||||
}
|
}
|
||||||
radius: 10
|
Text {
|
||||||
function execute() {
|
|
||||||
modelData.emoji
|
|
||||||
? Quickshell.clipboardText = modelData.emoji
|
|
||||||
: modelData.execute()
|
|
||||||
}
|
|
||||||
Column {
|
|
||||||
anchors {
|
anchors {
|
||||||
left: parent.left
|
left: parent.left
|
||||||
right: parent.right
|
right: parent.right
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
Image {
|
|
||||||
visible: !modelData.emoji
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
width: 64
|
|
||||||
height: width
|
|
||||||
source: Quickshell.iconPath(modelData.icon)
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
font.pixelSize: 64
|
|
||||||
text: modelData.emoji ?? ""
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
}
|
|
||||||
width: parent.width - 12
|
|
||||||
text: modelData.name
|
|
||||||
color: "white"
|
|
||||||
font.pixelSize: 16
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
}
|
||||||
|
width: parent.width - 12
|
||||||
|
text: modelData.name
|
||||||
|
color: "white"
|
||||||
|
font.pixelSize: 16
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transform: Translate {
|
|
||||||
y: -50
|
|
||||||
NumberAnimation on y {
|
|
||||||
id: entry
|
|
||||||
to: 0
|
|
||||||
duration: 300
|
|
||||||
easing.type: Easing.OutQuint
|
|
||||||
}
|
|
||||||
NumberAnimation on y {
|
|
||||||
id: exit
|
|
||||||
to: -50
|
|
||||||
duration: 300
|
|
||||||
easing.type: Easing.InQuint
|
|
||||||
onFinished: root.visible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opacity: 0
|
|
||||||
NumberAnimation on opacity {
|
|
||||||
running: entry.running
|
|
||||||
to: 1
|
|
||||||
duration: entry.duration/2
|
|
||||||
}
|
|
||||||
SequentialAnimation on opacity {
|
|
||||||
running: exit.running
|
|
||||||
PauseAnimation {duration: exit.duration/2}
|
|
||||||
NumberAnimation {
|
|
||||||
to: 0
|
|
||||||
duration: exit.duration/2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
63
Status.qml
Normal file
63
Status.qml
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import "./Widgets" as Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: 800
|
||||||
|
height: 36
|
||||||
|
Row {
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
width: height
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
margins: 4
|
||||||
|
}
|
||||||
|
radius: 12
|
||||||
|
color: parent.hover.hovered ? "#333333" : "#222222"
|
||||||
|
Image {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 20
|
||||||
|
height: width
|
||||||
|
source: Qt.resolvedUrl("./arch.svg")
|
||||||
|
sourceSize {width: width; height: height}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property var hover: HoverHandler {}
|
||||||
|
property var click: TapHandler {
|
||||||
|
onTapped: launcher.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Widgets.Workspaces {
|
||||||
|
height: parent.height
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
rightMargin: 12
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
property var clock: SystemClock {}
|
||||||
|
color: "white"
|
||||||
|
text: Qt.formatDateTime(clock.date, "ddd MMM dd · hh:mm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
139
StatusBar.qml
139
StatusBar.qml
@@ -1,139 +0,0 @@
|
|||||||
import Quickshell
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Effects
|
|
||||||
import QtQuick.Shapes
|
|
||||||
import "." as Shell
|
|
||||||
|
|
||||||
PanelWindow {
|
|
||||||
id: root
|
|
||||||
anchors {
|
|
||||||
top: true
|
|
||||||
}
|
|
||||||
implicitWidth: 1024
|
|
||||||
implicitHeight: 1
|
|
||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
|
||||||
exclusionMode: ExclusionMode.Ignore
|
|
||||||
property real radius: 16
|
|
||||||
property var bgColor: "#222222"
|
|
||||||
property int fullHeight: 48
|
|
||||||
color: "transparent"
|
|
||||||
Shape {
|
|
||||||
id: background
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
width: 1000
|
|
||||||
height: 0
|
|
||||||
property real radius: 12
|
|
||||||
property var color: "white"
|
|
||||||
preferredRendererType: Shape.CurveRenderer
|
|
||||||
NumberAnimation on height {
|
|
||||||
id: entry
|
|
||||||
running: false
|
|
||||||
to: fullHeight
|
|
||||||
duration: 300
|
|
||||||
easing.type: Easing.OutBack
|
|
||||||
easing.overshoot: 1.5
|
|
||||||
onStarted: root.implicitHeight = 60
|
|
||||||
}
|
|
||||||
NumberAnimation on height {
|
|
||||||
id: exit
|
|
||||||
running: false
|
|
||||||
to: 0
|
|
||||||
duration: 300
|
|
||||||
easing.type: Easing.InCubic
|
|
||||||
onFinished: root.implicitHeight = 1
|
|
||||||
}
|
|
||||||
ShapePath {
|
|
||||||
strokeWidth: 0
|
|
||||||
fillColor: root.bgColor
|
|
||||||
startX: 0
|
|
||||||
startY: 0
|
|
||||||
PathArc {
|
|
||||||
x: root.radius; y: Math.min(root.radius, background.height/2)
|
|
||||||
radiusX: root.radius; radiusY: y
|
|
||||||
direction: PathArc.Clockwise
|
|
||||||
}
|
|
||||||
PathLine { x: root.radius; y: background.height - Math.min(root.radius, background.height/2) }
|
|
||||||
PathArc {
|
|
||||||
x: root.radius * 2; y: background.height
|
|
||||||
radiusX: root.radius; radiusY: Math.min(root.radius, background.height/2)
|
|
||||||
direction: PathArc.Counterclockwise
|
|
||||||
}
|
|
||||||
PathLine { x: background.width - root.radius * 2; y: background.height }
|
|
||||||
PathArc {
|
|
||||||
x: background.width - root.radius; y: background.height - Math.min(root.radius, background.height/2)
|
|
||||||
radiusX: root.radius; radiusY: Math.min(root.radius, background.height/2)
|
|
||||||
direction: PathArc.Counterclockwise
|
|
||||||
}
|
|
||||||
PathLine { x: background.width - root.radius; y: Math.min(root.radius, background.height/2) }
|
|
||||||
PathArc {
|
|
||||||
x: background.width; y: 0
|
|
||||||
radiusX: root.radius; radiusY: Math.min(root.radius, background.height/2)
|
|
||||||
direction: PathArc.Clockwise
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layer.enabled: true
|
|
||||||
layer.effect: MultiEffect {
|
|
||||||
shadowEnabled: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Row {
|
|
||||||
anchors {
|
|
||||||
left: background.left
|
|
||||||
bottom: background.bottom
|
|
||||||
leftMargin: root.radius * 2
|
|
||||||
}
|
|
||||||
height: fullHeight
|
|
||||||
Button {
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
bottom: parent.bottom
|
|
||||||
}
|
|
||||||
width: 20
|
|
||||||
background: Image {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: 20
|
|
||||||
height: width
|
|
||||||
source: Qt.resolvedUrl("./arch.svg")
|
|
||||||
sourceSize {width: width; height: height}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Shell.Workspaces {
|
|
||||||
height: fullHeight
|
|
||||||
anchors {
|
|
||||||
horizontalCenter: background.horizontalCenter
|
|
||||||
bottom: background.bottom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Row {
|
|
||||||
anchors {
|
|
||||||
right: background.right
|
|
||||||
bottom: background.bottom
|
|
||||||
rightMargin: root.radius * 2
|
|
||||||
}
|
|
||||||
height: fullHeight
|
|
||||||
Text {
|
|
||||||
property var clock: SystemClock {}
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
color: "white"
|
|
||||||
text: Qt.formatDateTime(clock.date, "ddd MMM dd · hh:mm")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: background
|
|
||||||
hoverEnabled: true
|
|
||||||
onExited: {
|
|
||||||
entry.stop()
|
|
||||||
exit.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HoverHandler { onHoveredChanged: if (hovered) {
|
|
||||||
exit.stop()
|
|
||||||
entry.start()
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
172
TopBar.qml
Normal file
172
TopBar.qml
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import "." as Shell
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: root
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
}
|
||||||
|
implicitWidth: 1024
|
||||||
|
implicitHeight: 200
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
exclusionMode: ExclusionMode.Ignore
|
||||||
|
color: "transparent"
|
||||||
|
property bool up: false
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
target: "topbar"
|
||||||
|
function open() { root.open() }
|
||||||
|
function close() { root.close() }
|
||||||
|
function toggle() {
|
||||||
|
root.up ? close() : open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function open() {
|
||||||
|
background.index = 0
|
||||||
|
background.entry.start()
|
||||||
|
}
|
||||||
|
function close() {
|
||||||
|
background.exit.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
Shell.BarShape {
|
||||||
|
id: background
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
color: "#222222"
|
||||||
|
radius: 16
|
||||||
|
width: children[0].width + radius*2
|
||||||
|
height: children[0].height
|
||||||
|
component DefaultTransition: Behavior {
|
||||||
|
enabled: root.up
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 500
|
||||||
|
easing.type: Easing.OutQuint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefaultTransition on width { }
|
||||||
|
DefaultTransition on height { }
|
||||||
|
property int index: 0
|
||||||
|
HoverHandler { onHoveredChanged: if (!hovered) {
|
||||||
|
root.close()
|
||||||
|
}}
|
||||||
|
onIndexChanged: {
|
||||||
|
width = children[index].width + radius*2
|
||||||
|
height = children[index].height
|
||||||
|
for (const [i, child] of children.entries()) {
|
||||||
|
if (i === index) {
|
||||||
|
if (root.up) child.fadeIn.start()
|
||||||
|
else child.opacity = 1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (root.up) child.fadeOut.start()
|
||||||
|
else child.opacity = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component Display: Item {
|
||||||
|
id: display
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
width: children[0].width
|
||||||
|
height: children[0].height
|
||||||
|
opacity: 0
|
||||||
|
property var fadeIn: SequentialAnimation {
|
||||||
|
PauseAnimation {duration: 200}
|
||||||
|
NumberAnimation {
|
||||||
|
target: display
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
duration: 300
|
||||||
|
easing.type: Easing.OutQuint
|
||||||
|
}
|
||||||
|
onStarted: fadeOut.stop()
|
||||||
|
}
|
||||||
|
property var fadeOut: NumberAnimation {
|
||||||
|
target: display
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
duration: 300
|
||||||
|
onStarted: fadeIn.stop()
|
||||||
|
easing.type: Easing.OutQuint
|
||||||
|
}
|
||||||
|
property var entry: NumberAnimation {
|
||||||
|
target: display
|
||||||
|
property: "anchors.topMargin"
|
||||||
|
to: 0
|
||||||
|
duration: 300
|
||||||
|
easing.type: Easing.OutQuint
|
||||||
|
onStarted: exit.stop()
|
||||||
|
}
|
||||||
|
property var exit: NumberAnimation {
|
||||||
|
target: display
|
||||||
|
property: "anchors.topMargin"
|
||||||
|
to: -height
|
||||||
|
duration: 300
|
||||||
|
easing.type: Easing.InQuint
|
||||||
|
onStarted: entry.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Display { opacity: 1; Shell.Status {
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
Display { Shell.Launcher {
|
||||||
|
onShowChanged: if (show) background.index = 1; else background.index = 0
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
|
||||||
|
property var entry: NumberAnimation {
|
||||||
|
target: background
|
||||||
|
property: "height"
|
||||||
|
to: background.children[background.index].height
|
||||||
|
duration: 300
|
||||||
|
easing.type: Easing.OutQuint
|
||||||
|
onStarted: {
|
||||||
|
root.implicitHeight = 200
|
||||||
|
background.exit.stop()
|
||||||
|
root.up = true
|
||||||
|
for (const child of background.children) {
|
||||||
|
child.entry.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property var exit: NumberAnimation {
|
||||||
|
target: background
|
||||||
|
property: "height"
|
||||||
|
to: 0
|
||||||
|
duration: 300
|
||||||
|
easing.type: Easing.InQuint
|
||||||
|
onStarted: {
|
||||||
|
background.entry.stop()
|
||||||
|
for (const child of background.children) {
|
||||||
|
child.exit.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onFinished: {
|
||||||
|
root.implicitHeight = 1
|
||||||
|
root.up = false
|
||||||
|
background.index = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HoverHandler { onHoveredChanged: if (hovered) {
|
||||||
|
root.open()
|
||||||
|
}}
|
||||||
|
}
|
||||||
36
Widgets/Workspaces.qml
Normal file
36
Widgets/Workspaces.qml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
|
||||||
|
Row {
|
||||||
|
Repeater {
|
||||||
|
model: 9
|
||||||
|
delegate: Shape {
|
||||||
|
height: 14
|
||||||
|
width: 24
|
||||||
|
property var workspace: Hyprland.workspaces.values.find(ws => ws.id === modelData+1)
|
||||||
|
preferredRendererType: Shape.CurveRenderer
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
ShapePath {
|
||||||
|
strokeWidth: workspace ? 7 : 4
|
||||||
|
Behavior on strokeWidth {NumberAnimation {
|
||||||
|
duration: 150
|
||||||
|
}}
|
||||||
|
strokeColor: "white"
|
||||||
|
fillColor: "transparent"
|
||||||
|
PathAngleArc {
|
||||||
|
moveToStart: true
|
||||||
|
centerX: width/2
|
||||||
|
centerY: height/2
|
||||||
|
startAngle: 0
|
||||||
|
sweepAngle: 360
|
||||||
|
radiusX: workspace ? 3.5 : 5
|
||||||
|
Behavior on radiusX {NumberAnimation {
|
||||||
|
duration: 150
|
||||||
|
}}
|
||||||
|
radiusY: radiusX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user