aboutsummaryrefslogtreecommitdiff
path: root/quickshell/AppLauncher.qml
diff options
context:
space:
mode:
Diffstat (limited to 'quickshell/AppLauncher.qml')
-rw-r--r--quickshell/AppLauncher.qml402
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 + " &"])
+ })
+ }
}