diff --git a/ui/output_tab.go b/ui/output_tab.go
index 261b813b440694fe98eec37cbb2d36d602df67bb..e4504f6ee03470eb9080e9cec1a08819c36d6c6f 100644
--- a/ui/output_tab.go
+++ b/ui/output_tab.go
@@ -24,45 +24,32 @@ import (
"fyne.io/fyne/v2/widget"
)
-// A message is sent to the output tab, telling us the current status
+// We have a channel that sends the status to the output tab.
type status uint8
const (
- calculating status = iota
- resultsReady
- errorCalc
+ calculating status = iota // currently running a simulation
+ resultsReady // You should collect the results
+ errorCalc // You should display an error message
)
type workstatus struct {
- fdata, xdata []byte
+ fdata, xdata []byte // the data in a function or X value plot
err error
- status status
-}
-
-// showIniTab is a card to be shown before we have any calculations.
-func showIniTab(cntr *fyne.Container) {
- cntr.Add(widget.NewCard("No results yet", "go back to the input", nil))
+ status status // Tells us what we should do now
}
// If we get a message with an error, display it
func showErrTab(cntr *fyne.Container, err error) {
+ cntr.Objects = nil
cntr.Add(widget.NewCard("ERROR in MC", err.Error(), nil))
}
-// emptyContainer gets rid of any old contents. Could I just say,
-// cntr.Objects = nil ?
-func emptyContainer(cntr *fyne.Container) {
- for _, o := range cntr.Objects {
- cntr.Remove(o)
- }
-}
-
// showCalcTab is shown while calculating. Have to check if the refresh()
// is actually necessary.
func showCalcTab(cntr *fyne.Container) {
- emptyContainer(cntr)
+ cntr.Objects = nil
cntr.Add(widget.NewCard("calculating", "busy", nil))
- cntr.Refresh()
}
// fwrt writes the file. It will be called by the filesave dialog
@@ -115,29 +102,27 @@ func png2image(d []byte, fname string) *canvas.Image {
// showResultsTab show the two plots
func showResultsTab(cntr *fyne.Container, win fyne.Window, fdata, xdata []byte) {
- emptyContainer(cntr)
+ cntr.Objects = nil
fImage := png2image(fdata, "function.png")
xImage := png2image(xdata, "xdata.png")
right := container.NewGridWithRows(2, fImage, xImage)
left := leftbar(win, fdata, xdata)
- box := container.NewHBox(left, right)
+ box := container.NewHBox(left, widget.NewSeparator(), right)
cntr.Add(box)
}
// outputTab is run as a background process. After showing the initial
// screen, it sits and waits on notifications. When it gets one,
// it redraws its tab.
-func outputTab(chn chan workstatus, cntr *fyne.Container, form *widget.Form, win fyne.Window) {
- showIniTab(cntr)
- breaker()
- for s := range chn {
+func outputTab(genParams genParams, cntr *fyne.Container, form *widget.Form) {
+ cntr.Add(widget.NewCard("No results yet", "go back to the input", nil))
+ for s := range genParams.chn {
switch s.status {
case calculating:
showCalcTab(cntr)
case resultsReady:
- showResultsTab(cntr, win, s.fdata, s.xdata)
- breaker()
+ showResultsTab(cntr, genParams.win, s.fdata, s.xdata)
form.Enable()
form.Refresh()
case errorCalc:
diff --git a/ui/param_tab.go b/ui/param_tab.go
index a53c60946ca2b4a953b28d0ff1d8b87983e67803..b513ee81ed4ebed43982f82bfdd6f278d6f412d7 100644
--- a/ui/param_tab.go
+++ b/ui/param_tab.go
@@ -21,6 +21,14 @@ import (
"example.com/ackley_mc/mc_work"
)
+// startrun is what happens when you click on the form's button to start
+// a calculation.
+func startrun(genParams genParams, form *widget.Form, mcPrm *mcwork.McPrm) {
+ form.Disable()
+ go mcWrap(genParams)
+}
+
+
// fslicestrng makes a nice string from a slice of float32's
func fslicestrng(f []float32) string {
if len(f) == 0 {
@@ -33,6 +41,7 @@ func fslicestrng(f []float32) string {
return s
}
+
// str2f32 takes a string and returns a slice of float32's
func s2f32(s string) ([]float32, error) {
y := strings.Split(s, ",")
@@ -62,7 +71,7 @@ func validateXini(s string) error {
// This gets put on the list of things to do from the reload function.
func floatItem(xAddr *float64, label string) (*widget.FormItem, func()) {
bind := binding.BindFloat(xAddr)
- entry := widget.NewEntryWithData(binding.FloatToStringWithFormat(bind, "%10.2f"))
+ entry := widget.NewEntryWithData(binding.FloatToStringWithFormat(bind, "%.2f"))
fitem := widget.NewFormItem(label, entry)
reloadfunc := func() { bind.Reload() }
return fitem, reloadfunc
@@ -72,7 +81,8 @@ func floatItem(xAddr *float64, label string) (*widget.FormItem, func()) {
// It returns the screen and a function to be called to refresh it.
// This is necessary, since there is a button to read parameters from
// a file, which means all the values should be updated.
-func paramBox(mcPrm *mcwork.McPrm, parent fyne.Window, chn chan workstatus) *widget.Form {
+func paramBox(genParams genParams) *widget.Form {
+ mcPrm := genParams.mcPrm
iniTmpItem, iniTmpReload := floatItem(&mcPrm.IniTmp, "initial temperature")
fnlTmpItem, fnlTmpReload := floatItem(&mcPrm.FnlTmp, "final temperature")
xDltaItem, xDltaReload := floatItem(&mcPrm.XDlta, "X delta")
@@ -103,14 +113,14 @@ func paramBox(mcPrm *mcwork.McPrm, parent fyne.Window, chn chan workstatus) *wid
_ = nStepBnd.Reload()
}
- rdfile := func() { rdwork(mcPrm, parent, reloadPTab) }
+ rdfile := func() { rdwork(mcPrm, genParams.win, reloadPTab) }
rdfileBtn := widget.NewButton("get file ", rdfile)
rdFileItem := widget.NewFormItem("read from a file", rdfileBtn)
r := widget.NewForm(
iniTmpItem, fnlTmpItem, xDltaItem, xIniItem, nStepItem, rdFileItem)
r.SubmitText = "start calculation"
- r.OnSubmit = func() { startrun(chn, parent, r, mcPrm) }
+ r.OnSubmit = func() { startrun(genParams, r, mcPrm) }
return r
}
@@ -149,24 +159,18 @@ func rdwork(mcPrm *mcwork.McPrm, parent fyne.Window, reloadPTab func()) {
// mcWrap is run in the background so the interface does not block.
// It runs the Monte Carlo, then when it is finished, sends a message
// down the channel.
-func mcWrap(chn chan workstatus, parent fyne.Window, mcPrm *mcwork.McPrm) {
+func mcWrap(genParams genParams) {
+ chn := genParams.chn
chn <- workstatus{status: calculating}
- if fdata, xdata, err := mcwork.DoRun(mcPrm); err != nil {
- dialog.NewError(err, parent).Show()
+ if fdata, xdata, err := mcwork.DoRun(genParams.mcPrm); err != nil {
+ dialog.NewError(err, genParams.win).Show()
chn <- workstatus{status: errorCalc, err: err}
} else {
chn <- workstatus{fdata: fdata, xdata: xdata, status: resultsReady}
}
}
-// startrun is what happens when you click on the button to start
-// a calculation.
-func startrun(chn chan workstatus, parent fyne.Window, form *widget.Form, mcPrm *mcwork.McPrm) {
- form.Disable()
- go mcWrap(chn, parent, mcPrm)
-}
-
// inputTab sets up the input page.
-func inputTab(mcPrm *mcwork.McPrm, parent fyne.Window, chn chan workstatus) *widget.Form {
- return paramBox(mcPrm, parent, chn)
+func inputTab(genParams genParams) *widget.Form {
+ return paramBox(genParams)
}
diff --git a/ui/ui_run.go b/ui/ui_run.go
index a84062dae566815e9c1a3fd78838cbfc5b4263ff..b041550a95f4bf51f6c5dd3db58f15c75051f6ac 100644
--- a/ui/ui_run.go
+++ b/ui/ui_run.go
@@ -7,6 +7,7 @@
package ui
import (
+ "fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
@@ -14,28 +15,30 @@ import (
"example.com/ackley_mc/mc_work"
)
-func UiDoRun(mcPrm *mcwork.McPrm) error {
+// Convenience struct so we do not have perverse long parameter lists
+type genParams struct{
+ mcPrm *mcwork.McPrm // The MC parameters shared with the main simulation
+ win fyne.Window // Parent window. Needed for all dialog boxes
+ chn chan workstatus // To tell the output tab current status
+}
+// UiDoRun sets up the screen to do a run. It is effectively a big
+// wrapper around the DoRun() function.
+func UiDoRun(mcPrm *mcwork.McPrm) error {
a := app.NewWithID("Monte Carlo")
- w := a.NewWindow("Monte Carlo")
- quitbutton := widget.NewButton("click somewhere in here to exit", a.Quit)
+ win := a.NewWindow("Monte Carlo")
chn := make(chan workstatus)
- // inputTabCallback := func() *widget.Form { return (inputTab(mcPrm, w, chn))}
- inputForm := inputTab(mcPrm, w, chn)
+ var genParams = genParams {mcPrm, win, chn}
+ inputForm := inputTab(genParams)
+ quitbutton := widget.NewButton("click somewhere in here to confirm", a.Quit)
t1 := container.NewTabItem("input tab", inputForm)
cntrOut := container.NewWithoutLayout()
t2 := container.NewTabItem("output tab", cntrOut)
- t3 := container.NewTabItem("quit me", quitbutton)
+ t3 := container.NewTabItem("quit", quitbutton)
appTab := container.NewAppTabs(t1, t2, t3)
- w.SetContent(appTab)
- go outputTab(chn, cntrOut, inputForm, w)
- w.ShowAndRun()
+ win.SetContent(appTab)
+ go outputTab(genParams, cntrOut, inputForm)
+ win.ShowAndRun()
close(chn)
return nil
}
-
-// nothing does nothing
-func nothing(...interface{}) {}
-
-// and breaker does not do much more
-func breaker(...interface{}) {}