import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import Shotcut.Controls as Shotcut

Shotcut.KeyframableFilter {
    width: 350
    height: 1000
    keyframableParameters: ["topStart", "topEnd", "topBlendIn", "topBlendOut", "topFadeIn", "topBlurWidthStart", "topBlurWidthEnd", "topBlurHeightStart", "topBlurHeightEnd", "bottomStart", "bottomEnd", "bottomBlendIn", "bottomBlendOut", "bottomFadeIn", "bottomBlurWidthStart", "bottomBlurWidthEnd", "bottomBlurHeightStart", "bottomBlurHeightEnd"]
    startValues: [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,]
    middleValues: [45, 80, 0, 10, 10, 0, 360, 0, 2, 45, 80, 0, 10, 10, 0, 360, 0, 2]
    endValues: [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5,]
    property var allParameters: [
        {
            name: "interpolation",
            type: "combobox",
            def: 1
        },
        {
            name: "topStart",
            type: "simple",
            def: 45
        },
        {
            name: "topEnd",
            type: "simple",
            def: 80
        },
        {
            name: "topFadeIn",
            type: "simple",
            def: 10
        },
        {
            name: "topBlendIn",
            type: "simple",
            def: 0
        },
        {
            name: "topBlendOut",
            type: "simple",
            def: 10
        },
        {
            name: "topBlurWidthStart",
            type: "simple",
            def: 0
        },
        {
            name: "topBlurHeightStart",
            type: "simple",
            def: 0
        },
        {
            name: "topBlurWidthEnd",
            type: "simple",
            def: 360
        },
        {
            name: "topBlurHeightEnd",
            type: "simple",
            def: 2
        },
        {
            name: "bottomStart",
            type: "simple",
            def: 45
        },
        {
            name: "bottomEnd",
            type: "simple",
            def: 80
        },
        {
            name: "bottomFadeIn",
            type: "simple",
            def: 10
        },
        {
            name: "bottomBlendIn",
            type: "simple",
            def: 0
        },
        {
            name: "bottomBlendOut",
            type: "simple",
            def: 10
        },
        {
            name: "bottomBlurWidthStart",
            type: "simple",
            def: 0
        },
        {
            name: "bottomBlurHeightStart",
            type: "simple",
            def: 0
        },
        {
            name: "bottomBlurWidthEnd",
            type: "simple",
            def: 360
        },
        {
            name: "bottomBlurHeightEnd",
            type: "simple",
            def: 2
        },
        {
            name: "topEnabled",
            type: "checkbox",
            def: true
        },
        {
            name: "bottomEnabled",
            type: "checkbox",
            def: true
        },
    ]
    function isKeyframeButtonChecked(control) {
        return filter.animateIn <= 0 && filter.animateOut <= 0 && filter.keyframeCount(control) > 0;
    }
    function setSimpleControl(parameter, controlSlider, controlKeyframeButton) {
        controlSlider.value = filter.getDouble(parameter, getPosition());
        controlKeyframeButton.checked = isKeyframeButtonChecked(parameter);
    }
    function setSimpleControlStatic(parameter, controlSlider) {
        controlSlider.value = filter.getDouble(parameter, getPosition());
    }
    function setSimpleComboBox(parameter, controlComboBox) {
        controlComboBox.currentIndex = filter.get(parameter);
    }
    function setSimpleCheckBox(parameter, controlCheckBox) {
        controlCheckBox.checked = filter.get(parameter) == "1";
    }
    function setSimpleTextField(parameter, controlTextField) {
        controlTextField.text = filter.get(parameter);
    }
    function setSimpleNumTextField(parameter, controlTextField) {
        controlTextField.text = filter.getDouble(parameter).toFixed(4);
    }
    function getFrameRate() {
        return producer.getDouble("meta.media.frame_rate_num", getPosition()) / producer.getDouble("meta.media.frame_rate_den", getPosition());
    }
    function getClipOffset() {
        return filter.in;
    }
    function getKeyframesButton(param) {
        return this["prop_" + param.name + "KeyframesButton"];
    }
    function getControl(param) {
        if (param.control != null && param.control !== undefined) {
            return this["prop_" + param.control];
        } else if (param.type == "simple" || param.type == "static") {
            return this["prop_" + param.name + "Slider"];
        } else if (param.type == "checkbox") {
            return this["prop_" + param.name + "CheckBox"];
        } else if (param.type == "combobox") {
            return this["prop_" + param.name + "ComboBox"];
        } else if (param.type == "textfield" || param.type == "numtextfield") {
            return this["prop_" + param.name + "TextField"];
        } else {
            return null;
        }
    }
    function enableControls(enabled) {
        for (var i = 0; i < allParameters.length; ++i) {
            var control = getControl(allParameters[i]);
            control.enabled = enabled;
        }
    }
    function defaultBeforePresetLoaded() {
        for (var i in preset.parameters) {
            filter.resetProperty(preset.parameters[i]);
        }
        resetSimpleKeyframes();
    }
    function defaultPresetSelected() {
        initializeSimpleKeyframes();
        setControls();
    }
    function setControlsForAllParameters() {
        for (var i = 0; i < allParameters.length; ++i) {
            var param = allParameters[i];
            var control = getControl(param);
            if (param.type == "simple") {
                setSimpleControl(param.name, control, getKeyframesButton(param));
            } else if (param.type == "static") {
                setSimpleControlStatic(param.name, control);
            } else if (param.type == "combobox") {
                setSimpleComboBox(param.name, control);
            } else if (param.type == "checkbox") {
                setSimpleCheckBox(param.name, control);
            } else if (param.type == "textfield") {
                setSimpleTextField(param.name, control);
            } else if (param.type == "numtextfield") {
                setSimpleNumTextField(param.name, control);
            }
        }
    }
    function setControls() {
        blockUpdate = true;
        setControlsForAllParameters();
        blockUpdate = false;
        enableControls(isSimpleKeyframesActive());
    }
    function defaultOnCompleted() {
        if (filter.isNew) {
            for (var i = 0; i < allParameters.length; ++i) {
                var param = allParameters[i];
                if (param.def != null) {
                    var control = getControl(param);
                    filter.set(param.name, param.def);
                }
            }
            filter.savePreset(preset.parameters);
        }
        setControls();
    }
    function updateSimpleKeyframes() {
        setControlsForAllParameters();
    }
    Component.onCompleted: {
        defaultOnCompleted();
    }
    function updateProperty_interpolation() {
        if (!blockUpdate) {
            filter.set("interpolation", interpolationComboBox.currentIndex);
        }
    }
    property alias prop_interpolationComboBox: interpolationComboBox
    function updateProperty_topEnabled() {
        if (!blockUpdate) {
            filter.set("topEnabled", topEnabledCheckBox.checked);
        }
    }
    property alias prop_topEnabledCheckBox: topEnabledCheckBox
    function updateProperty_topStart() {
        if (!blockUpdate) {
            updateFilter("topStart", topStartSlider.value, topStartKeyframesButton, getPosition());
        }
    }
    property alias prop_topStartSlider: topStartSlider
    property alias prop_topStartKeyframesButton: topStartKeyframesButton
    function updateProperty_topEnd() {
        if (!blockUpdate) {
            updateFilter("topEnd", topEndSlider.value, topEndKeyframesButton, getPosition());
        }
    }
    property alias prop_topEndSlider: topEndSlider
    property alias prop_topEndKeyframesButton: topEndKeyframesButton
    function updateProperty_topFadeIn() {
        if (!blockUpdate) {
            updateFilter("topFadeIn", topFadeInSlider.value, topFadeInKeyframesButton, getPosition());
        }
    }
    property alias prop_topFadeInSlider: topFadeInSlider
    property alias prop_topFadeInKeyframesButton: topFadeInKeyframesButton
    function updateProperty_topBlendIn() {
        if (!blockUpdate) {
            updateFilter("topBlendIn", topBlendInSlider.value, topBlendInKeyframesButton, getPosition());
        }
    }
    property alias prop_topBlendInSlider: topBlendInSlider
    property alias prop_topBlendInKeyframesButton: topBlendInKeyframesButton
    function updateProperty_topBlendOut() {
        if (!blockUpdate) {
            updateFilter("topBlendOut", topBlendOutSlider.value, topBlendOutKeyframesButton, getPosition());
        }
    }
    property alias prop_topBlendOutSlider: topBlendOutSlider
    property alias prop_topBlendOutKeyframesButton: topBlendOutKeyframesButton
    function updateProperty_topBlurWidthStart() {
        if (!blockUpdate) {
            updateFilter("topBlurWidthStart", topBlurWidthStartSlider.value, topBlurWidthStartKeyframesButton, getPosition());
        }
    }
    property alias prop_topBlurWidthStartSlider: topBlurWidthStartSlider
    property alias prop_topBlurWidthStartKeyframesButton: topBlurWidthStartKeyframesButton
    function updateProperty_topBlurHeightStart() {
        if (!blockUpdate) {
            updateFilter("topBlurHeightStart", topBlurHeightStartSlider.value, topBlurHeightStartKeyframesButton, getPosition());
        }
    }
    property alias prop_topBlurHeightStartSlider: topBlurHeightStartSlider
    property alias prop_topBlurHeightStartKeyframesButton: topBlurHeightStartKeyframesButton
    function updateProperty_topBlurWidthEnd() {
        if (!blockUpdate) {
            updateFilter("topBlurWidthEnd", topBlurWidthEndSlider.value, topBlurWidthEndKeyframesButton, getPosition());
        }
    }
    property alias prop_topBlurWidthEndSlider: topBlurWidthEndSlider
    property alias prop_topBlurWidthEndKeyframesButton: topBlurWidthEndKeyframesButton
    function updateProperty_topBlurHeightEnd() {
        if (!blockUpdate) {
            updateFilter("topBlurHeightEnd", topBlurHeightEndSlider.value, topBlurHeightEndKeyframesButton, getPosition());
        }
    }
    property alias prop_topBlurHeightEndSlider: topBlurHeightEndSlider
    property alias prop_topBlurHeightEndKeyframesButton: topBlurHeightEndKeyframesButton
    function updateProperty_bottomEnabled() {
        if (!blockUpdate) {
            filter.set("bottomEnabled", bottomEnabledCheckBox.checked);
        }
    }
    property alias prop_bottomEnabledCheckBox: bottomEnabledCheckBox
    function updateProperty_bottomStart() {
        if (!blockUpdate) {
            updateFilter("bottomStart", bottomStartSlider.value, bottomStartKeyframesButton, getPosition());
        }
    }
    property alias prop_bottomStartSlider: bottomStartSlider
    property alias prop_bottomStartKeyframesButton: bottomStartKeyframesButton
    function updateProperty_bottomEnd() {
        if (!blockUpdate) {
            updateFilter("bottomEnd", bottomEndSlider.value, bottomEndKeyframesButton, getPosition());
        }
    }
    property alias prop_bottomEndSlider: bottomEndSlider
    property alias prop_bottomEndKeyframesButton: bottomEndKeyframesButton
    function updateProperty_bottomFadeIn() {
        if (!blockUpdate) {
            updateFilter("bottomFadeIn", bottomFadeInSlider.value, bottomFadeInKeyframesButton, getPosition());
        }
    }
    property alias prop_bottomFadeInSlider: bottomFadeInSlider
    property alias prop_bottomFadeInKeyframesButton: bottomFadeInKeyframesButton
    function updateProperty_bottomBlendIn() {
        if (!blockUpdate) {
            updateFilter("bottomBlendIn", bottomBlendInSlider.value, bottomBlendInKeyframesButton, getPosition());
        }
    }
    property alias prop_bottomBlendInSlider: bottomBlendInSlider
    property alias prop_bottomBlendInKeyframesButton: bottomBlendInKeyframesButton
    function updateProperty_bottomBlendOut() {
        if (!blockUpdate) {
            updateFilter("bottomBlendOut", bottomBlendOutSlider.value, bottomBlendOutKeyframesButton, getPosition());
        }
    }
    property alias prop_bottomBlendOutSlider: bottomBlendOutSlider
    property alias prop_bottomBlendOutKeyframesButton: bottomBlendOutKeyframesButton
    function updateProperty_bottomBlurWidthStart() {
        if (!blockUpdate) {
            updateFilter("bottomBlurWidthStart", bottomBlurWidthStartSlider.value, bottomBlurWidthStartKeyframesButton, getPosition());
        }
    }
    property alias prop_bottomBlurWidthStartSlider: bottomBlurWidthStartSlider
    property alias prop_bottomBlurWidthStartKeyframesButton: bottomBlurWidthStartKeyframesButton
    function updateProperty_bottomBlurHeightStart() {
        if (!blockUpdate) {
            updateFilter("bottomBlurHeightStart", bottomBlurHeightStartSlider.value, bottomBlurHeightStartKeyframesButton, getPosition());
        }
    }
    property alias prop_bottomBlurHeightStartSlider: bottomBlurHeightStartSlider
    property alias prop_bottomBlurHeightStartKeyframesButton: bottomBlurHeightStartKeyframesButton
    function updateProperty_bottomBlurWidthEnd() {
        if (!blockUpdate) {
            updateFilter("bottomBlurWidthEnd", bottomBlurWidthEndSlider.value, bottomBlurWidthEndKeyframesButton, getPosition());
        }
    }
    property alias prop_bottomBlurWidthEndSlider: bottomBlurWidthEndSlider
    property alias prop_bottomBlurWidthEndKeyframesButton: bottomBlurWidthEndKeyframesButton
    function updateProperty_bottomBlurHeightEnd() {
        if (!blockUpdate) {
            updateFilter("bottomBlurHeightEnd", bottomBlurHeightEndSlider.value, bottomBlurHeightEndKeyframesButton, getPosition());
        }
    }
    property alias prop_bottomBlurHeightEndSlider: bottomBlurHeightEndSlider
    property alias prop_bottomBlurHeightEndKeyframesButton: bottomBlurHeightEndKeyframesButton
    GridLayout {
        columns: 4
        anchors.fill: parent
        anchors.margins: 8
        Label {
            text: qsTr('Preset')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.Preset {
            id: preset
            parameters: ["interpolation", "topStart", "topEnd", "topBlendIn", "topBlendOut", "topFadeIn", "topBlurWidthStart", "topBlurWidthEnd", "topBlurHeightStart", "topBlurHeightEnd", "bottomStart", "bottomEnd", "bottomBlendIn", "bottomBlendOut", "bottomFadeIn", "bottomBlurWidthStart", "bottomBlurWidthEnd", "bottomBlurHeightStart", "bottomBlurHeightEnd", "topEnabled", "bottomEnabled"]
            Layout.columnSpan: 3
            onBeforePresetLoaded: {
                defaultBeforePresetLoaded();
            }
            onPresetSelected: {
                defaultPresetSelected();
            }
        }
        Label {
            text: qsTr('Interpolation')
            Layout.alignment: Qt.AlignRight
        }
        ComboBox {
            id: interpolationComboBox
            currentIndex: 0
            model: ["Nearest-neighbor", "Bilinear"]
            Layout.columnSpan: 2
            onCurrentIndexChanged: updateProperty_interpolation()
        }
        Shotcut.UndoButton {
            id: interpolationUndo
            onClicked: interpolationComboBox.currentIndex = 1
        }
        Label {
            text: qsTr('Top')
            Layout.alignment: Qt.AlignLeft
        }
        CheckBox {
            id: topEnabledCheckBox
            text: qsTr('')
            checked: true
            Layout.columnSpan: 3
            onCheckedChanged: updateProperty_topEnabled()
        }
        Label {
            text: qsTr('Start')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: topStartSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_topStart()
        }
        Shotcut.KeyframesButton {
            id: topStartKeyframesButton
            checked: isKeyframeButtonChecked("topStart")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "topStart", topStartSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: topStartUndo
            onClicked: topStartSlider.value = 45
        }
        Label {
            text: qsTr('End')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: topEndSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_topEnd()
        }
        Shotcut.KeyframesButton {
            id: topEndKeyframesButton
            checked: isKeyframeButtonChecked("topEnd")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "topEnd", topEndSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: topEndUndo
            onClicked: topEndSlider.value = 80
        }
        Label {
            text: qsTr('Fade')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: topFadeInSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_topFadeIn()
        }
        Shotcut.KeyframesButton {
            id: topFadeInKeyframesButton
            checked: isKeyframeButtonChecked("topFadeIn")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "topFadeIn", topFadeInSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: topFadeInUndo
            onClicked: topFadeInSlider.value = 10
        }
        Label {
            text: qsTr('Blend')
            Layout.alignment: Qt.AlignRight
        }
        Label {
            text: qsTr('')
            Layout.alignment: Qt.AlignRight
            Layout.columnSpan: 3
        }
        Label {
            text: qsTr('In')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: topBlendInSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_topBlendIn()
        }
        Shotcut.KeyframesButton {
            id: topBlendInKeyframesButton
            checked: isKeyframeButtonChecked("topBlendIn")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "topBlendIn", topBlendInSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: topBlendInUndo
            onClicked: topBlendInSlider.value = 0
        }
        Label {
            text: qsTr('Out')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: topBlendOutSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_topBlendOut()
        }
        Shotcut.KeyframesButton {
            id: topBlendOutKeyframesButton
            checked: isKeyframeButtonChecked("topBlendOut")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "topBlendOut", topBlendOutSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: topBlendOutUndo
            onClicked: topBlendOutSlider.value = 10
        }
        Label {
            text: qsTr('Blur')
            Layout.alignment: Qt.AlignRight
        }
        Label {
            text: qsTr('')
            Layout.alignment: Qt.AlignRight
            Layout.columnSpan: 3
        }
        Label {
            text: qsTr('Width at start')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: topBlurWidthStartSlider
            minimumValue: 0
            maximumValue: 360
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_topBlurWidthStart()
        }
        Shotcut.KeyframesButton {
            id: topBlurWidthStartKeyframesButton
            checked: isKeyframeButtonChecked("topBlurWidthStart")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "topBlurWidthStart", topBlurWidthStartSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: topBlurWidthStartUndo
            onClicked: topBlurWidthStartSlider.value = 0
        }
        Label {
            text: qsTr('Height at start')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: topBlurHeightStartSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_topBlurHeightStart()
        }
        Shotcut.KeyframesButton {
            id: topBlurHeightStartKeyframesButton
            checked: isKeyframeButtonChecked("topBlurHeightStart")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "topBlurHeightStart", topBlurHeightStartSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: topBlurHeightStartUndo
            onClicked: topBlurHeightStartSlider.value = 0
        }
        Label {
            text: qsTr('Width at end')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: topBlurWidthEndSlider
            minimumValue: 0
            maximumValue: 360
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_topBlurWidthEnd()
        }
        Shotcut.KeyframesButton {
            id: topBlurWidthEndKeyframesButton
            checked: isKeyframeButtonChecked("topBlurWidthEnd")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "topBlurWidthEnd", topBlurWidthEndSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: topBlurWidthEndUndo
            onClicked: topBlurWidthEndSlider.value = 360
        }
        Label {
            text: qsTr('Height at end')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: topBlurHeightEndSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_topBlurHeightEnd()
        }
        Shotcut.KeyframesButton {
            id: topBlurHeightEndKeyframesButton
            checked: isKeyframeButtonChecked("topBlurHeightEnd")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "topBlurHeightEnd", topBlurHeightEndSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: topBlurHeightEndUndo
            onClicked: topBlurHeightEndSlider.value = 2
        }
        Label {
            text: qsTr('Bottom')
            Layout.alignment: Qt.AlignLeft
        }
        CheckBox {
            id: bottomEnabledCheckBox
            text: qsTr('')
            checked: true
            Layout.columnSpan: 3
            onCheckedChanged: updateProperty_bottomEnabled()
        }
        Label {
            text: qsTr('Start')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: bottomStartSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_bottomStart()
        }
        Shotcut.KeyframesButton {
            id: bottomStartKeyframesButton
            checked: isKeyframeButtonChecked("bottomStart")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "bottomStart", bottomStartSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: bottomStartUndo
            onClicked: bottomStartSlider.value = 45
        }
        Label {
            text: qsTr('End')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: bottomEndSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_bottomEnd()
        }
        Shotcut.KeyframesButton {
            id: bottomEndKeyframesButton
            checked: isKeyframeButtonChecked("bottomEnd")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "bottomEnd", bottomEndSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: bottomEndUndo
            onClicked: bottomEndSlider.value = 80
        }
        Label {
            text: qsTr('Fade')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: bottomFadeInSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_bottomFadeIn()
        }
        Shotcut.KeyframesButton {
            id: bottomFadeInKeyframesButton
            checked: isKeyframeButtonChecked("bottomFadeIn")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "bottomFadeIn", bottomFadeInSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: bottomFadeInUndo
            onClicked: bottomFadeInSlider.value = 0
        }
        Label {
            text: qsTr('Blend')
            Layout.alignment: Qt.AlignRight
        }
        Label {
            text: qsTr('')
            Layout.alignment: Qt.AlignRight
            Layout.columnSpan: 3
        }
        Label {
            text: qsTr('In')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: bottomBlendInSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_bottomBlendIn()
        }
        Shotcut.KeyframesButton {
            id: bottomBlendInKeyframesButton
            checked: isKeyframeButtonChecked("bottomBlendIn")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "bottomBlendIn", bottomBlendInSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: bottomBlendInUndo
            onClicked: bottomBlendInSlider.value = 10
        }
        Label {
            text: qsTr('Out')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: bottomBlendOutSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_bottomBlendOut()
        }
        Shotcut.KeyframesButton {
            id: bottomBlendOutKeyframesButton
            checked: isKeyframeButtonChecked("bottomBlendOut")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "bottomBlendOut", bottomBlendOutSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: bottomBlendOutUndo
            onClicked: bottomBlendOutSlider.value = 10
        }
        Label {
            text: qsTr('Blur')
            Layout.alignment: Qt.AlignRight
        }
        Label {
            text: qsTr('')
            Layout.alignment: Qt.AlignRight
            Layout.columnSpan: 3
        }
        Label {
            text: qsTr('Width at start')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: bottomBlurWidthStartSlider
            minimumValue: 0
            maximumValue: 360
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_bottomBlurWidthStart()
        }
        Shotcut.KeyframesButton {
            id: bottomBlurWidthStartKeyframesButton
            checked: isKeyframeButtonChecked("bottomBlurWidthStart")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "bottomBlurWidthStart", bottomBlurWidthStartSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: bottomBlurWidthStartUndo
            onClicked: bottomBlurWidthStartSlider.value = 0
        }
        Label {
            text: qsTr('Height at start')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: bottomBlurHeightStartSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_bottomBlurHeightStart()
        }
        Shotcut.KeyframesButton {
            id: bottomBlurHeightStartKeyframesButton
            checked: isKeyframeButtonChecked("bottomBlurHeightStart")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "bottomBlurHeightStart", bottomBlurHeightStartSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: bottomBlurHeightStartUndo
            onClicked: bottomBlurHeightStartSlider.value = 0
        }
        Label {
            text: qsTr('Width at end')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: bottomBlurWidthEndSlider
            minimumValue: 0
            maximumValue: 360
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_bottomBlurWidthEnd()
        }
        Shotcut.KeyframesButton {
            id: bottomBlurWidthEndKeyframesButton
            checked: isKeyframeButtonChecked("bottomBlurWidthEnd")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "bottomBlurWidthEnd", bottomBlurWidthEndSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: bottomBlurWidthEndUndo
            onClicked: bottomBlurWidthEndSlider.value = 360
        }
        Label {
            text: qsTr('Height at end')
            Layout.alignment: Qt.AlignRight
        }
        Shotcut.SliderSpinner {
            id: bottomBlurHeightEndSlider
            minimumValue: 0
            maximumValue: 90
            spinnerWidth: 120
            suffix: ' deg'
            decimals: 3
            stepSize: 1
            onValueChanged: updateProperty_bottomBlurHeightEnd()
        }
        Shotcut.KeyframesButton {
            id: bottomBlurHeightEndKeyframesButton
            checked: isKeyframeButtonChecked("bottomBlurHeightEnd")
            onToggled: {
                enableControls(true);
                toggleKeyframes(checked, "bottomBlurHeightEnd", bottomBlurHeightEndSlider.value);
            }
        }
        Shotcut.UndoButton {
            id: bottomBlurHeightEndUndo
            onClicked: bottomBlurHeightEndSlider.value = 2
        }
    }
    Connections {
        target: filter
        onInChanged: updateSimpleKeyframes()
        onOutChanged: updateSimpleKeyframes()
        onAnimateInChanged: updateSimpleKeyframes()
        onAnimateOutChanged: updateSimpleKeyframes()
        onChanged: setControls()
    }
    Connections {
        target: producer
        onPositionChanged: setControls()
    }
}
