From 2ecb69d0282b943b3a2b5390ba378beb2a77d77e Mon Sep 17 00:00:00 2001 From: "Andrew E. Torda" <torda@zbh.uni-hamburg.de> Date: Sat, 19 Feb 2022 17:36:24 +0100 Subject: [PATCH] Tidying. --- ui/output_tab.go | 43 ++++++++++++++----------------------------- ui/param_tab.go | 36 ++++++++++++++++++++---------------- ui/ui_run.go | 33 ++++++++++++++++++--------------- 3 files changed, 52 insertions(+), 60 deletions(-) diff --git a/ui/output_tab.go b/ui/output_tab.go index 261b813..e4504f6 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 a53c609..b513ee8 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 a84062d..b041550 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{}) {} -- GitLab