123 lines
2.5 KiB
Go
123 lines
2.5 KiB
Go
|
package goterm
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
const DEFAULT_BORDER = "- │ ┌ ┐ └ ┘"
|
||
|
|
||
|
// Box allows you to create independent parts of screen, with its own buffer and borders.
|
||
|
// Can be used for creating modal windows
|
||
|
//
|
||
|
// Generates boxes likes this:
|
||
|
// ┌--------┐
|
||
|
// │hello │
|
||
|
// │world │
|
||
|
// │ │
|
||
|
// └--------┘
|
||
|
//
|
||
|
type Box struct {
|
||
|
Buf *bytes.Buffer
|
||
|
|
||
|
Width int
|
||
|
Height int
|
||
|
|
||
|
// To get even padding: PaddingX ~= PaddingY*4
|
||
|
PaddingX int
|
||
|
PaddingY int
|
||
|
|
||
|
// Should contain 6 border pieces separated by spaces
|
||
|
//
|
||
|
// Example border:
|
||
|
// "- │ ┌ ┐ └ ┘"
|
||
|
Border string
|
||
|
|
||
|
Flags int // Not used now
|
||
|
}
|
||
|
|
||
|
// Create new Box.
|
||
|
// Width and height can be relative:
|
||
|
//
|
||
|
// // Create box with 50% with of current screen and 10 lines height
|
||
|
// box := tm.NewBox(50|tm.PCT, 10, 0)
|
||
|
//
|
||
|
func NewBox(width, height int, flags int) *Box {
|
||
|
width, height = GetXY(width, height)
|
||
|
|
||
|
box := new(Box)
|
||
|
box.Buf = new(bytes.Buffer)
|
||
|
box.Width = width
|
||
|
box.Height = height
|
||
|
box.Border = DEFAULT_BORDER
|
||
|
box.PaddingX = 1
|
||
|
box.PaddingY = 0
|
||
|
box.Flags = flags
|
||
|
|
||
|
return box
|
||
|
}
|
||
|
|
||
|
func (b *Box) Write(p []byte) (int, error) {
|
||
|
return b.Buf.Write(p)
|
||
|
}
|
||
|
|
||
|
// Render Box
|
||
|
func (b *Box) String() (out string) {
|
||
|
borders := strings.Split(b.Border, " ")
|
||
|
lines := strings.Split(b.Buf.String(), "\n")
|
||
|
|
||
|
// Border + padding
|
||
|
prefix := borders[1] + strings.Repeat(" ", b.PaddingX)
|
||
|
suffix := strings.Repeat(" ", b.PaddingX) + borders[1]
|
||
|
|
||
|
offset := b.PaddingY + 1 // 1 is border width
|
||
|
|
||
|
// Content width without borders and padding
|
||
|
contentWidth := b.Width - (b.PaddingX+1)*2
|
||
|
|
||
|
for y := 0; y < b.Height; y++ {
|
||
|
var line string
|
||
|
|
||
|
switch {
|
||
|
// Draw borders for first line
|
||
|
case y == 0:
|
||
|
line = borders[2] + strings.Repeat(borders[0], b.Width-2) + borders[3]
|
||
|
|
||
|
// Draw borders for last line
|
||
|
case y == (b.Height - 1):
|
||
|
line = borders[4] + strings.Repeat(borders[0], b.Width-2) + borders[5]
|
||
|
|
||
|
// Draw top and bottom padding
|
||
|
case y <= b.PaddingY || y >= (b.Height-b.PaddingY):
|
||
|
line = borders[1] + strings.Repeat(" ", b.Width-2) + borders[1]
|
||
|
|
||
|
// Render content
|
||
|
default:
|
||
|
if len(lines) > y-offset {
|
||
|
line = lines[y-offset]
|
||
|
} else {
|
||
|
line = ""
|
||
|
}
|
||
|
|
||
|
if len(line) > contentWidth-1 {
|
||
|
// If line is too large limit it
|
||
|
line = line[0:contentWidth]
|
||
|
} else {
|
||
|
// If line is too small enlarge it by adding spaces
|
||
|
line = line + strings.Repeat(" ", contentWidth-len(line))
|
||
|
}
|
||
|
|
||
|
line = prefix + line + suffix
|
||
|
}
|
||
|
|
||
|
// Don't add newline for last element
|
||
|
if y != b.Height-1 {
|
||
|
line = line + "\n"
|
||
|
}
|
||
|
|
||
|
out += line
|
||
|
}
|
||
|
|
||
|
return out
|
||
|
}
|