1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-05 21:15:38 -05:00

dock: add border option

fixes #829
This commit is contained in:
bbedward
2025-12-01 10:53:15 -05:00
parent c6e9abda9f
commit cfc07f4411
4 changed files with 647 additions and 354 deletions

View File

@@ -275,6 +275,10 @@ Singleton {
property real dockMargin: 0 property real dockMargin: 0
property real dockIconSize: 40 property real dockIconSize: 40
property string dockIndicatorStyle: "circle" property string dockIndicatorStyle: "circle"
property bool dockBorderEnabled: false
property string dockBorderColor: "surfaceText"
property real dockBorderOpacity: 1.0
property int dockBorderThickness: 1
property bool notificationOverlayEnabled: false property bool notificationOverlayEnabled: false
property int overviewRows: 2 property int overviewRows: 2

View File

@@ -175,6 +175,10 @@ var SPEC = {
dockMargin: { def: 0 }, dockMargin: { def: 0 },
dockIconSize: { def: 40 }, dockIconSize: { def: 40 },
dockIndicatorStyle: { def: "circle" }, dockIndicatorStyle: { def: "circle" },
dockBorderEnabled: { def: false },
dockBorderColor: { def: "surfaceText" },
dockBorderOpacity: { def: 1.0, coerce: percentToUnit },
dockBorderThickness: { def: 1 },
notificationOverlayEnabled: { def: false }, notificationOverlayEnabled: { def: false },
overviewRows: { def: 2, persist: false }, overviewRows: { def: 2, persist: false },

View File

@@ -1,14 +1,12 @@
pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Shapes
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
pragma ComponentBehavior: Bound
Variants { Variants {
id: dockVariants id: dockVariants
model: SettingsData.getFilteredScreens("dock") model: SettingsData.getFilteredScreens("dock")
@@ -30,376 +28,438 @@ Variants {
} }
property var modelData: item property var modelData: item
property bool autoHide: SettingsData.dockAutoHide property bool autoHide: SettingsData.dockAutoHide
property real backgroundTransparency: SettingsData.dockTransparency property real backgroundTransparency: SettingsData.dockTransparency
property bool groupByApp: SettingsData.dockGroupByApp property bool groupByApp: SettingsData.dockGroupByApp
readonly property int borderThickness: SettingsData.dockBorderEnabled ? SettingsData.dockBorderThickness : 0
readonly property real widgetHeight: SettingsData.dockIconSize readonly property real widgetHeight: SettingsData.dockIconSize
readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10 readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10 + borderThickness * 2
readonly property real barSpacing: { readonly property real barSpacing: {
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default") const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
if (!defaultBar) return 0 if (!defaultBar)
return 0;
const barPos = defaultBar.position ?? SettingsData.Position.Top const barPos = defaultBar.position ?? SettingsData.Position.Top;
const barIsHorizontal = (barPos === SettingsData.Position.Top || barPos === SettingsData.Position.Bottom) const barIsHorizontal = (barPos === SettingsData.Position.Top || barPos === SettingsData.Position.Bottom);
const barIsVertical = (barPos === SettingsData.Position.Left || barPos === SettingsData.Position.Right) const barIsVertical = (barPos === SettingsData.Position.Left || barPos === SettingsData.Position.Right);
const samePosition = (SettingsData.dockPosition === barPos) const samePosition = (SettingsData.dockPosition === barPos);
const dockIsHorizontal = !isVertical const dockIsHorizontal = !isVertical;
const dockIsVertical = isVertical const dockIsVertical = isVertical;
if (!(defaultBar.visible ?? true)) return 0 if (!(defaultBar.visible ?? true))
const spacing = defaultBar.spacing ?? 4 return 0;
const bottomGap = defaultBar.bottomGap ?? 0 const spacing = defaultBar.spacing ?? 4;
if (dockIsHorizontal && barIsHorizontal && samePosition) { const bottomGap = defaultBar.bottomGap ?? 0;
return spacing + effectiveBarHeight + bottomGap if (dockIsHorizontal && barIsHorizontal && samePosition) {
} return spacing + effectiveBarHeight + bottomGap;
if (dockIsVertical && barIsVertical && samePosition) {
return spacing + effectiveBarHeight + bottomGap
}
return 0
}
readonly property real dockMargin: SettingsData.dockSpacing
readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin
readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
function px(v) { return Math.round(v * _dpr) / _dpr }
property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData)
property bool revealSticky: false
Timer {
id: revealHold
interval: 250
repeat: false
onTriggered: dock.revealSticky = false
}
property bool reveal: {
if (CompositorService.isNiri && NiriService.inOverview && SettingsData.dockOpenOnOverview) {
return true
}
return !autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky
}
onContextMenuOpenChanged: {
if (!contextMenuOpen && autoHide && !dockMouseArea.containsMouse) {
revealSticky = true
revealHold.restart()
}
}
Connections {
target: SettingsData
function onDockTransparencyChanged() {
dock.backgroundTransparency = SettingsData.dockTransparency
}
}
screen: modelData
visible: {
if (CompositorService.isNiri && NiriService.inOverview) {
return SettingsData.dockOpenOnOverview
}
return SettingsData.showDock
}
color: "transparent"
exclusiveZone: {
if (!SettingsData.showDock || autoHide) return -1
if (barSpacing > 0) return -1
return px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin)
}
property real animationHeadroom: Math.ceil(SettingsData.dockIconSize * 0.35)
implicitWidth: isVertical ? (px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
implicitHeight: !isVertical ? (px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
Item {
id: maskItem
parent: dock.contentItem
visible: false
x: {
const baseX = dockCore.x + dockMouseArea.x
if (isVertical && SettingsData.dockPosition === SettingsData.Position.Right) {
return baseX - animationHeadroom
} }
return baseX if (dockIsVertical && barIsVertical && samePosition) {
} return spacing + effectiveBarHeight + bottomGap;
y: {
const baseY = dockCore.y + dockMouseArea.y
if (!isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom) {
return baseY - animationHeadroom
} }
return baseY return 0;
} }
width: dockMouseArea.width + (isVertical ? animationHeadroom : 0)
height: dockMouseArea.height + (!isVertical ? animationHeadroom : 0)
}
mask: Region { readonly property real dockMargin: SettingsData.dockSpacing
item: maskItem readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin
} readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
function px(v) {
property var hoveredButton: { return Math.round(v * _dpr) / _dpr;
if (!dockApps.children[0]) {
return null
} }
const layoutItem = dockApps.children[0]
const flowLayout = layoutItem.children[0] property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData)
let repeater = null property bool revealSticky: false
for (var i = 0; i < flowLayout.children.length; i++) {
const child = flowLayout.children[i] Timer {
if (child && typeof child.count !== "undefined" && typeof child.itemAt === "function") { id: revealHold
repeater = child interval: 250
break repeat: false
onTriggered: dock.revealSticky = false
}
property bool reveal: {
if (CompositorService.isNiri && NiriService.inOverview && SettingsData.dockOpenOnOverview) {
return true;
}
return !autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky;
}
onContextMenuOpenChanged: {
if (!contextMenuOpen && autoHide && !dockMouseArea.containsMouse) {
revealSticky = true;
revealHold.restart();
} }
} }
if (!repeater || !repeater.itemAt) {
return null
}
for (var i = 0; i < repeater.count; i++) {
const item = repeater.itemAt(i)
if (item && item.dockButton && item.dockButton.showTooltip) {
return item.dockButton
}
}
return null
}
DankTooltip {
id: dockTooltip
targetScreen: dock.screen
}
Timer {
id: tooltipRevealDelay
interval: 250
repeat: false
onTriggered: dock.showTooltipForHoveredButton()
}
function showTooltipForHoveredButton() {
dockTooltip.hide()
if (dock.hoveredButton && dock.reveal && !slideXAnimation.running && !slideYAnimation.running) {
const buttonGlobalPos = dock.hoveredButton.mapToGlobal(0, 0)
const tooltipText = dock.hoveredButton.tooltipText || ""
if (tooltipText) {
const screenX = dock.screen ? (dock.screen.x || 0) : 0
const screenY = dock.screen ? (dock.screen.y || 0) : 0
const screenHeight = dock.screen ? dock.screen.height : 0
if (!dock.isVertical) {
const isBottom = SettingsData.dockPosition === SettingsData.Position.Bottom
const globalX = buttonGlobalPos.x + dock.hoveredButton.width / 2
const screenRelativeY = isBottom
? (screenHeight - dock.effectiveBarHeight - SettingsData.dockSpacing - SettingsData.dockBottomGap - SettingsData.dockMargin - 35)
: (buttonGlobalPos.y - screenY + dock.hoveredButton.height + Theme.spacingS)
dockTooltip.show(tooltipText,
globalX,
screenRelativeY,
dock.screen,
false, false)
} else {
const isLeft = SettingsData.dockPosition === SettingsData.Position.Left
const tooltipOffset = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + Theme.spacingXS
const tooltipX = isLeft ? tooltipOffset : (dock.screen.width - tooltipOffset)
const screenRelativeY = buttonGlobalPos.y - screenY + dock.hoveredButton.height / 2
dockTooltip.show(tooltipText,
screenX + tooltipX,
screenRelativeY,
dock.screen,
isLeft,
!isLeft)
}
}
}
}
Connections {
target: dock
function onRevealChanged() {
if (!dock.reveal) {
tooltipRevealDelay.stop()
dockTooltip.hide()
} else {
tooltipRevealDelay.restart()
}
}
function onHoveredButtonChanged() {
dock.showTooltipForHoveredButton()
}
}
Item {
id: dockCore
anchors.fill: parent
x: isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? animationHeadroom : 0
y: !isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? animationHeadroom : 0
Connections { Connections {
target: dockMouseArea target: SettingsData
function onContainsMouseChanged() { function onDockTransparencyChanged() {
if (dockMouseArea.containsMouse) { dock.backgroundTransparency = SettingsData.dockTransparency;
dock.revealSticky = true }
revealHold.stop() }
} else {
if (dock.autoHide && !dock.contextMenuOpen) { screen: modelData
revealHold.restart() visible: {
if (CompositorService.isNiri && NiriService.inOverview) {
return SettingsData.dockOpenOnOverview;
}
return SettingsData.showDock;
}
color: "transparent"
exclusiveZone: {
if (!SettingsData.showDock || autoHide)
return -1;
if (barSpacing > 0)
return -1;
return px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin);
}
property real animationHeadroom: Math.ceil(SettingsData.dockIconSize * 0.35)
implicitWidth: isVertical ? (px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
implicitHeight: !isVertical ? (px(effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
Item {
id: maskItem
parent: dock.contentItem
visible: false
x: {
const baseX = dockCore.x + dockMouseArea.x;
if (isVertical && SettingsData.dockPosition === SettingsData.Position.Right) {
return baseX - animationHeadroom - borderThickness;
}
return baseX - borderThickness;
}
y: {
const baseY = dockCore.y + dockMouseArea.y;
if (!isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom) {
return baseY - animationHeadroom - borderThickness;
}
return baseY - borderThickness;
}
width: dockMouseArea.width + (isVertical ? animationHeadroom : 0) + borderThickness * 2
height: dockMouseArea.height + (!isVertical ? animationHeadroom : 0) + borderThickness * 2
}
mask: Region {
item: maskItem
}
property var hoveredButton: {
if (!dockApps.children[0]) {
return null;
}
const layoutItem = dockApps.children[0];
const flowLayout = layoutItem.children[0];
let repeater = null;
for (var i = 0; i < flowLayout.children.length; i++) {
const child = flowLayout.children[i];
if (child && typeof child.count !== "undefined" && typeof child.itemAt === "function") {
repeater = child;
break;
}
}
if (!repeater || !repeater.itemAt) {
return null;
}
for (var i = 0; i < repeater.count; i++) {
const item = repeater.itemAt(i);
if (item && item.dockButton && item.dockButton.showTooltip) {
return item.dockButton;
}
}
return null;
}
DankTooltip {
id: dockTooltip
targetScreen: dock.screen
}
Timer {
id: tooltipRevealDelay
interval: 250
repeat: false
onTriggered: dock.showTooltipForHoveredButton()
}
function showTooltipForHoveredButton() {
dockTooltip.hide();
if (dock.hoveredButton && dock.reveal && !slideXAnimation.running && !slideYAnimation.running) {
const buttonGlobalPos = dock.hoveredButton.mapToGlobal(0, 0);
const tooltipText = dock.hoveredButton.tooltipText || "";
if (tooltipText) {
const screenX = dock.screen ? (dock.screen.x || 0) : 0;
const screenY = dock.screen ? (dock.screen.y || 0) : 0;
const screenHeight = dock.screen ? dock.screen.height : 0;
if (!dock.isVertical) {
const isBottom = SettingsData.dockPosition === SettingsData.Position.Bottom;
const globalX = buttonGlobalPos.x + dock.hoveredButton.width / 2;
const screenRelativeY = isBottom ? (screenHeight - dock.effectiveBarHeight - SettingsData.dockSpacing - SettingsData.dockBottomGap - SettingsData.dockMargin - 35) : (buttonGlobalPos.y - screenY + dock.hoveredButton.height + Theme.spacingS);
dockTooltip.show(tooltipText, globalX, screenRelativeY, dock.screen, false, false);
} else {
const isLeft = SettingsData.dockPosition === SettingsData.Position.Left;
const tooltipOffset = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + Theme.spacingXS;
const tooltipX = isLeft ? tooltipOffset : (dock.screen.width - tooltipOffset);
const screenRelativeY = buttonGlobalPos.y - screenY + dock.hoveredButton.height / 2;
dockTooltip.show(tooltipText, screenX + tooltipX, screenRelativeY, dock.screen, isLeft, !isLeft);
} }
} }
} }
} }
MouseArea { Connections {
id: dockMouseArea target: dock
property real currentScreen: modelData ? modelData : dock.screen function onRevealChanged() {
property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920 if (!dock.reveal) {
property real screenHeight: currentScreen ? currentScreen.geometry.height : 1080 tooltipRevealDelay.stop();
property real maxDockWidth: screenWidth * 0.98 dockTooltip.hide();
property real maxDockHeight: screenHeight * 0.98
height: {
if (dock.isVertical) {
const hiddenHeight = Math.min(Math.max(dockBackground.implicitHeight + 64, 200), screenHeight * 0.5)
return dock.reveal ? Math.max(Math.min(dockBackground.implicitHeight + 4, maxDockHeight), hiddenHeight) : hiddenHeight
} else { } else {
return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1 tooltipRevealDelay.restart();
}
}
width: {
if (dock.isVertical) {
return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1
} else {
const hiddenWidth = Math.min(Math.max(dockBackground.implicitWidth + 64, 200), screenWidth * 0.5)
return dock.reveal ? Math.max(Math.min(dockBackground.implicitWidth + 4, maxDockWidth), hiddenWidth) : hiddenWidth
}
}
anchors {
top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top) : 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.Right ? undefined : parent.left) : undefined
right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined
verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
}
hoverEnabled: true
acceptedButtons: Qt.NoButton
Behavior on height {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.OutCubic
} }
} }
Behavior on width { function onHoveredButtonChanged() {
NumberAnimation { dock.showTooltipForHoveredButton();
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
} }
}
Item { Item {
id: dockContainer id: dockCore
anchors.fill: parent anchors.fill: parent
clip: false x: isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? animationHeadroom : 0
y: !isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? animationHeadroom : 0
transform: Translate { Connections {
id: dockSlide target: dockMouseArea
x: { function onContainsMouseChanged() {
if (!dock.isVertical) return 0 if (dockMouseArea.containsMouse) {
if (dock.reveal) return 0 dock.revealSticky = true;
const hideDistance = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin + 10 revealHold.stop();
if (SettingsData.dockPosition === SettingsData.Position.Right) { } else {
return hideDistance if (dock.autoHide && !dock.contextMenuOpen) {
} else { revealHold.restart();
return -hideDistance
}
}
y: {
if (dock.isVertical) return 0
if (dock.reveal) return 0
const hideDistance = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin + 10
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
return hideDistance
} else {
return -hideDistance
} }
} }
}
}
Behavior on x { MouseArea {
NumberAnimation { id: dockMouseArea
id: slideXAnimation property real currentScreen: modelData ? modelData : dock.screen
duration: Theme.shortDuration property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920
easing.type: Easing.OutCubic property real screenHeight: currentScreen ? currentScreen.geometry.height : 1080
} property real maxDockWidth: screenWidth * 0.98
} property real maxDockHeight: screenHeight * 0.98
Behavior on y { height: {
NumberAnimation { if (dock.isVertical) {
id: slideYAnimation const extra = 4 + dock.borderThickness;
duration: Theme.shortDuration const hiddenHeight = Math.min(Math.max(dockBackground.implicitHeight + 64, 200), screenHeight * 0.5);
easing.type: Easing.OutCubic return dock.reveal ? Math.max(Math.min(dockBackground.implicitHeight + extra, maxDockHeight), hiddenHeight) : hiddenHeight;
} } else {
return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1;
}
}
width: {
if (dock.isVertical) {
return dock.reveal ? px(dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin) : 1;
} else {
const extra = 4 + dock.borderThickness;
const hiddenWidth = Math.min(Math.max(dockBackground.implicitWidth + 64, 200), screenWidth * 0.5);
return dock.reveal ? Math.max(Math.min(dockBackground.implicitWidth + extra, maxDockWidth), hiddenWidth) : hiddenWidth;
}
}
anchors {
top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top) : 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.Right ? undefined : parent.left) : undefined
right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined
verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
}
hoverEnabled: true
acceptedButtons: Qt.NoButton
Behavior on height {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
}
Behavior on width {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.OutCubic
} }
} }
Item { Item {
id: dockBackground id: dockContainer
objectName: "dockBackground" anchors.fill: parent
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
}
anchors.topMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Top ? barSpacing + SettingsData.dockMargin + 1 : 0
anchors.bottomMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? barSpacing + SettingsData.dockMargin + 1 : 0
anchors.leftMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? barSpacing + SettingsData.dockMargin + 1 : 0
anchors.rightMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? barSpacing + SettingsData.dockMargin + 1 : 0
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
layer.enabled: true
clip: false clip: false
DankRectangle { transform: Translate {
anchors.fill: parent id: dockSlide
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency) x: {
overlayColor: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04) if (!dock.isVertical)
return 0;
if (dock.reveal)
return 0;
const hideDistance = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin + 10;
if (SettingsData.dockPosition === SettingsData.Position.Right) {
return hideDistance;
} else {
return -hideDistance;
}
}
y: {
if (dock.isVertical)
return 0;
if (dock.reveal)
return 0;
const hideDistance = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin + 10;
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
return hideDistance;
} else {
return -hideDistance;
}
}
Behavior on x {
NumberAnimation {
id: slideXAnimation
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
}
Behavior on y {
NumberAnimation {
id: slideYAnimation
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
}
} }
}
DockApps { Item {
id: dockApps id: dockBackground
objectName: "dockBackground"
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
}
anchors.topMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Top ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0
anchors.bottomMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? barSpacing + SettingsData.dockMargin + 1 + dock.borderThickness : 0
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
anchors.top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top ? dockBackground.top : undefined) : undefined implicitWidth: dock.isVertical ? (dockApps.implicitHeight + SettingsData.dockSpacing * 2) : (dockApps.implicitWidth + SettingsData.dockSpacing * 2)
anchors.bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? dockBackground.bottom : undefined) : undefined implicitHeight: dock.isVertical ? (dockApps.implicitWidth + SettingsData.dockSpacing * 2) : (dockApps.implicitHeight + SettingsData.dockSpacing * 2)
anchors.horizontalCenter: !dock.isVertical ? dockBackground.horizontalCenter : undefined width: implicitWidth
anchors.left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Left ? dockBackground.left : undefined) : undefined height: implicitHeight
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.rightMargin: dock.isVertical ? SettingsData.dockSpacing : 0
contextMenu: dockVariants.contextMenu layer.enabled: true
groupByApp: dock.groupByApp clip: false
isVertical: dock.isVertical
dockScreen: dock.screen DankRectangle {
iconSize: dock.widgetHeight anchors.fill: parent
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency)
overlayColor: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
}
}
Shape {
id: dockBorderShape
x: dockBackground.x - borderThickness
y: dockBackground.y - borderThickness
width: dockBackground.width + borderThickness * 2
height: dockBackground.height + borderThickness * 2
visible: SettingsData.dockBorderEnabled
preferredRendererType: Shape.CurveRenderer
readonly property real borderThickness: Math.max(1, dock.borderThickness)
readonly property real i: borderThickness / 2
readonly property real cr: Theme.cornerRadius
readonly property real w: dockBackground.width
readonly property real h: dockBackground.height
readonly property color borderColor: {
const opacity = SettingsData.dockBorderOpacity;
switch (SettingsData.dockBorderColor) {
case "secondary":
return Theme.withAlpha(Theme.secondary, opacity);
case "primary":
return Theme.withAlpha(Theme.primary, opacity);
default:
return Theme.withAlpha(Theme.surfaceText, opacity);
}
}
ShapePath {
fillColor: "transparent"
strokeColor: dockBorderShape.borderColor
strokeWidth: dockBorderShape.borderThickness
joinStyle: ShapePath.RoundJoin
capStyle: ShapePath.FlatCap
PathSvg {
path: {
const bt = dockBorderShape.borderThickness;
const i = dockBorderShape.i;
const cr = dockBorderShape.cr + bt - i;
const w = dockBorderShape.w;
const h = dockBorderShape.h;
let d = `M ${i + cr} ${i}`;
d += ` L ${i + w + 2 * (bt - i) - cr} ${i}`;
if (cr > 0)
d += ` A ${cr} ${cr} 0 0 1 ${i + w + 2 * (bt - i)} ${i + cr}`;
d += ` L ${i + w + 2 * (bt - i)} ${i + h + 2 * (bt - i) - cr}`;
if (cr > 0)
d += ` A ${cr} ${cr} 0 0 1 ${i + w + 2 * (bt - i) - cr} ${i + h + 2 * (bt - i)}`;
d += ` L ${i + cr} ${i + h + 2 * (bt - i)}`;
if (cr > 0)
d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h + 2 * (bt - i) - cr}`;
d += ` L ${i} ${i + cr}`;
if (cr > 0)
d += ` A ${cr} ${cr} 0 0 1 ${i + cr} ${i}`;
d += " Z";
return d;
}
}
}
}
DockApps {
id: dockApps
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.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.rightMargin: dock.isVertical ? SettingsData.dockSpacing : 0
contextMenu: dockVariants.contextMenu
groupByApp: dock.groupByApp
isVertical: dock.isVertical
dockScreen: dock.screen
iconSize: dock.widgetHeight
}
} }
} }
} }
}
} }
} }

View File

@@ -45,18 +45,18 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { Column {
id: positionText width: Math.max(0, parent.width - Theme.iconSize - Theme.spacingM - positionButtonGroup.width - Theme.spacingM)
text: I18n.tr("Dock Position")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
}
Item { StyledText {
width: parent.width - Theme.iconSize - Theme.spacingM - positionText.width - positionButtonGroup.width - Theme.spacingM * 2 text: I18n.tr("Dock Position")
anchors.verticalCenter: parent.verticalCenter font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
elide: Text.ElideRight
width: parent.width
}
} }
DankButtonGroup { DankButtonGroup {
@@ -361,18 +361,18 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { Column {
id: indicatorStyleText width: Math.max(0, parent.width - Theme.iconSize - Theme.spacingM - indicatorStyleButtonGroup.width - Theme.spacingM)
text: I18n.tr("Indicator Style")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
}
Item { StyledText {
width: parent.width - Theme.iconSize - Theme.spacingM - indicatorStyleText.width - indicatorStyleButtonGroup.width - Theme.spacingM * 2 text: I18n.tr("Indicator Style")
anchors.verticalCenter: parent.verticalCenter font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
elide: Text.ElideRight
width: parent.width
}
} }
DankButtonGroup { DankButtonGroup {
@@ -760,6 +760,231 @@ Item {
} }
} }
} }
StyledRect {
width: parent.width
height: borderSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
border.width: 0
Column {
id: borderSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
DankToggle {
width: parent.width
text: I18n.tr("Border")
description: I18n.tr("Add a border around the dock")
checked: SettingsData.dockBorderEnabled
onToggled: checked => {
SettingsData.set("dockBorderEnabled", checked);
}
}
Column {
width: parent.width
leftPadding: Theme.spacingM
spacing: Theme.spacingM
visible: SettingsData.dockBorderEnabled
Rectangle {
width: parent.width - parent.leftPadding
height: 1
color: Theme.outline
opacity: 0.2
}
Row {
width: parent.width - parent.leftPadding
spacing: Theme.spacingM
Column {
width: parent.width - dockBorderColorGroup.width - Theme.spacingM
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Border Color")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: I18n.tr("Choose the border accent color")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
}
}
DankButtonGroup {
id: dockBorderColorGroup
anchors.verticalCenter: parent.verticalCenter
model: ["Surface", "Secondary", "Primary"]
currentIndex: {
switch (SettingsData.dockBorderColor) {
case "surfaceText":
return 0;
case "secondary":
return 1;
case "primary":
return 2;
default:
return 0;
}
}
onSelectionChanged: (index, selected) => {
if (!selected)
return;
switch (index) {
case 0:
SettingsData.set("dockBorderColor", "surfaceText");
break;
case 1:
SettingsData.set("dockBorderColor", "secondary");
break;
case 2:
SettingsData.set("dockBorderColor", "primary");
break;
}
}
}
}
Column {
width: parent.width - parent.leftPadding
spacing: Theme.spacingS
Row {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Border Opacity")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - dockBorderOpacityText.implicitWidth - resetDockBorderOpacityBtn.width - Theme.spacingS - Theme.spacingM
height: 1
StyledText {
id: dockBorderOpacityText
visible: false
text: I18n.tr("Border Opacity")
font.pixelSize: Theme.fontSizeSmall
}
}
DankActionButton {
id: resetDockBorderOpacityBtn
buttonSize: 20
iconName: "refresh"
iconSize: 12
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
iconColor: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
onClicked: {
SettingsData.set("dockBorderOpacity", 1.0);
}
}
Item {
width: Theme.spacingS
height: 1
}
}
DankSlider {
id: dockBorderOpacitySlider
width: parent.width
height: 24
value: SettingsData.dockBorderOpacity * 100
minimum: 0
maximum: 100
unit: "%"
showValue: true
wheelEnabled: false
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
onSliderValueChanged: newValue => {
SettingsData.set("dockBorderOpacity", newValue / 100);
}
}
}
Column {
width: parent.width - parent.leftPadding
spacing: Theme.spacingS
Row {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Border Thickness")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - dockBorderThicknessText.implicitWidth - resetDockBorderThicknessBtn.width - Theme.spacingS - Theme.spacingM
height: 1
StyledText {
id: dockBorderThicknessText
visible: false
text: I18n.tr("Border Thickness")
font.pixelSize: Theme.fontSizeSmall
}
}
DankActionButton {
id: resetDockBorderThicknessBtn
buttonSize: 20
iconName: "refresh"
iconSize: 12
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
iconColor: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
onClicked: {
SettingsData.set("dockBorderThickness", 1);
}
}
Item {
width: Theme.spacingS
height: 1
}
}
DankSlider {
id: dockBorderThicknessSlider
width: parent.width
height: 24
value: SettingsData.dockBorderThickness
minimum: 1
maximum: 10
unit: "px"
showValue: true
wheelEnabled: false
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
onSliderValueChanged: newValue => {
SettingsData.set("dockBorderThickness", newValue);
}
}
}
}
}
}
} }
} }
} }