summaryrefslogtreecommitdiff
path: root/vendor/github.com/buger/goterm/box.go
blob: 7df929d7dc949c18c2e7d4a73571bbf39fb12817 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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
}