tui/utils.go

115 lines
2.9 KiB
Go
Raw Permalink Normal View History

2022-04-01 20:10:51 +02:00
package tui
import (
"strings"
2022-04-02 13:01:41 +02:00
"golang.org/x/text/width"
2022-04-01 20:10:51 +02:00
)
// WriteString writes a whole string to the buffer at position (x,y)
// no word wrap is applied at all. If the string does not fit, it will be truncated
2022-04-02 13:01:41 +02:00
func WriteString(b *ViewBuffer, str string, style Style, x, y int) (width int) {
2022-04-01 20:10:51 +02:00
dx := x
for _, r := range str {
if dx >= b.Width() {
return
}
2022-04-02 13:01:41 +02:00
2022-04-01 20:10:51 +02:00
b.Set(dx, y, Rune{r, style})
2022-04-02 13:01:41 +02:00
dx += runeWidth(r)
2022-04-01 20:10:51 +02:00
}
2022-04-02 13:01:41 +02:00
return dx - x
2022-04-01 20:10:51 +02:00
}
// WriteMultiLineString writes a multi-line string to the buffer at position (x,y)
// no word wrap is applied at all. If a line does not fit horizontally, it will be truncated
// All lines which do not fit vertically will be truncated as well
2022-04-02 13:01:41 +02:00
func WriteMultiLineString(b *ViewBuffer, str string, style Style, x, y int) (maxLineWidth, lineCount int) {
2022-04-01 20:10:51 +02:00
lines := strings.Split(str, "\n")
for dy, line := range lines {
if dy >= b.Height() {
return
}
2022-04-02 13:01:41 +02:00
lineWidth := WriteString(b, line, style, x, y+dy)
maxLineWidth = max(maxLineWidth, lineWidth)
}
return maxLineWidth, len(lines)
}
// MeasureString measures how much horizontal space str consumes when drawn to a buffer
func MeasureString(str string) (width int) {
dx := 0
for _, r := range str {
dx += runeWidth(r)
}
return dx
}
// MeasureString measures how much horizontal and vertical space str consumes when drawn to a buffer
func MeasureMultiLineString(str string) (maxLineWidth, lineCount int) {
lines := strings.Split(str, "\n")
for _, line := range lines {
lineWidth := MeasureString(line)
maxLineWidth = max(maxLineWidth, lineWidth)
}
return maxLineWidth, len(lines)
}
func runeWidth(r rune) int {
//fmt.Println(r, width.LookupRune(r).Kind())
switch width.LookupRune(r).Kind() {
case width.EastAsianFullwidth:
fallthrough
case width.EastAsianWide:
return 2
default:
return 1
}
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
func iff[T any](condition bool, trueValue, falseValue T) T {
if condition {
return trueValue
2022-04-01 20:10:51 +02:00
}
2022-04-02 13:01:41 +02:00
return falseValue
2022-04-01 20:10:51 +02:00
}
2022-04-02 15:09:52 +02:00
func ConstrainBufferToAnchor(buf *ViewBuffer, anchor Anchor, width, height int) *ViewBuffer {
switch anchor {
default:
fallthrough
case AnchorTopLeft:
return buf.Sub(0, 0, width, height)
case AnchorTop:
return buf.Sub(buf.Width()/2-width/2, 0, width, height)
case AnchorTopRight:
return buf.Sub(buf.Width()-width, 0, width, height)
case AnchorLeft:
return buf.Sub(0, buf.Height()/2-height/2, width, height)
case AnchorCenter:
return buf.Sub(buf.Width()/2-width/2, buf.Height()/2-height/2, width, height)
case AnchorRight:
return buf.Sub(buf.Width()-width, buf.Height()/2-height/2, width, height)
case AnchorBottomLeft:
return buf.Sub(0, buf.Height()-height, width, height)
case AnchorBottom:
return buf.Sub(buf.Width()/2-width/2, buf.Height()-height, width, height)
case AnchorBottomRight:
return buf.Sub(buf.Width()-width, buf.Height()-height, width, height)
}
}