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-License-Identifier: GPL-2.0-or-later
*/
// 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.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

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")
onClicked: saveConfig()
}
Binding {
target: categoriesScroll //from parent scope AppletConfiguration
property: "enabled"
value: !switchContainmentWarning.visible
}
}
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-License-Identifier: GPL-2.0-or-later
*/
// 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 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()
}
}
}

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
}
}
}
}
}