From e4416db06fff64863614792d5cf5d4537f46596b Mon Sep 17 00:00:00 2001
From: Olivier Prat <olivier@zvork.fr>
Date: Wed, 28 Mar 2018 16:54:53 -0400
Subject: [PATCH] Added save/file dialog for transition configurations in
 transition editor

---
 libraries/render-utils/src/FadeEffectJobs.cpp |  7 +--
 libraries/render-utils/src/FadeEffectJobs.h   |  4 +-
 .../utilities/render/debugTransition.js       | 48 ++++++++++++++++---
 .../developer/utilities/render/transition.qml | 36 ++++++++++----
 4 files changed, 72 insertions(+), 23 deletions(-)

diff --git a/libraries/render-utils/src/FadeEffectJobs.cpp b/libraries/render-utils/src/FadeEffectJobs.cpp
index a55fb304dd..1e2ea2bc15 100644
--- a/libraries/render-utils/src/FadeEffectJobs.cpp
+++ b/libraries/render-utils/src/FadeEffectJobs.cpp
@@ -340,11 +340,9 @@ QString FadeConfig::eventNames[FADE_CATEGORY_COUNT] = {
     "avatar_change",
 };
 
-void FadeConfig::save() const {
-    // Save will only work if the HIFI_USE_SOURCE_TREE_RESOURCES environment variable is set
+void FadeConfig::save(const QString& configFilePath) const {
     assert(editedCategory < FADE_CATEGORY_COUNT);
     QJsonObject lProperties;
-    const QString configFilePath = PathUtils::resourcesPath() + "config/" + eventNames[editedCategory] + ".json";
     QFile file(configFilePath);
     if (!file.open(QFile::WriteOnly | QFile::Text)) {
         qWarning() << "Fade event configuration file " << configFilePath << " cannot be opened";
@@ -369,8 +367,7 @@ void FadeConfig::save() const {
     }
 }
 
-void FadeConfig::load() {
-    const QString configFilePath = PathUtils::resourcesPath() + "config/" + eventNames[editedCategory] + ".json";
+void FadeConfig::load(const QString& configFilePath) {
     QFile file(configFilePath);
     if (!file.exists()) {
         qWarning() << "Fade event configuration file " << configFilePath << " does not exist";
diff --git a/libraries/render-utils/src/FadeEffectJobs.h b/libraries/render-utils/src/FadeEffectJobs.h
index f1026b6c2e..449995dba5 100644
--- a/libraries/render-utils/src/FadeEffectJobs.h
+++ b/libraries/render-utils/src/FadeEffectJobs.h
@@ -160,8 +160,8 @@ public:
     float manualThreshold{ 0.f };
     bool manualFade{ false };
 
-    Q_INVOKABLE void save() const;
-    Q_INVOKABLE void load();
+    Q_INVOKABLE void save(const QString& filePath) const;
+    Q_INVOKABLE void load(const QString& filePath);
 
     static QString eventNames[FADE_CATEGORY_COUNT];
 
diff --git a/scripts/developer/utilities/render/debugTransition.js b/scripts/developer/utilities/render/debugTransition.js
index cef6e84268..27b04bd32b 100644
--- a/scripts/developer/utilities/render/debugTransition.js
+++ b/scripts/developer/utilities/render/debugTransition.js
@@ -1,5 +1,3 @@
-"use strict";
-
 //
 //  debugTransition.js
 //  developer/utilities/render
@@ -12,12 +10,17 @@
 //
 
 (function() {
+    "use strict";
+
     var TABLET_BUTTON_NAME = "Transition";
     var QMLAPP_URL = Script.resolvePath("./transition.qml");
     var ICON_URL = Script.resolvePath("../../../system/assets/images/transition-i.svg");
     var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/transition-a.svg");
 
-   
+    Script.include([
+        Script.resolvePath("../../../system/libraries/stringHelpers.js"),
+    ]);
+
     var onScreen = false;
 
     function onClicked() {
@@ -106,10 +109,21 @@
 
     Script.update.connect(update);
 
+    function loadConfiguration(fileUrl) {
+        var config = Render.getConfig("RenderMainView.Fade")
+        config.load(fileUrl)
+    }
+
+    function saveConfiguration(fileUrl) {
+        var config = Render.getConfig("RenderMainView.Fade")
+        config.save(fileUrl)
+    }
+
     function fromQml(message) {
-        tokens = message.split(' ')
+        tokens = message.split('*')
         print("Received '"+message+"' from transition.qml")
-        if (tokens[0]=="edit") {
+        command = tokens[0].toLowerCase()
+        if (command=="edit") {
             isEditEnabled = (tokens[1]=="true")
             if (isEditEnabled) {
                 if (gradientSphere==undefined) {
@@ -138,9 +152,28 @@
                 noiseSphere = undefined                
                 gradientSphere = undefined
             }
-        } else if (tokens[0]=="category") {
+        } else if (command=="category") {
             editedCategory = parseInt(tokens[1])
-        }      
+        } else if (command=="save") {
+            var filePath = tokens[1]
+            print("Raw token = "+filePath)
+            if (filePath.startsWith("file:///")) {
+                filePath = filePath.substr(8)
+                print("Saving configuration to "+filePath)
+                saveConfiguration(filePath)
+            } else {
+                print("Configurations can only be saved to local files")
+            }
+        } else if (command=="load") {
+            var filePath = tokens[1]
+            if (filePath.startsWith("file:///")) {
+                filePath = filePath.substr(8)
+                print("Loading configuration from "+filePath)
+                loadConfiguration(filePath)
+            } else {
+                print("Configurations can only be loaded from local files")
+            }
+        }
     }
         
     button.clicked.connect(onClicked);
@@ -172,6 +205,7 @@
         color: COLOR2,
         ignoreRayIntersection: true
     }
+    
     var laser = Pointers.createPointer(PickType.Ray, {
         joint: "Mouse",
         filter: Picks.PICK_ENTITIES,
diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml
index a8737dfa6b..564090e2d6 100644
--- a/scripts/developer/utilities/render/transition.qml
+++ b/scripts/developer/utilities/render/transition.qml
@@ -11,6 +11,7 @@
 import QtQuick 2.7
 import QtQuick.Controls 1.4
 import QtQuick.Layouts 1.3
+import QtQuick.Dialogs 1.0
 
 import "qrc:///qml/styles-uit"
 import "qrc:///qml/controls-uit" as HifiControls
@@ -29,6 +30,24 @@ Rectangle {
     property var config: Render.getConfig("RenderMainView.Fade");
     property var configEdit: Render.getConfig("RenderMainView.FadeEdit");
 
+    FileDialog {
+        id: fileDialog
+        title: "Please choose a file"
+        folder: shortcuts.documents
+        nameFilters: [ "JSON files (*.json)", "All files (*)" ]
+        onAccepted: {
+            root.sendToScript(title.split(" ")[0]+"*"+fileUrl.toString())
+            // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component
+            // by setting the loader source to Null and then recreate it 500ms later
+            paramWidgetLoader.sourceComponent = undefined;
+            postpone.interval = 500
+            postpone.start()
+        }
+        onRejected: {
+        }
+        Component.onCompleted: visible = false
+    }
+
     ColumnLayout {
         spacing: 3
         anchors.left: parent.left
@@ -50,7 +69,7 @@ Rectangle {
                 checked: root.configEdit["editFade"]
                 onCheckedChanged: {
                     root.configEdit["editFade"] = checked;
-                    root.sendToScript("edit "+checked);
+                    root.sendToScript("edit*"+checked);
                 }
             }
             HifiControls.ComboBox {
@@ -72,7 +91,7 @@ Rectangle {
                     paramWidgetLoader.sourceComponent = undefined;
                     postpone.interval = 100
                     postpone.start()
-                    root.sendToScript("category "+currentIndex)
+                    root.sendToScript("category*"+currentIndex)
                 }
             }
         }
@@ -107,19 +126,18 @@ Rectangle {
             id: saveAction
             text: "Save"
             onTriggered: {
-                root.config.save()
+                fileDialog.title = "Save configuration..."
+                fileDialog.selectExisting = false
+                fileDialog.open()
             }
         }
         Action {
             id: loadAction
             text: "Load"
             onTriggered: {
-                root.config.load()
-                // This is a hack to be sure the widgets below properly reflect the change of category: delete the Component
-                // by setting the loader source to Null and then recreate it 500ms later
-                paramWidgetLoader.sourceComponent = undefined;
-                postpone.interval = 500
-                postpone.start()
+                fileDialog.title = "Load configuration..."
+                fileDialog.selectExisting = true
+                fileDialog.open()
             }
         }