diff --git a/shell/Menu.qml b/shell/Menu.qml new file mode 100644 index 000000000..7e4f4f131 --- /dev/null +++ b/shell/Menu.qml @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +import QtQuick 2.11 +import QtQuick.Window 2.11 +import QtQuick.Layouts 1.11 +import QtQuick.Templates as T +import org.deepin.dtk 1.0 as D +import org.deepin.dtk.style 1.0 as DS + +T.Menu { + id: control + + property bool closeOnInactive: true + property int maxVisibleItems : DS.Style.arrowListView.maxVisibleItems + property D.Palette backgroundColor: DS.Style.menu.background + property D.Palette backgroundNoBlurColor: DS.Style.menu.backgroundNoBlur + property var model: control.contentModel + property Component header + property Component footer + readonly property bool existsChecked: { + for (var i = 0; i < count; ++i) { + var item = itemAt(i) + if (item && item.checked) + return true + } + return false + } + readonly property bool active: parent && parent.Window.active + + implicitHeight: DS.Style.control.implicitHeight(control) + implicitWidth: DS.Style.control.implicitWidth(control) + margins: DS.Style.menu.margins + overlap: DS.Style.menu.overlap + + delegate: MenuItem { } + + D.PopupHandle.delegate: PopupWindow { + blurControl: control + } + + contentItem: Control { + topPadding: 10 // TODO how to clip radius + bottomPadding: topPadding + leftPadding: 0 + rightPadding: leftPadding + contentItem: ColumnLayout { + id: viewLayout + + Loader { + Layout.fillWidth: true + Layout.preferredHeight: height + sourceComponent: control.header + } + ArrowListView { + id: contentView + property int count: contentView.view.count + + view.model: control.model + Layout.fillWidth: true + Layout.fillHeight: true + view.currentIndex: control.currentIndex + maxVisibleItems: control.maxVisibleItems + itemHeight: DS.Style.menu.item.height + + function refreshContentItemWidth() + { + for (var i = 0; i < view.count; ++i) { + var item = view.model.get(i) + if (item) { + item.width = view.width + } + } + } + + onCountChanged: refreshContentItemWidth() + onWidthChanged: refreshContentItemWidth() + } + Loader { + Layout.fillWidth: true + Layout.preferredHeight: height + sourceComponent: control.footer + } + } + } + + background: Loader { + active: !control.D.PopupHandle.window + sourceComponent: FloatingPanel { + implicitWidth: DS.Style.menu.item.width + implicitHeight: DS.Style.menu.item.height + radius: DS.Style.menu.radius + backgroundColor: control.backgroundColor + backgroundNoBlurColor: control.backgroundNoBlurColor + } + } + + onActiveChanged: { + if (!active && closeOnInactive) { + control.close() + } + } +} diff --git a/shell/MenuItem.qml b/shell/MenuItem.qml new file mode 100644 index 000000000..2381b0f1f --- /dev/null +++ b/shell/MenuItem.qml @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Templates as T +import org.deepin.dtk 1.0 as D +import org.deepin.dtk.style 1.0 as DS + +T.MenuItem { + id: control + + property bool useIndicatorPadding: menu && menu.existsChecked || false + implicitWidth: DS.Style.control.implicitWidth(control) + implicitHeight: DS.Style.control.implicitHeight(control) + baselineOffset: contentItem.y + contentItem.baselineOffset + padding: DS.Style.control.padding + spacing: DS.Style.control.spacing + opacity: D.ColorSelector.controlState === D.DTK.DisabledState ? 0.4 : 1 + icon { + height: DS.Style.menu.item.iconSize.height + width: DS.Style.menu.item.iconSize.height + } + + property D.Palette textColor: control.highlighted ? DS.Style.checkedButton.text + : DS.Style.menu.itemText + property D.Palette subMenuBackgroundColor: DS.Style.menu.subMenuOpenedBackground + property D.Palette backgroundColor: DS.Style.highlightPanel.background + + palette.windowText: D.ColorSelector.textColor + D.DciIcon.mode: D.ColorSelector.controlState + D.DciIcon.theme: D.ColorSelector.controlTheme + D.DciIcon.palette: D.DTK.makeIconPalette(palette) + contentItem: D.IconLabel { + readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0 + readonly property real indicatorPadding: control.useIndicatorPadding && control.indicator ? control.indicator.width + control.spacing : 0 + + leftPadding: (!control.mirrored ? indicatorPadding : arrowPadding) + 36 + rightPadding: (control.mirrored ? indicatorPadding : arrowPadding) + 36 + spacing: control.spacing + mirrored: control.mirrored + display: control.display + alignment: Qt.AlignLeft + text: control.text + font: control.font + color: control.palette.windowText + icon: D.DTK.makeIcon(control.icon, control.D.DciIcon) + } + + indicator: Loader { + width: DS.Style.menu.item.iconSize.width + height: DS.Style.menu.item.iconSize.height + active: control.checked + anchors { + left: control.left + leftMargin: control.mirrored ? control.width - width - control.rightPadding + : control.leftPadding + verticalCenter: parent.verticalCenter + } + + sourceComponent: D.DciIcon { + sourceSize: Qt.size(DS.Style.menu.item.iconSize.width, + DS.Style.menu.item.iconSize.height) + name: "menu_select" + palette: control.D.DciIcon.palette + mode: control.D.ColorSelector.controlState + theme: control.D.ColorSelector.controlTheme + fallbackToQIcon: false + } + } + + arrow: Loader { + width: DS.Style.menu.item.iconSize.width + height: DS.Style.menu.item.iconSize.height + active: control.subMenu + anchors { + right: parent.right + rightMargin: control.mirrored ? control.width - width - control.rightPadding + : control.rightPadding + verticalCenter: parent.verticalCenter + } + + sourceComponent: D.DciIcon { + sourceSize: Qt.size(DS.Style.menu.item.iconSize.width, + DS.Style.menu.item.iconSize.height) + mirror: control.mirrored + name: "menu_arrow" + palette: control.D.DciIcon.palette + mode: control.D.ColorSelector.controlState + theme: control.D.ColorSelector.controlTheme + fallbackToQIcon: false + } + } + + background: Rectangle { + + implicitWidth: DS.Style.menu.item.width + implicitHeight: DS.Style.menu.item.height + + visible: control.down || control.highlighted + color: control.D.ColorSelector.backgroundColor + radius: 1 // TODO can't display background when using dtk's InWindowBlur. + } +} diff --git a/shell/main.cpp b/shell/main.cpp index 38352eb68..cd10b8ed0 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -158,6 +158,7 @@ int main(int argc, char *argv[]) } Shell shell; + shell.installDtkInterceptor(); // TODO disable qml's cache avoid to parsing error for ExecutionEngine. shell.disableQmlCache(); shell.setFlickableWheelDeceleration(6000); diff --git a/shell/override_dtkdeclarative_qml.qrc b/shell/override_dtkdeclarative_qml.qrc index 6640eb8eb..60afdad26 100644 --- a/shell/override_dtkdeclarative_qml.qrc +++ b/shell/override_dtkdeclarative_qml.qrc @@ -1,5 +1,7 @@ InWindowBlur.qml + MenuItem.qml + Menu.qml diff --git a/shell/shell.cpp b/shell/shell.cpp index dc0aad650..0df1632a5 100644 --- a/shell/shell.cpp +++ b/shell/shell.cpp @@ -23,9 +23,14 @@ class DtkInterceptor : public QObject, public QQmlAbstractUrlInterceptor { if (type != DataType::QmlFile) return path; - if (path.path().endsWith("overridable/InWindowBlur.qml")) { - qDebug() << "Override dtk's InWindowBlur"; - return QStringLiteral("qrc:/shell/override/dtk/InWindowBlur.qml"); + + if (path.path().endsWith("dtk/MenuItem.qml")) { + qDebug() << "Override dtk's MenuItem" << path.path(); + return QStringLiteral("qrc:/shell/override/dtk/MenuItem.qml"); + } + if (path.path().endsWith("dtk/Menu.qml")) { + qDebug() << "Override dtk's Menu" << path.path(); + return QStringLiteral("qrc:/shell/override/dtk/Menu.qml"); } return path;