qml: Update the drag and drop implementation
[vlc.git] / modules / gui / qt / widgets / qml / DragItem.qml
blob746c0fa0082edbf8e2960e424459b2b0a1b732ef
1 /*****************************************************************************
2  * Copyright (C) 2020 VLC authors and VideoLAN
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * ( at your option ) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17  *****************************************************************************/
19 import QtQuick          2.11
20 import QtQuick.Controls 2.4
21 import QtQml.Models     2.2
23 import QtGraphicalEffects 1.0
25 import "qrc:///style/"
26 import "qrc:///playlist/" as Playlist
28 Item {
29     id: dragItem
31     //---------------------------------------------------------------------------------------------
32     // Properties
33     //---------------------------------------------------------------------------------------------
35     readonly property int coverSize: VLCStyle.icon_normal
37     property VLCColors colors: VLCStyle.colors
39     //---------------------------------------------------------------------------------------------
40     // Private
42     property var _model: {"covers": [], "title": "", "count": 0}
44     readonly property int _maxCovers: 3
46     readonly property int _displayedCoversCount: Math.min(_model.count, _maxCovers + 1)
48     //---------------------------------------------------------------------------------------------
49     // Settings
50     //---------------------------------------------------------------------------------------------
52     parent: g_mainDisplay
54     width: VLCStyle.colWidth(2)
56     height: coverSize + VLCStyle.margin_small * 2
58     opacity: visible ? 0.90 : 0
60     visible: Drag.active
62     //---------------------------------------------------------------------------------------------
63     // Events
64     //---------------------------------------------------------------------------------------------
66     Drag.onActiveChanged: {
67         if (Drag.active) {
68             _model = updateComponents(_maxCovers);
69             mainInterface.setCursor(Qt.DragMoveCursor);
70         } else {
71             mainInterface.restoreCursor();
72         }
73     }
75     //---------------------------------------------------------------------------------------------
76     // Functions
77     //---------------------------------------------------------------------------------------------
79     function coversXPos(index) {
80         return VLCStyle.margin_small + (coverSize / 3) * index;
81     }
83     //---------------------------------------------------------------------------------------------
84     // Pure virtual
86     // return {covers: [{artwork: <string> or cover: <component>},..maxCovers]
87     //         , title: <string>, *subtitle: <string>, count: <int> /*all selected*/}
88     // * - optional
89     function updateComponents(maxCovers) {
90         console.assert(false, "updateComponents is not implemented.");
91     }
93     function getSelectedInputItem() {
94         console.assert(false, "getSelectedInputItem is not implemented.");
96         return undefined;
97     }
99     //---------------------------------------------------------------------------------------------
100     // Animations
101     //---------------------------------------------------------------------------------------------
103     Behavior on opacity {
104         NumberAnimation {
105             easing.type: Easing.InOutSine
106             duration: 128
107         }
108     }
110     //---------------------------------------------------------------------------------------------
111     // Childs
112     //---------------------------------------------------------------------------------------------
114     Rectangle {
115         /* background */
116         anchors.fill: parent
117         color: colors.button
118         border.color: colors.buttonBorder
119         border.width: VLCStyle.dp(1, VLCStyle.scale)
120         radius: VLCStyle.dp(6, VLCStyle.scale)
121     }
123     RectangularGlow {
124         anchors.fill: parent
125         glowRadius: VLCStyle.dp(8, VLCStyle.scale)
126         color: colors.glowColor
127         spread: 0.2
128     }
130     Repeater {
131         id: coverRepeater
132         model: _model.covers
134         Item {
135             x: dragItem.coversXPos(index)
136             y: (dragItem.height - height) / 2
137             width: dragItem.coverSize
138             height: dragItem.coverSize
140             Rectangle {
141                 id: bg
143                 radius: coverRepeater.count > 1 ? dragItem.coverSize : VLCStyle.dp(2, VLCStyle.scale)
144                 anchors.fill: parent
145                 color: colors.bg
146             }
148             DropShadow {
149                 horizontalOffset: 0
150                 verticalOffset: VLCStyle.dp(1, VLCStyle.scale)
151                 radius: VLCStyle.dp(3, VLCStyle.scale)
152                 samples: 2 * radius + 1
153                 color: Qt.rgba(0, 0, 0, .18)
154                 anchors.fill: bg
155                 source: bg
156             }
158             DropShadow {
159                 horizontalOffset: 0
160                 verticalOffset: VLCStyle.dp(6, VLCStyle.scale)
161                 radius: VLCStyle.dp(14, VLCStyle.scale)
162                 samples: 2 * radius + 1
163                 color: Qt.rgba(0, 0, 0, .18)
164                 anchors.fill: bg
165                 source: bg
166             }
168             Loader {
169                 // parent may provide extra data with covers
170                 property var model: modelData
172                 anchors.centerIn: parent
173                 sourceComponent: (!modelData.artwork || modelData.artwork.toString() === "") ? modelData.cover : artworkLoader
174                 layer.enabled: true
175                 layer.effect: OpacityMask {
176                     maskSource: Rectangle {
177                         width: bg.width
178                         height: bg.height
179                         radius: bg.radius
180                         visible: false
181                     }
182                 }
184                 onItemChanged: {
185                     if (modelData.artwork && modelData.artwork.toString() !== "")
186                         item.source = modelData.artwork
187                 }
188             }
190             Rectangle {
191                 // for cover border
192                 color: "transparent"
193                 border.width: VLCStyle.dp(1, VLCStyle.scale)
194                 border.color: colors.buttonBorder
195                 anchors.fill: parent
196                 radius: bg.radius
197             }
198         }
199     }
201     Rectangle {
202         id: extraCovers
204         x: dragItem.coversXPos(_maxCovers)
205         y: (dragItem.height - height) / 2
206         width: dragItem.coverSize
207         height: dragItem.coverSize
208         radius: dragItem.coverSize
209         visible: _model.count > dragItem._maxCovers
210         color: colors.bgAlt
211         border.width: VLCStyle.dp(1, VLCStyle.scale)
212         border.color: colors.buttonBorder
214         MenuLabel {
215             anchors.centerIn: parent
216             color: colors.accent
217             text: "+" + (_model.count - dragItem._maxCovers)
218         }
219     }
221     DropShadow {
222         horizontalOffset: 0
223         verticalOffset: VLCStyle.dp(1, VLCStyle.scale)
224         radius: VLCStyle.dp(3, VLCStyle.scale)
225         samples: 2 * radius + 1
226         color: Qt.rgba(0, 0, 0, .18)
227         anchors.fill: extraCovers
228         source: extraCovers
229         visible: extraCovers.visible
230     }
232     DropShadow {
233         horizontalOffset: 0
234         verticalOffset: VLCStyle.dp(6, VLCStyle.scale)
235         radius: VLCStyle.dp(14, VLCStyle.scale)
236         samples: 2 * radius + 1
237         color: Qt.rgba(0, 0, 0, .18)
238         anchors.fill: extraCovers
239         source: extraCovers
240         visible: extraCovers.visible
241     }
243     Column {
244         id: labelColumn
246         anchors.verticalCenter: parent.verticalCenter
247         x: dragItem.coversXPos(_displayedCoversCount - 1) + dragItem.coverSize + VLCStyle.margin_small
248         width: parent.width - x - VLCStyle.margin_small
249         spacing: VLCStyle.margin_xxxsmall
251         ScrollingText {
252             label: titleLabel
253             scroll: true
254             height: titleLabel.height
255             width: parent.width
257             Label {
258                 id: titleLabel
260                 text: _model.title
261                 visible: text && text !== ""
262                 width: parent.width
263                 elide: Text.ElideNone
264                 font.pixelSize: VLCStyle.fontSize_large
265                 color: colors.buttonText
266             }
267         }
269         MenuCaption {
270             id: subtitleLabel
272             visible: text && text !== ""
273             width: parent.width
274             text: _model.subtitle || i18n.qtr("%1 selected").arg(_model.count)
275         }
276     }
278     Component {
279         id: artworkLoader
280         Image {
281             mipmap: true
282             fillMode: Image.PreserveAspectCrop
283             width: coverSize
284             height: coverSize
285         }
286     }