Esempio n. 1
0
func main() {
	err := termui.Init()
	if err != nil {
		panic(err)
	}
	defer termui.Close()

	//termui.UseTheme("helloworld")

	data := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
	spl0 := termui.NewSparkline()
	spl0.Data = data[3:]
	spl0.Title = "Sparkline 0"
	spl0.LineColor = termui.ColorGreen

	// single
	spls0 := termui.NewSparklines(spl0)
	spls0.Height = 2
	spls0.Width = 20
	spls0.Border = false

	spl1 := termui.NewSparkline()
	spl1.Data = data
	spl1.Title = "Sparkline 1"
	spl1.LineColor = termui.ColorRed

	spl2 := termui.NewSparkline()
	spl2.Data = data[5:]
	spl2.Title = "Sparkline 2"
	spl2.LineColor = termui.ColorMagenta

	// group
	spls1 := termui.NewSparklines(spl0, spl1, spl2)
	spls1.Height = 8
	spls1.Width = 20
	spls1.Y = 3
	spls1.BorderLabel = "Group Sparklines"

	spl3 := termui.NewSparkline()
	spl3.Data = data
	spl3.Title = "Enlarged Sparkline"
	spl3.Height = 8
	spl3.LineColor = termui.ColorYellow

	spls2 := termui.NewSparklines(spl3)
	spls2.Height = 11
	spls2.Width = 30
	spls2.BorderFg = termui.ColorCyan
	spls2.X = 21
	spls2.BorderLabel = "Tweeked Sparkline"

	termui.Render(spls0, spls1, spls2)

	termui.Handle("/sys/kbd/q", func(termui.Event) {
		termui.StopLoop()
	})
	termui.Loop()

}
Esempio n. 2
0
File: server.go Progetto: rzh/montu
func makeSparkline(title string, data []int, color termui.Attribute) termui.Sparkline {
	s := termui.NewSparkline()
	s.Data = data
	s.Title = title
	s.LineColor = color
	return s
}
Esempio n. 3
0
func addSparkLine(serviceName string, titles []string, color ui.Attribute) *ui.Sparklines {
	var sparkLines []ui.Sparkline
	for _, title := range titles {
		sparkLine := ui.NewSparkline()
		sparkLine.Height = 1
		sparkLine.Data = []int{}
		sparkLine.Title = title
		sparkLine.TitleColor = titleColor
		sparkLine.LineColor = color
		sparkLines = append(sparkLines, sparkLine)
	}
	sp := ui.NewSparklines(sparkLines...)
	sp.Height = 11
	sp.BorderLabel = serviceName

	ui.Body.AddRows(
		ui.NewRow(ui.NewCol(12, 0, sp)),
	)

	ui.Body.Align()
	ui.Render(sp)
	ui.Render(ui.Body)

	return sp
}
Esempio n. 4
0
// Init creates widgets, sets sizes and labels.
func (t *TermUISingle) Init(data UIData) error {
	err := termui.Init()
	if err != nil {
		return err
	}

	t.Sparklines = make(map[VarName]*termui.Sparkline)

	termui.UseTheme("helloworld")

	t.Title = func() *termui.Par {
		p := termui.NewPar("")
		p.Height = 3
		p.TextFgColor = termui.ColorWhite
		p.Border.Label = "Services Monitor"
		p.Border.FgColor = termui.ColorCyan
		return p
	}()
	t.Status = func() *termui.Par {
		p := termui.NewPar("")
		p.Height = 3
		p.TextFgColor = termui.ColorWhite
		p.Border.Label = "Status"
		p.Border.FgColor = termui.ColorCyan
		return p
	}()

	t.Pars = make([]*termui.Par, len(data.Vars))
	for i, name := range data.Vars {
		par := termui.NewPar("")
		par.TextFgColor = colorByKind(name.Kind())
		par.Border.Label = name.Short()
		par.Border.LabelFgColor = termui.ColorGreen
		par.Height = 3
		t.Pars[i] = par
	}

	var sparklines []termui.Sparkline
	for _, name := range data.Vars {
		spl := termui.NewSparkline()
		spl.Height = 1
		spl.TitleColor = colorByKind(name.Kind())
		spl.LineColor = colorByKind(name.Kind())
		spl.Title = name.Long()
		sparklines = append(sparklines, spl)
	}

	t.Sparkline = func() *termui.Sparklines {
		s := termui.NewSparklines(sparklines...)
		s.Height = 2*len(sparklines) + 2
		s.HasBorder = true
		s.Border.Label = fmt.Sprintf("Monitoring")
		return s
	}()

	t.Relayout()

	return nil
}
Esempio n. 5
0
func newTerminalUI(appName string) error {
	if err := ui.Init(); err != nil {
		return err
	}
	ui.UseTheme("helloworld")

	// usage text
	usageText := fmt.Sprintf(`Show live statistics for [%s]

:Press 'q' or 'ctrl-c' to exit
:Press 'PageUp' to increase app instances
:Press 'PageDown' to decrease app instances`, appName)
	usage := ui.NewPar(usageText)
	usage.Height = 12
	usage.TextFgColor = ui.ColorWhite
	usage.Border.Label = "Usage"
	usage.Border.FgColor = ui.ColorCyan

	// summary text
	summary := ui.NewPar("")
	summary.Height = 12
	summary.TextFgColor = ui.ColorRed
	summary.Border.Label = "Summary"
	summary.Border.FgColor = ui.ColorCyan

	// cpu sparklines
	data := [400]int{}
	line := ui.NewSparkline()
	line.Data = data[:]
	line.Height = 4
	line.LineColor = colors[0]
	cpu := ui.NewSparklines(line)
	cpu.Height = 7
	cpu.Border.Label = "CPU Usage"

	// memory gauges
	mem := make([]*ui.Gauge, 1)
	for i := range mem {
		mem[i] = ui.NewGauge()
		mem[i].Percent = 0
		mem[i].Height = 5
	}

	// disk bars
	disk := ui.NewBarChart()
	disk.Border.Label = "Disk Usage (in MB)"
	disk.Data = []int{0, 0, 0, 0, 0, 0, 0, 0}
	disk.Height = 12
	disk.BarWidth = 10
	disk.DataLabels = []string{"I: 0", "I: 1", "I: 2", "I: 3", "I: 4", "I: 5", "I: 6", "I: 7"}
	disk.TextColor = ui.ColorWhite
	disk.BarColor = ui.ColorYellow
	disk.NumColor = ui.ColorWhite

	term = &TerminalUI{ui.Body, usage, summary, cpu, mem, disk}
	return nil
}
Esempio n. 6
0
func NewMemTabElems(width int) *MemTabElems {
	g := termui.NewGauge()
	g.Width = width
	g.Height = 3
	g.Y = 0

	sline := termui.NewSparkline()
	sline.Title = "MEM"
	sline.Height = 8

	sls := termui.NewSparklines(sline)
	sls.Width = width
	sls.Height = 12
	sls.Y = 3
	return &MemTabElems{Gauge: g, SLines: sls}
}
Esempio n. 7
0
func addSparkLine(serviceName string, data [][]int) *ui.Sparklines {
	titles := []string{"CPU", "Disk Read", "Disk Write", "Memory", "Net RX", "Net TX"}
	var sparkLines []ui.Sparkline
	for i, title := range titles {
		sparkLine := ui.NewSparkline()
		sparkLine.Height = 1
		sparkLine.Data = data[i]
		sparkLine.Title = title
		sparkLines = append(sparkLines, sparkLine)
	}
	sp := ui.NewSparklines(sparkLines...)
	sp.Height = 14
	sp.Border.Label = serviceName

	ui.Body.AddRows(
		ui.NewRow(ui.NewCol(12, 0, sp)),
	)

	ui.Body.Align()
	ui.Render(sp)

	return sp
}
Esempio n. 8
0
func (t *TerminalUI) AdjustCPU(stats Statistics) {
	// adjust number of sparklines to number of app instances
	if len(stats.Instances) < len(t.CPU.Lines) {
		t.CPU.Lines = t.CPU.Lines[:len(stats.Instances)]
	}
	if len(stats.Instances) > len(t.CPU.Lines) {
		for i := len(t.CPU.Lines); i < len(stats.Instances); i++ {
			// show max 8 instances
			if len(t.CPU.Lines) > 7 {
				break
			}

			// new sparkline
			data := [400]int{}
			line := ui.NewSparkline()
			line.Data = data[:]
			line.LineColor = colors[i%6]

			// add sparkline
			t.CPU.Lines = append(t.CPU.Lines, line)
		}
	}
	t.CPU.Height = len(t.CPU.Lines)*(13-min(len(stats.Instances), 8)) + 2

	// calculate and update data values
	for i, idx := range stats.Instances {
		// show max 8 instances
		if i > 7 {
			break
		}
		cpu := int(math.Ceil(stats.Data[idx].Stats.Usage.CPU * 100 * 100 * 100))
		t.CPU.Lines[i].Data = append(t.CPU.Lines[i].Data[1:], cpu)
		t.CPU.Lines[i].Title = fmt.Sprintf("Instance %d: %.2f%%", i, stats.Data[idx].Stats.Usage.CPU*100.0)
		t.CPU.Lines[i].Height = 12 - min(len(stats.Instances), 8)
	}
}
Esempio n. 9
0
func main() {
	err := ui.Init()
	if err != nil {
		panic(err)
	}
	defer ui.Close()

	ui.UseTheme("helloworld")

	p := ui.NewPar(":PRESS q TO QUIT DEMO")
	p.Height = 3
	p.Width = 50
	p.Border.Label = "Text Box"

	strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"}
	list := ui.NewList()
	list.Items = strs
	list.Border.Label = "List"
	list.Height = 7
	list.Width = 25
	list.Y = 4

	g := ui.NewGauge()
	g.Percent = 50
	g.Width = 50
	g.Height = 3
	g.Y = 11
	g.Border.Label = "Gauge"

	spark := ui.NewSparkline()
	spark.Title = "srv 0:"
	spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
	spark.Data = spdata

	spark1 := ui.NewSparkline()
	spark1.Title = "srv 1:"
	spark1.Data = spdata

	sp := ui.NewSparklines(spark, spark1)
	sp.Width = 25
	sp.Height = 7
	sp.Border.Label = "Sparkline"
	sp.Y = 4
	sp.X = 25

	lc := ui.NewLineChart()
	sinps := (func() []float64 {
		n := 100
		ps := make([]float64, n)
		for i := range ps {
			ps[i] = 1 + math.Sin(float64(i)/4)
		}
		return ps
	})()

	lc.Border.Label = "Line Chart"
	lc.Data = sinps
	lc.Width = 50
	lc.Height = 11
	lc.X = 0
	lc.Y = 14
	lc.Mode = "dot"

	bc := ui.NewBarChart()
	bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
	bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
	bc.Border.Label = "Bar Chart"
	bc.Width = 26
	bc.Height = 10
	bc.X = 51
	bc.Y = 0
	bc.DataLabels = bclabels

	lc1 := ui.NewLineChart()
	lc1.Border.Label = "Line Chart"
	rndwalk := (func() []float64 {
		n := 150
		d := make([]float64, n)
		for i := 1; i < n; i++ {
			if i < 20 {
				d[i] = d[i-1] + 0.01
			}
			if i > 20 {
				d[i] = d[i-1] - 0.05
			}
		}
		return d
	})()
	lc1.Data = rndwalk
	lc1.Width = 26
	lc1.Height = 11
	lc1.X = 51
	lc1.Y = 14

	p1 := ui.NewPar("Hey!\nI am a borderless block!")
	p1.HasBorder = false
	p1.Width = 26
	p1.Height = 2
	p1.X = 52
	p1.Y = 11

	draw := func(t int) {
		g.Percent = t % 101
		list.Items = strs[t%9:]
		sp.Lines[0].Data = spdata[t%10:]
		sp.Lines[1].Data = spdata[t/2%10:]
		lc.Data = sinps[t/2:]
		lc1.Data = rndwalk[t:]
		bc.Data = bcdata[t/2%10:]
		ui.Render(p, list, g, sp, lc, bc, lc1, p1)
	}

	evt := ui.EventCh()
	i := 0
	for {
		select {
		case e := <-evt:
			if e.Type == ui.EventKey && e.Ch == 'q' {
				return
			}
		default:
			draw(i)
			i++
			if i == 102 {
				return
			}
			time.Sleep(time.Second / 2)
		}
	}
}
Esempio n. 10
0
func (sc *sparkyClient) runTestSequence() {
	// First, we need to build the widgets on our screen.

	// Build our title box
	titleBox := termui.NewPar("──────[ sparkyfish ]────────────────────────────────────────")
	titleBox.Height = 1
	titleBox.Width = 60
	titleBox.Y = 0
	titleBox.Border = false
	titleBox.TextFgColor = termui.ColorWhite | termui.AttrBold

	// Build the server name/location banner line
	bannerBox := termui.NewPar("")
	bannerBox.Height = 1
	bannerBox.Width = 60
	bannerBox.Y = 1
	bannerBox.Border = false
	bannerBox.TextFgColor = termui.ColorRed | termui.AttrBold

	// Build a download graph widget
	dlGraph := termui.NewLineChart()
	dlGraph.BorderLabel = " Download Speed (Mbit/s)"
	dlGraph.Data = []float64{0}
	dlGraph.Width = 30
	dlGraph.Height = 12
	dlGraph.PaddingTop = 1
	dlGraph.X = 0
	dlGraph.Y = 6
	// Windows Command Prompt doesn't support our Unicode characters with the default font
	if runtime.GOOS == "windows" {
		dlGraph.Mode = "dot"
		dlGraph.DotStyle = '+'
	}
	dlGraph.AxesColor = termui.ColorWhite
	dlGraph.LineColor = termui.ColorGreen | termui.AttrBold

	// Build an upload graph widget
	ulGraph := termui.NewLineChart()
	ulGraph.BorderLabel = " Upload Speed (Mbit/s)"
	ulGraph.Data = []float64{0}
	ulGraph.Width = 30
	ulGraph.Height = 12
	ulGraph.PaddingTop = 1
	ulGraph.X = 30
	ulGraph.Y = 6
	// Windows Command Prompt doesn't support our Unicode characters with the default font
	if runtime.GOOS == "windows" {
		ulGraph.Mode = "dot"
		ulGraph.DotStyle = '+'
	}
	ulGraph.AxesColor = termui.ColorWhite
	ulGraph.LineColor = termui.ColorGreen | termui.AttrBold

	latencyGraph := termui.NewSparkline()
	latencyGraph.LineColor = termui.ColorCyan
	latencyGraph.Height = 3

	latencyGroup := termui.NewSparklines(latencyGraph)
	latencyGroup.Y = 3
	latencyGroup.Height = 3
	latencyGroup.Width = 30
	latencyGroup.Border = false
	latencyGroup.Lines[0].Data = []int{0}

	latencyTitle := termui.NewPar("Latency")
	latencyTitle.Height = 1
	latencyTitle.Width = 30
	latencyTitle.Border = false
	latencyTitle.TextFgColor = termui.ColorGreen
	latencyTitle.Y = 2

	latencyStats := termui.NewPar("")
	latencyStats.Height = 4
	latencyStats.Width = 30
	latencyStats.X = 32
	latencyStats.Y = 2
	latencyStats.Border = false
	latencyStats.TextFgColor = termui.ColorWhite | termui.AttrBold
	latencyStats.Text = "Last: 30ms\nMin: 2ms\nMax: 34ms"

	// Build a stats summary widget
	statsSummary := termui.NewPar("")
	statsSummary.Height = 7
	statsSummary.Width = 60
	statsSummary.Y = 18
	statsSummary.BorderLabel = " Throughput Summary "
	statsSummary.Text = fmt.Sprintf("DOWNLOAD \nCurrent: -- Mbit/s\tMax: --\tAvg: --\n\nUPLOAD\nCurrent: -- Mbit/s\tMax: --\tAvg: --")
	statsSummary.TextFgColor = termui.ColorWhite | termui.AttrBold

	// Build out progress gauge widget
	progress := termui.NewGauge()
	progress.Percent = 40
	progress.Width = 60
	progress.Height = 3
	progress.Y = 25
	progress.X = 0
	progress.Border = true
	progress.BorderLabel = " Test Progress "
	progress.Percent = 0
	progress.BarColor = termui.ColorRed
	progress.BorderFg = termui.ColorWhite
	progress.PercentColorHighlighted = termui.ColorWhite | termui.AttrBold
	progress.PercentColor = termui.ColorWhite | termui.AttrBold

	// Build our helpbox widget
	helpBox := termui.NewPar(" COMMANDS: [q]uit")
	helpBox.Height = 1
	helpBox.Width = 60
	helpBox.Y = 28
	helpBox.Border = false
	helpBox.TextBgColor = termui.ColorBlue
	helpBox.TextFgColor = termui.ColorYellow | termui.AttrBold
	helpBox.Bg = termui.ColorBlue

	// Add the widgets to the rendering jobs and render the screen
	sc.wr.Add("titlebox", titleBox)
	sc.wr.Add("bannerbox", bannerBox)
	sc.wr.Add("dlgraph", dlGraph)
	sc.wr.Add("ulgraph", ulGraph)
	sc.wr.Add("latency", latencyGroup)
	sc.wr.Add("latencytitle", latencyTitle)
	sc.wr.Add("latencystats", latencyStats)
	sc.wr.Add("statsSummary", statsSummary)
	sc.wr.Add("progress", progress)
	sc.wr.Add("helpbox", helpBox)
	sc.wr.Render()

	// Launch a progress bar updater
	go sc.updateProgressBar()

	// Start our ping test and block until it's complete
	sc.pingTest()

	// Start our stats generator, which receives realtime measurements from the throughput
	// reporter and generates metrics from them
	go sc.generateStats()

	// Run our download tests and block until that's done
	sc.runThroughputTest(inbound)

	// Signal to our MeasureThroughput that we're about to begin the upload test
	close(sc.changeToUpload)

	// Run an outbound (upload) throughput test and block until it's complete
	sc.runThroughputTest(outbound)

	// Signal to our generators that the upload test is complete
	close(sc.statsGeneratorDone)

	// Notify the progress bar updater to change the bar color to green
	close(sc.allTestsDone)

	return
}
Esempio n. 11
0
// Init creates widgets, sets sizes and labels.
func (t *TermUI) Init(data UIData) error {
	err := termui.Init()
	if err != nil {
		return err
	}

	termui.UseTheme("helloworld")
	theme := termui.Theme()
	theme.BodyBg = termui.ColorDefault
	theme.BlockBg = termui.ColorDefault
	theme.BorderBg = termui.ColorDefault
	theme.BorderFg = termui.ColorBlack
	theme.BorderLabelTextBg = termui.ColorDefault
	theme.BorderLabelTextFg = termui.ColorCyan
	theme.ListItemBg = termui.ColorDefault
	theme.ParTextBg = termui.ColorDefault

	termui.SetTheme(theme)

	t.Title = func() *termui.Par {
		p := termui.NewPar("")
		p.Height = 3
		p.TextFgColor = termui.ColorWhite
		p.Border.Label = "Services Monitor"
		p.Border.FgColor = termui.ColorBlack
		return p
	}()
	t.Status = func() *termui.Par {
		p := termui.NewPar("")
		p.Height = 3
		p.TextFgColor = termui.ColorWhite
		p.Border.Label = "Status"
		p.Border.LabelFgColor = termui.ColorCyan
		p.Border.FgColor = termui.ColorBlack
		return p
	}()
	t.Services = func() *termui.List {
		list := termui.NewList()
		list.ItemFgColor = termui.ColorYellow
		list.Border.LabelFgColor = termui.ColorCyan | termui.AttrBold
		list.Border.Label = "Services"
		list.Height = len(data.Services) + 2
		return list
	}()

	t.Lists = make([]*termui.List, len(data.Vars))
	for i, name := range data.Vars {
		list := termui.NewList()
		list.ItemFgColor = colorByKind(name.Kind())
		list.Border.Label = name.Short()
		list.Border.LabelFgColor = termui.ColorCyan
		list.Height = len(data.Services) + 2
		t.Lists[i] = list
	}

	makeSparkline := func(name VarName) *termui.Sparklines {
		var sparklines []termui.Sparkline
		for _, service := range data.Services {
			spl := termui.NewSparkline()
			spl.Height = 1
			spl.TitleColor = termui.ColorGreen
			spl.LineColor = termui.ColorGreen
			spl.Title = service.Name
			sparklines = append(sparklines, spl)
		}

		s := termui.NewSparklines(sparklines...)
		s.Height = 2*len(data.Services) + 2
		s.HasBorder = true
		s.Border.Label = fmt.Sprintf("Monitoring %s", name.Long())
		return s
	}
	t.Sparkline1 = makeSparkline(data.Vars[0])
	if len(data.Vars) > 1 {
		t.Sparkline2 = makeSparkline(data.Vars[1])
	}

	t.Relayout()

	return nil
}
Esempio n. 12
0
func main() {
	err := tui.Init()
	if err != nil {
		panic(err)
	}
	defer tui.Close()

	///////////
	//
	//  Create UI components
	//
	///////////

	// Header
	pr_th := 3
	pr_title := tui.NewPar("Text Console User Interfaces")
	pr_title.Width = tui.TermWidth()
	pr_title.Height = pr_th
	pr_title.BorderFg = tui.ColorBlue

	// Footer
	g_h := 5
	g := tui.NewGauge()
	g.Percent = 1
	g.Width = tui.TermWidth()
	g.Height = g_h
	g.Y = tui.TermHeight() - g_h
	g.BorderLabel = "Progress"
	g.Label = "{{percent}} - Start!"
	g.LabelAlign = tui.AlignRight
	g.BarColor = tui.ColorGreen
	g.BorderFg = tui.ColorBlue
	g.BorderLabelFg = tui.ColorWhite

	// Slide 1
	txtlst1 := "Introduction\n\no Myself\n\no Interests in Go"
	se1_1 := tui.NewPar(txtlst1)
	se1_1.Width = tui.TermWidth()
	se1_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se1_1.Y = pr_th
	se1_2 := tui.NewPar("")
	se1_2.Width = tui.TermWidth()
	se1_2.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se1_2.Y = pr_th + se1_1.Height

	// Slide 2
	txtlst2 := "The Termui Library\n\no Console library UI\n\n"
	txtlst2 += "o A widget library for dashboard building in the terminal\n\n"
	txtlst2 += "o Cross Platform\n\n  o Runs on Linux, OSX, and Windows"
	se2_1 := tui.NewPar(txtlst2)
	se2_1.Width = tui.TermWidth()
	se2_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se2_1.Y = pr_th

	// Slide 3
	txtlst3 := "More Info\n\n"
	txtlst3 += "o Built on top of termbox library\n\n"
	txtlst3 += "o Inherits handlers, events, and cross platform compatibility"
	se3_1 := tui.NewPar(txtlst3)
	se3_1.Width = tui.TermWidth()
	se3_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se3_1.Y = pr_th

	// Slide 4
	txtlst4 := "Features\n\n"
	txtlst4 += "o Multiple widgets available\n\n"
	txtlst4 += "o Automatic grid layout\n\n"
	txtlst4 += "o 多言語可能 (multi-lang possible)"
	se4_1 := tui.NewPar(txtlst4)
	se4_1.Width = tui.TermWidth()
	se4_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se4_1.Y = pr_th

	// Slide 5
	txtlst5 := "Widget Features\n\n"
	txtlst5 += "o Can be surrounded by borders\n\n"
	txtlst5 += "o Can have labels associated with it\n\n"
	txtlst5 += "o Borders can also have labels\n\n"
	txtlst5 += "o Color"
	se5_1 := tui.NewPar(txtlst5)
	se5_1.Width = tui.TermWidth()
	se5_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se5_1.Y = pr_th

	// Slide 6
	txtlst6 := "Widgets - Par\n\no Par - aka Textbox\n\n"
	txtlst6 += "o Basic textbox widget\n\n"
	txtlst6 += "   p := termui.NewPar(\"World\")\n"
	txtlst6 += "   p.BorderLabel(\"Hello\")"
	se6_1 := tui.NewPar(txtlst6)
	se6_1.Width = tui.TermWidth()
	se6_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se6_1.Y = pr_th
	se6_2 := tui.NewPar("World")
	se6_2.BorderLabel = "Hello"
	se6_2.BorderFg = tui.ColorYellow
	se6_2.BorderLabelFg = tui.ColorWhite
	se6_2.Width = tui.TermWidth()
	se6_2.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se6_2.Y = pr_th + se6_1.Height

	// Slide 7
	txtlst7 := "Widgets - Lists\n\no List - A text list\n\n"
	txtlst7 += "o Text Lists\n\n"
	txtlst7 += "   tl := termui.NewList()\n"
	txtlst7 += "   tl.Items = textlist\n"
	se7_2lst := []string{
		"* List Elems",
		"* Are Just",
		"* Lists of",
		"* Strings",
		"* [and support](fg-blue)",
		"* [colors](fg-green,bg-black)"}
	se7_1 := tui.NewPar(txtlst7)
	se7_1.Width = tui.TermWidth()
	se7_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se7_1.Y = pr_th
	se7_2 := tui.NewList()
	se7_2.Items = se7_2lst
	se7_2.BorderFg = tui.ColorYellow
	se7_2.BorderLabelFg = tui.ColorWhite
	se7_2.Width = tui.TermWidth()
	se7_2.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se7_2.Y = pr_th + se7_1.Height

	// Slide 8
	txtlst8 := "Widgets - Line Charts\n\n"
	txtlst8 += "o Draw linecharts\n\n"
	txtlst8 += "   lc := termui.NewLineChart()\n"
	txtlst8 += "   lc.Data = cosdata"
	se8_1 := tui.NewPar(txtlst8)
	se8_1.Width = tui.TermWidth()
	se8_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se8_1.Y = pr_th
	se8_2 := tui.NewLineChart()
	se8_2.Data = cosData()
	se8_2.BorderFg = tui.ColorYellow
	se8_2.BorderLabelFg = tui.ColorWhite
	se8_2.Width = tui.TermWidth()
	se8_2.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se8_2.Y = pr_th + se8_1.Height

	// Slide 9
	txtlst9 := "Widgets - Bar Charts\n\n"
	txtlst9 += "o Draw bar charts\n\n"
	txtlst9 += "   data := []int{4, 5, 6, 7, 8, 6, 5}\n"
	txtlst9 += "   bc := termui.NewBarChart()\n"
	txtlst9 += "   bc.Data = data"
	se9_1 := tui.NewPar(txtlst9)
	se9_1.Width = tui.TermWidth()
	se9_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se9_1.Y = pr_th
	se9_2 := tui.NewBarChart()
	se9_2.Data = []int{4, 5, 6, 7, 8, 6, 5}
	se9_2.DataLabels = []string{"S0", "S1", "S2", "S3", "S4", "S5", "S6", "S7"}
	se9_2.BorderFg = tui.ColorYellow
	se9_2.BorderLabelFg = tui.ColorWhite
	se9_2.Width = tui.TermWidth()
	se9_2.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se9_2.Y = pr_th + se9_1.Height

	// Slide 10
	txtlst10 := "Widgets - Sparklines\n\n"
	txtlst10 += "o Draw sparklines\n\n"
	txtlst10 += "   data := []int{4, 5, 6, 7, 8, 6, 5}\n"
	txtlst10 += "   sp := termui.NewSparkline()\n"
	txtlst10 += "   sp.Data = data\n"
	txtlst10 += "   spl := termui.NewSparklines(sp)"
	se10_1 := tui.NewPar(txtlst10)
	se10_1.Width = tui.TermWidth()
	se10_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se10_1.Y = pr_th
	sp10_2 := tui.NewSparkline()
	sp10_2.Data = []int{4, 5, 6, 7, 8, 6, 5}
	sp10_2.LineColor = tui.ColorRed
	se10_2 := tui.NewSparklines(sp10_2)
	se10_2.Width = tui.TermWidth()
	se10_2.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se10_2.Y = pr_th + se10_1.Height

	// Slide 11
	txtlst11 := "General Workflow\n\n"
	txtlst11 += "o Setup\n\no Create & Setup UI elems\n\n"
	txtlst11 += "o Setup handlers\n\nLoop"
	se11_1 := tui.NewPar(txtlst11)
	se11_1.Width = tui.TermWidth()
	se11_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se11_1.Y = pr_th
	txtlst11_2 := "   termui.Init()\n"
	txtlst11_2 += "   p := termui.NewPar(\"Hello World\")\n"
	txtlst11_2 += "   termui.Render(p)\n"
	txtlst11_2 += "   termui.Handle(\"/sys/kbd/Q\", func(termui.Event) {\n"
	txtlst11_2 += "             termui.StopLoop() })\n"
	txtlst11_2 += "   termui.Loop()"
	se11_2 := tui.NewPar(txtlst11_2)
	se11_2.BorderFg = tui.ColorYellow
	se11_2.BorderLabelFg = tui.ColorWhite
	se11_2.Width = tui.TermWidth()
	se11_2.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se11_2.Y = pr_th + se11_1.Height

	// Slide 12
	txtlst12 := "Extra Notes\n\n"
	txtlst12 += "o V1 vs V2\n\n"
	txtlst12 += "o Timers\n\n"
	se12_1 := tui.NewPar(txtlst12)
	se12_1.Width = tui.TermWidth()
	se12_1.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se12_1.Y = pr_th
	se12_2 := tui.NewPar("")
	se12_2.Border = false
	se12_2.Width = tui.TermWidth()
	se12_2.Height = (tui.TermHeight() / 2) - (pr_th + g_h)
	se12_2.Y = pr_th + se12_1.Height

	///////////
	//
	//  Build the slideshow
	//
	///////////
	slides := NewSlideShow(pr_title, g)
	slides.AddSlide("start", []tui.Bufferer{})
	slides.AddSlide("Intro", []tui.Bufferer{se1_1})
	slides.AddSlide("Termui", []tui.Bufferer{se2_1})
	slides.AddSlide("More Info", []tui.Bufferer{se3_1})
	slides.AddSlide("Features", []tui.Bufferer{se4_1})
	slides.AddSlide("WidgetFeatures", []tui.Bufferer{se5_1})
	slides.AddSlide("Par()", []tui.Bufferer{se6_1, se6_2})
	slides.AddSlide("List()", []tui.Bufferer{se7_1, se7_2})
	slides.AddSlide("LineChart()", []tui.Bufferer{se8_1, se8_2})
	slides.AddSlide("BarChart()", []tui.Bufferer{se9_1, se9_2})
	slides.AddSlide("Sparkline()", []tui.Bufferer{se10_1, se10_2})
	slides.AddSlide("quickdemo", []tui.Bufferer{se11_1, se11_2})
	slides.AddSlide("gotchas", []tui.Bufferer{se12_1, se12_2})

	slides_num := slides.Length()
	slides_idx := 0

	maxttl := 360
	ttl := maxttl

	draw := func() {
		tui.Render(slides.At(slides_idx).Widgets...)
	}

	tui.Render(pr_title, g)

	tui.Handle("/sys/kbd/Q", func(tui.Event) {
		tui.StopLoop()
	})
	tui.Handle("/sys/kbd/<left>", func(tui.Event) {
	})
	tui.Handle("/sys/kbd/<right>", func(tui.Event) {
		ttl = maxttl
		slides_idx++
		if slides_idx > (slides_num - 1) {
			slides_idx = 0
		}
		g.Percent = calcPercent(slides_idx, slides_num)

		lbl := "Progress - " + strconv.Itoa(g.Percent) + "%" +
			" TTL: " + strconv.Itoa(ttl)

		g.BorderLabel = lbl
		g.Label = "{{percent}} - " + slides.At(slides_idx).Title
	})
	tui.Handle("/sys/kbd/<space>", func(tui.Event) {
		ttl = maxttl
		slides_idx++
		if slides_idx > (slides_num - 1) {
			slides_idx = 0
		}
		g.Percent = calcPercent(slides_idx, slides_num)

		lbl := "Progress - " + strconv.Itoa(g.Percent) + "%" +
			" TTL: " + strconv.Itoa(ttl)

		g.BorderLabel = lbl
		g.Label = "{{percent}} - " + slides.At(slides_idx).Title
	})
	tui.Handle("/timer/1s", func(e tui.Event) {
		ttl--
		if ttl <= 0 {
			if slides_idx < (slides_num - 1) {
				if slides_idx > slides.Length()-1 {
					slides_idx++
				}
			}
			g.Percent = calcPercent(slides_idx, slides_num)
			ttl = maxttl
		}
		lbl := "Progress - " + strconv.Itoa(g.Percent) + "%" +
			" TTL: " + strconv.Itoa(ttl)
		g.BorderLabel = lbl

		draw()
	})

	tui.Loop()
}