2022-04-01 20:10:51 +02:00
|
|
|
package tui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
2022-04-02 13:01:41 +02:00
|
|
|
|
2022-04-03 16:29:01 +02:00
|
|
|
"github.com/mattn/go-runewidth"
|
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 {
|
2022-04-03 16:29:01 +02:00
|
|
|
return runewidth.RuneWidth(r)
|
2022-04-02 13:01:41 +02:00
|
|
|
//fmt.Println(r, width.LookupRune(r).Kind())
|
2022-04-03 16:29:01 +02:00
|
|
|
// switch width.LookupRune(r).Kind() {
|
|
|
|
// case width.EastAsianFullwidth:
|
|
|
|
// fallthrough
|
|
|
|
// case width.EastAsianWide:
|
|
|
|
// return 2
|
|
|
|
// default:
|
|
|
|
// return 1
|
|
|
|
// }
|
2022-04-02 13:01:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|