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 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 } } }