mirror of
https://github.com/rivo/tview.git
synced 2024-11-07 03:20:39 +00:00
Added background colors and text attributes to color tags. Resolves #91
This commit is contained in:
parent
74643a2db5
commit
83d0a16fb2
@ -64,6 +64,8 @@ Add your issue here on GitHub. Feel free to get in touch if you have any questio
|
||||
|
||||
(There are no corresponding tags in the project. I only keep such a history in this README.)
|
||||
|
||||
- v0.13 (2018-04-01)
|
||||
- Added background colors and text attributes to color tags.
|
||||
- v0.12 (2018-03-13)
|
||||
- Added "suspended mode" to `Application`.
|
||||
- v0.11 (2018-03-02)
|
||||
|
@ -6,7 +6,7 @@ import "github.com/rivo/tview"
|
||||
func main() {
|
||||
box := tview.NewBox().
|
||||
SetBorder(true).
|
||||
SetTitle("Box Demo")
|
||||
SetTitle("A [red]c[yellow]o[green]l[darkcyan]o[blue]r[darkmagenta]f[red]u[yellow]l[white] [black:red]c[:yellow]o[:green]l[:darkcyan]o[:blue]r[:darkmagenta]f[:red]u[:yellow]l[white:] [::bu]title")
|
||||
if err := tview.NewApplication().SetRoot(box, true).Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
const colorsText = `You can use color tags almost everywhere to partially change the color of a string. Simply put a color name or hex string in square brackets to change the following characters' color. H[green]er[white]e i[yellow]s a[darkcyan]n ex[red]amp[white]le. The tags look like this: [red[] [#00ff00[]`
|
||||
const colorsText = `You can use color tags almost everywhere to partially change the color of a string. Simply put a color name or hex string in square brackets to change the following characters' color. H[green]er[white]e i[yellow]s a[darkcyan]n ex[red]amp[white]le. The [black:red]tags [black:green]look [black:yellow]like [::u]this: [blue:yellow:u[] [#00ff00[]`
|
||||
|
||||
// Colors demonstrates how to use colors.
|
||||
func Colors(nextSlide func()) (title string, content tview.Primitive) {
|
||||
@ -28,6 +28,6 @@ func Colors(nextSlide func()) (title string, content tview.Primitive) {
|
||||
}
|
||||
table.SetBorderPadding(1, 1, 2, 2).
|
||||
SetBorder(true).
|
||||
SetTitle("A [red]c[yellow]o[green]l[darkcyan]o[blue]r[darkmagenta]f[red]u[yellow]l[white] title")
|
||||
return "Colors", Center(73, 19, table)
|
||||
SetTitle("A [red]c[yellow]o[green]l[darkcyan]o[blue]r[darkmagenta]f[red]u[yellow]l[white] [black:red]c[:yellow]o[:green]l[:darkcyan]o[:blue]r[:darkmagenta]f[:red]u[:yellow]l[white:] [::bu]title")
|
||||
return "Colors", Center(78, 19, table)
|
||||
}
|
||||
|
38
doc.go
38
doc.go
@ -77,13 +77,49 @@ applies to almost everything from box titles, list text, form item labels, to
|
||||
table cells. In a TextView, this functionality has to be switched on explicitly.
|
||||
See the TextView documentation for more information.
|
||||
|
||||
Color tags may contain not just the foreground (text) color but also the
|
||||
background color and additional flags. In fact, the full definition of a color
|
||||
tag is as follows:
|
||||
|
||||
[<foreground>:<background>:<flags>]
|
||||
|
||||
Each of the three fields can be left blank and trailing fields can be ommitted.
|
||||
(Empty square brackets "[]", however, are not considered color tags.) Colors
|
||||
that are not specified will be changed. (If the flags field is indicated by a
|
||||
colon but left empty, it will reset any flags.)
|
||||
|
||||
You can specify the following flags (some flags may not be supported by your
|
||||
terminal):
|
||||
|
||||
l: blink
|
||||
b: bold
|
||||
d: dim
|
||||
r: reverse (switch foreground and background color)
|
||||
u: underline
|
||||
|
||||
Examples:
|
||||
|
||||
[yellow]Yellow text
|
||||
[yellow:red]Yellow text on red background
|
||||
[:red]Red background, text color unchanged
|
||||
[yellow::u]Yellow text underlined
|
||||
[::bl]Bold, blinking text
|
||||
[::]Colors unchanged, flags reset
|
||||
[:]No effect
|
||||
[]Not a valid color tag, will print square brackets as they are
|
||||
|
||||
In the rare event that you want to display a string such as "[red]" or
|
||||
"[#00ff1a]" without applying its effect, you need to put an opening square
|
||||
bracket before the closing square bracket. Examples:
|
||||
bracket before the closing square bracket. Note that the text inside the
|
||||
brackets will be matched less strictly than region or colors tags. I.e. any
|
||||
character that may be used in color or region tags will be recognized. Examples:
|
||||
|
||||
[red[] will be output as [red]
|
||||
["123"[] will be output as ["123"]
|
||||
[#6aff00[[] will be output as [#6aff00[]
|
||||
[a#"[[[] will be output as [a#"[[]
|
||||
[] will be output as [] (see color tags above)
|
||||
[[] will be output as [[] (not an escaped tag)
|
||||
|
||||
Styles
|
||||
|
||||
|
2
table.go
2
table.go
@ -590,7 +590,7 @@ ColumnLoop:
|
||||
expansion := 0
|
||||
for _, row := range rows {
|
||||
if cell := getCell(row, column); cell != nil {
|
||||
cellWidth := StringWidth(cell.Text)
|
||||
_, _, _, _, cellWidth := decomposeString(cell.Text)
|
||||
if cell.MaxWidth > 0 && cell.MaxWidth < cellWidth {
|
||||
cellWidth = cell.MaxWidth
|
||||
}
|
||||
|
81
textview.go
81
textview.go
@ -8,6 +8,7 @@ import (
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
colorful "github.com/lucasb-eyer/go-colorful"
|
||||
runewidth "github.com/mattn/go-runewidth"
|
||||
)
|
||||
|
||||
@ -17,12 +18,13 @@ var TabSize = 4
|
||||
// textViewIndex contains information about each line displayed in the text
|
||||
// view.
|
||||
type textViewIndex struct {
|
||||
Line int // The index into the "buffer" variable.
|
||||
Pos int // The index into the "buffer" string (byte position).
|
||||
NextPos int // The (byte) index of the next character in this buffer line.
|
||||
Width int // The screen width of this line.
|
||||
Color tcell.Color // The starting color.
|
||||
Region string // The starting region ID.
|
||||
Line int // The index into the "buffer" variable.
|
||||
Pos int // The index into the "buffer" string (byte position).
|
||||
NextPos int // The (byte) index of the next character in this buffer line.
|
||||
Width int // The screen width of this line.
|
||||
Style tcell.Style // The starting style.
|
||||
OverwriteAttr bool // The starting flag indicating if style attributes should be overwritten.
|
||||
Region string // The starting region ID.
|
||||
}
|
||||
|
||||
// TextView is a box which displays text. It implements the io.Writer interface
|
||||
@ -498,8 +500,8 @@ func (t *TextView) reindexBuffer(width int) {
|
||||
|
||||
// Initial states.
|
||||
regionID := ""
|
||||
var highlighted bool
|
||||
color := t.textColor
|
||||
var highlighted, overwriteAttr bool
|
||||
style := tcell.StyleDefault.Foreground(t.textColor)
|
||||
|
||||
// Go through each line in the buffer.
|
||||
for bufferIndex, str := range t.buffer {
|
||||
@ -507,11 +509,10 @@ func (t *TextView) reindexBuffer(width int) {
|
||||
var (
|
||||
colorTagIndices [][]int
|
||||
colorTags [][]string
|
||||
escapeIndices [][]int
|
||||
)
|
||||
if t.dynamicColors {
|
||||
colorTagIndices = colorPattern.FindAllStringIndex(str, -1)
|
||||
colorTags = colorPattern.FindAllStringSubmatch(str, -1)
|
||||
str = colorPattern.ReplaceAllString(str, "")
|
||||
colorTagIndices, colorTags, escapeIndices, str, _ = decomposeString(str)
|
||||
}
|
||||
|
||||
// Find all regions in this line. Then remove them.
|
||||
@ -523,13 +524,11 @@ func (t *TextView) reindexBuffer(width int) {
|
||||
regionIndices = regionPattern.FindAllStringIndex(str, -1)
|
||||
regions = regionPattern.FindAllStringSubmatch(str, -1)
|
||||
str = regionPattern.ReplaceAllString(str, "")
|
||||
}
|
||||
|
||||
// Find all replace tags in this line. Then replace them.
|
||||
var escapeIndices [][]int
|
||||
if t.dynamicColors || t.regions {
|
||||
escapeIndices = escapePattern.FindAllStringIndex(str, -1)
|
||||
str = escapePattern.ReplaceAllString(str, "[$1$2]")
|
||||
if !t.dynamicColors {
|
||||
// We haven't detected escape tags yet. Do it now.
|
||||
escapeIndices = escapePattern.FindAllStringIndex(str, -1)
|
||||
str = escapePattern.ReplaceAllString(str, "[$1$2]")
|
||||
}
|
||||
}
|
||||
|
||||
// Split the line if required.
|
||||
@ -562,10 +561,11 @@ func (t *TextView) reindexBuffer(width int) {
|
||||
var originalPos, colorPos, regionPos, escapePos int
|
||||
for _, splitLine := range splitLines {
|
||||
line := &textViewIndex{
|
||||
Line: bufferIndex,
|
||||
Pos: originalPos,
|
||||
Color: color,
|
||||
Region: regionID,
|
||||
Line: bufferIndex,
|
||||
Pos: originalPos,
|
||||
Style: style,
|
||||
OverwriteAttr: overwriteAttr,
|
||||
Region: regionID,
|
||||
}
|
||||
|
||||
// Shift original position with tags.
|
||||
@ -574,7 +574,7 @@ func (t *TextView) reindexBuffer(width int) {
|
||||
if colorPos < len(colorTagIndices) && colorTagIndices[colorPos][0] <= originalPos+lineLength {
|
||||
// Process color tags.
|
||||
originalPos += colorTagIndices[colorPos][1] - colorTagIndices[colorPos][0]
|
||||
color = tcell.GetColor(colorTags[colorPos][1])
|
||||
style, overwriteAttr = styleFromTag(style, overwriteAttr, colorTags[colorPos])
|
||||
colorPos++
|
||||
} else if regionPos < len(regionIndices) && regionIndices[regionPos][0] <= originalPos+lineLength {
|
||||
// Process region tags.
|
||||
@ -721,17 +721,18 @@ func (t *TextView) Draw(screen tcell.Screen) {
|
||||
// Get the text for this line.
|
||||
index := t.index[line]
|
||||
text := t.buffer[index.Line][index.Pos:index.NextPos]
|
||||
color := index.Color
|
||||
style := index.Style
|
||||
overwriteAttr := index.OverwriteAttr
|
||||
regionID := index.Region
|
||||
|
||||
// Get color tags.
|
||||
var (
|
||||
colorTagIndices [][]int
|
||||
colorTags [][]string
|
||||
escapeIndices [][]int
|
||||
)
|
||||
if t.dynamicColors {
|
||||
colorTagIndices = colorPattern.FindAllStringIndex(text, -1)
|
||||
colorTags = colorPattern.FindAllStringSubmatch(text, -1)
|
||||
colorTagIndices, colorTags, escapeIndices, _, _ = decomposeString(text)
|
||||
}
|
||||
|
||||
// Get regions.
|
||||
@ -742,12 +743,9 @@ func (t *TextView) Draw(screen tcell.Screen) {
|
||||
if t.regions {
|
||||
regionIndices = regionPattern.FindAllStringIndex(text, -1)
|
||||
regions = regionPattern.FindAllStringSubmatch(text, -1)
|
||||
}
|
||||
|
||||
// Get escape tags.
|
||||
var escapeIndices [][]int
|
||||
if t.dynamicColors || t.regions {
|
||||
escapeIndices = escapePattern.FindAllStringIndex(text, -1)
|
||||
if !t.dynamicColors {
|
||||
escapeIndices = escapePattern.FindAllStringIndex(text, -1)
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the position of the line.
|
||||
@ -770,7 +768,7 @@ func (t *TextView) Draw(screen tcell.Screen) {
|
||||
// Get the color.
|
||||
if currentTag < len(colorTags) && pos >= colorTagIndices[currentTag][0] && pos < colorTagIndices[currentTag][1] {
|
||||
if pos == colorTagIndices[currentTag][1]-1 {
|
||||
color = tcell.GetColor(colorTags[currentTag][1])
|
||||
style, overwriteAttr = styleFromTag(style, overwriteAttr, colorTags[currentTag])
|
||||
currentTag++
|
||||
}
|
||||
continue
|
||||
@ -812,16 +810,27 @@ func (t *TextView) Draw(screen tcell.Screen) {
|
||||
}
|
||||
|
||||
// Do we highlight this character?
|
||||
style := tcell.StyleDefault.Background(t.backgroundColor).Foreground(color)
|
||||
finalStyle := style
|
||||
if len(regionID) > 0 {
|
||||
if _, ok := t.highlights[regionID]; ok {
|
||||
style = tcell.StyleDefault.Background(color).Foreground(t.backgroundColor)
|
||||
fg, bg, _ := finalStyle.Decompose()
|
||||
if bg == tcell.ColorDefault {
|
||||
r, g, b := fg.RGB()
|
||||
c := colorful.Color{R: float64(r) / 255, G: float64(g) / 255, B: float64(b) / 255}
|
||||
_, _, li := c.Hcl()
|
||||
if li < .5 {
|
||||
bg = tcell.ColorWhite
|
||||
} else {
|
||||
bg = tcell.ColorBlack
|
||||
}
|
||||
}
|
||||
finalStyle = style.Background(fg).Foreground(bg)
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the character.
|
||||
for offset := 0; offset < chWidth; offset++ {
|
||||
screen.SetContent(x+posX+offset, y+line-t.lineOffset, ch, nil, style)
|
||||
screen.SetContent(x+posX+offset, y+line-t.lineOffset, ch, nil, finalStyle)
|
||||
}
|
||||
|
||||
// Advance.
|
||||
|
176
util.go
176
util.go
@ -104,13 +104,20 @@ var joints = map[string]rune{
|
||||
|
||||
// Common regular expressions.
|
||||
var (
|
||||
colorPattern = regexp.MustCompile(`\[([a-zA-Z]+|#[0-9a-zA-Z]{6})\]`)
|
||||
colorPattern = regexp.MustCompile(`\[([a-zA-Z]+|#[0-9a-zA-Z]{6})?(:([a-zA-Z]+|#[0-9a-zA-Z]{6})?(:([lbdru]+))?)?\]`)
|
||||
regionPattern = regexp.MustCompile(`\["([a-zA-Z0-9_,;: \-\.]*)"\]`)
|
||||
escapePattern = regexp.MustCompile(`\[("[a-zA-Z0-9_,;: \-\.]*"|[a-zA-Z]+|#[0-9a-zA-Z]{6})\[(\[*)\]`)
|
||||
escapePattern = regexp.MustCompile(`\[([a-zA-Z0-9_,;: \-\."#]+)\[(\[*)\]`)
|
||||
boundaryPattern = regexp.MustCompile("([[:punct:]]\\s*|\\s+)")
|
||||
spacePattern = regexp.MustCompile(`\s+`)
|
||||
)
|
||||
|
||||
// Positions of substrings in regular expressions.
|
||||
const (
|
||||
colorForegroundPos = 1
|
||||
colorBackgroundPos = 3
|
||||
colorFlagPos = 5
|
||||
)
|
||||
|
||||
// Predefined InputField acceptance functions.
|
||||
var (
|
||||
// InputFieldInteger accepts integers.
|
||||
@ -150,40 +157,148 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// styleFromTag takes the given style and modifies it based on the substrings
|
||||
// extracted by the regular expression for color tags. The new style is returned
|
||||
// as well as the flag indicating if any style attributes were explicitly
|
||||
// specified (whose original value is also returned).
|
||||
func styleFromTag(style tcell.Style, overwriteAttr bool, tagSubstrings []string) (tcell.Style, bool) {
|
||||
// Colors.
|
||||
if tagSubstrings[colorForegroundPos] != "" {
|
||||
color := tagSubstrings[colorForegroundPos]
|
||||
if color == "" {
|
||||
style = style.Foreground(tcell.ColorDefault)
|
||||
} else {
|
||||
style = style.Foreground(tcell.GetColor(color))
|
||||
}
|
||||
}
|
||||
if tagSubstrings[colorBackgroundPos-1] != "" {
|
||||
color := tagSubstrings[colorBackgroundPos]
|
||||
if color == "" {
|
||||
style = style.Background(tcell.ColorDefault)
|
||||
} else {
|
||||
style = style.Background(tcell.GetColor(color))
|
||||
}
|
||||
}
|
||||
|
||||
// Flags.
|
||||
specified := tagSubstrings[colorFlagPos-1] != ""
|
||||
if specified {
|
||||
overwriteAttr = true
|
||||
style = style.Normal()
|
||||
for _, flag := range tagSubstrings[colorFlagPos] {
|
||||
switch flag {
|
||||
case 'l':
|
||||
style = style.Blink(true)
|
||||
case 'b':
|
||||
style = style.Bold(true)
|
||||
case 'd':
|
||||
style = style.Dim(true)
|
||||
case 'r':
|
||||
style = style.Reverse(true)
|
||||
case 'u':
|
||||
style = style.Underline(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
return style, overwriteAttr
|
||||
}
|
||||
|
||||
// overlayStyle mixes a bottom and a top style and returns the result. Top
|
||||
// colors (other than tcell.ColorDefault) overwrite bottom colors. Top
|
||||
// style attributes overwrite bottom style attributes only if overwriteAttr is
|
||||
// true.
|
||||
func overlayStyle(bottom, top tcell.Style, overwriteAttr bool) tcell.Style {
|
||||
style := bottom
|
||||
fg, bg, attr := top.Decompose()
|
||||
if bg != tcell.ColorDefault {
|
||||
style = style.Background(bg)
|
||||
}
|
||||
if fg != tcell.ColorDefault {
|
||||
style = style.Foreground(fg)
|
||||
}
|
||||
if overwriteAttr {
|
||||
style = style.Normal()
|
||||
style |= tcell.Style(attr)
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
// decomposeString returns information about a string which may contain color
|
||||
// tags. It returns the indices of the color tags (as returned by
|
||||
// re.FindAllStringIndex()), the color tags themselves (as returned by
|
||||
// re.FindAllStringSubmatch()), the indices of an escaped tags, the string
|
||||
// stripped by any color tags and escaped, and the screen width of the stripped
|
||||
// string.
|
||||
func decomposeString(text string) (colorIndices [][]int, colors [][]string, escapeIndices [][]int, stripped string, width int) {
|
||||
// Get positions of color and escape tags.
|
||||
colorIndices = colorPattern.FindAllStringIndex(text, -1)
|
||||
colors = colorPattern.FindAllStringSubmatch(text, -1)
|
||||
escapeIndices = escapePattern.FindAllStringIndex(text, -1)
|
||||
|
||||
// Because the color pattern detects empty tags, we need to filter them out.
|
||||
for i := len(colorIndices) - 1; i >= 0; i-- {
|
||||
if colorIndices[i][1]-colorIndices[i][0] == 2 {
|
||||
colorIndices = append(colorIndices[:i], colorIndices[i+1:]...)
|
||||
colors = append(colors[:i], colors[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the color tags from the original string.
|
||||
var from int
|
||||
buf := make([]byte, 0, len(text))
|
||||
for _, indices := range colorIndices {
|
||||
buf = append(buf, []byte(text[from:indices[0]])...)
|
||||
from = indices[1]
|
||||
}
|
||||
buf = append(buf, text[from:]...)
|
||||
|
||||
// Escape string.
|
||||
stripped = string(escapePattern.ReplaceAll(buf, []byte("[$1$2]")))
|
||||
|
||||
// Get the width of the stripped string.
|
||||
width = runewidth.StringWidth(stripped)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 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 text color mid-text by inserting a color tag. See the
|
||||
// package description for details.
|
||||
// You can change the colors and text styles mid-text by inserting a color tag.
|
||||
// See the package description for details.
|
||||
//
|
||||
// Returns the number of actual runes printed (not including color 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) {
|
||||
return printWithStyle(screen, text, x, y, maxWidth, align, tcell.StyleDefault.Foreground(color), false)
|
||||
}
|
||||
|
||||
// printWithStyle works like Print() but it takes a style instead of just a
|
||||
// foreground color. The overwriteAttr indicates whether or not a style's
|
||||
// additional attributes (see tcell.AttrMask) should be overwritten.
|
||||
func printWithStyle(screen tcell.Screen, text string, x, y, maxWidth, align int, style tcell.Style, overwriteAttr bool) (int, int) {
|
||||
if maxWidth < 0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// Get positions of color and escape tags. Remove them from original string.
|
||||
colorIndices := colorPattern.FindAllStringIndex(text, -1)
|
||||
colors := colorPattern.FindAllStringSubmatch(text, -1)
|
||||
escapeIndices := escapePattern.FindAllStringIndex(text, -1)
|
||||
strippedText := escapePattern.ReplaceAllString(colorPattern.ReplaceAllString(text, ""), "[$1$2]")
|
||||
// Decompose the text.
|
||||
colorIndices, colors, escapeIndices, strippedText, _ := decomposeString(text)
|
||||
|
||||
// We deal with runes, not with bytes.
|
||||
runes := []rune(strippedText)
|
||||
|
||||
// This helper function takes positions for a substring of "runes" and a start
|
||||
// color and returns the substring with the original tags and the new start
|
||||
// color.
|
||||
substring := func(from, to int, color tcell.Color) (string, tcell.Color) {
|
||||
// style and returns the substring with the original tags and the new start
|
||||
// style.
|
||||
substring := func(from, to int, style tcell.Style, overwriteAttr bool) (string, tcell.Style, bool) {
|
||||
var colorPos, escapePos, runePos, startPos int
|
||||
for pos := range text {
|
||||
// Handle color tags.
|
||||
if colorPos < len(colorIndices) && pos >= colorIndices[colorPos][0] && pos < colorIndices[colorPos][1] {
|
||||
if pos == colorIndices[colorPos][1]-1 {
|
||||
if runePos <= from {
|
||||
color = tcell.GetColor(colors[colorPos][1])
|
||||
style, overwriteAttr = styleFromTag(style, overwriteAttr, colors[colorPos])
|
||||
}
|
||||
colorPos++
|
||||
}
|
||||
@ -203,13 +318,13 @@ func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tc
|
||||
if runePos == from {
|
||||
startPos = pos
|
||||
} else if runePos >= to {
|
||||
return text[startPos:pos], color
|
||||
return text[startPos:pos], style, overwriteAttr
|
||||
}
|
||||
|
||||
runePos++
|
||||
}
|
||||
|
||||
return text[startPos:], color
|
||||
return text[startPos:], style, overwriteAttr
|
||||
}
|
||||
|
||||
// We want to reduce everything to AlignLeft.
|
||||
@ -224,17 +339,17 @@ func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tc
|
||||
width += w
|
||||
start = index
|
||||
}
|
||||
text, color = substring(start, len(runes), color)
|
||||
return Print(screen, text, x+maxWidth-width, y, width, AlignLeft, color)
|
||||
text, style, overwriteAttr = substring(start, len(runes), style, overwriteAttr)
|
||||
return printWithStyle(screen, text, x+maxWidth-width, y, width, AlignLeft, style, overwriteAttr)
|
||||
} else if align == AlignCenter {
|
||||
width := runewidth.StringWidth(strippedText)
|
||||
if width == maxWidth {
|
||||
// Use the exact space.
|
||||
return Print(screen, text, x, y, maxWidth, AlignLeft, color)
|
||||
return printWithStyle(screen, text, x, y, maxWidth, AlignLeft, style, overwriteAttr)
|
||||
} else if width < maxWidth {
|
||||
// We have more space than we need.
|
||||
half := (maxWidth - width) / 2
|
||||
return Print(screen, text, x+half, y, maxWidth-half, AlignLeft, color)
|
||||
return printWithStyle(screen, text, x+half, y, maxWidth-half, AlignLeft, style, overwriteAttr)
|
||||
} else {
|
||||
// Chop off runes until we have a perfect fit.
|
||||
var choppedLeft, choppedRight, leftIndex, rightIndex int
|
||||
@ -250,8 +365,8 @@ func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tc
|
||||
rightIndex--
|
||||
}
|
||||
}
|
||||
text, color = substring(leftIndex, rightIndex, color)
|
||||
return Print(screen, text, x, y, maxWidth, AlignLeft, color)
|
||||
text, style, overwriteAttr = substring(leftIndex, rightIndex, style, overwriteAttr)
|
||||
return printWithStyle(screen, text, x, y, maxWidth, AlignLeft, style, overwriteAttr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,7 +378,7 @@ func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tc
|
||||
// Handle color tags.
|
||||
if colorPos < len(colorIndices) && pos >= colorIndices[colorPos][0] && pos < colorIndices[colorPos][1] {
|
||||
if pos == colorIndices[colorPos][1]-1 {
|
||||
color = tcell.GetColor(colors[colorPos][1])
|
||||
style, overwriteAttr = styleFromTag(style, overwriteAttr, colors[colorPos])
|
||||
colorPos++
|
||||
}
|
||||
continue
|
||||
@ -286,11 +401,11 @@ func Print(screen tcell.Screen, text string, x, y, maxWidth, align int, color tc
|
||||
finalX := x + drawnWidth
|
||||
|
||||
// Print the rune.
|
||||
_, _, style, _ := screen.GetContent(finalX, y)
|
||||
style = style.Foreground(color)
|
||||
_, _, finalStyle, _ := screen.GetContent(finalX, y)
|
||||
finalStyle = overlayStyle(finalStyle, style, overwriteAttr)
|
||||
for offset := 0; offset < chWidth; offset++ {
|
||||
// To avoid undesired effects, we place the same character in all cells.
|
||||
screen.SetContent(finalX+offset, y, ch, nil, style)
|
||||
screen.SetContent(finalX+offset, y, ch, nil, finalStyle)
|
||||
}
|
||||
|
||||
drawn++
|
||||
@ -308,7 +423,8 @@ func PrintSimple(screen tcell.Screen, text string, x, y int) {
|
||||
// StringWidth returns the width of the given string needed to print it on
|
||||
// screen. The text may contain color tags which are not counted.
|
||||
func StringWidth(text string) int {
|
||||
return runewidth.StringWidth(escapePattern.ReplaceAllString(colorPattern.ReplaceAllString(text, ""), "[$1$2]"))
|
||||
_, _, _, _, width := decomposeString(text)
|
||||
return width
|
||||
}
|
||||
|
||||
// WordWrap splits a text such that each resulting line does not exceed the
|
||||
@ -319,13 +435,7 @@ func StringWidth(text string) int {
|
||||
//
|
||||
// Text is always split at newline characters ('\n').
|
||||
func WordWrap(text string, width int) (lines []string) {
|
||||
// Strip color tags.
|
||||
strippedText := escapePattern.ReplaceAllString(colorPattern.ReplaceAllString(text, ""), "[$1$2]")
|
||||
|
||||
// Keep track of color tags and escape patterns so we can restore the original
|
||||
// indices.
|
||||
colorTagIndices := colorPattern.FindAllStringIndex(text, -1)
|
||||
escapeIndices := escapePattern.FindAllStringIndex(text, -1)
|
||||
colorTagIndices, _, escapeIndices, strippedText, _ := decomposeString(text)
|
||||
|
||||
// Find candidate breakpoints.
|
||||
breakPoints := boundaryPattern.FindAllStringIndex(strippedText, -1)
|
||||
|
Loading…
Reference in New Issue
Block a user