shift-shell/containments/homescreen/package/contents/ui/main.qml

621 lines
22 KiB
QML
Raw Normal View History

/*
* Copyright 2015 Marco Martin <mart@kde.org>
*
* 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.
*/
2015-04-11 09:26:55 +00:00
import QtQuick 2.4
2015-02-25 18:38:34 +00:00
import QtQuick.Layouts 1.1
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
2015-06-10 17:28:39 +00:00
import "LayoutManager.js" as LayoutManager
Item {
id: root
2015-02-26 10:34:33 +00:00
width: 480
height: 640
2015-06-20 23:08:46 +00:00
//BEGIN properties
property Item toolBox
property alias appletsSpace: applicationsView.headerItem
property int buttonHeight: width/4
2015-03-05 13:02:32 +00:00
property bool reorderingApps: false
property bool locked: applicationsView.contentY < -applicationsView.headerItem.height + plasmoid.availableScreenRect.height
2015-06-20 23:08:46 +00:00
//END properties
2015-06-20 23:08:46 +00:00
//BEGIN functions
function addApplet(applet, x, y) {
var container = appletContainerComponent.createObject(appletsSpace.layout)
container.visible = true
print("Applet added: " + applet)
var appletWidth = applet.width;
var appletHeight = applet.height;
applet.parent = container;
container.applet = applet;
applet.anchors.fill = container;
applet.visible = true;
container.visible = true;
// If the provided position is valid, use it.
if (x >= 0 && y >= 0) {
var index = LayoutManager.insertAtCoordinates(container, x , y);
// Fall through to determining an appropriate insert position.
} else {
var before = null;
//container.animationsEnabled = false;
if (before) {
LayoutManager.insertBefore(before, container);
// Fall through to adding at the end.
} else {
container.parent = appletsSpace.layout;
}
//event compress the enable of animations
//startupTimer.restart();
}
if (applet.Layout.fillWidth) {
appletsSpace.lastSpacer.parent = root;
}
}
2015-06-20 23:08:46 +00:00
//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;
}
2015-07-09 11:29:26 +00:00
function checkLastSpacer() {
appletsSpace.lastSpacer.parent = root
var expands = false;
for (var container in appletsSpace.layout.children) {
var item = appletsSpace.layout.children[container];
if (item.Layout && item.Layout.fillHeight) {
expands = true;
}
}
if (!expands) {
appletsSpace.lastSpacer.parent = appletsSpace.layout;
}
}
2015-06-20 23:08:46 +00:00
//END functions
//BEGIN slots
Component.onCompleted: {
LayoutManager.plasmoid = plasmoid;
LayoutManager.root = root;
LayoutManager.layout = appletsSpace.layout;
2015-06-20 04:45:56 +00:00
//LayoutManager.lastSpacer = appletsSpace.lastSpacer;
LayoutManager.restore();
applicationsView.contentY = -root.height;
plasmoid.nativeInterface.applicationListModel.appOrder = plasmoid.configuration.AppOrder;
plasmoid.nativeInterface.applicationListModel.loadApplications();
}
2015-06-20 23:08:46 +00:00
Containment.onAppletAdded: {
addApplet(applet, x, y);
LayoutManager.save();
}
Connections {
target: plasmoid.nativeInterface.applicationListModel
onAppOrderChanged: {
plasmoid.configuration.AppOrder = plasmoid.nativeInterface.applicationListModel.appOrder;
}
}
2015-06-20 23:08:46 +00:00
//END slots
Timer {
id: autoScrollTimer
property bool scrollDown: true
repeat: true
2015-04-11 09:26:55 +00:00
interval: 1500
onTriggered: {
2015-06-20 23:08:46 +00:00
//reordering launcher icons
if (root.reorderingApps) {
scrollAnim.to = scrollDown ?
//Scroll down
Math.min(applicationsView.contentItem.height - applicationsView.headerItem.height - root.height, applicationsView.contentY + root.height/2) :
//Scroll up
Math.max(0, applicationsView.contentY - root.height/2);
//reordering applets
} else {
scrollAnim.to = scrollDown ?
//Scroll down
Math.min(-root.height, applicationsView.contentY + root.height/2) :
//Scroll up
Math.max(-applicationsView.headerItem.height + root.height, applicationsView.contentY - root.height/2);
}
2015-04-11 09:26:55 +00:00
scrollAnim.running = true;
}
}
Component {
id: appletContainerComponent
MouseArea {
id: appletContainer
//not used yet
property bool animationsEnabled: true
property Item applet
2015-06-21 00:29:24 +00:00
z: applet && applet.compactRepresentationItem && applet.expanded ? 99 : 0
opacity: 1/Math.abs(x/(width/2))
2015-02-25 18:38:34 +00:00
Layout.fillWidth: true
Layout.fillHeight: applet && applet.Layout.fillHeight
Layout.onFillHeightChanged: {
2015-07-09 11:29:26 +00:00
checkLastSpacer();
2015-02-25 18:38:34 +00:00
}
2015-06-21 00:29:24 +00:00
Connections {
target: plasmoid
onAppletRemoved: {
print("Applet removed Applet-" + applet.id)
if (applet.id == appletContainer.applet.id) {
appletContainer.destroy();
}
}
}
2015-06-20 01:14:25 +00:00
onAppletChanged: {
if (applet.backgroundHints == PlasmaCore.Types.StandardBackground) {
applet.anchors.margins = background.margins.top;
}
2015-06-20 01:14:25 +00:00
}
onAnimationsEnabledChanged: {
if (!animationsEnabled) {
translation.x = 0;
translation.y = 0;
}
}
property int oldX: x
property int oldY: y
2015-06-20 01:14:25 +00:00
PlasmaCore.FrameSvgItem {
id: background
z: -1
anchors.fill: parent
imagePath: "widgets/background"
visible: applet.backgroundHints == PlasmaCore.Types.StandardBackground
}
2015-02-25 18:38:34 +00:00
Layout.minimumWidth: root.width
2015-03-18 14:41:38 +00:00
Layout.minimumHeight: Math.max(applet.Layout.minimumHeight, (root.height-applicationsView.headerItem.margin) / 2)
2015-02-25 18:38:34 +00:00
Layout.preferredWidth: root.width
2015-02-26 10:34:33 +00:00
Layout.preferredHeight: Layout.minimumHeight
2015-02-25 18:38:34 +00:00
Layout.maximumWidth: root.width
2015-02-26 10:34:33 +00:00
Layout.maximumHeight: Layout.minimumHeight
PlasmaComponents.BusyIndicator {
z: 1000
visible: applet && applet.busy
running: visible
anchors.centerIn: parent
width: Math.min(parent.width, parent.height)
height: width
}
onXChanged: {
return;
if (!animationsEnabled) {
return;
}
translation.x = oldX - x;
translation.y = oldY - y;
translAnim.running = true;
oldX = x;
oldY = y;
}
onYChanged: {
return;
if (!animationsEnabled) {
return;
}
translation.x = oldX - x;
translation.y = oldY - y;
translAnim.running = true;
oldX = x;
oldY = y;
}
transform: Translate {
id: translation
onYChanged: print(y)
}
NumberAnimation {
id: translAnim
duration: units.longDuration
easing.type: Easing.InOutQuad
target: translation
properties: "x,y"
to: 0
}
}
}
SequentialAnimation {
id: clickFedbackAnimation
property Item target
NumberAnimation {
target: clickFedbackAnimation.target
properties: "scale"
to: 2
duration: units.longDuration
easing.type: Easing.InOutQuad
}
PauseAnimation {
duration: units.shortDuration
}
NumberAnimation {
target: clickFedbackAnimation.target
properties: "scale"
to: 1
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
FeedbackWindow {
id: feedbackWindow
}
KRunner {
id: krunner
z: 998
anchors {
top: parent.top
left: parent.left
right: parent.right
topMargin: plasmoid.availableScreenRect.y
}
}
2015-06-20 23:08:46 +00:00
EditOverlay {
id: editOverlay
z: 999
}
MouseEventListener {
anchors.fill: parent
2015-06-20 23:08:46 +00:00
//Events handling: those events are about clicking and reordering of app icons
//applet related events are in AppeltsArea.qml
onPressAndHold: {
var pos = mapToItem(applicationsView.headerItem.favoritesStrip, mouse.x, mouse.y);
//in favorites area?
var item;
if (applicationsView.headerItem.favoritesStrip.contains(pos)) {
item = applicationsView.headerItem.favoritesStrip.itemAt(pos.x, pos.y);
} else {
pos = mapToItem(applicationsView.contentItem, mouse.x, mouse.y);
item = applicationsView.itemAt(pos.x, pos.y)
}
if (!item) {
return;
}
2015-03-05 16:28:24 +00:00
applicationsView.dragData = new Object;
applicationsView.dragData.ApplicationNameRole = item.modelData.ApplicationNameRole;
applicationsView.dragData.ApplicationIconRole = item.modelData.ApplicationIconRole;
applicationsView.dragData.ApplicationStorageIdRole = item.modelData.ApplicationStorageIdRole;
applicationsView.dragData.ApplicationEntryPathRole = item.modelData.ApplicationEntryPathRole;
applicationsView.dragData.ApplicationOriginalRowRole = item.modelData.ApplicationOriginalRowRole;
dragDelegate.modelData = applicationsView.dragData;
applicationsView.interactive = false;
root.reorderingApps = true;
dragDelegate.x = Math.floor(mouse.x / root.buttonHeight) * root.buttonHeight
dragDelegate.y = Math.floor(mouse.y / root.buttonHeight) * root.buttonHeight
dragDelegate.xTarget = mouse.x - dragDelegate.width/2;
dragDelegate.yTarget = mouse.y - dragDelegate.width/2;
dragDelegate.opacity = 1;
2015-03-18 14:45:48 +00:00
}
onPositionChanged: {
if (!applicationsView.dragData) {
return;
}
dragDelegate.x = mouse.x - dragDelegate.width/2;
dragDelegate.y = mouse.y - dragDelegate.height/2;
var pos = mapToItem(applicationsView.contentItem, mouse.x, mouse.y);
//in favorites area?
if (applicationsView.headerItem.favoritesStrip.contains(mapToItem(applicationsView.headerItem.favoritesStrip, mouse.x, mouse.y))) {
pos.y = 1;
}
var newRow = (Math.round(applicationsView.width / applicationsView.cellWidth) * Math.floor(pos.y / applicationsView.cellHeight) + Math.floor(pos.x / applicationsView.cellWidth));
if (applicationsView.dragData.ApplicationOriginalRowRole != newRow) {
plasmoid.nativeInterface.applicationListModel.moveItem(applicationsView.dragData.ApplicationOriginalRowRole, newRow);
applicationsView.dragData.ApplicationOriginalRowRole = newRow;
}
var pos = mapToItem(applicationsView.headerItem.favoritesStrip, mouse.x, mouse.y);
//FAVORITES
if (applicationsView.headerItem.favoritesStrip.contains(pos)) {
2015-06-20 23:08:46 +00:00
root.stopScroll();
//SCROLL UP
} else if (applicationsView.contentY > 0 && mouse.y < root.buttonHeight + root.height / 4) {
2015-06-20 23:08:46 +00:00
root.scrollUp();
//SCROLL DOWN
} else if (!applicationsView.atYEnd && mouse.y > 3 * (root.height / 4)) {
2015-06-20 23:08:46 +00:00
root.scrollDown();
//DON't SCROLL
} else {
2015-06-20 23:08:46 +00:00
root.stopScroll();
}
2015-03-18 14:45:48 +00:00
2015-04-11 09:26:55 +00:00
}
onReleased: {
if (krunner.showingResults) {
return;
2015-04-11 09:26:55 +00:00
}
applicationsView.interactive = true;
dragDelegate.xTarget = Math.floor(mouse.x / root.buttonHeight) * root.buttonHeight;
dragDelegate.yTarget = Math.floor(mouse.y / root.buttonHeight) * root.buttonHeight;
dragDelegate.opacity = 0;
if (dragDelegate.modelData) {
dragDelegate.modelData.ApplicationIconRole = "";
dragDelegate.modelDataChanged();
2015-04-11 09:26:55 +00:00
}
applicationsView.dragData = null;
root.reorderingApps = false;
applicationsView.forceLayout();
2015-06-20 23:08:46 +00:00
root.stopScroll();
2015-04-11 09:26:55 +00:00
}
onClicked: {
if (krunner.showingResults) {
return;
2015-04-11 09:26:55 +00:00
}
var pos = mapToItem(applicationsView.headerItem.favoritesStrip, mouse.x, mouse.y);
//in favorites area?
var item;
if (applicationsView.headerItem.favoritesStrip.contains(pos)) {
item = applicationsView.headerItem.favoritesStrip.itemAt(pos.x, pos.y);
} else {
pos = mapToItem(applicationsView.contentItem, mouse.x, mouse.y);
item = applicationsView.itemAt(pos.x, pos.y)
}
if (!item) {
return;
2015-04-11 09:26:55 +00:00
}
feedbackWindow.title = item.modelData.ApplicationNameRole;
feedbackWindow.state = "open";
plasmoid.nativeInterface.applicationListModel.runApplication(item.modelData.ApplicationStorageIdRole);
clickFedbackAnimation.target = item;
clickFedbackAnimation.running = true;
2015-04-11 09:26:55 +00:00
}
PlasmaCore.ColorScope {
anchors.fill: parent
//TODO: decide what color we want applets
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
Rectangle {
color: PlasmaCore.ColorScope.backgroundColor
opacity: 0.9 * (Math.min(applicationsView.contentY + root.height, root.height) / root.height)
anchors.fill: parent
}
PlasmaCore.Svg {
id: arrowsSvg
imagePath: "widgets/arrows"
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
}
PlasmaCore.SvgItem {
id: scrollUpIndicator
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 200
}
z: 2
opacity: 0
svg: arrowsSvg
elementId: "up-arrow"
width: units.iconSizes.large
height: width
Behavior on opacity {
2015-04-11 10:40:54 +00:00
OpacityAnimator {
duration: 1000
2015-04-11 10:40:54 +00:00
easing.type: Easing.InOutQuad
}
}
}
PlasmaCore.SvgItem {
id: scrollDownIndicator
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
2015-06-20 23:08:46 +00:00
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
2015-04-11 10:40:54 +00:00
easing.type: Easing.InOutQuad
}
}
}
2015-06-20 23:08:46 +00:00
//This HomeLauncher is the placeholder for the "drag"
//delegate (that is not actual drag and drop
HomeLauncher {
id: dragDelegate
z: 999
property int xTarget
property int yTarget
Behavior on opacity {
ParallelAnimation {
OpacityAnimator {
duration: units.longDuration
easing.type: Easing.InOutQuad
}
PropertyAnimation {
properties: "x"
to: dragDelegate.xTarget
target: dragDelegate
duration: units.longDuration
easing.type: Easing.InOutQuad
}
PropertyAnimation {
properties: "y"
to: dragDelegate.yTarget
target: dragDelegate
duration: units.longDuration
easing.type: Easing.InOutQuad
}
}
}
}
GridView {
id: applicationsView
anchors {
fill: parent
topMargin: plasmoid.availableScreenRect.y
bottomMargin: root.height - plasmoid.availableScreenRect.y - plasmoid.availableScreenRect.height
}
2015-02-25 18:38:34 +00:00
property var dragData
cellWidth: root.buttonHeight
cellHeight: cellWidth
model: plasmoid.nativeInterface.applicationListModel
2015-03-05 15:53:58 +00:00
snapMode: GridView.SnapToRow
2015-03-11 12:10:43 +00:00
onFlickingChanged: {
2015-06-23 17:01:27 +00:00
draggingVerticallyChanged(false);
2015-06-15 22:04:26 +00:00
}
onDraggingVerticallyChanged: {
if (draggingVertically) {
return;
}
2015-06-15 22:04:26 +00:00
//manage separately the first page, the lockscreen
//scrolling down
if (verticalVelocity > 0 && contentY < -headerItem.height + root.height &&
contentY > (-headerItem.height + root.height/6)) {
2015-06-20 04:45:56 +00:00
scrollAnim.to = -headerItem.height +plasmoid.availableScreenRect.height
scrollAnim.running = true;
return;
//scrolling up
} else if (verticalVelocity < 0 && contentY < -headerItem.height + root.height &&
contentY < (-headerItem.height + root.height/6*5)) {
scrollAnim.to = -headerItem.height;
scrollAnim.running = true;
return;
}
2015-03-11 12:10:43 +00:00
}
NumberAnimation {
id: scrollAnim
target: applicationsView
properties: "contentY"
duration: units.longDuration
easing.type: Easing.InOutQuad
}
move: Transition {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
properties: "x,y"
}
}
moveDisplaced: Transition {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
properties: "x,y"
}
}
//clip: true
delegate: HomeLauncher {
visible: index > 3
}
header: AppletsArea {}
footer: Item {
width: units. gridUnit * 4
height: width
}
}
2015-03-13 13:58:18 +00:00
Rectangle {
anchors {
top: parent.top
bottom: parent.bottom
horizontalCenter: scrollHandle.horizontalCenter
}
width: units.smallSpacing
color: PlasmaCore.ColorScope.textColor
opacity: scrollHandle.opacity / 2
2015-03-13 13:58:18 +00:00
}
Rectangle {
id: scrollHandle
color: PlasmaCore.ColorScope.textColor
width: units.gridUnit
height: width
radius: width
anchors.right: parent.right
y: applicationsView.height * applicationsView.visibleArea.yPosition
opacity: applicationsView.flicking || scrollDownIndicator.opacity > 0 || scrollUpIndicator.opacity > 0 ? 0.8 : 0
Behavior on opacity {
NumberAnimation {
duration: units.longDuration
easing.type: Easing.InOutQuad
}
2015-03-05 16:28:24 +00:00
}
}
}
}
}