SlidingPanel.qml 7.19 KB
Newer Older
Marco Martin's avatar
Marco Martin committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 *   Copyright 2014 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.
 */

import QtQuick 2.0
Marco Martin's avatar
Marco Martin committed
21
import QtQuick.Layouts 1.1
22
import QtQuick.Window 2.2
Marco Martin's avatar
Marco Martin committed
23
import org.kde.plasma.core 2.0 as PlasmaCore
Marco Martin's avatar
Marco Martin committed
24
import org.kde.plasma.components 3.0 as PlasmaComponents
25
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
Marco Martin's avatar
Marco Martin committed
26

27
NanoShell.FullScreenOverlay {
Marco Martin's avatar
Marco Martin committed
28
29
30
    id: window

    property int offset: 0
Marco Martin's avatar
Marco Martin committed
31
    property int openThreshold
32
    property bool userInteracting: false
33
34
    readonly property bool wideScreen: width > height || width > units.gridUnit * 45
    readonly property int drawerWidth: wideScreen ? contentItem.implicitWidth : width
35
    property int drawerX: 0
Marco Martin's avatar
Marco Martin committed
36
37
    property alias fixedArea: mainScope
    property alias flickable: mainFlickable
Marco Martin's avatar
Marco Martin committed
38

Marco Martin's avatar
Marco Martin committed
39
    color: "transparent"//Qt.rgba(0, 0, 0, 0.6 * Math.min(1, offset/contentArea.height))
Marco Martin's avatar
Marco Martin committed
40
    property alias contentItem: contentArea.contentItem
Marco Martin's avatar
Marco Martin committed
41
    property int headerHeight
Marco Martin's avatar
Marco Martin committed
42

Marco Martin's avatar
Marco Martin committed
43
44
    signal closed

45
46
    //width: Screen.width
    //height: Screen.height
47

48
49
50
51
52
53
54
    enum MovementDirection {
        None = 0,
        Up,
        Down
    }
    property int direction: SlidingPanel.MovementDirection.None

55
56
57
58
    function cancelAnimations() {
        closeAnim.stop();
        openAnim.stop();
    }
59
    function open() {
60
        cancelAnimations();
61
        window.showFullScreen();
62
        openAnim.restart();
63
64
    }
    function close() {
65
        cancelAnimations();
66
        closeAnim.restart();
67
    }
68
    function updateState() {
69
        cancelAnimations();
70
71
72
73
74
        if (window.offset <= -headerHeight) {
            // close immediately, so that we don't have to wait units.longDuration 
            window.visible = false;
            window.closed();
        } else if (window.direction === SlidingPanel.MovementDirection.None) {
75
76
77
78
79
80
81
82
            if (offset < openThreshold) {
                close();
            } else {
                openAnim.restart();
            }
        } else if (offset > openThreshold && window.direction === SlidingPanel.MovementDirection.Down) {
            openAnim.restart();
        } else if (mainFlickable.contentY > openThreshold) {
83
            close();
Marco Martin's avatar
Marco Martin committed
84
        } else {
85
            openAnim.restart();
Marco Martin's avatar
Marco Martin committed
86
        }
87
    }
Marco Martin's avatar
Marco Martin committed
88
89
90
91
92
    Timer {
        id: updateStateTimer
        interval: 0
        onTriggered: updateState()
    }
Marco Martin's avatar
Marco Martin committed
93

Marco Martin's avatar
Marco Martin committed
94
95
96
97
98
    onActiveChanged: {
        if (!active) {
            close();
        }
    }
99
    /*onVisibleChanged: {
100
        if (visible) {
101
102
            window.width = Screen.width;
            window.height = Screen.height;
Marco Martin's avatar
Marco Martin committed
103
            window.requestActivate();
104
        }
105
    }*/
Marco Martin's avatar
Marco Martin committed
106

107
108
109
110
111
112
113
114
    SequentialAnimation {
        id: closeAnim
        PropertyAnimation {
            target: window
            duration: units.longDuration
            easing.type: Easing.InOutQuad
            properties: "offset"
            from: window.offset
Marco Martin's avatar
Marco Martin committed
115
            to: -headerHeight
Marco Martin's avatar
Marco Martin committed
116
        }
117
118
        ScriptAction {
            script: {
Marco Martin's avatar
Marco Martin committed
119
                window.visible = false;
Marco Martin's avatar
Marco Martin committed
120
                window.closed();
Marco Martin's avatar
Marco Martin committed
121
122
            }
        }
123
    }
Marco Martin's avatar
Marco Martin committed
124
125
126
127
128
129
130
    PropertyAnimation {
        id: openAnim
        target: window
        duration: units.longDuration
        easing.type: Easing.InOutQuad
        properties: "offset"
        from: window.offset
Marco Martin's avatar
Marco Martin committed
131
        to: contentArea.height
Marco Martin's avatar
Marco Martin committed
132
    }
133

Marco Martin's avatar
Marco Martin committed
134
135
    Rectangle {
        anchors {
Devin Lin's avatar
Devin Lin committed
136
137
138
            left: parent.left
            right: parent.right
            bottom: parent.bottom
Marco Martin's avatar
Marco Martin committed
139
        }
Devin Lin's avatar
Devin Lin committed
140
        height: parent.height - headerHeight // don't layer on top panel indicators (area is darkened separately)
Marco Martin's avatar
Marco Martin committed
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
        color: "black"
        opacity: 0.6 * Math.min(1, offset/contentArea.height)
    
        Rectangle {
            height: headerHeight
            anchors {
                left: parent.left
                right: parent.right
                bottom: parent.top
            }
            color: "black"
            opacity: 0.2
        }
        Rectangle {
            height: units.smallSpacing
            anchors {
                left: parent.left
                right: parent.right
                top: parent.top
            }
            gradient: Gradient {
                GradientStop {
                    position: 1.0
                    color: Qt.rgba(0, 0, 0, 0.0)
                }
                GradientStop {
                    position: 0.5
                    color: Qt.rgba(0, 0, 0, 0.4)
                }
                GradientStop {
                    position: 1.0
                    color: "transparent"
                }
            }
        }
    }
177
    PlasmaCore.ColorScope {
178
        id: mainScope
179
        anchors.fill: parent
Marco Martin's avatar
Marco Martin committed
180

181
182
        Flickable {
            id: mainFlickable
Marco Martin's avatar
Marco Martin committed
183
184
185
186
            anchors {
                fill: parent
                topMargin: headerHeight
            }
187
188
189
            Binding {
                target: mainFlickable
                property: "contentY"
Marco Martin's avatar
Marco Martin committed
190
                value: -window.offset + contentArea.height
191
192
193
                when: !mainFlickable.moving && !mainFlickable.dragging && !mainFlickable.flicking
            }
            //no loop as those 2 values compute to exactly the same
194
            onContentYChanged: {
195
196
197
198
199
                if (contentY === oldContentY) {
                    window.direction = SlidingPanel.MovementDirection.None;
                } else {
                    window.direction = contentY > oldContentY ? SlidingPanel.MovementDirection.Up : SlidingPanel.MovementDirection.Down;
                }
Marco Martin's avatar
Marco Martin committed
200
                window.offset = -contentY + contentArea.height
201
                oldContentY = contentY;
202
            }
203
            property real oldContentY
204
            boundsBehavior: Flickable.StopAtBounds
205
206
207
            contentWidth: window.width
            contentHeight: window.height*2
            bottomMargin: window.height
208
209
210
211
            onMovementStarted: {
                window.cancelAnimations();
                window.userInteracting = true;
            }
212
213
214
215
216
217
218
219
220
            onFlickStarted: window.userInteracting = true;
            onMovementEnded: {
                window.userInteracting = false;
                window.updateState();
            }
            onFlickEnded: {
                window.userInteracting = true;
                window.updateState();
            }
221
            MouseArea {
Marco Martin's avatar
Marco Martin committed
222
                id: dismissArea
223
                z: 2
224
                width: parent.width
Marco Martin's avatar
Marco Martin committed
225
                height: mainFlickable.contentHeight
226
                onClicked: window.close();
Marco Martin's avatar
Marco Martin committed
227
228
                PlasmaComponents.Control {
                    id: contentArea
Marco Martin's avatar
Marco Martin committed
229
                    z: 1
230
                    y: 0
231
232
                    x: drawerX
                    width: drawerWidth
Marco Martin's avatar
Marco Martin committed
233
                }
234
            }
235
        }
236
    }
Marco Martin's avatar
Marco Martin committed
237
}