mirror of
https://github.com/end-4/dots-hyprland.git
synced 2026-06-05 14:59:27 -05:00
qs: cheatsheet: display categories nicely
This commit is contained in:
@@ -10,76 +10,9 @@ import Quickshell
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var keybinds: HyprlandKeybinds.keybinds.filter(function(keybind) {
|
||||
return keybind.has_description;
|
||||
})
|
||||
property real columnSpacing: 40
|
||||
property real titleSpacing: 7
|
||||
property real padding: 4
|
||||
implicitWidth: QsWindow.window.screen.width * 0.7
|
||||
implicitHeight: QsWindow.window.screen.height * 0.7
|
||||
// Excellent symbol explaination and source :
|
||||
// http://xahlee.info/comp/unicode_computing_symbols.html
|
||||
// https://www.nerdfonts.com/cheat-sheet
|
||||
property var macSymbolMap: ({
|
||||
"Ctrl": "",
|
||||
"Alt": "",
|
||||
"Shift": "",
|
||||
"Space": "",
|
||||
"Tab": "↹",
|
||||
"Equal": "",
|
||||
"Minus": "",
|
||||
"Print": "",
|
||||
"BackSpace": "",
|
||||
"Delete": "⌦",
|
||||
"Return": "",
|
||||
"Period": ".",
|
||||
"Escape": "⎋"
|
||||
})
|
||||
property var functionSymbolMap: ({
|
||||
"F1": "",
|
||||
"F2": "",
|
||||
"F3": "",
|
||||
"F4": "",
|
||||
"F5": "",
|
||||
"F6": "",
|
||||
"F7": "",
|
||||
"F8": "",
|
||||
"F9": "",
|
||||
"F10": "",
|
||||
"F11": "",
|
||||
"F12": "",
|
||||
})
|
||||
|
||||
property var mouseSymbolMap: ({
|
||||
"mouse_up": "",
|
||||
"mouse_down": "",
|
||||
"mouse:272": "L",
|
||||
"mouse:273": "R",
|
||||
"Scroll ↑/↓": "",
|
||||
"Page_↑/↓": "⇞/⇟",
|
||||
})
|
||||
|
||||
property var keyBlacklist: ["SUPER_L", "SUPER_R"]
|
||||
property var keySubstitutions: Object.assign({
|
||||
"Super": "",
|
||||
"mouse_up": "Scroll ↓", // ikr, weird
|
||||
"mouse_down": "Scroll ↑", // trust me bro
|
||||
"mouse:272": "LMB",
|
||||
"mouse:273": "RMB",
|
||||
"mouse:275": "MouseBack",
|
||||
"Slash": "/",
|
||||
"Hash": "#",
|
||||
"Return": "Enter",
|
||||
// "Shift": "",
|
||||
},
|
||||
!!Config.options.cheatsheet.superKey ? {
|
||||
"Super": Config.options.cheatsheet.superKey,
|
||||
}: {},
|
||||
Config.options.cheatsheet.useMacSymbol ? macSymbolMap : {},
|
||||
Config.options.cheatsheet.useFnSymbol ? functionSymbolMap : {},
|
||||
Config.options.cheatsheet.useMouseSymbol ? mouseSymbolMap : {},
|
||||
)
|
||||
implicitWidth: QsWindow?.window?.screen.width * 0.7 ?? 0
|
||||
implicitHeight: QsWindow?.window?.screen.height * 0.7 ?? 0
|
||||
|
||||
StyledFlickable {
|
||||
id: flickable
|
||||
@@ -91,79 +24,12 @@ Item {
|
||||
id: flow
|
||||
height: flickable.height
|
||||
flow: Flow.TopToBottom
|
||||
spacing: 4
|
||||
spacing: 12
|
||||
Repeater {
|
||||
model: root.keybinds
|
||||
delegate: BindLine {
|
||||
model: [...HyprlandKeybinds.keybindCategories, ""]
|
||||
delegate: CheatsheetKeybindsCategory {
|
||||
required property var modelData
|
||||
keyData: modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function modMaskToStringList(modMask: int): list<string> {
|
||||
var list = [];
|
||||
if (modMask & (1 << 0)) { list.push("Shift"); }
|
||||
if (modMask & (1 << 1)) { list.push("Caps"); }
|
||||
if (modMask & (1 << 2)) { list.push("Ctrl"); }
|
||||
if (modMask & (1 << 3)) { list.push("Alt"); }
|
||||
if (modMask & (1 << 4)) { list.push("Mod2"); }
|
||||
if (modMask & (1 << 5)) { list.push("Mod3"); }
|
||||
if (modMask & (1 << 6)) { list.push("Super"); }
|
||||
if (modMask & (1 << 7)) { list.push("Mod5"); }
|
||||
return list;
|
||||
}
|
||||
|
||||
property int maxBindWidth: 0
|
||||
|
||||
component BindLine: Row {
|
||||
required property var keyData
|
||||
Row {
|
||||
spacing: 16
|
||||
Row {
|
||||
id: modRow
|
||||
Component.onCompleted: root.maxBindWidth = Math.max(root.maxBindWidth, implicitWidth)
|
||||
width: root.maxBindWidth
|
||||
spacing: 4
|
||||
Repeater {
|
||||
model: {
|
||||
const modList = root.modMaskToStringList(keyData.modmask)
|
||||
if (modList.length == 0) return []
|
||||
if (Config.options.cheatsheet.splitButtons) return modList;
|
||||
return [modList.join(" ")]
|
||||
}
|
||||
delegate: KeyboardKey {
|
||||
required property var modelData
|
||||
key: root.keySubstitutions[modelData] || modelData
|
||||
pixelSize: Config.options.cheatsheet.fontSize.key
|
||||
}
|
||||
}
|
||||
StyledText {
|
||||
id: keybindPlus
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !keyBlacklist.includes(keyData.key) && keyData.modmask > 0
|
||||
text: "+"
|
||||
}
|
||||
KeyboardKey {
|
||||
id: keybindKey
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !keyBlacklist.includes(keyData.key)
|
||||
key: StringUtils.toTitleCase(root.keySubstitutions[keyData.key] || keyData.key)
|
||||
pixelSize: Config.options.cheatsheet.fontSize.key
|
||||
color: Appearance.colors.colOnLayer0
|
||||
}
|
||||
}
|
||||
Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
implicitWidth: commentText.implicitWidth + root.columnSpacing
|
||||
implicitHeight: commentText.implicitHeight
|
||||
StyledText {
|
||||
id: commentText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
font.pixelSize: Config.options.cheatsheet.fontSize.comment || Appearance.font.pixelSize.smaller
|
||||
text: keyData.description
|
||||
categoryName: modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
|
||||
Column {
|
||||
id: root
|
||||
required property string categoryName
|
||||
readonly property bool isCategorized: categoryName?.length > 0
|
||||
property int maxBindWidth: 0
|
||||
property real columnSpacing: 40
|
||||
property real titleSpacing: 7
|
||||
|
||||
// Excellent symbol explaination and source :
|
||||
// http://xahlee.info/comp/unicode_computing_symbols.html
|
||||
// https://www.nerdfonts.com/cheat-sheet
|
||||
property var macSymbolMap: ({
|
||||
"Ctrl": "",
|
||||
"Alt": "",
|
||||
"Shift": "",
|
||||
"Space": "",
|
||||
"Tab": "↹",
|
||||
"Equal": "",
|
||||
"Minus": "",
|
||||
"Print": "",
|
||||
"BackSpace": "",
|
||||
"Delete": "⌦",
|
||||
"Return": "",
|
||||
"Period": ".",
|
||||
"Escape": "⎋"
|
||||
})
|
||||
property var functionSymbolMap: ({
|
||||
"F1": "",
|
||||
"F2": "",
|
||||
"F3": "",
|
||||
"F4": "",
|
||||
"F5": "",
|
||||
"F6": "",
|
||||
"F7": "",
|
||||
"F8": "",
|
||||
"F9": "",
|
||||
"F10": "",
|
||||
"F11": "",
|
||||
"F12": "",
|
||||
})
|
||||
|
||||
property var mouseSymbolMap: ({
|
||||
"mouse_up": "",
|
||||
"mouse_down": "",
|
||||
"mouse:272": "L",
|
||||
"mouse:273": "R",
|
||||
"Scroll ↑/↓": "",
|
||||
"Page_↑/↓": "⇞/⇟",
|
||||
})
|
||||
|
||||
property var keyBlacklist: ["SUPER_L", "SUPER_R"]
|
||||
property var keySubstitutions: Object.assign({
|
||||
"Super": "",
|
||||
"mouse_up": "Scroll ↓", // ikr, weird
|
||||
"mouse_down": "Scroll ↑", // trust me bro
|
||||
"mouse:272": "LMB",
|
||||
"mouse:273": "RMB",
|
||||
"mouse:275": "MouseBack",
|
||||
"Slash": "/",
|
||||
"Hash": "#",
|
||||
"Return": "Enter",
|
||||
// "Shift": "",
|
||||
},
|
||||
!!Config.options.cheatsheet.superKey ? {
|
||||
"Super": Config.options.cheatsheet.superKey,
|
||||
}: {},
|
||||
Config.options.cheatsheet.useMacSymbol ? macSymbolMap : {},
|
||||
Config.options.cheatsheet.useFnSymbol ? functionSymbolMap : {},
|
||||
Config.options.cheatsheet.useMouseSymbol ? mouseSymbolMap : {},
|
||||
)
|
||||
|
||||
function modMaskToStringList(modMask: int): list<string> {
|
||||
var list = [];
|
||||
// Funny mathematical order but we wanna have this natural user-facing order
|
||||
if (modMask & (1 << 2)) { list.push("Ctrl"); }
|
||||
if (modMask & (1 << 6)) { list.push("Super"); }
|
||||
if (modMask & (1 << 0)) { list.push("Shift"); }
|
||||
if (modMask & (1 << 3)) { list.push("Alt"); }
|
||||
if (modMask & (1 << 1)) { list.push("Caps"); }
|
||||
if (modMask & (1 << 4)) { list.push("Mod2"); }
|
||||
if (modMask & (1 << 5)) { list.push("Mod3"); }
|
||||
if (modMask & (1 << 7)) { list.push("Mod5"); }
|
||||
return list;
|
||||
}
|
||||
|
||||
spacing: titleSpacing
|
||||
|
||||
StyledText {
|
||||
text: root.isCategorized ? root.categoryName : "Uncategorized"
|
||||
font.pixelSize: Appearance.font.pixelSize.title
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 4
|
||||
Repeater {
|
||||
model: {
|
||||
if (!root.isCategorized) {
|
||||
return HyprlandKeybinds.keybinds.filter(bind => bind.description?.length > 0 && bind.description.indexOf(":") === -1);
|
||||
}
|
||||
return HyprlandKeybinds.keybinds.filter(bind => bind.description?.length > 0 && bind.description.substring(0, bind.description.indexOf(":")) === root.categoryName);
|
||||
}
|
||||
delegate: BindLine {
|
||||
required property var modelData
|
||||
keyData: modelData
|
||||
categoryName: root.categoryName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component BindLine: Row {
|
||||
id: bindLine
|
||||
required property var keyData
|
||||
property string categoryName: ""
|
||||
|
||||
Row {
|
||||
spacing: 16
|
||||
Row {
|
||||
id: modRow
|
||||
Component.onCompleted: root.maxBindWidth = Math.max(root.maxBindWidth, implicitWidth)
|
||||
width: root.maxBindWidth
|
||||
spacing: 4
|
||||
Repeater {
|
||||
model: {
|
||||
const modList = root.modMaskToStringList(bindLine.keyData.modmask).map(mod => root.keySubstitutions[mod] || mod)
|
||||
if (modList.length == 0) return []
|
||||
if (Config.options.cheatsheet.splitButtons) return modList;
|
||||
return [modList.join(" ")]
|
||||
}
|
||||
delegate: KeyboardKey {
|
||||
required property var modelData
|
||||
key: modelData
|
||||
pixelSize: Config.options.cheatsheet.fontSize.key
|
||||
}
|
||||
}
|
||||
StyledText {
|
||||
id: keybindPlus
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !keyBlacklist.includes(bindLine.keyData.key) && bindLine.keyData.modmask > 0
|
||||
text: "+"
|
||||
}
|
||||
KeyboardKey {
|
||||
id: keybindKey
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !keyBlacklist.includes(bindLine.keyData.key)
|
||||
key: StringUtils.toTitleCase(root.keySubstitutions[bindLine.keyData.key] || bindLine.keyData.key)
|
||||
pixelSize: Config.options.cheatsheet.fontSize.key
|
||||
color: Appearance.colors.colOnLayer0
|
||||
}
|
||||
}
|
||||
Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
implicitWidth: commentText.implicitWidth + root.columnSpacing
|
||||
implicitHeight: commentText.implicitHeight
|
||||
StyledText {
|
||||
id: commentText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
font.pixelSize: Config.options.cheatsheet.fontSize.comment || Appearance.font.pixelSize.smaller
|
||||
text: {
|
||||
const regex = new RegExp("\\s*" + bindLine.categoryName + "\\s*:\\s*");
|
||||
return bindLine.keyData.description.replace(regex, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import Quickshell.Hyprland
|
||||
Singleton {
|
||||
id: root
|
||||
property var keybinds: []
|
||||
property var keybindCategories: []
|
||||
|
||||
Connections {
|
||||
target: Hyprland
|
||||
@@ -35,6 +36,15 @@ Singleton {
|
||||
onStreamFinished: {
|
||||
try {
|
||||
root.keybinds = JSON.parse(text)
|
||||
var groups = []
|
||||
for (var i = 0; i < root.keybinds.length; i++) {
|
||||
var bind = root.keybinds[i].description
|
||||
var group = bind.substring(0, bind.indexOf(":"))
|
||||
if (!groups.includes(group) && group.length > 0) {
|
||||
groups.push(group)
|
||||
}
|
||||
}
|
||||
root.keybindCategories = groups
|
||||
} catch (e) {
|
||||
console.error("[CheatsheetKeybinds] Error parsing keybinds:", e)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user