mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 13:32:50 -05:00
feat: Implement Dank Launcher button on the Dock
- Configurable with custom icons/logos - Respects light/dark theme - Drag & Drop in place
This commit is contained in:
@@ -83,6 +83,7 @@ Singleton {
|
||||
property string nightModeLocationProvider: ""
|
||||
|
||||
property var pinnedApps: []
|
||||
property int dockLauncherPosition: 0
|
||||
property var hiddenTrayIds: []
|
||||
property var recentColors: []
|
||||
property bool showThirdPartyPlugins: false
|
||||
|
||||
@@ -431,6 +431,13 @@ Singleton {
|
||||
property real dockBorderOpacity: 1.0
|
||||
property int dockBorderThickness: 1
|
||||
property bool dockIsolateDisplays: false
|
||||
property bool dockLauncherEnabled: false
|
||||
property string dockLauncherLogoMode: "apps"
|
||||
property string dockLauncherLogoCustomPath: ""
|
||||
property string dockLauncherLogoColorOverride: ""
|
||||
property int dockLauncherLogoSizeOffset: 0
|
||||
property real dockLauncherLogoBrightness: 0.5
|
||||
property real dockLauncherLogoContrast: 1
|
||||
|
||||
property bool notificationOverlayEnabled: false
|
||||
property int overviewRows: 2
|
||||
|
||||
@@ -255,6 +255,13 @@ var SPEC = {
|
||||
dockBorderOpacity: { def: 1.0, coerce: percentToUnit },
|
||||
dockBorderThickness: { def: 1 },
|
||||
dockIsolateDisplays: { def: false },
|
||||
dockLauncherEnabled: { def: false },
|
||||
dockLauncherLogoMode: { def: "apps" },
|
||||
dockLauncherLogoCustomPath: { def: "" },
|
||||
dockLauncherLogoColorOverride: { def: "" },
|
||||
dockLauncherLogoSizeOffset: { def: 0 },
|
||||
dockLauncherLogoBrightness: { def: 0.5, coerce: percentToUnit },
|
||||
dockLauncherLogoContrast: { def: 1, coerce: percentToUnit },
|
||||
|
||||
notificationOverlayEnabled: { def: false },
|
||||
overviewRows: { def: 2, persist: false },
|
||||
|
||||
@@ -208,7 +208,7 @@ Item {
|
||||
targetIndex = -1;
|
||||
originalIndex = -1;
|
||||
|
||||
if (dockApps && !didReorder) {
|
||||
if (dockApps) {
|
||||
dockApps.draggedIndex = -1;
|
||||
dockApps.dropTargetIndex = -1;
|
||||
}
|
||||
|
||||
@@ -22,18 +22,34 @@ Item {
|
||||
implicitWidth: isVertical ? appLayout.height : appLayout.width
|
||||
implicitHeight: isVertical ? appLayout.width : appLayout.height
|
||||
|
||||
function movePinnedApp(fromIndex, toIndex) {
|
||||
if (fromIndex === toIndex) {
|
||||
function dockIndexToPinnedIndex(dockIndex) {
|
||||
if (!SettingsData.dockLauncherEnabled) {
|
||||
return dockIndex;
|
||||
}
|
||||
|
||||
const launcherPos = SessionData.dockLauncherPosition;
|
||||
if (dockIndex < launcherPos) {
|
||||
return dockIndex;
|
||||
} else {
|
||||
return dockIndex - 1;
|
||||
}
|
||||
}
|
||||
|
||||
function movePinnedApp(fromDockIndex, toDockIndex) {
|
||||
const fromPinnedIndex = dockIndexToPinnedIndex(fromDockIndex);
|
||||
const toPinnedIndex = dockIndexToPinnedIndex(toDockIndex);
|
||||
|
||||
if (fromPinnedIndex === toPinnedIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentPinned = [...(SessionData.pinnedApps || [])];
|
||||
if (fromIndex < 0 || fromIndex >= currentPinned.length || toIndex < 0 || toIndex >= currentPinned.length) {
|
||||
if (fromPinnedIndex < 0 || fromPinnedIndex >= currentPinned.length || toPinnedIndex < 0 || toPinnedIndex >= currentPinned.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const movedApp = currentPinned.splice(fromIndex, 1)[0];
|
||||
currentPinned.splice(toIndex, 0, movedApp);
|
||||
const movedApp = currentPinned.splice(fromPinnedIndex, 1)[0];
|
||||
currentPinned.splice(toPinnedIndex, 0, movedApp);
|
||||
|
||||
SessionData.setPinnedApps(currentPinned);
|
||||
}
|
||||
@@ -75,6 +91,23 @@ Item {
|
||||
return false;
|
||||
}
|
||||
|
||||
function insertLauncher(targetArray) {
|
||||
if (!SettingsData.dockLauncherEnabled)
|
||||
return;
|
||||
|
||||
const launcherItem = {
|
||||
uniqueKey: "launcher_button",
|
||||
type: "launcher",
|
||||
appId: "__LAUNCHER__",
|
||||
toplevel: null,
|
||||
isPinned: true,
|
||||
isRunning: false
|
||||
};
|
||||
|
||||
const pos = Math.max(0, Math.min(SessionData.dockLauncherPosition, targetArray.length));
|
||||
targetArray.splice(pos, 0, launcherItem);
|
||||
}
|
||||
|
||||
function updateModel() {
|
||||
const items = [];
|
||||
const pinnedApps = [...(SessionData.pinnedApps || [])];
|
||||
@@ -136,6 +169,8 @@ Item {
|
||||
|
||||
pinnedGroups.forEach(item => items.push(item));
|
||||
|
||||
insertLauncher(items);
|
||||
|
||||
if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) {
|
||||
items.push({
|
||||
uniqueKey: "separator_grouped",
|
||||
@@ -148,7 +183,7 @@ Item {
|
||||
}
|
||||
|
||||
unpinnedGroups.forEach(item => items.push(item));
|
||||
root.pinnedAppCount = pinnedGroups.length;
|
||||
root.pinnedAppCount = pinnedGroups.length + (SettingsData.dockLauncherEnabled ? 1 : 0);
|
||||
} else {
|
||||
pinnedApps.forEach(rawAppId => {
|
||||
const appId = Paths.moddedAppId(rawAppId);
|
||||
@@ -162,7 +197,9 @@ Item {
|
||||
});
|
||||
});
|
||||
|
||||
root.pinnedAppCount = pinnedApps.length;
|
||||
root.pinnedAppCount = pinnedApps.length + (SettingsData.dockLauncherEnabled ? 1 : 0);
|
||||
|
||||
insertLauncher(items);
|
||||
|
||||
if (pinnedApps.length > 0 && sortedToplevels.length > 0) {
|
||||
items.push({
|
||||
@@ -203,10 +240,10 @@ Item {
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
property alias dockButton: button
|
||||
property var dockButton: itemData.type === "launcher" ? launcherButton : button
|
||||
property var itemData: modelData
|
||||
clip: false
|
||||
z: button.dragging ? 100 : 0
|
||||
z: (itemData.type === "launcher" ? launcherButton.dragging : button.dragging) ? 100 : 0
|
||||
|
||||
width: itemData.type === "separator" ? (root.isVertical ? root.iconSize : 8) : (root.isVertical ? root.iconSize : root.iconSize * 1.2)
|
||||
height: itemData.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize)
|
||||
@@ -261,9 +298,22 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
DockLauncherButton {
|
||||
id: launcherButton
|
||||
visible: itemData.type === "launcher"
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: delegateItem.width
|
||||
height: delegateItem.height
|
||||
actualIconSize: root.iconSize
|
||||
|
||||
dockApps: root
|
||||
index: model.index
|
||||
}
|
||||
|
||||
DockAppButton {
|
||||
id: button
|
||||
visible: itemData.type !== "separator"
|
||||
visible: itemData.type !== "separator" && itemData.type !== "launcher"
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: delegateItem.width
|
||||
@@ -314,5 +364,27 @@ Item {
|
||||
function onDockIsolateDisplaysChanged() {
|
||||
repeater.updateModel();
|
||||
}
|
||||
function onDockLauncherEnabledChanged() {
|
||||
root.suppressShiftAnimation = true;
|
||||
root.draggedIndex = -1;
|
||||
root.dropTargetIndex = -1;
|
||||
repeater.updateModel();
|
||||
Qt.callLater(() => {
|
||||
root.suppressShiftAnimation = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onDockLauncherPositionChanged() {
|
||||
root.suppressShiftAnimation = true;
|
||||
root.draggedIndex = -1;
|
||||
root.dropTargetIndex = -1;
|
||||
repeater.updateModel();
|
||||
Qt.callLater(() => {
|
||||
root.suppressShiftAnimation = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
294
quickshell/Modules/Dock/DockLauncherButton.qml
Normal file
294
quickshell/Modules/Dock/DockLauncherButton.qml
Normal file
@@ -0,0 +1,294 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,6 +164,265 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "apps"
|
||||
title: I18n.tr("Launcher Button")
|
||||
settingKey: "dockLauncher"
|
||||
|
||||
SettingsToggleRow {
|
||||
settingKey: "dockLauncherEnabled"
|
||||
tags: ["dock", "launcher", "button", "apps"]
|
||||
text: I18n.tr("Show Launcher Button")
|
||||
description: I18n.tr("Add a draggable launcher button to the dock")
|
||||
checked: SettingsData.dockLauncherEnabled
|
||||
onToggled: checked => SettingsData.set("dockLauncherEnabled", checked)
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingL
|
||||
visible: SettingsData.dockLauncherEnabled
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: I18n.tr("Long press and drag the launcher button to reposition it in the dock")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Launcher Icon")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: logoModeGroup.implicitHeight
|
||||
clip: true
|
||||
|
||||
DankButtonGroup {
|
||||
id: logoModeGroup
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL
|
||||
minButtonWidth: parent.width < 480 ? 44 : 64
|
||||
textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
||||
model: {
|
||||
const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo"), I18n.tr("Dank")];
|
||||
if (CompositorService.isNiri) {
|
||||
modes.push("niri");
|
||||
} else if (CompositorService.isHyprland) {
|
||||
modes.push("Hyprland");
|
||||
} else if (CompositorService.isDwl) {
|
||||
modes.push("mango");
|
||||
} else if (CompositorService.isSway) {
|
||||
modes.push("Sway");
|
||||
} else if (CompositorService.isScroll) {
|
||||
modes.push("Scroll");
|
||||
} else {
|
||||
modes.push(I18n.tr("Compositor"));
|
||||
}
|
||||
modes.push(I18n.tr("Custom"));
|
||||
return modes;
|
||||
}
|
||||
currentIndex: {
|
||||
if (SettingsData.dockLauncherLogoMode === "apps")
|
||||
return 0;
|
||||
if (SettingsData.dockLauncherLogoMode === "os")
|
||||
return 1;
|
||||
if (SettingsData.dockLauncherLogoMode === "dank")
|
||||
return 2;
|
||||
if (SettingsData.dockLauncherLogoMode === "compositor")
|
||||
return 3;
|
||||
if (SettingsData.dockLauncherLogoMode === "custom")
|
||||
return 4;
|
||||
return 0;
|
||||
}
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected)
|
||||
return;
|
||||
switch (index) {
|
||||
case 0:
|
||||
SettingsData.set("dockLauncherLogoMode", "apps");
|
||||
break;
|
||||
case 1:
|
||||
SettingsData.set("dockLauncherLogoMode", "os");
|
||||
break;
|
||||
case 2:
|
||||
SettingsData.set("dockLauncherLogoMode", "dank");
|
||||
break;
|
||||
case 3:
|
||||
SettingsData.set("dockLauncherLogoMode", "compositor");
|
||||
break;
|
||||
case 4:
|
||||
SettingsData.set("dockLauncherLogoMode", "custom");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingL
|
||||
visible: SettingsData.dockLauncherLogoMode !== "apps"
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Color Override")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: colorOverrideRow.implicitHeight
|
||||
clip: true
|
||||
|
||||
Row {
|
||||
id: colorOverrideRow
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankButtonGroup {
|
||||
id: colorModeGroup
|
||||
buttonPadding: parent.parent.width < 480 ? Theme.spacingS : Theme.spacingL
|
||||
minButtonWidth: parent.parent.width < 480 ? 44 : 64
|
||||
textSize: parent.parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
||||
model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")]
|
||||
currentIndex: {
|
||||
const override = SettingsData.dockLauncherLogoColorOverride;
|
||||
if (override === "")
|
||||
return 0;
|
||||
if (override === "primary")
|
||||
return 1;
|
||||
if (override === "surface")
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected)
|
||||
return;
|
||||
switch (index) {
|
||||
case 0:
|
||||
SettingsData.set("dockLauncherLogoColorOverride", "");
|
||||
break;
|
||||
case 1:
|
||||
SettingsData.set("dockLauncherLogoColorOverride", "primary");
|
||||
break;
|
||||
case 2:
|
||||
SettingsData.set("dockLauncherLogoColorOverride", "surface");
|
||||
break;
|
||||
case 3:
|
||||
const currentOverride = SettingsData.dockLauncherLogoColorOverride;
|
||||
const isPreset = currentOverride === "" || currentOverride === "primary" || currentOverride === "surface";
|
||||
if (isPreset) {
|
||||
SettingsData.set("dockLauncherLogoColorOverride", "#ffffff");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: colorPickerCircle
|
||||
visible: {
|
||||
const override = SettingsData.dockLauncherLogoColorOverride;
|
||||
return override !== "" && override !== "primary" && override !== "surface";
|
||||
}
|
||||
width: 36
|
||||
height: 36
|
||||
radius: 18
|
||||
color: {
|
||||
const override = SettingsData.dockLauncherLogoColorOverride;
|
||||
if (override !== "" && override !== "primary" && override !== "surface")
|
||||
return override;
|
||||
return "#ffffff";
|
||||
}
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (!PopoutService.colorPickerModal)
|
||||
return;
|
||||
PopoutService.colorPickerModal.selectedColor = SettingsData.dockLauncherLogoColorOverride;
|
||||
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Dock Launcher Logo Color");
|
||||
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
|
||||
SettingsData.set("dockLauncherLogoColorOverride", selectedColor);
|
||||
};
|
||||
PopoutService.colorPickerModal.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
settingKey: "dockLauncherLogoSizeOffset"
|
||||
tags: ["dock", "launcher", "logo", "size", "offset", "scale"]
|
||||
text: I18n.tr("Size Offset")
|
||||
minimum: -12
|
||||
maximum: 12
|
||||
value: SettingsData.dockLauncherLogoSizeOffset
|
||||
defaultValue: 0
|
||||
onSliderValueChanged: newValue => SettingsData.set("dockLauncherLogoSizeOffset", newValue)
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: {
|
||||
const override = SettingsData.dockLauncherLogoColorOverride;
|
||||
return override !== "" && override !== "primary" && override !== "surface";
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
settingKey: "dockLauncherLogoBrightness"
|
||||
tags: ["dock", "launcher", "logo", "brightness", "color"]
|
||||
text: I18n.tr("Brightness")
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
value: Math.round(SettingsData.dockLauncherLogoBrightness * 100)
|
||||
unit: "%"
|
||||
defaultValue: 50
|
||||
onSliderValueChanged: newValue => SettingsData.set("dockLauncherLogoBrightness", newValue / 100)
|
||||
}
|
||||
|
||||
SettingsSliderRow {
|
||||
settingKey: "dockLauncherLogoContrast"
|
||||
tags: ["dock", "launcher", "logo", "contrast", "color"]
|
||||
text: I18n.tr("Contrast")
|
||||
minimum: 0
|
||||
maximum: 200
|
||||
value: Math.round(SettingsData.dockLauncherLogoContrast * 100)
|
||||
unit: "%"
|
||||
defaultValue: 100
|
||||
onSliderValueChanged: newValue => SettingsData.set("dockLauncherLogoContrast", newValue / 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
width: parent.width
|
||||
iconName: "photo_size_select_large"
|
||||
|
||||
Reference in New Issue
Block a user