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