Something went wrong on our end
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
GUI.jl 4.66 KiB
### PersefoneDesktop - a GUI to the Persefone model of agriculture and ecosystems
###
### This file links the QML UI designs to the underlying model.
###
## For references, see:
## - https://github.com/barche/QML.jl
## - https://github.com/barche/QmlJuliaExamples
## - https://doc.qt.io/qt-6/qtquick-index.html
#TODO define standard config file for Persefone Desktop
global model = nothing
global landcovermap = nothing
global runsimulation = nothing
global timer = nothing
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")
function newsimulation()
global model, landcovermap
running[] = false
progress[] = 0.0
model = initialise() #TODO configure
landcovermap = load(@param(world.landcovermap))
date[] = model.date
println("Model initialised.")
end
#TODO loadsimulation()
#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
@resumable function createrunfunction()
while running[]
nextstep()
#XXX to reduce interface lag, always only sleep for 0.1s?
sleep(delay[])
@yield 1
end
end
function togglerunning()
global runsimulation, timer
if running[]
running[] = false
QML.stop(timer)
runbuttontext[] = ">>"
runbuttontip[] = "Run"
else
running[] = true
QML.start(timer)
runbuttontext[] = "||"
runbuttontip[] = "Pause"
runsimulation = createrunfunction()
end
end
function render_map(screen)
global model, landcovermap
println("Updating map")
figure = visualisemap(model, date[], landcovermap)
display(screen, figure.scene)
end
function render_plot(screen)
global model
println("Updating plot")
figure = populationtrends(model)
display(screen, figure.scene)
end
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
running[] && runsimulation()
end
function splashscreen()
qmlfile = joinpath(dirname(@__FILE__), "splash.qml")
quick_view = init_qquickview()
set_source(quick_view, QUrlFromLocalFile(qmlfile))
QML.show(quick_view)
#XXX exec_async() is currently still broken, but should be fixed soon
# (https://github.com/JuliaGraphics/QML.jl/issues/174)
@async exec()
end
"""
launch()
The main function that creates the application.
"""
function launch()
global model, timer
#splashscreen()
newsimulation()
@qmlfunction newsimulation
@qmlfunction nextstep
@qmlfunction previousstep
@qmlfunction togglerunning
timer = QTimer()
qmlfile = joinpath(dirname(@__FILE__), "main.qml")
loadqml(qmlfile,
timer = timer,
vars = JuliaPropertyMap("running" => running,
"ticks" => ticks,
"date" => date,
"delay" => delay,
"progress" => progress,
"runbuttontext" => runbuttontext,
"runbuttontip" => runbuttontip),
render_map_callback = @safe_cfunction(render_map, Cvoid, (Any,)),
render_plot_callback = @safe_cfunction(render_plot, Cvoid, (Any,)))
@emit updateMakie()
println("Launched Persefone Desktop.")
exec()
end