diff --git a/panels/dock/constants.h b/panels/dock/constants.h index bf3cb9372..69fc3823b 100644 --- a/panels/dock/constants.h +++ b/panels/dock/constants.h @@ -1,6 +1,6 @@ // Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd. // SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: LGPL-3.0-or-later @@ -36,6 +36,7 @@ enum IndicatorStyle { enum ItemAlignment { CenterAlignment = 0, LeftAlignment = 1, + FashionAlignment = 2, }; enum ColorTheme { diff --git a/panels/dock/docksettings.cpp b/panels/dock/docksettings.cpp index ac78af46f..575b60ccf 100644 --- a/panels/dock/docksettings.cpp +++ b/panels/dock/docksettings.cpp @@ -85,6 +85,8 @@ static QString itemAlignment2String(const ItemAlignment& alignment) return "left"; case ItemAlignment::CenterAlignment: return "center"; + case ItemAlignment::FashionAlignment: + return "fashion"; } return "center"; @@ -111,6 +113,8 @@ static ItemAlignment string2ItenAlignment(const QString& alignmentStr) return ItemAlignment::LeftAlignment; else if (alignmentStr == "center") return ItemAlignment::CenterAlignment; + else if (alignmentStr == "fashion") + return ItemAlignment::FashionAlignment; return ItemAlignment::CenterAlignment; } diff --git a/panels/dock/package/FashionDockController.qml b/panels/dock/package/FashionDockController.qml new file mode 100644 index 000000000..d6e80a810 --- /dev/null +++ b/panels/dock/package/FashionDockController.qml @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.15 + +import org.deepin.ds 1.0 +import org.deepin.ds.dock 1.0 +import org.deepin.dtk.style 1.0 as DStyle + +QtObject { + id: root + + property bool useColumnLayout: false + property int itemAlignment: Dock.CenterAlignment + property int position: Dock.Bottom + property int hideState: Dock.Show + property real dockSize: 0 + property real dockItemIconSize: 0 + property real devicePixelRatio: 1 + property int screenWidth: 0 + property int colorTheme: Dock.Light + property bool dragging: false + property var gridLayout: null + property var rightPart: null + + readonly property bool enabled: !useColumnLayout + && itemAlignment === Dock.FashionAlignment + && (position === Dock.Bottom || position === Dock.Top) + readonly property bool topMode: enabled && position === Dock.Top + readonly property bool bottomMode: enabled && position === Dock.Bottom + readonly property int floatingMargin: 8 + readonly property int verticalPadding: Math.max(6, Math.round(dockSize * 0.16)) + readonly property int surfaceThickness: useColumnLayout ? dockSize : dockSize + verticalPadding * 2 + readonly property int backgroundRadius: Math.round(surfaceThickness / 4) + readonly property real gridDisplayedWidth: enabled && gridLayout + ? gridLayout.implicitWidth + : 0 + readonly property real gridDisplayedHeight: enabled && gridLayout + ? gridLayout.implicitHeight + : 0 + readonly property real contentWidth: { + if (!enabled) { + return 0 + } + + let width = gridDisplayedWidth + if (rightPart && rightPart.visible) { + if (width > 0) { + width += gridLayout.columnSpacing + } + width += rightPart.implicitWidth + } + return width + } + readonly property bool widthAnimationEnabled: enabled && !dragging + + function effectiveShellWidth() { + if (!enabled) { + return 0 + } + + return Math.min(contentWidth, screenWidth) + } +} diff --git a/panels/dock/package/main.qml b/panels/dock/package/main.qml index ded6c54e4..d033634ed 100644 --- a/panels/dock/package/main.qml +++ b/panels/dock/package/main.qml @@ -13,19 +13,42 @@ import Qt.labs.platform as LP import org.deepin.ds 1.0 import org.deepin.ds.dock 1.0 import org.deepin.dtk 1.0 as D -import org.deepin.dtk.style 1.0 as DStyle Window { id: dock property int positionForAnimation: Panel.position property bool useColumnLayout: positionForAnimation % 2 + + FashionDockController { + id: fashionDockController + useColumnLayout: dock.useColumnLayout + itemAlignment: Panel.itemAlignment + position: dock.positionForAnimation + hideState: Panel.hideState + dockSize: dock.dockSize + dockItemIconSize: dock.dockItemIconSize + devicePixelRatio: Panel.devicePixelRatio > 0 ? Panel.devicePixelRatio : Screen.devicePixelRatio + screenWidth: Screen.width + colorTheme: Panel.colorTheme + dragging: dock.isDragging + gridLayout: gridLayout + rightPart: dockRightPart + } + + property alias fashionDock: fashionDockController property int dockCenterPartCount: dockCenterPartModel.count readonly property int dockRawCenterSpace: { if (useColumnLayout) { return Screen.height - dockLeftPart.implicitHeight - dockRightPart.implicitHeight; } else { - return Screen.width - dockLeftPart.implicitWidth - dockRightPart.implicitWidth; + let space = Screen.width - dockLeftPart.implicitWidth - dockRightPart.implicitWidth; + if (fashionDock.enabled && gridLayout) { + // 时尚模式下,dockRightPart 在 gridLayout 右侧,之间需要扣除 dockSpacing + // 这是为了确保 gridLayout 的宽度 + dockSpacing + rightPart 宽度 <= screenWidth + space -= Math.ceil(gridLayout.columnSpacing); + } + return Math.max(0, space); } } @@ -45,7 +68,13 @@ Window { property real dockItemIconSize: dockItemMaxSize * 9 / 14 // NOTE: -1 means not set its size, follow the platform size - width: positionForAnimation === Dock.Top || positionForAnimation === Dock.Bottom ? -1 : dockSize + width: { + if (fashionDock.enabled) { + return Math.max(1, fashionDock.effectiveShellWidth()) + } + + return positionForAnimation === Dock.Top || positionForAnimation === Dock.Bottom ? -1 : dockSize + } height: positionForAnimation === Dock.Left || positionForAnimation === Dock.Right ? -1 : dockSize color: "transparent" flags: Qt.WindowDoesNotAcceptFocus @@ -65,14 +94,21 @@ Window { MenuHelper.openMenu(dockMenuLoader.item) } - DLayerShellWindow.anchors: position2Anchors(positionForAnimation) + DLayerShellWindow.anchors: fashionDock.enabled + ? (fashionDock.topMode ? DLayerShellWindow.AnchorTop : DLayerShellWindow.AnchorBottom) + : position2Anchors(positionForAnimation) + DLayerShellWindow.topMargin: fashionDock.topMode ? fashionDock.floatingMargin : 0 + + DLayerShellWindow.bottomMargin: fashionDock.bottomMode ? fashionDock.floatingMargin : 0 DLayerShellWindow.layer: DLayerShellWindow.LayerTop - DLayerShellWindow.exclusionZone: Panel.hideMode === Dock.KeepShowing ? Applet.dockSize : 0 + DLayerShellWindow.exclusionZone: Panel.hideMode === Dock.KeepShowing + ? Applet.dockSize + (fashionDock.enabled ? fashionDock.floatingMargin : 0) + : 0 DLayerShellWindow.scope: "dde-shell/dock" DLayerShellWindow.keyboardInteractivity: DLayerShellWindow.KeyboardInteractivityOnDemand D.DWindow.enabled: true - D.DWindow.windowRadius: 0 + D.DWindow.windowRadius: fashionDock.enabled ? fashionDock.backgroundRadius : 0 //TODO:由于windoweffect处理有BUG,导致动画结束后一致保持无阴影,无borderwidth状态。 无法恢复到最初的阴影和边框 //D.DWindow.windowEffect: hideShowAnimation.running ? D.PlatformHandle.EffectNoShadow | D.PlatformHandle.EffectNoBorder : 0 @@ -89,12 +125,21 @@ Window { D.ColorSelector.family: D.Palette.CrystalColor onDockSizeChanged: { - if (dock.dockSize === Dock.MIN_DOCK_SIZE) { + if (fashionDock.enabled) { + Panel.indicatorStyle = Dock.Fashion + } else if (dock.dockSize === Dock.MIN_DOCK_SIZE) { Panel.indicatorStyle = Dock.Efficient } else { Panel.indicatorStyle = Dock.Fashion } } + Behavior on width { + enabled: fashionDock.widthAnimationEnabled + NumberAnimation { + duration: 200 + easing.type: Easing.OutQuad + } + } Binding on itemIconSizeBase { when: !isDragging @@ -326,6 +371,11 @@ Window { prop: "itemAlignment" value: Dock.CenterAlignment } + EnumPropertyMenuItem { + name: qsTr("Fashion Mode") + prop: "itemAlignment" + value: Dock.FashionAlignment + } } MutuallyExclusiveMenu { title: qsTr("Position") @@ -401,7 +451,7 @@ Window { D.StyledBehindWindowBlur { control: parent anchors.fill: parent - cornerRadius: 0 + cornerRadius: fashionDock.enabled ? fashionDock.backgroundRadius : 0 blendColor: { if (valid) { return DStyle.Style.control.selectColor(undefined, @@ -476,7 +526,7 @@ Window { //此处为边距区域的点击实践特殊处理。 MouseArea { id: leftMarginArea - width: useColumnLayout ? parent.width : gridLayout.columnSpacing + width: useColumnLayout ? parent.width : (fashionDock.enabled ? 0 : gridLayout.columnSpacing) height: useColumnLayout ? gridLayout.rowSpacing : parent.height anchors.left: parent.left anchors.top: parent.top @@ -505,13 +555,14 @@ Window { Item { id: leftMargin + visible: !fashionDock.enabled implicitWidth: 0 implicitHeight: 0 } Item { id: dockLeftPart - visible: dockLeftPartModel.count > 0 + visible: !fashionDock.enabled && dockLeftPartModel.count > 0 implicitWidth: leftLoader.implicitWidth implicitHeight: leftLoader.implicitHeight OverflowContainer { @@ -534,7 +585,7 @@ Window { Layout.maximumHeight: useColumnLayout ? dockRawCenterSpace : -1 onXChanged: dockCenterPartPosChanged() onYChanged: dockCenterPartPosChanged() - Layout.leftMargin: !useColumnLayout && Panel.itemAlignment === Dock.CenterAlignment ? + Layout.leftMargin: !useColumnLayout && !fashionDock.enabled && Panel.itemAlignment === Dock.CenterAlignment ? Math.max(0, (dock.width - dockCenterPart.implicitWidth) / 2 - (dockLeftPart.implicitWidth + 20) + Math.min((dock.width - dockCenterPart.implicitWidth) / 2 - (dockRightPart.implicitWidth + 20), 0)) : 0 Layout.topMargin: useColumnLayout && Panel.itemAlignment === Dock.CenterAlignment ? Math.max(0, (dock.height - dockCenterPart.implicitHeight) / 2 - (dockLeftPart.implicitHeight + 20) + Math.min((dock.height - dockCenterPart.implicitHeight) / 2 - (dockRightPart.implicitHeight + 20), 0)) : 0 @@ -569,8 +620,9 @@ Window { } Item { - Layout.fillWidth: true - Layout.fillHeight: true + Layout.fillWidth: !fashionDock.enabled + Layout.fillHeight: !fashionDock.enabled + visible: !fashionDock.enabled } } diff --git a/panels/dock/showdesktop/package/showdesktop.qml b/panels/dock/showdesktop/package/showdesktop.qml index cd3b18932..e0230b7ba 100644 --- a/panels/dock/showdesktop/package/showdesktop.qml +++ b/panels/dock/showdesktop/package/showdesktop.qml @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -13,11 +13,13 @@ AppletItem { id: showdesktop readonly property int showDesktopWidth: 10 property bool useColumnLayout: Panel.position % 2 + readonly property bool fashionMode: Panel.rootObject && Panel.rootObject.fashionDock && Panel.rootObject.fashionDock.enabled property int dockSize: Panel.rootObject.dockItemMaxSize property int dockOrder: 30 - property bool shouldVisible: Applet.visible - implicitWidth: useColumnLayout ? Panel.rootObject.dockSize : showDesktopWidth - implicitHeight: useColumnLayout ? showDesktopWidth : Panel.rootObject.dockSize + property bool shouldVisible: Applet.visible && !fashionMode + visible: shouldVisible + implicitWidth: shouldVisible ? (useColumnLayout ? Panel.rootObject.dockSize : showDesktopWidth) : 0 + implicitHeight: shouldVisible ? (useColumnLayout ? showDesktopWidth : Panel.rootObject.dockSize) : 0 PanelToolTip { id: toolTip diff --git a/panels/dock/taskmanager/package/TaskManager.qml b/panels/dock/taskmanager/package/TaskManager.qml index 130bbc1be..30e30d4e3 100644 --- a/panels/dock/taskmanager/package/TaskManager.qml +++ b/panels/dock/taskmanager/package/TaskManager.qml @@ -14,6 +14,8 @@ ContainmentItem { id: taskmanager property bool useColumnLayout: Panel.rootObject.useColumnLayout property int dockOrder: 16 + readonly property bool fashionMode: Panel.rootObject && Panel.rootObject.fashionDock && Panel.rootObject.fashionDock.enabled + readonly property bool horizontalFashionMode: fashionMode && !useColumnLayout function calcRemainingSpace(baseSize) { const otherCount = Panel.rootObject.dockCenterPartCount - 1; @@ -21,7 +23,9 @@ ContainmentItem { return Panel.rootObject.dockRawCenterSpace - otherOccupied; } - readonly property real remainingSpacesForTaskManager: calcRemainingSpace(Panel.rootObject.dockItemMaxSize) + property real remainingSpacesForTaskManager: fashionMode + ? 0 + : calcRemainingSpace(Panel.rootObject.dockItemMaxSize) readonly property int appTitleSpacing: Math.max(10, Math.round(Panel.rootObject.dockItemMaxSize * 9 / 14) / 3) // Start padding for the app container so that the visual gap // (multitask icon right edge → first app icon left edge) = appTitleSpacing. @@ -37,12 +41,14 @@ ContainmentItem { readonly property real startPadding: Math.max(0, appTitleSpacing - (Panel.rootObject.dockItemMaxSize * (multitaskViewIconRatio - iconWidthToMaxSizeRatio) / 2)) implicitWidth: { + if (horizontalFashionMode) return appContainer.implicitWidth + (useColumnLayout ? 0 : startPadding) let extra = useColumnLayout ? 0 : startPadding let w = appContainer.implicitWidth + extra let maxW = Panel.itemAlignment === Dock.LeftAlignment ? Math.max(remainingSpacesForTaskManager, w) : Math.min(remainingSpacesForTaskManager, w) return useColumnLayout ? Panel.rootObject.dockSize : maxW } implicitHeight: { + if (fashionMode && useColumnLayout) return appContainer.implicitHeight + (useColumnLayout ? startPadding : 0) let extra = useColumnLayout ? startPadding : 0 let h = appContainer.implicitHeight + extra let maxH = Panel.itemAlignment === Dock.LeftAlignment ? Math.max(remainingSpacesForTaskManager, h) : Math.min(remainingSpacesForTaskManager, h) @@ -81,7 +87,7 @@ ContainmentItem { TextCalculator { id: textCalculator - enabled: taskmanager.Applet.windowSplit && (Panel.position == Dock.Bottom || Panel.position == Dock.Top) + enabled: !fashionMode && taskmanager.Applet.windowSplit && (Panel.position == Dock.Bottom || Panel.position == Dock.Top) dataModel: taskmanager.Applet.dataModel iconSize: Panel.rootObject.dockSize * 9 / 14 spacing: Math.max(10, Math.round(textCalculator.iconSize) / 3)