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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
package tview
import (
"math"
"os"
"regexp"
"github.com/gdamore/tcell/v2"
)
// Text alignment within a box. Also used to align images.
const (
AlignLeft = iota
AlignCenter
AlignRight
AlignTop = 0
AlignBottom = 2
)
var (
// Regular expression used to escape style/region tags.
nonEscapePattern = regexp.MustCompile(`(\[[a-zA-Z0-9_,;: \-\."#]+\[*)\]`)
// The number of colors available in the terminal.
availableColors = 256
)
// Package initialization.
func init() {
// Determine the number of colors available in the terminal.
info, err := tcell.LookupTerminfo(os.Getenv("TERM"))
if err == nil {
availableColors = info.Colors
}
}
// Print prints text onto the screen into the given box at (x,y,maxWidth,1),
// not exceeding that box. "align" is one of AlignLeft, AlignCenter, or
// AlignRight. The screen's background color will not be changed.
//
// You can change the colors and text styles mid-text by inserting a style tag.
// See the package description for details.
//
// Returns the number of actual bytes of the text printed (including style tags)
// and the actual width used for the printed runes.
func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tcell.Color) (int, int) {
start, end, width := printWithStyle(screen, text, x, y, 0, maxWidth, align, tcell.StyleDefault.Foreground(color), true)
return end - start, width
}
// printWithStyle works like Print() but it takes a style instead of just a
// foreground color. The skipWidth parameter specifies the number of cells
// skipped at the beginning of the text. It returns the start index, end index
// (exclusively), and screen width of the text actually printed. If
// maintainBackground is "true", the existing screen background is not changed
// (i.e. the style's background color is ignored).
func printWithStyle(screen tcell.Screen, text string, x, y, skipWidth, maxWidth, align int, style tcell.Style, maintainBackground bool) (start, end, printedWidth int) {
totalWidth, totalHeight := screen.Size()
if maxWidth <= 0 || len(text) == 0 || y < 0 || y >= totalHeight {
return 0, 0, 0
}
// If we don't overwrite the background, we use the default color.
if maintainBackground {
style = style.Background(tcell.ColorDefault)
}
// Skip beginning and measure width.
var (
state *stepState
textWidth int
)
str := text
for len(str) > 0 {
_, str, state = step(str, state, stepOptionsStyle)
if skipWidth > 0 {
skipWidth -= state.Width()
if skipWidth <= 0 {
text = str
style = state.Style()
}
start += state.GrossLength()
} else {
textWidth += state.Width()
}
}
// Reduce all alignments to AlignLeft.
if align == AlignRight {
// Chop off characters on the left until it fits.
state = nil
for len(text) > 0 && textWidth > maxWidth {
_, text, state = step(text, state, stepOptionsStyle)
textWidth -= state.Width()
start += state.GrossLength()
style = state.Style()
}
x, maxWidth = x+maxWidth-textWidth, textWidth
} else if align == AlignCenter {
// Chop off characters on the left until it fits.
state = nil
subtracted := (textWidth - maxWidth) / 2
for len(text) > 0 && subtracted > 0 {
_, text, state = step(text, state, stepOptionsStyle)
subtracted -= state.Width()
textWidth -= state.Width()
start += state.GrossLength()
style = state.Style()
}
if textWidth < maxWidth {
x, maxWidth = x+maxWidth/2-textWidth/2, textWidth
}
}
// Draw left-aligned text.
end = start
rightBorder := x + maxWidth
state = &stepState{
unisegState: -1,
style: style,
}
for len(text) > 0 && x < rightBorder && x < totalWidth {
var c string
c, text, state = step(text, state, stepOptionsStyle)
if c == "" {
break // We don't care about the style at the end.
}
width := state.Width()
if width > 0 {
finalStyle := state.Style()
if maintainBackground {
_, backgroundColor, _ := finalStyle.Decompose()
if backgroundColor == tcell.ColorDefault {
_, _, existingStyle, _ := screen.GetContent(x, y)
_, background, _ := existingStyle.Decompose()
finalStyle = finalStyle.Background(background)
}
}
for offset := width - 1; offset >= 0; offset-- {
// To avoid undesired effects, we populate all cells.
runes := []rune(c)
if offset == 0 {
screen.SetContent(x+offset, y, runes[0], runes[1:], finalStyle)
} else {
screen.SetContent(x+offset, y, ' ', nil, finalStyle)
}
}
}
x += width
end += state.GrossLength()
printedWidth += width
}
return
}
// PrintSimple prints white text to the screen at the given position.
func PrintSimple(screen tcell.Screen, text string, x, y int) {
Print(screen, text, x, y, math.MaxInt32, AlignLeft, Styles.PrimaryTextColor)
}
|