import "nix" import Quickshell import Quickshell.Wayland import QtQuick import QtQuick.Controls import QtQuick.Layouts // You'll need to create or import a fuzzy matching utility // For desktop entries, you may need a custom C++ plugin or use // QProcess to query applications PanelWindow { id: win anchors { top: true bottom: true left: true right: true } exclusionMode: ExclusionMode.Ignore focusable: true color: "transparent" // Main content container Rectangle { id: contentBox anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 100 width: 700 height: contentCol.implicitHeight + contentCol.anchors.topMargin + contentCol.anchors.bottomMargin radius: 12 color: Theme.bg palette { text: Theme.fg placeholderText: Theme.shaded windowText: Theme.fg } // Close on escape and handle Alt+number shortcuts Keys.onPressed: event => { if (event.key === Qt.Key_Escape) { win.visible = false; event.accepted = true; return; } // Handle Alt+1 through Alt+9 if (event.modifiers & Qt.AltModifier) { var num = -1; if (event.key >= Qt.Key_1 && event.key <= Qt.Key_9) { num = event.key - Qt.Key_1; // 0-8 } else if (event.key === Qt.Key_0) { num = 9; // Alt+0 for 10th item if needed } if (num >= 0 && num < appList.count) { launch(appList.get(num)); event.accepted = true; } } } ColumnLayout { id: contentCol anchors.fill: parent anchors.margins: 15 Layout.preferredHeight: 20 spacing: 10 // Search entry row RowLayout { id: searchEntry Layout.fillWidth: true spacing: 10 Text { font.pixelSize: 32 text: "" color: Theme.accent } TextField { id: searchField Layout.fillWidth: true placeholderText: "Application" font.pixelSize: 24 background: Rectangle { color: "transparent" } onTextChanged: search(text) onAccepted: { if (appList.count > 0) { console.log("launching:", appList.get(0).name); launch(appList.get(0)); } } Component.onCompleted: forceActiveFocus() } } Rectangle { Layout.fillWidth: true Layout.preferredHeight: 3 color: Theme.divider visible: appList.count > 0 } // Application list ListView { id: listView visible: appList.count > 0 Layout.fillWidth: true Layout.preferredHeight: Math.min(appList.count * 50, 450) model: appList spacing: 0 clip: true delegate: Button { id: entryButton width: listView.width height: 50 background: Rectangle { color: entryButton.hovered ? Theme.accent : "transparent" radius: 14 } contentItem: RowLayout { anchors.fill: parent anchors.leftMargin: 12 anchors.rightMargin: 12 spacing: 10 Image { source: model.icon ? "image://icon/" + model.icon : "" Layout.preferredWidth: 32 Layout.preferredHeight: 32 } Label { text: model.name font.pixelSize: 24 Layout.fillWidth: true elide: Text.ElideRight maximumLineCount: 1 wrapMode: Text.Wrap } Label { text: "⌘" + (index + 1) Layout.alignment: Qt.AlignRight color: entryButton.hovered ? Theme.fg : Theme.accent font.pointSize: 12 } } onClicked: launch(model) } } } } // Close when clicking outside content MouseArea { anchors.fill: parent onPressed: mouse => { var pnt = mapToItem(contentBox, mouse.x, mouse.y); if (!contentBox.contains(Qt.point(pnt.x, pnt.y))) { win.visible = false; } } // Let clicks pass through to content propagateComposedEvents: true } // Data model for applications ListModel { id: appList } // Function to perform fuzzy search function search(text) { if (text === "") { appList.clear(); return; } // You'll need to implement fuzzy_query // This could be via a C++ plugin or calling an external process // For now, placeholder showing the pattern: var results = DesktopEntries.applications.values; appList.clear(); for (var i = 0; i < results.length; i++) { appList.append(results[i]); } } // Function to launch application function launch(app) { if (!app) return; win.visible = false; app.execute(); } // Handle visibility changes onVisibleChanged: { if (visible) { searchField.forceActiveFocus(); searchField.selectAll(); } else { searchField.text = ""; appList.clear(); } } }