feat(quickshell): add dense telemetry bar #4
@@ -27,7 +27,7 @@ Quickshell hot-reloads QML on file save when already running, so for most edits
|
|||||||
**Directory layout**:
|
**Directory layout**:
|
||||||
- `widgets/bar/` — `Bar.qml` is the main sidebar (right-anchored, full height) hosting the module stack (date, clock, tray, decorative dividers); `BarTop.qml`/`BarBottom.qml` are thin accent-colored strips anchored to the top/bottom edges.
|
- `widgets/bar/` — `Bar.qml` is the main sidebar (right-anchored, full height) hosting the module stack (date, clock, tray, decorative dividers); `BarTop.qml`/`BarBottom.qml` are thin accent-colored strips anchored to the top/bottom edges.
|
||||||
- `widgets/bar/modules/` — individual bar widgets (`Clock`, `Date`, `Tray`/`TrayItem`, `Volume`) built on the shared `BarWidget` base component.
|
- `widgets/bar/modules/` — individual bar widgets (`Clock`, `Date`, `Tray`/`TrayItem`, `Volume`) built on the shared `BarWidget` base component.
|
||||||
- `widgets/launcher/` — app launcher panel (`Launcher` → `LauncherPanel` → `SearchBar`/`TextField`), currently a WIP skeleton (search box has no backing logic yet, `Launcher.qml` is instantiated with `visible: false`).
|
- `widgets/launcher/` — shared `AppModel` search/execution plus eight launcher variants. `ApplicationLauncher` (variant 8 and the primary `SUPER` launcher) keeps its visual core in the headlessly renderable `ApplicationLauncherContent`; variants 1–7 remain available on `SUPER CTRL 1–7` for comparison.
|
||||||
- `widgets/decoration/` — reusable QtQuick `Shape`-based visual accents (angled panel edges, slashes) used to give bar panels their non-rectangular look. `Dummy.qml` is a placeholder/test rectangle.
|
- `widgets/decoration/` — reusable QtQuick `Shape`-based visual accents (angled panel edges, slashes) used to give bar panels their non-rectangular look. `Dummy.qml` is a placeholder/test rectangle.
|
||||||
- `widgets/input/` — thin wrappers around `QtQuick.Controls` inputs (currently just `TextField`).
|
- `widgets/input/` — thin wrappers around `QtQuick.Controls` inputs (currently just `TextField`).
|
||||||
- `widgets/layout/` — `HorizontalStack`/`VerticalStack`: `RowLayout`/`ColumnLayout` wrappers that expose `default property alias content` for terser call sites, with a trailing filler `Item` that soaks up remaining space.
|
- `widgets/layout/` — `HorizontalStack`/`VerticalStack`: `RowLayout`/`ColumnLayout` wrappers that expose `default property alias content` for terser call sites, with a trailing filler `Item` that soaks up remaining space.
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
hyprctl dispatch 'hl.dsp.global ("quickshell:launcher7")'
|
hyprctl dispatch 'hl.dsp.global ("quickshell:launcher8")'
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ Scope {
|
|||||||
SideBar {}
|
SideBar {}
|
||||||
BarBottom {}
|
BarBottom {}
|
||||||
|
|
||||||
// App launcher variants — toggled via Hyprland global shortcuts
|
// App launcher variants — SUPER CTRL 1–8; variant 8 is the primary HUD.
|
||||||
// (SUPER CTRL 1/2/3). Try each and keep the one you like.
|
|
||||||
LauncherStack {} // 1 — left vertical list
|
LauncherStack {} // 1 — left vertical list
|
||||||
LauncherGrid {} // 2 — centered icon grid
|
LauncherGrid {} // 2 — centered icon grid
|
||||||
LauncherSpotlight {} // 3 — top-center command bar
|
LauncherSpotlight {} // 3 — top-center command bar
|
||||||
@@ -26,6 +25,7 @@ Scope {
|
|||||||
LauncherDock {} // 5 — deck rising from the bottom bar
|
LauncherDock {} // 5 — deck rising from the bottom bar
|
||||||
LauncherSlant {} // 6 — angular / sheared panel
|
LauncherSlant {} // 6 — angular / sheared panel
|
||||||
LauncherCorner {} // 7 — Slant (V6) copy + floating power panel (shutdown/reboot)
|
LauncherCorner {} // 7 — Slant (V6) copy + floating power panel (shutdown/reboot)
|
||||||
|
ApplicationLauncher {} // 8 — dense HUD command index (primary)
|
||||||
|
|
||||||
Notifications {}
|
Notifications {}
|
||||||
VolumeOsd {}
|
VolumeOsd {}
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.widgets.launcher
|
||||||
|
|
||||||
|
ApplicationLauncherContent {
|
||||||
|
width: 1080
|
||||||
|
height: 620
|
||||||
|
|
||||||
|
query: "term"
|
||||||
|
selectedIndex: 1
|
||||||
|
showIcons: false
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: "Alacritty",
|
||||||
|
genericName: "Terminal Emulator",
|
||||||
|
comment: "GPU accelerated command interface",
|
||||||
|
icon: "utilities-terminal",
|
||||||
|
categories: ["System", "TerminalEmulator"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Ghostty",
|
||||||
|
genericName: "Terminal",
|
||||||
|
comment: "Fast native terminal for local operations",
|
||||||
|
icon: "com.mitchellh.ghostty",
|
||||||
|
categories: ["System", "TerminalEmulator"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Kitty",
|
||||||
|
genericName: "Terminal Emulator",
|
||||||
|
comment: "GPU based terminal with multiplexing",
|
||||||
|
icon: "kitty",
|
||||||
|
categories: ["System", "TerminalEmulator"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Vivaldi",
|
||||||
|
genericName: "Web Browser",
|
||||||
|
comment: "Access network and web applications",
|
||||||
|
icon: "vivaldi",
|
||||||
|
categories: ["Network", "WebBrowser"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Cosmic Files",
|
||||||
|
genericName: "File Manager",
|
||||||
|
comment: "Browse and manage local storage",
|
||||||
|
icon: "com.system76.CosmicFiles",
|
||||||
|
categories: ["System", "FileManager"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Obsidian",
|
||||||
|
genericName: "Knowledge Base",
|
||||||
|
comment: "Local-first markdown workspace",
|
||||||
|
icon: "obsidian",
|
||||||
|
categories: ["Office"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Steam",
|
||||||
|
genericName: "Game Platform",
|
||||||
|
comment: "Launch and manage games",
|
||||||
|
icon: "steam",
|
||||||
|
categories: ["Game"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import QtQuick
|
||||||
|
import qs.widgets.theme
|
||||||
|
|
||||||
|
// Primary application launcher (variant 8). The full-screen layer-shell adapter
|
||||||
|
// owns focus, DesktopEntries and execution; ApplicationLauncherContent remains
|
||||||
|
// an Item so the complete visual state can be rendered headlessly.
|
||||||
|
Scope {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool active: false
|
||||||
|
|
||||||
|
function toggle() { root.active = !root.active; }
|
||||||
|
|
||||||
|
GlobalShortcut {
|
||||||
|
name: "launcher8"
|
||||||
|
description: "Toggle dense application command index"
|
||||||
|
onPressed: root.toggle()
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: win
|
||||||
|
|
||||||
|
visible: root.active
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||||
|
exclusionMode: ExclusionMode.Ignore
|
||||||
|
color: Theme.textAlpha(0)
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
left: true
|
||||||
|
right: true
|
||||||
|
bottom: true
|
||||||
|
}
|
||||||
|
|
||||||
|
property int selectedIndex: 0
|
||||||
|
|
||||||
|
function clampSelection(index) {
|
||||||
|
if (model.apps.length === 0)
|
||||||
|
return 0;
|
||||||
|
return Math.max(0, Math.min(model.apps.length - 1, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
function move(delta) {
|
||||||
|
const count = model.apps.length;
|
||||||
|
if (count === 0)
|
||||||
|
return;
|
||||||
|
selectedIndex = ((selectedIndex + delta) % count + count) % count;
|
||||||
|
}
|
||||||
|
|
||||||
|
function launch(index) {
|
||||||
|
if (model.launch(index))
|
||||||
|
root.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onVisibleChanged: {
|
||||||
|
if (visible) {
|
||||||
|
content.clearSearch();
|
||||||
|
selectedIndex = 0;
|
||||||
|
content.focusSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AppModel {
|
||||||
|
id: model
|
||||||
|
search: content.query
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Theme.surface
|
||||||
|
opacity: 0.72
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: root.active = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationLauncherContent {
|
||||||
|
id: content
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 1080
|
||||||
|
height: 620
|
||||||
|
scale: Math.min(1, (parent.width - 64) / width, (parent.height - 64) / height)
|
||||||
|
transformOrigin: Item.Center
|
||||||
|
apps: model.apps
|
||||||
|
selectedIndex: win.selectedIndex
|
||||||
|
|
||||||
|
onSelectionRequested: index => win.selectedIndex = win.clampSelection(index)
|
||||||
|
onMoveRequested: delta => win.move(delta)
|
||||||
|
onLaunchRequested: index => win.launch(index)
|
||||||
|
onDismissRequested: root.active = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,602 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import qs.widgets.bar
|
||||||
|
import qs.widgets.theme
|
||||||
|
|
||||||
|
// Headlessly renderable visual core for the primary application launcher.
|
||||||
|
// Runtime concerns (DesktopEntries, layer shell, launching) stay in
|
||||||
|
// ApplicationLauncher.qml; this component only renders state and emits intent.
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var apps: []
|
||||||
|
property int selectedIndex: 0
|
||||||
|
property bool showIcons: true
|
||||||
|
property alias query: searchInput.text
|
||||||
|
|
||||||
|
readonly property var selectedApp: apps.length > 0 && selectedIndex >= 0 && selectedIndex < apps.length
|
||||||
|
? apps[selectedIndex] : null
|
||||||
|
|
||||||
|
signal selectionRequested(int index)
|
||||||
|
signal moveRequested(int delta)
|
||||||
|
signal launchRequested(int index)
|
||||||
|
signal dismissRequested
|
||||||
|
|
||||||
|
function focusSearch() { searchInput.forceActiveFocus(); }
|
||||||
|
function clearSearch() { searchInput.text = ""; }
|
||||||
|
|
||||||
|
implicitWidth: 1080
|
||||||
|
implicitHeight: 620
|
||||||
|
|
||||||
|
component MicroText: Text {
|
||||||
|
color: Theme.muted
|
||||||
|
font.family: Theme.microFont
|
||||||
|
font.pixelSize: 7
|
||||||
|
font.letterSpacing: 0.9
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
component KeyHint: Row {
|
||||||
|
property string keyText: ""
|
||||||
|
property string actionText: ""
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: keyLabel.implicitWidth + 10
|
||||||
|
height: 18
|
||||||
|
color: Theme.accentAlpha(0.14)
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.accent
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: keyLabel
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: parent.parent.keyText
|
||||||
|
color: Theme.accent
|
||||||
|
font.family: Theme.microFont
|
||||||
|
font.pixelSize: 7
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MicroText {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: parent.actionText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBarPanel {
|
||||||
|
anchors.fill: parent
|
||||||
|
panelId: "008"
|
||||||
|
title: "APPLICATION COMMAND INDEX"
|
||||||
|
meta: root.apps.length + " TARGETS"
|
||||||
|
chamfer: 18
|
||||||
|
|
||||||
|
// Query module.
|
||||||
|
StatusBarPanel {
|
||||||
|
id: queryPanel
|
||||||
|
x: 18
|
||||||
|
y: 34
|
||||||
|
width: 670
|
||||||
|
height: 76
|
||||||
|
panelId: "QRY"
|
||||||
|
title: "SEARCH VECTOR"
|
||||||
|
meta: "FUZZY / PREFIX"
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
anchors.topMargin: 31
|
||||||
|
height: 34
|
||||||
|
spacing: 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: ">_"
|
||||||
|
color: Theme.accent
|
||||||
|
font.family: Theme.displayFont
|
||||||
|
font.pixelSize: 20
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
|
||||||
|
TextInput {
|
||||||
|
id: searchInput
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
color: Theme.text
|
||||||
|
selectionColor: Theme.accent
|
||||||
|
selectedTextColor: Theme.surface
|
||||||
|
font.family: Theme.displayFont
|
||||||
|
font.pixelSize: 18
|
||||||
|
font.letterSpacing: 1
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
onTextChanged: root.selectionRequested(0)
|
||||||
|
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
switch (event.key) {
|
||||||
|
case Qt.Key_Down:
|
||||||
|
case Qt.Key_Tab:
|
||||||
|
root.moveRequested(1);
|
||||||
|
event.accepted = true;
|
||||||
|
break;
|
||||||
|
case Qt.Key_Up:
|
||||||
|
case Qt.Key_Backtab:
|
||||||
|
root.moveRequested(-1);
|
||||||
|
event.accepted = true;
|
||||||
|
break;
|
||||||
|
case Qt.Key_PageDown:
|
||||||
|
root.moveRequested(5);
|
||||||
|
event.accepted = true;
|
||||||
|
break;
|
||||||
|
case Qt.Key_PageUp:
|
||||||
|
root.moveRequested(-5);
|
||||||
|
event.accepted = true;
|
||||||
|
break;
|
||||||
|
case Qt.Key_Return:
|
||||||
|
case Qt.Key_Enter:
|
||||||
|
root.launchRequested(root.selectedIndex);
|
||||||
|
event.accepted = true;
|
||||||
|
break;
|
||||||
|
case Qt.Key_Escape:
|
||||||
|
root.dismissRequested();
|
||||||
|
event.accepted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
visible: searchInput.text.length === 0
|
||||||
|
text: "TYPE APPLICATION DESIGNATION"
|
||||||
|
color: Theme.muted
|
||||||
|
font: searchInput.font
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.preferredWidth: 84
|
||||||
|
Layout.preferredHeight: 22
|
||||||
|
color: Theme.accentAlpha(0.12)
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.hair
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "LIVE INDEX"
|
||||||
|
color: Theme.accent
|
||||||
|
font.family: Theme.microFont
|
||||||
|
font.pixelSize: 7
|
||||||
|
font.bold: true
|
||||||
|
font.letterSpacing: 0.8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search result table.
|
||||||
|
StatusBarPanel {
|
||||||
|
id: resultPanel
|
||||||
|
x: 18
|
||||||
|
y: 118
|
||||||
|
width: 670
|
||||||
|
height: 424
|
||||||
|
panelId: "IDX"
|
||||||
|
title: "APPLICATION TABLE"
|
||||||
|
meta: root.query.length > 0 ? "FILTER ACTIVE" : "A–Z / LOCAL"
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: appList
|
||||||
|
x: 9
|
||||||
|
y: 29
|
||||||
|
width: parent.width - 18
|
||||||
|
height: parent.height - 38
|
||||||
|
clip: true
|
||||||
|
spacing: 3
|
||||||
|
model: root.apps
|
||||||
|
currentIndex: root.selectedIndex
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
onCurrentIndexChanged: positionViewAtIndex(currentIndex, ListView.Contain)
|
||||||
|
|
||||||
|
delegate: MouseArea {
|
||||||
|
id: row
|
||||||
|
required property int index
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
width: ListView.view.width
|
||||||
|
height: 48
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
readonly property bool selected: index === root.selectedIndex
|
||||||
|
|
||||||
|
onEntered: root.selectionRequested(index)
|
||||||
|
onClicked: root.launchRequested(index)
|
||||||
|
|
||||||
|
Shape {
|
||||||
|
id: rowShape
|
||||||
|
anchors.fill: parent
|
||||||
|
preferredRendererType: Shape.CurveRenderer
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
fillColor: row.selected ? Theme.selection : Theme.textAlpha(0.025)
|
||||||
|
strokeColor: row.selected ? Theme.accent : Theme.textAlpha(0.10)
|
||||||
|
strokeWidth: 1
|
||||||
|
startX: 9; startY: 0
|
||||||
|
PathLine { x: rowShape.width; y: 0 }
|
||||||
|
PathLine { x: rowShape.width - 9; y: rowShape.height }
|
||||||
|
PathLine { x: 0; y: rowShape.height }
|
||||||
|
PathLine { x: 9; y: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
fillColor: row.selected ? Theme.accent : Theme.textAlpha(0.12)
|
||||||
|
strokeWidth: 0
|
||||||
|
startX: 9; startY: 0
|
||||||
|
PathLine { x: 13; y: 0 }
|
||||||
|
PathLine { x: 4; y: rowShape.height }
|
||||||
|
PathLine { x: 0; y: rowShape.height }
|
||||||
|
PathLine { x: 9; y: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 18
|
||||||
|
anchors.rightMargin: 18
|
||||||
|
spacing: 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.preferredWidth: 28
|
||||||
|
text: String(row.index + 1).padStart(2, "0")
|
||||||
|
color: row.selected ? Theme.accent : Theme.muted
|
||||||
|
font.family: Theme.microFont
|
||||||
|
font.pixelSize: 8
|
||||||
|
font.bold: row.selected
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.preferredWidth: 34
|
||||||
|
Layout.preferredHeight: 34
|
||||||
|
color: row.selected ? Theme.accentAlpha(0.14) : Theme.textAlpha(0.035)
|
||||||
|
border.width: 1
|
||||||
|
border.color: row.selected ? Theme.accent : Theme.hair
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
visible: root.showIcons
|
||||||
|
anchors.centerIn: parent
|
||||||
|
implicitSize: 24
|
||||||
|
source: root.showIcons
|
||||||
|
? Quickshell.iconPath(row.modelData.icon || "application-x-executable", "application-x-executable")
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
visible: !root.showIcons
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: String(row.modelData.name || "?").charAt(0).toUpperCase()
|
||||||
|
color: row.selected ? Theme.accent : Theme.text
|
||||||
|
font.family: Theme.displayFont
|
||||||
|
font.pixelSize: 14
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 1
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: row.modelData.name || "UNKNOWN TARGET"
|
||||||
|
color: row.selected ? Theme.accent : Theme.text
|
||||||
|
font.family: Theme.displayFont
|
||||||
|
font.pixelSize: 11
|
||||||
|
font.bold: row.selected
|
||||||
|
font.letterSpacing: 0.5
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
MicroText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: row.modelData.genericName || row.modelData.comment || "DESKTOP APPLICATION"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MicroText {
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
text: row.index === root.selectedIndex ? "LOCKED" : "AVAILABLE"
|
||||||
|
color: row.selected ? Theme.accent : Theme.muted
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.preferredWidth: 38
|
||||||
|
Layout.preferredHeight: 6
|
||||||
|
color: Theme.textAlpha(0.05)
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.hair
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: row.selected ? parent.width : Math.max(5, parent.width * (1 - row.index / Math.max(1, root.apps.length)))
|
||||||
|
height: parent.height
|
||||||
|
color: row.selected ? Theme.accent : Theme.textAlpha(0.20)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
visible: root.apps.length === 0
|
||||||
|
text: "NO EXECUTABLE TARGETS MATCH QUERY"
|
||||||
|
color: Theme.muted
|
||||||
|
font.family: Theme.microFont
|
||||||
|
font.pixelSize: 9
|
||||||
|
font.letterSpacing: 1.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selected application inspector.
|
||||||
|
StatusBarPanel {
|
||||||
|
id: inspector
|
||||||
|
x: 700
|
||||||
|
y: 34
|
||||||
|
width: 362
|
||||||
|
height: 508
|
||||||
|
panelId: "SEL"
|
||||||
|
title: "TARGET INSPECTOR"
|
||||||
|
meta: root.selectedApp ? "LOCKED" : "NO TARGET"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: reticle
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
y: 39
|
||||||
|
width: 126
|
||||||
|
height: 126
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 112
|
||||||
|
height: 112
|
||||||
|
radius: 56
|
||||||
|
color: Theme.textAlpha(0.015)
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.accentAlpha(0.52)
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 84
|
||||||
|
height: 84
|
||||||
|
radius: 42
|
||||||
|
color: Theme.textAlpha(0)
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.hair
|
||||||
|
}
|
||||||
|
Rectangle { anchors.centerIn: parent; width: 126; height: 1; color: Theme.hair }
|
||||||
|
Rectangle { anchors.centerIn: parent; width: 1; height: 126; color: Theme.hair }
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 60
|
||||||
|
height: 60
|
||||||
|
color: Theme.surface
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.accent
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
visible: root.showIcons
|
||||||
|
anchors.centerIn: parent
|
||||||
|
implicitSize: 44
|
||||||
|
source: root.showIcons && root.selectedApp
|
||||||
|
? Quickshell.iconPath(root.selectedApp.icon || "application-x-executable", "application-x-executable")
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
visible: !root.showIcons
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: root.selectedApp ? String(root.selectedApp.name || "?").charAt(0).toUpperCase() : "?"
|
||||||
|
color: Theme.accent
|
||||||
|
font.family: Theme.displayFont
|
||||||
|
font.pixelSize: 28
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: 4
|
||||||
|
Rectangle {
|
||||||
|
required property int index
|
||||||
|
width: 5; height: 5
|
||||||
|
x: index % 2 === 0 ? 8 : reticle.width - 13
|
||||||
|
y: index < 2 ? 8 : reticle.height - 13
|
||||||
|
color: Theme.accent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.top: reticle.bottom
|
||||||
|
anchors.topMargin: 14
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: parent.width - 34
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: root.selectedApp ? root.selectedApp.name : "NO TARGET"
|
||||||
|
color: Theme.text
|
||||||
|
font.family: Theme.displayFont
|
||||||
|
font.pixelSize: 19
|
||||||
|
font.bold: true
|
||||||
|
font.letterSpacing: 1
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
MicroText {
|
||||||
|
id: genericLabel
|
||||||
|
anchors.top: reticle.bottom
|
||||||
|
anchors.topMargin: 42
|
||||||
|
x: 18
|
||||||
|
width: parent.width - 36
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: root.selectedApp ? (root.selectedApp.genericName || "DESKTOP APPLICATION") : "AWAITING SEARCH VECTOR"
|
||||||
|
color: Theme.accent
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
x: 18
|
||||||
|
anchors.top: genericLabel.bottom
|
||||||
|
anchors.topMargin: 12
|
||||||
|
width: parent.width - 36
|
||||||
|
height: 1
|
||||||
|
color: Theme.hair
|
||||||
|
}
|
||||||
|
|
||||||
|
MicroText {
|
||||||
|
id: description
|
||||||
|
x: 22
|
||||||
|
anchors.top: genericLabel.bottom
|
||||||
|
anchors.topMargin: 27
|
||||||
|
width: parent.width - 44
|
||||||
|
height: 42
|
||||||
|
text: root.selectedApp ? (root.selectedApp.comment || "No application description supplied by desktop entry.") : "Enter a designation to acquire an executable target."
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 3
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
id: telemetryGrid
|
||||||
|
x: 18
|
||||||
|
anchors.top: description.bottom
|
||||||
|
anchors.topMargin: 15
|
||||||
|
width: parent.width - 36
|
||||||
|
columns: 2
|
||||||
|
rowSpacing: 7
|
||||||
|
columnSpacing: 7
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: [
|
||||||
|
{ label: "ENTRY", value: "DESKTOP" },
|
||||||
|
{ label: "MODE", value: "DETACHED" },
|
||||||
|
{ label: "AUTH", value: "LOCAL USER" },
|
||||||
|
{ label: "INDEX", value: String(Math.max(0, root.selectedIndex + 1)).padStart(3, "0") }
|
||||||
|
]
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 46
|
||||||
|
color: Theme.textAlpha(0.025)
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.hair
|
||||||
|
|
||||||
|
MicroText { x: 8; y: 7; width: parent.width - 16; text: modelData.label }
|
||||||
|
Text {
|
||||||
|
x: 8; y: 22; width: parent.width - 16
|
||||||
|
text: modelData.value
|
||||||
|
color: Theme.text
|
||||||
|
font.family: Theme.displayFont
|
||||||
|
font.pixelSize: 9
|
||||||
|
font.bold: true
|
||||||
|
font.letterSpacing: 0.6
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
x: 18
|
||||||
|
anchors.bottom: executeTile.top
|
||||||
|
anchors.bottomMargin: 12
|
||||||
|
width: parent.width - 36
|
||||||
|
height: 18
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 5
|
||||||
|
Repeater {
|
||||||
|
model: 24
|
||||||
|
Rectangle {
|
||||||
|
required property int index
|
||||||
|
width: 7; height: 3
|
||||||
|
y: index % 3 === 0 ? 0 : 4
|
||||||
|
color: index < 16 ? Theme.accent : Theme.hair
|
||||||
|
transform: Rotation { angle: -35 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: executeTile
|
||||||
|
x: 18
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 14
|
||||||
|
width: parent.width - 36
|
||||||
|
height: 42
|
||||||
|
enabled: root.selectedApp !== null
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
onClicked: root.launchRequested(root.selectedIndex)
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: executeTile.containsMouse ? Theme.accent : Theme.accentAlpha(0.16)
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.accent
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: root.selectedApp ? "EXECUTE SELECTED TARGET" : "NO TARGET ACQUIRED"
|
||||||
|
color: executeTile.containsMouse ? Theme.surface : Theme.accent
|
||||||
|
font.family: Theme.displayFont
|
||||||
|
font.pixelSize: 10
|
||||||
|
font.bold: true
|
||||||
|
font.letterSpacing: 1.2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dense command footer.
|
||||||
|
StatusBarPanel {
|
||||||
|
x: 18
|
||||||
|
y: 550
|
||||||
|
width: 1044
|
||||||
|
height: 52
|
||||||
|
showHeader: false
|
||||||
|
chamfer: 9
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
spacing: 18
|
||||||
|
|
||||||
|
MicroText { text: "INPUT CHANNEL // KEYBOARD"; color: Theme.accent }
|
||||||
|
Rectangle { Layout.preferredWidth: 1; Layout.preferredHeight: 22; color: Theme.hair }
|
||||||
|
KeyHint { keyText: "↑ ↓"; actionText: "SELECT" }
|
||||||
|
KeyHint { keyText: "ENTER"; actionText: "EXECUTE" }
|
||||||
|
KeyHint { keyText: "ESC"; actionText: "ABORT" }
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
MicroText { text: "QRY:" + (root.query.length > 0 ? "ACTIVE" : "IDLE") }
|
||||||
|
MicroText { text: "CRC // A7F2" }
|
||||||
|
Rectangle {
|
||||||
|
Layout.preferredWidth: 76
|
||||||
|
Layout.preferredHeight: 4
|
||||||
|
color: Theme.accent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -198,7 +198,7 @@ in
|
|||||||
|
|
||||||
# quickshell app-launcher variants (evaluating — pick one)
|
# quickshell app-launcher variants (evaluating — pick one)
|
||||||
]
|
]
|
||||||
++ (map (n: bind "SUPER + CTRL + ${toString n}" (dsp.global "quickshell:launcher${toString n}")) (lib.range 1 7))
|
++ (map (n: bind "SUPER + CTRL + ${toString n}" (dsp.global "quickshell:launcher${toString n}")) (lib.range 1 8))
|
||||||
++ [
|
++ [
|
||||||
# restart quickshell (also starts it if not running)
|
# restart quickshell (also starts it if not running)
|
||||||
(bind "SUPER + CTRL + 0" (dsp.exec "qs kill; sleep 0.3; qs"))
|
(bind "SUPER + CTRL + 0" (dsp.exec "qs kill; sleep 0.3; qs"))
|
||||||
|
|||||||
Reference in New Issue
Block a user