1/*
2 * Copyright (c) 2014-2021 Meltytech, LLC
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 3 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, see <http://www.gnu.org/licenses/>.
16 */
17
18import QtQuick 2.1
19import QtQuick.Controls 2.12
20import QtQuick.Layouts 1.0
21import Shotcut.Controls 1.0 as Shotcut
22import org.shotcut.qml 1.0 as Shotcut
23
24Rectangle {
25    id: root
26    property int selectedIndex: Shotcut.Filter.NoCurrentFilter
27    signal currentFilterRequested(int attachedIndex)
28
29    function clearCurrentFilter() {
30        if (filterConfig.item) {
31            filterConfig.item.width = 1
32            filterConfig.item.height = 1
33        }
34        filterConfig.source = ""
35    }
36
37    function setCurrentFilter(index) {
38        clearCurrentFilter()
39        attachedFilters.setCurrentFilter(index)
40        selectedIndex = index
41        filterConfig.source = metadata ? metadata.qmlFilePath : ""
42    }
43
44    function openFilterMenu() {
45        if (attachedfiltersmodel.isProducerSelected)
46            filterMenu.open()
47    }
48
49    color: activePalette.window
50    width: 400
51
52    onWidthChanged: _setLayout()
53    onHeightChanged: _setLayout()
54
55    function _setLayout() {
56        if (height > width - attachedFilters.minimumWidth) {
57            root.state = "portrait"
58        } else {
59            root.state = "landscape"
60        }
61    }
62
63    SystemPalette { id: activePalette }
64
65    Rectangle {
66        id: titleBackground
67        anchors {
68            top: parent.top
69            left: parent.left
70            right: parent.right
71            bottom: titleLabel.bottom
72            topMargin: 10
73            leftMargin: 10
74            rightMargin: 10
75        }
76        color: activePalette.highlight
77        visible: attachedfiltersmodel.producerTitle != ""
78    }
79
80    Label {
81        id: titleLabel
82        anchors {
83            top: parent.top
84            left: parent.left
85            right: parent.right
86            topMargin: 10
87            leftMargin: 10
88            rightMargin: 10
89        }
90        text: attachedfiltersmodel.producerTitle
91        elide: Text.ElideLeft
92        color: activePalette.highlightedText
93        font.bold: true
94        horizontalAlignment: Text.AlignHCenter
95    }
96
97
98    GridLayout {
99        id: attachedContainer
100        columns: children.length - 1
101        anchors {
102            top: titleBackground.bottom
103            left: parent.left
104            leftMargin: 10
105            rightMargin: 10
106            topMargin: 6
107            bottomMargin: 4
108        }
109
110        AttachedFilters {
111            id: attachedFilters
112            property int minimumWidth: application.OS === 'Windows'? 350 : 250
113            Layout.columnSpan: parent.columns
114            Layout.fillWidth: true
115            Layout.fillHeight: true
116            onFilterClicked: {
117                root.currentFilterRequested(index)
118            }
119            Label {
120                anchors.centerIn: parent
121                text: qsTr("Nothing selected")
122                color: activePalette.text
123                visible: !attachedfiltersmodel.isProducerSelected
124            }
125        }
126
127        Shotcut.Button {
128            id: addButton
129            implicitWidth: height
130            icon.name: 'list-add'
131            icon.source: 'qrc:///icons/oxygen/32x32/actions/list-add.png'
132            enabled: attachedfiltersmodel.isProducerSelected
133            opacity: enabled ? 1.0 : 0.5
134            Shotcut.HoverTip { text: qsTr('Add a filter') }
135            onClicked: {
136                if (application.confirmOutputFilter()) {
137                    filterMenu.open()
138                }
139            }
140        }
141        Shotcut.Button {
142            id: removeButton
143            implicitWidth: height
144            icon.name: 'list-remove'
145            icon.source: 'qrc:///icons/oxygen/32x32/actions/list-remove.png'
146            enabled: selectedIndex > Shotcut.Filter.NoCurrentFilter
147            opacity: enabled ? 1.0 : 0.5
148            Shotcut.HoverTip { text: qsTr('Remove selected filter') }
149            onClicked: {
150                attachedfiltersmodel.remove(selectedIndex)
151            }
152        }
153        Shotcut.Button { // separator
154            enabled: false
155            implicitWidth: 1
156            implicitHeight: 20
157        }
158        Shotcut.Button {
159            id: copyButton
160            implicitWidth: height
161            icon.name: 'edit-copy'
162            icon.source: 'qrc:///icons/oxygen/32x32/actions/edit-copy.png'
163            enabled: selectedIndex > Shotcut.Filter.NoCurrentFilter
164            opacity: enabled ? 1.0 : 0.5
165            Shotcut.HoverTip { text: qsTr('Copy the filters') }
166            onClicked: application.copyFilters()
167        }
168        Shotcut.Button {
169            id: pasteButton
170            implicitWidth: height
171            enabled: application.hasFiltersOnClipboard && attachedfiltersmodel.isProducerSelected
172            opacity: enabled ? 1.0 : 0.5
173            icon.name: 'edit-paste'
174            icon.source: 'qrc:///icons/oxygen/32x32/actions/edit-paste.png'
175            Shotcut.HoverTip { text: qsTr('Paste filters') }
176            onClicked: application.pasteFilters()
177        }
178        Shotcut.Button { // separator
179            enabled: false
180            implicitWidth: 1
181            implicitHeight: 20
182        }
183        Shotcut.Button {
184            id: moveUpButton
185            implicitWidth: height
186            enabled: selectedIndex > 0
187            opacity: enabled ? 1.0 : 0.5
188            icon.name: 'lift'
189            icon.source: 'qrc:///icons/oxygen/32x32/actions/lift.png'
190            Shotcut.HoverTip { text: qsTr('Move filter up') }
191            onClicked: attachedfiltersmodel.move(selectedIndex, --selectedIndex)
192        }
193        Shotcut.Button {
194            id: moveDownButton
195            implicitWidth: height
196            enabled: selectedIndex > Shotcut.Filter.NoCurrentFilter && selectedIndex + 1 < attachedfiltersmodel.rowCount()
197            opacity: enabled ? 1.0 : 0.5
198            icon.name: 'overwrite'
199            icon.source: 'qrc:///icons/oxygen/32x32/actions/overwrite.png'
200            Shotcut.HoverTip { text: qsTr('Move filter down') }
201            onClicked: attachedfiltersmodel.move(selectedIndex, ++selectedIndex)
202        }
203        Shotcut.Button { // separator
204            enabled: false
205            implicitWidth: 1
206            implicitHeight: 20
207        }
208        Shotcut.Button {
209            id: deselectButton
210            implicitWidth: height
211            icon.name: 'window-close'
212            icon.source: 'qrc:///icons/oxygen/32x32/actions/window-close.png'
213            enabled: selectedIndex > Shotcut.Filter.NoCurrentFilter
214            opacity: enabled ? 1.0 : 0.5
215            Shotcut.HoverTip { text: qsTr('Deselect the filter') }
216            onClicked: {
217                clearCurrentFilter()
218                attachedFilters.setCurrentFilter(Shotcut.Filter.DeselectCurrentFilter)
219                selectedIndex = Shotcut.Filter.NoCurrentFilter
220                filter.deselect()
221            }
222        }
223        Item {
224            Layout.fillWidth: true
225        }
226    }
227
228    Flickable {
229        id: filterConfigScrollView
230        clip: true
231        interactive: false
232        anchors.bottomMargin: 16
233        anchors.rightMargin: 16
234        contentWidth: filterConfig.item.width + 16
235        contentHeight: filterConfig.item.height + 16
236        ScrollBar.horizontal: ScrollBar {
237            height: 16
238            policy: ScrollBar.AlwaysOn
239            visible: filterConfigScrollView.contentWidth > filterConfigScrollView.width
240            parent: filterConfigScrollView.parent
241            anchors.top: filterConfigScrollView.bottom
242            anchors.left: filterConfigScrollView.left
243            anchors.right: filterConfigScrollView.right
244            background: Rectangle { color: parent.palette.alternateBase }
245        }
246        ScrollBar.vertical: ScrollBar {
247            width: 16
248            policy: ScrollBar.AlwaysOn
249            visible: filterConfigScrollView.contentHeight > filterConfigScrollView.height
250            parent: filterConfigScrollView.parent
251            anchors.top: filterConfigScrollView.top
252            anchors.left: filterConfigScrollView.right
253            anchors.bottom: filterConfigScrollView.bottom
254            background: Rectangle { color: parent.palette.alternateBase }
255        }
256
257        function expandWidth() {
258            if (filterConfig.item) {
259                filterConfig.item.width =
260                    Math.max(filterConfig.minimumWidth,
261                             filterConfigScrollView.width - 20 /* scroll bar */)
262            }
263        }
264        onWidthChanged: expandWidth()
265        Loader {
266            id: filterConfig
267            enabled: !filterMenu.visible
268            property int minimumWidth: 0
269            onLoaded: {
270                minimumWidth = item.width
271                filterConfigScrollView.expandWidth()
272            }
273        }
274    }
275
276    FilterMenu {
277        id: filterMenu
278        anchors {
279            top: titleBackground.bottom
280            left: parent.left
281            right: parent.right
282            bottom: parent.bottom
283            topMargin: attachedContainer.anchors.topMargin
284        }
285        z: 1
286        onFilterSelected: {
287            attachedfiltersmodel.add(metadatamodel.get(index))
288        }
289    }
290
291    states: [
292        State {
293            name: "landscape"
294            AnchorChanges {
295                target: filterConfigScrollView
296                anchors {
297                    top: titleBackground.bottom
298                    bottom: root.bottom
299                    left: attachedContainer.right
300                    right: root.right
301                }
302            }
303            PropertyChanges {
304                target: attachedContainer
305                width: attachedFilters.minimumWidth
306                height: root.height -
307                    titleBackground.height - titleBackground.anchors.topMargin - titleBackground.anchors.bottomMargin -
308                    attachedContainer.anchors.topMargin - attachedContainer.anchors.bottomMargin
309            }
310        },
311        State {
312            name: "portrait"
313            AnchorChanges {
314                target: filterConfigScrollView
315                anchors {
316                    top: attachedContainer.bottom
317                    bottom: root.bottom
318                    left: root.left
319                    right: root.right
320                }
321            }
322            PropertyChanges {
323                target: attachedContainer
324                width: titleBackground.width
325                height: 165
326            }
327        }
328    ]
329
330    Connections {
331        target: attachedfiltersmodel
332        function onIsProducerSelectedChanged() {
333            filterMenu.close()
334        }
335    }
336}
337