Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Desktop.qml 8.87 KB
Newer Older
Aaron J. Seigo's avatar
Aaron J. Seigo committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 *   Copyright 2014 Aaron Seigo <aseigo@kde.org>
 *   Copyright 2012 Marco Martin <notmart@gmail.com>
 *
 *   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.
 */

21
import QtQuick 2.7
Aaron J. Seigo's avatar
Aaron J. Seigo committed
22
import QtGraphicalEffects 1.0
23
import QtQuick.Controls 2.3
Aaron J. Seigo's avatar
Aaron J. Seigo committed
24
import org.kde.plasma.core 2.0 as PlasmaCore
25
import org.kde.plasma.shell 2.0 as Shell
26
import org.kde.plasma.components 2.0 as PlasmaComponents
Pier Luigi Fiorini's avatar
Pier Luigi Fiorini committed
27
import org.kde.plasma.workspace.components 2.0 as PlasmaWorkspace
28
import org.kde.kquickcontrolsaddons 2.0
Marco Martin's avatar
Marco Martin committed
29
import org.kde.activities 0.1 as Activities
Aaron J. Seigo's avatar
Aaron J. Seigo committed
30 31
import "../components"

32
Item {
33
    id: root
34 35
    width: 0
    height: 0
Aaron J. Seigo's avatar
Aaron J. Seigo committed
36 37

    property Item containment;
38
    property Item containmentNextActivityPreview;
Aaron J. Seigo's avatar
Aaron J. Seigo committed
39
    property Item wallpaper;
Aaron J. Seigo's avatar
Aaron J. Seigo committed
40
    property int notificationId: 0;
41
    property int buttonHeight: width/4
42
    property bool loadCompleted: false
Aaron J. Seigo's avatar
Aaron J. Seigo committed
43

Marco Martin's avatar
Marco Martin committed
44
    XAnimator {
45
        id: switchAnim
Marco Martin's avatar
Marco Martin committed
46 47
        target: activitiesLayout
        duration: units.longDuration
48
        easing.type: Easing.InOutQuad
Marco Martin's avatar
Marco Martin committed
49
    }
50
    MouseArea {
51
        id: activitiesView
52
        z: 99
Marco Martin's avatar
Marco Martin committed
53 54
        visible: root.containment
        anchors.fill: parent
55 56 57 58 59
        drag.filterChildren: true
        drag.target: activitiesLayout
        drag.axis: Drag.XAxis
        drag.minimumX: -activitiesLayout.width + width
        drag.maximumX: 0
60
        property int currentIndex: -1
Marco Martin's avatar
Marco Martin committed
61
        property Item nextContainment: root.containment
62

Marco Martin's avatar
Marco Martin committed
63
        function adjustPosition() {
64
            if (!activitiesLayout.loadCompleted) {
Marco Martin's avatar
Marco Martin committed
65
                activitiesLayout.x = - currentIndex * width;
66 67
                return;
            }
Marco Martin's avatar
Marco Martin committed
68 69
            switchAnim.from = activitiesLayout.x;
            switchAnim.to = - currentIndex * width;
70 71
            switchAnim.running = true;
        }
Marco Martin's avatar
Marco Martin committed
72 73
        onCurrentIndexChanged: adjustPosition();
        
74 75
        //don't animate
        onWidthChanged: contentX = currentIndex * width;
Marco Martin's avatar
Marco Martin committed
76

Marco Martin's avatar
Marco Martin committed
77 78 79 80 81 82 83 84 85
        onPositionChanged: {
            var tempIndex = Math.round(-activitiesLayout.x / width);
            nextContainment = activitiesLayout.children[tempIndex].containment;
        }
        onReleased: {
            currentIndex = Math.round(-activitiesLayout.x / width);
            //unconditionally run the slide anim
            adjustPosition();
        }
86 87
        Row {
            id: activitiesLayout
88
            height: activitiesView.height
89 90 91 92 93 94 95 96 97 98 99
            spacing: 0
            //don't try to do anything until we are well setted up
            property bool loadCompleted: root.loadCompleted && width == activitiesView.width * (activitiesLayout.children.length - 1) && activitiesLayout.children.length == activityRepeater.count + 1
            onLoadCompletedChanged: activitiesView.currentIndexChanged();

            Repeater {
                id: activityRepeater
                model: Activities.ActivityModel {
                    id: activityModel
                }

Marco Martin's avatar
Marco Martin committed
100
                delegate: Item {
101 102 103 104
                    id: mainDelegate
                    width: activitiesView.width
                    height: activitiesView.height
                    property Item containment
Marco Martin's avatar
Marco Martin committed
105
                    //inViewport should be only the current, and the other adjacent two
106
                    readonly property bool inViewport: activitiesLayout.loadCompleted && root.containment &&
107
                            ((x >= -activitiesLayout.x &&
Marco Martin's avatar
Marco Martin committed
108 109
                            x <= -activitiesLayout.x + activitiesView.width) ||
                            (x + width >= -activitiesLayout.x &&
110
                            x + width < -activitiesLayout.x + activitiesView.width))
111
                    readonly property bool currentActivity: root.containment && model.current
112

113 114 115
                    
                    Connections {
                        target: activitiesView
Marco Martin's avatar
Marco Martin committed
116
                        onCurrentIndexChanged: {
117 118 119 120 121 122 123 124 125 126
                            if (activitiesView.currentIndex == index) {
                                activityModel.setCurrentActivity(model.id, function(){
                                    mainDelegate.containment.parent = mainDelegate;
                                });
                            }
                        }
                        onFlickEnded: activitiesView.movementEnded()
                    }
                    onInViewportChanged: {
                        if (inViewport && !mainDelegate.containment) {
127
                            mainDelegate.containment = desktop.candidateContainments[model.id];
Marco Martin's avatar
Marco Martin committed
128
                            //desktop.containmentItemForActivity(model.id);
129
                            containmentNextActivityPreview = containment;
130
                            mainDelegate.containment.parent = mainDelegate;
131 132 133 134 135 136 137
                            mainDelegate.containment.anchors.fill = mainDelegate;
                        }
                    }
                    onCurrentActivityChanged: {
                        if (currentActivity) {
                            activitiesView.currentIndex = index;
                        }
138
                        mainDelegate.containment.visible = true;
139
                    }
140 141
                }
            }
Marco Martin's avatar
Marco Martin committed
142 143
        }
    }
144 145

    //TODO: adjust its Y to current containment availablescreenrect
146
    PageIndicator {
147
        z: 100
148 149
        anchors {
            bottom: parent.bottom
Marco Martin's avatar
Marco Martin committed
150
            bottomMargin: root.containment.availableScreenRect.y + root.containment.availableScreenRect.height
151 152
            horizontalCenter: parent.horizontalCenter
        }
153 154
        count: activitiesView.count
        currentIndex: activitiesView.currentIndex
155
    }
Marco Martin's avatar
Marco Martin committed
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
    PlasmaCore.FrameSvgItem {
        z: 100
        opacity: activitiesView.drag.active ? 1 : 0
        anchors.centerIn: parent
        imagePath: "widgets/background"
        width: childrenRect.width + units.gridUnit*2
        height: childrenRect.height + units.gridUnit*2
        PlasmaComponents.Label {
            anchors.centerIn: parent
            text: activitiesView.nextContainment.activityName
        }
        Behavior on opacity {
            OpacityAnimator {
                duration: units.longDuration
                easing.type: Easing.InOutQuad
            }
        }
    }
174

175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
    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
Marco Martin's avatar
Marco Martin committed
190
        width: parent.width
191 192 193 194 195 196 197 198 199
        
        onLoaded: {
            if (widgetExplorerStack.item) {
                item.closed.connect(function() {
                    widgetExplorerStack.source = ""
                });
            }
        }
    }
200

201 202 203 204 205
    Binding {
        target: containment
        property: "width"
        value: root.width
    }
206 207 208 209 210 211 212
    //some properties that shouldn't be accessible from elsewhere
    QtObject {
        id: internal;

        property Item oldContainment: null;
        property Item newContainment: null;
    }
213

214 215 216 217 218
    //pass the focus to the containment, so it can react to homescreen activate/inactivate
    Connections {
        target: desktop
        onActiveChanged: {
            containment.focus = desktop.active;
Aaron J. Seigo's avatar
Aaron J. Seigo committed
219
        }
Aaron J. Seigo's avatar
Aaron J. Seigo committed
220 221
    }

222 223
    Loader {
        id: pinOverlay
Aaron J. Seigo's avatar
Aaron J. Seigo committed
224
        anchors {
Marco Martin's avatar
Marco Martin committed
225 226 227
            fill: parent
            topMargin: containment.availableScreenRect.y
            bottomMargin: parent.height - containment.availableScreenRect.height - containment.availableScreenRect.y
Aaron J. Seigo's avatar
Aaron J. Seigo committed
228
        }
Marco Martin's avatar
Marco Martin committed
229
        z: 222
230
        source: Qt.resolvedUrl("Pin.qml")
Aaron J. Seigo's avatar
Aaron J. Seigo committed
231 232
    }

233 234 235 236 237 238 239 240 241
    onWidthChanged: {
        //There will be a resize at the very start which we can't avoid, don't do anything until then
        //configure the view behavior
        if (desktop && root.width > 0) {
            desktop.width = width;
            desktop.height = height;
            root.loadCompleted = true;
        }
    }
242 243
    Component.onCompleted: {
        //configure the view behavior
244
        if (desktop && root.width > 0) {
Aaron J. Seigo's avatar
Aaron J. Seigo committed
245 246
            desktop.width = width;
            desktop.height = height;
247
            root.loadCompleted = true;
Aaron J. Seigo's avatar
Aaron J. Seigo committed
248
        }
249
    }
250
}