diff --git a/src/GUI.jl b/src/GUI.jl
index f216a8f5f5de9c9e9c684bc206f56b1cb4132ac9..60356902b0f016c4b95403b5a73f25406b0c657d 100644
--- a/src/GUI.jl
+++ b/src/GUI.jl
@@ -3,42 +3,6 @@
### This file links the QML UI designs to the underlying model.
###
-global model = nothing
-global landcovermap = nothing
-global runsimulation = nothing
-global timer = nothing
-
-const configfile = Observable("guiparams.toml")
-const launching = Observable(false)
-const running = Observable(false)
-const ticks = Observable(0)
-const date = Observable(today())
-const progress = Observable(0.0)
-const delay = Observable(0.5)
-const runbuttontext = Observable(">>")
-const runbuttontip = Observable("Run")
-const mapimage = Observable(Figure().scene)
-
-global guiproperties =
- ["running" => running,
- "ticks" => ticks,
- "date" => date,
- "delay" => delay,
- "progress" => progress,
- "runbuttontext" => runbuttontext,
- "runbuttontip" => runbuttontip]
-
-function newsimulation()
- global model, landcovermap
- launching[] = true # trigger the launch screen
- running[] = false
- progress[] = 0.0
- model = initialise(configfile[])
- landcovermap = rotr90(load(@param(world.landcovermap)))
- date[] = model.date
- launching[] = false
- println("Model initialised.")
-end
function loadsimulation(filename)
global model
@@ -73,59 +37,6 @@ end
#TODO saveoutput()
-function nextstep()
- global model
- if date[] >= @param(core.enddate)
- running[] = false
- runbuttontext[] = ">>"
- runbuttontip[] = "Run"
- return
- elseif date[] < model.date
- # If we've "scrolled back" in time, step forward again without
- # having to resimulate (see `previousstep()`)
- date[] += Day(1)
- else
- # If we're already displaying the newest model update, we need to
- # keep simulating
- stepsimulation!(model)
- date[] = model.date
- end
- progress[] = (date[]-@param(core.startdate)) /
- (@param(core.enddate)-@param(core.startdate))
- @emit updateMakie()
- println("Updated model: $(date[]-Day(1))")
-end
-
-function previousstep()
- # Since we store all model output in a dataframe, we can simply
- # "scroll back" in time and visualise the state of the model at
- # a previous date
- global model
- date[] <= @param(core.startdate) && return
- date[] -= Day(1)
- progress[] = (date[]-@param(core.startdate)) /
- (@param(core.enddate)-@param(core.startdate))
- @emit updateMakie()
- println("Backtracked model: $(date[]-Day(1))")
-end
-
-#XXX This could also be done with Channels rather than ResumableFunctions,
-# which would save us one dependency (Channels are inbuilt). However, the
-# ResumableFunctions version seemed to work more smoothly.
-@resumable function createrunfunction()
- i = round(delay[]*10)
- while running[]
- i -= 1
- if i <= 0
- nextstep()
- i = round(delay[]*10)
- end
- # to reduce interface lag, always only sleep for 0.1s
- sleep(0.1)
- @yield 1
- end
-end
-
function togglerunning()
global runsimulation, timer
if running[]
@@ -137,7 +48,6 @@ function togglerunning()
running[] = true
runbuttontext[] = "||"
runbuttontip[] = "Pause"
- runsimulation = createrunfunction()
QML.start(timer)
end
end
@@ -195,16 +105,6 @@ on(delay) do d
println("Delay is now $(round(d, digits=1)) seconds.") #XXX DEBUG
end
-on(running) do r
- ticks = 0 #prevent overflows
- r ? println("Simulation started.") : println("Simulation stopped.") #XXX DEBUG
-end
-
-on(ticks) do t
- #launching[] && #FIXME
- running[] && runsimulation()
-end
-
on(launching) do l
if l
@emit showSplash()
@@ -246,7 +146,7 @@ function launch()
qmlfile = joinpath(dirname(@__FILE__), "main.qml")
loadqml(qmlfile,
timer = timer,
- vars = JuliaPropertyMap(guiproperties...,configproperties...),
+ vars = JuliaPropertyMap(guiproperties...),
render_map_callback = @safe_cfunction(render_map, Cvoid, (Any,)),
render_plot_callback = @safe_cfunction(render_plot, Cvoid, (Any,)))
launching[] = true
diff --git a/src/PersefoneDesktop.jl b/src/PersefoneDesktop.jl
index f8c58990f49c225fb90e19096bbc097affe917fc..75d8489deb5a027d78aa244c85aa25c8fda9fe97 100644
--- a/src/PersefoneDesktop.jl
+++ b/src/PersefoneDesktop.jl
@@ -26,6 +26,8 @@ using
DataFramesMeta,
ResumableFunctions
+include("variables.jl")
+include("logic.jl")
include("config.jl")
include("GUI.jl")
@@ -33,7 +35,6 @@ precompile(launch, ())
precompile(render_map, (Any,)) #what's the input type?
export
- configwindow,
launch
end
diff --git a/src/config.jl b/src/config.jl
index 89c5b21e7cfa49a2ae963832d7e1bb4f627a93a1..33c17a73aed9c967526308cf47cebceb27521cdc 100644
--- a/src/config.jl
+++ b/src/config.jl
@@ -3,41 +3,6 @@
### 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") #XXX alternatives not yet implemented
-#const farmmodel = Observable("FieldManager") #XXX not yet implemented
-#const targetspecies = Observable() #TODO not sure how to configure a list?
-#const insectmodel = Observable() #TODO not sure how to configure a list?
-const cropmodel = Observable("ALMaSS") #XXX alternatives not yet implemented
-
-global configproperties =
- ["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]
-
function writeconfig()
println("Wrote config file.")
diff --git a/src/logic.jl b/src/logic.jl
new file mode 100644
index 0000000000000000000000000000000000000000..3ae716528f7e7e9019ecb1953cb79ddf73ba11bf
--- /dev/null
+++ b/src/logic.jl
@@ -0,0 +1,82 @@
+### PersefoneDesktop - a GUI to the Persefone model of agriculture and ecosystems
+###
+### This file manages the model initialisation and run functions.
+###
+
+
+function newsimulation()
+ global model, landcovermap
+ launching[] = true # trigger the launch screen
+ running[] = false
+ progress[] = 0.0
+ model = initialise(configfile[])
+ landcovermap = rotr90(load(@param(world.landcovermap)))
+ date[] = model.date
+ launching[] = false
+ println("Model initialised.")
+end
+
+function nextstep()
+ global model
+ if date[] >= @param(core.enddate)
+ running[] = false
+ runbuttontext[] = ">>"
+ runbuttontip[] = "Run"
+ return
+ elseif date[] < model.date
+ # If we've "scrolled back" in time, step forward again without
+ # having to resimulate (see `previousstep()`)
+ date[] += Day(1)
+ else
+ # If we're already displaying the newest model update, we need to
+ # keep simulating
+ stepsimulation!(model)
+ date[] = model.date
+ end
+ progress[] = (date[]-@param(core.startdate)) /
+ (@param(core.enddate)-@param(core.startdate))
+ @emit updateMakie()
+ println("Updated model: $(date[]-Day(1))")
+end
+
+function previousstep()
+ # Since we store all model output in a dataframe, we can simply
+ # "scroll back" in time and visualise the state of the model at
+ # a previous date
+ global model
+ date[] <= @param(core.startdate) && return
+ date[] -= Day(1)
+ progress[] = (date[]-@param(core.startdate)) /
+ (@param(core.enddate)-@param(core.startdate))
+ @emit updateMakie()
+ println("Backtracked model: $(date[]-Day(1))")
+end
+
+#XXX This could also be done with Channels rather than ResumableFunctions,
+# which would save us one dependency (Channels are inbuilt). However, the
+# ResumableFunctions version seemed to work more smoothly.
+@resumable function createrunfunction()
+ i = round(delay[]*10)
+ while running[]
+ i -= 1
+ if i <= 0
+ nextstep()
+ i = round(delay[]*10)
+ end
+ # to reduce interface lag, always only sleep for 0.1s
+ sleep(0.1)
+ @yield 1
+ end
+end
+
+
+on(running) do r
+ ticks = 0 #prevent overflows
+ runsimulation = createrunfunction()
+ r ? println("Simulation started.") : println("Simulation stopped.") #XXX DEBUG
+end
+
+on(ticks) do t
+ #launching[] && #FIXME
+ running[] && runsimulation()
+end
diff --git a/src/mockup.ui b/src/mockup.ui
deleted file mode 100644
index 19c710a6771b047d65cba91a8ed56f49252e3404..0000000000000000000000000000000000000000
--- a/src/mockup.ui
+++ /dev/null
@@ -1,189 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>1067</width>
- <height>614</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Persefone Desktop</string>
- </property>
- <property name="windowIcon">
- <iconset>
- <normaloff>../eacf50ed/favicon.png</normaloff>../eacf50ed/favicon.png</iconset>
- </property>
- <property name="toolTipDuration">
- <number>-1</number>
- </property>
- <widget class="QWidget" name="centralwidget">
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QGraphicsView" name="graphicsView"/>
- </item>
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_4">
- <property name="leftMargin">
- <number>5</number>
- </property>
- <item>
- <widget class="QCalendarWidget" name="calendarWidget"/>
- </item>
- <item>
- <widget class="QGraphicsView" name="graphicsView_2"/>
- </item>
- </layout>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QPushButton" name="pushButton_3">
- <property name="toolTip">
- <string>Pause</string>
- </property>
- <property name="text">
- <string>||</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="pushButton">
- <property name="toolTip">
- <string>Step</string>
- </property>
- <property name="text">
- <string>></string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="pushButton_2">
- <property name="toolTip">
- <string>Run</string>
- </property>
- <property name="text">
- <string>>></string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QProgressBar" name="progressBar">
- <property name="value">
- <number>24</number>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSlider" name="horizontalSlider">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>200</width>
- <height>0</height>
- </size>
- </property>
- <property name="toolTip">
- <string>Delay between updates</string>
- </property>
- <property name="maximum">
- <number>10</number>
- </property>
- <property name="value">
- <number>5</number>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="tickPosition">
- <enum>QSlider::TicksBelow</enum>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <widget class="QMenuBar" name="menubar">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>1067</width>
- <height>25</height>
- </rect>
- </property>
- <widget class="QMenu" name="menu_Menu">
- <property name="title">
- <string>&Menu</string>
- </property>
- <addaction name="separator"/>
- <addaction name="action_New_run"/>
- <addaction name="actionLoad_saved_state"/>
- <addaction name="actionSave_current_state"/>
- <addaction name="separator"/>
- <addaction name="action_Quit"/>
- </widget>
- <widget class="QMenu" name="menu_Help">
- <property name="title">
- <string>&Help</string>
- </property>
- <addaction name="actionHelp"/>
- <addaction name="actionWebsite"/>
- <addaction name="actionAbout"/>
- </widget>
- <addaction name="menu_Menu"/>
- <addaction name="menu_Help"/>
- </widget>
- <widget class="QStatusBar" name="statusbar"/>
- <action name="actionHelp">
- <property name="text">
- <string>Documentation</string>
- </property>
- </action>
- <action name="actionAbout">
- <property name="text">
- <string>About</string>
- </property>
- </action>
- <action name="action_New_run">
- <property name="text">
- <string>&New run</string>
- </property>
- </action>
- <action name="action_Quit">
- <property name="text">
- <string>&Quit</string>
- </property>
- </action>
- <action name="actionSave_current_state">
- <property name="text">
- <string>&Save current state</string>
- </property>
- </action>
- <action name="actionLoad_saved_state">
- <property name="text">
- <string>&Load saved state</string>
- </property>
- </action>
- <action name="actionWebsite">
- <property name="text">
- <string>Website</string>
- </property>
- </action>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/splash.qml b/src/splash.qml
deleted file mode 100644
index 4108ee5e74f6eacbdab6ed27904696e44f65e483..0000000000000000000000000000000000000000
--- a/src/splash.qml
+++ /dev/null
@@ -1,34 +0,0 @@
-/// PersefoneDesktop - a GUI to the Persefone model of agriculture and ecosystems
-///
-/// This file creates the splash screen. Load it using a QQuickView.
-///
-
-import QtQuick
-import QtQuick.Controls
-import org.julialang
-
-Popup {
- id: splashPopupExt
- parent: Overlay.overlay
-
- width: 600
- height: 250
-
- x: Math.round((parent.width - width) / 2)
- y: Math.round((parent.height - height) / 2)
-
- Rectangle {
- anchors.fill: parent
-
- Image {
- source: "persefonejl_logo_v3_splash.png"
- fillMode: Image.Stretch
- }
- Timer {
- // Show the splash screen while the model object is initialised
- //XXX is 15s a good time here?
- interval: 15000; running: true; repeat: false
- onTriggered: parent.Window.window.close()
- }
- }
-}
diff --git a/src/variables.jl b/src/variables.jl
new file mode 100644
index 0000000000000000000000000000000000000000..b2a6b85de9cb40e50a9964d743c2853ee3c50d55
--- /dev/null
+++ b/src/variables.jl
@@ -0,0 +1,70 @@
+### PersefoneDesktop - a GUI to the Persefone model of agriculture and ecosystems
+###
+### This file contains all globals and Observables.
+###
+
+
+## GUI parameters
+
+global model = nothing
+global landcovermap = nothing
+global runsimulation = nothing
+global timer = nothing
+
+const configfile = Observable("guiparams.toml")
+const launching = Observable(false)
+const running = Observable(false)
+const ticks = Observable(0)
+const date = Observable(today())
+const progress = Observable(0.0)
+const delay = Observable(0.5)
+const runbuttontext = Observable(">>")
+const runbuttontip = Observable("Run")
+const mapimage = Observable(Figure().scene)
+
+
+## configuration parameters
+
+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") #XXX alternatives not yet implemented
+#const farmmodel = Observable("FieldManager") #XXX not yet implemented
+#const targetspecies = Observable() #TODO not sure how to configure a list?
+#const insectmodel = Observable() #TODO not sure how to configure a list?
+const cropmodel = Observable("ALMaSS") #XXX alternatives not yet implemented
+
+
+## the property list passed to QML
+
+global guiproperties =
+ ["running" => running,
+ "ticks" => ticks,
+ "date" => date,
+ "delay" => delay,
+ "progress" => progress,
+ "runbuttontext" => runbuttontext,
+ "runbuttontip" => runbuttontip,
+ "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]