master sewn/kohai / ui / colors.go
  1package ui
  2
  3import (
  4	"hash/fnv"
  5	"math"
  6
  7	"git.sr.ht/~rockorager/vaxis"
  8)
  9
 10var ColorDefault = vaxis.Color(0)
 11var ColorGreen = vaxis.IndexColor(2)
 12var ColorRed = vaxis.IndexColor(9)
 13
 14type ColorSchemeType int
 15
 16type ColorScheme struct {
 17	Type   ColorSchemeType
 18	Others vaxis.Color
 19	Self   vaxis.Color
 20}
 21
 22const (
 23	ColorSchemeBase ColorSchemeType = iota
 24	ColorSchemeExtended
 25	ColorSchemeFixed
 26)
 27
 28var baseColors = []vaxis.Color{
 29	// base 16 colors, excluding grayscale colors.
 30	vaxis.IndexColor(1),
 31	vaxis.IndexColor(2),
 32	vaxis.IndexColor(3),
 33	vaxis.IndexColor(4),
 34	vaxis.IndexColor(5),
 35	vaxis.IndexColor(6),
 36	vaxis.IndexColor(7),
 37	vaxis.IndexColor(9),
 38	vaxis.IndexColor(10),
 39	vaxis.IndexColor(11),
 40	vaxis.IndexColor(12),
 41	vaxis.IndexColor(13),
 42	vaxis.IndexColor(14),
 43}
 44
 45func hslToRGB(hue, sat, light float64) (r, g, b uint8) {
 46	var r1, g1, b1 float64
 47	chroma := (1 - math.Abs(2*light-1)) * sat
 48	h6 := hue / 60
 49	x := chroma * (1 - math.Abs(math.Mod(h6, 2)-1))
 50	if h6 < 1 {
 51		r1, g1, b1 = chroma, x, 0
 52	} else if h6 < 2 {
 53		r1, g1, b1 = x, chroma, 0
 54	} else if h6 < 3 {
 55		r1, g1, b1 = 0, chroma, x
 56	} else if h6 < 4 {
 57		r1, g1, b1 = 0, x, chroma
 58	} else if h6 < 5 {
 59		r1, g1, b1 = x, 0, chroma
 60	} else {
 61		r1, g1, b1 = chroma, 0, x
 62	}
 63	m := light - chroma/2
 64	r = uint8(math.MaxUint8 * (r1 + m))
 65	g = uint8(math.MaxUint8 * (g1 + m))
 66	b = uint8(math.MaxUint8 * (b1 + m))
 67	return r, g, b
 68}
 69
 70func (ui *UI) IdentColor(scheme ColorScheme, ident string, self bool) vaxis.Color {
 71	if self && scheme.Self != 0 {
 72		return scheme.Self
 73	}
 74	h := fnv.New32()
 75	_, _ = h.Write([]byte(ident))
 76	switch scheme.Type {
 77	case ColorSchemeFixed:
 78		if self {
 79			return ColorRed
 80		} else {
 81			return scheme.Others
 82		}
 83	case ColorSchemeBase:
 84		return baseColors[int(h.Sum32()%uint32(len(baseColors)))]
 85	case ColorSchemeExtended:
 86		sum := h.Sum32()
 87		lo := int(sum & 0xFFFF)
 88		hi := int((sum >> 16) & 0xFFFF)
 89		hue := float64(lo) / float64(math.MaxUint16) * 360
 90		sat := 1.0
 91		var lightMin, lightMax float64
 92		switch ui.colorThemeMode {
 93		case vaxis.DarkMode:
 94			lightMin, lightMax = 0.5, 0.7
 95		case vaxis.LightMode:
 96			lightMin, lightMax = 0.2, 0.4
 97		}
 98		light := lightMin + float64(hi)/float64(math.MaxUint16)*(lightMax-lightMin)
 99		return vaxis.RGBColor(hslToRGB(hue, sat, light))
100	default:
101		panic("invalid color scheme setting")
102	}
103}
104
105func (ui *UI) IdentString(scheme ColorScheme, ident string, self bool) StyledString {
106	color := ui.IdentColor(scheme, ident, self)
107	style := vaxis.Style{
108		Foreground: color,
109	}
110	return Styled(ident, style)
111}