Create Alt+tab window, refactor sortedDesktopApplications so they are inside a ListModel instead of a Map()

This commit is contained in:
2025-10-13 16:51:26 -03:00
parent f80abc48ae
commit 22c6bbf8ba
5 changed files with 189 additions and 25 deletions

5
Common/Shortcuts.qml Normal file
View File

@@ -0,0 +1,5 @@
import Quickshell.Hyprland
GlobalShortcut {
appid: "quickbar"
}

View File

@@ -1,5 +1,6 @@
pragma Singleton pragma Singleton
import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import Quickshell.Wayland import Quickshell.Wayland
@@ -70,6 +71,34 @@ Singleton {
return sortedTopLevels.map(topLevel => topLevel.workspace); return sortedTopLevels.map(topLevel => topLevel.workspace);
} }
property ListModel sortedDesktopApplicationsModel: ListModel {}
onSortedTopLevelsChanged: updateSortedDesktopApplications()
function updateSortedDesktopApplications() {
sortedDesktopApplicationsModel.clear();
for (const topLevel of sortedTopLevels) {
const entry = DesktopEntries.heuristicLookup(topLevel.wayland.appId);
sortedDesktopApplicationsModel.append({
topLevel: topLevel,
desktopEntry: entry
});
}
}
function workspaceApps(workspaceIndexAlign) {
const list = []
const model = sortedDesktopApplicationsModel
for (let i = 0; i < model.count; i++) {
const item = model.get(i)
if (item.topLevel.workspace.id === workspaceIndexAlign)
list.push(item.desktopEntry)
}
return list
}
property var sortedDesktopApplications: { property var sortedDesktopApplications: {
const sortedWayland = sortedTopLevels.map(topLevel => topLevel.wayland).filter(wayland => wayland !== null); const sortedWayland = sortedTopLevels.map(topLevel => topLevel.wayland).filter(wayland => wayland !== null);

View File

@@ -62,13 +62,13 @@ Singleton {
StyledText { StyledText {
text: { text: {
if (!HoverMediator.component?.model) if (!HoverMediator.component?.model)
return ""; return "";
if (HoverMediator.component.model.tooltipTitle) if (HoverMediator.component.model.tooltipTitle)
return HoverMediator.component.model.tooltipTitle; return HoverMediator.component.model.tooltipTitle;
if (HoverMediator.component.model.title) if (HoverMediator.component.model.title)
return HoverMediator.component.model.title; return HoverMediator.component.model.title;
else else
return ""; return "";
} }
} }
} }
@@ -76,7 +76,7 @@ Singleton {
Component { Component {
id: time id: time
RowLayout{ RowLayout {
id: rowlayoutCalendar id: rowlayoutCalendar
readonly property date now: new Date() readonly property date now: new Date()
@@ -132,9 +132,7 @@ Singleton {
Repeater { Repeater {
property var modelo: HyprlandService.sortedDesktopApplications.get(parent.workspaceIndexAlign) model: HyprlandService.workspaceApps(parent.workspaceIndexAlign)
model: modelo
delegate: IconImage { delegate: IconImage {
required property var modelData required property var modelData
@@ -172,15 +170,15 @@ Singleton {
id: hoverLoader id: hoverLoader
sourceComponent: { sourceComponent: {
if (!HoverMediator.type) if (!HoverMediator.type)
return stub; return stub;
if (HoverMediator.type === "workspace") if (HoverMediator.type === "workspace")
return workspaceComponent; return workspaceComponent;
if (HoverMediator.type === "audio") if (HoverMediator.type === "audio")
return audio; return audio;
if (HoverMediator.type === "time") if (HoverMediator.type === "time")
return time; return time;
if (HoverMediator.type === "systray") if (HoverMediator.type === "systray")
return systray; return systray;
} }
} }
} }

122
Widgets/WindowSwitcher.qml Normal file
View File

@@ -0,0 +1,122 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import qs.Services
import qs.Common.Styled
import qs.Common
import Quickshell.Wayland
PanelWindow {
id: root
anchors {
left: true
bottom: true
right: true
top: true
}
implicitWidth: screen.width
// implicitWidth: 400
implicitHeight: screen.height
color: "transparent"
visible: true
signal clear
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
MouseArea {
anchors.fill: parent
onClicked: root.clear()
}
Rectangle {
id: notifWindow
anchors.centerIn:parent
implicitHeight: 300
implicitWidth: listview.contentWidth
color: "transparent"
ListView {
id: listview
anchors.fill: parent
clip: true
spacing: 5
orientation: ListView.Horizontal
focus:true
highlight: Rectangle { color: "black"; radius: 5 }
highlightFollowsCurrentItem: true
keyNavigationEnabled: false
Keys.onPressed: (event) => {
switch (event.key) {
case Qt.Key_L: // move down
case Qt.Key_D:
if (currentIndex < count - 1)
currentIndex++
event.accepted = true
break
case Qt.Key_H: // move up
case Qt.Key_A:
if (currentIndex > 0)
currentIndex--
event.accepted = true
break
case Qt.Key_Return:
currentItem.activate()
event.accepted = true
break
case Qt.Key_Escape:
root.clear()
break
}
}
model: HyprlandService.sortedDesktopApplicationsModel
delegate: Rectangle {
required property var modelData
implicitHeight: 300
implicitWidth: 300
color: "transparent"
function activate() {
modelData.topLevel.wayland.activate()
root.clear()
}
MouseArea {
anchors.fill: parent
onClicked: activate()
}
ScreencopyView {
anchors.fill: parent
live: true
captureSource: modelData.topLevel.wayland
}
IconImage {
anchors.bottom: parent.bottom
property int workspaceId: modelData.topLevel.workspace.id
property var desktopEntry: modelData.desktopEntry
width: 30
height: 30
source: (modelData && desktopEntry.icon) ? Quickshell.iconPath(desktopEntry.icon, 1) : "aaa"
}
}
}
}
}

View File

@@ -1,20 +1,13 @@
//@ pragma UseQApplication //@ pragma UseQApplication
import Quickshell import Quickshell
import qs.Widgets
import qs.Common
import qs.Services
ShellRoot { ShellRoot {
// Bar { id: root
// modelData: Quickshell.screens.values[0]
// barComponentsLeft: ["NotificationsWidget.qml"]
// barComponentsCenter: ["Workspaces.qml"]
// barComponentsRight: ["AudioWidget.qml", "SysTrayWidget.qml", "ClockWidget.qml"]
// }
// Bar { property bool createWindow: false
// panelMonitor: "DP-2"
// barComponentsLeft: []
// barComponentsCenter: ["Workspaces.qml"]
// barComponentsRight: ["AudioWidget.qml", "ClockWidget.qml"]
// }
Variants { Variants {
model: Quickshell.screens model: Quickshell.screens
@@ -25,4 +18,21 @@ ShellRoot {
barComponentsRight: ["AudioWidget.qml", "SysTrayWidget.qml", "ClockWidget.qml"] barComponentsRight: ["AudioWidget.qml", "SysTrayWidget.qml", "ClockWidget.qml"]
} }
} }
Shortcuts {
name: "showAltTab"
onPressed: {
root.createWindow = !root.createWindow;
}
}
LazyLoader {
id: windowLoader
active: root.createWindow
component: WindowSwitcher {
onClear: root.createWindow = false
}
}
} }