1
0
mirror of https://github.com/gdamore/tcell.git synced 2025-04-24 13:48:51 +08:00

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") puts(s, style, 2, row, "Strikethrough")
row++ row++
style = plain.DoubleUnderline(true) style = plain.Underline(tcell.UnderlineStyleDouble)
puts(s, style, 2, row, "Double Underline") puts(s, style, 2, row, "Double Underline")
row++ row++
style = plain.CurlyUnderline(true) style = plain.Underline(tcell.UnderlineStyleCurly)
puts(s, style, 2, row, "Curly Underline") puts(s, style, 2, row, "Curly Underline")
row++ row++
style = plain.DottedUnderline(true) style = plain.Underline(tcell.UnderlineStyleDotted)
puts(s, style, 2, row, "Dotted Underline") puts(s, style, 2, row, "Dotted Underline")
row++ row++
style = plain.DashedUnderline(true) style = plain.Underline(tcell.UnderlineStyleDashed)
puts(s, style, 2, row, "Dashed Underline") puts(s, style, 2, row, "Dashed Underline")
row++ row++
style = plain.Underline(true).UnderlineColor(tcell.ColorBlue) style = plain.Underline(true, tcell.ColorBlue)
puts(s, style, 2, row, "Blue Underline") puts(s, style, 2, row, "Blue Underline")
row++ row++
style = plain.Underline(true).UnderlineColor(tcell.ColorHoneydew) style = plain.Underline(tcell.UnderlineStyleSolid, tcell.ColorHoneydew)
puts(s, style, 2, row, "Honeydew Underline") puts(s, style, 2, row, "Honeydew Underline")
row++ 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") puts(s, style, 2, row, "Pink Curly Underline")
row++ row++

View File

@ -25,14 +25,10 @@ const (
AttrBold AttrMask = 1 << iota AttrBold AttrMask = 1 << iota
AttrBlink AttrBlink
AttrReverse AttrReverse
AttrUnderline AttrUnderline // Deprecated: Use UnderlineStyle
AttrDim AttrDim
AttrItalic AttrItalic
AttrStrikeThrough AttrStrikeThrough
AttrDoubleUnderline
AttrCurlyUnderline
AttrDottedUnderline
AttrDashedUnderline
AttrInvalid AttrMask = 1 << 31 // Mark the style or attributes invalid AttrInvalid AttrMask = 1 << 31 // Mark the style or attributes invalid
AttrNone AttrMask = 0 // Just normal text. 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) { func (s *cScreen) sendVtStyle(style Style) {
esc := &strings.Builder{} 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) esc.WriteString(vtSgr0)
if attrs&(AttrBold|AttrDim) == AttrBold { if attrs&(AttrBold|AttrDim) == AttrBold {
esc.WriteString(vtBold) esc.WriteString(vtBold)
} }
if attrs&AttrBlink != 0 { if attrs&AttrBlink != 0 {
esc.WriteString(vtBlink) esc.WriteString(vtBlink)
} }
if attrs&(AttrUnderline|AttrDoubleUnderline|AttrCurlyUnderline|AttrDottedUnderline|AttrDashedUnderline) != 0 { if us != UnderlineStyleNone {
if uc.Valid() {
if uc == ColorReset { if uc == ColorReset {
esc.WriteString(vtUnderColorReset) esc.WriteString(vtUnderColorReset)
} else if uc.IsRGB() { } else if uc.IsRGB() {
r, g, b := uc.RGB() r, g, b := uc.RGB()
_, _ = fmt.Fprintf(esc, vtUnderColorRGB, int(r), int(g), int(b)) _, _ = fmt.Fprintf(esc, vtUnderColorRGB, int(r), int(g), int(b))
} else { } else if uc.Valid() {
_, _ = fmt.Fprintf(esc, vtUnderColor, uc&0xff) _, _ = fmt.Fprintf(esc, vtUnderColor, uc&0xff)
} }
} }
esc.WriteString(vtUnderline) esc.WriteString(vtUnderline)
// legacy ConHost does not understand these but Terminal does // legacy ConHost does not understand these but Terminal does
if (attrs & AttrDoubleUnderline) != 0 { switch us {
case UnderlineStyleSolid:
case UnderlineStyleDouble:
esc.WriteString(vtDoubleUnderline) esc.WriteString(vtDoubleUnderline)
} else if (attrs & AttrCurlyUnderline) != 0 { case UnderlineStyleCurly:
esc.WriteString(vtCurlyUnderline) esc.WriteString(vtCurlyUnderline)
} else if (attrs & AttrDottedUnderline) != 0 { case UnderlineStyleDotted:
esc.WriteString(vtDottedUnderline) esc.WriteString(vtDottedUnderline)
} else if (attrs & AttrDashedUnderline) != 0 { case UnderlineStyleDashed:
esc.WriteString(vtDashedUnderline) esc.WriteString(vtDashedUnderline)
} }
} }

View File

@ -25,7 +25,8 @@ package tcell
type Style struct { type Style struct {
fg Color fg Color
bg Color bg Color
under Color ulStyle UnderlineStyle
ulColor Color
attrs AttrMask attrs AttrMask
url string url string
urlId string urlId string
@ -111,36 +112,55 @@ func (s Style) Reverse(on bool) Style {
return s.setAttrs(AttrReverse, on) 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. // StrikeThrough sets strikethrough mode.
func (s Style) StrikeThrough(on bool) Style { func (s Style) StrikeThrough(on bool) Style {
return s.setAttrs(AttrStrikeThrough, on) return s.setAttrs(AttrStrikeThrough, on)
} }
func (s Style) DoubleUnderline(on bool) Style { // Underline style. Modern terminals have the option of rendering the
return s.setAttrs(AttrDoubleUnderline, on) // underline using different styles, and even different colors.
} type UnderlineStyle int
func (s Style) CurlyUnderline(on bool) Style { const (
return s.setAttrs(AttrCurlyUnderline, on) UnderlineStyleNone = UnderlineStyle(iota)
} UnderlineStyleSolid
UnderlineStyleDouble
UnderlineStyleCurly
UnderlineStyleDotted
UnderlineStyleDashed
)
func (s Style) DottedUnderline(on bool) Style { // Underline returns a new style based on s, with the underline attribute set
return s.setAttrs(AttrDottedUnderline, on) // as requested. The parameters can be:
} //
// bool: on / off - enables just a simple underline
func (s Style) DashedUnderline(on bool) Style { // UnderlineStyle: sets a specific style (should not coexist with the bool)
return s.setAttrs(AttrDashedUnderline, on) // Color: the color to use
} func (s Style) Underline(params ...interface{}) Style {
func (s Style) UnderlineColor(c Color) Style {
s2 := s 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 return s2
} }

View File

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