Files
hyprlua/widgets/launcher/RadialLauncher.qml
T
2026-07-03 07:25:09 +02:00

159 lines
3.3 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Widgets
PanelWindow {
id: launcher
required property bool open
required property string repoRoot
required property string flavorName
signal closeRequested()
visible: open
focusable: true
aboveWindows: true
color: "transparent"
anchors {
top: true
right: true
bottom: true
left: true
}
FileView {
id: flavorFile
path: launcher.repoRoot + "/theme/flavors/" + launcher.flavorName + "/launcher.json"
blockLoading: true
watchChanges: true
onFileChanged: reload()
}
readonly property var flavor: JSON.parse(flavorFile.text())
Process {
id: appProcess
}
function fileUrl(path) {
if (!path || path.length === 0)
return ""
if (path.startsWith("/"))
return "file://" + path
return "file://" + launcher.repoRoot + "/" + path
}
function launchProgram(program) {
launcher.closeRequested()
appProcess.command = program.command
appProcess.startDetached()
}
Rectangle {
anchors.fill: parent
color: launcher.flavor.colors.overlay
MouseArea {
anchors.fill: parent
onClicked: launcher.closeRequested()
}
Item {
id: dial
property real r: launcher.flavor.radius
property real appR: launcher.flavor.appRadius
property real orbit: launcher.flavor.orbitMultiplier * r
width: orbit * 2 + appR * 2
height: orbit * 2 + appR * 2
anchors.centerIn: parent
Rectangle {
id: center
width: dial.r * 2
height: dial.r * 2
radius: dial.r
anchors.centerIn: parent
color: launcher.flavor.colors.centerBackground
border.color: launcher.flavor.colors.centerBorder
border.width: 2
clip: true
Image {
anchors.fill: parent
anchors.margins: 6
source: launcher.fileUrl(launcher.flavor.centerIcon)
fillMode: Image.PreserveAspectFit
smooth: true
}
}
Repeater {
model: launcher.flavor.programs
delegate: Item {
id: appButton
required property int index
required property var modelData
property real angle: (index * 45 - 90) * Math.PI / 180
width: dial.appR * 2
height: dial.appR * 2
x: dial.width / 2 + Math.cos(angle) * dial.orbit - width / 2
y: dial.height / 2 + Math.sin(angle) * dial.orbit - height / 2
Rectangle {
anchors.fill: parent
radius: width / 2
color: mouse.containsMouse
? launcher.flavor.colors.appHoverBackground
: launcher.flavor.colors.appBackground
border.color: launcher.flavor.colors.appBorder
border.width: 2
clip: true
Image {
anchors.fill: parent
anchors.margins: 7
source: launcher.fileUrl(appButton.modelData.icon)
fillMode: Image.PreserveAspectFit
smooth: true
}
MouseArea {
id: mouse
anchors.fill: parent
hoverEnabled: true
onClicked: launcher.launchProgram(appButton.modelData)
}
}
}
}
}
}
}