shell: Update configuration dialogs based on desktop, use new UI for wallpaper selector

This commit is contained in:
Devin Lin 2022-06-23 00:16:20 -04:00
parent dee476e773
commit 436b2660d2
7 changed files with 510 additions and 600 deletions

View file

@ -1,43 +1,116 @@
/* // SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
* SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org> // SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
* // SPDX-License-Identifier: GPL-2.0-or-later
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.6 import QtQuick 2.15
import QtQuick.Controls 2.3 as QtControls import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.0 import QtQuick.Layouts 1.15
import QtQuick.Window 2.2 import QtQuick.Window 2.15
import org.kde.kirigami 2.5 as Kirigami import org.kde.kirigami 2.19 as Kirigami
import org.kde.plasma.core 2.1 as PlasmaCore
import org.kde.plasma.configuration 2.0 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 { Rectangle {
id: root id: root
// Layout.minimumWidth: plasmoid.availableScreenRect.width
// Layout.minimumHeight: plasmoid.availableScreenRect.height
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true LayoutMirroring.childrenInherit: true
color: "transparent" color: "transparent"
//BEGIN properties //BEGIN properties
property bool isContainment: false property bool isContainment: false
property alias internalDialog: dialogContents property alias appComponent: app
//END properties //END properties
//BEGIN model //BEGIN model
property ConfigModel globalConfigModel: globalAppletConfigModel property ConfigModel globalConfigModel: globalAppletConfigModel
ConfigModel { ConfigModel {
id: globalAppletConfigModel 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 { Connections {
target: root.Window.window target: root.Window.window
function onVisibleChanged() { function onVisibleChanged() {
@ -47,336 +120,103 @@ 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: { Component.onCompleted: {
if (!isContainment && configDialog.configModel && configDialog.configModel.count > 0) { // if we are a containment then the first item will be ConfigurationContainmentAppearance
if (configDialog.configModel.get(0).source) { // if the applet does not have own configs then the first item will be Shortcuts
pageStack.sourceFile = configDialog.configModel.get(0).source if (isContainment || !configDialog.configModel || configDialog.configModel.count === 0) {
} else if (configDialog.configModel.get(0).kcm) { open(root.globalConfigModel.get(0))
pageStack.sourceFile = Qt.resolvedUrl("ConfigurationKcmPage.qml");
pageStack.currentItem.kcm = configDialog.configModel.get(0).kcm;
} else { } else {
pageStack.sourceFile = ""; open(configDialog.configModel.get(0))
}
pageStack.title = configDialog.configModel.get(0).name
} 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;
} }
} }
//END connections //END connections
//BEGIN UI components //BEGIN UI components
Rectangle { Component {
id: dialogContents id: configurationKcmPageComponent
visible: true ConfigurationKcmPage {}
anchors.fill: parent }
color: Kirigami.Theme.backgroundColor
ColumnLayout { Component {
id: dialogRootItem 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 anchors.fill: parent
spacing: 0 pageStack.globalToolBar.canContainHandles: true
implicitWidth: scroll.implicitWidth pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.ToolBar
pageStack.globalToolBar.showNavigationButtons: Kirigami.ApplicationHeaderStyle.ShowBackButton;
QtControls.ScrollView { property var currentConfigPage: null
id: scroll property bool isAboutPage: false
activeFocusOnTab: false // pop pages when not in use
Connections {
Layout.fillWidth: true target: app.pageStack
Layout.fillHeight: true function onCurrentIndexChanged() {
// wait for animation to finish before popping pages
implicitWidth: pageColumn.implicitWidth timer.restart();
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 Timer {
if (configurationChangedSignal) { id: timer
configurationChangedSignal.connect(root.settingValueChanged) interval: 300
} onTriggered: {
let currentIndex = app.pageStack.currentIndex;
scroll.flickableItem.contentY = 0 while (app.pageStack.depth > (currentIndex + 1) && currentIndex >= 0) {
app.pageStack.pop();
/*
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
}
}
}
}
}
}
}
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
} }
} }
} }
QtControls.ScrollView { footer: Kirigami.NavigationTabBar {
id: categoriesScroll id: footerBar
visible: count > 1
Layout.fillWidth: true height: visible ? implicitHeight : 0
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 { Repeater {
model: root.isContainment ? globalConfigModel : undefined model: root.isContainment ? globalConfigModel : undefined
delegate: ConfigCategoryDelegate {} delegate: configCategoryDelegate
} }
Repeater { Repeater {
model: configDialogFilterModel model: configDialogFilterModel
delegate: ConfigCategoryDelegate {} delegate: configCategoryDelegate
} }
Repeater { Repeater {
model: !root.isContainment ? globalConfigModel : undefined model: !root.isContainment ? globalConfigModel : undefined
delegate: ConfigCategoryDelegate {} delegate: configCategoryDelegate
} }
} }
} }
}
}
//END UI components //END UI components
} }

View file

@ -1,131 +0,0 @@
/*
* SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
*
* 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
}

View file

@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: 2020 Nicolas Fella <nicolas.fella@gmx.de>
// 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)
}
}
}
}

View file

@ -136,12 +136,6 @@ ColumnLayout {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Apply now") text: i18nd("plasma_shell_org.kde.plasma.desktop", "Apply now")
onClicked: saveConfig() onClicked: saveConfig()
} }
Binding {
target: categoriesScroll //from parent scope AppletConfiguration
property: "enabled"
value: !switchContainmentWarning.visible
}
} }
Item { Item {

View file

@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
// SPDX-FileCopyrightText: 2020 Nicolas Fella <nicolas.fella@gmx.de>
// SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
// 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()
}
}
}
}

View file

@ -1,29 +1,23 @@
/* // SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
* SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org> // SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
* // SPDX-License-Identifier: GPL-2.0-or-later
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Layouts 1.0 import QtQuick.Layouts 1.0
import QtQuick.Window 2.2 import QtQuick.Window 2.2
import QtQuick.Controls 2.3 as Controls import QtQuick.Controls 2.15 as Controls
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.configuration 2.0 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 { AppletConfiguration {
id: root id: root
isContainment: true isContainment: true
internalDialog.visible: false appComponent.visible: false
internalDialog.width: root.width < root.height ? root.width : Math.min(root.width, Math.max(internalDialog.implicitWidth, PlasmaCore.Units.gridUnit * 45)) appComponent.width: root.width < root.height ? root.width : Math.min(root.width, Math.max(appComponent.implicitWidth, PlasmaCore.Units.gridUnit * 45))
internalDialog.height: Math.min(root.height, Math.max(internalDialog.implicitHeight, PlasmaCore.Units.gridUnit * 29)) appComponent.height: Math.min(root.height, Math.max(appComponent.implicitHeight, PlasmaCore.Units.gridUnit * 29))
readonly property bool horizontal: root.width > root.height readonly property bool horizontal: root.width > root.height
@ -40,126 +34,74 @@ AppletConfiguration {
} }
//END model //END model
Controls.Drawer { Loader {
id: imageWallpaperDrawer id: wallpaperSelectorLoader
edge: root.horizontal ? Qt.LeftEdge : Qt.BottomEdge asynchronous: true
visible: true active: true
dragMargin: 0
onClosed: { sourceComponent: WallpaperSelector {
if (!root.internalDialog.visible) { visible: false
configDialog.close() horizontal: root.horizontal
} }
} }
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 { MouseArea {
id: wallpapersView z: -1
anchors.fill: parent anchors.fill: parent
orientation: root.horizontal ? ListView.Vertical : ListView.Horizontal onClicked: configDialog.close()
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.Control {
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)
}
}
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;
}
}
z: wallpapersView.currentIndex === index ? 2 : 0
contentItem: Item {
Addons.QIconItem {
anchors.centerIn: parent anchors.centerIn: parent
width: PlasmaCore.Units.iconSizes.large leftPadding: PlasmaCore.Units.largeSpacing
height: width rightPadding: PlasmaCore.Units.largeSpacing
icon: "view-preview" topPadding: PlasmaCore.Units.largeSpacing
visible: !walliePreview.visible bottomPadding: PlasmaCore.Units.largeSpacing
}
Addons.QPixmapItem { NumberAnimation on opacity {
id: walliePreview id: opacityAnim
anchors.fill: parent running: true
visible: model.screenshot != null from: 0
smooth: true to: 1
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 duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad }
background: PlasmaCore.FrameSvgItem {
enabledBorders: PlasmaCore.FrameSvg.AllBorders
imagePath: "widgets/background"
}
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();
} }
} }
}
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()
} }
} }
} }

View file

@ -0,0 +1,120 @@
// SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// 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
}
}
}
}
}