mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 07:22:50 -05:00
displays: break monolith config down and allow floats/fix integer
writing (niri)
This commit is contained in:
368
quickshell/Modules/Settings/DisplayConfig/NiriOutputSettings.qml
Normal file
368
quickshell/Modules/Settings/DisplayConfig/NiriOutputSettings.qml
Normal file
@@ -0,0 +1,368 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
|
||||
property string outputName: ""
|
||||
property var outputData: null
|
||||
property bool expanded: false
|
||||
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: headerRow.implicitHeight + Theme.spacingS * 2
|
||||
color: headerMouse.containsMouse ? Theme.withAlpha(Theme.primary, 0.1) : "transparent"
|
||||
radius: Theme.cornerRadius / 2
|
||||
|
||||
Row {
|
||||
id: headerRow
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: root.expanded ? "expand_more" : "chevron_right"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Compositor Settings")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: headerMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.expanded = !root.expanded
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
visible: root.expanded
|
||||
topPadding: Theme.spacingS
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Disable Output")
|
||||
checked: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "disabled", false)
|
||||
onToggled: checked => DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "disabled", checked)
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Focus at Startup")
|
||||
checked: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "focusAtStartup", false)
|
||||
onToggled: checked => DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "focusAtStartup", checked)
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width
|
||||
text: I18n.tr("Hot Corners")
|
||||
addHorizontalPadding: true
|
||||
|
||||
property var hotCornersData: {
|
||||
void (DisplayConfigState.pendingNiriChanges);
|
||||
return DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "hotCorners", null);
|
||||
}
|
||||
|
||||
currentValue: {
|
||||
if (!hotCornersData)
|
||||
return I18n.tr("Inherit");
|
||||
if (hotCornersData.off)
|
||||
return I18n.tr("Off");
|
||||
const corners = hotCornersData.corners || [];
|
||||
if (corners.length === 0)
|
||||
return I18n.tr("Inherit");
|
||||
if (corners.length === 4)
|
||||
return I18n.tr("All");
|
||||
return I18n.tr("Select...");
|
||||
}
|
||||
options: [I18n.tr("Inherit"), I18n.tr("Off"), I18n.tr("All"), I18n.tr("Select...")]
|
||||
|
||||
onValueChanged: value => {
|
||||
switch (value) {
|
||||
case I18n.tr("Inherit"):
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", null);
|
||||
break;
|
||||
case I18n.tr("Off"):
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", {
|
||||
"off": true
|
||||
});
|
||||
break;
|
||||
case I18n.tr("All"):
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", {
|
||||
"corners": ["top-left", "top-right", "bottom-left", "bottom-right"]
|
||||
});
|
||||
break;
|
||||
case I18n.tr("Select..."):
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", {
|
||||
"corners": []
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: hotCornersGroup.implicitHeight
|
||||
clip: true
|
||||
|
||||
property var hotCornersData: {
|
||||
void (DisplayConfigState.pendingNiriChanges);
|
||||
return DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "hotCorners", null);
|
||||
}
|
||||
|
||||
visible: hotCornersData && !hotCornersData.off && hotCornersData.corners !== undefined
|
||||
|
||||
DankButtonGroup {
|
||||
id: hotCornersGroup
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
selectionMode: "multi"
|
||||
checkEnabled: false
|
||||
buttonHeight: 32
|
||||
buttonPadding: parent.width < 400 ? Theme.spacingXS : Theme.spacingM
|
||||
minButtonWidth: parent.width < 400 ? 28 : 56
|
||||
textSize: parent.width < 400 ? 11 : Theme.fontSizeMedium
|
||||
model: [I18n.tr("Top Left"), I18n.tr("Top Right"), I18n.tr("Bottom Left"), I18n.tr("Bottom Right")]
|
||||
|
||||
property var cornerKeys: ["top-left", "top-right", "bottom-left", "bottom-right"]
|
||||
|
||||
currentSelection: {
|
||||
const hcData = parent.hotCornersData;
|
||||
if (!hcData?.corners)
|
||||
return [];
|
||||
return hcData.corners.map(key => {
|
||||
const idx = cornerKeys.indexOf(key);
|
||||
return idx >= 0 ? model[idx] : null;
|
||||
}).filter(v => v !== null);
|
||||
}
|
||||
|
||||
onSelectionChanged: (index, selected) => {
|
||||
const corners = currentSelection.map(label => {
|
||||
const idx = model.indexOf(label);
|
||||
return idx >= 0 ? cornerKeys[idx] : null;
|
||||
}).filter(v => v !== null);
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "hotCorners", {
|
||||
"corners": corners
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.withAlpha(Theme.outline, 0.15)
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: layoutColumn.implicitHeight
|
||||
|
||||
Column {
|
||||
id: layoutColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Layout Overrides")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Override global layout settings for this output")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.withAlpha(Theme.surfaceVariantText, 0.7)
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Window Gaps (px)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: parent.width
|
||||
height: 40
|
||||
placeholderText: I18n.tr("Inherit")
|
||||
text: {
|
||||
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null);
|
||||
if (layout?.gaps === undefined)
|
||||
return "";
|
||||
return layout.gaps.toString();
|
||||
}
|
||||
onEditingFinished: {
|
||||
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {};
|
||||
const trimmed = text.trim();
|
||||
if (!trimmed) {
|
||||
delete layout.gaps;
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null);
|
||||
return;
|
||||
}
|
||||
const val = parseInt(trimmed);
|
||||
if (isNaN(val) || val < 0)
|
||||
return;
|
||||
layout.gaps = val;
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Default Width (%)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: parent.width
|
||||
height: 40
|
||||
placeholderText: I18n.tr("Inherit")
|
||||
text: {
|
||||
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null);
|
||||
if (!layout?.defaultColumnWidth)
|
||||
return "";
|
||||
if (layout.defaultColumnWidth.type !== "proportion")
|
||||
return "";
|
||||
const percent = layout.defaultColumnWidth.value * 100;
|
||||
return parseFloat(percent.toFixed(4)).toString();
|
||||
}
|
||||
onEditingFinished: {
|
||||
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {};
|
||||
const trimmed = text.trim().replace("%", "");
|
||||
if (!trimmed) {
|
||||
delete layout.defaultColumnWidth;
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null);
|
||||
return;
|
||||
}
|
||||
const val = parseFloat(trimmed);
|
||||
if (isNaN(val) || val <= 0 || val > 100)
|
||||
return;
|
||||
layout.defaultColumnWidth = {
|
||||
"type": "proportion",
|
||||
"value": parseFloat((val / 100).toFixed(6))
|
||||
};
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Preset Widths (%)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "e.g. 33.33, 50, 66.67"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.withAlpha(Theme.surfaceVariantText, 0.7)
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: parent.width
|
||||
height: 40
|
||||
placeholderText: I18n.tr("Inherit")
|
||||
text: {
|
||||
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null);
|
||||
const presets = layout?.presetColumnWidths || [];
|
||||
if (presets.length === 0)
|
||||
return "";
|
||||
return presets.filter(p => p.type === "proportion").map(p => parseFloat((p.value * 100).toFixed(4))).join(", ");
|
||||
}
|
||||
onEditingFinished: {
|
||||
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {};
|
||||
const trimmed = text.trim();
|
||||
if (!trimmed) {
|
||||
delete layout.presetColumnWidths;
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null);
|
||||
return;
|
||||
}
|
||||
const parts = trimmed.split(/[,\s]+/).filter(s => s);
|
||||
const presets = [];
|
||||
for (const part of parts) {
|
||||
const val = parseFloat(part.replace("%", ""));
|
||||
if (!isNaN(val) && val > 0 && val <= 100)
|
||||
presets.push({
|
||||
"type": "proportion",
|
||||
"value": parseFloat((val / 100).toFixed(6))
|
||||
});
|
||||
}
|
||||
if (presets.length === 0) {
|
||||
delete layout.presetColumnWidths;
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null);
|
||||
return;
|
||||
}
|
||||
presets.sort((a, b) => a.value - b.value);
|
||||
layout.presetColumnWidths = presets;
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Center Single Column")
|
||||
property var layoutData: DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", null)
|
||||
checked: layoutData?.alwaysCenterSingleColumn ?? false
|
||||
onToggled: checked => {
|
||||
const layout = DisplayConfigState.getNiriSetting(root.outputData, root.outputName, "layout", {}) || {};
|
||||
if (checked) {
|
||||
layout.alwaysCenterSingleColumn = true;
|
||||
} else {
|
||||
delete layout.alwaysCenterSingleColumn;
|
||||
}
|
||||
DisplayConfigState.setNiriSetting(root.outputData, root.outputName, "layout", Object.keys(layout).length > 0 ? layout : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user