commit 17006ee
Lauri Tirkkonen
·
2024-11-14 12:14:42 +0000 UTC
parent 207463e
extended color scheme: use rgb colors Also detect background color & vary lightness.
3 files changed,
+89,
-64
M
app.go
+8,
-8
1@@ -532,6 +532,8 @@ func (app *App) handleUIEvent(ev interface{}) bool {
2 app.win.SetFocused(true)
3 case vaxis.FocusOut:
4 app.win.SetFocused(false)
5+ case vaxis.ColorThemeUpdate:
6+ app.win.SetColorTheme(ev.Mode)
7 case *ui.NotifyEvent:
8 app.win.JumpBufferNetwork(ev.NetID, ev.Buffer)
9 case statusLine:
10@@ -2049,12 +2051,12 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin
11 if isAction || isNotice {
12 head = "*"
13 } else {
14- headColor = ui.IdentColor(app.cfg.Colors.Nicks, head, isFromSelf)
15+ headColor = app.win.IdentColor(app.cfg.Colors.Nicks, head, isFromSelf)
16 }
17
18 var body ui.StyledStringBuilder
19 if isNotice {
20- color := ui.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf)
21+ color := app.win.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf)
22 body.SetStyle(vaxis.Style{
23 Foreground: color,
24 })
25@@ -2063,7 +2065,7 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin
26 body.WriteString(": ")
27 body.WriteStyledString(ui.IRCString(content))
28 } else if isAction {
29- color := ui.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf)
30+ color := app.win.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf)
31 body.SetStyle(vaxis.Style{
32 Foreground: color,
33 })
34@@ -2250,15 +2252,13 @@ func (app *App) updatePrompt() {
35 if buffer == "" || command {
36 prompt = ui.Styled(">", vaxis.Style{
37 Foreground: app.cfg.Colors.Prompt,
38- },
39- )
40+ })
41 } else if s == nil {
42 prompt = ui.Styled("<offline>", vaxis.Style{
43 Foreground: ui.ColorRed,
44- },
45- )
46+ })
47 } else {
48- prompt = ui.IdentString(app.cfg.Colors.Nicks, s.Nick(), true)
49+ prompt = app.win.IdentString(app.cfg.Colors.Nicks, s.Nick(), true)
50 }
51 app.win.SetPrompt(prompt)
52 }
+64,
-55
1@@ -2,6 +2,7 @@ package ui
2
3 import (
4 "hash/fnv"
5+ "math"
6
7 "git.sr.ht/~rockorager/vaxis"
8 )
9@@ -23,74 +24,82 @@ const (
10 ColorSchemeFixed
11 )
12
13-var colors = map[ColorSchemeType][]vaxis.Color{
14+var baseColors = []vaxis.Color{
15 // base 16 colors, excluding grayscale colors.
16- ColorSchemeBase: {
17- vaxis.IndexColor(1),
18- vaxis.IndexColor(2),
19- vaxis.IndexColor(3),
20- vaxis.IndexColor(4),
21- vaxis.IndexColor(5),
22- vaxis.IndexColor(6),
23- vaxis.IndexColor(7),
24- vaxis.IndexColor(9),
25- vaxis.IndexColor(10),
26- vaxis.IndexColor(11),
27- vaxis.IndexColor(12),
28- vaxis.IndexColor(13),
29- vaxis.IndexColor(14),
30- },
31- // all XTerm extended colors with HSL saturation=1, light=0.5
32- ColorSchemeExtended: {
33- vaxis.IndexColor(196), // HSL hue: 0°
34- vaxis.IndexColor(202), // HSL hue: 22°
35- vaxis.IndexColor(208), // HSL hue: 32°
36- vaxis.IndexColor(214), // HSL hue: 41°
37- vaxis.IndexColor(220), // HSL hue: 51°
38- vaxis.IndexColor(226), // HSL hue: 60°
39- vaxis.IndexColor(190), // HSL hue: 69°
40- vaxis.IndexColor(154), // HSL hue: 79°
41- vaxis.IndexColor(118), // HSL hue: 88°
42- vaxis.IndexColor(82), // HSL hue: 98°
43- vaxis.IndexColor(46), // HSL hue: 120°
44- vaxis.IndexColor(47), // HSL hue: 142°
45- vaxis.IndexColor(48), // HSL hue: 152°
46- vaxis.IndexColor(49), // HSL hue: 161°
47- vaxis.IndexColor(50), // HSL hue: 171°
48- vaxis.IndexColor(51), // HSL hue: 180°
49- vaxis.IndexColor(45), // HSL hue: 189°
50- vaxis.IndexColor(39), // HSL hue: 199°
51- vaxis.IndexColor(33), // HSL hue: 208°
52- vaxis.IndexColor(27), // HSL hue: 218°
53- vaxis.IndexColor(21), // HSL hue: 240°
54- vaxis.IndexColor(57), // HSL hue: 262°
55- vaxis.IndexColor(93), // HSL hue: 272°
56- vaxis.IndexColor(129), // HSL hue: 281°
57- vaxis.IndexColor(165), // HSL hue: 291°
58- vaxis.IndexColor(201), // HSL hue: 300°
59- vaxis.IndexColor(200), // HSL hue: 309°
60- vaxis.IndexColor(199), // HSL hue: 319°
61- vaxis.IndexColor(198), // HSL hue: 328°
62- vaxis.IndexColor(197), // HSL hue: 338°
63- },
64+ vaxis.IndexColor(1),
65+ vaxis.IndexColor(2),
66+ vaxis.IndexColor(3),
67+ vaxis.IndexColor(4),
68+ vaxis.IndexColor(5),
69+ vaxis.IndexColor(6),
70+ vaxis.IndexColor(7),
71+ vaxis.IndexColor(9),
72+ vaxis.IndexColor(10),
73+ vaxis.IndexColor(11),
74+ vaxis.IndexColor(12),
75+ vaxis.IndexColor(13),
76+ vaxis.IndexColor(14),
77 }
78
79-func IdentColor(scheme ColorScheme, ident string, self bool) vaxis.Color {
80+func hslToRGB(hue, sat, light float64) (r, g, b uint8) {
81+ var r1, g1, b1 float64
82+ chroma := (1 - math.Abs(2*light-1)) * sat
83+ h6 := hue / 60
84+ x := chroma * (1 - math.Abs(math.Mod(h6, 2)-1))
85+ if h6 < 1 {
86+ r1, g1, b1 = chroma, x, 0
87+ } else if h6 < 2 {
88+ r1, g1, b1 = x, chroma, 0
89+ } else if h6 < 3 {
90+ r1, g1, b1 = 0, chroma, x
91+ } else if h6 < 4 {
92+ r1, g1, b1 = 0, x, chroma
93+ } else if h6 < 5 {
94+ r1, g1, b1 = x, 0, chroma
95+ } else {
96+ r1, g1, b1 = chroma, 0, x
97+ }
98+ m := light - chroma/2
99+ r = uint8(math.MaxUint8 * (r1 + m))
100+ g = uint8(math.MaxUint8 * (g1 + m))
101+ b = uint8(math.MaxUint8 * (b1 + m))
102+ return r, g, b
103+}
104+
105+func (ui *UI) IdentColor(scheme ColorScheme, ident string, self bool) vaxis.Color {
106 h := fnv.New32()
107 _, _ = h.Write([]byte(ident))
108- if scheme.Type == ColorSchemeFixed {
109+ switch scheme.Type {
110+ case ColorSchemeFixed:
111 if self {
112 return scheme.Self
113 } else {
114 return scheme.Others
115 }
116+ case ColorSchemeBase:
117+ return baseColors[int(h.Sum32()%uint32(len(baseColors)))]
118+ case ColorSchemeExtended:
119+ sum := h.Sum32()
120+ lo := int(sum & 0xFFFF)
121+ hi := int((sum >> 16) & 0xFFFF)
122+ hue := float64(lo) / float64(math.MaxUint16) * 360
123+ sat := 1.0
124+ var lightMin, lightMax float64
125+ switch ui.colorThemeMode {
126+ case vaxis.DarkMode:
127+ lightMin, lightMax = 0.5, 0.7
128+ case vaxis.LightMode:
129+ lightMin, lightMax = 0.2, 0.4
130+ }
131+ light := lightMin + float64(hi)/float64(math.MaxUint16)*(lightMax-lightMin)
132+ return vaxis.RGBColor(hslToRGB(hue, sat, light))
133+ default:
134+ panic("invalid color scheme setting")
135 }
136- c := colors[scheme.Type]
137- return c[int(h.Sum32()%uint32(len(c)))]
138 }
139
140-func IdentString(scheme ColorScheme, ident string, self bool) StyledString {
141- color := IdentColor(scheme, ident, self)
142+func (ui *UI) IdentString(scheme ColorScheme, ident string, self bool) StyledString {
143+ color := ui.IdentColor(scheme, ident, self)
144 style := vaxis.Style{
145 Foreground: color,
146 }
M
ui/ui.go
+17,
-1
1@@ -75,6 +75,8 @@ type UI struct {
2 image vaxis.Image
3
4 mouseLinks bool
5+
6+ colorThemeMode vaxis.ColorThemeMode
7 }
8
9 func New(config Config) (ui *UI, err error) {
10@@ -102,6 +104,16 @@ func New(config Config) (ui *UI, err error) {
11 window: vx.Window(),
12 }
13
14+ if bg := ui.vx.QueryBackground().Params(); len(bg) == 3 {
15+ if (int(bg[0])+int(bg[1])+int(bg[2]))/3 > 127 {
16+ ui.colorThemeMode = vaxis.LightMode
17+ } else {
18+ ui.colorThemeMode = vaxis.DarkMode
19+ }
20+ } else {
21+ ui.colorThemeMode = vaxis.DarkMode
22+ }
23+
24 ui.vx.SetTitle("senpai")
25 ui.vx.SetAppID("senpai")
26
27@@ -518,6 +530,10 @@ func (ui *UI) SetMouseShape(shape vaxis.MouseShape) {
28 ui.vx.SetMouseShape(shape)
29 }
30
31+func (ui *UI) SetColorTheme(mode vaxis.ColorThemeMode) {
32+ ui.colorThemeMode = mode
33+}
34+
35 // InputContent result must not be modified.
36 func (ui *UI) InputContent() []rune {
37 return ui.e.Content()
38@@ -894,7 +910,7 @@ func (ui *UI) drawVerticalMemberList(vx *Vaxis, x0, y0, width, height int, b *bu
39 Attribute: attr,
40 })
41 } else {
42- color := IdentColor(ui.config.Colors.Nicks, m.Name.Name, m.Self)
43+ color := ui.IdentColor(ui.config.Colors.Nicks, m.Name.Name, m.Self)
44 name = Styled(nameText, vaxis.Style{
45 Foreground: color,
46 Attribute: attr,