diff --git a/shell/contents/configuration/AppletConfiguration.qml b/shell/contents/configuration/AppletConfiguration.qml index ca33184d..2d889892 100644 --- a/shell/contents/configuration/AppletConfiguration.qml +++ b/shell/contents/configuration/AppletConfiguration.qml @@ -1,43 +1,116 @@ -/* - * SPDX-FileCopyrightText: 2013 Marco Martin - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ +// SPDX-FileCopyrightText: 2013 Marco Martin +// SPDX-FileCopyrightText: 2022 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later -import QtQuick 2.6 -import QtQuick.Controls 2.3 as QtControls -import QtQuick.Layouts 1.0 -import QtQuick.Window 2.2 +import QtQuick 2.15 +import QtQuick.Controls 2.15 as QQC2 +import QtQuick.Layouts 1.15 +import QtQuick.Window 2.15 -import org.kde.kirigami 2.5 as Kirigami -import org.kde.plasma.core 2.1 as PlasmaCore +import org.kde.kirigami 2.19 as Kirigami import org.kde.plasma.configuration 2.0 +import org.kde.kitemmodels 1.0 as KItemModels - -//TODO: all of this will be done with desktop components Rectangle { id: root - // Layout.minimumWidth: plasmoid.availableScreenRect.width - // Layout.minimumHeight: plasmoid.availableScreenRect.height - - LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true color: "transparent" //BEGIN properties + property bool isContainment: false - property alias internalDialog: dialogContents + property alias appComponent: app + //END properties //BEGIN model - property ConfigModel globalConfigModel: globalAppletConfigModel + + property ConfigModel globalConfigModel: globalAppletConfigModel ConfigModel { id: globalAppletConfigModel } + KItemModels.KSortFilterProxyModel { + id: configDialogFilterModel + sourceModel: configDialog.configModel + filterRowCallback: (row, parent) => { + return sourceModel.data(sourceModel.index(row, 0), ConfigModel.VisibleRole); + } + } + +//END model + +//BEGIN functions + + function saveConfig() { + if (app.pageStack.currentItem.saveConfig) { + app.pageStack.currentItem.saveConfig() + } + for (var key in plasmoid.configuration) { + if (app.pageStack.currentItem["cfg_"+key] !== undefined) { + plasmoid.configuration[key] = app.pageStack.currentItem["cfg_"+key] + } + } + } + + function configurationHasChanged() { + for (var key in plasmoid.configuration) { + if (app.pageStack.currentItem["cfg_"+key] !== undefined) { + //for objects == doesn't work + if (typeof plasmoid.configuration[key] == 'object') { + for (var i in plasmoid.configuration[key]) { + if (plasmoid.configuration[key][i] != app.pageStack.currentItem["cfg_"+key][i]) { + return true; + } + } + return false; + } else if (app.pageStack.currentItem["cfg_"+key] != plasmoid.configuration[key]) { + return true; + } + } + } + return false; + } + + + function settingValueChanged() { + if (app.pageStack.currentItem.saveConfig !== undefined) { + app.pageStack.currentItem.saveConfig(); + } else { + root.saveConfig(); + } + } + + function pushReplace(item, config) { + let page; + if (app.pageStack.depth === 0) { + page = app.pageStack.push(item, config); + } else { + page = app.pageStack.replace(item, config); + } + app.currentConfigPage = page; + } + + function open(item) { + app.isAboutPage = false; + if (item.source) { + app.isAboutPage = item.source === "AboutPlugin.qml"; + pushReplace(Qt.resolvedUrl("ConfigurationAppletPage.qml"), {configItem: item, title: item.name}); + } else if (item.kcm) { + pushReplace(configurationKcmPageComponent, {kcm: item.kcm, internalPage: item.kcm.mainUi}); + } else { + app.pageStack.pop(); + } + } + +//END functions + + +//BEGIN connections + Connections { target: root.Window.window function onVisibleChanged() { @@ -47,334 +120,101 @@ Rectangle { } } - PlasmaCore.SortFilterModel { - id: configDialogFilterModel - sourceModel: configDialog.configModel - filterRole: "visible" - filterCallback: function(source_row, value) { return value; } - } -//END model - -//BEGIN functions - function saveConfig() { - if (pageStack.currentItem.saveConfig) { - pageStack.currentItem.saveConfig() - } - for (var key in plasmoid.configuration) { - if (pageStack.currentItem["cfg_"+key] !== undefined) { - plasmoid.configuration[key] = pageStack.currentItem["cfg_"+key] - } - } - } - - function configurationHasChanged() { - for (var key in plasmoid.configuration) { - if (pageStack.currentItem["cfg_"+key] !== undefined) { - //for objects == doesn't work - if (typeof plasmoid.configuration[key] == 'object') { - for (var i in plasmoid.configuration[key]) { - if (plasmoid.configuration[key][i] != pageStack.currentItem["cfg_"+key][i]) { - return true; - } - } - return false; - } else if (pageStack.currentItem["cfg_"+key] != plasmoid.configuration[key]) { - return true; - } - } - } - return false; - } - - - function settingValueChanged() { - if (pageStack.currentItem.saveConfig !== undefined) { - pageStack.currentItem.saveConfig(); - } else { - root.saveConfig(); - } - } -//END functions - - -//BEGIN connections Component.onCompleted: { - if (!isContainment && configDialog.configModel && configDialog.configModel.count > 0) { - if (configDialog.configModel.get(0).source) { - pageStack.sourceFile = configDialog.configModel.get(0).source - } else if (configDialog.configModel.get(0).kcm) { - pageStack.sourceFile = Qt.resolvedUrl("ConfigurationKcmPage.qml"); - pageStack.currentItem.kcm = configDialog.configModel.get(0).kcm; - } else { - pageStack.sourceFile = ""; - } - pageStack.title = configDialog.configModel.get(0).name + // if we are a containment then the first item will be ConfigurationContainmentAppearance + // if the applet does not have own configs then the first item will be Shortcuts + if (isContainment || !configDialog.configModel || configDialog.configModel.count === 0) { + open(root.globalConfigModel.get(0)) } else { - pageStack.sourceFile = globalConfigModel.get(0).source - pageStack.title = globalConfigModel.get(0).name - } -// root.width = dialogRootItem.implicitWidth -// root.height = dialogRootItem.implicitHeight - } - onVisibleChanged: { - if (visible) { - dialogContents.visible = true; + open(configDialog.configModel.get(0)) } } + //END connections //BEGIN UI components - Rectangle { - id: dialogContents - visible: true + Component { + id: configurationKcmPageComponent + ConfigurationKcmPage {} + } + + Component { + id: configCategoryDelegate + Kirigami.NavigationTabButton { + icon.name: model.icon + text: model.name +// recolorIcon: false + QQC2.ButtonGroup.group: footerBar.tabGroup + + onClicked: { + if (checked) { + root.open(model); + } + } + + checked: { + if (app.pageStack.currentItem) { + if (model.kcm && app.pageStack.currentItem.kcm) { + return model.kcm == app.pageStack.currentItem.kcm; + } else if (app.pageStack.currentItem.configItem) { + return model.source == app.pageStack.currentItem.configItem.source; + } else { + return app.pageStack.currentItem.source == Qt.resolvedUrl(model.source); + } + } + return false; + } + } + } + + Kirigami.ApplicationItem { + id: app anchors.fill: parent - color: Kirigami.Theme.backgroundColor - - ColumnLayout { - id: dialogRootItem - anchors.fill: parent - - spacing: 0 - implicitWidth: scroll.implicitWidth - - QtControls.ScrollView { - id: scroll - - activeFocusOnTab: false - - Layout.fillWidth: true - Layout.fillHeight: true - - implicitWidth: pageColumn.implicitWidth - implicitHeight: pageColumn.implicitHeight - - property Item flickableItem: pageFlickable - // this horrible code below ensures the control with active focus stays visible in the window - // by scrolling the view up or down as needed when tabbing through the window - Window.onActiveFocusItemChanged: { - var flickable = scroll.flickableItem; - - var item = Window.activeFocusItem; - if (!item) { - return; - } - - // when an item within ScrollView has active focus the ScrollView, - // as FocusScope, also has it, so we only scroll in this case - if (!scroll.activeFocus) { - return; - } - - var padding = PlasmaCore.Units.gridUnit * 2 // some padding to the top/bottom when we scroll - - var yPos = item.mapToItem(scroll.contentItem, 0, 0).y; - if (yPos < flickable.contentY) { - flickable.contentY = Math.max(0, yPos - padding); - - // The "Math.min(padding, item.height)" ensures that we only scroll the item into view - // when it's barely visible. The logic was mostly meant for keyboard navigating through - // a list of CheckBoxes, so this check keeps us from trying to scroll an inner ScrollView - // into view when it implicitly gains focus (like plasma-pa config dialog has). - } else if (yPos + Math.min(padding, item.height) > flickable.contentY + flickable.height) { - flickable.contentY = Math.min(flickable.contentHeight - flickable.height, - yPos - flickable.height + item.height + padding); - } - } - Flickable { - id: pageFlickable - anchors { - fill: parent - margins: PlasmaCore.Units.smallSpacing - } - contentHeight: pageColumn.height - contentWidth: width - ColumnLayout { - id: pageColumn - spacing: PlasmaCore.Units.largeSpacing / 2 - width: pageFlickable.width - height: Math.max(implicitHeight, pageFlickable.height) - - Kirigami.Heading { - id: pageTitle - Layout.fillWidth: true - level: 1 - text: pageStack.title - } - - QtControls.StackView { - id: pageStack - property string title: "" - property bool invertAnimations: false - - Layout.fillWidth: true - Layout.fillHeight: true - implicitWidth: Math.max(currentItem ? Math.max(currentItem.Layout.minimumWidth, currentItem.Layout.preferredWidth, currentItem.implicitWidth) : 0, PlasmaCore.Units.gridUnit * 15) - implicitHeight: Math.max(currentItem ? Math.max(currentItem.Layout.minimumHeight, currentItem.Layout.preferredHeight, currentItem.implicitHeight) : 0, PlasmaCore.Units.gridUnit * 15) - - property string sourceFile - - onSourceFileChanged: { - if (!sourceFile) { - return; - } - - //in a StackView pages need to be initialized with stackviews size, or have none - var props = {"width": width, "height": height} - - var plasmoidConfig = plasmoid.configuration - for (var key in plasmoidConfig) { - props["cfg_" + key] = plasmoid.configuration[key] - } - - var newItem = replace(Qt.resolvedUrl(sourceFile), props) - - for (var key in plasmoidConfig) { - var changedSignal = newItem["cfg_" + key + "Changed"] - if (changedSignal) { - changedSignal.connect(root.settingValueChanged) - } - } - - var configurationChangedSignal = newItem.configurationChanged - if (configurationChangedSignal) { - configurationChangedSignal.connect(root.settingValueChanged) - } - - scroll.flickableItem.contentY = 0 - - /* - for (var prop in currentItem) { - if (prop.indexOf("cfg_") === 0) { - currentItem[prop+"Changed"].connect(root.pageChanged) - } - }*/ - } - - replaceEnter: Transition { - ParallelAnimation { - //OpacityAnimator when starting from 0 is buggy (it shows one frame with opacity 1) - NumberAnimation { - property: "opacity" - from: 0 - to: 1 - duration: PlasmaCore.Units.longDuration - easing.type: Easing.InOutQuad - } - XAnimator { - from: pageStack.invertAnimations ? -scroll.width/3: scroll.width/3 - to: 0 - duration: PlasmaCore.Units.longDuration - easing.type: Easing.InOutQuad - } - } - } - replaceExit: Transition { - ParallelAnimation { - OpacityAnimator { - from: 1 - to: 0 - duration: PlasmaCore.Units.longDuration - easing.type: Easing.InOutQuad - } - XAnimator { - from: 0 - to: pageStack.invertAnimations ? scroll.width/3 : -scroll.width/3 - duration: PlasmaCore.Units.longDuration - easing.type: Easing.InOutQuad - } - } - } - } - } + + pageStack.globalToolBar.canContainHandles: true + pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.ToolBar + pageStack.globalToolBar.showNavigationButtons: Kirigami.ApplicationHeaderStyle.ShowBackButton; + + property var currentConfigPage: null + property bool isAboutPage: false + + // pop pages when not in use + Connections { + target: app.pageStack + function onCurrentIndexChanged() { + // wait for animation to finish before popping pages + timer.restart(); + } + } + + Timer { + id: timer + interval: 300 + onTriggered: { + let currentIndex = app.pageStack.currentIndex; + while (app.pageStack.depth > (currentIndex + 1) && currentIndex >= 0) { + app.pageStack.pop(); } } + } - Rectangle { - id: separator - Layout.fillWidth: true - Layout.preferredHeight: 1 - color: Kirigami.Theme.highlightColor - visible: categoriesScroll.visible - Behavior on color { - ColorAnimation { - duration: PlasmaCore.Units.longDuration - easing.type: Easing.InOutQuad - } - } + footer: Kirigami.NavigationTabBar { + id: footerBar + visible: count > 1 + height: visible ? implicitHeight : 0 + Repeater { + model: root.isContainment ? globalConfigModel : undefined + delegate: configCategoryDelegate } - - QtControls.ScrollView { - id: categoriesScroll - - Layout.fillWidth: true - Layout.preferredHeight: categories.implicitHeight - - visible: (configDialog.configModel ? configDialog.configModel.count : 0) + globalConfigModel.count > 1 - - Keys.onLeftPressed: { - var buttons = categories.children - - var foundPrevious = false - for (var i = buttons.length - 1; i >= 0; --i) { - var button = buttons[i]; - if (!button.hasOwnProperty("current")) { - // not a ConfigCategoryDelegate - continue; - } - - if (foundPrevious) { - button.openCategory() - return - } else if (button.current) { - foundPrevious = true - } - } - } - - Keys.onRightPressed: { - var buttons = categories.children - - var foundNext = false - for (var i = 0, length = buttons.length; i < length; ++i) { - var button = buttons[i]; - console.log(button) - if (!button.hasOwnProperty("current")) { - continue; - } - - if (foundNext) { - button.openCategory() - return - } else if (button.current) { - foundNext = true - } - } - } - - RowLayout { - id: categories - spacing: 0 - width: categoriesScroll.width - height: implicitHeight - - property Item currentItem: children[1] - - Repeater { - model: root.isContainment ? globalConfigModel : undefined - delegate: ConfigCategoryDelegate {} - } - Repeater { - model: configDialogFilterModel - delegate: ConfigCategoryDelegate {} - } - Repeater { - model: !root.isContainment ? globalConfigModel : undefined - delegate: ConfigCategoryDelegate {} - } - } + Repeater { + model: configDialogFilterModel + delegate: configCategoryDelegate + } + Repeater { + model: !root.isContainment ? globalConfigModel : undefined + delegate: configCategoryDelegate } - } } //END UI components diff --git a/shell/contents/configuration/ConfigCategoryDelegate.qml b/shell/contents/configuration/ConfigCategoryDelegate.qml deleted file mode 100644 index 8f940178..00000000 --- a/shell/contents/configuration/ConfigCategoryDelegate.qml +++ /dev/null @@ -1,131 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2013 Marco Martin - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -import QtQuick 2.0 -import QtQuick.Layouts 1.1 -import QtQuick.Controls 2.3 as QtControls -import QtQuick.Window 2.2 - -import org.kde.plasma.core 2.0 as PlasmaCore -import org.kde.kquickcontrolsaddons 2.0 -import org.kde.kirigami 2.5 as Kirigami - -MouseArea { - id: delegate - -//BEGIN properties - implicitWidth: delegateContents.implicitWidth + 4 * PlasmaCore.Units.smallSpacing - implicitHeight: delegateContents.height + PlasmaCore.Units.smallSpacing * 4 - Layout.fillWidth: true - hoverEnabled: true - - property bool current: (model.kcm && pageStack.currentItem.kcm && model.kcm == pageStack.currentItem.kcm) || (model.source == pageStack.sourceFile) -//END properties - -//BEGIN functions - function openCategory() { - if (current) { - return; - } - if (typeof(categories.currentItem) !== "undefined") { - pageStack.invertAnimations = (categories.currentItem.x > delegate.x); - categories.currentItem = delegate; - } - - if (model.source) { - pageStack.sourceFile = model.source; - } else if (model.kcm) { - pageStack.sourceFile = ""; - pageStack.sourceFile = Qt.resolvedUrl("ConfigurationKcmPage.qml"); - pageStack.currentItem.kcm = model.kcm; - } else { - pageStack.sourceFile = ""; - } - pageStack.title = model.name - } -//END functions - -//BEGIN connections - onPressed: { - categoriesScroll.forceActiveFocus() - - if (current) { - return; - } - - openCategory(); - } - onCurrentChanged: { - if (current) { - categories.currentItem = delegate; - } - } -//END connections - -//BEGIN UI components - Rectangle { - anchors.fill: parent - color: Kirigami.Theme.highlightColor - opacity: { // try to match Breeze style hover handling - var active = categoriesScroll.activeFocus && Window.active - if (current) { - if (active) { - return 1 - } else if (delegate.containsMouse) { - return 0.6 - } else { - return 0.3 - } - } else if (delegate.containsMouse) { - if (active) { - return 0.3 - } else { - return 0.1 - } - } - return 0 - } - Behavior on opacity { - NumberAnimation { - duration: PlasmaCore.Units.longDuration - easing.type: Easing.InOutQuad - } - } - } - - ColumnLayout { - id: delegateContents - spacing: PlasmaCore.Units.smallSpacing - width: parent.width - anchors.verticalCenter: parent.verticalCenter - - QIconItem { - id: iconItem - Layout.alignment: Qt.AlignHCenter - width: PlasmaCore.Units.iconSizes.medium - height: width - icon: model.icon - state: current && categoriesScroll.activeFocus ? QIconItem.SelectedState : QIconItem.DefaultState - } - - QtControls.Label { - id: nameLabel - Layout.fillWidth: true - text: model.name - wrapMode: Text.Wrap - horizontalAlignment: Text.AlignHCenter - color: current && categoriesScroll.activeFocus ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor - Behavior on color { - ColorAnimation { - duration: PlasmaCore.Units.longDuration - easing.type: Easing.InOutQuad - } - } - } - } -//END UI components -} - diff --git a/shell/contents/configuration/ConfigurationAppletPage.qml b/shell/contents/configuration/ConfigurationAppletPage.qml new file mode 100644 index 00000000..0abd9b35 --- /dev/null +++ b/shell/contents/configuration/ConfigurationAppletPage.qml @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: 2020 Nicolas Fella +// SPDX-License-Identifier: GPL-2.0-or-later + +import QtQuick 2.0 + +import org.kde.kirigami 2.10 as Kirigami + +Kirigami.ScrollablePage { + id: root + + title: configItem.name + + required property var configItem + + signal settingValueChanged() + + function saveConfig() { + for (let key in plasmoid.configuration) { + if (loader.item["cfg_" + key] != undefined) { + plasmoid.configuration[key] = loader.item["cfg_" + key] + } + } + + // For ConfigurationContainmentActions.qml + if (loader.item.hasOwnProperty("saveConfig")) { + loader.item.saveConfig() + } + } + + implicitHeight: loader.height + + padding: Kirigami.Units.largeSpacing + bottomPadding: 0 + + Loader { + id: loader + width: parent.width + // HACK the height of the loader is based on the implicitHeight of the content. + // Unfortunately not all content items have a sensible implicitHeight. + // If it is zero fall back to the height of its children + // Also make it at least as high as the page itself. Some existing configs assume they fill the whole space + // TODO KF6 clean this up by making all configs based on SimpleKCM/ScrollViewKCM/GridViewKCM + height: Math.max(root.availableHeight, item.implicitHeight ? item.implicitHeight : item.childrenRect.height) + + Component.onCompleted: { + const plasmoidConfig = plasmoid.configuration + + const props = {} + for (let key in plasmoidConfig) { + props["cfg_" + key] = plasmoid.configuration[key] + } + + setSource(configItem.source, props) + } + + onLoaded: { + const plasmoidConfig = plasmoid.configuration; + + for (let key in plasmoidConfig) { + const changedSignal = item["cfg_" + key + "Changed"] + if (changedSignal) { + changedSignal.connect(root.settingValueChanged) + } + } + + const configurationChangedSignal = item.configurationChanged + if (configurationChangedSignal) { + configurationChangedSignal.connect(root.settingValueChanged) + } + } + } +} diff --git a/shell/contents/configuration/ConfigurationContainmentAppearance.qml b/shell/contents/configuration/ConfigurationContainmentAppearance.qml index 4457bac7..62ba4796 100644 --- a/shell/contents/configuration/ConfigurationContainmentAppearance.qml +++ b/shell/contents/configuration/ConfigurationContainmentAppearance.qml @@ -136,12 +136,6 @@ ColumnLayout { text: i18nd("plasma_shell_org.kde.plasma.desktop", "Apply now") onClicked: saveConfig() } - - Binding { - target: categoriesScroll //from parent scope AppletConfiguration - property: "enabled" - value: !switchContainmentWarning.visible - } } Item { diff --git a/shell/contents/configuration/ConfigurationKcmPage.qml b/shell/contents/configuration/ConfigurationKcmPage.qml new file mode 100644 index 00000000..d957f5c2 --- /dev/null +++ b/shell/contents/configuration/ConfigurationKcmPage.qml @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: 2015 Marco Martin +// SPDX-FileCopyrightText: 2020 Nicolas Fella +// SPDX-FileCopyrightText: 2020 Carl Schwan +// SPDX-License-Identifier: GPL-2.0-or-later + +import QtQuick 2.6 +import QtQuick.Controls 2.2 as QQC2 +import org.kde.kirigami 2.5 as Kirigami + +Kirigami.Page { + id: container + + required property QtObject kcm + required property Item internalPage + + signal settingValueChanged() + + title: kcm.name + topPadding: 0 + leftPadding: 0 + rightPadding: 0 + bottomPadding: 0 + flickable: internalPage.flickable + actions.main: internalPage.actions.main + actions.contextualActions: internalPage.contextualActions + + onInternalPageChanged: { + internalPage.parent = contentItem; + internalPage.anchors.fill = contentItem; + } + onActiveFocusChanged: { + if (activeFocus) { + internalPage.forceActiveFocus(); + } + } + + Component.onCompleted: { + kcm.load() + } + + function saveConfig() { + kcm.save(); + } + + data: [ + Connections { + target: kcm + onPagePushed: { + app.pageStack.push(configurationKcmPageComponent.createObject(app.pageStack, {"kcm": kcm, "internalPage": page})); + } + onPageRemoved: app.pageStack.pop(); + }, + Connections { + target: app.pageStack + onPageRemoved: { + if (kcm.needsSave) { + kcm.save() + } + if (page == container) { + page.destroy(); + } + } + } + ] + Connections { + target: kcm + function onNeedsSaveChanged() { + if (kcm.needsSave) { + container.settingValueChanged() + } + } + } +} diff --git a/shell/contents/configuration/ContainmentConfiguration.qml b/shell/contents/configuration/ContainmentConfiguration.qml index 217cbd2c..70193d5f 100644 --- a/shell/contents/configuration/ContainmentConfiguration.qml +++ b/shell/contents/configuration/ContainmentConfiguration.qml @@ -1,29 +1,23 @@ -/* - * SPDX-FileCopyrightText: 2013 Marco Martin - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ +// SPDX-FileCopyrightText: 2013 Marco Martin +// SPDX-FileCopyrightText: 2022 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later import QtQuick 2.12 import QtQuick.Layouts 1.0 import QtQuick.Window 2.2 -import QtQuick.Controls 2.3 as Controls -import org.kde.plasma.extras 2.0 as PlasmaExtras +import QtQuick.Controls 2.15 as Controls + +import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.configuration 2.0 -//for the "simple mode" -import org.kde.plasma.wallpapers.image 2.0 as Wallpaper -import org.kde.kquickcontrolsaddons 2.0 as Addons -import org.kde.kcm 1.1 as KCM - AppletConfiguration { id: root isContainment: true - internalDialog.visible: false - internalDialog.width: root.width < root.height ? root.width : Math.min(root.width, Math.max(internalDialog.implicitWidth, PlasmaCore.Units.gridUnit * 45)) - internalDialog.height: Math.min(root.height, Math.max(internalDialog.implicitHeight, PlasmaCore.Units.gridUnit * 29)) + appComponent.visible: false + appComponent.width: root.width < root.height ? root.width : Math.min(root.width, Math.max(appComponent.implicitWidth, PlasmaCore.Units.gridUnit * 45)) + appComponent.height: Math.min(root.height, Math.max(appComponent.implicitHeight, PlasmaCore.Units.gridUnit * 29)) readonly property bool horizontal: root.width > root.height @@ -40,126 +34,74 @@ AppletConfiguration { } //END model - Controls.Drawer { - id: imageWallpaperDrawer - edge: root.horizontal ? Qt.LeftEdge : Qt.BottomEdge - visible: true - dragMargin: 0 - - onClosed: { - if (!root.internalDialog.visible) { - configDialog.close() + Loader { + id: wallpaperSelectorLoader + asynchronous: true + active: true + + sourceComponent: WallpaperSelector { + visible: false + horizontal: root.horizontal + } + } + + MouseArea { + z: -1 + anchors.fill: parent + onClicked: configDialog.close() + + Controls.Control { + anchors.centerIn: parent + leftPadding: PlasmaCore.Units.largeSpacing + rightPadding: PlasmaCore.Units.largeSpacing + topPadding: PlasmaCore.Units.largeSpacing + bottomPadding: PlasmaCore.Units.largeSpacing + + NumberAnimation on opacity { + id: opacityAnim + running: true + from: 0 + to: 1 + duration: PlasmaCore.Units.longDuration } - } - onOpened: { - wallpapersView.forceActiveFocus() - } - implicitWidth: PlasmaCore.Units.gridUnit * 10 - implicitHeight: PlasmaCore.Units.gridUnit * 8 - width: root.horizontal ? implicitWidth : root.width - height: root.horizontal ? root.height : implicitHeight - Wallpaper.ImageBackend { - id: imageWallpaper - } - background: null - - ListView { - id: wallpapersView - anchors.fill: parent - orientation: root.horizontal ? ListView.Vertical : ListView.Horizontal - keyNavigationEnabled: true - highlightFollowsCurrentItem: true - snapMode: ListView.SnapToItem - model: imageWallpaper.wallpaperModel - onCountChanged: currentIndex = Math.min(model.indexOf(configDialog.wallpaperConfiguration["Image"]), model.rowCount()-1) - footer: Controls.Control { - z: 999 - width: root.horizontal ? parent.width : implicitWidth - height: root.horizontal ? implicitHeight : parent.height - leftPadding: PlasmaCore.Units.gridUnit - topPadding: PlasmaCore.Units.gridUnit - rightPadding: PlasmaCore.Units.gridUnit - bottomPadding: PlasmaCore.Units.gridUnit - - contentItem: ColumnLayout { - Controls.Button { - icon.name: "configure" - text: i18nd("plasma_shell_org.kde.plasma.desktop", "Customize...") - onClicked: { - print(wallpapersView.currentIndex) - internalDialog.visible = true; - imageWallpaperDrawer.close() - } - } - } - background: Rectangle { - color: Qt.rgba (0, 0, 0, 0.3) - } + + background: PlasmaCore.FrameSvgItem { + enabledBorders: PlasmaCore.FrameSvg.AllBorders + imagePath: "widgets/background" } - headerPositioning: ListView.PullBackHeader - delegate: Controls.ItemDelegate { - width: root.horizontal ? parent.width : height * (root.Screen.width / root.Screen.height) - height: root.horizontal ? width / (root.Screen.width / root.Screen.height) : parent.height - padding: wallpapersView.currentIndex === index ? PlasmaCore.Units.gridUnit / 4 : PlasmaCore.Units.gridUnit / 2 - leftPadding: padding - topPadding: padding - rightPadding: padding - bottomPadding: padding - Behavior on padding { - NumberAnimation { - duration: PlasmaCore.Units.longDuration - easing.type: Easing.InOutQuad - } - } - - property bool isCurrent: configDialog.wallpaperConfiguration["Image"] == model.path - onIsCurrentChanged: { - if (isCurrent) { - wallpapersView.currentIndex = index; + + contentItem: RowLayout { + PlasmaComponents3.Button { + Layout.alignment: Qt.AlignRight + Layout.preferredHeight: PlasmaCore.Units.gridUnit * 4 + Layout.preferredWidth: PlasmaCore.Units.gridUnit * 8 + + display: PlasmaComponents3.ToolButton.TextUnderIcon + icon.name: "viewimage" + icon.width: PlasmaCore.Units.iconSizes.medium + icon.height: PlasmaCore.Units.iconSizes.medium + text: i18n("Change Wallpaper") + onClicked: { + opacityAnim.from = 1; + opacityAnim.to = 0; + opacityAnim.restart(); + wallpaperSelectorLoader.item.open(); } } - z: wallpapersView.currentIndex === index ? 2 : 0 - contentItem: Item { - Addons.QIconItem { - anchors.centerIn: parent - width: PlasmaCore.Units.iconSizes.large - height: width - icon: "view-preview" - visible: !walliePreview.visible - } - - Addons.QPixmapItem { - id: walliePreview - anchors.fill: parent - visible: model.screenshot != null - smooth: true - pixmap: model.screenshot - fillMode: Image.PreserveAspectCrop - - } - } - onClicked: { - configDialog.currentWallpaper = "org.kde.image"; - configDialog.wallpaperConfiguration["Image"] = model.path; - configDialog.applyWallpaper() - } - Keys.onReturnPressed: { - clicked(); - } - background: Item { - Rectangle { - anchors { - fill: parent - margins: wallpapersView.currentIndex === index ? 0 : PlasmaCore.Units.gridUnit / 4 - Behavior on margins { - NumberAnimation { - duration: PlasmaCore.Units.longDuration - easing.type: Easing.InOutQuad - } - } - } - radius: PlasmaCore.Units.gridUnit / 4 + PlasmaComponents3.Button { + Layout.alignment: Qt.AlignLeft + Layout.preferredHeight: PlasmaCore.Units.gridUnit * 4 + Layout.preferredWidth: PlasmaCore.Units.gridUnit * 8 + + display: PlasmaComponents3.ToolButton.TextUnderIcon + icon.name: "configure" + icon.width: PlasmaCore.Units.iconSizes.medium + icon.height: PlasmaCore.Units.iconSizes.medium + text: i18n("Configure") + onClicked: { + appComponent.visible = true; + wallpaperSelectorLoader.item.close() } } } diff --git a/shell/contents/configuration/WallpaperSelector.qml b/shell/contents/configuration/WallpaperSelector.qml new file mode 100644 index 00000000..6a80759a --- /dev/null +++ b/shell/contents/configuration/WallpaperSelector.qml @@ -0,0 +1,120 @@ +// SPDX-FileCopyrightText: 2013 Marco Martin +// SPDX-FileCopyrightText: 2022 Devin Lin +// SPDX-License-Identifier: GPL-2.0-or-later + +import QtQuick 2.12 +import QtQuick.Layouts 1.0 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.3 as Controls +import org.kde.plasma.extras 2.0 as PlasmaExtras +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.configuration 2.0 + +import org.kde.plasma.wallpapers.image 2.0 as Wallpaper +import org.kde.kquickcontrolsaddons 2.0 as Addons +import org.kde.kcm 1.1 as KCM + +Controls.Drawer { + id: imageWallpaperDrawer + edge: root.horizontal ? Qt.LeftEdge : Qt.BottomEdge + dragMargin: 0 + + required property bool horizontal + + onClosed: { + if (!root.appComponent.visible) { + configDialog.close() + } + } + onOpened: { + wallpapersView.forceActiveFocus() + } + implicitWidth: PlasmaCore.Units.gridUnit * 10 + implicitHeight: PlasmaCore.Units.gridUnit * 8 + width: imageWallpaperDrawer.horizontal ? implicitWidth : root.width + height: imageWallpaperDrawer.horizontal ? root.height : implicitHeight + + Wallpaper.ImageBackend { + id: imageWallpaper + } + + background: null + + ListView { + id: wallpapersView + anchors.fill: parent + orientation: imageWallpaperDrawer.horizontal ? ListView.Vertical : ListView.Horizontal + keyNavigationEnabled: true + highlightFollowsCurrentItem: true + snapMode: ListView.SnapToItem + model: imageWallpaper.wallpaperModel + onCountChanged: currentIndex = Math.min(model.indexOf(configDialog.wallpaperConfiguration["Image"]), model.rowCount()-1) + headerPositioning: ListView.PullBackHeader + delegate: Controls.ItemDelegate { + width: imageWallpaperDrawer.horizontal ? parent.width : height * (root.Screen.width / root.Screen.height) + height: imageWallpaperDrawer.horizontal ? width / (root.Screen.width / root.Screen.height) : parent.height + padding: wallpapersView.currentIndex === index ? PlasmaCore.Units.gridUnit / 4 : PlasmaCore.Units.gridUnit / 2 + leftPadding: padding + topPadding: padding + rightPadding: padding + bottomPadding: padding + Behavior on padding { + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutQuad + } + } + + property bool isCurrent: configDialog.wallpaperConfiguration["Image"] == model.path + onIsCurrentChanged: { + if (isCurrent) { + wallpapersView.currentIndex = index; + } + } + + z: wallpapersView.currentIndex === index ? 2 : 0 + contentItem: Item { + Addons.QIconItem { + anchors.centerIn: parent + width: PlasmaCore.Units.iconSizes.large + height: width + icon: "view-preview" + visible: !walliePreview.visible + } + + Addons.QPixmapItem { + id: walliePreview + anchors.fill: parent + visible: model.screenshot != null + smooth: true + pixmap: model.screenshot + fillMode: Image.PreserveAspectCrop + + } + } + onClicked: { + configDialog.currentWallpaper = "org.kde.image"; + configDialog.wallpaperConfiguration["Image"] = model.path; + configDialog.applyWallpaper() + } + Keys.onReturnPressed: { + clicked(); + } + background: Item { + Rectangle { + anchors { + fill: parent + margins: wallpapersView.currentIndex === index ? 0 : PlasmaCore.Units.gridUnit / 4 + Behavior on margins { + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + radius: PlasmaCore.Units.gridUnit / 4 + } + } + } + } +}