assetList.qml 15.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/***************************************************************************
 *   Copyright (C) 2017 by Nicolas Carion                                  *
 *   This file is part of Kdenlive. See www.kdenlive.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) version 3 or any later version accepted by the       *
 *   membership of KDE e.V. (or its successor approved  by the membership  *
 *   of KDE e.V.), which shall act as a proxy defined in Section 14 of     *
 *   version 3 of the license.                                             *
 *                                                                         *
 *   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, see <http://www.gnu.org/licenses/>. *
 ***************************************************************************/

22
23
24
import QtQuick 2.11
import QtQuick.Layouts 1.11
import QtQuick.Controls 1.4
25
26
import QtQuick.Controls.Styles 1.4
import QtQuick.Window 2.2
27
import QtQml.Models 2.11
28
import com.enums 1.0
29
30
31

Rectangle {
    id: listRoot
32
33
    SystemPalette { id: activePalette }
    color: activePalette.window
Nicolas Carion's avatar
Nicolas Carion committed
34

35
36
    function expandNodes(indexes)  {
        for(var i = 0; i < indexes.length; i++) {
37
38
39
            if (indexes[i].valid) {
                treeView.expand(indexes[i]);
            }
40
41
        }
    }
42
43
44
45
46
47
48
49
50
51
52
53
    function rowPosition(model, index) {
        var pos = 0;
        for(var i = 0; i < index.parent.row; i++) {
            var catIndex = model.getCategory(i);
            if (treeView.isExpanded(catIndex)) {
                pos += model.rowCount(catIndex);
            }
            pos ++;
        }
        pos += index.row + 2;
        return pos;
    }
54

Nicolas Carion's avatar
Nicolas Carion committed
55
    ColumnLayout {
56
        anchors.fill: parent
57
        spacing: 0
Nicolas Carion's avatar
Nicolas Carion committed
58
59
60
        RowLayout {
            Layout.fillWidth: true
            Layout.fillHeight: false
61
            spacing: 4
Nicolas Carion's avatar
Nicolas Carion committed
62
63
64
65
            ExclusiveGroup { id: filterGroup}
            ToolButton {
                id: showAll
                iconName: "show-all-effects"
66
67
                checkable: true
                checked: true
Nicolas Carion's avatar
Nicolas Carion committed
68
                exclusiveGroup: filterGroup
Pino Toscano's avatar
Pino Toscano committed
69
                tooltip: isEffectList ? i18n("Main effects") : i18n("Main compositions")
70
                onClicked: {
Nicolas Carion's avatar
Nicolas Carion committed
71
                    assetlist.setFilterType("")
72
                }
73
            }
Nicolas Carion's avatar
Nicolas Carion committed
74
75
            ToolButton {
                id: showVideo
Nicolas Carion's avatar
Nicolas Carion committed
76
                visible: isEffectList
Nicolas Carion's avatar
Nicolas Carion committed
77
                iconName: "kdenlive-show-video"
78
                iconSource: 'image://icon/kdenlive-show-video'
Nicolas Carion's avatar
Nicolas Carion committed
79
80
                checkable:true
                exclusiveGroup: filterGroup
Yuri Chornoivan's avatar
Yuri Chornoivan committed
81
                tooltip: i18n("Show all video effects")
82
                onClicked: {
Nicolas Carion's avatar
Nicolas Carion committed
83
                    assetlist.setFilterType("video")
84
                }
85
            }
Nicolas Carion's avatar
Nicolas Carion committed
86
87
            ToolButton {
                id: showAudio
Nicolas Carion's avatar
Nicolas Carion committed
88
                visible: isEffectList
Nicolas Carion's avatar
Nicolas Carion committed
89
                iconName: "kdenlive-show-audio"
90
                iconSource: 'image://icon/kdenlive-show-audio'
Nicolas Carion's avatar
Nicolas Carion committed
91
92
                checkable:true
                exclusiveGroup: filterGroup
Yuri Chornoivan's avatar
Yuri Chornoivan committed
93
                tooltip: i18n("Show all audio effects")
94
                onClicked: {
Nicolas Carion's avatar
Nicolas Carion committed
95
                    assetlist.setFilterType("audio")
96
97
98
99
                }
            }
            ToolButton {
                id: showCustom
Nicolas Carion's avatar
Nicolas Carion committed
100
                visible: isEffectList
101
102
103
                iconName: "kdenlive-custom-effect"
                checkable:true
                exclusiveGroup: filterGroup
Yuri Chornoivan's avatar
Yuri Chornoivan committed
104
                tooltip: i18n("Show all custom effects")
105
                onClicked: {
Nicolas Carion's avatar
Nicolas Carion committed
106
                    assetlist.setFilterType("custom")
107
                }
Nicolas Carion's avatar
Nicolas Carion committed
108
            }
109
110
111
112
113
            ToolButton {
                id: showFavorites
                iconName: "favorite"
                checkable:true
                exclusiveGroup: filterGroup
Yuri Chornoivan's avatar
Yuri Chornoivan committed
114
                tooltip: i18n("Show favorite items")
115
116
117
118
                onClicked: {
                    assetlist.setFilterType("favorites")
                }
            }
119
120
121
122
            ToolButton {
                id: downloadTransitions
                visible: !isEffectList
                iconName: "edit-download"
Yuri Chornoivan's avatar
Yuri Chornoivan committed
123
                tooltip: i18n("Download New Wipes...")
124
125
126
127
                onClicked: {
                    assetlist.downloadNewLumas()
                }
            }
Nicolas Carion's avatar
Nicolas Carion committed
128
129
            Rectangle {
                //This is a spacer
130
                Layout.fillHeight: false
Nicolas Carion's avatar
Nicolas Carion committed
131
                Layout.fillWidth: true
132
                color: "transparent"
Nicolas Carion's avatar
Nicolas Carion committed
133
134
135
136
137
            }
            ToolButton {
                id: showDescription
                iconName: "help-about"
                checkable:true
Pino Toscano's avatar
Pino Toscano committed
138
                tooltip: isEffectList ? i18n("Show/hide description of the effects") : i18n("Show/hide description of the compositions")
139
                onCheckedChanged:{
140
                    assetlist.showDescription = checked
141
                }
142
                Component.onCompleted: checked = assetlist.showDescription
Nicolas Carion's avatar
Nicolas Carion committed
143
144
145
            }

        }
146
147
148
        TextField {
            id: searchInput
            Layout.fillWidth:true
Nicolas Carion's avatar
Nicolas Carion committed
149
150
            Image {
                id: clear
151
                source: 'image://icon/edit-clear'
152
153
                width: parent.height * 0.8
                height: width
Nicolas Carion's avatar
Nicolas Carion committed
154
155
156
157
                anchors { right: parent.right; rightMargin: 8; verticalCenter: parent.verticalCenter }
                opacity: 0
                MouseArea {
                    anchors.fill: parent
158
                    onClicked: { searchInput.text = ''; searchInput.focus = true; }
Nicolas Carion's avatar
Nicolas Carion committed
159
160
161
                }
            }
            states: State {
162
                name: "hasText"; when: searchInput.text != ''
Nicolas Carion's avatar
Nicolas Carion committed
163
164
165
166
167
168
                PropertyChanges { target: clear; opacity: 1 }
            }

            transitions: [
                Transition {
                    from: ""; to: "hasText"
169
                    NumberAnimation { properties: "opacity" }
Nicolas Carion's avatar
Nicolas Carion committed
170
171
172
173
174
175
                },
                Transition {
                    from: "hasText"; to: ""
                    NumberAnimation { properties: "opacity" }
                }
            ]
Nicolas Carion's avatar
Nicolas Carion committed
176
            onTextChanged: {
177
                var current = sel.currentIndex
178
                var rowModelIndex = assetListModel.getModelIndex(sel.currentIndex);
Nicolas Carion's avatar
Nicolas Carion committed
179
                assetlist.setFilterName(text)
180
                if (text.length > 0) {
181
182
183
184
                    sel.setCurrentIndex(assetListModel.firstVisibleItem(current), ItemSelectionModel.ClearAndSelect)
                } else {
                    sel.clearCurrentIndex()
                    sel.setCurrentIndex(assetListModel.getProxyIndex(rowModelIndex), ItemSelectionModel.ClearAndSelect)
185
                }
186
187
                treeView.__listView.positionViewAtIndex(rowPosition(assetListModel, sel.currentIndex), ListView.Visible)
            }
188
            /*onEditingFinished: {
189
190
191
                if (!assetContextMenu.isDisplayed) {
                    searchList.checked = false
                }
192
            }*/
193
194
195
196
197
198
199
200
201
202
            Keys.onDownPressed: {
                sel.setCurrentIndex(assetListModel.getNextChild(sel.currentIndex), ItemSelectionModel.ClearAndSelect)
                treeView.expand(sel.currentIndex.parent)
                treeView.__listView.positionViewAtIndex(rowPosition(assetListModel, sel.currentIndex), ListView.Visible)
            }
            Keys.onUpPressed: {
                sel.setCurrentIndex(assetListModel.getPreviousChild(sel.currentIndex), ItemSelectionModel.ClearAndSelect)
                treeView.expand(sel.currentIndex.parent)
                treeView.__listView.positionViewAtIndex(rowPosition(assetListModel, sel.currentIndex), ListView.Visible)
            }
203
204
            Keys.onPressed: {
                if (sel.hasSelection && (event.key === Qt.Key_Return || event.key === Qt.Key_Enter )) {
205
                    assetlist.activate(sel.currentIndex)
206
                    treeView.focus = true
207
                    event.accepted = true
208
                    searchInput.text = '';
209
                }
Nicolas Carion's avatar
Nicolas Carion committed
210
211
212
213
            }
        }
        ItemSelectionModel {
            id: sel
Nicolas Carion's avatar
Nicolas Carion committed
214
            model: assetListModel
215
            onSelectionChanged: {
216
                assetDescription.text = assetlist.getDescription(sel.currentIndex)
217
            }
218
        }
219
220
221
222
        SplitView {
            orientation: Qt.Vertical
            Layout.fillHeight: true
            Layout.fillWidth: true
Nicolas Carion's avatar
Nicolas Carion committed
223
        TreeView {
224
            id: treeView
Nicolas Carion's avatar
Nicolas Carion committed
225
226
227
228
            Layout.fillHeight: true
            Layout.fillWidth: true
            alternatingRowColors: false
            headerVisible: false
229
230
231
            selection: sel
            selectionMode: SelectionMode.SingleSelection
            itemDelegate: Rectangle {
232
233
234
235
                id: assetDelegate
                // These anchors are important to allow "copy" dragging
                anchors.verticalCenter: parent ? parent.verticalCenter : undefined
                anchors.right: parent ? parent.right : undefined
236
                property bool isItem : styleData.value !== "root" && styleData.value !== ""
237
                property string mimeType : isItem ? assetlist.getMimeType(styleData.value) : ""
238
                height: assetText.implicitHeight
239
                color: dragArea.containsMouse ? activePalette.highlight : "transparent"
240
241
242
243

                Drag.active: isItem ? dragArea.drag.active : false
                Drag.dragType: Drag.Automatic
                Drag.supportedActions: Qt.CopyAction
244
245
246
247
                Drag.mimeData: isItem ? assetlist.getMimeData(styleData.value) : {}
                Drag.keys:[
                    isItem ? assetlist.getMimeType(styleData.value) : ""
                ]
248
249
250

                Row {
                    anchors.fill:parent
251
252
253
254
                    anchors.leftMargin: 1
                    anchors.topMargin: 1
                    anchors.bottomMargin: 1
                    spacing: 4
255
                    Image{
256
                        id: assetThumb
257
                        anchors.verticalCenter: parent.verticalCenter
258
                        visible: assetDelegate.isItem
259
                        property bool isFavorite: model == undefined || model.favorite === undefined ? false : model.favorite
260
                        property bool isCustom: model == undefined ? false : model.type == AssetType.Custom || model.type == AssetType.CustomAudio
261
                        height: parent.height * 0.8
262
                        width: height
263
                        source: assetText.text == '' ? '' : 'image://asseticon/' + assetText.text + '/' + model.type
264
265
                    }
                    Label {
266
267
                        id: assetText
                        font.bold : assetThumb.isFavorite
268
                        text: assetlist.getName(styleData.index)
269
                    }
Nicolas Carion's avatar
Nicolas Carion committed
270
                }
271
272
                MouseArea {
                    id: dragArea
273
                    anchors.fill: assetDelegate
274
                    hoverEnabled: true
275
276
277
278
279
                    acceptedButtons: Qt.LeftButton | Qt.RightButton
                    drag.target: undefined
                    onReleased: {
                        drag.target = undefined
                    }
280
                    onPressed: {
281
282
                        if (assetDelegate.isItem) {
                            //sel.select(styleData.index, ItemSelectionModel.Select)
283
                            sel.setCurrentIndex(styleData.index, ItemSelectionModel.ClearAndSelect)
284
285
                            if (mouse.button === Qt.LeftButton) {
                                drag.target = parent
286
287
                                // grabToImage does not work on QQuickWidget from AssetListWidget. We should use QQuickView + QWidget::createWindowContainer
                                /*parent.grabToImage(function(result) {
288
                                    parent.Drag.imageSource = result.url
289
                                })*/
290
291
                            } else {
                                drag.target = undefined
292
                                assetContextMenu.isItemFavorite = assetThumb.isFavorite
293
                                assetContextMenu.isCustom = assetThumb.isCustom
294
                                assetContextMenu.popup()
295
                                mouse.accepted = false
296
                            }
297
                            console.log(parent.Drag.keys)
298
299
300
301
302
303
304
305
                        } else {
                            if (treeView.isExpanded(styleData.index)) {
                                treeView.collapse(styleData.index)
                            } else {
                                treeView.expand(styleData.index)
                            }

                        }
306
                        treeView.focus = true
307
                    }
308
309
310
311
312
                    onDoubleClicked: {
                        if (isItem) {
                            assetlist.activate(styleData.index)
                        }
                    }
Nicolas Carion's avatar
Nicolas Carion committed
313
314
                }
            }
315
316
            Menu {
                id: assetContextMenu
317
                property bool isItemFavorite
318
                property bool isCustom: false
319
                MenuItem {
Yuri Chornoivan's avatar
Yuri Chornoivan committed
320
                    text: assetContextMenu.isItemFavorite ? i18n("Remove from favorites") : i18n("Add to favorites")
321
                    onTriggered: {
322
                        assetlist.setFavorite(sel.currentIndex, !assetContextMenu.isItemFavorite)
323
324
                    }
                }
325
326
327
328
329
330
331
                MenuItem {
                    id: removeMenu
                    text: i18n("Delete custom effect")
                    visible: isEffectList && assetContextMenu.isCustom
                    onTriggered: {
                        assetlist.deleteCustomEffect(sel.currentIndex)
                    }
332
                }
333
            }
334

Pino Toscano's avatar
Pino Toscano committed
335
            TableViewColumn { role: "identifier"; title: i18n("Name"); }
Nicolas Carion's avatar
Nicolas Carion committed
336
            model: assetListModel
337
338
339
340

            Keys.onDownPressed: {
                sel.setCurrentIndex(assetListModel.getNextChild(sel.currentIndex), ItemSelectionModel.ClearAndSelect)
                treeView.expand(sel.currentIndex.parent)
341
                treeView.__listView.positionViewAtIndex(rowPosition(assetListModel, sel.currentIndex), ListView.Visible)
342
343
344
345
            }
            Keys.onUpPressed: {
                sel.setCurrentIndex(assetListModel.getPreviousChild(sel.currentIndex), ItemSelectionModel.ClearAndSelect)
                treeView.expand(sel.currentIndex.parent)
346
                treeView.__listView.positionViewAtIndex(rowPosition(assetListModel, sel.currentIndex), ListView.Visible)
347
            }
348
349
350
351
352
            Keys.onReturnPressed: {
                if (sel.hasSelection) {
                    assetlist.activate(sel.currentIndex)
                }
            }
353

354
355
        }
        TextArea {
Nicolas Carion's avatar
Nicolas Carion committed
356
            id: assetDescription
357
            text: ""
358
            visible: showDescription.checked
359
            readOnly: true
360
            Layout.fillWidth: true
361
            height: font.pixelSize * 5
362
            states: State {
Nicolas Carion's avatar
Nicolas Carion committed
363
364
                name: "hasDescription"; when: assetDescription.text != '' && showDescription.checked
                PropertyChanges { target: assetDescription; visible: true}
365
            }
366
        }
367

368
369
370
        }
    }
}