From 1f6bd402b5d2ffef845129a327cae95113b23e55 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sun, 18 Oct 2026 12:26:10 +0200 Subject: window-switcher: animate, respace and label the expose, add arrow keys Closing a window from the expose now glides the rest into their new rects instead of jumping. The Repeater's plain array model rebuilt every card on any change, leaving nothing to animate; ScriptModel diffs by identity, so only the closed card goes. The Behaviors stay off until the fade-in settles, or every card would fly in from the corner on open. The scatter keeps its centre weighting but spaces windows further apart (GAP 60 -> 200 real px) and may fill 95% of the screen rather than 92%. Measured with node at 7 windows: about 45px on screen between cards. The bottom 28px are reserved so the lowest card's name stays on screen. Each card shows the app's desktop-entry name below its preview, falling back to the app id, and the app icon moved to a larger overlay in the preview's bottom-left corner; the hover title starts right of it. Arrow keys select a card and Enter focuses it. The scatter has no grid, so Expose.step picks the nearest centre on the arrow's side with sideways drift counted double, and the first press picks the top-left card; test_expose.js covers it. The selection is held as the window, not an index, so a close that shifts the list does not move it, and hovering selects too, so pointer and keys never show two highlights. Co-Authored-By: Claude Opus 5.5 --- window-switcher/WindowCard.qml | 56 +++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 17 deletions(-) (limited to 'window-switcher/WindowCard.qml') diff --git a/window-switcher/WindowCard.qml b/window-switcher/WindowCard.qml index be97427..b7b69f1 100644 --- a/window-switcher/WindowCard.qml +++ b/window-switcher/WindowCard.qml @@ -15,12 +15,15 @@ import Quickshell.Widgets import QtQuick // One window in the expose: a live preview sized from outside to its rect in -// the scatter. App icon and workspace marker are always shown; title and -// close only on hover, so the scatter stays clean. +// the scatter. App icon, workspace marker and app name are always shown; +// title only on the selected card, close only on hover, so the scatter +// stays clean. Item { id: card required property var toplevel + property bool selected: false + readonly property bool hovered: cardHover.hovered signal activated() signal closeRequested() @@ -43,7 +46,7 @@ Item { Glow { anchors.fill: box radius: box.radius - on: cardHover.hovered + on: card.selected } Rectangle { @@ -51,7 +54,7 @@ Item { anchors.fill: parent radius: 10 color: Theme.surface - border.color: cardHover.hovered ? Theme.accent : Theme.surfaceAlt + border.color: card.selected ? Theme.accent : Theme.surfaceAlt border.width: 1 // The rect already has the window's shape, so the preview fills it. @@ -84,17 +87,6 @@ Item { anchors { left: parent.left; top: parent.top; margins: 8 } spacing: 6 - Rectangle { - width: 34; height: 34; radius: 8 - color: Qt.rgba(Theme.base.r, Theme.base.g, Theme.base.b, 0.75) - - IconImage { - anchors.centerIn: parent - width: 24; height: 24 - source: Quickshell.iconPath(card.wl ? card.wl.appId : "", true) - } - } - // The desktop marker, drawn with the workspace icon rather than // the number. A workspace with no icon keeps the name, so the // marker never goes blank. @@ -147,8 +139,21 @@ Item { } Rectangle { - visible: cardHover.hovered - anchors { left: parent.left; right: parent.right; bottom: parent.bottom; margins: 8 } + id: appIcon + anchors { left: parent.left; bottom: parent.bottom; margins: 8 } + width: 40; height: 40; radius: 10 + color: Qt.rgba(Theme.base.r, Theme.base.g, Theme.base.b, 0.75) + + IconImage { + anchors.centerIn: parent + width: 30; height: 30 + source: Quickshell.iconPath(card.wl ? card.wl.appId : "", true) + } + } + + Rectangle { + visible: card.selected + anchors { left: appIcon.right; right: parent.right; bottom: parent.bottom; margins: 8 } height: 30; radius: 8 color: Qt.rgba(Theme.base.r, Theme.base.g, Theme.base.b, 0.75) @@ -163,4 +168,21 @@ Item { } } } + + // The app's name hangs below the preview, outside the card's rect: the + // scatter's gap leaves room for it. The desktop entry's name reads + // better than an app id, which is the fallback. + Text { + anchors { top: box.bottom; topMargin: 6; horizontalCenter: box.horizontalCenter } + width: Math.min(implicitWidth, box.width) + elide: Text.ElideRight + text: { + const id = card.wl ? card.wl.appId : ""; + const e = id ? DesktopEntries.heuristicLookup(id) : null; + return e ? e.name : id; + } + color: card.selected ? Theme.text : Theme.subtext + font.family: Theme.fontFamily + font.pixelSize: 14 + } } -- cgit v1.2.3