From b8d37842ee1db74862031e52ff191d9295ae4202 Mon Sep 17 00:00:00 2001 From: gizak Date: Tue, 24 Mar 2015 17:16:43 -0400 Subject: [PATCH] Add docs --- bar.go | 16 ++++++++++++++ block.go | 20 ++++++++++++------ box.go | 4 ++++ chart.go | 16 ++++++++++++-- doc.go | 27 +++++++++++++++++++++++ gauge.go | 13 ++++++++++++ grid.go | 60 +++++++++++++++++++++++++++++++++++++++++----------- list.go | 25 ++++++++++++++++++++++ p.go | 9 ++++++++ point.go | 1 + render.go | 11 ++++++++-- sparkline.go | 19 ++++++++++++++++- 12 files changed, 197 insertions(+), 24 deletions(-) create mode 100644 doc.go diff --git a/bar.go b/bar.go index 9ec3b1c..d0b4ec0 100644 --- a/bar.go +++ b/bar.go @@ -6,6 +6,20 @@ package termui import "fmt" +// BarChart creates multiple bars in a widget: +/* + bc := termui.NewBarChart() + data := []int{3, 2, 5, 3, 9, 5} + bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"} + bc.Border.Label = "Bar Chart" + bc.Data = data + bc.Width = 26 + bc.Height = 10 + bc.DataLabels = bclabels + bc.TextColor = termui.ColorGreen + bc.BarColor = termui.ColorRed + bc.NumColor = termui.ColorYellow +*/ type BarChart struct { Block BarColor Attribute @@ -22,6 +36,7 @@ type BarChart struct { max int } +// NewBarChart returns a new *BarChart with current theme. func NewBarChart() *BarChart { bc := &BarChart{Block: *NewBlock()} bc.BarColor = theme.BarChartBar @@ -53,6 +68,7 @@ func (bc *BarChart) layout() { bc.scale = float64(bc.max) / float64(bc.innerHeight-1) } +// Buffer implements Bufferer interface. func (bc *BarChart) Buffer() []Point { ps := bc.Block.Buffer() bc.layout() diff --git a/block.go b/block.go index 5df8149..33e143b 100644 --- a/block.go +++ b/block.go @@ -4,7 +4,9 @@ package termui -// basic struct, consider it as css: display:block +// Block is a base struct for all other upper level widgets, +// consider it as css: display:block. +// Normally you do not need to create it manually. type Block struct { X int Y int @@ -24,6 +26,7 @@ type Block struct { PaddingRight int } +// NewBlock returns a *Block which inherits styles from current theme. func NewBlock() *Block { d := Block{} d.IsDisplay = true @@ -52,11 +55,13 @@ func (d *Block) align() { d.Border.Y = d.Y d.Border.Width = d.Width d.Border.Height = d.Height - d.innerX += 1 - d.innerY += 1 + d.innerX++ + d.innerY++ } } +// Buffer implements Bufferer interface. +// Draw background and border (if any). func (d *Block) Buffer() []Point { d.align() @@ -82,22 +87,23 @@ func (d *Block) Buffer() []Point { return ps } +// GetHeight implements GridBufferer. +// It returns current height of the block. func (d Block) GetHeight() int { return d.Height } -func (d Block) GetWidth() int { - return d.Width -} - +// SetX implements GridBufferer interface, which sets block's x position. func (d *Block) SetX(x int) { d.X = x } +// SetY implements GridBufferer interface, it sets y position for block. func (d *Block) SetY(y int) { d.Y = y } +// SetWidth implements GridBuffer interface, it sets block's width. func (d *Block) SetWidth(w int) { d.Width = w } diff --git a/box.go b/box.go index 776ef6e..6b500ed 100644 --- a/box.go +++ b/box.go @@ -29,6 +29,7 @@ type vline struct { BgColor Attribute } +// Draw a horizontal line. func (l hline) Buffer() []Point { pts := make([]Point, l.Length) for i := 0; i < l.Length; i++ { @@ -41,6 +42,7 @@ func (l hline) Buffer() []Point { return pts } +// Draw a vertical line. func (l vline) Buffer() []Point { pts := make([]Point, l.Length) for i := 0; i < l.Length; i++ { @@ -53,6 +55,7 @@ func (l vline) Buffer() []Point { return pts } +// Draw a box border. func (b border) Buffer() []Point { if b.Width < 2 || b.Height < 2 { return nil @@ -98,6 +101,7 @@ type labeledBorder struct { LabelBgColor Attribute } +// Draw a box border with label. func (lb labeledBorder) Buffer() []Point { ps := lb.border.Buffer() maxTxtW := lb.Width - 2 diff --git a/chart.go b/chart.go index 05859ac..12771b8 100644 --- a/chart.go +++ b/chart.go @@ -32,8 +32,18 @@ var braillePatterns = map[[2]int]rune{ var lSingleBraille = [4]rune{'\u2840', '⠄', '⠂', '⠁'} var rSingleBraille = [4]rune{'\u2880', '⠠', '⠐', '⠈'} -//var singleBraille = [4]rune{'⣀', '⠤', '⠒', '⠉'} - +// LineChart has two modes: braille(default) and dot. Using braille gives 2x capicity as dot mode, +// because one braille char can represent two data points. +/* + lc := termui.NewLineChart() + lc.Border.Label = "braille-mode Line Chart" + lc.Data = [1.2, 1.3, 1.5, 1.7, 1.5, 1.6, 1.8, 2.0] + lc.Width = 50 + lc.Height = 12 + lc.AxesColor = termui.ColorWhite + lc.LineColor = termui.ColorGreen | termui.AttrBold + // termui.Render(lc)... +*/ type LineChart struct { Block Data []float64 @@ -58,6 +68,7 @@ type LineChart struct { minY float64 } +// NewLineChart returns a new LineChart with current theme. func NewLineChart() *LineChart { lc := &LineChart{Block: *NewBlock()} lc.AxesColor = theme.LineChartAxes @@ -298,6 +309,7 @@ func (lc *LineChart) plotAxes() []Point { return ps } +// Buffer implements Bufferer interface. func (lc *LineChart) Buffer() []Point { ps := lc.Block.Buffer() if lc.Data == nil || len(lc.Data) == 0 { diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..43f886f --- /dev/null +++ b/doc.go @@ -0,0 +1,27 @@ +// Copyright 2015 Zack Guo . All rights reserved. +// Use of this source code is governed by a MIT license that can +// be found in the LICENSE file. + +/* +Package termui is a library designed for creating command line UI. For more info, goto http://github.com/gizak/termui + +A simplest example: + package main + + import ui "github.com/gizak/termui" + + func main() { + if err:=ui.Init(); err != nil { + panic(err) + } + defer ui.Close() + + g := ui.NewGauge() + g.Percent = 50 + g.Width = 50 + g.Border.Label = "Gauge" + + ui.Render(g) + } +*/ +package termui diff --git a/gauge.go b/gauge.go index 107d317..e437899 100644 --- a/gauge.go +++ b/gauge.go @@ -6,6 +6,17 @@ package termui import "strconv" +// Gauge is a progress bar like widget. +// A simple example: +/* + g := termui.NewGauge() + g.Percent = 40 + g.Width = 50 + g.Height = 3 + g.Border.Label = "Slim Gauge" + g.BarColor = termui.ColorRed + g.PercentColor = termui.ColorBlue +*/ type Gauge struct { Block Percent int @@ -13,6 +24,7 @@ type Gauge struct { PercentColor Attribute } +// NewGauge return a new gauge with current theme. func NewGauge() *Gauge { g := &Gauge{ Block: *NewBlock(), @@ -23,6 +35,7 @@ func NewGauge() *Gauge { return g } +// Buffer implements Bufferer interface. func (g *Gauge) Buffer() []Point { ps := g.Block.Buffer() diff --git a/grid.go b/grid.go index d35958c..9cba491 100644 --- a/grid.go +++ b/grid.go @@ -4,8 +4,8 @@ package termui -// Bufferers that can be manipulated by Grid -type LayoutBufferer interface { +// GridBufferer introduces a Bufferer that can be manipulated by Grid. +type GridBufferer interface { Bufferer GetHeight() int SetWidth(int) @@ -13,10 +13,10 @@ type LayoutBufferer interface { SetY(int) } -// build a layout tree +// row builds a layout tree type row struct { - Cols []*row //children - Widget LayoutBufferer // root + Cols []*row //children + Widget GridBufferer // root X int Y int Width int @@ -25,6 +25,7 @@ type row struct { Offset int } +// calculate and set the underlying layout tree's x, y, height and width. func (r *row) calcLayout() { r.assignWidth(r.Width) r.Height = r.solveHeight() @@ -32,6 +33,7 @@ func (r *row) calcLayout() { r.assignY(r.Y) } +// tell if the node is leaf in the tree. func (r *row) isLeaf() bool { return r.Cols == nil || len(r.Cols) == 0 } @@ -40,16 +42,18 @@ func (r *row) isRenderableLeaf() bool { return r.isLeaf() && r.Widget != nil } +// assign widgets' (and their parent rows') width recursively. func (r *row) assignWidth(w int) { cw := int(float64(w*r.Span) / 12) r.SetWidth(cw) - for i, _ := range r.Cols { + for i := range r.Cols { r.Cols[i].assignWidth(cw) } } -// bottom up, return r's total height +// bottom up calc and set rows' (and their widgets') height, +// return r's total height. func (r *row) solveHeight() int { if r.isRenderableLeaf() { r.Height = r.Widget.GetHeight() @@ -74,6 +78,7 @@ func (r *row) solveHeight() int { return maxh } +// recursively assign x position for r tree. func (r *row) assignX(x int) { r.SetX(x) @@ -89,6 +94,7 @@ func (r *row) assignX(x int) { } } +// recursively assign y position to r. func (r *row) assignY(y int) { r.SetY(y) @@ -106,10 +112,12 @@ func (r *row) assignY(y int) { } +// GetHeight implements GridBufferer interface. func (r row) GetHeight() int { return r.Height } +// SetX implements GridBufferer interface. func (r *row) SetX(x int) { r.X = x if r.Widget != nil { @@ -117,6 +125,7 @@ func (r *row) SetX(x int) { } } +// SetY implements GridBufferer interface. func (r *row) SetY(y int) { r.Y = y if r.Widget != nil { @@ -124,6 +133,7 @@ func (r *row) SetY(y int) { } } +// SetWidth implements GridBufferer interface. func (r *row) SetWidth(w int) { r.Width = w if r.Widget != nil { @@ -131,6 +141,7 @@ func (r *row) SetWidth(w int) { } } +// Buffer implements Bufferer interface, // recursively merge all widgets buffer func (r *row) Buffer() []Point { merged := []Point{} @@ -154,6 +165,27 @@ func (r *row) Buffer() []Point { return merged } +// Grid implements 12 columns system. +// A simple example: +/* + import ui "github.com/gizak/termui" + // init and create widgets... + + // build + ui.Body.AddRows( + ui.NewRow( + ui.NewCol(6, 0, widget0), + ui.NewCol(6, 0, widget1)), + ui.NewRow( + ui.NewCol(3, 0, widget2), + ui.NewCol(3, 0, widget30, widget31, widget32), + ui.NewCol(6, 0, widget4))) + + // calculate layout + ui.Body.Align() + + ui.Render(ui.Body) +*/ type Grid struct { Rows []*row Width int @@ -162,23 +194,25 @@ type Grid struct { BgColor Attribute } +// NewGrid returns *Grid with given rows. func NewGrid(rows ...*row) *Grid { return &Grid{Rows: rows} } +// AddRows appends given rows to Grid. func (g *Grid) AddRows(rs ...*row) { g.Rows = append(g.Rows, rs...) } +// NewRow creates a new row out of given columns. func NewRow(cols ...*row) *row { rs := &row{Span: 12, Cols: cols} return rs } -// NewCol accepts: widgets are LayoutBufferer or -// widgets is A NewRow -// Note that if multiple widgets are provided, they will stack up in the col -func NewCol(span, offset int, widgets ...LayoutBufferer) *row { +// NewCol accepts: widgets are LayoutBufferer or widgets is A NewRow. +// Note that if multiple widgets are provided, they will stack up in the col. +func NewCol(span, offset int, widgets ...GridBufferer) *row { r := &row{Span: span, Offset: offset} if widgets != nil && len(widgets) == 1 { @@ -203,7 +237,7 @@ func NewCol(span, offset int, widgets ...LayoutBufferer) *row { return r } -// Calculate each rows' layout +// Align calculate each rows' layout. func (g *Grid) Align() { h := 0 for _, r := range g.Rows { @@ -215,6 +249,7 @@ func (g *Grid) Align() { } } +// Buffer implments Bufferer interface. func (g Grid) Buffer() []Point { ps := []Point{} for _, r := range g.Rows { @@ -223,4 +258,5 @@ func (g Grid) Buffer() []Point { return ps } +// Body corresponds to the entire terminal display region. var Body *Grid diff --git a/list.go b/list.go index 70750d7..131c718 100644 --- a/list.go +++ b/list.go @@ -6,6 +6,29 @@ package termui import "strings" +// List displays []string as its items, +// it has a Overflow option (default is "hidden"), when set to "hidden", +// the item exceeding List's width is truncated, but when set to "wrap", +// the overflowed text breaks into next line. +/* + strs := []string{ + "[0] github.com/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"} + + ls := termui.NewList() + ls.Items = strs + ls.ItemFgColor = termui.ColorYellow + ls.Border.Label = "List" + ls.Height = 7 + ls.Width = 25 + ls.Y = 0 +*/ type List struct { Block Items []string @@ -14,6 +37,7 @@ type List struct { ItemBgColor Attribute } +// NewList returns a new *List with current theme. func NewList() *List { l := &List{Block: *NewBlock()} l.Overflow = "hidden" @@ -22,6 +46,7 @@ func NewList() *List { return l } +// Buffer implements Bufferer interface. func (l *List) Buffer() []Point { ps := l.Block.Buffer() switch l.Overflow { diff --git a/p.go b/p.go index dc519b4..fe03ab0 100644 --- a/p.go +++ b/p.go @@ -4,6 +4,13 @@ package termui +// Par displays a paragraph. +/* + par := termui.NewPar("Simple Text") + par.Height = 3 + par.Width = 17 + par.Border.Label = "Label" +*/ type Par struct { Block Text string @@ -11,6 +18,7 @@ type Par struct { TextBgColor Attribute } +// NewPar returns a new *Par with given text as its content. func NewPar(s string) *Par { return &Par{ Block: *NewBlock(), @@ -19,6 +27,7 @@ func NewPar(s string) *Par { TextBgColor: theme.ParTextBg} } +// Buffer implements Bufferer interface. func (p *Par) Buffer() []Point { ps := p.Block.Buffer() diff --git a/point.go b/point.go index 2289559..c381af9 100644 --- a/point.go +++ b/point.go @@ -4,6 +4,7 @@ package termui +// Point stands for a single cell in terminal. type Point struct { Ch rune Bg Attribute diff --git a/render.go b/render.go index 1316a1c..df09a00 100644 --- a/render.go +++ b/render.go @@ -6,11 +6,13 @@ package termui import tm "github.com/nsf/termbox-go" -// all renderable components should implement this +// Bufferer should be implemented by all renderable components. type Bufferer interface { Buffer() []Point } +// Init initializes termui library. This function should be called before any others. +// After initialization, the library must be finalized by 'Close' function. func Init() error { Body = NewGrid() Body.X = 0 @@ -23,21 +25,26 @@ func Init() error { return tm.Init() } +// Close finalizes termui library, +// should be called after successful initialization when termui's functionality isn't required anymore. func Close() { tm.Close() } +// TermWidth returns the current terminal's width. func TermWidth() int { w, _ := tm.Size() return w } +// TermHeight returns the current terminal's height. func TermHeight() int { _, h := tm.Size() return h } -// render all from left to right, right could overlap on left ones +// Render renders all Bufferer in the given order from left to right, +// right could overlap on left ones. func Render(rs ...Bufferer) { tm.Clear(tm.ColorDefault, toTmAttr(theme.BodyBg)) for _, r := range rs { diff --git a/sparkline.go b/sparkline.go index 5faed2c..db87f39 100644 --- a/sparkline.go +++ b/sparkline.go @@ -6,6 +6,14 @@ package termui import "math" +// Sparkline is like: ▅▆▂▂▅▇▂▂▃▆▆▆▅▃ +/* + 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} + spl := termui.NewSparkline() + spl.Data = data + spl.Title = "Sparkline 0" + spl.LineColor = termui.ColorGreen +*/ type Sparkline struct { Data []int Height int @@ -17,6 +25,12 @@ type Sparkline struct { max int } +// Sparklines is a renderable widget which groups together the given sparklines. +/* + spls := termui.NewSparklines(spl0,spl1,spl2) //... + spls.Height = 2 + spls.Width = 20 +*/ type Sparklines struct { Block Lines []Sparkline @@ -26,11 +40,12 @@ type Sparklines struct { var sparks = []rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'} +// Add appends a given Sparkline to s *Sparklines. func (s *Sparklines) Add(sl Sparkline) { s.Lines = append(s.Lines, sl) } -// return unrenderable single sparkline, need to add it into Sparklines +// NewSparkline returns a unrenderable single sparkline that intended to be added into Sparklines. func NewSparkline() Sparkline { return Sparkline{ Height: 1, @@ -38,6 +53,7 @@ func NewSparkline() Sparkline { LineColor: theme.SparklineLine} } +// NewSparklines return a new *Spaklines with given Sparkline(s), you can always add a new Sparkline later. func NewSparklines(ss ...Sparkline) *Sparklines { s := &Sparklines{Block: *NewBlock(), Lines: ss} return s @@ -79,6 +95,7 @@ func (sl *Sparklines) update() { } } +// Buffer implements Bufferer interface. func (sl *Sparklines) Buffer() []Point { ps := sl.Block.Buffer() sl.update()