mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 13:32:50 -05:00
- Configurable with custom icons/logos - Respects light/dark theme - Drag & Drop in place
295 lines
11 KiB
QML
295 lines
11 KiB
QML
import QtQuick
|
|
import QtQuick.Effects
|
|
import Quickshell.Widgets
|
|
import qs.Common
|
|
import qs.Services
|
|
import qs.Widgets
|
|
|
|
Item {
|
|
id: root
|
|
|
|
clip: false
|
|
property var dockApps: null
|
|
property int index: -1
|
|
property bool longPressing: false
|
|
property bool dragging: false
|
|
property point dragStartPos: Qt.point(0, 0)
|
|
property real dragAxisOffset: 0
|
|
property int targetIndex: -1
|
|
property int originalIndex: -1
|
|
property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
|
property bool isHovered: mouseArea.containsMouse && !dragging
|
|
property bool showTooltip: mouseArea.containsMouse && !dragging
|
|
property real actualIconSize: 40
|
|
|
|
readonly property string tooltipText: I18n.tr("Applications")
|
|
|
|
readonly property color effectiveLogoColor: {
|
|
const override = SettingsData.dockLauncherLogoColorOverride;
|
|
if (override === "primary")
|
|
return Theme.primary;
|
|
if (override === "surface")
|
|
return Theme.surfaceText;
|
|
if (override !== "")
|
|
return override;
|
|
return Theme.surfaceText;
|
|
}
|
|
|
|
onIsHoveredChanged: {
|
|
if (mouseArea.pressed || dragging)
|
|
return;
|
|
if (isHovered) {
|
|
exitAnimation.stop();
|
|
if (!bounceAnimation.running) {
|
|
bounceAnimation.restart();
|
|
}
|
|
} else {
|
|
bounceAnimation.stop();
|
|
exitAnimation.restart();
|
|
}
|
|
}
|
|
|
|
readonly property bool animateX: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
|
readonly property real animationDistance: actualIconSize
|
|
readonly property real animationDirection: {
|
|
if (SettingsData.dockPosition === SettingsData.Position.Bottom)
|
|
return -1;
|
|
if (SettingsData.dockPosition === SettingsData.Position.Top)
|
|
return 1;
|
|
if (SettingsData.dockPosition === SettingsData.Position.Right)
|
|
return -1;
|
|
if (SettingsData.dockPosition === SettingsData.Position.Left)
|
|
return 1;
|
|
return -1;
|
|
}
|
|
|
|
SequentialAnimation {
|
|
id: bounceAnimation
|
|
|
|
running: false
|
|
|
|
NumberAnimation {
|
|
target: root
|
|
property: "hoverAnimOffset"
|
|
to: animationDirection * animationDistance * 0.25
|
|
duration: Anims.durShort
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: Anims.emphasizedAccel
|
|
}
|
|
|
|
NumberAnimation {
|
|
target: root
|
|
property: "hoverAnimOffset"
|
|
to: animationDirection * animationDistance * 0.2
|
|
duration: Anims.durShort
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: Anims.emphasizedDecel
|
|
}
|
|
}
|
|
|
|
NumberAnimation {
|
|
id: exitAnimation
|
|
|
|
running: false
|
|
target: root
|
|
property: "hoverAnimOffset"
|
|
to: 0
|
|
duration: Anims.durShort
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: Anims.emphasizedDecel
|
|
}
|
|
|
|
Timer {
|
|
id: longPressTimer
|
|
|
|
interval: 500
|
|
repeat: false
|
|
onTriggered: {
|
|
longPressing = true;
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: mouseArea
|
|
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
enabled: true
|
|
preventStealing: true
|
|
cursorShape: longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor
|
|
acceptedButtons: Qt.LeftButton
|
|
onPressed: mouse => {
|
|
if (mouse.button === Qt.LeftButton) {
|
|
dragStartPos = Qt.point(mouse.x, mouse.y);
|
|
longPressTimer.start();
|
|
}
|
|
}
|
|
onReleased: mouse => {
|
|
longPressTimer.stop();
|
|
|
|
const wasDragging = dragging;
|
|
const didReorder = wasDragging && targetIndex >= 0 && dockApps;
|
|
|
|
if (didReorder) {
|
|
SessionData.dockLauncherPosition = targetIndex;
|
|
}
|
|
|
|
longPressing = false;
|
|
dragging = false;
|
|
dragAxisOffset = 0;
|
|
targetIndex = -1;
|
|
originalIndex = -1;
|
|
|
|
if (dockApps) {
|
|
dockApps.draggedIndex = -1;
|
|
dockApps.dropTargetIndex = -1;
|
|
}
|
|
|
|
if (wasDragging || mouse.button !== Qt.LeftButton)
|
|
return;
|
|
|
|
PopoutService.toggleDankLauncherV2();
|
|
}
|
|
onPositionChanged: mouse => {
|
|
if (longPressing && !dragging) {
|
|
const distance = Math.sqrt(Math.pow(mouse.x - dragStartPos.x, 2) + Math.pow(mouse.y - dragStartPos.y, 2));
|
|
if (distance > 5) {
|
|
dragging = true;
|
|
targetIndex = index;
|
|
originalIndex = index;
|
|
if (dockApps) {
|
|
dockApps.draggedIndex = index;
|
|
dockApps.dropTargetIndex = index;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!dragging || !dockApps)
|
|
return;
|
|
|
|
const axisOffset = isVertical ? (mouse.y - dragStartPos.y) : (mouse.x - dragStartPos.x);
|
|
dragAxisOffset = axisOffset;
|
|
|
|
const spacing = Math.min(8, Math.max(4, actualIconSize * 0.08));
|
|
const itemSize = actualIconSize * 1.2 + spacing;
|
|
const slotOffset = Math.round(axisOffset / itemSize);
|
|
const newTargetIndex = Math.max(0, Math.min(dockApps.pinnedAppCount, originalIndex + slotOffset));
|
|
|
|
if (newTargetIndex !== targetIndex) {
|
|
targetIndex = newTargetIndex;
|
|
dockApps.dropTargetIndex = newTargetIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
property real hoverAnimOffset: 0
|
|
|
|
Item {
|
|
id: visualContent
|
|
anchors.fill: parent
|
|
|
|
transform: Translate {
|
|
x: dragging && !isVertical ? dragAxisOffset : (!dragging && isVertical ? hoverAnimOffset : 0)
|
|
y: dragging && isVertical ? dragAxisOffset : (!dragging && !isVertical ? hoverAnimOffset : 0)
|
|
}
|
|
|
|
Item {
|
|
anchors.centerIn: parent
|
|
width: actualIconSize
|
|
height: actualIconSize
|
|
|
|
DankIcon {
|
|
visible: SettingsData.dockLauncherLogoMode === "apps"
|
|
anchors.centerIn: parent
|
|
name: "apps"
|
|
size: actualIconSize - 4
|
|
color: Theme.widgetIconColor
|
|
}
|
|
|
|
SystemLogo {
|
|
visible: SettingsData.dockLauncherLogoMode === "os"
|
|
anchors.centerIn: parent
|
|
width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
|
height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
|
colorOverride: effectiveLogoColor
|
|
brightnessOverride: SettingsData.dockLauncherLogoBrightness
|
|
contrastOverride: SettingsData.dockLauncherLogoContrast
|
|
}
|
|
|
|
IconImage {
|
|
visible: SettingsData.dockLauncherLogoMode === "dank"
|
|
anchors.centerIn: parent
|
|
width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
|
height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
|
smooth: true
|
|
mipmap: true
|
|
asynchronous: true
|
|
source: "file://" + Theme.shellDir + "/assets/danklogo.svg"
|
|
layer.enabled: effectiveLogoColor !== ""
|
|
layer.smooth: true
|
|
layer.mipmap: true
|
|
layer.effect: MultiEffect {
|
|
saturation: 0
|
|
colorization: 1
|
|
colorizationColor: effectiveLogoColor
|
|
}
|
|
}
|
|
|
|
IconImage {
|
|
visible: SettingsData.dockLauncherLogoMode === "compositor" && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll || CompositorService.isLabwc)
|
|
anchors.centerIn: parent
|
|
width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
|
height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
|
smooth: true
|
|
asynchronous: true
|
|
source: {
|
|
if (CompositorService.isNiri) {
|
|
return "file://" + Theme.shellDir + "/assets/niri.svg";
|
|
} else if (CompositorService.isHyprland) {
|
|
return "file://" + Theme.shellDir + "/assets/hyprland.svg";
|
|
} else if (CompositorService.isDwl) {
|
|
return "file://" + Theme.shellDir + "/assets/mango.png";
|
|
} else if (CompositorService.isSway) {
|
|
return "file://" + Theme.shellDir + "/assets/sway.svg";
|
|
} else if (CompositorService.isScroll) {
|
|
return "file://" + Theme.shellDir + "/assets/sway.svg";
|
|
} else if (CompositorService.isLabwc) {
|
|
return "file://" + Theme.shellDir + "/assets/labwc.png";
|
|
}
|
|
return "";
|
|
}
|
|
layer.enabled: effectiveLogoColor !== ""
|
|
layer.effect: MultiEffect {
|
|
saturation: 0
|
|
colorization: 1
|
|
colorizationColor: effectiveLogoColor
|
|
brightness: {
|
|
SettingsData.dockLauncherLogoBrightness;
|
|
}
|
|
contrast: {
|
|
SettingsData.dockLauncherLogoContrast;
|
|
}
|
|
}
|
|
}
|
|
|
|
IconImage {
|
|
visible: SettingsData.dockLauncherLogoMode === "custom" && SettingsData.dockLauncherLogoCustomPath !== ""
|
|
anchors.centerIn: parent
|
|
width: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
|
height: actualIconSize + SettingsData.dockLauncherLogoSizeOffset
|
|
smooth: true
|
|
asynchronous: true
|
|
source: SettingsData.dockLauncherLogoCustomPath ? "file://" + SettingsData.dockLauncherLogoCustomPath.replace("file://", "") : ""
|
|
layer.enabled: effectiveLogoColor !== ""
|
|
layer.effect: MultiEffect {
|
|
saturation: 0
|
|
colorization: 1
|
|
colorizationColor: effectiveLogoColor
|
|
brightness: SettingsData.dockLauncherLogoBrightness
|
|
contrast: SettingsData.dockLauncherLogoContrast
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|