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.12 19import QtQuick.Controls 2.12 20import QtQuick.Layouts 1.12 21import Shotcut.Controls 1.0 as Shotcut 22 23Item { 24 property var defaultParameters: ['circle_radius','gaussian_radius', 'correlation', 'noise'] 25 property bool blockUpdate: true 26 property var startValues: [0.0, 0.0, 0.0, 0.0 ] 27 property var middleValues: [2.0, 0.0, 0.95, 0.01] 28 property var endValues: [0.0, 0.0, 0.0, 0.0 ] 29 width: 350 30 height: 150 31 Component.onCompleted: { 32 if (filter.isNew) { 33 // Set default parameter values 34 filter.set('circle_radius', 2.0) 35 filter.set('gaussian_radius', 0.0) 36 filter.set('correlation', 0.95) 37 filter.set('noise', 0.01) 38 filter.savePreset(defaultParameters) 39 } else { 40 initSimpleAnimation() 41 } 42 setControls() 43 } 44 45 function initSimpleAnimation() { 46 middleValues = [filter.getDouble(defaultParameters[0], filter.animateIn), 47 filter.getDouble(defaultParameters[1], filter.animateIn), 48 filter.getDouble(defaultParameters[2], filter.animateIn), 49 filter.getDouble(defaultParameters[3], filter.animateIn)] 50 if (filter.animateIn > 0) { 51 startValues = [filter.getDouble(defaultParameters[0], 0), 52 filter.getDouble(defaultParameters[1], 0), 53 filter.getDouble(defaultParameters[2], 0), 54 filter.getDouble(defaultParameters[3], 0)] 55 } 56 if (filter.animateOut > 0) { 57 endValues = [filter.getDouble(defaultParameters[0], filter.duration - 1), 58 filter.getDouble(defaultParameters[1], filter.duration - 1), 59 filter.getDouble(defaultParameters[2], filter.duration - 1), 60 filter.getDouble(defaultParameters[3], filter.duration - 1)] 61 } 62 } 63 64 function getPosition() { 65 return Math.max(producer.position - (filter.in - producer.in), 0) 66 } 67 68 function setControls() { 69 var position = getPosition() 70 blockUpdate = true 71 circleSlider.value = filter.getDouble("circle_radius", position) 72 circleKeyframesButton.checked = filter.animateIn <= 0 && filter.animateOut <= 0 && filter.keyframeCount('circle_radius') > 0 73 gaussianSlider.value = filter.getDouble("gaussian_radius", position) 74 gaussianKeyframesButton.checked = filter.animateIn <= 0 && filter.animateOut <= 0 && filter.keyframeCount('gaussian_radius') > 0 75 correlationSlider.value = filter.getDouble("correlation", position) 76 correlationKeyframesButton.checked = filter.animateIn <= 0 && filter.animateOut <= 0 && filter.keyframeCount('correlation') > 0 77 noiseSlider.value = filter.getDouble("noise", position) 78 noiseKeyframesButton.checked = filter.animateIn <= 0 && filter.animateOut <= 0 && filter.keyframeCount('noise') > 0 79 blockUpdate = false 80 circleSlider.enabled = gaussianSlider.enabled = correlationSlider.enabled = noiseSlider.enabled 81 = position <= 0 || (position >= (filter.animateIn - 1) && position <= (filter.duration - filter.animateOut)) || position >= (filter.duration - 1) 82 } 83 84 function updateFilter(parameter, value, position, button) { 85 if (blockUpdate) return 86 var index = defaultParameters.indexOf(parameter) 87 88 if (position !== null) { 89 if (position <= 0 && filter.animateIn > 0) 90 startValues[index] = value 91 else if (position >= filter.duration - 1 && filter.animateOut > 0) 92 endValues[index] = value 93 else 94 middleValues[index] = value 95 } 96 97 if (filter.animateIn > 0 || filter.animateOut > 0) { 98 filter.resetProperty(parameter) 99 button.checked = false 100 if (filter.animateIn > 0) { 101 filter.set(parameter, startValues[index], 0) 102 filter.set(parameter, middleValues[index], filter.animateIn - 1) 103 } 104 if (filter.animateOut > 0) { 105 filter.set(parameter, middleValues[index], filter.duration - filter.animateOut) 106 filter.set(parameter, endValues[index], filter.duration - 1) 107 } 108 } else if (!button.checked) { 109 filter.resetProperty(parameter) 110 filter.set(parameter, middleValues[index]) 111 } else if (position !== null) { 112 filter.set(parameter, value, position) 113 } 114 } 115 116 function onKeyframesButtonClicked(checked, parameter, value) { 117 if (checked) { 118 blockUpdate = true 119 circleSlider.enabled = gaussianSlider.enabled = correlationSlider.enabled = noiseSlider.enabled = true 120 if (filter.animateIn > 0 || filter.animateOut > 0) { 121 for (var i = 0; i < defaultParameters.length; i++) 122 filter.resetProperty(defaultParameters[i]) 123 filter.animateIn = filter.animateOut = 0 124 } else { 125 filter.clearSimpleAnimation(parameter) 126 } 127 blockUpdate = false 128 filter.set(parameter, value, getPosition()) 129 } else { 130 filter.resetProperty(parameter) 131 filter.set(parameter, value) 132 } 133 } 134 135 GridLayout { 136 columns: 4 137 anchors.fill: parent 138 anchors.margins: 8 139 140 Label { 141 text: qsTr('Preset') 142 Layout.alignment: Qt.AlignRight 143 } 144 Shotcut.Preset { 145 Layout.columnSpan: 3 146 parameters: defaultParameters 147 onBeforePresetLoaded: { 148 for (var i = 0; i < defaultParameters.length; i++) 149 filter.resetProperty(defaultParameters[i]) 150 } 151 onPresetSelected: { 152 setControls() 153 initSimpleAnimation() 154 } 155 } 156 157 // Row 2 158 Label { 159 text: qsTr('Circle radius') 160 Layout.alignment: Qt.AlignRight 161 } 162 Shotcut.SliderSpinner { 163 id: circleSlider 164 minimumValue: 0 165 maximumValue: 99.99 166 decimals: 2 167 stepSize: 0.1 168 onValueChanged: updateFilter('circle_radius', value, getPosition(), circleKeyframesButton) 169 } 170 Shotcut.UndoButton { 171 onClicked: circleSlider.value = 2 172 } 173 Shotcut.KeyframesButton { 174 id: circleKeyframesButton 175 onToggled: onKeyframesButtonClicked(checked, 'circle_radius', circleSlider.value) 176 } 177 178 // Row 3 179 Label { 180 text: qsTr('Gaussian radius') 181 Layout.alignment: Qt.AlignRight 182 } 183 Shotcut.SliderSpinner { 184 id: gaussianSlider 185 minimumValue: 0 186 maximumValue: 99.99 187 decimals: 2 188 stepSize: 0.1 189 onValueChanged: updateFilter('gaussian_radius', value, getPosition(), gaussianKeyframesButton) 190 } 191 Shotcut.UndoButton { 192 onClicked: gaussianSlider.value = 0 193 } 194 Shotcut.KeyframesButton { 195 id: gaussianKeyframesButton 196 onToggled: onKeyframesButtonClicked(checked, 'gaussian_radius', gaussianSlider.value) 197 } 198 199 // Row 4 200 Label { 201 text: qsTr('Correlation') 202 Layout.alignment: Qt.AlignRight 203 } 204 Shotcut.SliderSpinner { 205 id: correlationSlider 206 minimumValue: 0.0 207 maximumValue: 1.0 208 decimals: 2 209 onValueChanged: updateFilter('correlation', value, getPosition(), correlationKeyframesButton) 210 } 211 Shotcut.UndoButton { 212 onClicked: correlationSlider.value = 0.95 213 } 214 Shotcut.KeyframesButton { 215 id: correlationKeyframesButton 216 onToggled: onKeyframesButtonClicked(checked, 'correlation', correlationSlider.value) 217 } 218 219 // Row 5 220 Label { 221 text: qsTr('Noise') 222 Layout.alignment: Qt.AlignRight 223 } 224 Shotcut.SliderSpinner { 225 id: noiseSlider 226 minimumValue: 0.0 227 maximumValue: 1.0 228 decimals: 2 229 onValueChanged: updateFilter('noise', value, getPosition(), noiseKeyframesButton) 230 } 231 Shotcut.UndoButton { 232 onClicked: noiseSlider.value = 0.01 233 } 234 Shotcut.KeyframesButton { 235 id: noiseKeyframesButton 236 onToggled: onKeyframesButtonClicked(checked, 'noise', noiseSlider.value) 237 } 238 239 Item { 240 Layout.fillHeight: true 241 } 242 } 243 244 function updateSimpleAnimation() { 245 updateFilter('circle_radius', circleSlider.value, getPosition(), circleKeyframesButton) 246 updateFilter('gaussian_radius', gaussianSlider.value, getPosition(), gaussianKeyframesButton) 247 updateFilter('correlation', correlationSlider.value, getPosition(), correlationKeyframesButton) 248 updateFilter('noise', noiseSlider.value, getPosition(), noiseKeyframesButton) 249 } 250 251 Connections { 252 target: filter 253 onInChanged: updateSimpleAnimation() 254 onOutChanged: updateSimpleAnimation() 255 onAnimateInChanged: updateSimpleAnimation() 256 onAnimateOutChanged: updateSimpleAnimation() 257 } 258 259 Connections { 260 target: producer 261 onPositionChanged: setControls() 262 } 263} 264