diff --git a/desktop.jl b/desktop.jl index 7f27065286014f1ffff51dd5e4a1f8b3bcb133df..fd96f76b97c043b6bad596932cc2c31370cebf8f 100755 --- a/desktop.jl +++ b/desktop.jl @@ -1,12 +1,10 @@ #!/usr/bin/env julia -# Start Persefone Desktop +# A very thin wrapper to start Persefone Desktop. +# (This is not included in PersefoneDesktop.jl in order to enable the latter to +# be used as a library/package.) #XXX does this make sense? -#using GLMakie -#using Makie -using QML +using Pkg +Pkg.activate(".") +using PersefoneDesktop -# MUST disable threading in Qt -ENV["QSG_RENDER_LOOP"] = "basic" - -loadqml("src/main.qml") -exec() +launch() diff --git a/run.jl b/run.jl deleted file mode 100755 index fd96f76b97c043b6bad596932cc2c31370cebf8f..0000000000000000000000000000000000000000 --- a/run.jl +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env julia -# A very thin wrapper to start Persefone Desktop. -# (This is not included in PersefoneDesktop.jl in order to enable the latter to -# be used as a library/package.) #XXX does this make sense? - -using Pkg -Pkg.activate(".") -using PersefoneDesktop - -launch() diff --git a/src/config.jl b/src/config.jl new file mode 100644 index 0000000000000000000000000000000000000000..f8d2c111ac25525f49b2ae1bf80c010016eec5f9 --- /dev/null +++ b/src/config.jl @@ -0,0 +1,60 @@ +### PersefoneDesktop - a GUI to the Persefone model of agriculture and ecosystems +### +### This file manages the backend of the setup window. +### + +const userconfigfile = Observable("userconfig.toml") + +const outdir = Observable("persefone_output") +const csvoutput = Observable(false) +const loglevel = Observable("warn") +const processors = Observable(1) +const seed = Observable(2) +const startdateday = Observable(1) +const startdatemonth = Observable(1) +const startdateyear = Observable(2022) +const enddateday = Observable(31) +const enddatemonth = Observable(12) +const enddateyear = Observable(2022) +const region = Observable("Jena") +#const farmmodel = Observable("FieldManager") #XXX not yet implemented +#const targetspecies = Observable() +#const insectmodel = Observable() #TODO not sure how to configure a list? +const cropmodel = Observable("ALMaSS") #XXX alternatives not yet implemented + + +# TODO create config file with fixed options: +# - overwrite = true (?) +# - storedata = true +# - indoutfreq = "daily" +# - popoutfreq = "daily" + + +function writeconfig() + println("Wrote config file.") + #TODO +end + +function configwindow() + #TODO + @qmlfunction splashscreen + @qmlfunction writeconfig + @qmlfunction newsimulation + qmlfile = joinpath(dirname(@__FILE__), "config.qml") + loadqml(qmlfile, + conf = JuliaPropertyMap("userconfigfile" => userconfigfile, + "outdir" => outdir, + "csvoutput" => csvoutput, + "loglevel" => loglevel, + "processors" => processors, + "seed" => seed, + "startdateday" => startdateday, + "startdatemonth" => startdatemonth, + "startdateyear" => startdateyear, + "enddateday" => enddateday, + "enddatemonth" => enddatemonth, + "enddateyear" => enddateyear, + "region" => region, + "cropmodel" => cropmodel)) + exec() +end diff --git a/src/config.qml b/src/config.qml new file mode 100644 index 0000000000000000000000000000000000000000..3acab11631661dfb8eb247571c99dcca9627e749 --- /dev/null +++ b/src/config.qml @@ -0,0 +1,246 @@ +/// PersefoneDesktop - a GUI to the Persefone model of agriculture and ecosystems +/// +/// This file defines the layout of the configuration window. +/// + +import QtQuick +import QtQuick.Window +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs +import org.julialang + +ApplicationWindow { + id: configWindow + title: "Configure simulation" + width: 700 + height: 350 + visible: true + + ColumnLayout { + id: generalSettings + anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: 20 + anchors.topMargin: 20 + spacing: 8 + + Text { + text: "General Settings:" + horizontalAlignment: Text.AlignCenter + font.bold: true + } + + RowLayout { + Label { text: "Configuration file:" } + Label { + text: conf.userconfigfile + font.italic: true + } + Button { + text: "Select..." + onClicked: conffileChooser.open() + } + FileDialog { + id: conffileChooser + defaultSuffix: "toml" + fileMode: FileDialog.SaveFile + nameFilters: ["Configuration files (*.toml)"] + onAccepted: conf.userconfigfile = selectedFile + } + } + + RowLayout { + Label { text: "Output folder:" } + Label { + text: conf.outdir + font.italic: true + } + Button { + text: "Select..." + onClicked: outdirChooser.open() + } + FolderDialog { + id: outdirChooser + selectedFolder: conf.outdir + onAccepted: conf.outdir = selectedFolder + } + } + + //XXX Not all regions have data available! + // (currently, only Jena is fully configured) + RowLayout { + Label { text: "Region:" } + ComboBox { + currentIndex: 3 + model: ["Bodensee", "Eichsfeld", "Hohenlohe", "Jena", + "Oberrhein", "Thüringer Becken"] + onCurrentIndexChanged: conf.region = currentText + } + } + + RowLayout { + Label { text: "Crop model:" } + ComboBox { + currentIndex: 0 + model: ["ALMaSS", "AquaCrop"] + onCurrentIndexChanged: conf.cropmodel = currentText + } + } + + //XXX For which years do I actually have data? + RowLayout { + Label { text: "Start date:" } + SpinBox { + Layout.maximumWidth: 100 + from: 1 + to: 31 + value: conf.startdateday + editable: true + wrap: true + onValueModified: conf.startdateday = value + } + SpinBox { + Layout.maximumWidth: 100 + from: 1 + to: 12 + value: conf.startdatemonth + editable: true + wrap: true + onValueModified: conf.startdatemonth = value + } + SpinBox { + Layout.maximumWidth: 100 + from: 2000 + to: 2050 + value: conf.startdateyear + editable: true + wrap: true + textFromValue: function(value) { return Number(value).toString(); } + onValueModified: conf.startdateyear = value + } + } + + RowLayout { + Label { text: "End date:" } + SpinBox { + Layout.maximumWidth: 100 + from: 1 + to: 31 + value: conf.enddateday + editable: true + wrap: true + onValueModified: conf.enddateday = value + } + SpinBox { + Layout.maximumWidth: 100 + from: 1 + to: 12 + value: conf.enddatemonth + editable: true + wrap: true + onValueModified: conf.enddatemonth = value + } + SpinBox { + Layout.maximumWidth: 100 + from: 2000 + to: 2050 + value: conf.enddateyear + editable: true + wrap: true + textFromValue: function(value) { return Number(value).toString(); } + onValueModified: conf.enddateyear = value + } + } + } + + ColumnLayout { + id: advancedSettings + anchors.top: parent.top + anchors.right: parent.right + anchors.left: generalSettings.right + anchors.rightMargin: 20 + anchors.topMargin: 20 + anchors.leftMargin: 20 + spacing: 8 + + Text { + text: "Advanced Settings:" + horizontalAlignment: Text.AlignCenter + font.bold: true + } + + RowLayout { + Label { text: "Random seed:" } + SpinBox { + from: 0 + to: 2147483647 + value: 2 + editable: true + onValueModified: conf.seed = value + } + } + + RowLayout { + Label { text: "Log level:" } + ComboBox { + currentIndex: 2 + model: ["debug", "info", "warn"] + onCurrentIndexChanged: conf.loglevel = currentText + } + } + + RowLayout { + Label { text: "Processors:" } + SpinBox { + from: 1 + to: 8 + value: conf.processors + editable: true + onValueModified: conf.processors = value + } + } + + CheckBox { + checked: conf.csvoutput + text: "Write CSV output" + onClicked: conf.csvoutput = checked + } + + //TODO add config options for: + // farmmodel + // targetspecies + // insectmodel + + } + + footer: ToolBar { + RowLayout { + anchors.right: parent.right + layoutDirection: Qt.RightToLeft + + Button { + text: "Start new simulation" + onClicked: { + //Julia.splashscreen() //FIXME crashes + Julia.writeconfig() + Julia.newsimulation() + configWindow.close() + } + } + + Button { + text: "Save configuration" + onClicked: { + Julia.writeconfig() + configWindow.close() + } + } + + Button { + text: "Cancel" + onClicked: configWindow.close() + } + } + } +}