mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
keybinds/cheasheet: support all providers
This commit is contained in:
@@ -513,11 +513,11 @@ Item {
|
|||||||
|
|
||||||
active: false
|
active: false
|
||||||
|
|
||||||
HyprKeybindsModal {
|
KeybindsModal {
|
||||||
id: hyprKeybindsModal
|
id: keybindsModal
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
PopoutService.hyprKeybindsModal = hyprKeybindsModal
|
PopoutService.hyprKeybindsModal = keybindsModal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -306,11 +306,58 @@ Item {
|
|||||||
target: "mpris"
|
target: "mpris"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
function toggle(provider: string): string {
|
||||||
|
if (!provider) {
|
||||||
|
return "ERROR: No provider specified"
|
||||||
|
}
|
||||||
|
|
||||||
|
KeybindsService.loadProvider(provider)
|
||||||
|
root.hyprKeybindsModalLoader.active = true
|
||||||
|
|
||||||
|
if (root.hyprKeybindsModalLoader.item) {
|
||||||
|
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
|
||||||
|
root.hyprKeybindsModalLoader.item.close()
|
||||||
|
} else {
|
||||||
|
root.hyprKeybindsModalLoader.item.open()
|
||||||
|
}
|
||||||
|
return `KEYBINDS_TOGGLE_SUCCESS: ${provider}`
|
||||||
|
}
|
||||||
|
return `KEYBINDS_TOGGLE_FAILED: ${provider}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function open(provider: string): string {
|
||||||
|
if (!provider) {
|
||||||
|
return "ERROR: No provider specified"
|
||||||
|
}
|
||||||
|
|
||||||
|
KeybindsService.loadProvider(provider)
|
||||||
|
root.hyprKeybindsModalLoader.active = true
|
||||||
|
|
||||||
|
if (root.hyprKeybindsModalLoader.item) {
|
||||||
|
root.hyprKeybindsModalLoader.item.open()
|
||||||
|
return `KEYBINDS_OPEN_SUCCESS: ${provider}`
|
||||||
|
}
|
||||||
|
return `KEYBINDS_OPEN_FAILED: ${provider}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function close(): string {
|
||||||
|
if (root.hyprKeybindsModalLoader.item) {
|
||||||
|
root.hyprKeybindsModalLoader.item.close()
|
||||||
|
return "KEYBINDS_CLOSE_SUCCESS"
|
||||||
|
}
|
||||||
|
return "KEYBINDS_CLOSE_FAILED"
|
||||||
|
}
|
||||||
|
|
||||||
|
target: "keybinds"
|
||||||
|
}
|
||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
function openBinds(): string {
|
function openBinds(): string {
|
||||||
if (!CompositorService.isHyprland) {
|
if (!CompositorService.isHyprland) {
|
||||||
return "HYPR_NOT_AVAILABLE"
|
return "HYPR_NOT_AVAILABLE"
|
||||||
}
|
}
|
||||||
|
KeybindsService.loadProvider("hyprland")
|
||||||
root.hyprKeybindsModalLoader.active = true
|
root.hyprKeybindsModalLoader.active = true
|
||||||
if (root.hyprKeybindsModalLoader.item) {
|
if (root.hyprKeybindsModalLoader.item) {
|
||||||
root.hyprKeybindsModalLoader.item.open()
|
root.hyprKeybindsModalLoader.item.open()
|
||||||
@@ -334,6 +381,7 @@ Item {
|
|||||||
if (!CompositorService.isHyprland) {
|
if (!CompositorService.isHyprland) {
|
||||||
return "HYPR_NOT_AVAILABLE"
|
return "HYPR_NOT_AVAILABLE"
|
||||||
}
|
}
|
||||||
|
KeybindsService.loadProvider("hyprland")
|
||||||
root.hyprKeybindsModalLoader.active = true
|
root.hyprKeybindsModalLoader.active = true
|
||||||
if (root.hyprKeybindsModalLoader.item) {
|
if (root.hyprKeybindsModalLoader.item) {
|
||||||
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
|
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
|
||||||
|
|||||||
@@ -1,297 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import Quickshell
|
|
||||||
import qs.Common
|
|
||||||
import qs.Modals.Common
|
|
||||||
import qs.Services
|
|
||||||
import qs.Widgets
|
|
||||||
|
|
||||||
DankModal {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
layerNamespace: "dms:hyprkeybinds"
|
|
||||||
property real scrollStep: 60
|
|
||||||
property var activeFlickable: null
|
|
||||||
property real _maxW: Math.min(Screen.width * 0.92, 1200)
|
|
||||||
property real _maxH: Math.min(Screen.height * 0.92, 900)
|
|
||||||
width: _maxW
|
|
||||||
height: _maxH
|
|
||||||
onBackgroundClicked: close()
|
|
||||||
|
|
||||||
function scrollDown() {
|
|
||||||
if (!root.activeFlickable) return
|
|
||||||
let newY = root.activeFlickable.contentY + scrollStep
|
|
||||||
newY = Math.min(newY, root.activeFlickable.contentHeight - root.activeFlickable.height)
|
|
||||||
root.activeFlickable.contentY = newY
|
|
||||||
}
|
|
||||||
|
|
||||||
function scrollUp() {
|
|
||||||
if (!root.activeFlickable) return
|
|
||||||
let newY = root.activeFlickable.contentY - root.scrollStep
|
|
||||||
newY = Math.max(0, newY)
|
|
||||||
root.activeFlickable.contentY = newY
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Shortcut { sequence: "Ctrl+j"; onActivated: root.scrollDown() }
|
|
||||||
Shortcut { sequence: "Down"; onActivated: root.scrollDown() }
|
|
||||||
Shortcut { sequence: "Ctrl+k"; onActivated: root.scrollUp() }
|
|
||||||
Shortcut { sequence: "Up"; onActivated: root.scrollUp() }
|
|
||||||
Shortcut { sequence: "Esc"; onActivated: root.close() }
|
|
||||||
|
|
||||||
function categorizeKeybinds() {
|
|
||||||
const categories = {
|
|
||||||
"Workspace": [],
|
|
||||||
"Window": [],
|
|
||||||
"Monitor": [],
|
|
||||||
"Execute": [],
|
|
||||||
"System": [],
|
|
||||||
"Other": []
|
|
||||||
}
|
|
||||||
|
|
||||||
function addKeybind(keybind) {
|
|
||||||
const dispatcher = keybind.dispatcher || ""
|
|
||||||
if (dispatcher.includes("workspace")) {
|
|
||||||
categories["Workspace"].push(keybind)
|
|
||||||
} else if (dispatcher.includes("monitor")) {
|
|
||||||
categories["Monitor"].push(keybind)
|
|
||||||
} else if (dispatcher.includes("window") || dispatcher.includes("focus") || dispatcher.includes("move") || dispatcher.includes("swap") || dispatcher.includes("resize") || dispatcher === "killactive" || dispatcher === "fullscreen" || dispatcher === "togglefloating") {
|
|
||||||
categories["Window"].push(keybind)
|
|
||||||
} else if (dispatcher === "exec") {
|
|
||||||
categories["Execute"].push(keybind)
|
|
||||||
} else if (dispatcher === "exit" || dispatcher.includes("dpms")) {
|
|
||||||
categories["System"].push(keybind)
|
|
||||||
} else {
|
|
||||||
categories["Other"].push(keybind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const allKeybinds = HyprKeybindsService.keybinds.keybinds || []
|
|
||||||
for (let i = 0; i < allKeybinds.length; i++) {
|
|
||||||
addKeybind(allKeybinds[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
const children = HyprKeybindsService.keybinds.children || []
|
|
||||||
for (let i = 0; i < children.length; i++) {
|
|
||||||
const child = children[i]
|
|
||||||
const childKeybinds = child.keybinds || []
|
|
||||||
for (let j = 0; j < childKeybinds.length; j++) {
|
|
||||||
addKeybind(childKeybinds[j])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
categories["Workspace"].sort((a, b) => {
|
|
||||||
const dispA = a.dispatcher || ""
|
|
||||||
const dispB = b.dispatcher || ""
|
|
||||||
return dispA.localeCompare(dispB)
|
|
||||||
})
|
|
||||||
|
|
||||||
categories["Window"].sort((a, b) => {
|
|
||||||
const dispA = a.dispatcher || ""
|
|
||||||
const dispB = b.dispatcher || ""
|
|
||||||
return dispA.localeCompare(dispB)
|
|
||||||
})
|
|
||||||
|
|
||||||
categories["Monitor"].sort((a, b) => {
|
|
||||||
const dispA = a.dispatcher || ""
|
|
||||||
const dispB = b.dispatcher || ""
|
|
||||||
return dispA.localeCompare(dispB)
|
|
||||||
})
|
|
||||||
|
|
||||||
categories["Execute"].sort((a, b) => {
|
|
||||||
const modsA = a.mods || []
|
|
||||||
const keyA = a.key || ""
|
|
||||||
const bindA = [...modsA, keyA].join("+")
|
|
||||||
|
|
||||||
const modsB = b.mods || []
|
|
||||||
const keyB = b.key || ""
|
|
||||||
const bindB = [...modsB, keyB].join("+")
|
|
||||||
|
|
||||||
return bindA.localeCompare(bindB)
|
|
||||||
})
|
|
||||||
|
|
||||||
return categories
|
|
||||||
}
|
|
||||||
|
|
||||||
content: Component {
|
|
||||||
Item {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
DankFlickable {
|
|
||||||
id: mainFlickable
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingL
|
|
||||||
contentWidth: rowLayout.implicitWidth
|
|
||||||
contentHeight: rowLayout.implicitHeight
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
Component.onCompleted: root.activeFlickable = mainFlickable
|
|
||||||
Component.onDestruction: root.activeFlickable = null
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: rowLayout
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
property var categories: root.categorizeKeybinds()
|
|
||||||
property real columnWidth: (mainFlickable.width - spacing * 2) / 3
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: rowLayout.columnWidth
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: "Window / Monitor"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
font.weight: Font.Bold
|
|
||||||
color: Theme.primary
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: 1
|
|
||||||
color: Theme.primary
|
|
||||||
opacity: 0.3
|
|
||||||
}
|
|
||||||
|
|
||||||
Item { width: 1; height: Theme.spacingXS }
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: [...(rowLayout.categories["Window"] || []), ...(rowLayout.categories["Monitor"] || [])]
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
width: Math.min(140, parent.width * 0.42)
|
|
||||||
height: 22
|
|
||||||
radius: 4
|
|
||||||
opacity: 0.9
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
anchors.margins: 2
|
|
||||||
width: parent.width - 4
|
|
||||||
color: Theme.secondary
|
|
||||||
text: {
|
|
||||||
const mods = modelData.mods || []
|
|
||||||
const key = modelData.key || ""
|
|
||||||
const parts = [...mods, key]
|
|
||||||
return parts.join("+")
|
|
||||||
}
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
font.weight: Font.Medium
|
|
||||||
isMonospace: true
|
|
||||||
elide: Text.ElideRight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
width: parent.width - 150
|
|
||||||
text: {
|
|
||||||
const comment = modelData.comment || ""
|
|
||||||
if (comment) return comment
|
|
||||||
|
|
||||||
const dispatcher = modelData.dispatcher || ""
|
|
||||||
const params = modelData.params || ""
|
|
||||||
return params ? `${dispatcher} ${params}` : dispatcher
|
|
||||||
}
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
opacity: 0.9
|
|
||||||
elide: Text.ElideRight
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: ["Workspace", "Execute"]
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: rowLayout.columnWidth
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: modelData
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
font.weight: Font.Bold
|
|
||||||
color: Theme.primary
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: 1
|
|
||||||
color: Theme.primary
|
|
||||||
opacity: 0.3
|
|
||||||
}
|
|
||||||
|
|
||||||
Item { width: 1; height: Theme.spacingXS }
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: rowLayout.categories[modelData] || []
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
width: Math.min(140, parent.width * 0.42)
|
|
||||||
height: 22
|
|
||||||
radius: 4
|
|
||||||
opacity: 0.9
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
anchors.margins: 2
|
|
||||||
width: parent.width - 4
|
|
||||||
color: Theme.secondary
|
|
||||||
text: {
|
|
||||||
const mods = modelData.mods || []
|
|
||||||
const key = modelData.key || ""
|
|
||||||
const parts = [...mods, key]
|
|
||||||
return parts.join("+")
|
|
||||||
}
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
font.weight: Font.Medium
|
|
||||||
isMonospace: true
|
|
||||||
elide: Text.ElideRight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
width: parent.width - 150
|
|
||||||
text: {
|
|
||||||
const comment = modelData.comment || ""
|
|
||||||
if (comment) return comment
|
|
||||||
|
|
||||||
const dispatcher = modelData.dispatcher || ""
|
|
||||||
const params = modelData.params || ""
|
|
||||||
return params ? `${dispatcher} ${params}` : dispatcher
|
|
||||||
}
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
opacity: 0.9
|
|
||||||
elide: Text.ElideRight
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
232
Modals/KeybindsModal.qml
Normal file
232
Modals/KeybindsModal.qml
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import qs.Common
|
||||||
|
import qs.Modals.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
DankModal {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
layerNamespace: "dms:keybinds"
|
||||||
|
property real scrollStep: 60
|
||||||
|
property var activeFlickable: null
|
||||||
|
property real _maxW: Math.min(Screen.width * 0.92, 1200)
|
||||||
|
property real _maxH: Math.min(Screen.height * 0.92, 900)
|
||||||
|
width: _maxW
|
||||||
|
height: _maxH
|
||||||
|
onBackgroundClicked: close()
|
||||||
|
|
||||||
|
function scrollDown() {
|
||||||
|
if (!root.activeFlickable) return
|
||||||
|
let newY = root.activeFlickable.contentY + scrollStep
|
||||||
|
newY = Math.min(newY, root.activeFlickable.contentHeight - root.activeFlickable.height)
|
||||||
|
root.activeFlickable.contentY = newY
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollUp() {
|
||||||
|
if (!root.activeFlickable) return
|
||||||
|
let newY = root.activeFlickable.contentY - root.scrollStep
|
||||||
|
newY = Math.max(0, newY)
|
||||||
|
root.activeFlickable.contentY = newY
|
||||||
|
}
|
||||||
|
|
||||||
|
Shortcut { sequence: "Ctrl+j"; onActivated: root.scrollDown() }
|
||||||
|
Shortcut { sequence: "Down"; onActivated: root.scrollDown() }
|
||||||
|
Shortcut { sequence: "Ctrl+k"; onActivated: root.scrollUp() }
|
||||||
|
Shortcut { sequence: "Up"; onActivated: root.scrollUp() }
|
||||||
|
Shortcut { sequence: "Esc"; onActivated: root.close() }
|
||||||
|
|
||||||
|
content: Component {
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: KeybindsService.keybinds.title || "Keybinds"
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
DankFlickable {
|
||||||
|
id: mainFlickable
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height - parent.spacing - 40
|
||||||
|
contentWidth: rowLayout.implicitWidth
|
||||||
|
contentHeight: rowLayout.implicitHeight
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Component.onCompleted: root.activeFlickable = mainFlickable
|
||||||
|
|
||||||
|
property var rawBinds: KeybindsService.keybinds.binds || {}
|
||||||
|
property var categories: {
|
||||||
|
const processed = {}
|
||||||
|
for (const cat in rawBinds) {
|
||||||
|
const binds = rawBinds[cat]
|
||||||
|
const subcats = {}
|
||||||
|
let hasSubcats = false
|
||||||
|
|
||||||
|
for (let i = 0; i < binds.length; i++) {
|
||||||
|
const bind = binds[i]
|
||||||
|
if (bind.subcat) {
|
||||||
|
hasSubcats = true
|
||||||
|
if (!subcats[bind.subcat]) {
|
||||||
|
subcats[bind.subcat] = []
|
||||||
|
}
|
||||||
|
subcats[bind.subcat].push(bind)
|
||||||
|
} else {
|
||||||
|
if (!subcats["_root"]) {
|
||||||
|
subcats["_root"] = []
|
||||||
|
}
|
||||||
|
subcats["_root"].push(bind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processed[cat] = {
|
||||||
|
hasSubcats: hasSubcats,
|
||||||
|
subcats: subcats,
|
||||||
|
subcatKeys: Object.keys(subcats)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return processed
|
||||||
|
}
|
||||||
|
property var categoryKeys: Object.keys(categories)
|
||||||
|
|
||||||
|
function distributeCategories(cols) {
|
||||||
|
const columns = []
|
||||||
|
for (let i = 0; i < cols; i++) {
|
||||||
|
columns.push([])
|
||||||
|
}
|
||||||
|
for (let i = 0; i < categoryKeys.length; i++) {
|
||||||
|
columns[i % cols].push(categoryKeys[i])
|
||||||
|
}
|
||||||
|
return columns
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: rowLayout
|
||||||
|
width: mainFlickable.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
property int numColumns: Math.max(1, Math.min(3, Math.floor(width / 350)))
|
||||||
|
property var columnCategories: mainFlickable.distributeCategories(numColumns)
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: rowLayout.numColumns
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: masonryColumn
|
||||||
|
width: (rowLayout.width - rowLayout.spacing * (rowLayout.numColumns - 1)) / rowLayout.numColumns
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: rowLayout.columnCategories[index] || []
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: categoryColumn
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
property string catName: modelData
|
||||||
|
property var catData: mainFlickable.categories[catName]
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: categoryColumn.catName
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Bold
|
||||||
|
color: Theme.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: Theme.primary
|
||||||
|
opacity: 0.3
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { width: 1; height: Theme.spacingXS }
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: categoryColumn.catData?.subcatKeys || []
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
property string subcatName: modelData
|
||||||
|
property var subcatBinds: categoryColumn.catData?.subcats?.[subcatName] || []
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
visible: parent.subcatName !== "_root"
|
||||||
|
text: parent.subcatName
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.DemiBold
|
||||||
|
color: Theme.primary
|
||||||
|
opacity: 0.7
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: parent.parent.subcatBinds
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
width: Math.min(140, parent.width * 0.42)
|
||||||
|
height: 22
|
||||||
|
radius: 4
|
||||||
|
opacity: 0.9
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.margins: 2
|
||||||
|
width: parent.width - 4
|
||||||
|
color: Theme.secondary
|
||||||
|
text: modelData.key || ""
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
isMonospace: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width - 150
|
||||||
|
text: modelData.desc || ""
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
opacity: 0.9
|
||||||
|
elide: Text.ElideRight
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtCore
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import qs.Common
|
|
||||||
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
readonly property string _configUrl: StandardPaths.writableLocation(StandardPaths.ConfigLocation)
|
|
||||||
readonly property string _configDir: Paths.strip(_configUrl)
|
|
||||||
property string hyprConfigPath: `${_configDir}/hypr`
|
|
||||||
property var keybinds: ({"children": [], "keybinds": []})
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: getKeybinds
|
|
||||||
running: false
|
|
||||||
command: ["dms", "hyprland", "keybinds", "--path", root.hyprConfigPath]
|
|
||||||
|
|
||||||
stdout: SplitParser {
|
|
||||||
onRead: data => {
|
|
||||||
try {
|
|
||||||
root.keybinds = JSON.parse(data)
|
|
||||||
} catch (e) {
|
|
||||||
console.error("[HyprKeybindsService] Error parsing keybinds:", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onExited: (code) => {
|
|
||||||
if (code !== 0) {
|
|
||||||
console.warn("[HyprKeybindsService] Process exited with code:", code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
getKeybinds.running = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function reload() {
|
|
||||||
getKeybinds.running = false
|
|
||||||
Qt.callLater(function() {
|
|
||||||
getKeybinds.running = true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
60
Services/KeybindsService.qml
Normal file
60
Services/KeybindsService.qml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtCore
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string currentProvider: "hyprland"
|
||||||
|
property var keybinds: ({"title": "", "provider": "", "binds": []})
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: getKeybinds
|
||||||
|
running: false
|
||||||
|
command: ["dms", "keybinds", "show", root.currentProvider]
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
try {
|
||||||
|
root.keybinds = JSON.parse(text)
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[KeybindsService] Error parsing keybinds:", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onExited: (code) => {
|
||||||
|
if (code !== 0 && code !== 15) {
|
||||||
|
console.warn("[KeybindsService] Process exited with code:", code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 500
|
||||||
|
running: true
|
||||||
|
repeat: false
|
||||||
|
onTriggered: {
|
||||||
|
getKeybinds.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadProvider(provider) {
|
||||||
|
root.currentProvider = provider
|
||||||
|
reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
function reload() {
|
||||||
|
if (getKeybinds.running) {
|
||||||
|
getKeybinds.running = false
|
||||||
|
}
|
||||||
|
Qt.callLater(function() {
|
||||||
|
getKeybinds.running = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user