diff --git a/applets/kickoff/package/contents/ui/ApplicationsView.qml b/applets/kickoff/package/contents/ui/ApplicationsView.qml index 7d4d71adf..3fd9d9458 100644 --- a/applets/kickoff/package/contents/ui/ApplicationsView.qml +++ b/applets/kickoff/package/contents/ui/ApplicationsView.qml @@ -1,293 +1,293 @@ /* Copyright (C) 2011 Martin Gräßlin Copyright (C) 2012 Gregor Taetzner Copyright 2014 Sebastian Kügler Copyright (C) 2015 Eike Hein 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 02110-1301 USA. */ import QtQuick 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.components 2.0 as PlasmaComponents +import Qt.labs.handlers 1.0 Item { id: appViewContainer anchors.fill: parent objectName: "ApplicationsView" property ListView listView: applicationsView function decrementCurrentIndex() { applicationsView.decrementCurrentIndex(); } function incrementCurrentIndex() { applicationsView.incrementCurrentIndex(); } function activateCurrentIndex(start) { if (!applicationsView.currentItem.modelChildren) { if (!start) { return; } } appViewScrollArea.state = "OutgoingLeft"; } function openContextMenu() { applicationsView.currentItem.openActionMenu(); } function deactivateCurrentIndex() { if (crumbModel.count > 0) { // this is not the case when switching from the "Applications" to the "Favorites" tab using the "Left" key breadcrumbsElement.children[crumbModel.count-1].clickCrumb(); appViewScrollArea.state = "OutgoingRight"; return true; } return false; } function reset() { applicationsView.model = rootModel; applicationsView.positionViewAtBeginning(); applicationsView.clearBreadcrumbs(); } function refreshed() { reset(); updatedLabelTimer.running = true; } Connections { target: plasmoid onExpandedChanged: { if (!expanded) { reset(); } } } Item { id: crumbContainer anchors { top: parent.top left: parent.left right: parent.right } height: childrenRect.height Behavior on opacity { NumberAnimation { duration: units.longDuration } } Flickable { id: breadcrumbFlickable anchors { top: parent.top left: parent.left right: parent.right } height: breadcrumbsElement.height boundsBehavior: Flickable.StopAtBounds contentWidth: breadcrumbsElement.width pixelAligned: true //contentX: contentWidth - width // HACK: Align the content to right for RTL locales leftMargin: LayoutMirroring.enabled ? Math.max(0, width - contentWidth) : 0 PlasmaComponents.ButtonRow { id: breadcrumbsElement exclusive: false Breadcrumb { id: rootBreadcrumb root: true text: i18n("All Applications") depth: 0 } Repeater { model: ListModel { id: crumbModel // Array of the models property var models: [] } Breadcrumb { root: false text: model.text } } onWidthChanged: { if (LayoutMirroring.enabled) { breadcrumbFlickable.contentX = -Math.max(0, breadcrumbsElement.width - breadcrumbFlickable.width) } else { breadcrumbFlickable.contentX = Math.max(0, breadcrumbsElement.width - breadcrumbFlickable.width) } } } } // Flickable } // crumbContainer PlasmaExtras.ScrollArea { id: appViewScrollArea property Item activatedItem: null anchors { top: crumbContainer.bottom bottom: parent.bottom rightMargin: -units.largeSpacing leftMargin: -units.largeSpacing } Behavior on opacity { NumberAnimation { duration: units.longDuration } } width: parent.width function moveRight() { state = ""; activatedItem.activate() applicationsView.positionViewAtBeginning() } function moveLeft() { state = ""; // newModelIndex set by clicked breadcrumb var oldModel = applicationsView.model; applicationsView.model = applicationsView.newModel; applicationsView.positionViewAtIndex(applicationsView.model.rowForModel(oldModel), ListView.Center) } ListView { id: applicationsView property variant newModel focus: true keyNavigationWraps: true boundsBehavior: Flickable.StopAtBounds highlight: KickoffHighlight {} highlightMoveDuration : 0 highlightResizeDuration: 0 model: rootModel delegate: KickoffItem { id: kickoffItem appView: true } function addBreadcrumb(model, title) { crumbModel.append({"text": title, "depth": crumbModel.count+1}) crumbModel.models.push(model); } function clearBreadcrumbs() { crumbModel.clear(); crumbModel.models = []; } + TapHandler { + acceptedButtons: Qt.BackButton + onTapped: { + deactivateCurrentIndex() + } + } } // applicationsView states: [ State { name: "OutgoingLeft" PropertyChanges { target: appViewScrollArea x: -parent.width opacity: 0.0 } }, State { name: "OutgoingRight" PropertyChanges { target: appViewScrollArea x: parent.width opacity: 0.0 } } ] transitions: [ Transition { to: "OutgoingLeft" SequentialAnimation { // We need to cache the currentItem since the selection can move during animation, // and we want the item that has been clicked on, not the one that is under the // mouse once the animation is done ScriptAction { script: appViewScrollArea.activatedItem = applicationsView.currentItem } NumberAnimation { properties: "x,opacity"; easing.type: Easing.InQuad; duration: units.longDuration } ScriptAction { script: appViewScrollArea.moveRight() } } }, Transition { to: "OutgoingRight" SequentialAnimation { NumberAnimation { properties: "x,opacity"; easing.type: Easing.InQuad; duration: units.longDuration } ScriptAction { script: appViewScrollArea.moveLeft() } } } ] } // appViewScrollArea - MouseArea { - anchors.fill: appViewScrollArea - acceptedButtons: Qt.BackButton - onClicked: { - deactivateCurrentIndex() - } - } Timer { id: updatedLabelTimer interval: 1500 running: false repeat: true onRunningChanged: { if (running) { updatedLabel.opacity = 1; crumbContainer.opacity = 0.3; appViewScrollArea.opacity = 0.3; } } onTriggered: { updatedLabel.opacity = 0; crumbContainer.opacity = 1; appViewScrollArea.opacity = 1; running = false; } } PlasmaComponents.Label { id: updatedLabel text: i18n("Applications updated.") opacity: 0 visible: opacity != 0 anchors.centerIn: parent Behavior on opacity { NumberAnimation { duration: units.shortDuration } } } Component.onCompleted: { rootModel.cleared.connect(refreshed); } } // appViewContainer diff --git a/applets/kickoff/package/contents/ui/Header.qml b/applets/kickoff/package/contents/ui/Header.qml index 9337ae92b..1b57fd726 100644 --- a/applets/kickoff/package/contents/ui/Header.qml +++ b/applets/kickoff/package/contents/ui/Header.qml @@ -1,242 +1,238 @@ /* * Copyright 2014 Sebastian Kügler * * 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 02110-1301 USA. */ import QtQuick 2.0 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.kcoreaddons 1.0 as KCoreAddons import org.kde.kquickcontrolsaddons 2.0 +import Qt.labs.handlers 1.0 + Item { id: header implicitHeight: units.gridUnit * 5 property alias query: queryField.text property Item input: queryField KCoreAddons.KUser { id: kuser } state: (query !== "") ? "query" : "hint" Timer { id: labelTimer interval: 8000 repeat: true running: (header.state === "hint" || header.state === "info") && plasmoid.expanded && (header.query === "") onTriggered: { if (header.state == "info") { header.state = "hint"; } else if (header.state == "hint") { header.state = "info"; } } } Image { id: faceIcon source: kuser.faceIconUrl cache: false visible: source !== "" width: units.gridUnit * 3 height: width anchors { top: parent.top left: parent.left topMargin: units.gridUnit leftMargin: units.gridUnit } + TapHandler { + acceptedButtons: Qt.LeftButton +// cursorShape: Qt.PointingHandCursor + onTapped: { + KCMShell.open("user_manager") + } + } } PlasmaCore.IconItem { source: "user-identity" visible: faceIcon.status !== Image.Ready width: units.gridUnit * 3 height: width anchors { top: faceIcon.top right: faceIcon.right rightMargin: -units.gridUnit/2 } usesPlasmaTheme: false } - MouseArea { - anchors.fill: faceIcon - acceptedButtons: Qt.LeftButton - cursorShape: Qt.PointingHandCursor - onClicked: { - KCMShell.open("user_manager") - } - visible: KCMShell.authorize("user_manager.desktop").length > 0 - } - PlasmaExtras.Heading { id: nameLabel level: 2 text: kuser.fullName elide: Text.ElideRight horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignTop height: paintedHeight anchors { left: faceIcon.right top: faceIcon.top right: parent.right leftMargin: units.gridUnit rightMargin: units.gridUnit } } Item { id: searchWidget property int animationDuration: units.longDuration property real normalOpacity: .6 property int yOffset: height / 2 height: infoLabel.height anchors { left: nameLabel.left top: nameLabel.bottom right: nameLabel.right } PlasmaComponents.Label { id: infoLabel anchors { left: parent.left right: parent.right } horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignBottom text: kuser.os != "" ? i18n("%2@%3 (%1)", kuser.os, kuser.loginName, kuser.host) : i18n("%1@%2", kuser.loginName, kuser.host) elide: Text.ElideRight Behavior on opacity { NumberAnimation { duration: searchWidget.animationDuration; easing.type: Easing.InOutQuad; } } Behavior on y { NumberAnimation { duration: searchWidget.animationDuration; easing.type: Easing.InOutQuad; } } } PlasmaComponents.Label { id: hintLabel anchors { left: parent.left right: parent.right } verticalAlignment: Text.AlignBottom text: i18nc("Type is a verb here, not a noun", "Type to search...") Behavior on opacity { NumberAnimation { duration: searchWidget.animationDuration; easing.type: Easing.InOutQuad; } } Behavior on y { NumberAnimation { duration: searchWidget.animationDuration; easing.type: Easing.InOutQuad; } } } - - MouseArea { + PlasmaComponents.TextField { + id: queryField anchors.fill: parent - cursorShape: header.state === "hint" ? Qt.PointingHandCursor : Qt.ArrowCursor - acceptedButtons: Qt.LeftButton - enabled: header.state === "hint" - onClicked: { - root.previousState = "Normal" - root.state = "Search" - header.state = "query" - queryField.forceActiveFocus() + clearButtonShown: true + visible: opacity > 0 + placeholderText: i18nc("Type is a verb here, not a noun", "Type to search...") + Behavior on opacity { NumberAnimation { duration: searchWidget.animationDuration / 4 } } + + TapHandler { + acceptedButtons: Qt.LeftButton + enabled: header.state === "hint" + onTapped: { + root.previousState = "Normal" + root.state = "Search" + header.state = "query" + queryField.forceActiveFocus() + } } - PlasmaComponents.TextField { - id: queryField - anchors.fill: parent - clearButtonShown: true - visible: opacity > 0 - placeholderText: i18nc("Type is a verb here, not a noun", "Type to search...") - Behavior on opacity { NumberAnimation { duration: searchWidget.animationDuration / 4 } } - - onTextChanged: { - if (root.state != "Search") { - root.previousState = root.state; - root.state = "Search"; - } - if (text == "") { - root.state = root.previousState; - header.state = "info"; - } else { - header.state = "query"; - } + onTextChanged: { + if (root.state != "Search") { + root.previousState = root.state; + root.state = "Search"; + } + if (text == "") { + root.state = root.previousState; + header.state = "info"; + } else { + header.state = "query"; } } } } states: [ State { name: "info" PropertyChanges { target: infoLabel opacity: searchWidget.normalOpacity y: 0 } PropertyChanges { target: hintLabel opacity: 0 y: searchWidget.yOffset } PropertyChanges { target: queryField opacity: 0 } }, State { name: "hint" PropertyChanges { target: infoLabel y: -searchWidget.yOffset opacity: 0 } PropertyChanges { target: hintLabel y: 0 opacity: searchWidget.normalOpacity } PropertyChanges { target: queryField opacity: 0 } }, State { name: "query" PropertyChanges { target: infoLabel opacity: 0 } PropertyChanges { target: hintLabel opacity: 0 } PropertyChanges { target: queryField opacity: 1 } } ] // states } diff --git a/applets/kickoff/package/contents/ui/KickoffItem.qml b/applets/kickoff/package/contents/ui/KickoffItem.qml index f90000736..d54ef1ae5 100644 --- a/applets/kickoff/package/contents/ui/KickoffItem.qml +++ b/applets/kickoff/package/contents/ui/KickoffItem.qml @@ -1,249 +1,226 @@ /* Copyright (C) 2011 Martin Gräßlin Copyright (C) 2012 Gregor Taetzner Copyright 2014 Sebastian Kügler Copyright (C) 2015 Eike Hein 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 02110-1301 USA. */ import QtQuick 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.draganddrop 2.0 +import Qt.labs.handlers 1.0 import "code/tools.js" as Tools Item { id: listItem width: ListView.view.width height: (units.smallSpacing * 2) + Math.max(elementIcon.height, titleElement.height + subTitleElement.height) signal actionTriggered(string actionId, variant actionArgument) signal aboutToShowActionMenu(variant actionMenu) readonly property int itemIndex: model.index property bool dropEnabled: false property bool appView: false property bool modelChildren: model.hasChildren || false property bool isCurrent: listItem.ListView.view.currentIndex === index; property string url: model.url || "" property bool showAppsByName: plasmoid.configuration.showAppsByName property bool hasActionList: ((model.favoriteId != null) || (("hasActionList" in model) && (model.hasActionList == true))) property Item menu: actionMenu onAboutToShowActionMenu: { var actionList = hasActionList ? model.actionList : []; Tools.fillActionMenu(i18n, actionMenu, actionList, ListView.view.model.favoritesModel, model.favoriteId); } onActionTriggered: { if (Tools.triggerAction(ListView.view.model, model.index, actionId, actionArgument) === true) { plasmoid.expanded = false; } if (actionId.indexOf("_kicker_favorite_") === 0) { switchToInitial(); } } function activate() { var view = listItem.ListView.view; if (model.hasChildren) { var childModel = view.model.modelForRow(index); view.addBreadcrumb(childModel, display); view.model = childModel; } else { view.model.trigger(index, "", null); plasmoid.expanded = false; if (view.reset) { view.reset(); } } } function openActionMenu(visualParent, x, y) { aboutToShowActionMenu(actionMenu); actionMenu.visualParent = visualParent != undefined ? visualParent : mouseArea; actionMenu.open(x, y); } ActionMenu { id: actionMenu onActionClicked: { actionTriggered(actionId, actionArgument); } } - MouseArea { + Item { id: mouseArea anchors { left: parent.left right: parent.right top: parent.top bottom: parent.bottom } - property bool pressed: false - property int pressX: -1 - property int pressY: -1 - - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - - onEntered: { - listItem.ListView.view.currentIndex = index; - } - - onExited: { - listItem.ListView.view.currentIndex = -1; + TapHandler { + acceptedButtons: Qt.RightButton + enabled: hasActionList + onTapped: openActionMenu(mouseArea, mouse.x, mouse.y) } - onPressed: { - if (mouse.buttons & Qt.RightButton) { - if (hasActionList) { - openActionMenu(mouseArea, mouse.x, mouse.y); - } - } else { - pressed = true; - pressX = mouse.x; - pressY = mouse.y; - } - } - - onReleased: { - if (pressed) { - if (appView) { + TapHandler { + acceptedButtons: Qt.LeftButton + onTapped: if (appView) { appViewScrollArea.state = "OutgoingLeft"; } else { - listItem.activate(); +// listItem.activate(); } - listItem.ListView.view.currentIndex = -1; - } - - pressed = false; - pressX = -1; - pressY = -1; +// listItem.ListView.view.currentIndex = -1; } - onPositionChanged: { - if (pressX != -1 && model.url && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { - kickoff.dragSource = listItem; + DragHandler { + target: null + onActiveChanged: if (active) { + console.log("DRAG"); dragHelper.startDrag(root, model.url, model.decoration); - pressed = false; - pressX = -1; - pressY = -1; } + xAxis.minimum: 10 + yAxis.minimum: 10 } - onContainsMouseChanged: { - if (!containsMouse) { - pressed = false; - pressX = -1; - pressY = -1; - } - } + +// onPositionChanged: { +// if (pressX != -1 && model.url && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { +// kickoff.dragSource = listItem; +// pressed = false; +// pressX = -1; +// pressY = -1; +// } +// } PlasmaCore.IconItem { id: elementIcon anchors { left: parent.left leftMargin: (units.gridUnit * 4) - units.iconSizes.medium verticalCenter: parent.verticalCenter } width: units.iconSizes.medium height: width animated: false usesPlasmaTheme: false source: model.decoration } PlasmaComponents.Label { id: titleElement y: Math.round((parent.height - titleElement.height - ( (subTitleElement.text != "") ? subTitleElement.paintedHeight : 0) ) / 2) anchors { //bottom: elementIcon.verticalCenter left: elementIcon.right right: arrow.left leftMargin: units.gridUnit rightMargin: units.gridUnit * 2 } height: paintedHeight // TODO: games should always show the by name! text: model.display elide: Text.ElideRight horizontalAlignment: Text.AlignLeft } PlasmaComponents.Label { id: subTitleElement anchors { left: titleElement.left right: arrow.left rightMargin: units.gridUnit * 2 top: titleElement.bottom } height: paintedHeight text: model.description opacity: isCurrent ? 0.8 : 0.6 font.pointSize: theme.smallestFont.pointSize elide: Text.ElideMiddle horizontalAlignment: Text.AlignLeft } PlasmaCore.SvgItem { id: arrow anchors { right: parent.right rightMargin: units.gridUnit * 2 verticalCenter: parent.verticalCenter } width: visible ? units.iconSizes.small : 0 height: width visible: (model.hasChildren == true) opacity: (listItem.ListView.view.currentIndex == index) ? 1.0 : 0.4 svg: arrowsSvg elementId: (Qt.application.layoutDirection == Qt.RightToLeft) ? "left-arrow" : "right-arrow" } } // listItemDelegate Keys.onPressed: { if (event.key == Qt.Key_Menu && hasActionList) { event.accepted = true; openActionMenu(mouseArea); } else if ((event.key == Qt.Key_Enter || event.key == Qt.Key_Return) && !modelChildren) { if (!modelChildren) { event.accepted = true; listItem.activate(); } } } } // listItem