dots/quickshell/shell/Modules/Launcher.qml
2026-02-14 17:22:42 +00:00

182 lines
6.1 KiB
QML

import Quickshell
import Quickshell.Wayland
import Quickshell.Io
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import "../Config"
PanelWindow {
id: launcher
anchors.top: true
property var open: false
property int selectedIndex: 0
readonly property list<DesktopEntry> visibleEntries: Array.from(DesktopEntries.applications.values).sort((d1, d2) => d1.name.localeCompare(d2.name)).filter(application => application.name.toLowerCase().includes(search.text.toLowerCase()))
function genHeight() {
if (launcher.visibleEntries.length > Config.launcherVisibleEntries) {
return ((search.height * (Config.launcherVisibleEntries + 1) + Config.launcherOuterPadding))
}
else {
return (search.height * (launcher.visibleEntries.length + 1) + Config.launcherOuterPadding)
}
}
implicitHeight: open ? genHeight() : 0
implicitWidth: HostSpecific.menuWidth
color: "transparent"
visible: open ? true : false
Behavior on implicitHeight {
NumberAnimation {
duration: 80
easing.type: Easing.InOutQuad
easing.overshoot: 2
}
}
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
exclusionMode: ExclusionMode.Ignore
Rectangle {
id: rect
anchors.fill: parent
color: Colours.background
opacity: 0.9
bottomLeftRadius: 20
bottomRightRadius: 20
ColumnLayout {
id: content
anchors.fill: parent
Row{
Rectangle {
color: "transparent"
width: Config.launcherOuterPadding
height: search.height
}
Rectangle {
height: search.height
width: search.height
color: "transparent"
IconImage {
anchors.centerIn: parent
source: Quickshell.iconPath("search-icon")
height: search.height
width: search.height
}
}
Rectangle {
color: "transparent"
width: launcher.width - search.height - (2 * Config.launcherOuterPadding)
height: search.height
TextField {
id: search
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
focus: true
placeholderText: "Search..."
background: null
color: Colours.foreground
placeholderTextColor: Colours.colour0
font.pixelSize: HostSpecific.menuFontSize
font.family: "Departure Mono"
Keys.onPressed: event => {
if (event.key == Qt.Key_Return) {
launcher.open = false;
launcher.visibleEntries[launcher.selectedIndex].execute();
}
if (event.key == Qt.Key_Down) {
if (list.currentIndex < (launcher.visibleEntries.length-1)) {
list.currentIndex++;
}
event.accepted = true;
}
if (event.key == Qt.Key_Up) {
if (list.currentIndex > 0) {
list.currentIndex--;
}
event.accepted = true;
}
if (event.key == Qt.Key_Escape) {
launcher.open = false;
event.accepted = true;
}
}
}
}
Rectangle {
color: "transparent"
width: Config.launcherOuterPadding
height: search.height
}
}
ListView {
id: list
model: launcher.visibleEntries
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
preferredHighlightBegin: 0
highlight: Rectangle { color: Colours.colour1; radius:20 }
currentIndex: 0
delegate: Row {
Rectangle {
color: "transparent"
width: Config.launcherOuterPadding
height: search.height
}
Rectangle {
color: "transparent"
height: search.height
width: search.height
IconImage {
source: Quickshell.iconPath(modelData.icon, true)
height:search.height
width: search.height
}
}
Rectangle {
color: "transparent"
height: search.height
width: launcher.width - search.height - Config.launcherOuterPadding
Text{
color: Colours.foreground
text: modelData.name
font.pixelSize: HostSpecific.menuFontSize
font.family: "Departure Mono"
anchors.verticalCenter: parent.verticalCenter
}
}
}
}
}
}
IpcHandler {
target: "launcher"
function toggle() {
search.text = ""
launcher.open = !launcher.open
}
}
}