1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-27 15:02:50 -05:00

feat: Dock overflow & New setting options

This commit is contained in:
purian23
2026-01-26 15:25:45 -05:00
parent 2263338878
commit 14a3a0ae55
9 changed files with 864 additions and 313 deletions

View File

@@ -443,6 +443,9 @@ Singleton {
property int dockLauncherLogoSizeOffset: 0
property real dockLauncherLogoBrightness: 0.5
property real dockLauncherLogoContrast: 1
property int dockMaxVisibleApps: 10
property int dockMaxVisibleRunningApps: 10
property bool dockShowOverflowBadge: true
property bool notificationOverlayEnabled: false
property int overviewRows: 2

View File

@@ -272,6 +272,9 @@ var SPEC = {
dockLauncherLogoSizeOffset: { def: 0 },
dockLauncherLogoBrightness: { def: 0.5, coerce: percentToUnit },
dockLauncherLogoContrast: { def: 1, coerce: percentToUnit },
dockMaxVisibleApps: { def: 10 },
dockMaxVisibleRunningApps: { def: 10 },
dockShowOverflowBadge: { def: true },
notificationOverlayEnabled: { def: false },
overviewRows: { def: 2, persist: false },

View File

@@ -533,7 +533,6 @@ Variants {
anchors {
top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top ? parent.top : undefined) : undefined
bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined) : undefined
horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined
left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Left ? parent.left : undefined) : undefined
right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined
verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
@@ -543,11 +542,23 @@ Variants {
anchors.leftMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0
anchors.rightMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0
readonly property real baseImplicitWidth: dock.isVertical ? (dockApps.baseImplicitHeight + SettingsData.dockSpacing * 2) : (dockApps.baseImplicitWidth + SettingsData.dockSpacing * 2)
readonly property real baseImplicitHeight: dock.isVertical ? (dockApps.baseImplicitWidth + SettingsData.dockSpacing * 2) : (dockApps.baseImplicitHeight + SettingsData.dockSpacing * 2)
implicitWidth: dock.isVertical ? (dockApps.implicitHeight + SettingsData.dockSpacing * 2) : (dockApps.implicitWidth + SettingsData.dockSpacing * 2)
implicitHeight: dock.isVertical ? (dockApps.implicitWidth + SettingsData.dockSpacing * 2) : (dockApps.implicitHeight + SettingsData.dockSpacing * 2)
width: implicitWidth
height: implicitHeight
x: {
if (dock.isVertical)
return 0;
const targetWidth = (dockApps.overflowExpanded) ? implicitWidth : baseImplicitWidth;
const centered = (parent.width - targetWidth) / 2;
return Math.max(0, centered);
}
layer.enabled: true
clip: false
@@ -625,13 +636,12 @@ Variants {
anchors.top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top ? dockBackground.top : undefined) : undefined
anchors.bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? dockBackground.bottom : undefined) : undefined
anchors.horizontalCenter: !dock.isVertical ? dockBackground.horizontalCenter : undefined
anchors.left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Left ? dockBackground.left : undefined) : undefined
anchors.left: !dock.isVertical ? dockBackground.left : (SettingsData.dockPosition === SettingsData.Position.Left ? dockBackground.left : undefined)
anchors.right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? dockBackground.right : undefined) : undefined
anchors.verticalCenter: dock.isVertical ? dockBackground.verticalCenter : undefined
anchors.topMargin: !dock.isVertical ? SettingsData.dockSpacing : 0
anchors.bottomMargin: !dock.isVertical ? SettingsData.dockSpacing : 0
anchors.leftMargin: dock.isVertical ? SettingsData.dockSpacing : 0
anchors.leftMargin: SettingsData.dockSpacing
anchors.rightMargin: dock.isVertical ? SettingsData.dockSpacing : 0
contextMenu: dockVariants.contextMenu
@@ -639,6 +649,27 @@ Variants {
isVertical: dock.isVertical
dockScreen: dock.screen
iconSize: dock.widgetHeight
maxAvailableLength: {
const border = (SettingsData.dockBorderEnabled ? dock.borderThickness * 2 : 0);
const internalPadding = SettingsData.dockSpacing * 2;
if (dock.isVertical) {
// Calculate vertical space available for apps
const maxH = dockMouseArea.maxDockHeight;
const vMargins = (dockBackground.anchors.topMargin || 0) + (dockBackground.anchors.bottomMargin || 0);
const result = maxH - vMargins - internalPadding - border;
console.warn("Dock: maxAvailableLength (V):", result, "= maxH:", maxH, "- margins:", vMargins, "- padding:", internalPadding, "- border:", border);
return Math.max(0, result); // Ensure non-negative
} else {
// Calculate horizontal space available for apps
const maxW = dockMouseArea.maxDockWidth;
const hMargins = (dockBackground.anchors.leftMargin || 0) + (dockBackground.anchors.rightMargin || 0);
const result = maxW - hMargins - internalPadding - border;
console.warn("Dock: maxAvailableLength (H):", result, "= maxW:", maxW, "- margins:", hMargins, "- padding:", internalPadding, "- border:", border);
return Math.max(0, result); // Ensure non-negative
}
}
}
}
}

View File

@@ -29,6 +29,15 @@ Item {
property bool showTooltip: mouseArea.containsMouse && !dragging
property var cachedDesktopEntry: null
property real actualIconSize: 40
property bool shouldShowIndicator: {
if (!appData)
return false;
if (appData.type === "window")
return true;
if (appData.type === "grouped")
return appData.windowCount > 0;
return appData.isRunning;
}
readonly property string coreIconColorOverride: SettingsData.dockLauncherLogoColorOverride
readonly property bool coreIconHasCustomColor: coreIconColorOverride !== "" && coreIconColorOverride !== "primary" && coreIconColorOverride !== "surface"
readonly property color effectiveCoreIconColor: {
@@ -206,9 +215,20 @@ Item {
anchors.fill: parent
hoverEnabled: true
enabled: true
preventStealing: true
// Prevent stealing during drag operations
// Also prevent stealing when NOT in scroll mode (original behavior)
// Only allow Flickable to steal when scrollable AND not dragging
preventStealing: dragging || longPressing || !(dockApps && dockApps.canScroll)
cursorShape: longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
onWheel: (wheel) => {
// Only handle wheel if we're NOT in scrollable mode
if (dockApps && dockApps.canScroll) {
wheel.accepted = false // Allow event to propagate to Flickable
} else {
wheel.accepted = true // Consume event (no scrolling needed)
}
}
onPressed: mouse => {
if (mouse.button === Qt.LeftButton && appData && appData.isPinned) {
dragStartPos = Qt.point(mouse.x, mouse.y);
@@ -221,8 +241,14 @@ Item {
const wasDragging = dragging;
const didReorder = wasDragging && targetIndex >= 0 && targetIndex !== originalIndex && dockApps;
if (didReorder)
console.warn("DockAppButton onReleased:", appData?.appId || "unknown");
console.warn(" wasDragging:", wasDragging, "originalIndex:", originalIndex, "targetIndex:", targetIndex);
console.warn(" didReorder:", didReorder);
if (didReorder) {
// Use movePinnedApp which takes dock indices (original behavior)
dockApps.movePinnedApp(originalIndex, targetIndex);
}
longPressing = false;
dragging = false;
@@ -295,7 +321,7 @@ Item {
groupedToplevel.activate();
} else if (contextMenu) {
const shouldHidePin = appData.appId === "org.quickshell";
contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen);
contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps);
}
break;
}
@@ -305,6 +331,7 @@ Item {
const distance = Math.sqrt(Math.pow(mouse.x - dragStartPos.x, 2) + Math.pow(mouse.y - dragStartPos.y, 2));
if (distance > 5) {
dragging = true;
// Use dock index directly (original behavior)
targetIndex = index;
originalIndex = index;
if (dockApps) {
@@ -323,6 +350,7 @@ Item {
const spacing = Math.min(8, Math.max(4, actualIconSize * 0.08));
const itemSize = actualIconSize * 1.2 + spacing;
const slotOffset = Math.round(axisOffset / itemSize);
// Use pinnedAppCount as max (original behavior)
const newTargetIndex = Math.max(0, Math.min(dockApps.pinnedAppCount - 1, originalIndex + slotOffset));
if (newTargetIndex !== targetIndex) {
@@ -342,7 +370,7 @@ Item {
case "grouped":
if (contextMenu) {
const shouldHidePin = appData.appId === "org.quickshell";
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen);
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps);
}
break;
default:
@@ -365,7 +393,7 @@ Item {
if (!contextMenu)
return;
const shouldHidePin = appData.appId === "org.quickshell";
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen);
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen, dockApps);
}
}
}
@@ -498,15 +526,7 @@ Item {
sourceComponent: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? columnIndicator : rowIndicator
visible: {
if (!appData)
return false;
if (appData.type === "window")
return true;
if (appData.type === "grouped")
return appData.windowCount > 0;
return appData.isRunning;
}
visible: root.shouldShowIndicator
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,8 +19,9 @@ PanelWindow {
property bool hidePin: false
property var desktopEntry: null
property bool isDmsWindow: appData?.appId === "org.quickshell"
property var dockApps: null
function showForButton(button, data, dockHeight, hidePinOption, entry, dockScreen) {
function showForButton(button, data, dockHeight, hidePinOption, entry, dockScreen, parentDockApps) {
if (dockScreen) {
root.screen = dockScreen
}
@@ -30,6 +31,7 @@ PanelWindow {
dockVisibleHeight = dockHeight || 40
hidePin = hidePinOption || false
desktopEntry = entry || null
dockApps = parentDockApps || null
visible = true
}
@@ -397,6 +399,16 @@ PanelWindow {
SessionData.removePinnedApp(root.appData.appId)
} else {
SessionData.addPinnedApp(root.appData.appId)
// Auto-expand overflow if pinning would exceed limit
if (root.dockApps) {
Qt.callLater(() => {
const newPinnedCount = SessionData.pinnedApps.length;
if (newPinnedCount > root.dockApps.maxVisibleApps && root.dockApps.overflowItemCount > 0) {
root.dockApps.overflowExpanded = true;
}
});
}
}
root.close()
}

View File

@@ -115,9 +115,20 @@ Item {
anchors.fill: parent
hoverEnabled: true
enabled: true
preventStealing: true
// Prevent stealing during drag operations
// Also prevent stealing when NOT in scroll mode (original behavior)
// Only allow Flickable to steal when scrollable AND not dragging
preventStealing: dragging || longPressing || !(dockApps && dockApps.canScroll)
cursorShape: longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton
onWheel: (wheel) => {
// Only handle wheel if we're NOT in scrollable mode
if (dockApps && dockApps.canScroll) {
wheel.accepted = false // Allow event to propagate to Flickable
} else {
wheel.accepted = true // Consume event (no scrolling needed)
}
}
onPressed: mouse => {
if (mouse.button === Qt.LeftButton) {
dragStartPos = Qt.point(mouse.x, mouse.y);

View File

@@ -0,0 +1,88 @@
import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
Item {
id: root
property real actualIconSize: 40
property int overflowCount: 0
property bool overflowExpanded: false
property bool isVertical: false
signal clicked()
Rectangle {
id: buttonBackground
anchors.centerIn: parent
width: actualIconSize
height: actualIconSize
radius: Theme.cornerRadius
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, mouseArea.containsMouse ? 0.2 : 0.1)
Behavior on color {
ColorAnimation { duration: Theme.shortDuration }
}
DankIcon {
id: arrowIcon
anchors.centerIn: parent
size: actualIconSize * 0.6
name: "expand_more"
color: Theme.surfaceText
// For horizontal docks, rotate -90° to point right (collapsed), then 90° to point left (expanded)
// For vertical docks, keep default (down arrow = 0°), flip 180° to point up (expanded)
rotation: {
if (isVertical) {
return overflowExpanded ? 180 : 0;
} else {
return overflowExpanded ? 90 : -90;
}
}
Behavior on rotation {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
}
}
}
// Badge showing overflow count (outside main rectangle to avoid clipping)
Rectangle {
visible: overflowCount > 0 && !overflowExpanded && SettingsData.dockShowOverflowBadge
anchors.right: buttonBackground.right
anchors.top: buttonBackground.top
anchors.rightMargin: -4
anchors.topMargin: -4
width: Math.max(18, badgeText.width + 8)
height: 18
radius: 9
color: Theme.primary
z: 10
StyledText {
id: badgeText
anchors.centerIn: parent
text: `+${overflowCount}`
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold
color: Theme.onPrimary
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onWheel: (wheel) => {
// Always allow wheel events to propagate to Flickable for scrolling
wheel.accepted = false
}
onClicked: root.clicked()
}
}

View File

@@ -162,6 +162,39 @@ Item {
}
}
}
SettingsSliderRow {
settingKey: "dockMaxVisibleApps"
tags: ["dock", "overflow", "max", "apps", "limit"]
text: I18n.tr("Max Number of Pinned Apps Before Overflow")
minimum: 3
maximum: 20
value: SettingsData.dockMaxVisibleApps
defaultValue: 10
unit: ""
onSliderValueChanged: newValue => SettingsData.set("dockMaxVisibleApps", newValue)
}
SettingsSliderRow {
settingKey: "dockMaxVisibleRunningApps"
tags: ["dock", "overflow", "max", "running", "apps", "limit"]
text: I18n.tr("Max Open Running Apps Before Overflow")
minimum: 0
maximum: 20
value: SettingsData.dockMaxVisibleRunningApps
defaultValue: 10
unit: ""
onSliderValueChanged: newValue => SettingsData.set("dockMaxVisibleRunningApps", newValue)
}
SettingsToggleRow {
settingKey: "dockShowOverflowBadge"
tags: ["dock", "overflow", "badge", "count", "indicator"]
text: I18n.tr("Show Overflow Badge Count")
description: I18n.tr("Display a badge with the number of apps in overflow")
checked: SettingsData.dockShowOverflowBadge
onToggled: checked => SettingsData.set("dockShowOverflowBadge", checked)
}
}
SettingsCard {