Lauri Tirkkonen: 3 extended color scheme: use rgb colors extended color scheme: detect background color & vary lightness extended color scheme: detect background color & vary lightness 5 files changed, 85 insertions(+), 52 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~delthas/senpai-dev/patches/55950/mbox | git am -3Learn more about email & git
--- ui/colors.go | 83 ++++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/ui/colors.go b/ui/colors.go index 096bdbe..f356234 100644 --- a/ui/colors.go +++ b/ui/colors.go @@ -1,6 +1,7 @@ package ui import ( + "math" "hash/fnv" "git.sr.ht/~rockorager/vaxis" @@ -40,53 +41,59 @@ var colors = map[ColorSchemeType][]vaxis.Color{ vaxis.IndexColor(13), vaxis.IndexColor(14), }, - // all XTerm extended colors with HSL saturation=1, light=0.5 - ColorSchemeExtended: { - vaxis.IndexColor(196), // HSL hue: 0° - vaxis.IndexColor(202), // HSL hue: 22° - vaxis.IndexColor(208), // HSL hue: 32° - vaxis.IndexColor(214), // HSL hue: 41° - vaxis.IndexColor(220), // HSL hue: 51° - vaxis.IndexColor(226), // HSL hue: 60° - vaxis.IndexColor(190), // HSL hue: 69° - vaxis.IndexColor(154), // HSL hue: 79° - vaxis.IndexColor(118), // HSL hue: 88° - vaxis.IndexColor(82), // HSL hue: 98° - vaxis.IndexColor(46), // HSL hue: 120° - vaxis.IndexColor(47), // HSL hue: 142° - vaxis.IndexColor(48), // HSL hue: 152° - vaxis.IndexColor(49), // HSL hue: 161° - vaxis.IndexColor(50), // HSL hue: 171° - vaxis.IndexColor(51), // HSL hue: 180° - vaxis.IndexColor(45), // HSL hue: 189° - vaxis.IndexColor(39), // HSL hue: 199° - vaxis.IndexColor(33), // HSL hue: 208° - vaxis.IndexColor(27), // HSL hue: 218° - vaxis.IndexColor(21), // HSL hue: 240° - vaxis.IndexColor(57), // HSL hue: 262° - vaxis.IndexColor(93), // HSL hue: 272° - vaxis.IndexColor(129), // HSL hue: 281° - vaxis.IndexColor(165), // HSL hue: 291° - vaxis.IndexColor(201), // HSL hue: 300° - vaxis.IndexColor(200), // HSL hue: 309° - vaxis.IndexColor(199), // HSL hue: 319° - vaxis.IndexColor(198), // HSL hue: 328° - vaxis.IndexColor(197), // HSL hue: 338° - }, +} + +func u32ToAngle(n uint32) float64 { + return float64(n) / float64(math.MaxUint32) * 360 +} + +func hslToRGB(hue, sat, light float64) (r, g, b uint8) { + var r1, g1, b1 float64 + chroma := (1 - math.Abs(2 * light - 1)) * sat + h6 := hue/60 + x := chroma * (1 - math.Abs(math.Mod(h6, 2) - 1)) + if 0 <= h6 && h6 < 1 { + r1, g1, b1 = chroma, x, 0 + } else if 1 <= h6 && h6 < 2 { + r1, g1, b1 = x, chroma, 0 + } else if 2 <= h6 && h6 < 3 { + r1, g1, b1 = 0, chroma, x + } else if 3 <= h6 && h6 < 4 { + r1, g1, b1 = 0, x, chroma + } else if 4 <= h6 && h6 < 5 { + r1, g1, b1 = x, 0, chroma + } else if 5 <= h6 && h6 < 6 { + r1, g1, b1 = chroma, 0, x + } + m := light - chroma/2 + r = uint8(math.MaxUint8 * (r1 + m)) + g = uint8(math.MaxUint8 * (g1 + m)) + b = uint8(math.MaxUint8 * (b1 + m)) + return r, g, b } func IdentColor(scheme ColorScheme, ident string, self bool) vaxis.Color { - h := fnv.New32() - _, _ = h.Write([]byte(ident)) - if scheme.Type == ColorSchemeFixed { + hash := fnv.New32() + _, _ = hash.Write([]byte(ident)) + switch scheme.Type { + case ColorSchemeFixed: if self { return scheme.Self } else { return scheme.Others } + case ColorSchemeBase: + c := colors[scheme.Type] + return c[int(hash.Sum32()%uint32(len(c)))] + case ColorSchemeExtended: + hue := u32ToAngle(hash.Sum32()) + sat := 1.0 + light := 0.5 + return vaxis.RGBColor(hslToRGB(hue, sat, light)) + + default: + panic("invalid color scheme setting") } - c := colors[scheme.Type] - return c[int(h.Sum32()%uint32(len(c)))] } func IdentString(scheme ColorScheme, ident string, self bool) StyledString { -- 2.46.2 -- Lauri Tirkkonen | lotheac @ IRCnet
humans can detect lightness differences pretty well, so it makes sense to vary color selection in that dimension too. --- app.go | 8 ++++---- ui/colors.go | 27 ++++++++++++++++++++------- ui/ui.go | 15 ++++++++++++++- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/app.go b/app.go index 2de6d95..91530d3 100644 --- a/app.go +++ b/app.go @@ -1994,12 +1994,12 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin if isAction || isNotice { head = "*" } else { - headColor = ui.IdentColor(app.cfg.Colors.Nicks, head, isFromSelf) + headColor = app.win.IdentColor(app.cfg.Colors.Nicks, head, isFromSelf) } var body ui.StyledStringBuilder if isNotice { - color := ui.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf) + color := app.win.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf) body.SetStyle(vaxis.Style{ Foreground: color, }) @@ -2008,7 +2008,7 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin body.WriteString(": ") body.WriteStyledString(ui.IRCString(content)) } else if isAction { - color := ui.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf) + color := app.win.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf) body.SetStyle(vaxis.Style{ Foreground: color, }) @@ -2203,7 +2203,7 @@ func (app *App) updatePrompt() { }, ) } else { - prompt = ui.IdentString(app.cfg.Colors.Nicks, s.Nick(), true) + prompt = app.win.IdentString(app.cfg.Colors.Nicks, s.Nick(), true) } app.win.SetPrompt(prompt) } diff --git a/ui/colors.go b/ui/colors.go index f356234..b99762b 100644 --- a/ui/colors.go +++ b/ui/colors.go @@ -43,8 +43,14 @@ var colors = map[ColorSchemeType][]vaxis.Color{ }, } -func u32ToAngle(n uint32) float64 { - return float64(n) / float64(math.MaxUint32) * 360 +func mapToRange(n uint16, min1, max1 uint16, min2, max2 float64) float64 { + // scale val to range [0,1] + val := float64(n - min1) / float64(max1 - min1) + return min2 + (max2-min2) * val +} + +func u16ToAngle(n uint16) float64 { + return float64(n) / float64(math.MaxUint16) * 360 } func hslToRGB(hue, sat, light float64) (r, g, b uint8) { @@ -72,7 +78,7 @@ func hslToRGB(hue, sat, light float64) (r, g, b uint8) { return r, g, b } -func IdentColor(scheme ColorScheme, ident string, self bool) vaxis.Color { +func (ui UI) IdentColor(scheme ColorScheme, ident string, self bool) vaxis.Color { hash := fnv.New32() _, _ = hash.Write([]byte(ident)) switch scheme.Type { @@ -86,9 +92,16 @@ func IdentColor(scheme ColorScheme, ident string, self bool) vaxis.Color { c := colors[scheme.Type] return c[int(hash.Sum32()%uint32(len(c)))] case ColorSchemeExtended: - hue := u32ToAngle(hash.Sum32()) + sum := hash.Sum32() + hue := mapToRange(uint16(sum), 0, math.MaxUint16, 0.0, 360.0) sat := 1.0 - light := 0.5 + var light float64 + switch ui.colorThemeMode { + case vaxis.DarkMode: + light = mapToRange(uint16(sum >> 16), 0, math.MaxUint16, 0.6, 1.0) + case vaxis.LightMode: + light = mapToRange(uint16(sum >> 16), 0, math.MaxUint16, 0.0, 0.4) + } return vaxis.RGBColor(hslToRGB(hue, sat, light)) default: @@ -96,8 +109,8 @@ func IdentColor(scheme ColorScheme, ident string, self bool) vaxis.Color { } } -func IdentString(scheme ColorScheme, ident string, self bool) StyledString { - color := IdentColor(scheme, ident, self) +func (ui UI) IdentString(scheme ColorScheme, ident string, self bool) StyledString { + color := ui.IdentColor(scheme, ident, self) style := vaxis.Style{ Foreground: color, } diff --git a/ui/ui.go b/ui/ui.go index 7cef99e..b6d0926 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -3,6 +3,7 @@ package ui import ( "fmt" "image" + "math" "strings" "sync/atomic" "time" @@ -75,6 +76,8 @@ type UI struct { image vaxis.Image mouseLinks bool + + colorThemeMode vaxis.ColorThemeMode } func New(config Config) (ui *UI, err error) { @@ -102,6 +105,16 @@ func New(config Config) (ui *UI, err error) { window: vx.Window(), } + bgcol := ui.vx.QueryBackground() + parm := bgcol.Params() + r,g,b := float64(parm[0]),float64(parm[1]),float64(parm[2]) + bglight := (math.Max(math.Max(r,g),b) + math.Min(math.Min(r,g),b))/2 + if (bglight > 127) { + ui.colorThemeMode = vaxis.LightMode + } else { + ui.colorThemeMode = vaxis.DarkMode + } + ui.vx.SetTitle("senpai") ui.vx.SetAppID("senpai") @@ -847,7 +860,7 @@ func (ui *UI) drawVerticalMemberList(vx *Vaxis, x0, y0, width, height int, membe Attribute: attr, }) } else { - color := IdentColor(ui.config.Colors.Nicks, m.Name.Name, m.Self) + color := ui.IdentColor(ui.config.Colors.Nicks, m.Name.Name, m.Self) name = Styled(nameText, vaxis.Style{ Foreground: color, Attribute: attr, -- 2.46.2 -- Lauri Tirkkonen | lotheac @ IRCnet
I think this actually shows pretty well why this is needed: I adjusted the max/min lightness values a little bit, and the difference is quite staggering. My initial values were off; I don't think they should necessarily be configurable, but they can make a big difference. diff --git a/ui/colors.go b/ui/colors.go index b99762b..7fe0b1f 100644 --- a/ui/colors.go +++ b/ui/colors.go @@ -98,9 +98,9 @@ func (ui UI) IdentColor(scheme ColorScheme, ident string, self bool) vaxis.Color var light float64 switch ui.colorThemeMode { case vaxis.DarkMode: - light = mapToRange(uint16(sum >> 16), 0, math.MaxUint16, 0.6, 1.0) + light = mapToRange(uint16(sum >> 16), 0, math.MaxUint16, 0.4, 0.9) case vaxis.LightMode: - light = mapToRange(uint16(sum >> 16), 0, math.MaxUint16, 0.0, 0.4) + light = mapToRange(uint16(sum >> 16), 0, math.MaxUint16, 0.1, 0.6) } return vaxis.RGBColor(hslToRGB(hue, sat, light)) -- Lauri Tirkkonen | lotheac @ IRCnet