diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b2471dc..636745d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ set(SOURCE_FILES launchercontroller.cpp launchercontroller.h debughelper.cpp debughelper.h inputeventitem.h inputeventitem.cpp + src/quick/painteddciicon.h src/quick/painteddciicon.cpp ) set(QML_FILES diff --git a/qml/Helper.qml b/qml/Helper.qml index 52bc45a5..2fd78824 100644 --- a/qml/Helper.qml +++ b/qml/Helper.qml @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -40,6 +40,12 @@ QtObject { } } + // Snap a logical pixel value so that value * DPR lands on an integer + // physical pixel, avoiding sub-pixel texture sampling blur in Scene Graph. + function pixelAligned(value, dpr) { + return Math.round(value * dpr) / dpr + } + function generateDragMimeData(desktopId, dockOnly = false) { // In some cases an app is not allowed to be pinned onto dock via drag-n-drop; // We only insert the MIME data for dde-dock in those allowed cases. diff --git a/qml/windowed/BottomBar.qml b/qml/windowed/BottomBar.qml index 77cf0f07..a1c5ca28 100644 --- a/qml/windowed/BottomBar.qml +++ b/qml/windowed/BottomBar.qml @@ -1,10 +1,11 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Controls 2.15 +import QtQuick.Window 2.15 import org.deepin.dtk 1.0 import org.deepin.ds 1.0 import org.deepin.dtk.style 1.0 as DStyle @@ -20,12 +21,17 @@ Control { property Item nextKeyTabTarget property alias searchEdit: searchEdit - padding: 10 + padding: Helper.pixelAligned(10, Screen.devicePixelRatio) contentItem: RowLayout { ToolButton { id: shutdownBtn - icon.name: "shutdown" + contentItem: PaintedDciIcon { + name: "shutdown" + sourceSize: Qt.size(16, 16) + width: 16 + height: 16 + } background: ItemBackground { button: shutdownBtn } @@ -95,7 +101,12 @@ Control { ToolButton { id: fullscreenBtn - icon.name: "launcher_fullscreen" + contentItem: PaintedDciIcon { + name: "launcher_fullscreen" + sourceSize: Qt.size(16, 16) + width: 16 + height: 16 + } background: ItemBackground { button: fullscreenBtn } diff --git a/qml/windowed/SideBar.qml b/qml/windowed/SideBar.qml index 215a0cc5..60d9b432 100644 --- a/qml/windowed/SideBar.qml +++ b/qml/windowed/SideBar.qml @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -15,7 +15,7 @@ import org.deepin.launchpad 1.0 import org.deepin.launchpad.models 1.0 ColumnLayout { - spacing: 10 + spacing: Helper.pixelAligned(10, Screen.devicePixelRatio) property bool isFreeSort: CategorizedSortProxyModel.categoryType === CategorizedSortProxyModel.FreeCategory property Item keyTabTarget: title @@ -92,27 +92,29 @@ ColumnLayout { KeyNavigation.down: computer KeyNavigation.up: setting KeyNavigation.tab: nextKeyTabTarget - topPadding: 7 - bottomPadding: 5 + topPadding: Helper.pixelAligned(7, Screen.devicePixelRatio) + bottomPadding: Helper.pixelAligned(5, Screen.devicePixelRatio) ToolTip.visible: hovered ToolTip.delay: 500 ToolTip.text: qsTr("Sorting Mode") contentItem: ColumnLayout { spacing: 2 - D.DciIcon { + PaintedDciIcon { sourceSize: Qt.size(16, 16) + width: 16 + height: 16 name: isFreeSort ? categorizedIcon("freeSort") : categorizedIcon(CategorizedSortProxyModel.categoryType) - palette: D.DTK.makeIconPalette(title.palette) - theme: D.DTK.toColorType(title.palette.window) + foreground: title.palette.windowText Layout.alignment: Qt.AlignHCenter } - D.DciIcon { + PaintedDciIcon { name: "arrow" sourceSize: Qt.size(12, 12) - palette: D.DTK.makeIconPalette(title.palette) - theme: D.DTK.toColorType(title.palette.window) + width: 12 + height: 12 + foreground: title.palette.windowText Layout.alignment: Qt.AlignHCenter } } @@ -133,15 +135,19 @@ ColumnLayout { component SideBarButton: D.ActionButton { id: btn + property alias iconSource: paintedIcon.name ToolTip.visible: hovered ToolTip.delay: 500 Layout.alignment: Qt.AlignCenter focusPolicy: Qt.NoFocus // don't inherit window's windowText (it's has opacity of 0.7 in dtkgui.) palette.windowText: D.ColorSelector.textColor - icon { + contentItem: PaintedDciIcon { + id: paintedIcon width: 16 height: 16 + sourceSize: Qt.size(16, 16) + foreground: D.ColorSelector.textColor } background: ItemBackground { button: btn @@ -150,7 +156,7 @@ ColumnLayout { SideBarButton { id: computer - icon.name: "computer-symbolic" + iconSource: "computer-symbolic" ToolTip.text: qsTr("Computer") KeyNavigation.down: images KeyNavigation.up: title @@ -161,7 +167,7 @@ ColumnLayout { SideBarButton { id: images - icon.name: "folder-pictures-symbolic" + iconSource: "folder-pictures-symbolic" ToolTip.text: qsTr("Pictures") KeyNavigation.down: documents KeyNavigation.up: computer @@ -172,7 +178,7 @@ ColumnLayout { SideBarButton { id: documents - icon.name: "folder-documents-symbolic" + iconSource: "folder-documents-symbolic" ToolTip.text: qsTr("Documents") KeyNavigation.down: desktop KeyNavigation.up: images @@ -183,7 +189,7 @@ ColumnLayout { SideBarButton { id: desktop - icon.name: "user-desktop-symbolic" + iconSource: "user-desktop-symbolic" ToolTip.text: qsTr("Desktop") KeyNavigation.down: setting KeyNavigation.up: documents @@ -194,7 +200,7 @@ ColumnLayout { SideBarButton { id: setting - icon.name: "setting" + iconSource: "setting" ToolTip.text: qsTr("Control Center") KeyNavigation.down: title KeyNavigation.up: desktop @@ -209,6 +215,6 @@ ColumnLayout { Item { height: title.height - Layout.bottomMargin: 10 + Layout.bottomMargin: Helper.pixelAligned(10, Screen.devicePixelRatio) } } diff --git a/qml/windowed/WindowedFrame.qml b/qml/windowed/WindowedFrame.qml index 1d2759a6..cbea3444 100644 --- a/qml/windowed/WindowedFrame.qml +++ b/qml/windowed/WindowedFrame.qml @@ -84,8 +84,8 @@ InputEventItem { anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom - anchors.topMargin: 10 - anchors.leftMargin: 10 + anchors.topMargin: Helper.pixelAligned(10, Screen.devicePixelRatio) + anchors.leftMargin: Helper.pixelAligned(10, Screen.devicePixelRatio) nextKeyTabTarget: bottomBar.keyTabTarget } @@ -95,7 +95,7 @@ InputEventItem { anchors.left: sideBar.right anchors.top: baseLayer.top anchors.bottom: bottomBar.top - anchors.leftMargin: 10 + anchors.leftMargin: Helper.pixelAligned(10, Screen.devicePixelRatio) property Palette backgroundColor: Palette { normal { diff --git a/src/quick/painteddciicon.cpp b/src/quick/painteddciicon.cpp new file mode 100644 index 00000000..862a75a4 --- /dev/null +++ b/src/quick/painteddciicon.cpp @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "painteddciicon.h" + +#include +#include +#include +#include +#include + +DGUI_USE_NAMESPACE + +PaintedDciIcon::PaintedDciIcon(QQuickItem *parent) + : QQuickPaintedItem(parent) +{ + setRenderTarget(QQuickPaintedItem::Image); + + connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, + this, [this]() { update(); }); +} + +void PaintedDciIcon::paint(QPainter *painter) +{ + if (m_dciIcon.isNull()) + return; + + qreal dpr = window() ? window()->devicePixelRatio() : qApp->devicePixelRatio(); + auto appTheme = DGuiApplicationHelper::instance()->themeType(); + DDciIcon::Theme theme = (appTheme == DGuiApplicationHelper::DarkType) + ? DDciIcon::Dark : DDciIcon::Light; + + QPalette pa = qApp->palette(); + DDciIconPalette palette( + m_foreground.isValid() ? m_foreground : pa.windowText().color(), + pa.window().color(), + pa.highlight().color(), + pa.highlightedText().color() + ); + + int iconW = m_sourceSize.isValid() ? m_sourceSize.width() : qRound(width()); + int iconH = m_sourceSize.isValid() ? m_sourceSize.height() : qRound(height()); + QRect iconRect(0, 0, iconW, iconH); + QRect itemRect(0, 0, qRound(width()), qRound(height())); + iconRect.moveCenter(itemRect.center()); + m_dciIcon.paint(painter, iconRect, dpr, theme, DDciIcon::Normal, + Qt::AlignCenter, palette); +} + +QString PaintedDciIcon::name() const +{ + return m_name; +} + +void PaintedDciIcon::setName(const QString &name) +{ + if (m_name == name) + return; + m_name = name; + m_dciIcon = DDciIcon::fromTheme(m_name); + emit nameChanged(); + update(); +} + +QColor PaintedDciIcon::foreground() const +{ + return m_foreground; +} + +void PaintedDciIcon::setForeground(const QColor &color) +{ + if (m_foreground == color) + return; + m_foreground = color; + emit foregroundChanged(); + update(); +} + +QSize PaintedDciIcon::sourceSize() const +{ + return m_sourceSize; +} + +void PaintedDciIcon::setSourceSize(const QSize &size) +{ + if (m_sourceSize == size) + return; + m_sourceSize = size; + emit sourceSizeChanged(); + update(); +} diff --git a/src/quick/painteddciicon.h b/src/quick/painteddciicon.h new file mode 100644 index 00000000..1bea9d72 --- /dev/null +++ b/src/quick/painteddciicon.h @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef PAINTEDDCIICON_H +#define PAINTEDDCIICON_H + +#include +#include +#include + +DGUI_USE_NAMESPACE + +class PaintedDciIcon : public QQuickPaintedItem +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QColor foreground READ foreground WRITE setForeground NOTIFY foregroundChanged) + Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize NOTIFY sourceSizeChanged) + +public: + explicit PaintedDciIcon(QQuickItem *parent = nullptr); + + void paint(QPainter *painter) override; + + QString name() const; + void setName(const QString &name); + + QColor foreground() const; + void setForeground(const QColor &color); + + QSize sourceSize() const; + void setSourceSize(const QSize &size); + +signals: + void nameChanged(); + void foregroundChanged(); + void sourceSizeChanged(); + +private: + QString m_name; + QColor m_foreground; + QSize m_sourceSize; + DDciIcon m_dciIcon; +}; + +#endif // PAINTEDDCIICON_H