1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-03 20:32:07 -04:00

Continue frame implementation

This commit is contained in:
purian23
2026-03-23 21:24:03 -04:00
parent 952ab9b753
commit e57ab3e1f3
11 changed files with 221 additions and 60 deletions

View File

@@ -14,7 +14,7 @@ import "settings/SettingsStore.js" as Store
Singleton { Singleton {
id: root id: root
readonly property int settingsConfigVersion: 7 readonly property int settingsConfigVersion: 9
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true" readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
@@ -205,7 +205,7 @@ Singleton {
onFrameThicknessChanged: saveSettings() onFrameThicknessChanged: saveSettings()
property real frameRounding: 24 property real frameRounding: 24
onFrameRoundingChanged: saveSettings() onFrameRoundingChanged: saveSettings()
property string frameColor: "#2a2a2a" property string frameColor: ""
onFrameColorChanged: saveSettings() onFrameColorChanged: saveSettings()
property real frameOpacity: 1.0 property real frameOpacity: 1.0
onFrameOpacityChanged: saveSettings() onFrameOpacityChanged: saveSettings()
@@ -213,6 +213,18 @@ Singleton {
onFrameSyncBarColorChanged: saveSettings() onFrameSyncBarColorChanged: saveSettings()
property var frameScreenPreferences: ["all"] property var frameScreenPreferences: ["all"]
onFrameScreenPreferencesChanged: saveSettings() onFrameScreenPreferencesChanged: saveSettings()
property real frameBarThickness: 48
onFrameBarThicknessChanged: saveSettings()
property bool frameShowOnOverview: false
onFrameShowOnOverviewChanged: saveSettings()
readonly property color effectiveFrameColor: {
const fc = frameColor;
if (!fc || fc === "default") return Theme.background;
if (fc === "primary") return Theme.primary;
if (fc === "surface") return Theme.surface;
return fc;
}
property bool showLauncherButton: true property bool showLauncherButton: true
property bool showWorkspaceSwitcher: true property bool showWorkspaceSwitcher: true
@@ -1979,7 +1991,26 @@ Singleton {
return ""; return "";
} }
function getActiveBarEdgesForScreen(screen) {
if (!screen) return [];
var edges = [];
for (var i = 0; i < barConfigs.length; i++) {
var bc = barConfigs[i];
if (!bc.enabled) continue;
var prefs = bc.screenPreferences || ["all"];
if (!prefs.includes("all") && !isScreenInPreferences(screen, prefs)) continue;
switch (bc.position ?? 0) {
case SettingsData.Position.Top: edges.push("top"); break;
case SettingsData.Position.Bottom: edges.push("bottom"); break;
case SettingsData.Position.Left: edges.push("left"); break;
case SettingsData.Position.Right: edges.push("right"); break;
}
}
return edges;
}
function getActiveBarThicknessForScreen(screen) { function getActiveBarThicknessForScreen(screen) {
if (frameEnabled) return frameBarThickness;
if (!screen) return frameThickness; if (!screen) return frameThickness;
for (var i = 0; i < barConfigs.length; i++) { for (var i = 0; i < barConfigs.length; i++) {
var bc = barConfigs[i]; var bc = barConfigs[i];

View File

@@ -552,10 +552,12 @@ var SPEC = {
frameEnabled: { def: false }, frameEnabled: { def: false },
frameThickness: { def: 15 }, frameThickness: { def: 15 },
frameRounding: { def: 24 }, frameRounding: { def: 24 },
frameColor: { def: "#2a2a2a" }, frameColor: { def: "" },
frameOpacity: { def: 1.0 }, frameOpacity: { def: 1.0 },
frameSyncBarColor: { def: true }, frameSyncBarColor: { def: true },
frameScreenPreferences: { def: ["all"] } frameScreenPreferences: { def: ["all"] },
frameBarThickness: { def: 42 },
frameShowOnOverview: { def: false }
}; };
function getValidKeys() { function getValidKeys() {

View File

@@ -262,6 +262,22 @@ function migrateToVersion(obj, targetVersion) {
settings.configVersion = 7; settings.configVersion = 7;
} }
if (currentVersion < 8) {
console.info("Migrating settings from version", currentVersion, "to version 8");
if (settings.frameBarThickness === undefined) settings.frameBarThickness = 48;
settings.configVersion = 8;
}
if (currentVersion < 9) {
console.info("Migrating settings from version", currentVersion, "to version 9");
if (settings.frameShowOnOverview === undefined) settings.frameShowOnOverview = false;
settings.configVersion = 9;
}
return settings; return settings;
} }

View File

@@ -177,6 +177,8 @@ Item {
} }
} }
Frame {}
Repeater { Repeater {
id: dankBarRepeater id: dankBarRepeater
model: ScriptModel { model: ScriptModel {
@@ -208,8 +210,6 @@ Item {
} }
} }
Frame {}
property bool dockEnabled: false property bool dockEnabled: false
Timer { Timer {

View File

@@ -38,7 +38,7 @@ Item {
property real rt: { property real rt: {
if (SettingsData.frameEnabled) if (SettingsData.frameEnabled)
return Math.max(0, SettingsData.frameRounding - SettingsData.frameThickness); return 0;
if (barConfig?.squareCorners ?? false) if (barConfig?.squareCorners ?? false)
return 0; return 0;
if (barWindow.hasMaximizedToplevel) if (barWindow.hasMaximizedToplevel)

View File

@@ -239,7 +239,7 @@ PanelWindow {
readonly property string _barId: barConfig?.id ?? "default" readonly property string _barId: barConfig?.id ?? "default"
property real _backgroundAlpha: barConfig?.transparency ?? 1.0 property real _backgroundAlpha: barConfig?.transparency ?? 1.0
readonly property color _bgColor: (SettingsData.frameEnabled && SettingsData.frameSyncBarColor) readonly property color _bgColor: (SettingsData.frameEnabled && SettingsData.frameSyncBarColor)
? SettingsData.frameColor ? Qt.rgba(SettingsData.effectiveFrameColor.r, SettingsData.effectiveFrameColor.g, SettingsData.effectiveFrameColor.b, SettingsData.frameOpacity)
: Theme.withAlpha(_surfaceContainer, _backgroundAlpha) : Theme.withAlpha(_surfaceContainer, _backgroundAlpha)
function _updateBackgroundAlpha() { function _updateBackgroundAlpha() {
@@ -397,7 +397,12 @@ PanelWindow {
} }
readonly property int notificationCount: NotificationService.notifications.length readonly property int notificationCount: NotificationService.notifications.length
readonly property real effectiveBarThickness: Theme.snap(Math.max(barWindow.widgetThickness + (barConfig?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))), _dpr) readonly property real effectiveBarThickness: SettingsData.frameEnabled
? SettingsData.frameBarThickness
: Theme.snap(Math.max(barWindow.widgetThickness + (barConfig?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))), _dpr)
readonly property bool effectiveOpenOnOverview: SettingsData.frameEnabled
? SettingsData.frameShowOnOverview
: (barConfig?.openOnOverview ?? false)
readonly property real widgetThickness: Theme.snap(Math.max(20, 26 + (barConfig?.innerPadding ?? 4) * 0.6), _dpr) readonly property real widgetThickness: Theme.snap(Math.max(20, 26 + (barConfig?.innerPadding ?? 4) * 0.6), _dpr)
readonly property bool hasAdjacentTopBar: { readonly property bool hasAdjacentTopBar: {
@@ -653,7 +658,7 @@ PanelWindow {
readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + barWindow.effectiveSpacing, barWindow._dpr) readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + barWindow.effectiveSpacing, barWindow._dpr)
readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false) readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && barWindow.effectiveOpenOnOverview
readonly property bool effectiveVisible: (barConfig?.visible ?? true) || inOverviewWithShow readonly property bool effectiveVisible: (barConfig?.visible ?? true) || inOverviewWithShow
readonly property bool showing: effectiveVisible && (topBarCore.reveal || inOverviewWithShow || !topBarCore.autoHide) readonly property bool showing: effectiveVisible && (topBarCore.reveal || inOverviewWithShow || !topBarCore.autoHide)
@@ -794,7 +799,7 @@ PanelWindow {
} }
property bool reveal: { property bool reveal: {
const inOverviewWithShow = CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false); const inOverviewWithShow = CompositorService.isNiri && NiriService.inOverview && barWindow.effectiveOpenOnOverview;
if (inOverviewWithShow) if (inOverviewWithShow)
return true; return true;
@@ -891,7 +896,7 @@ PanelWindow {
top: barWindow.isVertical ? parent.top : undefined top: barWindow.isVertical ? parent.top : undefined
bottom: barWindow.isVertical ? parent.bottom : undefined bottom: barWindow.isVertical ? parent.bottom : undefined
} }
readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && (barConfig?.openOnOverview ?? false) readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && barWindow.effectiveOpenOnOverview
hoverEnabled: (barConfig?.autoHide ?? false) && !inOverview && !topBarCore.hasActivePopout hoverEnabled: (barConfig?.autoHide ?? false) && !inOverview && !topBarCore.hasActivePopout
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
enabled: (barConfig?.autoHide ?? false) && !inOverview enabled: (barConfig?.autoHide ?? false) && !inOverview

View File

@@ -7,19 +7,19 @@ import qs.Common
Item { Item {
id: root id: root
required property string barEdge // "top" | "bottom" | "left" | "right" | "" required property var barEdges // array of "top" | "bottom" | "left" | "right"
required property real barThickness
anchors.fill: parent anchors.fill: parent
readonly property real _thickness: SettingsData.frameThickness readonly property real _thickness: SettingsData.frameThickness
readonly property real _rounding: SettingsData.frameRounding readonly property real _barThickness: SettingsData.frameBarThickness
readonly property real _rounding: SettingsData.frameRounding
Rectangle { Rectangle {
id: borderRect id: borderRect
anchors.fill: parent anchors.fill: parent
color: SettingsData.frameColor color: SettingsData.effectiveFrameColor
opacity: SettingsData.frameOpacity opacity: SettingsData.frameOpacity
layer.enabled: true layer.enabled: true
@@ -42,10 +42,10 @@ Item {
Rectangle { Rectangle {
anchors { anchors {
fill: parent fill: parent
topMargin: root.barEdge === "top" ? root.barThickness : root._thickness topMargin: root.barEdges.includes("top") ? root._barThickness : root._thickness
bottomMargin: root.barEdge === "bottom" ? root.barThickness : root._thickness bottomMargin: root.barEdges.includes("bottom") ? root._barThickness : root._thickness
leftMargin: root.barEdge === "left" ? root.barThickness : root._thickness leftMargin: root.barEdges.includes("left") ? root._barThickness : root._thickness
rightMargin: root.barEdge === "right" ? root.barThickness : root._thickness rightMargin: root.barEdges.includes("right") ? root._barThickness : root._thickness
} }
radius: root._rounding radius: root._rounding
} }

View File

@@ -10,48 +10,51 @@ Scope {
required property ShellScreen screen required property ShellScreen screen
readonly property string barEdge: SettingsData.getActiveBarEdgeForScreen(screen) readonly property var barEdges: {
SettingsData.barConfigs; // force re-eval when bar configs change
return SettingsData.getActiveBarEdgesForScreen(screen);
}
// One thin invisible PanelWindow per edge. // One thin invisible PanelWindow per edge.
// Skips the edge where the bar already provides its own exclusiveZone. // Skips any edge where a bar already provides its own exclusiveZone.
Loader { Loader {
active: root.barEdge !== "top" active: !root.barEdges.includes("top")
sourceComponent: EdgeExclusion {
screen: root.screen
anchorTop: true
anchorLeft: true
anchorRight: true
}
}
Loader {
active: root.barEdge !== "bottom"
sourceComponent: EdgeExclusion {
screen: root.screen
anchorBottom: true
anchorLeft: true
anchorRight: true
}
}
Loader {
active: root.barEdge !== "left"
sourceComponent: EdgeExclusion { sourceComponent: EdgeExclusion {
screen: root.screen screen: root.screen
anchorLeft: true anchorTop: true
anchorTop: true anchorLeft: true
anchorBottom: true anchorRight: true
} }
} }
Loader { Loader {
active: root.barEdge !== "right" active: !root.barEdges.includes("bottom")
sourceComponent: EdgeExclusion { sourceComponent: EdgeExclusion {
screen: root.screen screen: root.screen
anchorRight: true anchorBottom: true
anchorTop: true anchorLeft: true
anchorBottom: true anchorRight: true
}
}
Loader {
active: !root.barEdges.includes("left")
sourceComponent: EdgeExclusion {
screen: root.screen
anchorLeft: true
anchorTop: true
anchorBottom: true
}
}
Loader {
active: !root.barEdges.includes("right")
sourceComponent: EdgeExclusion {
screen: root.screen
anchorRight: true
anchorTop: true
anchorBottom: true
} }
} }

View File

@@ -11,7 +11,7 @@ PanelWindow {
required property ShellScreen screen required property ShellScreen screen
WlrLayershell.namespace: "dms:frame" WlrLayershell.namespace: "dms:frame"
WlrLayershell.layer: WlrLayer.Bottom WlrLayershell.layer: WlrLayer.Top
WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.exclusionMode: ExclusionMode.Ignore
anchors { anchors {
@@ -28,7 +28,9 @@ PanelWindow {
FrameBorder { FrameBorder {
anchors.fill: parent anchors.fill: parent
barEdge: SettingsData.getActiveBarEdgeForScreen(win.screen) barEdges: {
barThickness: SettingsData.getActiveBarThicknessForScreen(win.screen) SettingsData.barConfigs; // force re-eval when bar configs change
return SettingsData.getActiveBarEdgesForScreen(win.screen);
}
} }
} }

View File

@@ -693,6 +693,8 @@ Item {
SettingsToggleRow { SettingsToggleRow {
visible: CompositorService.isNiri visible: CompositorService.isNiri
enabled: !SettingsData.frameEnabled
opacity: SettingsData.frameEnabled ? 0.5 : 1.0
text: I18n.tr("Show on Overview") text: I18n.tr("Show on Overview")
checked: selectedBarConfig?.openOnOverview ?? false checked: selectedBarConfig?.openOnOverview ?? false
onToggled: toggled => { onToggled: toggled => {
@@ -798,11 +800,42 @@ Item {
} }
} }
Item {
visible: SettingsData.frameEnabled
width: parent.width
implicitHeight: frameNote.implicitHeight + Theme.spacingS * 2
Row {
id: frameNote
x: Theme.spacingM
width: parent.width - Theme.spacingM * 2
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "frame_source"
size: Theme.fontSizeMedium
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Spacing and size are managed by Frame mode")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width - Theme.fontSizeMedium - Theme.spacingS
}
}
}
SettingsCard { SettingsCard {
iconName: "space_bar" iconName: "space_bar"
title: I18n.tr("Spacing") title: I18n.tr("Spacing")
settingKey: "barSpacing" settingKey: "barSpacing"
visible: selectedBarConfig?.enabled visible: selectedBarConfig?.enabled
enabled: !SettingsData.frameEnabled
opacity: SettingsData.frameEnabled ? 0.5 : 1.0
SettingsSliderRow { SettingsSliderRow {
id: edgeSpacingSlider id: edgeSpacingSlider
@@ -1287,6 +1320,8 @@ Item {
SettingsToggleRow { SettingsToggleRow {
text: I18n.tr("Square Corners") text: I18n.tr("Square Corners")
enabled: !SettingsData.frameEnabled
opacity: SettingsData.frameEnabled ? 0.5 : 1.0
checked: selectedBarConfig?.squareCorners ?? false checked: selectedBarConfig?.squareCorners ?? false
onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
squareCorners: checked squareCorners: checked
@@ -1295,6 +1330,8 @@ Item {
SettingsToggleRow { SettingsToggleRow {
text: I18n.tr("No Background") text: I18n.tr("No Background")
enabled: !SettingsData.frameEnabled
opacity: SettingsData.frameEnabled ? 0.5 : 1.0
checked: selectedBarConfig?.noBackground ?? false checked: selectedBarConfig?.noBackground ?? false
onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
noBackground: checked noBackground: checked
@@ -1334,6 +1371,8 @@ Item {
SettingsToggleRow { SettingsToggleRow {
text: I18n.tr("Goth Corners") text: I18n.tr("Goth Corners")
enabled: !SettingsData.frameEnabled
opacity: SettingsData.frameEnabled ? 0.5 : 1.0
checked: selectedBarConfig?.gothCornersEnabled ?? false checked: selectedBarConfig?.gothCornersEnabled ?? false
onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
gothCornersEnabled: checked gothCornersEnabled: checked

View File

@@ -91,6 +91,27 @@ Item {
} }
} }
SettingsSliderRow {
id: barThicknessSlider
settingKey: "frameBarThickness"
tags: ["frame", "bar", "thickness", "size", "height", "width"]
text: I18n.tr("Bar-edge thickness")
description: I18n.tr("Height of horizontal bars / width of vertical bars in frame mode")
unit: "px"
minimum: 24
maximum: 100
step: 1
defaultValue: 48
value: SettingsData.frameBarThickness
onSliderDragFinished: v => SettingsData.set("frameBarThickness", v)
Binding {
target: barThicknessSlider
property: "value"
value: SettingsData.frameBarThickness
}
}
SettingsSliderRow { SettingsSliderRow {
id: opacitySlider id: opacitySlider
settingKey: "frameOpacity" settingKey: "frameOpacity"
@@ -110,13 +131,45 @@ Item {
} }
} }
// Color row // Color mode buttons
SettingsButtonGroupRow {
settingKey: "frameColor"
tags: ["frame", "border", "color", "theme", "primary", "surface", "default"]
text: I18n.tr("Border color")
model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")]
currentIndex: {
const fc = SettingsData.frameColor;
if (!fc || fc === "default") return 0;
if (fc === "primary") return 1;
if (fc === "surface") return 2;
return 3;
}
onSelectionChanged: (index, selected) => {
if (!selected) return;
switch (index) {
case 0: SettingsData.set("frameColor", ""); break;
case 1: SettingsData.set("frameColor", "primary"); break;
case 2: SettingsData.set("frameColor", "surface"); break;
case 3:
const cur = SettingsData.frameColor;
const isPreset = !cur || cur === "primary" || cur === "surface";
if (isPreset) SettingsData.set("frameColor", "#2a2a2a");
break;
}
}
}
// Custom color swatch — only visible when a hex color is stored (Custom mode)
Item { Item {
visible: {
const fc = SettingsData.frameColor;
return !!(fc && fc !== "primary" && fc !== "surface");
}
width: parent.width width: parent.width
height: colorRow.height + Theme.spacingM * 2 height: customColorRow.height + Theme.spacingM * 2
Row { Row {
id: colorRow id: customColorRow
width: parent.width - Theme.spacingM * 2 width: parent.width - Theme.spacingM * 2
x: Theme.spacingM x: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@@ -124,7 +177,7 @@ Item {
StyledText { StyledText {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: I18n.tr("Border color") text: I18n.tr("Custom color")
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
@@ -136,7 +189,7 @@ Item {
width: 32 width: 32
height: 32 height: 32
radius: 16 radius: 16
color: SettingsData.frameColor color: SettingsData.effectiveFrameColor
border.color: Theme.outline border.color: Theme.outline
border.width: 1 border.width: 1
@@ -144,7 +197,7 @@ Item {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
PopoutService.colorPickerModal.selectedColor = SettingsData.frameColor; PopoutService.colorPickerModal.selectedColor = SettingsData.effectiveFrameColor;
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Frame Border Color"); PopoutService.colorPickerModal.pickerTitle = I18n.tr("Frame Border Color");
PopoutService.colorPickerModal.onColorSelectedCallback = function (color) { PopoutService.colorPickerModal.onColorSelectedCallback = function (color) {
SettingsData.set("frameColor", color.toString()); SettingsData.set("frameColor", color.toString());
@@ -174,6 +227,16 @@ Item {
checked: SettingsData.frameSyncBarColor checked: SettingsData.frameSyncBarColor
onToggled: checked => SettingsData.set("frameSyncBarColor", checked) onToggled: checked => SettingsData.set("frameSyncBarColor", checked)
} }
SettingsToggleRow {
visible: CompositorService.isNiri
settingKey: "frameShowOnOverview"
tags: ["frame", "overview", "show", "hide", "niri"]
text: I18n.tr("Show on Overview")
description: I18n.tr("Show the bar and frame during Niri overview mode")
checked: SettingsData.frameShowOnOverview
onToggled: checked => SettingsData.set("frameShowOnOverview", checked)
}
} }
// ── Display Assignment ──────────────────────────────────────────── // ── Display Assignment ────────────────────────────────────────────