From ad54f0a1a264b1b3a18dcb5a2da90b7e2b75bd5e Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Fri, 19 Jun 2015 17:52:09 -0700 Subject: [PATCH] simple widgetexplorer derived from desktop one --- .../package/contents/ui/EditOverlay.qml | 78 +++++++ .../homescreen/package/contents/ui/main.qml | 11 +- shell/contents/explorer/AppletDelegate.qml | 153 +++++++++++++ shell/contents/explorer/WidgetExplorer.qml | 208 ++++++++++++++++++ shell/contents/views/Desktop.qml | 26 +++ 5 files changed, 471 insertions(+), 5 deletions(-) create mode 100644 containments/homescreen/package/contents/ui/EditOverlay.qml create mode 100644 shell/contents/explorer/AppletDelegate.qml create mode 100644 shell/contents/explorer/WidgetExplorer.qml diff --git a/containments/homescreen/package/contents/ui/EditOverlay.qml b/containments/homescreen/package/contents/ui/EditOverlay.qml new file mode 100644 index 00000000..3c5c8820 --- /dev/null +++ b/containments/homescreen/package/contents/ui/EditOverlay.qml @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2015 Marco Martin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) version 3, or any + * later version accepted by the membership of KDE e.V. (or its + * successor approved by the membership of KDE e.V.), which shall + * act as a proxy defined in Section 6 of version 3 of the license. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + */ + +import QtQuick 2.0 +import QtQuick.Layouts 1.1 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtras + +import org.kde.milou 0.1 as Milou + +Rectangle { + id: editOverlay + anchors.fill: parent + + color: Qt.rgba(0, 0, 0, 0.8) + visible: false + + MouseArea { + enabled: listView.visible + anchors.fill: parent + preventStealing: true + onClicked: editOverlay.visible = false; + } + PlasmaCore.FrameSvgItem { + id: background + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + bottomMargin: editOverlay.height - (plasmoid.availableScreenRect.y + plasmoid.availableScreenRect.height) + } + height: buttonsLayout.height + margins.top + imagePath: "widgets/background" + enabledBorders: PlasmaCore.FrameSvg.TopBorder + RowLayout { + id: buttonsLayout + anchors { + left: parent.left + right: parent.right + top: parent.top + topMargin: parent.margins.top + } + PlasmaComponents.Button { + Layout.fillWidth: true + Layout.fillHeight:true + text: i18n("Wallpaper...") + onClicked: plasmoid.action("configure").trigger(); + } + PlasmaComponents.Button { + Layout.fillWidth: true + Layout.fillHeight:true + text: i18n("Add Widgets...") + onClicked: plasmoid.action("add widgets").trigger(); + } + } + } +} + diff --git a/containments/homescreen/package/contents/ui/main.qml b/containments/homescreen/package/contents/ui/main.qml index 429b666d..a1b46e4d 100644 --- a/containments/homescreen/package/contents/ui/main.qml +++ b/containments/homescreen/package/contents/ui/main.qml @@ -169,7 +169,7 @@ Item { } KRunner { id: krunner - z: 1000 + z: 999 anchors { top: parent.top left: parent.left @@ -177,13 +177,14 @@ Item { topMargin: plasmoid.availableScreenRect.y } } + EditOverlay { + id: editOverlay + z: 1000 + } MouseEventListener { anchors.fill: parent onPressAndHold: { - if (krunner.showingResults) { - return; - } var pos = mapToItem(applicationsView.headerItem.favoritesStrip, mouse.x, mouse.y); //in favorites area? var item; @@ -478,7 +479,7 @@ Item { onPressAndHold: { print(favoritesView.contains(mapToItem(favoritesView, mouse.x, mouse.y))) if (!favoritesView.contains(mapToItem(favoritesView, mouse.x, mouse.y))) { - plasmoid.action("configure").trigger(); + editOverlay.visible = true; } } diff --git a/shell/contents/explorer/AppletDelegate.qml b/shell/contents/explorer/AppletDelegate.qml new file mode 100644 index 00000000..0f5816a9 --- /dev/null +++ b/shell/contents/explorer/AppletDelegate.qml @@ -0,0 +1,153 @@ +/* + * Copyright 2011 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.4 +import QtQuick.Layouts 1.1 + +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtras +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.draganddrop 2.0 +import org.kde.kquickcontrolsaddons 2.0 + +Item { + id: delegate + + readonly property string pluginName: model.pluginName + + width: list.width + height: iconContainer.height + units.largeSpacing + + + RowLayout { + anchors { + fill: parent + margins: units.smallSpacing + rightMargin: units.smallSpacing * 2 // don't cram the text to the border too much + } + spacing: units.largeSpacing + + Item { + id: iconContainer + width: units.iconSizes.huge + height: width + + QIconItem { + id: iconWidget + anchors.fill: parent + icon: model.decoration + } + + Item { + id: badgeMask + anchors.fill: parent + + Rectangle { + x: Math.round(-units.smallSpacing * 1.5 / 2) + y: x + width: runningBadge.width + Math.round(units.smallSpacing * 1.5) + height: width + radius: height + visible: running + } + } + + Rectangle { + id: runningBadge + width: height + height: Math.round(theme.mSize(countLabel.font).height * 1.3) + radius: height + color: theme.highlightColor + visible: running + onVisibleChanged: maskShaderSource.scheduleUpdate() + + PlasmaComponents.Label { + id: countLabel + anchors.fill: parent + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: theme.backgroundColor + text: running + } + } + + ShaderEffect { + anchors.fill: parent + property var source: ShaderEffectSource { + sourceItem: iconWidget + hideSource: true + live: false + } + property var mask: ShaderEffectSource { + id: maskShaderSource + sourceItem: badgeMask + hideSource: true + live: false + } + + supportsAtlasTextures: true + + fragmentShader: " + varying highp vec2 qt_TexCoord0; + uniform highp float qt_Opacity; + uniform lowp sampler2D source; + uniform lowp sampler2D mask; + void main() { + gl_FragColor = texture2D(source, qt_TexCoord0.st) * (1.0 - (texture2D(mask, qt_TexCoord0.st).a)) * qt_Opacity; + } + " + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: units.smallSpacing + + PlasmaExtras.Heading { + id: heading + Layout.fillWidth: true + level: 4 + text: model.name + elide: Text.ElideRight + wrapMode: Text.WordWrap + maximumLineCount: 2 + lineHeight: 0.95 + } + PlasmaComponents.Label { + Layout.fillWidth: true + // otherwise causes binding loop due to the way the Plasma sets the height + height: implicitHeight + text: model.description + font.pointSize: theme.smallestFont.pointSize + wrapMode: Text.WordWrap + elide: Text.ElideRight + maximumLineCount: heading.lineCount === 1 ? 3 : 2 + } + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onDoubleClicked: widgetExplorer.addApplet(pluginName) + onEntered: delegate.ListView.view.currentIndex = index + onExited: delegate.ListView.view.currentIndex = -1 + } +} diff --git a/shell/contents/explorer/WidgetExplorer.qml b/shell/contents/explorer/WidgetExplorer.qml new file mode 100644 index 00000000..672bebb8 --- /dev/null +++ b/shell/contents/explorer/WidgetExplorer.qml @@ -0,0 +1,208 @@ +/* + * Copyright 2011 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.2 +import QtQuick.Controls 1.1 + +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.extras 2.0 as PlasmaExtras +import org.kde.kquickcontrolsaddons 2.0 + +import QtQuick.Window 2.1 +import QtQuick.Layouts 1.1 + +import org.kde.plasma.private.shell 2.0 + +PlasmaCore.FrameSvgItem { + id: main + imagePath: "widgets/background" + enabledBorders: PlasmaCore.FrameSvgItem.RightBorder + + width: Math.max(heading.paintedWidth, units.gridUnit * 16) + height: 800//Screen.height + + property alias containment: widgetExplorer.containment + + //external drop events can cause a raise event causing us to lose focus and + //therefore get deleted whilst we are still in a drag exec() + //this is a clue to the owning dialog that hideOnWindowDeactivate should be deleted + //See https://bugs.kde.org/show_bug.cgi?id=332733 + property bool preventWindowHide: false + + property Item getWidgetsButton + property Item categoryButton + + signal closed() + + function addCurrentApplet() { + var pluginName = list.currentItem ? list.currentItem.pluginName : "" + if (pluginName) { + widgetExplorer.addApplet(pluginName) + } + } + + + WidgetExplorer { + id: widgetExplorer + //view: desktop + onShouldClose: main.closed(); + } + + GridLayout { + id: topBar + anchors { + top: parent.top + left: parent.left + right: parent.right + topMargin: 0 + leftMargin: units.smallSpacing + rightMargin: main.margins.right + } + columns: 2 + + PlasmaExtras.Title { + id: heading + text: i18nd("plasma_shell_org.kde.plasma.desktop", "Widgets") + Layout.fillWidth: true + } + + PlasmaComponents.ToolButton { + id: closeButton + anchors { + right: parent.right + verticalCenter: heading.verticalCenter + } + iconSource: "window-close" + onClicked: main.closed() + } + + PlasmaComponents.TextField { + id: searchInput + clearButtonShown: true + placeholderText: i18nd("plasma_shell_org.kde.plasma.desktop", "Search...") + onTextChanged: { + list.positionViewAtBeginning() + list.currentIndex = -1 + widgetExplorer.widgetsModel.searchTerm = text + } + + Component.onCompleted: forceActiveFocus() + Layout.columnSpan: 2 + Layout.fillWidth: true + } + } + + PlasmaCore.FrameSvgItem { + id: backgroundHint + imagePath: "widgets/viewitem" + prefix: "normal" + visible: false + } + PlasmaExtras.ScrollArea { + anchors { + top: topBar.bottom + left: parent.left + right: parent.right + bottom: bottomBar.top + topMargin: units.smallSpacing + leftMargin: units.smallSpacing + bottomMargin: units.smallSpacing + rightMargin: main.margins.right + } + ListView { + id: list + + model: widgetExplorer.widgetsModel + activeFocusOnTab: true + currentIndex: -1 + keyNavigationWraps: true + + delegate: AppletDelegate {} + + //slide in to view from the left + add: Transition { + NumberAnimation { + properties: "x" + from: -list.width + to: 0 + duration: units.shortDuration * 3 + + } + } + + //slide out of view to the right + remove: Transition { + NumberAnimation { + properties: "x" + to: list.width + duration: units.shortDuration * 3 + } + } + + //if we are adding other items into the view use the same animation as normal adding + //this makes everything slide in together + //if we make it move everything ends up weird + addDisplaced: list.add + + //moved due to filtering + displaced: Transition { + NumberAnimation { + properties: "y" + duration: units.shortDuration * 3 + } + } + } + } + + Column { + id: bottomBar + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + leftMargin: units.smallSpacing + rightMargin: units.smallSpacing + bottomMargin: units.smallSpacing + } + + spacing: units.smallSpacing + + Repeater { + model: widgetExplorer.extraActions.length + PlasmaComponents.Button { + anchors { + left: parent.left + right: parent.right + } + iconSource: widgetExplorer.extraActions[modelData].icon + text: widgetExplorer.extraActions[modelData].text + onClicked: { + widgetExplorer.extraActions[modelData].trigger() + } + } + } + } + + Component.onCompleted: { + main.getWidgetsButton = getWidgetsButton + main.categoryButton = categoryButton + } +} + diff --git a/shell/contents/views/Desktop.qml b/shell/contents/views/Desktop.qml index cd5457d6..d9044a48 100644 --- a/shell/contents/views/Desktop.qml +++ b/shell/contents/views/Desktop.qml @@ -38,6 +38,32 @@ Item { property int notificationId: 0; property int buttonHeight: width/4 + function toggleWidgetExplorer(containment) { + console.log("Widget Explorer toggled"); + if (widgetExplorerStack.source != "") { + widgetExplorerStack.source = ""; + } else { + widgetExplorerStack.setSource(Qt.resolvedUrl("../explorer/WidgetExplorer.qml"), {"containment": containment}) + } + } + + Loader { + id: widgetExplorerStack + z: 99 + asynchronous: true + y: containment ? containment.availableScreenRect.y : 0 + height: containment ? containment.availableScreenRect.height : parent.height + width: item ? item.width: 0 + + onLoaded: { + if (widgetExplorerStack.item) { + item.closed.connect(function() { + widgetExplorerStack.source = "" + }); + } + } + } + onContainmentChanged: { containment.parent = homescreen;