diff --git a/Makefile b/Makefile
index 923682cd392cc70d52d96b5f2a968c17f37fb57d..6268a46a23f8def201413c6bb6e8b9bc5e66d435 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,10 @@
 all:
 	go build ./...
 
+test:
+	go test ./...
+	go test -tags no_gfx ./...
+
 clean:
 	go clean
 	rm -rf */*_delme.*
diff --git a/go.sum b/go.sum
index 95dec1be5bb6e11aba3379fbf019c64f7f486701..a90edb9dd2eaed553195e95de6463f6e301ba775 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,3 @@
-fyne.io/fyne v1.4.3 h1:356CnXCiYrrfaLGsB7qLK3c6ktzyh8WR05v/2RBu51I=
-fyne.io/fyne v1.4.3/go.mod h1:8kiPBNSDmuplxs9WnKCkaWYqbcXFy0DeAzwa6PBO9Z8=
 fyne.io/fyne/v2 v2.1.2 h1:avp9CvLAUdvE7fDMtH1tVKyjxEWHWcpow6aI6L7Kvvw=
 fyne.io/fyne/v2 v2.1.2/go.mod h1:p+E/Dh+wPW8JwR2DVcsZ9iXgR9ZKde80+Y+40Is54AQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -14,15 +12,11 @@ github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8
 github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8=
 github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/fyne-io/mobile v0.1.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY=
-github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
 github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f h1:s0O46d8fPwk9kU4k1jj76wBquMVETx7uveQD9MCIQoU=
 github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f/go.mod h1:wjpnOv6ONl2SuJSxqCPVaPZibGFdSci9HFocT9qtVYM=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be h1:Z28GdQBfKOL8tNHjvaDn3wHDO7AzTRkmAXvHvnopp98=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=
@@ -32,10 +26,11 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw
 github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
 github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng=
 github.com/lucor/goinfo v0.0.0-20210802170112-c078a2b0f08b/go.mod h1:PRq09yoB+Q2OJReAmwzKivcYyremnibWGbK7WfftHzc=
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -56,7 +51,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I=
 github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
-github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.3.8 h1:Nw158Q8QN+CPgTmVRByhVwapp8Mm1e2blinhmx4wx5E=
 github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -64,27 +58,20 @@ gitlab.rrz.uni-hamburg.de/Bae5157/axticks v0.0.0-20220120103412-d663ebb46145 h1:
 gitlab.rrz.uni-hamburg.de/Bae5157/axticks v0.0.0-20220120103412-d663ebb46145/go.mod h1:5CNHyqeidRypmIVTnQksGqnmP56Oshw1Zv1nlUezrpQ=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
 golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -92,19 +79,16 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/main_gfx.go b/main_gfx.go
new file mode 100644
index 0000000000000000000000000000000000000000..db7a65b050465814e25d4765b7a163bc0f76b9f0
--- /dev/null
+++ b/main_gfx.go
@@ -0,0 +1,30 @@
+// Aug 2021
+// +build !no_gfx
+
+// Ackley_mc is for playing with Monte Carlo or simulated annealing on the
+// ackley function in N dimensions.
+//
+//    ackley_mc input_file
+// where input_file has a list of keywords and values.
+
+package main
+
+import (
+	"fmt"
+	"os"
+
+	"example.com/ackley_mc/ui"
+)
+
+const (
+	exitSuccess = iota
+	exitFailure
+)
+
+func main() {
+	if err := ui.MyMain(); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(exitFailure)
+	}
+	os.Exit(exitSuccess)
+}
diff --git a/main.go b/main_nogfx.go
similarity index 87%
rename from main.go
rename to main_nogfx.go
index e69a7cb2973720296bc6e7df00d1aa6cbb6c1355..adae62813be58bb47706f7b4d2dea1343f7ff358 100644
--- a/main.go
+++ b/main_nogfx.go
@@ -1,4 +1,5 @@
 // Aug 2021
+// +build no_gfx
 
 // Ackley_mc is for playing with Monte Carlo or simulated annealing on the
 // ackley function in N dimensions.
@@ -21,7 +22,7 @@ const (
 )
 
 func main() {
-	if err := mc_work.MyMain(); err != nil {
+	if err := mcwork.MyMain(); err != nil {
 		fmt.Fprintln(os.Stderr, err)
 		os.Exit(exitFailure)
 	}
diff --git a/mc_work/dorun.go b/mc_work/dorun.go
index 78c0552e9f32af23d4fbbd1fbd8da3a0c00078d1..4c05d432cf70364087dfffaf086c65fa3aff183f 100644
--- a/mc_work/dorun.go
+++ b/mc_work/dorun.go
@@ -1,5 +1,5 @@
 // Aug 2021
-package mc_work
+package mcwork
 
 import (
 	"bufio"
@@ -12,7 +12,6 @@ import (
 	"sync"
 
 	"example.com/ackley_mc/ackley"
-	"example.com/ackley_mc/ui"
 )
 
 const (
@@ -54,35 +53,35 @@ type cprm struct { // parameters calculated from input
 }
 
 // isNotSane checks for obviously silly parameters
-func isNotSane(mcPrm *mcPrm) error {
+func isNotSane(mcPrm *McPrm) error {
 	if mcPrm.fOutName == "" && mcPrm.fPltName == "" && mcPrm.xPltName == "" {
 		if false { // if there are no graphics compiled in, ..
 			return fmt.Errorf("All output files are empty. You would not see anything")
 		}
 	}
-	if mcPrm.iniTmp < 0 {
-		return fmt.Errorf("negative initial temperature %g", mcPrm.iniTmp)
+	if mcPrm.IniTmp < 0 {
+		return fmt.Errorf("negative initial temperature %g", mcPrm.IniTmp)
 	}
 	return nil
 }
 
 // setupRun does things like get the cooling rate, seed the random numbers.
-func setupRun(mcPrm *mcPrm, cprm *cprm) error {
+func setupRun(mcPrm *McPrm, cprm *cprm) error {
 	var err error
 	if mcPrm.dummy {
 		return nil
 	}
 	cprm.rand = rand.New(rand.NewSource(getSeed()))
 
-	if mcPrm.iniTmp != mcPrm.fnlTmp { // cooling or constant temperature ?
+	if mcPrm.IniTmp != mcPrm.FnlTmp { // cooling or constant temperature ?
 		var coolrate float64
 		cprm.coolme = true
-		if mcPrm.fnlTmp > mcPrm.iniTmp {
+		if mcPrm.FnlTmp > mcPrm.IniTmp {
 			const finalTempErr = "Final temp %g higher than initial temp %g"
-			return fmt.Errorf(finalTempErr, mcPrm.fnlTmp, mcPrm.iniTmp)
+			return fmt.Errorf(finalTempErr, mcPrm.FnlTmp, mcPrm.IniTmp)
 		}
-		nStep := float64(mcPrm.nStep)
-		fnlTmp, iniTmp := float64(mcPrm.fnlTmp), float64(mcPrm.iniTmp)
+		nStep := float64(mcPrm.NStep)
+		fnlTmp, iniTmp := float64(mcPrm.FnlTmp), float64(mcPrm.IniTmp)
 		if fnlTmp == 0 { // avoid divide by zeroes
 			fnlTmp = math.SmallestNonzeroFloat32
 		}
@@ -112,7 +111,7 @@ func setupRun(mcPrm *mcPrm, cprm *cprm) error {
 		var w bytes.Buffer // could be fancy, preallocate and use bytes.Newbuffer
 		cprm.fplotWrt = &w
 	}
-	n_alloc := mcPrm.nStep / 5 // About a fifth of the number of steps
+	n_alloc := mcPrm.NStep / 5 // About a fifth of the number of steps
 	cprm.plotnstp = make([]float64, 0, n_alloc)
 	cprm.plotf = make([]float64, 0, n_alloc)
 	if cprm.coolme {
@@ -130,7 +129,7 @@ func setupRun(mcPrm *mcPrm, cprm *cprm) error {
 		var w bytes.Buffer
 		cprm.xplotWrt = &w // I think we can remove the preceding line
 	}
-	cprm.plotXtrj = make([]float32, 0, int(n_alloc)*len(mcPrm.xIni))
+	cprm.plotXtrj = make([]float32, 0, int(n_alloc)*len(mcPrm.XIni))
 	if err = isNotSane(mcPrm); err != nil {
 		return err
 	}
@@ -148,14 +147,14 @@ func alt_newx(xold []float32, xT []float32, rand *rand.Rand, xDlta float32) {
 }
 
 // newx will move just one coordinate at a time
-func newx(xold []float32, xT []float32, rand *rand.Rand, xDlta float32) {
+func newx(xold []float32, xT []float32, rand *rand.Rand, xDlta float64) {
 	var iDim int
 	if (len(xold)) > 1 {
 		iDim = rand.Intn(len(xold)) // pick one dimension to change
 	}
-	t := 2.*rand.Float32() - 1
+	t := 2.*rand.Float64() - 1
 	t *= xDlta
-	xT[iDim] = xold[iDim] + t
+	xT[iDim] = xold[iDim] + float32(t)
 }
 
 // printfVal is the loop to print out the function value and coordinates
@@ -185,7 +184,7 @@ func saveStep(cprm *cprm, n uint32, tmprtr float64, x []float32, fTrial float64)
 }
 
 // nRunAdj will try to adjust the step size, given our history of accept/reject.
-func nRunAdj(mcPrm *mcPrm, nstep uint32, runAcc float64, xDlta float32) float32 {
+func nRunAdj(mcPrm *McPrm, nstep uint32, runAcc float64, xDlta float64) float64 {
 	const step = "step"
 	if runAcc < accRateIdeal-0.01 { // acceptance rate too low
 		xDlta *= 0.9
@@ -205,10 +204,10 @@ func nRunAdj(mcPrm *mcPrm, nstep uint32, runAcc float64, xDlta float32) float32
 // coordinates and function, we use double precision for the temperature.
 // Unfortunately, the plotting functions want double precision, so we store
 // an awful lot of stuff as float64.
-func doRun(mcPrm *mcPrm) error {
+func DoRun(mcPrm *McPrm) ([]byte, []byte, error) {
 	var cprm cprm
 	if err := setupRun(mcPrm, &cprm); err != nil {
-		return err
+		return nil, nil, err
 	}
 	if cprm.doTxtFval { // The text file documenting the run
 		defer cprm.fOutRaw.Close()
@@ -220,19 +219,24 @@ func doRun(mcPrm *mcPrm) error {
 	}
 
 	var nAcc int                           // Counter, number of accepted moves
-	x := make([]float32, len(mcPrm.xIni))  // current position
-	xT := make([]float32, len(mcPrm.xIni)) // trial position
+	x := make([]float32, len(mcPrm.XIni))  // current position
+	xT := make([]float32, len(mcPrm.XIni)) // trial position
 	runAcc := accRateIdeal                 // Running acceptance rate, exponentially weighted
-	copy(x, mcPrm.xIni)
+
+	for i := range mcPrm.XIni {
+		x[i] = float32(mcPrm.XIni[i])
+	}
+
+	//	copy(x, mcPrm.XIni) I had to replace this with the loop above
 	fOld := ackley.Ackley(x) // Initial function value
 	fTrial := fOld
-	tmprtr := float64(mcPrm.iniTmp)
+	tmprtr := float64(mcPrm.IniTmp)
 	nRunAcc := nRunAccAdj // Every nRunAccAdj, try adjusting the step size.
 	const runMult = 0.99
-	xDlta := mcPrm.xDlta // Adaptable step size
+	xDlta := mcPrm.XDlta // Adaptable step size
 	saveStep(&cprm, 0, tmprtr, x, fOld)
 
-	for n := uint32(0); n < mcPrm.nStep; n++ {
+	for n := uint32(0); n < mcPrm.NStep; n++ {
 		var accept bool
 		nRunAcc--
 		if nRunAcc == 0 { // Do we want to try adjusting the step size ?
@@ -266,32 +270,25 @@ func doRun(mcPrm *mcPrm) error {
 
 	// On plots, we want the last step, even if nothing changed.
 	if fTrial != fOld { // last move was not accepted, so we have to add last step
-		saveStep(&cprm, mcPrm.nStep, tmprtr, x, fOld)
+		saveStep(&cprm, mcPrm.NStep, tmprtr, x, fOld)
 	}
-	defer fmt.Println("n accepted:", nAcc, "of", mcPrm.nStep+1)
+	defer fmt.Println("n accepted:", nAcc, "of", mcPrm.NStep+1)
 
 	if err := plotfWrt(&cprm); err != nil {
-		return err
+		return nil, nil, err
 	}
-	if err := plotxWrt(&cprm, len(mcPrm.xIni)); err != nil {
-		return err
-	}
-	{
-		var fdata, xdata []byte
-		if funcBuf, ok := cprm.fplotWrt.(withBytes); ok {
-			fdata = funcBuf.Bytes()
-		}
-		if xBuf, ok := cprm.xplotWrt.(withBytes); ok {
-			xdata = xBuf.Bytes()
-		}
-		nothing(fdata, xdata)
-		ui.Scrnplt(fdata, xdata)
-		nothing(ui.Scrnplt)
+	if err := plotxWrt(&cprm, len(mcPrm.XIni)); err != nil {
+		return nil, nil, err
 	}
 
-	/*	if bBuf,  := plotxWrt(&cprm, mcPrm.xPltName, len(mcPrm.xIni)); err != nil {
-		return err
-	} */
+	var fdata, xdata []byte
+	if funcBuf, ok := cprm.fplotWrt.(withBytes); ok {
+		fdata = funcBuf.Bytes()
+	}
+	if xBuf, ok := cprm.xplotWrt.(withBytes); ok {
+		xdata = xBuf.Bytes()
+	}
+	nothing(fdata, xdata)
 
-	return nil
+	return fdata, xdata, nil
 }
diff --git a/mc_work/export_test.go b/mc_work/export_test.go
index 2d4bddfbf37924d3cde6af9f6b2ab5017deda45b..f8d71022507b808278c61b39369379fd70e06232 100644
--- a/mc_work/export_test.go
+++ b/mc_work/export_test.go
@@ -1,4 +1,4 @@
-package mc_work
+package mcwork
 
 var SetSuffix = setSuffix
 var RemoveQuotes = removeQuotes
diff --git a/mc_work/mc_work.go b/mc_work/mc_work.go
index 7b65f85cf1a018eecdd4123734af5b813dedf902..476888ad621ab142bc8f2448cf2cd2ecb50cd47b 100644
--- a/mc_work/mc_work.go
+++ b/mc_work/mc_work.go
@@ -1,22 +1,20 @@
 // Aug 2021
 
-package mc_work
+package mcwork
 
 import (
 	"flag"
 	"fmt"
-	"io"
 	"os"
-
-	"example.com/ackley_mc/ackley"
 )
 
-type mcPrm struct {
-	iniTmp, fnlTmp float32   // Initial and final temperatures
-	xIni           []float32 // initial x slice
-	xDlta          float32   // change x by up to +- xDlta in trial moves
-	nStep          uint32    // number of steps
-	nRun           uint32    // number of separate runs
+// Have to export everything so the graphical interface can get to them
+type McPrm struct {
+	IniTmp, FnlTmp float64   // Initial and final temperatures
+	XIni           []float32 // initial x slice
+	XDlta          float64   // change x by up to +- xDlta in trial moves
+	NStep          uint32    // number of steps
+	NRun           uint32    // number of separate runs
 	fOutName       string    // where we write output to
 	fPltName       string    // where we plot to (function values)
 	xPltName       string    // where we plot x trajectories to
@@ -31,39 +29,3 @@ func usage() {
 	u := `[options] input_parameter_file`
 	fmt.Fprintf(flag.CommandLine.Output(), "usage of %s: %s\n", os.Args[0], u)
 }
-
-// realmain is the real main function. The program wants to read from a file,
-// but we can have it read from an io.Reader and then use the test functions
-// for playing with it.
-func realmain(fp io.Reader) error {
-	var mcPrm mcPrm
-	if err := rdPrm(fp, &mcPrm); err != nil {
-		return err
-	}
-	if err := doRun(&mcPrm); err != nil {
-		return err
-	}
-	var x [1]float32
-	ackley.Ackley(x[:])
-	return nil
-}
-
-// MyMain is called from the real main. It opens the input file, but passes a
-// reader to the function that does the work. This lets us call it from a test
-// function.
-func MyMain() error {
-	if len(os.Args) < 2 {
-		usage()
-		return fmt.Errorf("No input file given")
-	}
-	fname := os.Args[1]
-	if fp, err := os.Open(fname); err != nil {
-		return err
-	} else {
-		defer fp.Close()
-		if err := realmain(fp); err != nil {
-			return err
-		}
-	}
-	return nil
-}
diff --git a/mc_work/mc_work_test.go b/mc_work/mc_work_test.go
index 485c92393e02ac4e0fb5bbd036971665d991e4dc..0a067f9f085b93f22c82c0907a46397ff86a2818 100644
--- a/mc_work/mc_work_test.go
+++ b/mc_work/mc_work_test.go
@@ -1,6 +1,7 @@
 // Aug 2021
+// +build no_gfx
 
-package mc_work
+package mcwork
 
 import (
 	"fmt"
diff --git a/mc_work/plot.go b/mc_work/plot.go
index e8268846bee4113de7a83d2b689fc26bfea2a6cf..e2112608b61cf6df3a368f03f73992bd9619b619 100644
--- a/mc_work/plot.go
+++ b/mc_work/plot.go
@@ -15,7 +15,7 @@
 // the X-axis differently. The solution is that we draw the temperature on both
 // plots, but set all the style attributes to be invisible when we plot the
 // X trajectories.
-package mc_work
+package mcwork
 
 import (
 	"fmt"
diff --git a/mc_work/rdprm.go b/mc_work/rdprm.go
index 3730db7edeb6ba0401d33be6a9667f44d576273e..e3b8ad2619f65ad3b1ca6c477a713233d07660f8 100644
--- a/mc_work/rdprm.go
+++ b/mc_work/rdprm.go
@@ -4,7 +4,7 @@
 // These are stored in a map along with string values. These are then converted
 // to floats or ints and put into a structure or variable.
 
-package mc_work
+package mcwork
 
 import (
 	"bufio"
@@ -34,15 +34,23 @@ var cmdDflt = []struct {
 }
 
 // digest digests the map, fills out our structure and sets the seed.
-func digest(prmMap map[string]string, mcPrm *mcPrm) error {
+func digest(prmMap map[string]string, mcPrm *McPrm) error {
 	var err error
-	getf := func(s string) float32 {
+/*	getf := func(s string) float32 {
 		if err != nil {
 			return 0.0
 		}
 		var r float64
 		r, err = strconv.ParseFloat(s, 32)
 		return float32(r)
+	} */
+	getf64 := func(s string) float64 {
+		if err != nil {
+			return 0.0
+		}
+		var r float64
+		r, err = strconv.ParseFloat(s, 64)
+		return r
 	}
 	getu := func(s string) uint32 {
 		if err != nil {
@@ -72,12 +80,12 @@ func digest(prmMap map[string]string, mcPrm *mcPrm) error {
 		}
 		return x
 	}
-	mcPrm.iniTmp = getf(prmMap["ini_temp"])
-	mcPrm.fnlTmp = getf(prmMap["final_temp"])
-	mcPrm.xDlta = getf(prmMap["x_delta"])
-	mcPrm.nStep = getu(prmMap["n_step"])
-	mcPrm.nRun = getu(prmMap["n_run"])
-	mcPrm.xIni = getx(prmMap["x_ini"])
+	mcPrm.IniTmp = getf64(prmMap["ini_temp"])
+	mcPrm.FnlTmp = getf64(prmMap["final_temp"])
+	mcPrm.XDlta = getf64(prmMap["x_delta"])
+	mcPrm.NStep = getu(prmMap["n_step"])
+	mcPrm.NRun = getu(prmMap["n_run"])
+	mcPrm.XIni = getx(prmMap["x_ini"])
 	mcPrm.fOutName = prmMap["foutname"]
 	mcPrm.fPltName = prmMap["fpltname"]
 	mcPrm.xPltName = prmMap["xpltname"]
@@ -106,8 +114,8 @@ pairs. Values for x_ini are separated by commas without spaces.
 	return s
 }
 
-// rdPrmInner is in a function by itself, to make testing easier
-func rdPrm(fp io.Reader, mcPrm *mcPrm) error {
+// RdPrm reads parameters from a io reader and fills out an control structure.
+func RdPrm(fp io.Reader, mcPrm *McPrm) error {
 	prmMap := make(map[string]string)
 	for _, s := range cmdDflt {
 		prmMap[s.key] = s.v // Put default values into map
diff --git a/mc_work/realmain_nogfx.go b/mc_work/realmain_nogfx.go
new file mode 100644
index 0000000000000000000000000000000000000000..a63116ed07f5df35dcda0a070bc6a990b4cc9462
--- /dev/null
+++ b/mc_work/realmain_nogfx.go
@@ -0,0 +1,48 @@
+// feb 2022
+// We are building a version without graphics
+// +build no_gfx
+
+
+// This should mirror the file realmain_gfx.go. It should also remain short.
+package mcwork
+
+import (
+	"io"
+	"os"
+	"fmt"
+)
+
+// realmain is the real main function. The program wants to read from a file,
+// but we can have it read from an io.Reader and then use the test functions
+// for playing with it.
+func realmain(fp io.Reader) error {
+	var mcPrm McPrm
+	if err := RdPrm(fp, &mcPrm); err != nil {
+		return err
+	}
+	if _, _, err := doRun(&mcPrm); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// MyMain is called from the real main. It opens the input file, but passes a
+// reader to the function that does the work. This lets us call it from a test
+// function.
+func MyMain() error {
+	if len(os.Args) < 2 {
+		usage()
+		return fmt.Errorf("No input file given")
+	}
+	fname := os.Args[1]
+	if fp, err := os.Open(fname); err != nil {
+		return err
+	} else {
+		defer fp.Close()
+		if err := realmain(fp); err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/mc_work/set_suffix.go b/mc_work/set_suffix.go
index c0bf8d0b70a0fe3267a3ed24ddc70dd691a00576..5428c204779cf6ffe5f8722c681f0e5ddff3cc9e 100644
--- a/mc_work/set_suffix.go
+++ b/mc_work/set_suffix.go
@@ -1,5 +1,5 @@
 // a utility
-package mc_work
+package mcwork
 
 import (
 	"errors"
diff --git a/mc_work/unwanted.goat b/mc_work/unwanted.goat
deleted file mode 100644
index cf1601145ce8b74fd4fea4219d56b337ea0b3d11..0000000000000000000000000000000000000000
--- a/mc_work/unwanted.goat
+++ /dev/null
@@ -1,16 +0,0 @@
-// maketicks this version works, but usually leaves you wanting one tick more.
-/*func alt_maketicks(axisDscrpt axticks.AxisDscrpt, prcsn int) []chart.Tick {
-	xmin, xmax, delta, prcsn := axisDscrpt.Xmin, axisDscrpt.Xmax, axisDscrpt.Delta, axisDscrpt.Prcsn
-	var t []chart.Tick
-	const fstr = "%.*f"
-	xv, xl := xmin, fmt.Sprintf(fstr, prcsn, xmin)
-	if xmin > 3.56 && xmin < 3.58 {
-		fmt.Println (axisDscrpt)
-	}
-	for ; xv <= xmax; xv, xl = xv+delta, fmt.Sprintf("%.*f", prcsn, xv) {
-		t = append(t, chart.Tick {Value: xv, Label: xl})
-	}
-
-	return t
-}*/
-
diff --git a/ui/embed_exmple.go b/ui/embed_exmple.go
new file mode 100644
index 0000000000000000000000000000000000000000..44342ac029206dd7273f672883440c8774b66dc9
--- /dev/null
+++ b/ui/embed_exmple.go
@@ -0,0 +1,20 @@
+// 15 Feb 2022
+// Let us read up an example input file and put its contents into a McPrm
+// (monte carlo control parameters) structure.
+
+package ui
+
+import (
+	_ "embed"
+	"strings"
+
+	"example.com/ackley_mc/mc_work"
+)
+
+//go:embed example_input
+var exmplInput string
+
+func getExmpl(mcPrm *mcwork.McPrm) error {
+	s := strings.NewReader(exmplInput)
+	return mcwork.RdPrm(s, mcPrm)
+}
diff --git a/example_input b/ui/example_input
similarity index 100%
rename from example_input
rename to ui/example_input
diff --git a/ui/mymain.go b/ui/mymain.go
new file mode 100644
index 0000000000000000000000000000000000000000..27bc825e3decb2a557b8d1bdec6a7c9188d6ffeb
--- /dev/null
+++ b/ui/mymain.go
@@ -0,0 +1,45 @@
+// feb 2022
+// We are building a version without graphics
+// +build !no_gfx
+
+package ui
+
+import (
+	"fmt"
+	"io"
+	"os"
+	
+	"example.com/ackley_mc/mc_work"
+)
+
+// realmain is the real main function. The program wants to read from a file,
+// but we can have it read from an io.Reader and then use the test functions
+// for playing with it.
+func realmain(fp io.Reader) error {
+	var mcPrm mcwork.McPrm
+	if fp != nil {
+		if err := mcwork.RdPrm(fp, &mcPrm); err != nil {
+			return err
+		}
+	} else {
+		if err := getExmpl(&mcPrm); err != nil {
+			return err
+		}
+	}
+	return UiDoRun(&mcPrm)
+
+}
+
+func MyMain() error {
+	if len(os.Args) < 2 {
+		fmt.Println("MyMain did not get a file to work with ")
+		return realmain(nil)
+	}
+	fname := os.Args[1]
+	if fp, err := os.Open(fname); err != nil {
+		return err
+	} else {
+		defer fp.Close()
+		return realmain(fp)
+	}
+}
diff --git a/ui/param_tab.go b/ui/param_tab.go
new file mode 100644
index 0000000000000000000000000000000000000000..504f283e494762ea16f6cfb3bbff1da48b83cf16
--- /dev/null
+++ b/ui/param_tab.go
@@ -0,0 +1,182 @@
+// Feb 2022
+// Set up a tab for getting Monte Carlo Parameters
+// This should return an object that can be embedded in a tabbed page.
+//go:build !no_gfx
+// +build !no_gfx
+
+package ui
+
+import (
+	"fmt"
+	"fyne.io/fyne/v2"
+	"fyne.io/fyne/v2/container"
+	"fyne.io/fyne/v2/data/binding"
+	"fyne.io/fyne/v2/dialog"
+	"fyne.io/fyne/v2/storage"
+	"fyne.io/fyne/v2/widget"
+	"os"
+	"strconv"
+	"strings"
+
+	"example.com/ackley_mc/mc_work"
+)
+
+// fslicestrng makes a nice string from a slice of float32's
+func fslicestrng(f []float32) string {
+	if len(f) == 0 {
+		return ""
+	}
+	s := fmt.Sprintf("%g", f[0])
+	for i := 1; i < len(f); i++ {
+		s += fmt.Sprintf(", %g", f[i])
+	}
+	return s
+}
+
+// str2f32 takes a string and returns a slice of float32's
+func s2f32(s string) ([]float32, error) {
+	y := strings.Split(s, ",")
+	if len(y) < 1 {
+		return nil, fmt.Errorf("no fields found")
+	}
+	x := make([]float32, len(y))
+	for i, s := range y {
+		if r, err := strconv.ParseFloat(strings.TrimSpace(s), 32); err != nil {
+			return nil, fmt.Errorf("tried to parse %v %v", s, err)
+		} else {
+			x[i] = float32(r)
+		}
+	}
+	return x, nil
+}
+
+func validateXini(s string) error {
+	fmt.Println("validation called")
+	_, err := s2f32(s)
+	return err
+}
+
+// paramScreen sets up a screen full of parameters we can adjust. It returns a the screen
+// and a function to be called to refresh it if parameters are changed elsewhere, like
+// reading from a file.
+func paramScreen(mcPrm *mcwork.McPrm) (*fyne.Container, func()) {
+
+	iniTmp := binding.BindFloat(&mcPrm.IniTmp)
+	iniTmpEntry := widget.NewEntryWithData(binding.FloatToString(iniTmp))
+	iniTmpLabel := widget.NewLabel("initial temp")
+
+	fnlTmp := binding.BindFloat(&mcPrm.FnlTmp)
+	fnlTmpEntry := widget.NewEntryWithData(binding.FloatToString(fnlTmp))
+	fnlTmpLabel := widget.NewLabel("final temp")
+
+	xDlta := binding.BindFloat(&mcPrm.XDlta)
+	xDltaEntry := widget.NewEntryWithData(binding.FloatToString(xDlta))
+	xDltaLabel := widget.NewLabel("X delta")
+
+	xIniStr := binding.NewString()
+	xIniStr.Set(fslicestrng(mcPrm.XIni))
+	xIniEntry := widget.NewEntryWithData(xIniStr)
+	xIniEntry.OnChanged = func(s string) {
+		x, err := s2f32(s)
+		if err != nil {
+			xIniEntry.SetValidationError(err)
+		} else {
+			mcPrm.XIni = append(mcPrm.XIni[:0], x...)
+		}
+	}
+	xIniEntry.Validator = validateXini
+	xIniLabel := widget.NewLabel("X ini")
+
+	r := container.NewGridWithColumns(2,
+		iniTmpLabel, iniTmpEntry,
+		fnlTmpLabel, fnlTmpEntry,
+		xDltaLabel, xDltaEntry,
+		xIniLabel, xIniEntry)
+	refreshPScreen := func() {
+		iniTmp.Reload()
+		fnlTmp.Reload()
+		xDlta.Reload()
+		xIniEntry.SetText(fslicestrng(mcPrm.XIni))
+	}
+	return r, refreshPScreen
+}
+
+func checkok(c *fyne.Container, parent fyne.Window) error {
+	for _, obj := range c.Objects {
+		if ent, ok := obj.(*widget.Entry); ok {
+			if err := ent.Validate(); err != nil {
+				dialog.NewError(err, parent).Show()
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// rdwork is called after the file open dialog gets "OK"
+func rdwork(mcPrm *mcwork.McPrm, parent fyne.Window, refreshme func()) error {
+	var e error
+	getmcprm := func(rd fyne.URIReadCloser, err error) {
+		if err != nil {
+			fmt.Println("error given to getmcprm")
+			dialog.NewError(err, parent).Show()
+			e = err
+			return
+		}
+		if rd == nil { // cancelled
+			return
+		}
+		defer rd.Close()
+		if err := mcwork.RdPrm(rd, mcPrm); err != nil {
+			e = err
+			return
+		} else {
+			fmt.Println("I think mcprm is", mcPrm)
+			refreshme()
+			dialog.NewInformation("OK confirmed", "read file, no errors", parent).Show()
+			return
+		}
+	}
+
+	t := dialog.NewFileOpen(getmcprm, parent)
+
+	if cwd, err := os.Getwd(); err == nil {
+		if y, err := storage.ListerForURI(storage.NewFileURI(cwd)); err == nil {
+			t.SetLocation(y) // If there was an error, we just use default location
+		}
+	}
+
+	t.Show() // set an error and see if anybody notices
+	return e
+}
+
+// inputTab sets up the input page. At the top, we have a button to read from
+// a file.
+func inputTab(mcPrm *mcwork.McPrm, parent fyne.Window, chn chan workstatus) (*fyne.Container, error) {
+	paramBinding, refreshPscreen := paramScreen(mcPrm)
+	rdfile := func() {
+		if err := rdwork(mcPrm, parent, refreshPscreen); err != nil {
+			dialog.NewError(err, parent).Show()
+		}
+	}
+	startrun := func() {
+		if err := checkok(paramBinding, parent); err != nil {
+			dialog.NewError(err, parent).Show()
+			return
+		}
+		fmt.Println("I want to run with paremeters", mcPrm)
+		chn <- workstatus{status: calculating}
+		if fdata, xdata, err := mcwork.DoRun(mcPrm); err != nil {
+			dialog.NewError(err, parent).Show()
+			close(chn)
+			return
+		} else {
+			chn <- workstatus{fdata: fdata, xdata: xdata, status: resultsReady}
+		}
+	}
+	rdfileBtn := widget.NewButton("read file", rdfile)
+	runBtn := widget.NewButton("start run", startrun)
+	buttons := container.NewVBox(rdfileBtn, runBtn)
+	c := container.NewHBox(buttons, paramBinding)
+	return c, nil
+}
diff --git a/ui/scrnplt.go b/ui/scrnplt.go
index 715fc16582508183f7c8080c4d5e385a6f55feaf..ac34c13e8ab8404f0830ba957494a7501df278f7 100644
--- a/ui/scrnplt.go
+++ b/ui/scrnplt.go
@@ -10,7 +10,6 @@ import (
 	"fmt"
 
 	"fyne.io/fyne/v2"
-	"fyne.io/fyne/v2/app"
 	"fyne.io/fyne/v2/canvas"
 	"fyne.io/fyne/v2/container"
 	"fyne.io/fyne/v2/dialog"
@@ -31,7 +30,6 @@ func tryfsave(uriw fyne.URIWriteCloser, err error, data []byte, parent fyne.Wind
 	if err := uriw.Close(); err != nil {
 		fmt.Println("error closing")
 	}
-	fmt.Printf("trydsave called with %+v %+v", uriw, err)
 }
 
 func fsave(parent fyne.Window, fdata []byte, suggested string) {
@@ -43,8 +41,6 @@ func fsave(parent fyne.Window, fdata []byte, suggested string) {
 	t.SetFileName(suggested)
 	t.SetFilter(filter)
 	t.Show()
-
-	fmt.Println("dsave called and returning")
 }
 
 func topmenu(parent fyne.Window, fdata, xdata []byte) *fyne.Menu {
@@ -70,19 +66,15 @@ func fileSaved(f fyne.URIWriteCloser, w fyne.Window) {
 
 func nothing(...interface{}) {}
 func breaker(...interface{}) {}
-func Scrnplt(fdata, xdata []byte) {
-	a := app.NewWithID("ackley") // Find a way to check if it is happy
-	w := a.NewWindow("Monte Carlo")
-
-	w.SetMainMenu(fyne.NewMainMenu(topmenu(w, fdata, xdata)))
+func scrnplt(fdata, xdata []byte) *fyne.Container {
 	fImage := canvas.NewImageFromReader(bytes.NewReader(fdata), "func.png")
 	fImage.FillMode = canvas.ImageFillContain
 	xImage := canvas.NewImageFromReader(bytes.NewReader(xdata), "xdata.png")
 	xImage.FillMode = canvas.ImageFillContain
 	content := container.NewGridWithRows(2, fImage, xImage)
 
-	w.Resize(fyne.NewSize(500, 600))
-	w.SetContent(content)
-	w.ShowAndRun()
-	fmt.Println("This was executed after the graphics finished")
+//	w.Resize(fyne.NewSize(500, 600))
+//	w.SetContent(content)
+	//	w.ShowAndRun()
+	return content
 }
diff --git a/ui/scrnplt.goat b/ui/scrnplt.goat
deleted file mode 100644
index 470aa0e79ae7daaf2bbe61c82d582c23a3b9e727..0000000000000000000000000000000000000000
--- a/ui/scrnplt.goat
+++ /dev/null
@@ -1,32 +0,0 @@
-// 25 Jan 2020
-// Given a buffer or two with a plot picture, send it to the screen
-
-// I think this might be better in its own package
-package ui
-
-import (
-	"bytes"
-	"fmt"
-	"image/color" // need this for the green ?
-		"fyne.io/fyne/v2"
-	"fyne.io/fyne/v2/app"
-	"fyne.io/fyne/v2/canvas"
-	"fyne.io/fyne/v2/container"
-)
-
-func Scrnplt (b []byte) {
-	fmt.Println ("scrnplt says buf size", len(b), "first few bytes:", string(b[:10]))
-	a := app.New()
-	w := a.NewWindow("container")
-	image := canvas.NewImageFromReader(bytes.NewReader(b), "boo.svg")
-	green := color.NRGBA{R: 0, G: 180, B: 0, A: 255}
-	text1 := canvas.NewText("Hello", green); print(text1)
-	text2 := canvas.NewText("There", green)
-	text2.Move(fyne.NewPos(20, 20))
-	content := container.NewWithoutLayout( image) // no more text 1, text2
-	// content := container.New(layout.NewGridLayout(2), text1, text2)
-
-	w.SetContent(content)
-
-	w.ShowAndRun()
-}
diff --git a/ui/ui_run.go b/ui/ui_run.go
new file mode 100644
index 0000000000000000000000000000000000000000..ef2ff0ad244a687d956520366f072b4e892b7db9
--- /dev/null
+++ b/ui/ui_run.go
@@ -0,0 +1,43 @@
+// 25 Jan 2020
+// Given a buffer or two with a plot picture, send it to the screen
+
+// +build !no_gfx
+
+package ui
+
+import (
+	"fyne.io/fyne/v2"
+	"fyne.io/fyne/v2/app"
+	"fyne.io/fyne/v2/container"
+	"fyne.io/fyne/v2/widget"
+
+	"example.com/ackley_mc/mc_work"
+)
+
+
+func initIn () *widget.Card {	
+	return widget.NewCard("input screen", "click on run to start a calc", nil)
+}
+
+func UiDoRun (mcPrm *mcwork.McPrm) error {
+
+	a := app.NewWithID("Monte Carlo")
+	w := a.NewWindow  ("Monte Carlo")
+	quitbutton := widget.NewButton ("quit .. click somwhere in here", a.Quit)
+	chn := make(chan workstatus)
+	inputTabCallback := func() (*fyne.Container) {
+		a, _ := inputTab(mcPrm, w, chn)
+		return a
+	}
+	t1 := container.NewTabItem("input tab", inputTabCallback())
+	cntrOut := fyne.NewContainer()
+	t2 := container.NewTabItem("output tab", cntrOut)
+	t3 := container.NewTabItem("quit me", quitbutton)
+	appTab := container.NewAppTabs(t1, t2, t3)
+	w.SetContent(appTab)
+	breaker()
+	go outputTab(chn, cntrOut)
+	w.ShowAndRun()
+	close (chn)
+	return nil
+}