Revision control

++ // Copyright (C) 2022 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ import QtQuick
++ import QtQuick.Controls
++ import QtQuick.Dialogs
++ import QtQuick.Layouts
++
++ CustomPopup {
++ id: rootItem
++
++ property int propertyIndex: -1
++ readonly property bool isNewProperty: (propertyIndex == -1)
++ property variant defaultValue
++ property variant minValue
++ property variant maxValue
++ property int initialType: 2
++ property variant initialDefaultValue
++ property variant initialMinValue
++ property variant initialMaxValue
++ property string initialName
++ property string initialDescription
++ property string initialCustomValue
++ property bool initialUseCustomValue: false
++ property bool initialEnableMipmap: false // For image properties
++ property bool enableMipmap: false // For image properties
++ property bool initialExportImage: true
++ property bool exportImage: true
++ property int selectedNodeId: nodeViewItem.selectedNodeId
++ readonly property real componentSpacing: 10
++
++ function insertUniform() {
++ let newRow = -1
++ if (effectManager.uniformModel.updateRow(selectedNodeId, newRow, typeComboBox.currentIndex, uniformNameTextInput.text,
++ rootItem.defaultValue, descriptionTextArea.text, customValueTextArea.text,
++ customValueSwitch.checked, rootItem.minValue, rootItem.maxValue, rootItem.enableMipmap,
++ rootItem.exportImage)) {
++ rootItem.close();
++ }
++ }
++
++ function updateUniform() {
++ if (effectManager.uniformModel.updateRow(selectedNodeId, rootItem.propertyIndex, typeComboBox.currentIndex, uniformNameTextInput.text,
++ rootItem.defaultValue, descriptionTextArea.text, customValueTextArea.text,
++ customValueSwitch.checked, rootItem.minValue, rootItem.maxValue, rootItem.enableMipmap,
++ rootItem.exportImage)) {
++ rootItem.close();
++ }
++ }
++
++ function removeUniform() {
++ effectManager.uniformModel.removeRow(propertyIndex, 1);
++ rootItem.close();
++ }
++
++ function roundedNumber(num) {
++ return num.toFixed(3).toString();
++ }
++
++ x: mainWindow.width / 2 - width / 2
++ y: mainWindow.height / 2 - height / 2
++ width: 540
++ height: 640
++ modal: true
++ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
++
++ onVisibleChanged: {
++ if (visible) {
++ typeComboBox.currentIndex = initialType;
++ rootItem.enableMipmap = rootItem.initialEnableMipmap;
++ rootItem.exportImage = rootItem.initialExportImage;
++ if (initialType == 7) {
++ // When editing an image property, update the correct image
++ // preview & mipmap status
++ valueItemLoader.item.loadSource(initialDefaultValue, initialEnableMipmap, initialExportImage);
++ }
++ uniformNameTextInput.text = initialName;
++ descriptionTextArea.text = initialDescription;
++ customValueTextArea.text = initialCustomValue;
++ customValueSwitch.checked = initialUseCustomValue;
++ }
++ }
++
++ CustomDialog {
++ id: removeUniformDialog
++ title: qsTr("Delete Selected Property")
++ x: rootItem.width / 2 - width / 2
++ y: rootItem.height / 2 - height / 2
++ width: 320
++ height: 200
++ modal: true
++ focus: true
++ standardButtons: Dialog.Yes | Dialog.No
++ closePolicy: Popup.NoAutoClose
++
++ Text {
++ width: parent.width
++ text: "Are you sure you want to delete the property <b>" + uniformNameTextInput.text + "</b>?"
++ font.pixelSize: 14
++ color: mainView.foregroundColor2
++ wrapMode: Text.WordWrap
++ }
++ onAccepted: {
++ removeUniform();
++ }
++ }
++
++ ColorDialog {
++ id: colorPickerDialog
++ options: ColorDialog.ShowAlphaChannel
++ onAccepted: {
++ var cItem = valueItemLoader.item;
++ if (cItem)
++ cItem.updateFromPicker(selectedColor);
++ }
++ }
++
++ component ValueLabelComponent : Text {
++ color: mainView.foregroundColor2
++ font.pixelSize: 14
++ anchors.verticalCenter: parent.verticalCenter
++ width: text === "" ? 0 : 50
++ }
++
++ component SingleFloatComponent : Item {
++ id: singleFloatComponent
++ property string name: ""
++ property alias text: textItem.text
++ width: nameItem.width + textItem.width + 10
++ height: 40
++ Text {
++ id: nameItem
++ text: name
++ color: mainView.foregroundColor2
++ font.pixelSize: 14
++ anchors.verticalCenter: parent.verticalCenter
++ }
++ CustomTextField {
++ id: textItem
++ anchors.verticalCenter: parent.verticalCenter
++ anchors.left: nameItem.right
++ anchors.leftMargin: 5
++ width: 50
++ text: "0"
++ }
++ }
++
++ Component {
++ id: boolComponent
++ CheckBox {
++ checked: initialDefaultValue ? Boolean(initialDefaultValue) : false
++ onToggled: {
++ rootItem.defaultValue = checked;
++ }
++ }
++ }
++
++ Component {
++ id: floatComponent
++ Column {
++ spacing: 10
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "default"
++ }
++ SingleFloatComponent {
++ id: defValue
++ name: ""
++ text: initialDefaultValue ? initialDefaultValue.toString() : "0.0"
++ onTextChanged: {
++ rootItem.defaultValue = Number(text);
++ }
++ }
++ }
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "min"
++ }
++ SingleFloatComponent {
++ id: minValue
++ name: ""
++ text: initialMinValue ? initialMinValue.toString() : "0.0"
++ onTextChanged: {
++ rootItem.minValue = Number(text);
++ }
++ }
++ }
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "max"
++ }
++ SingleFloatComponent {
++ id: maxValue
++ name: ""
++ text: initialMaxValue ? initialMaxValue.toString() : "1.0"
++ onTextChanged: {
++ rootItem.maxValue = Number(text);
++ }
++ }
++ }
++ }
++ }
++
++ Component {
++ id: vec2Component
++ Column {
++ function updateDefaultValue() {
++ rootItem.defaultValue = Qt.vector2d(xDefaultValue.text, yDefaultValue.text);
++ }
++ function updateMinValue() {
++ rootItem.minValue = Qt.vector2d(xMinValue.text, yMinValue.text);
++ }
++ function updateMaxValue() {
++ rootItem.maxValue = Qt.vector2d(xMaxValue.text, yMaxValue.text);
++ }
++ spacing: 10
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "default"
++ }
++ SingleFloatComponent {
++ id: xDefaultValue
++ name: "x:"
++ text: initialDefaultValue && initialDefaultValue.x ? roundedNumber(initialDefaultValue.x) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ SingleFloatComponent {
++ id: yDefaultValue
++ name: "y:"
++ text: initialDefaultValue && initialDefaultValue.y ? roundedNumber(initialDefaultValue.y) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ }
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "min"
++ }
++ SingleFloatComponent {
++ id: xMinValue
++ name: "x:"
++ text: initialMinValue && initialMinValue.x ? roundedNumber(initialMinValue.x) : "0.0"
++ onTextChanged: {
++ updateMinValue();
++ }
++ }
++ SingleFloatComponent {
++ id: yMinValue
++ name: "y:"
++ text: initialMinValue && initialMinValue.y ? roundedNumber(initialMinValue.y) : "0.0"
++ onTextChanged: {
++ updateMinValue();
++ }
++ }
++ }
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "max"
++ }
++ SingleFloatComponent {
++ id: xMaxValue
++ name: "x:"
++ text: initialMaxValue && initialMaxValue.x ? roundedNumber(initialMaxValue.x) : "1.0"
++ onTextChanged: {
++ updateMaxValue();
++ }
++ }
++ SingleFloatComponent {
++ id: yMaxValue
++ name: "y:"
++ text: initialMaxValue && initialMaxValue.y ? roundedNumber(initialMaxValue.y) : "1.0"
++ onTextChanged: {
++ updateMaxValue();
++ }
++ }
++ }
++ }
++ }
++
++ Component {
++ id: vec3Component
++ Column {
++ function updateDefaultValue() {
++ rootItem.defaultValue = Qt.vector3d(xDefaultValue.text, yDefaultValue.text, zDefaultValue.text);
++ }
++ function updateMinValue() {
++ rootItem.minValue = Qt.vector3d(xMinValue.text, yMinValue.text, zMinValue.text);
++ }
++ function updateMaxValue() {
++ rootItem.maxValue = Qt.vector3d(xMaxValue.text, yMaxValue.text, zMaxValue.text);
++ }
++ spacing: 10
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "default"
++ }
++ SingleFloatComponent {
++ id: xDefaultValue
++ name: "x:"
++ text: initialDefaultValue && initialDefaultValue.x ? roundedNumber(initialDefaultValue.x) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ SingleFloatComponent {
++ id: yDefaultValue
++ name: "y:"
++ text: initialDefaultValue && initialDefaultValue.y ? roundedNumber(initialDefaultValue.y) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ SingleFloatComponent {
++ id: zDefaultValue
++ name: "z:"
++ text: initialDefaultValue && initialDefaultValue.z ? roundedNumber(initialDefaultValue.z) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ }
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "min"
++ }
++ SingleFloatComponent {
++ id: xMinValue
++ name: "x:"
++ text: initialMinValue && initialMinValue.x ? roundedNumber(initialMinValue.x) : "0.0"
++ onTextChanged: {
++ updateMinValue();
++ }
++ }
++ SingleFloatComponent {
++ id: yMinValue
++ name: "y:"
++ text: initialMinValue && initialMinValue.y ? roundedNumber(initialMinValue.y) : "0.0"
++ onTextChanged: {
++ updateMinValue();
++ }
++ }
++ SingleFloatComponent {
++ id: zMinValue
++ name: "z:"
++ text: initialMinValue && initialMinValue.z ? roundedNumber(initialMinValue.z) : "0.0"
++ onTextChanged: {
++ updateMinValue();
++ }
++ }
++ }
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "max"
++ }
++ SingleFloatComponent {
++ id: xMaxValue
++ name: "x:"
++ text: initialMaxValue && initialMaxValue.x ? roundedNumber(initialMaxValue.x) : "1.0"
++ onTextChanged: {
++ updateMaxValue();
++ }
++ }
++ SingleFloatComponent {
++ id: yMaxValue
++ name: "y:"
++ text: initialMaxValue && initialMaxValue.y ? roundedNumber(initialMaxValue.y) : "1.0"
++ onTextChanged: {
++ updateMaxValue();
++ }
++ }
++ SingleFloatComponent {
++ id: zMaxValue
++ name: "z:"
++ text: initialMaxValue && initialMaxValue.z ? roundedNumber(initialMaxValue.z) : "1.0"
++ onTextChanged: {
++ updateMaxValue();
++ }
++ }
++ }
++ }
++ }
++
++ Component {
++ id: vec4Component
++ Column {
++ function updateDefaultValue() {
++ rootItem.defaultValue = Qt.vector4d(xDefaultValue.text, yDefaultValue.text, zDefaultValue.text, wDefaultValue.text);
++ }
++ function updateMinValue() {
++ rootItem.minValue = Qt.vector4d(xMinValue.text, yMinValue.text, zMinValue.text, wMinValue.text);
++ }
++ function updateMaxValue() {
++ rootItem.maxValue = Qt.vector4d(xMaxValue.text, yMaxValue.text, zMaxValue.text, wMaxValue.text);
++ }
++ spacing: 10
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "default"
++ }
++ SingleFloatComponent {
++ id: xDefaultValue
++ name: "x:"
++ text: initialDefaultValue && initialDefaultValue.x ? roundedNumber(initialDefaultValue.x) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ SingleFloatComponent {
++ id: yDefaultValue
++ name: "y:"
++ text: initialDefaultValue && initialDefaultValue.y ? roundedNumber(initialDefaultValue.y) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ SingleFloatComponent {
++ id: zDefaultValue
++ name: "z:"
++ text: initialDefaultValue && initialDefaultValue.z ? roundedNumber(initialDefaultValue.z) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ SingleFloatComponent {
++ id: wDefaultValue
++ name: "w:"
++ text: initialDefaultValue && initialDefaultValue.w ? roundedNumber(initialDefaultValue.w) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ }
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "min"
++ }
++ SingleFloatComponent {
++ id: xMinValue
++ name: "x:"
++ text: initialMinValue && initialMinValue.x ? roundedNumber(initialMinValue.x) : "0.0"
++ onTextChanged: {
++ updateMinValue();
++ }
++ }
++ SingleFloatComponent {
++ id: yMinValue
++ name: "y:"
++ text: initialMinValue && initialMinValue.y ? roundedNumber(initialMinValue.y) : "0.0"
++ onTextChanged: {
++ updateMinValue();
++ }
++ }
++ SingleFloatComponent {
++ id: zMinValue
++ name: "z:"
++ text: initialMinValue && initialMinValue.z ? roundedNumber(initialMinValue.z) : "0.0"
++ onTextChanged: {
++ updateMinValue();
++ }
++ }
++ SingleFloatComponent {
++ id: wMinValue
++ name: "w:"
++ text: initialMinValue && initialMinValue.w ? roundedNumber(initialMinValue.w) : "0.0"
++ onTextChanged: {
++ updateMinValue();
++ }
++ }
++ }
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "max"
++ }
++ SingleFloatComponent {
++ id: xMaxValue
++ name: "x:"
++ text: initialMaxValue && initialMaxValue.x ? roundedNumber(initialMaxValue.x) : "1.0"
++ onTextChanged: {
++ updateMaxValue();
++ }
++ }
++ SingleFloatComponent {
++ id: yMaxValue
++ name: "y:"
++ text: initialMaxValue && initialMaxValue.y ? roundedNumber(initialMaxValue.y) : "1.0"
++ onTextChanged: {
++ updateMaxValue();
++ }
++ }
++ SingleFloatComponent {
++ id: zMaxValue
++ name: "z:"
++ text: initialMaxValue && initialMaxValue.z ? roundedNumber(initialMaxValue.z) : "1.0"
++ onTextChanged: {
++ updateMaxValue();
++ }
++ }
++ SingleFloatComponent {
++ id: wMaxValue
++ name: "w:"
++ text: initialMaxValue && initialMaxValue.w ? roundedNumber(initialMaxValue.w) : "1.0"
++ onTextChanged: {
++ updateMaxValue();
++ }
++ }
++ }
++ }
++ }
++
++ Component {
++ id: colorComponent
++ Column {
++ function updateDefaultValue() {
++ rootItem.defaultValue = Qt.rgba(xDefaultValue.text, yDefaultValue.text, zDefaultValue.text, wDefaultValue.text);
++ rootItem.minValue = Qt.rgba(0.0, 0.0, 0.0, 0.0);
++ rootItem.maxValue = Qt.rgba(1.0, 1.0, 1.0, 1.0);
++ }
++ function updateFromPicker(newColor) {
++ xDefaultValue.text = (newColor.r).toFixed(3);
++ yDefaultValue.text = (newColor.g).toFixed(3);
++ zDefaultValue.text = (newColor.b).toFixed(3);
++ wDefaultValue.text = (newColor.a).toFixed(3);
++ }
++
++ spacing: 10
++ Row {
++ spacing: rootItem.componentSpacing
++ ValueLabelComponent {
++ text: "default"
++ }
++ SingleFloatComponent {
++ id: xDefaultValue
++ name: "r:"
++ text: initialDefaultValue && initialDefaultValue.r ? roundedNumber(initialDefaultValue.r) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ SingleFloatComponent {
++ id: yDefaultValue
++ name: "g:"
++ text: initialDefaultValue && initialDefaultValue.g ? roundedNumber(initialDefaultValue.g) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ SingleFloatComponent {
++ id: zDefaultValue
++ name: "b:"
++ text: initialDefaultValue && initialDefaultValue.b ? roundedNumber(initialDefaultValue.b) : "0.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ SingleFloatComponent {
++ id: wDefaultValue
++ name: "a:"
++ text: initialDefaultValue && initialDefaultValue.a ? roundedNumber(initialDefaultValue.a) : "1.0"
++ onTextChanged: {
++ updateDefaultValue();
++ }
++ }
++ }
++ Rectangle {
++ width: 100
++ height: 40
++ border.width: 1
++ border.color: foregroundColor2
++ color: rootItem.defaultValue
++ Text {
++ anchors.centerIn: parent
++ text: "PICK"
++ font.pixelSize: 12
++ color: mainView.foregroundColor2
++ style: Text.Outline
++ styleColor: mainView.backgroundColor1
++ }
++ MouseArea {
++ anchors.fill: parent
++ onClicked: {
++ colorPickerDialog.selectedColor = rootItem.defaultValue;
++ colorPickerDialog.open();
++ }
++ }
++ }
++ }
++ }
++
++ Component {
++ id: imageComponent
++ Column {
++ function loadSource(sourceImage, mipmapEnabled, exportImage) {
++ previewImage.source = sourceImage ? sourceImage : "";
++ mipmapCheckBox.checked = mipmapEnabled;
++ exportImageCheckBox.checked = exportImage;
++ }
++ spacing: -10
++ Rectangle {
++ width: 180
++ height: 90
++ border.width: 1
++ color: mainView.backgroundColor2
++ border.color: mainView.foregroundColor1
++ Image {
++ id: previewImage
++ anchors.fill: parent
++ anchors.margins: 1
++ sourceSize: Qt.size(width, height);
++ fillMode: Image.PreserveAspectFit
++ }
++ CustomIconButton {
++ width: 30
++ height: width
++ anchors.left: parent.left
++ anchors.top: parent.top
++ icon: "images/icon_remove_shadow.png"
++ visible: previewImage.source !== ""
++ onClicked: {
++ rootItem.defaultValue = "";
++ previewImage.source = "";
++ }
++ }
++
++ Button {
++ anchors.centerIn: parent
++ text: "Choose Image"
++ onClicked: {
++ if (initialDefaultValue) {
++ textureSourceDialog.currentFolder = effectManager.getDirectory(initialDefaultValue);
++ textureSourceDialog.selectedFile = effectManager.addFileToURL(initialDefaultValue);
++ } else {
++ textureSourceDialog.currentFolder = effectManager.getDefaultImagesDirectory();
++ }
++ textureSourceDialog.open()
++ }
++ }
++ }
++ CheckBox {
++ id: mipmapCheckBox
++ text: "Enable mipmaps"
++ checked: rootItem.initialEnableMipmap
++ onToggled: {
++ rootItem.enableMipmap = checked;
++ if (initialName !== "") {
++ var mipmapPropertyName = effectManager.mipmapPropertyName(initialName);
++ g_propertyData[mipmapPropertyName] = checked;
++ }
++ }
++ }
++ CheckBox {
++ id: exportImageCheckBox
++ text: "Create QML Image element"
++ checked: rootItem.initialExportImage
++ onToggled: {
++ rootItem.exportImage = checked;
++ }
++ }
++ FileDialog {
++ id: textureSourceDialog
++ title: "Open an Image File"
++ nameFilters: [ effectManager.getSupportedImageFormatsFilter() ]
++ onAccepted: {
++ if (textureSourceDialog.selectedFile !== null) {
++ rootItem.defaultValue = textureSourceDialog.selectedFile
++ previewImage.source = textureSourceDialog.selectedFile
++ }
++ }
++ }
++ }
++ }
++
++ Component {
++ id: defineComponent
++ Column {
++ CustomTextField {
++ width: 100
++ text: initialDefaultValue ? initialDefaultValue.toString() : "0"
++ onTextChanged: {
++ rootItem.defaultValue = Number(text);
++ }
++ }
++ }
++ }
++
++ Item {
++ id: propertiesDialogView
++ anchors.top: parent.top
++ anchors.bottom: dialogButtons.top
++ width: parent.width
++ Text {
++ id: dialogTitle
++ anchors.horizontalCenter: parent.horizontalCenter
++ text: isNewProperty ? "Add Property" : "Edit Property"
++ font.pixelSize: 16
++ color: mainView.foregroundColor2
++ }
++ GridLayout {
++ anchors.top: dialogTitle.bottom
++ anchors.topMargin: 10
++ columns: 3
++ Label {
++ text: "Type:"
++ Layout.row: 0
++ Layout.column: 0
++ Layout.preferredWidth: 100
++ color: mainView.foregroundColor2
++ }
++ ComboBox {
++ id: typeComboBox
++ currentIndex: initialType
++ Layout.preferredHeight: 40
++ Layout.row: 0
++ Layout.column: 1
++ model: [
++ "bool",
++ "int",
++ "float",
++ "vec2",
++ "vec3",
++ "vec4",
++ "color",
++ "image",
++ "define"
++ ]
++ onCurrentIndexChanged: {
++ if (currentIndex === 8) {
++ customValueSwitch.checked = false;
++ }
++ }
++ }
++ Label {
++ text: "Name:"
++ Layout.row: 1
++ Layout.column: 0
++ Layout.preferredWidth: 100
++ color: mainView.foregroundColor2
++ }
++ CustomTextField {
++ id: uniformNameTextInput
++ RegularExpressionValidator {
++ id: propertyNameValidator
++ regularExpression: /[a-z_][a-zA-Z0-9_]+/
++ }
++ RegularExpressionValidator {
++ id: defineNameValidator
++ regularExpression: /[a-zA-Z_][a-zA-Z0-9_]+/
++ }
++ // Properties must start with lowercase letter, defines can be ALL_CAPS
++ validator: (typeComboBox.currentIndex === 8) ? defineNameValidator : propertyNameValidator
++ placeholderText: "propertyName"
++ text: initialName ? initialName.toString() : ""
++ onAccepted: rootItem.insertUniform()
++ Layout.row: 1
++ Layout.column: 1
++ Layout.preferredWidth: 300
++ }
++ Label {
++ text: "Custom:"
++ Layout.row: 2
++ Layout.column: 0
++ Layout.alignment: Qt.AlignTop
++ Layout.topMargin: 10
++ Layout.preferredWidth: 100
++ color: mainView.foregroundColor2
++ }
++ CheckBox {
++ id: customValueSwitch
++ Layout.row: 2
++ Layout.column: 1
++ checked: initialUseCustomValue
++ // Defines are already custom
++ enabled: (typeComboBox.currentIndex !== 8)
++ }
++ Label {
++ text: "Value:"
++ Layout.row: 3
++ Layout.column: 0
++ Layout.alignment: Qt.AlignTop
++ Layout.topMargin: 10
++ Layout.preferredWidth: 100
++ color: mainView.foregroundColor2
++ }
++ CustomTextEdit {
++ id: customValueTextArea
++ Layout.row: 3
++ Layout.column: 1
++ Layout.columnSpan: 2
++ Layout.preferredWidth: 380
++ Layout.preferredHeight: 160
++ visible: customValueSwitch.checked
++ text: initialCustomValue ? initialCustomValue.toString() : ""
++ }
++ Loader {
++ id: valueItemLoader
++ Layout.row: 3
++ Layout.column: 1
++ Layout.preferredHeight: 160
++ visible: !customValueTextArea.visible
++ sourceComponent: {
++ if (typeComboBox.currentIndex === 0)
++ return boolComponent;
++ if (typeComboBox.currentIndex === 1 || typeComboBox.currentIndex === 2)
++ return floatComponent;
++ if (typeComboBox.currentIndex === 3)
++ return vec2Component;
++ if (typeComboBox.currentIndex === 4)
++ return vec3Component;
++ if (typeComboBox.currentIndex === 5)
++ return vec4Component;
++ if (typeComboBox.currentIndex === 6)
++ return colorComponent;
++ if (typeComboBox.currentIndex === 7)
++ return imageComponent;
++ if (typeComboBox.currentIndex === 8)
++ return defineComponent;
++ return null;
++ }
++ }
++ Label {
++ text: "Description:"
++ Layout.row: 4
++ Layout.column: 0
++ Layout.alignment: Qt.AlignTop
++ Layout.preferredWidth: 100
++ color: mainView.foregroundColor2
++ }
++ CustomTextEdit {
++ id: descriptionTextArea
++ Layout.row: 4
++ Layout.column: 1
++ Layout.columnSpan: 2
++ Layout.preferredWidth: 380
++ Layout.preferredHeight: 200
++ text: initialDescription ? initialDescription.toString() : ""
++ }
++ }
++ }
++
++ Item {
++ id: dialogButtons
++ anchors.bottom: parent.bottom
++ width: parent.width
++ height: 60
++ Button {
++ id: addButton
++ anchors.right: parent.right
++ anchors.bottom: parent.bottom
++ text: isNewProperty ? "Add" : "OK"
++ enabled: uniformNameTextInput.text !== ""
++ onClicked: {
++ if (isNewProperty) {
++ rootItem.insertUniform();
++ } else {
++ rootItem.updateUniform();
++ }
++ }
++ }
++ Button {
++ id: removeButton
++ anchors.horizontalCenter: parent.horizontalCenter
++ anchors.bottom: parent.bottom
++ text: "Remove"
++ visible: !isNewProperty
++ onClicked: {
++ removeUniformDialog.open();
++ }
++ }
++ Button {
++ id: cancelButton
++ anchors.left: parent.left
++ anchors.bottom: parent.bottom
++ text: "Cancel"
++ onClicked: {
++ if ((typeComboBox.currentIndex === 7) && initialName !== "") {
++ // For image properties return the initial mipmap value
++ var mipmapPropertyName = effectManager.mipmapPropertyName(initialName);
++ g_propertyData[mipmapPropertyName] = initialEnableMipmap;
++ }
++ rootItem.close();
++ }
++ }
++ }
++ }