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
++ import QtCore
++
++ Window {
++ id: rootItem
++
++ readonly property real baseMargin: 20
++
++ title: qsTr("Preferences")
++ width: 660
++ height: 620
++ minimumWidth: 400
++ minimumHeight: 400
++ color: mainView.backgroundColor1
++ modality: Qt.ApplicationModal
++ flags: Qt.Dialog
++
++ function addPreviewSourceImage() {
++ sourceImagesFileDialog.open();
++ }
++
++ FileDialog {
++ id: sourceImagesFileDialog
++ currentFolder: effectManager.getDefaultImagesDirectory()
++ onAccepted: {
++ if (selectedFile) {
++ effectManager.settings.addSourceImage(selectedFile);
++ mainView.outputView.effectPreview.selectLastPreviewSource();
++ }
++ }
++ }
++
++ FileDialog {
++ id: codeFontFileDialog
++ nameFilters: ["TrueType font (*.ttf)"]
++ currentFolder: StandardPaths.writableLocation(StandardPaths.FontsLocation)
++ onAccepted: {
++ if (selectedFile) {
++ effectManager.settings.setCodeFontFile(selectedFile);
++ }
++ }
++ }
++
++ FolderDialog {
++ id: customNodePathDialog
++ onAccepted: {
++ if (currentFolder) {
++ let added = effectManager.settings.addCustomNodesPath(currentFolder.toString());
++ if (added)
++ effectManager.refreshAddNodesList();
++ }
++ }
++ }
++
++ ScrollView {
++ id: scrollView
++ anchors.left: parent.left
++ anchors.right: parent.right
++ anchors.top: parent.top
++ anchors.bottom: footer.top
++ contentWidth: mainContent.implicitWidth
++ contentHeight: mainContent.implicitHeight + 2 * baseMargin
++
++ Column {
++ id: mainContent
++ width: rootItem.width - 2 * baseMargin
++ x: baseMargin
++ y: baseMargin
++
++ Item {
++ id: sourceImagesToolbar
++ width: parent.width
++ height: 40
++ Text {
++ anchors.verticalCenter: parent.verticalCenter
++ color: mainView.foregroundColor2
++ font.pixelSize: 14
++ font.bold: true
++ text: "Source Images"
++ }
++ Button {
++ height: parent.height - 4
++ anchors.verticalCenter: parent.verticalCenter
++ anchors.right: addSourceImageButton.left
++ anchors.rightMargin: 5
++ text: qsTr("Refresh");
++ onClicked: {
++ effectManager.settings.refreshSourceImagesModel();
++ }
++ }
++ Button {
++ id: addSourceImageButton
++ height: parent.height - 4
++ anchors.verticalCenter: parent.verticalCenter
++ anchors.right: parent.right
++ text: qsTr("Add");
++ onClicked: {
++ sourceImagesFileDialog.open();
++ }
++ }
++ }
++
++ Rectangle {
++ id: sourceImagesTable
++ width: parent.width
++ height: 120
++ color: mainView.backgroundColor2
++ border.color: mainView.foregroundColor1
++ border.width: 1
++ ListView {
++ id: sourceImagesList
++ anchors.fill: parent
++ clip: true
++ ScrollBar.vertical: ScrollBar {
++ id: scrollBar
++ policy: ScrollBar.AlwaysOn
++ }
++ model: effectManager.settings.sourceImagesModel
++ delegate: Item {
++ width: sourceImagesList.width
++ height: 30
++ Row {
++ id: delegateRow
++ x: 10
++ width: parent.width - x * 2
++ height: parent.height
++ spacing: 10
++ Rectangle {
++ id: sourceImageItem
++ y: 4
++ width: 100
++ height: parent.height - 8
++ border.width: 1
++ border.color: mainView.foregroundColor1
++ color: mainView.backgroundColor1
++ Image {
++ anchors.fill: parent
++ anchors.margins: 1
++ fillMode: Image.PreserveAspectCrop
++ source: model.file
++ mipmap: true
++ }
++ }
++ Text {
++ anchors.verticalCenter: parent.verticalCenter
++ width: parent.width - scrollBar.width - sourceImageItem.width - sizeItem.width - removeButton.width - delegateRow.spacing * 3
++ text: model.file
++ color: mainView.foregroundColor2
++ elide: Text.ElideLeft
++ }
++ Text {
++ id: sizeItem
++ anchors.verticalCenter: parent.verticalCenter
++ text: "(" + model.width + " x " + model.height + ")"
++ color: mainView.foregroundColor2
++ elide: Text.ElideLeft
++ }
++ CustomIconButton {
++ id: removeButton
++ anchors.verticalCenter: parent.verticalCenter
++ height: parent.height * 0.6
++ width: height
++ icon: "images/icon_remove_shadow.png"
++ description: "Remove"
++ enabled: model.canRemove
++ onClicked: {
++ effectManager.settings.removeSourceImage(model.index);
++ }
++ }
++ }
++ }
++ }
++ }
++ Item {
++ width: 1
++ height: 20
++ }
++ Item {
++ id: customNodesToolbar
++ width: parent.width
++ height: 40
++ Text {
++ anchors.verticalCenter: parent.verticalCenter
++ color: mainView.foregroundColor2
++ font.pixelSize: 14
++ font.bold: true
++ text: "Custom Nodes"
++ }
++ Button {
++ id: addCustomNodesPathButton
++ height: parent.height - 4
++ anchors.verticalCenter: parent.verticalCenter
++ anchors.right: parent.right
++ text: qsTr("Add");
++ onClicked: {
++ customNodePathDialog.open();
++ }
++ }
++ }
++ Rectangle {
++ id: customNodesTable
++ width: parent.width
++ height: 60
++ color: mainView.backgroundColor2
++ border.color: mainView.foregroundColor1
++ border.width: 1
++ ListView {
++ id: customNodesList
++ anchors.fill: parent
++ clip: true
++ ScrollBar.vertical: ScrollBar {
++ id: nodesListScrollBar
++ policy: ScrollBar.AlwaysOn
++ }
++ model: effectManager.settings.customNodesModel
++ delegate: Item {
++ width: customNodesList.width
++ height: 30
++ Row {
++ id: customNodesDelegateRow
++ x: 10
++ width: parent.width - x * 2
++ height: parent.height
++ spacing: 10
++ Text {
++ anchors.verticalCenter: parent.verticalCenter
++ width: parent.width - nodesListScrollBar.width - removeNodePathButton.width - customNodesDelegateRow.spacing
++ text: model.path
++ color: mainView.foregroundColor2
++ elide: Text.ElideLeft
++ }
++ CustomIconButton {
++ id: removeNodePathButton
++ anchors.verticalCenter: parent.verticalCenter
++ height: parent.height * 0.6
++ width: height
++ icon: "images/icon_remove_shadow.png"
++ description: "Remove"
++ onClicked: {
++ effectManager.settings.removeCustomNodesPath(model.index);
++ }
++ }
++ }
++ }
++ }
++ }
++ Item {
++ width: 1
++ height: 20
++ }
++ Row {
++ height: 40
++ spacing: 10
++ Text {
++ anchors.verticalCenter: parent.verticalCenter
++ color: mainView.foregroundColor2
++ font.pixelSize: 14
++ font.bold: true
++ text: "Recent Projects menu"
++ }
++ Button {
++ height: parent.height - 4
++ anchors.verticalCenter: parent.verticalCenter
++ text: qsTr("Clear");
++ onClicked: {
++ effectManager.settings.clearRecentProjectsModel();
++ }
++ }
++ }
++ Item {
++ width: 1
++ height: 20
++ }
++ Column {
++ width: parent.width
++ CheckBox {
++ text: "Enable legacy GLSL versions"
++ checked: effectManager.settings.useLegacyShaders
++ onToggled: {
++ effectManager.settings.useLegacyShaders = checked;
++ }
++ }
++ Text {
++ width: parent.width
++ color: mainView.foregroundColor2
++ font.pixelSize: 11
++ wrapMode: Text.WordWrap
++ text: "This will include also OpenGL 2.1 and OpenGL ES 2.0 versions into baked shaders. Note: Some effect nodes do not work when the legacy mode is enabled."
++ }
++ }
++ Item {
++ width: 1
++ height: 20
++ }
++ RowLayout {
++ id: fontSelection
++ width: parent.width
++ height: 40
++ Text {
++ color: mainView.foregroundColor2
++ font.pixelSize: 14
++ font.bold: true
++ text: "Source Font:"
++ }
++ Text {
++ Layout.fillWidth: true
++ elide: Text.ElideMiddle
++ text: effectManager.settings.codeFontFile
++ font.pixelSize: 14
++ font.italic: true
++ color: mainView.foregroundColor2
++ }
++ Button {
++ Layout.preferredHeight: 40
++ text: qsTr("Select");
++ onClicked: {
++ codeFontFileDialog.open();
++ }
++ }
++ ComboBox {
++ id: fontSizeSelector
++ Layout.preferredWidth: 80
++ Layout.preferredHeight: 40
++ model: [6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72]
++ onActivated: {
++ effectManager.settings.setCodeFontSize(currentValue);
++ }
++ Component.onCompleted: {
++ currentIndex = indexOfValue(effectManager.settings.codeFontSize);
++ }
++ Connections {
++ target: effectManager.settings
++ function onCodeFontSizeChanged() {
++ fontSizeSelector.currentIndex = fontSizeSelector.indexOfValue(effectManager.settings.codeFontSize);
++ }
++ }
++ }
++ CustomIconButton {
++ height: 20
++ width: height
++ icon: "images/icon_reset.png"
++ onClicked: {
++ effectManager.settings.resetCodeFont();
++ }
++ }
++ }
++ }
++ }
++
++ DialogButtonBox {
++ id: footer
++ anchors.bottom: parent.bottom
++ width: parent.width
++ standardButtons: DialogButtonBox.Close
++ onRejected: {
++ rootItem.close();
++ }
++ }
++ }