mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-04 12:52:06 -04:00
779 lines
39 KiB
QML
779 lines
39 KiB
QML
pragma ComponentBehavior: Bound
|
|
import QtQuick
|
|
import QtQuick.Shapes
|
|
import Quickshell
|
|
import Quickshell.Hyprland
|
|
import Quickshell.Wayland
|
|
import qs.Common
|
|
import qs.Services
|
|
import qs.Widgets
|
|
|
|
Variants {
|
|
id: dockVariants
|
|
model: SettingsData.getFilteredScreens("dock")
|
|
|
|
property var contextMenu
|
|
|
|
delegate: PanelWindow {
|
|
id: dock
|
|
|
|
WindowBlur {
|
|
targetWindow: dock
|
|
blurEnabled: dock.effectiveBlurEnabled
|
|
blurX: dockBackground.x + dockContainer.x + dockMouseArea.x + dockCore.x + dockSlide.x - dock.horizontalConnectorExtent
|
|
blurY: dockBackground.y + dockContainer.y + dockMouseArea.y + dockCore.y + dockSlide.y - dock.verticalConnectorExtent
|
|
blurWidth: dock.hasApps && dock.reveal ? dockBackground.width + dock.horizontalConnectorExtent * 2 : 0
|
|
blurHeight: dock.hasApps && dock.reveal ? dockBackground.height + dock.verticalConnectorExtent * 2 : 0
|
|
blurRadius: dock.surfaceRadius
|
|
}
|
|
|
|
WlrLayershell.namespace: "dms:dock"
|
|
|
|
readonly property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
|
|
|
anchors {
|
|
top: !isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top) : true
|
|
bottom: !isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom) : true
|
|
left: !isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Left)
|
|
right: !isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Right)
|
|
}
|
|
|
|
property var modelData: item
|
|
property bool autoHide: SettingsData.dockAutoHide || SettingsData.dockSmartAutoHide
|
|
property real backgroundTransparency: SettingsData.dockTransparency
|
|
property bool groupByApp: SettingsData.dockGroupByApp
|
|
readonly property int borderThickness: SettingsData.dockBorderEnabled ? SettingsData.dockBorderThickness : 0
|
|
readonly property string connectedBarSide: SettingsData.dockPosition === SettingsData.Position.Top ? "top"
|
|
: SettingsData.dockPosition === SettingsData.Position.Bottom ? "bottom"
|
|
: SettingsData.dockPosition === SettingsData.Position.Left ? "left" : "right"
|
|
readonly property bool connectedBarActiveOnEdge: Theme.isConnectedEffect
|
|
&& !!(dock.screen || modelData)
|
|
&& SettingsData.getActiveBarEdgesForScreen(dock.screen || modelData).includes(connectedBarSide)
|
|
readonly property real connectedJoinInset: {
|
|
if (!Theme.isConnectedEffect)
|
|
return 0;
|
|
return connectedBarActiveOnEdge ? SettingsData.frameBarSize : SettingsData.frameThickness;
|
|
}
|
|
readonly property real surfaceRadius: Theme.connectedSurfaceRadius
|
|
readonly property color surfaceColor: Theme.isConnectedEffect
|
|
? Theme.connectedSurfaceColor
|
|
: Theme.withAlpha(Theme.surfaceContainer, backgroundTransparency)
|
|
readonly property color surfaceBorderColor: Theme.isConnectedEffect ? "transparent" : BlurService.borderColor
|
|
readonly property real surfaceBorderWidth: Theme.isConnectedEffect ? 0 : BlurService.borderWidth
|
|
readonly property real surfaceTopLeftRadius: Theme.isConnectedEffect && (SettingsData.dockPosition === SettingsData.Position.Top || SettingsData.dockPosition === SettingsData.Position.Left) ? 0 : surfaceRadius
|
|
readonly property real surfaceTopRightRadius: Theme.isConnectedEffect && (SettingsData.dockPosition === SettingsData.Position.Top || SettingsData.dockPosition === SettingsData.Position.Right) ? 0 : surfaceRadius
|
|
readonly property real surfaceBottomLeftRadius: Theme.isConnectedEffect && (SettingsData.dockPosition === SettingsData.Position.Bottom || SettingsData.dockPosition === SettingsData.Position.Left) ? 0 : surfaceRadius
|
|
readonly property real surfaceBottomRightRadius: Theme.isConnectedEffect && (SettingsData.dockPosition === SettingsData.Position.Bottom || SettingsData.dockPosition === SettingsData.Position.Right) ? 0 : surfaceRadius
|
|
readonly property real horizontalConnectorExtent: Theme.isConnectedEffect && !isVertical ? Theme.connectedCornerRadius : 0
|
|
readonly property real verticalConnectorExtent: Theme.isConnectedEffect && isVertical ? Theme.connectedCornerRadius : 0
|
|
|
|
readonly property int hasApps: dockApps.implicitWidth > 0 || dockApps.implicitHeight > 0
|
|
|
|
readonly property real widgetHeight: SettingsData.dockIconSize
|
|
readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10 + borderThickness * 2
|
|
function getBarHeight(barConfig) {
|
|
if (!barConfig)
|
|
return 0;
|
|
const innerPadding = barConfig.innerPadding ?? 4;
|
|
const widgetThickness = Math.max(20, 26 + innerPadding * 0.6);
|
|
const barThickness = Math.max(widgetThickness + innerPadding + 4, Theme.barHeight - 4 - (8 - innerPadding));
|
|
const spacing = barConfig.spacing ?? 4;
|
|
const bottomGap = barConfig.bottomGap ?? 0;
|
|
return barThickness + spacing + bottomGap;
|
|
}
|
|
|
|
readonly property real barSpacing: {
|
|
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
|
|
if (!defaultBar)
|
|
return 0;
|
|
|
|
const barPos = defaultBar.position ?? SettingsData.Position.Top;
|
|
const barIsHorizontal = (barPos === SettingsData.Position.Top || barPos === SettingsData.Position.Bottom);
|
|
const barIsVertical = (barPos === SettingsData.Position.Left || barPos === SettingsData.Position.Right);
|
|
const samePosition = (SettingsData.dockPosition === barPos);
|
|
const dockIsHorizontal = !isVertical;
|
|
const dockIsVertical = isVertical;
|
|
|
|
if (!(defaultBar.visible ?? true))
|
|
return 0;
|
|
const spacing = defaultBar.spacing ?? 4;
|
|
const bottomGap = defaultBar.bottomGap ?? 0;
|
|
if (dockIsHorizontal && barIsHorizontal && samePosition) {
|
|
return spacing + effectiveBarHeight + bottomGap;
|
|
}
|
|
if (dockIsVertical && barIsVertical && samePosition) {
|
|
return spacing + effectiveBarHeight + bottomGap;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
readonly property real adjacentTopBarHeight: {
|
|
if (!isVertical || autoHide)
|
|
return 0;
|
|
const screenName = dock.modelData?.name ?? "";
|
|
const topBar = SettingsData.barConfigs.find(bc => {
|
|
if (!bc.enabled || bc.autoHide || !(bc.visible ?? true))
|
|
return false;
|
|
if (bc.position !== SettingsData.Position.Top && bc.position !== 0)
|
|
return false;
|
|
const onThisScreen = bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all") || bc.screenPreferences.includes(screenName);
|
|
return onThisScreen;
|
|
});
|
|
return getBarHeight(topBar);
|
|
}
|
|
|
|
readonly property real adjacentLeftBarWidth: {
|
|
if (isVertical || autoHide)
|
|
return 0;
|
|
const screenName = dock.modelData?.name ?? "";
|
|
const leftBar = SettingsData.barConfigs.find(bc => {
|
|
if (!bc.enabled || bc.autoHide || !(bc.visible ?? true))
|
|
return false;
|
|
if (bc.position !== SettingsData.Position.Left && bc.position !== 2)
|
|
return false;
|
|
const onThisScreen = bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all") || bc.screenPreferences.includes(screenName);
|
|
return onThisScreen;
|
|
});
|
|
return getBarHeight(leftBar);
|
|
}
|
|
|
|
readonly property real dockMargin: SettingsData.dockMargin
|
|
readonly property bool effectiveBlurEnabled: Theme.connectedSurfaceBlurEnabled
|
|
readonly property real effectiveDockBottomGap: Theme.isConnectedEffect ? 0 : SettingsData.dockBottomGap
|
|
readonly property real effectiveDockMargin: Theme.isConnectedEffect ? 0 : SettingsData.dockMargin
|
|
readonly property real positionSpacing: barSpacing + effectiveDockBottomGap + effectiveDockMargin
|
|
readonly property real joinedEdgeMargin: Theme.isConnectedEffect ? 0 : (barSpacing + effectiveDockMargin + 1 + dock.borderThickness)
|
|
readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
|
|
function px(v) {
|
|
return Math.round(v * _dpr) / _dpr;
|
|
}
|
|
|
|
function connectorWidth(spacing) {
|
|
return dock.isVertical ? (spacing + Theme.connectedCornerRadius) : Theme.connectedCornerRadius;
|
|
}
|
|
|
|
function connectorHeight(spacing) {
|
|
return dock.isVertical ? Theme.connectedCornerRadius : (spacing + Theme.connectedCornerRadius);
|
|
}
|
|
|
|
function connectorSeamX(baseX, bodyWidth, placement) {
|
|
if (!dock.isVertical)
|
|
return placement === "left" ? baseX : baseX + bodyWidth;
|
|
return SettingsData.dockPosition === SettingsData.Position.Left ? baseX : baseX + bodyWidth;
|
|
}
|
|
|
|
function connectorSeamY(baseY, bodyHeight, placement) {
|
|
if (SettingsData.dockPosition === SettingsData.Position.Top)
|
|
return baseY;
|
|
if (SettingsData.dockPosition === SettingsData.Position.Bottom)
|
|
return baseY + bodyHeight;
|
|
return placement === "left" ? baseY : baseY + bodyHeight;
|
|
}
|
|
|
|
function connectorX(baseX, bodyWidth, placement, spacing) {
|
|
const seamX = connectorSeamX(baseX, bodyWidth, placement);
|
|
const width = connectorWidth(spacing);
|
|
if (!dock.isVertical)
|
|
return placement === "left" ? seamX - width : seamX;
|
|
return SettingsData.dockPosition === SettingsData.Position.Left ? seamX : seamX - width;
|
|
}
|
|
|
|
function connectorY(baseY, bodyHeight, placement, spacing) {
|
|
const seamY = connectorSeamY(baseY, bodyHeight, placement);
|
|
const height = connectorHeight(spacing);
|
|
if (SettingsData.dockPosition === SettingsData.Position.Top)
|
|
return seamY;
|
|
if (SettingsData.dockPosition === SettingsData.Position.Bottom)
|
|
return seamY - height;
|
|
return placement === "left" ? seamY - height : seamY;
|
|
}
|
|
|
|
property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData)
|
|
property bool revealSticky: false
|
|
|
|
readonly property bool shouldHideForWindows: {
|
|
if (!SettingsData.dockSmartAutoHide)
|
|
return false;
|
|
if (!CompositorService.isNiri && !CompositorService.isHyprland)
|
|
return false;
|
|
|
|
const screenName = dock.modelData?.name ?? "";
|
|
const dockThickness = dock.connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin;
|
|
const screenWidth = dock.screen?.width ?? 0;
|
|
const screenHeight = dock.screen?.height ?? 0;
|
|
|
|
if (CompositorService.isNiri) {
|
|
NiriService.windows;
|
|
|
|
let currentWorkspaceId = null;
|
|
for (let i = 0; i < NiriService.allWorkspaces.length; i++) {
|
|
const ws = NiriService.allWorkspaces[i];
|
|
if (ws.output === screenName && ws.is_active) {
|
|
currentWorkspaceId = ws.id;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (currentWorkspaceId === null)
|
|
return false;
|
|
|
|
for (let i = 0; i < NiriService.windows.length; i++) {
|
|
const win = NiriService.windows[i];
|
|
if (win.workspace_id !== currentWorkspaceId)
|
|
continue;
|
|
|
|
// Get window position and size from layout data
|
|
const tilePos = win.layout?.tile_pos_in_workspace_view;
|
|
const winSize = win.layout?.window_size || win.layout?.tile_size;
|
|
|
|
if (tilePos && winSize) {
|
|
const winX = tilePos[0];
|
|
const winY = tilePos[1];
|
|
const winW = winSize[0];
|
|
const winH = winSize[1];
|
|
|
|
switch (SettingsData.dockPosition) {
|
|
case SettingsData.Position.Top:
|
|
if (winY < dockThickness)
|
|
return true;
|
|
break;
|
|
case SettingsData.Position.Bottom:
|
|
if (winY + winH > screenHeight - dockThickness)
|
|
return true;
|
|
break;
|
|
case SettingsData.Position.Left:
|
|
if (winX < dockThickness)
|
|
return true;
|
|
break;
|
|
case SettingsData.Position.Right:
|
|
if (winX + winW > screenWidth - dockThickness)
|
|
return true;
|
|
break;
|
|
}
|
|
} else if (!win.is_floating) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Hyprland implementation
|
|
Hyprland.focusedWorkspace;
|
|
const filtered = CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName);
|
|
|
|
if (filtered.length === 0)
|
|
return false;
|
|
|
|
for (let i = 0; i < filtered.length; i++) {
|
|
const toplevel = filtered[i];
|
|
|
|
let hyprToplevel = null;
|
|
if (Hyprland.toplevels) {
|
|
const hyprToplevels = Array.from(Hyprland.toplevels.values);
|
|
for (let j = 0; j < hyprToplevels.length; j++) {
|
|
if (hyprToplevels[j].wayland === toplevel) {
|
|
hyprToplevel = hyprToplevels[j];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hyprToplevel?.lastIpcObject)
|
|
continue;
|
|
|
|
const ipc = hyprToplevel.lastIpcObject;
|
|
const at = ipc.at;
|
|
const size = ipc.size;
|
|
if (!at || !size)
|
|
continue;
|
|
|
|
const monX = hyprToplevel.monitor?.x ?? 0;
|
|
const monY = hyprToplevel.monitor?.y ?? 0;
|
|
|
|
const winX = at[0] - monX;
|
|
const winY = at[1] - monY;
|
|
const winW = size[0];
|
|
const winH = size[1];
|
|
|
|
switch (SettingsData.dockPosition) {
|
|
case SettingsData.Position.Top:
|
|
if (winY < dockThickness)
|
|
return true;
|
|
break;
|
|
case SettingsData.Position.Bottom:
|
|
if (winY + winH > screenHeight - dockThickness)
|
|
return true;
|
|
break;
|
|
case SettingsData.Position.Left:
|
|
if (winX < dockThickness)
|
|
return true;
|
|
break;
|
|
case SettingsData.Position.Right:
|
|
if (winX + winW > screenWidth - dockThickness)
|
|
return true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Timer {
|
|
id: revealHold
|
|
interval: 250
|
|
repeat: false
|
|
onTriggered: dock.revealSticky = false
|
|
}
|
|
|
|
property bool reveal: {
|
|
if (CompositorService.isNiri && NiriService.inOverview && SettingsData.dockOpenOnOverview) {
|
|
return true;
|
|
}
|
|
|
|
// Smart auto-hide: show dock when no windows overlap, hide when they do
|
|
if (SettingsData.dockSmartAutoHide) {
|
|
if (shouldHideForWindows)
|
|
return dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky;
|
|
return true; // No overlapping windows - show dock
|
|
}
|
|
|
|
// Regular auto-hide: always hide unless hovering
|
|
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(connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + effectiveDockBottomGap + effectiveDockMargin);
|
|
}
|
|
|
|
property real animationHeadroom: Math.ceil(SettingsData.dockIconSize * 0.35)
|
|
|
|
implicitWidth: isVertical ? (px(connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + effectiveDockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
|
|
implicitHeight: !isVertical ? (px(connectedJoinInset + effectiveBarHeight + SettingsData.dockSpacing + effectiveDockMargin + SettingsData.dockIconSize * 0.3) + animationHeadroom) : 0
|
|
|
|
Item {
|
|
id: maskItem
|
|
parent: dock.contentItem
|
|
visible: false
|
|
readonly property bool expanded: dock.reveal
|
|
x: {
|
|
const baseX = dockCore.x + dockMouseArea.x;
|
|
if (isVertical && SettingsData.dockPosition === SettingsData.Position.Right)
|
|
return baseX - (expanded ? animationHeadroom + borderThickness + dock.horizontalConnectorExtent : 0);
|
|
return baseX - (expanded ? borderThickness + dock.horizontalConnectorExtent : 0);
|
|
}
|
|
y: {
|
|
const baseY = dockCore.y + dockMouseArea.y;
|
|
if (!isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom)
|
|
return baseY - (expanded ? animationHeadroom + borderThickness + dock.verticalConnectorExtent : 0);
|
|
return baseY - (expanded ? borderThickness + dock.verticalConnectorExtent : 0);
|
|
}
|
|
width: dockMouseArea.width + (isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 + dock.horizontalConnectorExtent * 2 : 0)
|
|
height: dockMouseArea.height + (!isVertical && expanded ? animationHeadroom : 0) + (expanded ? borderThickness * 2 + dock.verticalConnectorExtent * 2 : 0)
|
|
}
|
|
|
|
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)
|
|
return;
|
|
|
|
const buttonGlobalPos = dock.hoveredButton.mapToGlobal(0, 0);
|
|
const tooltipText = dock.hoveredButton.tooltipText || "";
|
|
if (!tooltipText)
|
|
return;
|
|
|
|
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;
|
|
|
|
const gap = Theme.spacingS;
|
|
const bgMargin = dock.joinedEdgeMargin + dock.connectedJoinInset;
|
|
const btnW = dock.hoveredButton.width;
|
|
const btnH = dock.hoveredButton.height;
|
|
|
|
if (!dock.isVertical) {
|
|
const isBottom = SettingsData.dockPosition === SettingsData.Position.Bottom;
|
|
const globalX = buttonGlobalPos.x + btnW / 2 + adjacentLeftBarWidth;
|
|
const tooltipHeight = 32;
|
|
const totalFromEdge = bgMargin + dockBackground.height + dock.borderThickness + gap;
|
|
const screenRelativeY = isBottom ? (screenHeight - totalFromEdge - tooltipHeight) : totalFromEdge;
|
|
dockTooltip.show(tooltipText, globalX, screenRelativeY, dock.screen, false, false);
|
|
return;
|
|
}
|
|
|
|
const isLeft = SettingsData.dockPosition === SettingsData.Position.Left;
|
|
const screenWidth = dock.screen ? dock.screen.width : 0;
|
|
const totalFromEdge = bgMargin + dockBackground.width + dock.borderThickness + gap;
|
|
const tooltipX = isLeft ? (screenX + totalFromEdge) : (screenX + screenWidth - totalFromEdge);
|
|
const screenRelativeY = buttonGlobalPos.y - screenY + btnH / 2 + adjacentTopBarHeight;
|
|
dockTooltip.show(tooltipText, 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 {
|
|
target: dockMouseArea
|
|
function onContainsMouseChanged() {
|
|
if (dockMouseArea.containsMouse) {
|
|
dock.revealSticky = true;
|
|
revealHold.stop();
|
|
} else {
|
|
if (dock.autoHide && !dock.contextMenuOpen) {
|
|
revealHold.restart();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: dockMouseArea
|
|
property real currentScreen: modelData ? modelData : dock.screen
|
|
property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920
|
|
property real screenHeight: currentScreen ? currentScreen.geometry.height : 1080
|
|
property real maxDockWidth: screenWidth * 0.98
|
|
property real maxDockHeight: screenHeight * 0.98
|
|
|
|
height: {
|
|
if (dock.isVertical) {
|
|
// Keep the taller hit area regardless of the reveal state to prevent shrinking loop
|
|
return Math.min(Math.max(dockBackground.height + 64, 200), maxDockHeight);
|
|
}
|
|
return dock.reveal ? px(dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin) : 1;
|
|
}
|
|
width: {
|
|
if (dock.isVertical) {
|
|
return dock.reveal ? px(dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin) : 1;
|
|
}
|
|
// Keep the wider hit area regardless of the reveal state to prevent shrinking loop
|
|
return Math.min(dockBackground.width + 8 + dock.borderThickness, maxDockWidth);
|
|
}
|
|
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 {
|
|
id: dockContainer
|
|
anchors.fill: parent
|
|
clip: false
|
|
|
|
transform: Translate {
|
|
id: dockSlide
|
|
x: {
|
|
if (!dock.isVertical)
|
|
return 0;
|
|
if (dock.reveal)
|
|
return 0;
|
|
const hideDistance = dock.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin + 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.connectedJoinInset + dock.effectiveBarHeight + SettingsData.dockSpacing + dock.effectiveDockBottomGap + dock.effectiveDockMargin + 10;
|
|
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
|
|
return hideDistance;
|
|
} else {
|
|
return -hideDistance;
|
|
}
|
|
}
|
|
|
|
Behavior on x {
|
|
NumberAnimation {
|
|
id: slideXAnimation
|
|
duration: Theme.isConnectedEffect
|
|
? Theme.variantDuration(Theme.popoutAnimationDuration, dock.reveal)
|
|
: Theme.shortDuration
|
|
easing.type: Theme.isConnectedEffect ? Easing.BezierSpline : Easing.OutCubic
|
|
easing.bezierCurve: Theme.isConnectedEffect
|
|
? (dock.reveal ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve)
|
|
: []
|
|
}
|
|
}
|
|
|
|
Behavior on y {
|
|
NumberAnimation {
|
|
id: slideYAnimation
|
|
duration: Theme.isConnectedEffect
|
|
? Theme.variantDuration(Theme.popoutAnimationDuration, dock.reveal)
|
|
: Theme.shortDuration
|
|
easing.type: Theme.isConnectedEffect ? Easing.BezierSpline : Easing.OutCubic
|
|
easing.bezierCurve: Theme.isConnectedEffect
|
|
? (dock.reveal ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve)
|
|
: []
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
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 ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
|
|
anchors.bottomMargin: !dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Bottom ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
|
|
anchors.leftMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Left ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 0
|
|
anchors.rightMargin: dock.isVertical && SettingsData.dockPosition === SettingsData.Position.Right ? (dock.connectedJoinInset + dock.joinedEdgeMargin) : 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
|
|
|
|
// Avoid an offscreen texture seam where the connected dock meets the frame.
|
|
layer.enabled: !Theme.isConnectedEffect
|
|
clip: false
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: dock.surfaceColor
|
|
topLeftRadius: dock.surfaceTopLeftRadius
|
|
topRightRadius: dock.surfaceTopRightRadius
|
|
bottomLeftRadius: dock.surfaceBottomLeftRadius
|
|
bottomRightRadius: dock.surfaceBottomRightRadius
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: "transparent"
|
|
topLeftRadius: dock.surfaceTopLeftRadius
|
|
topRightRadius: dock.surfaceTopRightRadius
|
|
bottomLeftRadius: dock.surfaceBottomLeftRadius
|
|
bottomRightRadius: dock.surfaceBottomRightRadius
|
|
border.color: dock.surfaceBorderColor
|
|
border.width: dock.surfaceBorderWidth
|
|
z: 100
|
|
}
|
|
}
|
|
|
|
ConnectedCorner {
|
|
visible: Theme.isConnectedEffect && dock.reveal
|
|
barSide: dock.connectedBarSide
|
|
placement: "left"
|
|
spacing: 0
|
|
connectorRadius: Theme.connectedCornerRadius
|
|
color: dock.surfaceColor
|
|
x: Theme.snap(dock.connectorX(dockBackground.x, dockBackground.width, placement, spacing), dock._dpr)
|
|
y: Theme.snap(dock.connectorY(dockBackground.y, dockBackground.height, placement, spacing), dock._dpr)
|
|
}
|
|
|
|
ConnectedCorner {
|
|
visible: Theme.isConnectedEffect && dock.reveal
|
|
barSide: dock.connectedBarSide
|
|
placement: "right"
|
|
spacing: 0
|
|
connectorRadius: Theme.connectedCornerRadius
|
|
color: dock.surfaceColor
|
|
x: Theme.snap(dock.connectorX(dockBackground.x, dockBackground.width, placement, spacing), dock._dpr)
|
|
y: Theme.snap(dock.connectorY(dockBackground.y, dockBackground.height, placement, spacing), dock._dpr)
|
|
}
|
|
|
|
Shape {
|
|
id: dockBorderShape
|
|
x: dockBackground.x - borderThickness
|
|
y: dockBackground.y - borderThickness
|
|
width: dockBackground.width + borderThickness * 2
|
|
height: dockBackground.height + borderThickness * 2
|
|
visible: SettingsData.dockBorderEnabled && dock.hasApps && !Theme.isConnectedEffect
|
|
preferredRendererType: Shape.CurveRenderer
|
|
|
|
readonly property real borderThickness: Math.max(1, dock.borderThickness)
|
|
readonly property real i: borderThickness / 2
|
|
readonly property real cr: dock.surfaceRadius
|
|
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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|