v0.2.2 tui update, reverse row bar
This commit is contained in:
8 files changed
+183
-86
No files matched your search
+7
-5
@@ -125,9 +125,11 @@ draws alike in each: `DefaultTheme` is dark true color, `Theme16` uses the
|
||||
ANSI 16 on the terminal's own background, `MonoTheme` uses attributes
|
||||
alone, and `ThemeFor(term.ColorMode())` picks among them. A selection
|
||||
always changes a glyph (a radio mark, a pointer, the focus mark), so it reads
|
||||
without color. `GlyphsUnicode`, `GlyphsCP437` (text consoles) and
|
||||
`GlyphsASCII` (outside UTF-8) are the glyph sets; `Glyphs.Line` is the line
|
||||
type of frames, rules and wires.
|
||||
without color. A reverse-video `Selected` with no color of its own
|
||||
(`Theme16`, `MonoTheme`) keeps the terminal's own foreground in every cell
|
||||
drawn on it, so the cursor row is one bar. `GlyphsUnicode`, `GlyphsCP437`
|
||||
(text consoles) and `GlyphsASCII` (outside UTF-8) are the glyph sets;
|
||||
`Glyphs.Line` is the line type of frames, rules and wires.
|
||||
|
||||
```go
|
||||
th := tui.DefaultTheme
|
||||
@@ -257,8 +259,8 @@ Pure logic, no rendering — usable independently:
|
||||
|
||||
## Notes
|
||||
|
||||
- Width calculations count runes, not terminal columns; East Asian wide
|
||||
characters and combining marks are not width-aware.
|
||||
- Width calculations count runes, one column each, as `Flush` draws a wide or
|
||||
joining rune as U+FFFD.
|
||||
- Zero-value `color.RGB` in style fields generally means "inherit"
|
||||
(widget default or row background) — check specific widget docs. A zero
|
||||
background with no Bg color bits is transparent: the cell keeps the
|
||||
|
||||
+7
-1
@@ -25,11 +25,17 @@ func (s Style) IsZero() bool {
|
||||
}
|
||||
|
||||
// On returns s drawn on bg: s's foreground, bg's background (s's own where
|
||||
// bg's is transparent), and the attributes of both
|
||||
// bg's is transparent), and the attributes of both. On a reverse bg with no
|
||||
// color of its own, s keeps only its background, with the terminal's own
|
||||
// foreground and bg's styles: a reversed cell's background is its foreground
|
||||
// (a console's keeps its intensity), so mixed styles would break the bar.
|
||||
func (s Style) On(bg Style) Style {
|
||||
out := Style{Fg: s.Fg, Bg: s.Bg, Attr: s.Attr | bg.Attr&terminal.AttrStyle}
|
||||
if bg.Bg != (color.RGB{}) || bg.Attr&terminal.AttrBgColor != 0 {
|
||||
out.Bg, out.Attr = bg.Bg, out.Attr&^terminal.AttrBgColor|bg.Attr&terminal.AttrBgColor
|
||||
}
|
||||
if bg.Attr&terminal.AttrReverse != 0 && bg.Bg == (color.RGB{}) && bg.Attr&terminal.AttrBg256 == 0 {
|
||||
out.Fg, out.Attr = color.RGB{}, terminal.AttrFgDefault|out.Attr&terminal.AttrBgColor|bg.Attr&terminal.AttrStyle
|
||||
}
|
||||
return out
|
||||
}
|
||||
+2
-18
@@ -5,16 +5,12 @@ import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// --- Length calculation ---
|
||||
|
||||
// RuneLen returns rune count, used as display width under the package-wide assumption of 1 cell per rune
|
||||
// Wide (CJK), emoji, and combining characters are not handled
|
||||
// RuneLen returns s's width in cells, a rune each: Flush draws every rune in
|
||||
// one column, a wide or joining one as U+FFFD
|
||||
func RuneLen(s string) int {
|
||||
return utf8.RuneCountInString(s)
|
||||
}
|
||||
|
||||
// --- Truncation ---
|
||||
|
||||
// Truncate truncates string with … suffix if exceeds maxLen
|
||||
func Truncate(s string, maxLen int) string {
|
||||
if maxLen <= 0 {
|
||||
@@ -63,16 +59,12 @@ func TruncateMiddle(s string, maxLen int) string {
|
||||
return Truncate(s, maxLen)
|
||||
}
|
||||
|
||||
// Split remaining space between start and end
|
||||
// Favor start slightly: (maxLen-1)/2 for start, rest for end
|
||||
startLen := (maxLen - 1) / 2
|
||||
endLen := maxLen - 1 - startLen
|
||||
|
||||
return string(runes[:startLen]) + "…" + string(runes[len(runes)-endLen:])
|
||||
}
|
||||
|
||||
// --- Padding ---
|
||||
|
||||
// PadRight pads string with spaces to width
|
||||
func PadRight(s string, width int) string {
|
||||
runes := []rune(s)
|
||||
@@ -117,8 +109,6 @@ func PadCenter(s string, width int) string {
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// --- Text wrapping ---
|
||||
|
||||
// WrapText wraps text to fit width: at each line break, at spaces, or, in a
|
||||
// word longer than a line, after its last '.', ',', ':', '/', '[' or ']'
|
||||
// that fits (a path or a key such as a[0].b); a word without one is cut.
|
||||
@@ -146,17 +136,14 @@ func wrapLine(s string, width int) []string {
|
||||
lastSpace, lastMark := -1, -1
|
||||
|
||||
for i := 0; i <= len(runes); i++ {
|
||||
// Check if we need to wrap
|
||||
if i-lineStart >= width || i == len(runes) {
|
||||
if i == len(runes) {
|
||||
// End of string
|
||||
if lineStart < len(runes) {
|
||||
lines = append(lines, string(runes[lineStart:]))
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// Need to wrap
|
||||
wrapAt := i
|
||||
switch {
|
||||
case lastSpace > lineStart:
|
||||
@@ -167,7 +154,6 @@ func wrapLine(s string, width int) []string {
|
||||
|
||||
lines = append(lines, string(runes[lineStart:wrapAt]))
|
||||
|
||||
// Skip space at wrap point
|
||||
if wrapAt < len(runes) && runes[wrapAt] == ' ' {
|
||||
lineStart = wrapAt + 1
|
||||
} else {
|
||||
@@ -192,8 +178,6 @@ func wrapLine(s string, width int) []string {
|
||||
return lines
|
||||
}
|
||||
|
||||
// --- Repetition ---
|
||||
|
||||
// RepeatRune returns a string of n repeated runes, for string repeat use strings.Repeat
|
||||
func RepeatRune(r rune, n int) string {
|
||||
if n <= 0 {
|
||||
|
||||
+21
-1
@@ -37,12 +37,32 @@ func TestTransparentBackgroundKeepsItsKind(t *testing.T) {
|
||||
if c := r.Cells[0]; c.Bg != panel.Bg || c.Attrs != terminal.AttrBold|panel.Attr&terminal.AttrBgColor {
|
||||
t.Errorf("on %+v: %+v", panel, c)
|
||||
}
|
||||
if on := panel.On(Style{Attr: terminal.AttrReverse}); on.Bg != panel.Bg || on.Attr != panel.Attr|terminal.AttrReverse {
|
||||
if on := panel.On(Style{Attr: terminal.AttrReverse}); on.Bg != panel.Bg || on.Attr != panel.Attr&terminal.AttrBgColor|terminal.AttrFgDefault|terminal.AttrReverse {
|
||||
t.Errorf("%+v on reverse: %+v", panel, on)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A reverse cursor row is one bar: its pointer, key, name, hint and blanks
|
||||
// take one style, whatever each draws in off the row, where they keep it
|
||||
func TestReverseCursorRowIsOneStyle(t *testing.T) {
|
||||
s := NewOptionListState([]Option{{Name: "file", Hint: "rotating files", Key: 'f'}, {Name: "tcp", Key: 't'}})
|
||||
s.Menu = true
|
||||
for name, th := range map[string]Theme{"16 colors": Theme16, "mono": MonoTheme} {
|
||||
r := canvas(40, 2, th)
|
||||
r.OptionList(s, th)
|
||||
for x, c := range r.Cells[:r.W] {
|
||||
if first := r.Cells[0]; c.Fg != first.Fg || c.Bg != first.Bg || c.Attrs != first.Attrs {
|
||||
t.Errorf("%s %q: column %d %+v, column 0 %+v", name, row(r, 0), x, c, first)
|
||||
break
|
||||
}
|
||||
}
|
||||
if c, a := r.Cells[r.W+2], th.Accent; c.Rune != 't' || c.Fg != a.Fg || c.Attrs&^terminal.AttrBgColor != a.Attr {
|
||||
t.Errorf("%s %q: the key off the cursor row %+v, want %+v", name, row(r, 1), c, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Every widget marks its selection with a glyph, so it reads with no color
|
||||
func TestSelectionChangesAGlyph(t *testing.T) {
|
||||
for _, th := range []Theme{DefaultTheme, Theme16, MonoTheme} {
|
||||
|
||||
Reference in new issue
Block a user