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}