1/*
2 * Copyright (c) 2019-2020 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.5
19
20Item {
21    // NOTE: This item only works for numeric parameters.
22
23    // The following 4 arrays should be the same length and aligned to the
24    // same parameters added to keyframableParameters. They should be set
25    // by the filter that inherits this item.
26    property var keyframableParameters: [] // strings of MLT property names
27    // The following 3 arrays are for simple keyframes.
28    property var startValues: []
29    property var middleValues: []
30    property var endValues: []
31
32    // Set this property true to guard against updateFilter() getting
33    // called when setting a control value in code. Do not forget to reset it
34    // to false when you are done setting controls' values.
35    property bool blockUpdate: true
36
37    Component.onCompleted: {
38        if (!filter.isNew)
39            initializeSimpleKeyframes()
40    }
41
42    // This function should be called in your Preset.beforePresetSelected handler.
43    function resetSimpleKeyframes() {
44        for (var i in keyframableParameters)
45            filter.resetProperty(keyframableParameters[i])
46    }
47
48    // This function should be called in your Preset.presetSelected handler.
49    function initializeSimpleKeyframes() {
50        for (var i in keyframableParameters) {
51            var parameter = keyframableParameters[i]
52            middleValues[i] = filter.getDouble(parameter, filter.animateIn)
53            if (filter.animateIn > 0)
54                startValues[i] = filter.getDouble(parameter, 0)
55            if (filter.animateOut > 0)
56                endValues[i] = filter.getDouble(parameter, filter.duration - 1)
57        }
58    }
59
60    // This function should be called when calling updateFilter() (except
61    // in filter Connections).
62    function getPosition() {
63        return Math.max(producer.position - (filter.in - producer.in), 0)
64    }
65
66    // This function can be called in your setControls() function to determine
67    // whether to enable keyframable controls.
68    function isSimpleKeyframesActive() {
69        var position = getPosition()
70        return  position <= 0
71            || (position >= (filter.animateIn - 1) &&
72                position <= (filter.duration - filter.animateOut))
73            ||  position >= (filter.duration - 1)
74    }
75
76    // This function should be called in your controls' valueChanged handler.
77    function updateFilter(parameter, value, button, position) {
78        if (blockUpdate) return
79        var index = keyframableParameters.indexOf(parameter)
80
81        if (position !== null) {
82            if (position <= 0 && filter.animateIn > 0)
83                startValues[index] = value
84            else if (position >= filter.duration - 1 && filter.animateOut > 0)
85                endValues[index] = value
86            else
87                middleValues[index] = value
88        }
89
90        if (filter.animateIn > 0 || filter.animateOut > 0) {
91            filter.resetProperty(parameter)
92            button.checked = false
93            if (filter.animateIn > 0) {
94                filter.set(parameter, startValues[index], 0)
95                filter.set(parameter, middleValues[index], filter.animateIn - 1)
96            }
97            if (filter.animateOut > 0) {
98                filter.set(parameter, middleValues[index], filter.duration - filter.animateOut)
99                filter.set(parameter, endValues[index], filter.duration - 1)
100            }
101        } else if (!button.checked) {
102            filter.resetProperty(parameter)
103            filter.set(parameter, middleValues[index])
104        } else if (position !== null) {
105            filter.set(parameter, value, position)
106        }
107    }
108
109    // This function should be called in the KeyframesButton.toggled handler.
110    function toggleKeyframes(isEnabled, parameter, value) {
111        if (isEnabled) {
112            blockUpdate = true
113            if (filter.animateIn > 0 || filter.animateOut > 0) {
114                // Reset all of the simple keyframes.
115                resetSimpleKeyframes()
116                filter.animateIn = 0
117                blockUpdate = false
118                filter.animateOut = 0
119            } else {
120                filter.clearSimpleAnimation(parameter)
121                blockUpdate = false
122            }
123            // Set this keyframe value.
124            filter.set(parameter, value, getPosition())
125        } else {
126            // Remove keyframes and set the parameter.
127            filter.resetProperty(parameter)
128            filter.set(parameter, value)
129        }
130    }
131}
132