| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 | package doorimport (	"log"	"strings")type BorderStyle intconst (	NONE BorderStyle = iota	SINGLE	DOUBLE	DOUBLE_SINGLE	SINGLE_DOUBLE)type Panel struct {	X           int	Y           int	Width       int	Style       BorderStyle	BorderColor string	Lines       []Line	Title       string	TitleColor  string	TitleOffset int}// Output the panelfunc (p *Panel) Output() string {	var style int = int(p.Style)	var box_style *BoxStyle	var output string	if style > 0 {		box_style = &BOXES[style-1]	}	var row int = p.Y	if style > 0 {		// Top line / border		output += Goto(p.X, row) + p.BorderColor + box_style.top_left		if p.Title != "" {			if p.TitleOffset+len(p.Title) > p.Width {				log.Panicf("Panel (not wide enough) Width %d : Title size %d + offset %d = %d\n",					p.Width, len(p.Title), p.TitleOffset, p.TitleOffset+len(p.Title))			}			output += strings.Repeat(box_style.top, p.TitleOffset) + p.TitleColor + p.Title + p.BorderColor		}		output += strings.Repeat(box_style.top, p.Width-(p.TitleOffset+len(p.Title))) + box_style.top_right		row++	}	for _, line := range p.Lines {		output += Goto(p.X, row)		line.LineLength(&line.Text)		var joined bool = false		if style > 0 {			top := box_style.top			if line.Text[0:len(top)] == top {				// Yes, this line needs to be joined...				output += p.BorderColor + box_style.middle_left + line.Output() + p.BorderColor + box_style.middle_right				joined = true			}		}		if !joined {			if style > 0 {				output += p.BorderColor + box_style.side			}			output += line.Output()			if style > 0 {				output += p.BorderColor + box_style.side			}		}		row++	}	if style > 0 {		// Bottom / border		output += Goto(p.X, row) + p.BorderColor + box_style.bottom_left		output += strings.Repeat(box_style.top, p.Width) + box_style.bottom_right	}	return output}// Output anything that has updatedfunc (p *Panel) Update() string {	var output string	var style int = int(p.Style)	var row, col int	row = p.Y	col = p.X	if style > 0 {		row++		col++	}	for idx := range p.Lines {		if p.Lines[idx].Update() {			// Yes, line was updated			output += Goto(col, row) + p.Lines[idx].Output()		}		row++	}	return output}// Output the updated linefunc (p *Panel) UpdateLine(index int) string {	var output string	var style int = int(p.Style)	p.Lines[index].Update()	var row, col int	row = p.Y + index	col = p.X	if style > 0 {		row++		col++	}	var line *Line = &p.Lines[index]	output += Goto(col, row) + line.Output()	return output}// Goto the endfunc (p *Panel) GotoEnd() string {	var row, col int	row = p.Y	col = p.X	if p.Style > 0 {		row++		col += 2	}	row += len(p.Lines)	col += p.Width	return Goto(col, row)}// Is the top line of this style a single line?func Single(bs BorderStyle) bool {	switch bs {	case SINGLE, SINGLE_DOUBLE:		return true	default:		return false	}}// Create a spacer line that will be connected maybe to the sides.func (p *Panel) Spacer() Line {	var l Line = Line{}	var pos int	if Single(p.Style) {		pos = 0	} else {		pos = 1	}	l.Text = strings.Repeat(BOXES[pos].top, p.Width)	return l}func (p *Panel) Center() {	p.CenterX()	p.CenterY()}func (p *Panel) CenterX() {	p.X = (Width - p.Width) / 2}func (p *Panel) CenterY() {	p.Y = (Height - len(p.Lines)) / 2}
 |