Underline API change.

The underline styles are mutually exclusive.  And let's simplify
passing the color with the underline style in a single function call.
This commit is contained in:
Garrett D'Amore 2024-03-04 23:56:23 -08:00
parent 826c271964
commit 9bc5c636ae
5 changed files with 75 additions and 57 deletions

View File

@ -155,31 +155,31 @@ func main() {
puts(s, style, 2, row, "Strikethrough")
row++
style = plain.DoubleUnderline(true)
style = plain.Underline(tcell.UnderlineStyleDouble)
puts(s, style, 2, row, "Double Underline")
row++
style = plain.CurlyUnderline(true)
style = plain.Underline(tcell.UnderlineStyleCurly)
puts(s, style, 2, row, "Curly Underline")
row++
style = plain.DottedUnderline(true)
style = plain.Underline(tcell.UnderlineStyleDotted)
puts(s, style, 2, row, "Dotted Underline")
row++
style = plain.DashedUnderline(true)
style = plain.Underline(tcell.UnderlineStyleDashed)
puts(s, style, 2, row, "Dashed Underline")
row++
style = plain.Underline(true).UnderlineColor(tcell.ColorBlue)
style = plain.Underline(true, tcell.ColorBlue)
puts(s, style, 2, row, "Blue Underline")
row++
style = plain.Underline(true).UnderlineColor(tcell.ColorHoneydew)
style = plain.Underline(tcell.UnderlineStyleSolid, tcell.ColorHoneydew)
puts(s, style, 2, row, "Honeydew Underline")
row++
style = plain.CurlyUnderline(true).UnderlineColor(tcell.NewRGBColor(0xc5, 0x8a, 0xf9))
style = plain.Underline(tcell.UnderlineStyleCurly, tcell.NewRGBColor(0xc5, 0x8a, 0xf9))
puts(s, style, 2, row, "Pink Curly Underline")
row++

View File

@ -25,14 +25,10 @@ const (
AttrBold AttrMask = 1 << iota
AttrBlink
AttrReverse
AttrUnderline
AttrUnderline // Deprecated: Use UnderlineStyle
AttrDim
AttrItalic
AttrStrikeThrough
AttrDoubleUnderline
AttrCurlyUnderline
AttrDottedUnderline
AttrDashedUnderline
AttrInvalid AttrMask = 1 << 31 // Mark the style or attributes invalid
AttrNone AttrMask = 0 // Just normal text.
)

View File

@ -919,37 +919,38 @@ func (s *cScreen) mapStyle(style Style) uint16 {
func (s *cScreen) sendVtStyle(style Style) {
esc := &strings.Builder{}
fg, bg, uc, attrs := style.fg, style.bg, style.under, style.attrs
fg, bg, attrs := style.fg, style.bg, style.attrs
us, uc := style.ulStyle, style.ulColor
esc.WriteString(vtSgr0)
if attrs&(AttrBold|AttrDim) == AttrBold {
esc.WriteString(vtBold)
}
if attrs&AttrBlink != 0 {
esc.WriteString(vtBlink)
}
if attrs&(AttrUnderline|AttrDoubleUnderline|AttrCurlyUnderline|AttrDottedUnderline|AttrDashedUnderline) != 0 {
if uc.Valid() {
if us != UnderlineStyleNone {
if uc == ColorReset {
esc.WriteString(vtUnderColorReset)
} else if uc.IsRGB() {
r, g, b := uc.RGB()
_, _ = fmt.Fprintf(esc, vtUnderColorRGB, int(r), int(g), int(b))
} else {
} else if uc.Valid() {
_, _ = fmt.Fprintf(esc, vtUnderColor, uc&0xff)
}
}
esc.WriteString(vtUnderline)
// legacy ConHost does not understand these but Terminal does
if (attrs & AttrDoubleUnderline) != 0 {
switch us {
case UnderlineStyleSolid:
case UnderlineStyleDouble:
esc.WriteString(vtDoubleUnderline)
} else if (attrs & AttrCurlyUnderline) != 0 {
case UnderlineStyleCurly:
esc.WriteString(vtCurlyUnderline)
} else if (attrs & AttrDottedUnderline) != 0 {
case UnderlineStyleDotted:
esc.WriteString(vtDottedUnderline)
} else if (attrs & AttrDashedUnderline) != 0 {
case UnderlineStyleDashed:
esc.WriteString(vtDashedUnderline)
}
}

View File

@ -23,12 +23,13 @@ package tcell
//
// To use Style, just declare a variable of its type.
type Style struct {
fg Color
bg Color
under Color
attrs AttrMask
url string
urlId string
fg Color
bg Color
ulStyle UnderlineStyle
ulColor Color
attrs AttrMask
url string
urlId string
}
// StyleDefault represents a default style, based upon the context.
@ -111,36 +112,55 @@ func (s Style) Reverse(on bool) Style {
return s.setAttrs(AttrReverse, on)
}
// Underline returns a new style based on s, with the underline attribute set
// as requested.
func (s Style) Underline(on bool) Style {
return s.setAttrs(AttrUnderline, on)
}
// StrikeThrough sets strikethrough mode.
func (s Style) StrikeThrough(on bool) Style {
return s.setAttrs(AttrStrikeThrough, on)
}
func (s Style) DoubleUnderline(on bool) Style {
return s.setAttrs(AttrDoubleUnderline, on)
}
// Underline style. Modern terminals have the option of rendering the
// underline using different styles, and even different colors.
type UnderlineStyle int
func (s Style) CurlyUnderline(on bool) Style {
return s.setAttrs(AttrCurlyUnderline, on)
}
const (
UnderlineStyleNone = UnderlineStyle(iota)
UnderlineStyleSolid
UnderlineStyleDouble
UnderlineStyleCurly
UnderlineStyleDotted
UnderlineStyleDashed
)
func (s Style) DottedUnderline(on bool) Style {
return s.setAttrs(AttrDottedUnderline, on)
}
func (s Style) DashedUnderline(on bool) Style {
return s.setAttrs(AttrDashedUnderline, on)
}
func (s Style) UnderlineColor(c Color) Style {
// Underline returns a new style based on s, with the underline attribute set
// as requested. The parameters can be:
//
// bool: on / off - enables just a simple underline
// UnderlineStyle: sets a specific style (should not coexist with the bool)
// Color: the color to use
func (s Style) Underline(params ...interface{}) Style {
s2 := s
s2.under = c
for _, param := range params {
switch v := param.(type) {
case bool:
if v {
s2.ulStyle = UnderlineStyleSolid
s2.attrs |= AttrUnderline
} else {
s2.ulStyle = UnderlineStyleNone
s2.attrs &^= AttrUnderline
}
case UnderlineStyle:
if v == UnderlineStyleNone {
s2.attrs &^= AttrUnderline
} else {
s2.attrs |= AttrUnderline
}
s2.ulStyle = v
case Color:
s2.ulColor = v
default:
panic("Bad type for underline")
}
}
return s2
}

View File

@ -796,7 +796,7 @@ func (t *tScreen) drawCell(x, y int) int {
style = t.style
}
if style != t.curstyle {
fg, bg, attrs, uc := style.fg, style.bg, style.attrs, style.under
fg, bg, attrs := style.fg, style.bg, style.attrs
t.TPuts(ti.AttrOff)
@ -804,8 +804,8 @@ func (t *tScreen) drawCell(x, y int) int {
if attrs&AttrBold != 0 {
t.TPuts(ti.Bold)
}
if attrs&(AttrUnderline|AttrDoubleUnderline|AttrCurlyUnderline|AttrDottedUnderline|AttrDashedUnderline) != 0 {
if uc.Valid() && (t.underColor != "" || t.underRGB != "") {
if us, uc := style.ulStyle, style.ulColor; us != UnderlineStyleNone {
if t.underColor != "" || t.underRGB != "" {
if uc == ColorReset {
t.TPuts(t.underFg)
} else if uc.IsRGB() {
@ -822,18 +822,19 @@ func (t *tScreen) drawCell(x, y int) int {
}
t.TPuts(ti.TParm(t.underColor, int(uc&0xff)))
}
} else {
} else if uc.Valid() {
t.TPuts(ti.TParm(t.underColor, int(uc&0xff)))
}
}
t.TPuts(ti.Underline) // to ensure everyone gets at least a basic underline
if (attrs & AttrDoubleUnderline) != 0 {
switch us {
case UnderlineStyleDouble:
t.TPuts(t.doubleUnder)
} else if (attrs & AttrCurlyUnderline) != 0 {
case UnderlineStyleCurly:
t.TPuts(t.curlyUnder)
} else if (attrs & AttrDottedUnderline) != 0 {
case UnderlineStyleDotted:
t.TPuts(t.dottedUnder)
} else if (attrs & AttrDashedUnderline) != 0 {
case UnderlineStyleDashed:
t.TPuts(t.dashedUnder)
}
}