1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

keybinds: add niri provider

This commit is contained in:
bbedward
2025-11-30 19:25:48 -05:00
parent 17639e8729
commit 35e0dc84e8
14 changed files with 1271 additions and 102 deletions

View File

@@ -44,6 +44,7 @@ Item {
property bool keepContentLoaded: false
property bool keepPopoutsOpen: false
property var customKeyboardFocus: null
property bool useOverlayLayer: false
readonly property alias contentWindow: contentWindow
readonly property alias backgroundWindow: backgroundWindow
@@ -148,6 +149,7 @@ Item {
id: backgroundWindow
visible: false
color: "transparent"
screen: root.effectiveScreen
WlrLayershell.namespace: root.layerNamespace + ":background"
WlrLayershell.layer: WlrLayershell.Top
@@ -207,9 +209,12 @@ Item {
id: contentWindow
visible: false
color: "transparent"
screen: root.effectiveScreen
WlrLayershell.namespace: root.layerNamespace
WlrLayershell.layer: {
if (root.useOverlayLayer)
return WlrLayershell.Overlay;
switch (Quickshell.env("DMS_MODAL_LAYER")) {
case "bottom":
console.error("DankModal: 'bottom' layer is not valid for modals. Defaulting to 'top' layer.");

View File

@@ -1,6 +1,5 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import qs.Common
import qs.Modals.Common
import qs.Services
@@ -10,33 +9,52 @@ DankModal {
id: root
layerNamespace: "dms:keybinds"
useOverlayLayer: true
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
modalWidth: _maxW
modalHeight: _maxH
onBackgroundClicked: close()
onOpened: () => Qt.callLater(() => modalFocusScope.forceActiveFocus())
HyprlandFocusGrab {
windows: [root.contentWindow]
active: CompositorService.isHyprland && root.shouldHaveFocus
}
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
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
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() }
modalFocusScope.Keys.onPressed: event => {
if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
scrollDown();
event.accepted = true;
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
scrollUp();
event.accepted = true;
} else if (event.key === Qt.Key_Down) {
scrollDown();
event.accepted = true;
} else if (event.key === Qt.Key_Up) {
scrollUp();
event.accepted = true;
}
}
content: Component {
Item {
@@ -66,25 +84,25 @@ DankModal {
property var rawBinds: KeybindsService.keybinds.binds || {}
property var categories: {
const processed = {}
const processed = {};
for (const cat in rawBinds) {
const binds = rawBinds[cat]
const subcats = {}
let hasSubcats = false
const binds = rawBinds[cat];
const subcats = {};
let hasSubcats = false;
for (let i = 0; i < binds.length; i++) {
const bind = binds[i]
const bind = binds[i];
if (bind.subcat) {
hasSubcats = true
hasSubcats = true;
if (!subcats[bind.subcat]) {
subcats[bind.subcat] = []
subcats[bind.subcat] = [];
}
subcats[bind.subcat].push(bind)
subcats[bind.subcat].push(bind);
} else {
if (!subcats["_root"]) {
subcats["_root"] = []
subcats["_root"] = [];
}
subcats["_root"].push(bind)
subcats["_root"].push(bind);
}
}
@@ -92,21 +110,21 @@ DankModal {
hasSubcats: hasSubcats,
subcats: subcats,
subcatKeys: Object.keys(subcats)
}
};
}
return processed
return processed;
}
property var categoryKeys: Object.keys(categories)
function distributeCategories(cols) {
const columns = []
const columns = [];
for (let i = 0; i < cols; i++) {
columns.push([])
columns.push([]);
}
for (let i = 0; i < categoryKeys.length; i++) {
columns[i % cols].push(categoryKeys[i])
columns[i % cols].push(categoryKeys[i]);
}
return columns
return columns;
}
Row {
@@ -136,92 +154,95 @@ DankModal {
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
}
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
}
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 || []
Item {
width: 1
height: Theme.spacingXS
}
Column {
width: parent.width
spacing: Theme.spacingXS
spacing: Theme.spacingM
property string subcatName: modelData
property var subcatBinds: categoryColumn.catData?.subcats?.[subcatName] || []
Repeater {
model: categoryColumn.catData?.subcatKeys || []
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
Column {
width: parent.width
spacing: Theme.spacingXS
property string subcatName: modelData
property var subcatBinds: categoryColumn.catData?.subcats?.[subcatName] || []
Repeater {
model: parent.parent.subcatBinds
StyledText {
visible: parent.subcatName !== "_root"
text: parent.subcatName
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.DemiBold
color: Theme.primary
opacity: 0.7
}
Row {
Column {
width: parent.width
spacing: Theme.spacingS
spacing: Theme.spacingXS
StyledRect {
width: Math.min(140, parent.width * 0.42)
height: 22
radius: 4
opacity: 0.9
Repeater {
model: parent.parent.subcatBinds
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
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
}
}
}
StyledText {
width: parent.width - 150
text: modelData.desc || ""
font.pixelSize: Theme.fontSizeSmall
opacity: 0.9
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
}
}
}
}
}
}
}
}
}
}
}
}