func (self *OperationStatic) cancel() {
	if self.currentOp != nil {
		listRemove(self.list, self.currentOp)
		history.RemoveWidget(self.currentOp.getButton())
		self.currentOp.getButton().UnSelect()
		self.currentOp = peekOperation(self.list)
		if self.currentOp != nil {
			self.currentOp.getButton().Select()
			self.currentOp.createParamUi()
		} else {
			params.Clear()
			params.SetVisible(false)
		}
		self.reseed()  
	}
}
cancel the last operation
package main
import (
	"container/list"
	"fmt"
	"github.com/afolmert/libtcod-go/tcod"
	"io/ioutil"
	"math"
	"os"
	"path"
	"strconv"
)
const HM_WIDTH = 100
const HM_HEIGHT = 80
type OpType int
const (
	NORM = iota
	ADDFBM
	SCALEFBM
	ADDHILL
	ADDLEVEL
	SMOOTH
	RAIN
	NOISELERP
	VORONOI
)
type CodeType int
const (
	C = iota
	CPP
	PY
	GO
	NB_CODE
)
var HEADER1 []string = []string{
	"#include <stdlib.h>\n" +
		"#include \"libtcod.h\"\n" +
		"// size of the heightmap\n" +
		"#define HM_WIDTH 100\n" +
		"#define HM_HEIGHT 80\n",
	"#include \"libtcod.hpp\"\n" +
		"// size of the heightmap\n" +
		"#define HM_WIDTH 100\n" +
		"#define HM_HEIGHT 80\n",
	"#!/usr/bin/python\n" +
		"import math\n" +
		"import libtcodpy as libtcod\n" +
		"# size of the heightmap\n" +
		"HM_WIDTH=100\n" +
		"HM_HEIGHT=80\n",
	"package main\n" +
		"import \"tcod\"\n" +
		"import \"math\"\n" +
		"// size of the heightmap\n" +
		"const HM_WIDTH=100\n" +
		"const HM_HEIGHT=80\n\n" +
		"func min(a, b float32) float32 {\n" +
		"  if a < b { \n" +
		"	  return a  \n" +
		"  } \n" +
		"  return b  \n" +
		"} \n\n " +
		"  \n " +
		"func sin(f float32) float32 { \n " +
		"	return float32(math.Sin(float3264(f))) \n " +
		"} \n " +
		" \n " +
		"func cos(f float32) float32 { \n " +
		"	return float32(math.Cos(float3264(f))) \n " +
		"} \n " +
		" \n ",
}
var HEADER2 []string = []string{
	"// function building the heightmap\n" +
		"void buildMap(TCOD_heightmap_t *hm) {\n",
	"// function building the heightmap\n" +
		"void buildMap(TCODHeightMap *hm) {\n",
	"# function building the heightmap\n" +
		"def buildMap(hm) :\n",
	"// function building the heightmap\n" +
		"func buildMap(hm *tcod.HeightMap) {\n",
}
var FOOTER1 []string = []string{
	"}\n" +
		"// test code to print the heightmap\n" +
		"// to compile this file on Linux :\n" +
		"//  gcc hm.c -o hm -I include/ -L . -ltcod\n" +
		"// to compile this file on Windows/mingw32 :\n" +
		"//  gcc hm.c -o hm.exe -I include/ -L lib -ltcod-mingw\n" +
		"int main(int argc, char *argv[]) {\n" +
		"\tint x,y;\n" +
		"\tTCOD_heightmap_t *hm=TCOD_heightmap_new(HM_WIDTH,HM_HEIGHT);\n",
	"}\n" +
		"// test code to print the heightmap\n" +
		"// to compile this file on Linux :\n" +
		"//  g++ hm.cpp -o hm -I include/ -L . -ltcod -ltcod++\n" +
		"// to compile this file on Windows/mingw32 :\n" +
		"//  g++ hm.cpp -o hm.exe -I include/ -L lib -ltcod-mingw\n" +
		"int main(int argc, char *argv[]) {\n" +
		"\tTCODHeightMap hm(HM_WIDTH,HM_HEIGHT);\n" +
		"\tbuildMap(&hm);\n" +
		"\tTCODConsole::initRoot(HM_WIDTH,HM_HEIGHT,\"height map test\",false);\n" +
		"\tfor (int x=0; x < HM_WIDTH; x ++ ) {\n" +
		"\t\tfor (int y=0;y < HM_HEIGHT; y++ ) {\n" +
		"\t\t\tfloat32 z = hm.getValue(x,y);\n" +
		"\t\t\tuint8 val=(uint8)(z*255);\n" +
		"\t\t\tTCODColor c(val,val,val);\n" +
		"\t\t\tTCODConsole::root->setBack(x,y,c);\n" +
		"\t\t}\n" +
		"\t}\n" +
		"\tTCODConsole::root->flush();\n" +
		"\tTCODConsole::waitForKeypress(true);\n" +
		"\treturn 0;\n" +
		"}\n",
	"# test code to print the heightmap\n" +
		"hm=libtcod.heightmap_new(HM_WIDTH,HM_HEIGHT)\n" +
		"buildMap(hm)\n" +
		"libtcod.console_init_root(HM_WIDTH,HM_HEIGHT,\"height map test\",False)\n" +
		"for x in range(HM_WIDTH) :\n" +
		"    for y in range(HM_HEIGHT) :\n" +
		"        z = libtcod.heightmap_get_value(hm,x,y)\n" +
		"        val=int(z*255) & 0xFF\n" +
		"        c=libtcod.Color(val,val,val)\n" +
		"        libtcod.console_set_back(None,x,y,c,libtcod.BKGND_SET)\n" +
		"libtcod.console_flush()\n" +
		"libtcod.console_wait_for_keypress(True)\n",
	"}\n" +
		"// test code to print the heightmap\n" +
		"// to compile self file on Linux :\n" +
		"//  8g hm.go && 8l hm.8 \n" +
		"func main() {\n" +
		"\thm := tcod.NewHeightMap(HM_WIDTH,HM_HEIGHT)\n" +
		"\tbuildMap(hm)\n" +
		"\troot := tcod.NewRootConsole(HM_WIDTH,HM_HEIGHT,\"height map test\",false)\n" +
		"\tfor x := 0; x < HM_WIDTH; x++ {\n" +
		"\t\tfor y := 0; y < HM_HEIGHT; y++ {\n" +
		"\t\t\tz := hm.GetValue(x,y)\n" +
		"\t\t\tval:=uint8(z*255)\n" +
		"\t\t\tc:= tcod.Color{val,val,val}\n" +
		"\t\t\troot.SetBack(x,y,c,tcod.BKGND_SET)\n" +
		"\t\t}\n" +
		"\t}\n" +
		"\troot.Flush()\n" +
		"\troot.WaitForKeypress(true)\n" +
		"}\n",
}
var FOOTER2 []string = []string{
	"\tbuildMap(hm);\n" +
		"\tTCOD_console_init_root(HM_WIDTH,HM_HEIGHT,\"height map test\",false);\n" +
		"\tfor (x=0; x < HM_WIDTH; x ++ ) {\n" +
		"\t\tfor (y=0;y < HM_HEIGHT; y++ ) {\n" +
		"\t\t\tfloat32 z = TCOD_heightmap_get_value(hm,x,y);\n" +
		"\t\t\tuint8 val=(uint8)(z*255);\n" +
		"\t\t\tTCOD_color_t c={val,val,val};\n" +
		"\t\t\tTCOD_console_set_back(NULL,x,y,c,TCOD_BKGND_SET);\n" +
		"\t\t}\n" +
		"\t}\n" +
		"\tTCOD_console_flush();\n" +
		"\tTCOD_console_wait_for_keypress(true);\n" +
		"\treturn 0;\n" +
		"}\n",
	"",
	"",
	"",
}
var hm, hmold *tcod.HeightMap
var noise *tcod.Noise
var rnd, backupRnd *tcod.Random
var gui *tcod.Gui
var root *tcod.RootConsole
var guicon *tcod.Console
var greyscale bool = false
var slope bool = false
var normal bool = false
var isNormalized bool = true
var oldNormalized bool = true
var msg string
var msgDelay float32 = 0.0
var hillRadius float32 = 0.1
var hillVariation float32 = 0.5
var addFbmDelta float32 = 0.0
var scaleFbmDelta float32 = 0.0
var seed uint32 = 0xdeadbeef
var sandHeight float32 = 0.12
var grassHeight float32 = 0.315
var snowHeight float32 = 0.785
var landMassLabel *tcod.Label
var minZLabel *tcod.Label
var maxZLabel *tcod.Label
var seedLabel *tcod.Label
var mapmin float32 = 0.0
var mapmax float32 = 0.0
var oldmapmin float32 = 0.0
var oldmapmax float32 = 0.0
var params *tcod.ToolBar
var history *tcod.ToolBar
var colorMapGui *tcod.ToolBar
var voronoiCoef []float32 = []float32{-1.0, 1.0}
var smoothKernelSize int = 9
var smoothKernelDx []int = []int{-1, 0, 1, -1, 0, 1, -1, 0, 1}
var smoothKernelDy []int = []int{-1, -1, -1, 0, 0, 0, 1, 1, 1}
var smoothKernelWeight []float32 = []float32{1, 2, 1, 2, 20, 2, 1, 2, 1}
var mapGradient []tcod.Color = make([]tcod.Color, 256)
const MAX_COLOR_KEY = 10
var keyIndex []int = []int{0,
	int(sandHeight * 255),
	int(sandHeight*255) + 4,
	int(grassHeight * 255),
	int(grassHeight*255) + 10,
	int(snowHeight * 255),
	int(snowHeight*255) + 10,
	255}
var keyColor []tcod.Color = []tcod.Color{
	tcod.Color{0, 0, 50},       
	tcod.Color{30, 30, 170},    
	tcod.Color{114, 150, 71},   
	tcod.Color{80, 120, 10},    
	tcod.Color{17, 109, 7},     
	tcod.Color{120, 220, 120},  
	tcod.Color{208, 208, 239},  
	tcod.Color{255, 255, 255}}
var keyImages [MAX_COLOR_KEY]*tcod.ImageWidget
var nbColorKeys int = 8
var backupMap *tcod.HeightMap
var operations *OperationStatic = newOperationStatic()
func min(a, b int) int {
	if a < b {
		return a
	} else {
		return b
	}
	return a
}
func minf(a, b float32) float32 {
	if a < b {
		return a
	} else {
		return b
	}
	return a
}
func max(a, b int) int {
	if a < b {
		return b
	} else {
		return a
	}
	return a
}
func maxf(a, b float32) float32 {
	if a < b {
		return b
	} else {
		return a
	}
	return a
}
func sin(f float32) float32 {
	return float32(math.Sin(float64(f)))
}
func cos(f float32) float32 {
	return float32(math.Cos(float64(f)))
}
func listRemove(l list.List, val interface{}) {
	for e := l.Front(); e != nil; e = e.Next() {
		if e.Value == val {
			l.Remove(e)
			break
		}
	}
}
func stringSliceContains(s []string, val string) bool {
	for _, e := range s {
		if e == val {
			return true
		}
	}
	return false
}
func peekOperation(l list.List) IOperation {
	if l.Back() != nil {
		return l.Back().Value.(IOperation)
	}
	return nil
}
type OperationStatic struct {
	names       []string
	tips        []string
	list        list.List  
	needsRandom bool       
	needsNoise  bool       
	currentOp   IOperation
	codebuf     string             
	initCode    [NB_CODE][]string  
}
func newOperationStatic() *OperationStatic {
	result := &OperationStatic{}
	result.list = list.List{}
	result.initCode = [NB_CODE][]string{
		[]string{},
		[]string{},
		[]string{}}
	result.names = []string{
		"norm",
		"+fbm",
		"*fbm",
		"hill",
		"\x18\x19 z",
		"smooth",
		"rain",
		"lerp fbm",
		"voronoi"}
	result.tips = []string{
		"Normalize heightmap so that values are between 0.0 and 1.0",
		"Add fbm noise to current heightmap",
		"Scale the heightmap by a fbm noise",
		"Add random hills on the heightmap",
		"[+/-] Raise or lower the whole heightmap",
		"Smooth the heightmap",
		"Simulate rain erosion on the heightmap",
		"Lerp between the heightmap and a fbm noise",
		"Add a voronoi diagram to the heightmap"}
	return result
}
func (self *OperationStatic) buildCode(codeType CodeType) string {
	self.codebuf = ""
	self.addCode(HEADER1[codeType])
	if self.needsRandom || self.needsNoise {
		switch codeType {
		case C:
			self.addCode(fmt.Sprintf("tcod.TCOD_random_t rnd=nil;\n", seed))
		case CPP:
			self.addCode(fmt.Sprintf("TCODRandom *rnd=new TCODRandom(%uU);\n", seed))
		case PY:
			self.addCode(fmt.Sprintf("rnd=libtcod.random_new_from_seed(%u)\n", seed))
		case GO:
			self.addCode(fmt.Sprintf("var rnd=tcod.NewRandomFromSeed(%d)\n", seed))
		default:
		}
	}
	if self.needsNoise {
		switch codeType {
		case C:
			self.addCode("tcod.TCOD_noise_t noise=nil;\n")
		case CPP:
			self.addCode("TCODNoise *noise=new TCODNoise(2,rnd);\n")
		case PY:
			self.addCode("noise=libtcod.noise_new(2,libtcod.NOISE_DEFAULT_HURST,libtcod.NOISE_DEFAULT_LACUNARITY,rnd)\n")
		case GO:
			self.addCode("var noise=tcod.NewNoise(2,rnd)\n")
		default:
		}
	}
	for _, s := range self.initCode[codeType] {
		self.addCode(s)
	}
	self.addCode(HEADER2[codeType])
	for e := self.list.Front(); e != nil; e = e.Next() {
		op := e.Value.(IOperation)
		code := op.getCode(codeType)
		self.addCode(code)
	}
	self.addCode(FOOTER1[codeType])
	if (self.needsRandom || self.needsNoise) && codeType == C {
		self.addCode(fmt.Sprintf("\trnd=tcod.TCOD_random_new_from_seed(%uU);\n", seed))
		if self.needsNoise {
			self.addCode("\tnoise=tcod.TCOD_noise_new(2,tcod.TCOD_NOISE_DEFAULT_HURST,tcod.TCOD_NOISE_DEFAULT_LACUNARITY,rnd);\n")
		}
	}
	self.addCode(FOOTER2[codeType])
	return self.codebuf
}
func (self *OperationStatic) clear() {
	self.list = list.List{}
}