/* Copyright (c) 2016 Jesper Öqvist <jesper@llbit.se>
*
* This file is part of Chunky.
*
* Chunky is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chunky is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Chunky. If not, see <http://www.gnu.org/licenses/>.
*/
package se.llbit.chunky.ui.render;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import se.llbit.json.JsonMember;
import se.llbit.json.JsonObject;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* This dialog lets the user export selected scene settings as a JSON string.
*
* <p>The dialog contains check boxes for selecting which parts of the
* scene configuration should be exported. A text field is updated to
* contain the JSON string for exporting the selected settings.
*/
class SettingsExport extends Stage {
static final Set<String> excluded = new HashSet<>();
static final Set<String> defaultIncluded = new HashSet<>();
static final Map<String, Set<String>> groups = new LinkedHashMap<>();
static {
// Set up the hidden configuration variables.
excluded.add("sdfVersion");
excluded.add("name");
// Render status variables should not be exported.
excluded.add("renderTime");
excluded.add("spp");
excluded.add("pathTrace");
groups.put("Camera", set("camera", "cameraPresets"));
groups.put("Canvas size", set("width", "height"));
groups.put("Emitters", set("emittersEnabled", "emitterIntensity"));
groups.put("Entities", set("actors", "renderActors"));
groups.put("Fog", set("fogColor", "fastFog", "fogDensity"));
groups.put("Sky", set("sky", "transparentSky"));
groups.put("Sun", set("sun", "sunEnabled"));
groups.put("Water", set("waterColor", "waterOpacity", "waterVisibility", "useCustomWaterColor", "waterHeight", "stillWater"));
groups.put("Misc", set("sppTarget", "dumpFrequency", "saveSnapshots", "world", "outputMode",
"biomeColorsEnabled", "exposure"));
groups.put("Advanced", set("postprocess", "rayDepth"));
defaultIncluded.add("Fog");
defaultIncluded.add("Water");
defaultIncluded.add("Emitters");
defaultIncluded.add("Sun");
defaultIncluded.add("Sky");
// Exclude the grouped options to avoid duplicates.
for (Set<String> group : groups.values()) {
for (String key : group) {
excluded.add(key);
}
}
}
private static Set<String> set(String... members) {
HashSet<String> set = new HashSet<>();
if (members != null) {
Collections.addAll(set, members);
}
return set;
}
private final JsonObject json;
private Map<String, CheckBox> checkMap = new HashMap<>();
private TextField jsonField = new TextField("{}");
/**
* @param json the complete scene settings JSON
*/
SettingsExport(JsonObject json) {
this.json = json;
ScrollPane scrollPane = new ScrollPane();
VBox vBox = new VBox();
vBox.setPadding(new Insets(10));
vBox.setSpacing(10);
vBox.getChildren().add(new Label("Settings to export:"));
for (Map.Entry<String, Set<String>> group : groups.entrySet()) {
CheckBox checkBox = new CheckBox(group.getKey());
checkBox.setSelected(defaultIncluded.contains(group.getKey()));
checkBox.setOnAction(event -> update());
vBox.getChildren().add(checkBox);
for (String setting : group.getValue()) {
checkMap.put(setting, checkBox);
}
}
for (JsonMember setting : json.object()) {
if (!excluded.contains(setting.getName())) {
// TODO build a hierarchical checkbox system for complex settings.
CheckBox checkBox = new CheckBox(setting.getName());
checkBox.setSelected(defaultIncluded.contains(setting.getName()));
checkBox.setOnAction(event -> update());
vBox.getChildren().add(checkBox);
checkMap.put(setting.getName(), checkBox);
}
}
HBox exportBox = new HBox();
exportBox.setAlignment(Pos.BASELINE_LEFT);
exportBox.setSpacing(10);
exportBox.getChildren().add(new Label("Settings JSON:"));
exportBox.getChildren().add(jsonField);
vBox.getChildren().add(exportBox);
HBox buttonBox = new HBox();
buttonBox.setAlignment(Pos.BOTTOM_RIGHT);
Button doneButton = new Button("Done");
doneButton.setOnAction(event -> hide());
buttonBox.getChildren().add(doneButton);
vBox.getChildren().add(buttonBox);
scrollPane.setContent(vBox);
setScene(new Scene(scrollPane));
setTitle("Settings Export");
getIcons().add(new Image(getClass().getResourceAsStream("/chunky-icon.png")));
addEventFilter(KeyEvent.KEY_PRESSED, e -> {
if (e.getCode() == KeyCode.ESCAPE) {
e.consume();
hide();
}
});
update();
jsonField.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
Platform.runLater(() -> jsonField.selectAll());
}
});
setOnShowing(event -> {
Platform.runLater(() -> jsonField.requestFocus());
});
}
private void update() {
JsonObject result = new JsonObject();
for (JsonMember setting : json.object()) {
CheckBox checkBox = checkMap.get(setting.name);
if (checkBox != null && checkBox.isSelected()) {
result.add(setting.copy());
}
}
jsonField.setText(result.toCompactString());
}
}