diff options
Diffstat (limited to 'quickshell/AppLauncher.qml')
| -rw-r--r-- | quickshell/AppLauncher.qml | 402 |
1 files changed, 182 insertions, 220 deletions
diff --git a/quickshell/AppLauncher.qml b/quickshell/AppLauncher.qml index a1b5ab2..91deb1e 100644 --- a/quickshell/AppLauncher.qml +++ b/quickshell/AppLauncher.qml @@ -4,245 +4,207 @@ import Quickshell import Quickshell.Io Rectangle { - id: appLauncher - - width: 400 - height: 600 - color: shellRoot.black - radius: 16 - border.width: 3 - border.color: shellRoot.blue - antialiasing: true - - property bool isVisible: false - property int selectedIndex: -1 - property int hoverIndex: -1 - - signal requestClose() - - focus: true - - Keys.onEscapePressed: requestClose() - - Keys.onUpPressed: { - hoverIndex = -1 - if (selectedIndex === -1) { - selectedIndex = appListModel.count - 1 - } else if (selectedIndex > 0) { - selectedIndex-- - } - listView.positionViewAtIndex(selectedIndex, ListView.Contain) + id: appLauncher + + width: 400 + height: 600 + color: shellRoot.black + antialiasing: true + + property bool isVisible: false + property int hoverIndex: 0 + property bool cleared: true + + signal requestClose() + + focus: true + + Keys.onEscapePressed: requestClose() + + Keys.onUpPressed: { + hoverIndex-- + if (hoverIndex < 0) hoverIndex += appListModel.count + listView.positionViewAtIndex(hoverIndex, ListView.Contain) + } + + Keys.onDownPressed: { + hoverIndex = (hoverIndex + 1) % appListModel.count + listView.positionViewAtIndex(hoverIndex, ListView.Contain) + } + + Keys.onReturnPressed: { + if (hoverIndex >= 0 && hoverIndex < appListModel.count) { + launchApp(appListModel.get(hoverIndex).appCommand) } - - Keys.onDownPressed: { - hoverIndex = -1 - if (selectedIndex === -1) { - selectedIndex = 0 - } else if (selectedIndex < appListModel.count - 1) { - selectedIndex++ - } - listView.positionViewAtIndex(selectedIndex, ListView.Contain) + } + + Keys.onEnterPressed: { + if (hoverIndex >= 0 && hoverIndex < appListModel.count) { + launchApp(appListModel.get(hoverIndex).appCommand) } + } + + onIsVisibleChanged: { + if (!isVisible) return; + hoverIndex = -1 + appLauncher.forceActiveFocus() + loadApps() + } + + Process { + id: appLoader + running: false + command: ["sh", "-c", "~/.config/quickshell/scripts/list-apps.sh"] - Keys.onReturnPressed: { - if (selectedIndex >= 0 && selectedIndex < appListModel.count) { - launchApp(appListModel.get(selectedIndex).appCommand) + stdout: SplitParser { + onRead: data => { + if (!cleared) { + appListModel.clear() + cleared = true; } - } - - Keys.onEnterPressed: { - if (selectedIndex >= 0 && selectedIndex < appListModel.count) { - launchApp(appListModel.get(selectedIndex).appCommand) + + const lines = data.split('\n') + for (const line of lines) { + if (line.trim().length === 0) continue + + const parts = line.split('|') + if (parts.length < 4) continue; + appListModel.append({ + appName: parts[0], + appDescription: parts[1], + appIcon: parts[2], + appCommand: parts[3] + }) } + } } - // Reset selection when widget becomes visible - onIsVisibleChanged: { - if (isVisible) { - selectedIndex = -1 // Start with nothing selected - hoverIndex = -1 // Reset hover on open - appLauncher.forceActiveFocus() - // Reload apps every time the launcher opens - loadApps() - } + onRunningChanged: { + if (running) return; + appLoader.running = false } + } + + function loadApps() { + cleared = false; + appLoader.running = true + } + + Component.onCompleted: { + loadApps() + } + + Column { + anchors.fill: parent + anchors.margins: 12 + spacing: 8 - // Process to load apps - Process { - id: appLoader - running: false // Don't auto-start, we'll trigger it manually - command: ["sh", "-c", "~/.config/quickshell/scripts/list-apps.sh"] + Rectangle { + width: parent.width + height: 36 + color: "transparent" + + Text { + anchors.centerIn: parent + text: "Applications" + font.family: shellRoot.fontFamily + font.pixelSize: 20 + font.weight: Font.Medium + color: shellRoot.white + } + + Rectangle { + width: 28 + height: 28 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + radius: 6 + color: closeMouseArea.containsMouse ? shellRoot.red : "transparent" - stdout: SplitParser { - onRead: data => { - const lines = data.split('\n') - for (const line of lines) { - if (line.trim().length === 0) continue - - const parts = line.split('|') - if (parts.length >= 4) { - appListModel.append({ - appName: parts[0], - appDescription: parts[1], - appIcon: parts[2], - appCommand: parts[3] - }) - } - } - console.log("Loaded", appListModel.count, "applications") - } + Text { + anchors.centerIn: parent + text: "✕" + font.family: shellRoot.fontFamily + font.pixelSize: 16 + font.weight: Font.Bold + color: closeMouseArea.containsMouse ? shellRoot.white : shellRoot.red } - onRunningChanged: { - // When process finishes, reset it for next run - if (!running) { - appLoader.running = false - } + MouseArea { + id: closeMouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: appLauncher.requestClose() } + } } - // Function to load/reload applications - function loadApps() { - // Clear existing apps - appListModel.clear() - // Start the process to reload - appLoader.running = true - } - - // Load apps initially when component is created - Component.onCompleted: { - loadApps() - } - - Column { - anchors.fill: parent - anchors.margins: 12 - spacing: 8 - - // Header - Rectangle { - width: parent.width - height: 36 - color: "transparent" - - Text { - anchors.centerIn: parent - text: "Applications" - font.family: shellRoot.fontFamily - font.pixelSize: 14 - font.weight: Font.Medium - color: shellRoot.white - } - - // Close button - Rectangle { - width: 28 - height: 28 - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - radius: 6 - color: closeMouseArea.containsMouse ? shellRoot.red : "transparent" - - Text { - anchors.centerIn: parent - text: "✕" - font.family: shellRoot.fontFamily - font.pixelSize: 16 - font.weight: Font.Bold - color: closeMouseArea.containsMouse ? shellRoot.red : shellRoot.orange - } - - MouseArea { - id: closeMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: appLauncher.requestClose() - } - } + ListView { + id: listView + width: parent.width + height: parent.height - 44 + spacing: 8 + clip: true + + model: ListModel { + id: appListModel + } + + delegate: Rectangle { + width: listView.width + height: 30 + color: { + if (appLauncher.hoverIndex === index) return shellRoot.lightgray + return shellRoot.gray } - // Apps list - ListView { - id: listView - width: parent.width - height: parent.height - 44 - spacing: 8 - clip: true - - model: ListModel { - id: appListModel - // Apps will be loaded dynamically from the script - } - - delegate: Rectangle { - width: listView.width - height: 30 - color: { - if (appLauncher.hoverIndex === index) return shellRoot.lightgray - if (appLauncher.hoverIndex === -1 && index === shellRoot.selectedIndex) return shellRoot.lightgray - return shellRoot.gray - } - radius: 12 - border.width: 2 - border.color: { - if (appLauncher.hoverIndex === index || (shellRoot.hoverIndex === -1 && index === shellRoot.selectedIndex)) return shellRoot.blue - return "transparent" - } - - Row { - anchors.fill: parent - anchors.leftMargin: 12 - anchors.rightMargin: 12 - anchors.topMargin: 8 - anchors.bottomMargin: 8 - spacing: 12 - - Text { - width: parent.width - 62 - anchors.centerIn: parent - text: model.appName - font.family: shellRoot.fontFamily - font.pixelSize: 14 - font.weight: Font.Medium - color: { - if (appLauncher.hoverIndex === index) return shellRoot.blue - if (appLauncher.hoverIndex === -1 && index === shellRoot.selectedIndex) return shellRoot.blue - return shellRoot.purple - } - elide: Text.ElideRight - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - - onEntered: { - appLauncher.hoverIndex = index - } - onExited: { - appLauncher.hoverIndex = -1 - } - - onClicked: { - launchApp(model.appCommand) - } - } + Row { + anchors.fill: parent + anchors.leftMargin: 12 + anchors.rightMargin: 12 + anchors.topMargin: 8 + anchors.bottomMargin: 8 + spacing: 12 + + Text { + width: parent.width - 62 + anchors.centerIn: parent + text: model.appName + font.family: shellRoot.fontFamily + font.pixelSize: 14 + font.weight: Font.Medium + color: { + return shellRoot.white; } + elide: Text.ElideRight + } } - } - - function launchApp(command) { - console.log("Launching app:", command) - // Close the launcher first - appLauncher.requestClose() - // Use a small delay before launching to ensure the window closes properly - Qt.callLater(() => { - Quickshell.execDetached(["sh", "-c", command + " &"]) - }) + MouseArea { + id:ouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + + onEntered: { + appLauncher.hoverIndex = index + } + + onClicked: { + launchApp(model.appCommand) + } + } + } } + } + + function launchApp(command) { + appLauncher.requestClose() + + // Use a small delay before launching to ensure the window closes properly + Qt.callLater(() => { + Quickshell.execDetached(["sh", "-c", command + " &"]) + }) + } } |
