From e383e6d6be3205f0a9cedacf24ec37d3df506880 Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Wed, 16 Dec 2020 19:06:24 +0200 Subject: [PATCH] widget/material: better disabled color calculation Use desaturation in combination with alpha multiplication. Signed-off-by: Egon Elbre --- internal/f32color/rgba.go | 33 +++++++++++++++++++++++++++++++++ widget/material/button.go | 4 ++-- widget/material/checkable.go | 2 +- widget/material/editor.go | 2 +- widget/material/progressbar.go | 2 +- widget/material/slider.go | 2 +- widget/material/switch.go | 2 +- 7 files changed, 40 insertions(+), 7 deletions(-) diff --git a/internal/f32color/rgba.go b/internal/f32color/rgba.go index c72f50ef..d1b7564d 100644 --- a/internal/f32color/rgba.go +++ b/internal/f32color/rgba.go @@ -35,6 +35,14 @@ func (col RGBA) SRGB() color.NRGBA { } } +// Luminance calculates the relative luminance of a linear RGBA color. +// Normalized to 0 for black and 1 for white. +// +// See https://www.w3.org/TR/WCAG20/#relativeluminancedef for more details +func (col RGBA) Luminance() float32 { + return 0.2126*col.R + 0.7152*col.G + 0.0722*col.B +} + // Opaque returns the color without alpha component. func (col RGBA) Opaque() RGBA { col.A = 1.0 @@ -115,3 +123,28 @@ func MulAlpha(c color.NRGBA, alpha uint8) color.NRGBA { c.A = uint8(uint32(c.A) * uint32(alpha) / 0xFF) return c } + +// Disabled blends color towards the luminance and multiplies alpha. +// Blending towards luminance will desaturate the color. +// Multiplying alpha blends the color together more with the background. +func Disabled(c color.NRGBA) (d color.NRGBA) { + const r = 80 // blend ratio + lum := approxLuminance(c) + return color.NRGBA{ + R: byte((int(c.R)*r + int(lum)*(256-r)) / 256), + G: byte((int(c.G)*r + int(lum)*(256-r)) / 256), + B: byte((int(c.B)*r + int(lum)*(256-r)) / 256), + A: byte(int(c.A) * (128 + 32) / 256), + } +} + +// approxLuminance is a fast approximate version of RGBA.Luminance. +func approxLuminance(c color.NRGBA) byte { + const ( + r = 13933 // 0.2126 * 256 * 256 + g = 46871 // 0.7152 * 256 * 256 + b = 4732 // 0.0722 * 256 * 256 + t = r + g + b + ) + return byte((r*int(c.R) + g*int(c.G) + b*int(c.B)) / t) +} diff --git a/widget/material/button.go b/widget/material/button.go index 41be9ee6..03b88c3d 100644 --- a/widget/material/button.go +++ b/widget/material/button.go @@ -129,7 +129,7 @@ func (b ButtonLayoutStyle) Layout(gtx layout.Context, w layout.Widget) layout.Di }}, rr).Add(gtx.Ops) background := b.Background if gtx.Queue == nil { - background = f32color.MulAlpha(b.Background, 150) + background = f32color.Disabled(b.Background) } paint.Fill(gtx.Ops, background) for _, c := range b.Button.History() { @@ -156,7 +156,7 @@ func (b IconButtonStyle) Layout(gtx layout.Context) layout.Dimensions { }, rr).Add(gtx.Ops) background := b.Background if gtx.Queue == nil { - background = f32color.MulAlpha(b.Background, 150) + background = f32color.Disabled(b.Background) } paint.Fill(gtx.Ops, background) for _, c := range b.Button.History() { diff --git a/widget/material/checkable.go b/widget/material/checkable.go index 617d3201..90f2103e 100644 --- a/widget/material/checkable.go +++ b/widget/material/checkable.go @@ -43,7 +43,7 @@ func (c *checkable) layout(gtx layout.Context, checked bool) layout.Dimensions { size := gtx.Px(c.Size) icon.Color = c.IconColor if gtx.Queue == nil { - icon.Color = f32color.MulAlpha(icon.Color, 150) + icon.Color = f32color.Disabled(icon.Color) } icon.Layout(gtx, unit.Px(float32(size))) return layout.Dimensions{ diff --git a/widget/material/editor.go b/widget/material/editor.go index 9e8a33e0..7b01dbe4 100644 --- a/widget/material/editor.go +++ b/widget/material/editor.go @@ -61,7 +61,7 @@ func (e EditorStyle) Layout(gtx layout.Context) layout.Dimensions { if e.Editor.Len() > 0 { textColor := e.Color if disabled { - textColor = f32color.MulAlpha(textColor, 150) + textColor = f32color.Disabled(textColor) } paint.ColorOp{Color: textColor}.Add(gtx.Ops) e.Editor.PaintText(gtx) diff --git a/widget/material/progressbar.go b/widget/material/progressbar.go index b8fc046b..9f53bb1f 100644 --- a/widget/material/progressbar.go +++ b/widget/material/progressbar.go @@ -55,7 +55,7 @@ func (p ProgressBarStyle) Layout(gtx layout.Context) layout.Dimensions { fillWidth := progressBarWidth * clamp1(p.Progress) fillColor := p.Color if gtx.Queue == nil { - fillColor = f32color.MulAlpha(fillColor, 200) + fillColor = f32color.Disabled(fillColor) } return shader(fillWidth, fillColor) }), diff --git a/widget/material/slider.go b/widget/material/slider.go index 801e19c8..2a99ebc9 100644 --- a/widget/material/slider.go +++ b/widget/material/slider.go @@ -68,7 +68,7 @@ func (s SliderStyle) Layout(gtx layout.Context) layout.Dimensions { color := s.Color if gtx.Queue == nil { - color = f32color.MulAlpha(color, 150) + color = f32color.Disabled(color) } // Draw track before thumb. diff --git a/widget/material/switch.go b/widget/material/switch.go index c0f6eff9..fb0e9ecf 100644 --- a/widget/material/switch.go +++ b/widget/material/switch.go @@ -55,7 +55,7 @@ func (s SwitchStyle) Layout(gtx layout.Context) layout.Dimensions { col = s.Color.Enabled } if gtx.Queue == nil { - col = f32color.MulAlpha(col, 150) + col = f32color.Disabled(col) } trackColor := s.Color.Track op.Offset(f32.Point{Y: trackOff}).Add(gtx.Ops)