diff --git a/containments/homescreen2/package/contents/ui/launcher/Delegate.qml b/containments/homescreen2/package/contents/ui/launcher/Delegate.qml new file mode 100644 index 00000000..28ab9147 --- /dev/null +++ b/containments/homescreen2/package/contents/ui/launcher/Delegate.qml @@ -0,0 +1,144 @@ +/* + * Copyright 2019 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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 General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.3 as Controls + +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.kquickcontrolsaddons 2.0 + + +Controls.Control { + id: delegate + + z: dragging ? 1 : 0 + + property var modelData: typeof model !== "undefined" ? model : null + property bool dragging + property Controls.Control dragDelegate + + Drag.active: false + Drag.hotSpot.x: delegate.width/2 + Drag.hotSpot.y: delegate.height/2 + Drag.mimeData: { "text/uri-list": modelData ? "file://" + modelData.ApplicationDesktopRole : "" } + Drag.dragType: Drag.Automatic + + leftPadding: units.smallSpacing*2 + topPadding: units.smallSpacing*2 + rightPadding: units.smallSpacing*2 + bottomPadding: units.smallSpacing*2 + + opacity: dragging ? 0.4 : 1 + + onDraggingChanged: { + if (dragging) { + dragDelegate.x = delegate.x + dragDelegate.y = delegate.y + dragDelegate.modelData = model; + root.reorderingApps = true; + } else { + dragDelegate.modelData = null; + root.reorderingApps = false; + } + } + contentItem: MouseArea { + drag.target: dragging ? dragDelegate : null + + onClicked: { + if (modelData.ApplicationStartupNotifyRole) { + clickFedbackAnimation.target = delegate; + clickFedbackAnimation.running = true; + feedbackWindow.title = modelData.ApplicationNameRole; + feedbackWindow.state = "open"; + } + plasmoid.nativeInterface.applicationListModel.runApplication(modelData.ApplicationStorageIdRole); + } + + onPressAndHold: { + delegate.dragging = true; + } + + onReleased: delegate.dragging = false; + + onCanceled: delegate.dragging = false; + + onPositionChanged: { + if (!dragging || !dragDelegate) { + return; + } + + if (dragDelegate.x + dragDelegate.width < 0 + || dragDelegate.y + dragDelegate.height < 0 + || dragDelegate.x > applicationsFlow.width + || dragDelegate.y > applicationsFlow.height) { + dragging = false; + delegate.grabToImage(function(result) { + root.externalDragStarted(); + delegate.Drag.imageSource = result.url; + delegate.Drag.active = true; + }) + return; + } + + var newRow = Math.round(applicationsFlow.width / dragDelegate.width) * Math.floor((dragDelegate.y+dragDelegate.height/2) / dragDelegate.height) + Math.floor((dragDelegate.x+dragDelegate.width/2) / dragDelegate.width); + + plasmoid.nativeInterface.applicationListModel.moveItem(modelData.index, newRow); + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + PlasmaCore.IconItem { + id: icon + + Layout.alignment: Qt.AlignHCenter | Qt.AlignTop + Layout.fillWidth: true + Layout.preferredHeight: parent.height - root.reservedSpaceForLabel + + source: modelData ? modelData.ApplicationIconRole : "" + scale: root.reorderingApps && dragDelegate && !dragging ? 0.6 : 1 + Behavior on scale { + NumberAnimation { + duration: units.longDuration + easing.type: Easing.InOutQuad + } + } + } + + PlasmaComponents.Label { + id: label + visible: text.length > 0 + + Layout.fillWidth: true + Layout.fillHeight: true + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignTop + maximumLineCount: 2 + elide: Text.ElideRight + + text: modelData ? modelData.ApplicationNameRole : "" + font.pixelSize: theme.defaultFont.pixelSize + color: PlasmaCore.ColorScope.textColor + } + } + } +} diff --git a/containments/homescreen2/package/contents/ui/launcher/FeedbackWindow.qml b/containments/homescreen2/package/contents/ui/launcher/FeedbackWindow.qml new file mode 100644 index 00000000..b9b92f09 --- /dev/null +++ b/containments/homescreen2/package/contents/ui/launcher/FeedbackWindow.qml @@ -0,0 +1,102 @@ +/* + * Copyright 2015 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 Library 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.0 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.2 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +Window { + id: window + + property alias state: background.state + width: Screen.width + height: Screen.height + color: "transparent" + onVisibleChanged: { + if (!visible) { + background.state = "closed"; + } + } + onActiveChanged: { + if (!active) { + background.state = "closed"; + } + } + + PlasmaCore.ColorScope { + id: background + anchors.fill: parent + colorGroup: PlasmaCore.Theme.ComplementaryColorGroup + width: window.width + height: window.height + state: "closed" + Rectangle { + anchors.fill: parent + color: background.backgroundColor + + PlasmaComponents.BusyIndicator { + anchors.centerIn: parent + } + } + + states: [ + State { + name: "closed" + PropertyChanges { + target: background + scale: 0 + } + PropertyChanges { + target: window + visible: false + } + }, + State { + name: "open" + PropertyChanges { + target: background + scale: 1 + } + PropertyChanges { + target: window + visible: true + } + } + ] + + transitions: [ + Transition { + from: "closed" + SequentialAnimation { + ScriptAction { + script: window.visible = true; + } + PropertyAnimation { + target: background + duration: units.longDuration + easing.type: Easing.InOutQuad + properties: "scale" + } + } + } + ] + } +} diff --git a/containments/homescreen2/package/contents/ui/launcher/LauncherGrid.qml b/containments/homescreen2/package/contents/ui/launcher/LauncherGrid.qml new file mode 100644 index 00000000..bc841c59 --- /dev/null +++ b/containments/homescreen2/package/contents/ui/launcher/LauncherGrid.qml @@ -0,0 +1,127 @@ +/* + * Copyright 2019 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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 General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.3 as Controls + +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.kquickcontrolsaddons 2.0 + + +Controls.Control { + id: root + + readonly property bool dragging: applicationsFlow.dragData + property bool reorderingApps: false + + property int availableCellHeight: units.iconSizes.huge + reservedSpaceForLabel + + readonly property int reservedSpaceForLabel: metrics.height + + readonly property int cellWidth: applicationsFlow.width / Math.floor(applicationsFlow.width / ((availableCellHeight - reservedSpaceForLabel) + units.smallSpacing*4)) + readonly property int cellHeight: availableCellHeight - topPadding + + signal externalDragStarted + signal dragPositionChanged(point pos) + + implicitHeight: applicationsFlow.implicitHeight + frame.margins.top + frame.margins.bottom + + leftPadding: frame.margins.left + topPadding: frame.margins.top + rightPadding: frame.margins.right + bottomPadding: frame.margins.bottom + + background: PlasmaCore.FrameSvgItem { + id: frame + imagePath: "widgets/background" + anchors.fill: parent + + Rectangle { + y: root.cellHeight + frame.margins.top + color: theme.textColor + opacity: 0.3 + height: 1 + anchors { + left: parent.left + right: parent.right + leftMargin: frame.margins.left + rightMargin: frame.margins.right + } + } + } + + contentItem: Item { + //NOTE: TextMetrics can't handle multi line + Controls.Label { + id: metrics + text: "M\nM" + visible: false + } + + //This Delegate is the placeholder for the "drag" + //delegate (that is not actual drag and drop + Delegate { + id: dragDelegateItem + z: 999 + width: root.cellWidth + height: root.cellHeight + onYChanged: dragPositionChanged(Qt.point(x, y)) + + visible: modelData !== null + } + + Flow { + id: applicationsFlow + anchors.fill: parent + + spacing: 0 + + property var dragData + property int startContentYDrag + property bool viewHasBeenDragged + + + NumberAnimation { + id: scrollAnim + target: applicationsFlow + properties: "contentY" + duration: units.longDuration + easing.type: Easing.InOutQuad + } + move: Transition { + NumberAnimation { + duration: units.longDuration + easing.type: Easing.InOutQuad + properties: "x,y" + } + } + + Repeater { + model: plasmoid.nativeInterface.applicationListModel + delegate: Delegate { + width: root.cellWidth + height: root.cellHeight + dragDelegate: dragDelegateItem + } + } + } + } +} diff --git a/containments/homescreen2/package/contents/ui/launcher/LauncherScroller.qml b/containments/homescreen2/package/contents/ui/launcher/LauncherScroller.qml new file mode 100644 index 00000000..33a228fe --- /dev/null +++ b/containments/homescreen2/package/contents/ui/launcher/LauncherScroller.qml @@ -0,0 +1,182 @@ +/* + * Copyright 2019 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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 General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + +import QtQuick 2.4 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.3 as Controls + +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.kquickcontrolsaddons 2.0 + + +MouseArea { + id: root + + property alias availableCellHeight: launcherGrid.availableCellHeight + property alias contentY: mainFlickable.contentY + property alias contentHeight: mainFlickable.contentHeight + property alias topMargin: mainFlickable.topMargin + property int leftPadding + property int rightPadding + signal movementEnded + signal externalDragStarted + + drag.filterChildren: true + + onClicked: closeAnim.restart() + +//BEGIN functions + //Autoscroll related functions + function scrollUp() { + autoScrollTimer.scrollDown = false; + autoScrollTimer.running = true; + scrollUpIndicator.opacity = 1; + scrollDownIndicator.opacity = 0; + } + + function scrollDown() { + autoScrollTimer.scrollDown = true; + autoScrollTimer.running = true; + scrollUpIndicator.opacity = 0; + scrollDownIndicator.opacity = 1; + } + + function stopScroll() { + autoScrollTimer.running = false; + scrollUpIndicator.opacity = 0; + scrollDownIndicator.opacity = 0; + } +//END functions + + Timer { + id: autoScrollTimer + property bool scrollDown: true + repeat: true + interval: 1500 + onTriggered: { + //reordering launcher icons + if (launcherGrid.reorderingApps) { + scrollAnim.to = scrollDown ? + //Scroll down + Math.min(mainFlickable.contentItem.height - root.height, mainFlickable.contentY + root.height/2) : + //Scroll up + Math.max(0, mainFlickable.contentY - root.height/2); + + } else { + stopScroll(); + } + scrollAnim.running = true; + } + } + + NumberAnimation { + id: scrollAnim + target: mainFlickable + property: "contentY" + duration: units.longDuration + easing.type: Easing.InOutQuad + } + + PlasmaCore.Svg { + id: arrowsSvg + imagePath: "widgets/arrows" + } + PlasmaCore.SvgItem { + id: scrollUpIndicator + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + topMargin: 300 + } + z: 2 + opacity: 0 + svg: arrowsSvg + elementId: "up-arrow" + width: units.iconSizes.large + height: width + Behavior on opacity { + OpacityAnimator { + duration: 1000 + easing.type: Easing.InOutQuad + } + } + } + PlasmaCore.SvgItem { + id: scrollDownIndicator + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + bottomMargin: units.gridUnit * 2 + } + z: 2 + opacity: 0 + svg: arrowsSvg + elementId: "down-arrow" + width: units.iconSizes.large + height: width + Behavior on opacity { + OpacityAnimator { + duration: 1000 + easing.type: Easing.InOutQuad + } + } + } + + Flickable { + id: mainFlickable + anchors{ + fill: parent + leftMargin: root.leftPadding + rightMargin: root.rightPadding + } + contentWidth: width + contentHeight: launcherGrid.height + onMovementEnded: root.movementEnded(); + onFlickEnded: root.movementEnded(); + LauncherGrid { + id: launcherGrid + width: parent.width + onExternalDragStarted: root.externalDragStarted() + onDragPositionChanged: { + pos = mapToItem(root, pos.x, pos.y); + + if (pos.y < root.height /3) { + scrollUp(); + } else if (pos.y > root.height / 3 * 2) { + scrollDown(); + } else { + stopScroll(); + } + } + } + } + + PlasmaComponents.ScrollBar { + anchors { + top: parent.top + right: parent.right + bottom: parent.bottom + topMargin: Math.max(0, -mainFlickable.contentY) + units.smallSpacing*2 + rightMargin: root.rightPadding + units.smallSpacing * 2 + } + interactive: false + flickableItem: mainFlickable + } +} diff --git a/containments/homescreen2/package/contents/ui/main.qml b/containments/homescreen2/package/contents/ui/main.qml index 5253437b..f1ef4b5b 100644 --- a/containments/homescreen2/package/contents/ui/main.qml +++ b/containments/homescreen2/package/contents/ui/main.qml @@ -26,6 +26,8 @@ import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.draganddrop 2.0 as DragDrop +import "launcher" as Launcher + import org.kde.plasma.private.containmentlayoutmanager 1.0 as ContainmentLayoutManager Item { @@ -68,67 +70,78 @@ Item { Text { text:"Edit Mode" color: "white" - visible: appletsLayout.editMode + visible: plasmoid.editMode } Connections { target: plasmoid - onEditModeChanged: appletsLayout.editMode = plasmoid.editMode + onEditModeChanged: { + appletsLayout.editMode = plasmoid.editMode + if (plasmoid.editMode) { + menuRepeater.freeLayout(); + } else { + menuRepeater.relayout(); + } + } } - ContainmentLayoutManager.AppletsLayout { - id: appletsLayout + Flickable { anchors.fill: parent - configKey: width > height ? "ItemGeometries" : "ItemGeometriesVertical" - containment: plasmoid - editModeCondition: plasmoid.immutable - ? ContainmentLayoutManager.AppletsLayout.Manual - : ContainmentLayoutManager.AppletsLayout.AfterPressAndHold + contentWidth: width + contentHeight: appletsLayout.height + interactive: !plasmoid.editMode - // Sets the containment in edit mode when we go in edit mode as well - onEditModeChanged: plasmoid.editMode = editMode + ContainmentLayoutManager.AppletsLayout { + id: appletsLayout + width: parent.width + height: 500 + launcher.height + configKey: width > height ? "ItemGeometries" : "ItemGeometriesVertical" + containment: plasmoid + editModeCondition: plasmoid.immutable + ? ContainmentLayoutManager.AppletsLayout.Manual + : ContainmentLayoutManager.AppletsLayout.AfterPressAndHold - minimumItemWidth: units.gridUnit * 3 - minimumItemHeight: minimumItemWidth + // Sets the containment in edit mode when we go in edit mode as well + onEditModeChanged: plasmoid.editMode = editMode - defaultItemWidth: units.gridUnit * 6 - defaultItemHeight: defaultItemWidth + minimumItemWidth: units.gridUnit * 3 + minimumItemHeight: minimumItemWidth - cellWidth: units.iconSizes.small - cellHeight: cellWidth + defaultItemWidth: units.gridUnit * 6 + defaultItemHeight: defaultItemWidth - acceptsAppletCallback: function(applet, x, y) { - print("Applet: "+applet+" "+x+" "+y) - return true; - } + cellWidth: units.iconSizes.small + cellHeight: cellWidth - appletContainerComponent: ContainmentLayoutManager.BasicAppletContainer { - id: appletContainer - configOverlayComponent: ConfigOverlay {} - } + acceptsAppletCallback: function(applet, x, y) { + print("Applet: "+applet+" "+x+" "+y) + return true; + } - placeHolder: ContainmentLayoutManager.PlaceHolder {} + appletContainerComponent: ContainmentLayoutManager.BasicAppletContainer { + id: appletContainer + configOverlayComponent: ConfigOverlay {} + onEditModeChanged: { + if (editMode) { + plasmoid.editMode = true; + } + } + } - Repeater { - model: 3 - ContainmentLayoutManager.ItemContainer { - id: extraIcon - key: "Icon-" + modelData - preferredLayoutDirection: editMode ? ContainmentLayoutManager.AppletsLayout.Closest : ContainmentLayoutManager.AppletsLayout.TopToBottom - x: 16 - y: 16 - implicitWidth: 48 - implicitHeight: 48 - - editModeCondition: ContainmentLayoutManager.ItemContainer.AfterPress + placeHolder: ContainmentLayoutManager.PlaceHolder {} - Rectangle { - anchors.fill: parent - color: extraIcon.focus ? "green" : "red" - radius: width - opacity: extraIcon.editMode ? 0.6 : 1 + Launcher.LauncherGrid { + id: launcher + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom } } } } + Controls.Button { + text: "load" + onClicked: menuRepeater.model = plasmoid.nativeInterface.applicationListModel + } } }