| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- package rgb
- import (
- "fmt"
- "strconv"
- "strings"
- )
- // HSV is a color in the units the keyboard uses: hue, saturation and value,
- // each 0-255. The keyboard stores hue and saturation only; Value is the
- // brightness register, which is why it is tracked apart from the color.
- type HSV struct {
- H, S, V uint8
- // hasValue separates "the notation carried no value" from "the notation
- // asked for value 0". The hex forms mean the first, and leave V at zero.
- hasValue bool
- }
- // HasValue reports whether the notation carried a value component, that is,
- // whether the caller asked for a brightness as well as a color.
- func (c HSV) HasValue() bool { return c.hasValue }
- // ParseColorSpec parses one of the three documented color notations: a bare or
- // rgb:-prefixed six digit hex value, or hsv:<h>,<s>,<v> in the firmware's own
- // 0-255 units. A hex value contributes hue and saturation; the value component
- // of a hex color is not a brightness request and is dropped.
- func ParseColorSpec(spec string) (HSV, error) {
- prefix, body, found := strings.Cut(spec, ":")
- if !found {
- if prefix == "hsv" || prefix == "rgb" {
- return HSV{}, unknownNotation(spec)
- }
- return hexToHSV(spec)
- }
- switch prefix {
- case "hsv":
- return parseHSVSpec(body)
- case "rgb":
- return hexToHSV(body)
- default:
- return HSV{}, unknownNotation(spec)
- }
- }
- // hexToHSV converts a hex color to the hue and saturation the keyboard stores.
- // The value component of the hex color is not carried over: only the hsv
- // notation asks for a brightness, and HasValue keeps that distinction visible.
- func hexToHSV(hex string) (HSV, error) {
- c, err := ParseHexColor(hex)
- if err != nil {
- return HSV{}, err
- }
- h, s, _ := c.HSV()
- return HSV{H: h, S: s}, nil
- }
- // parseHSVSpec parses the body of an hsv: notation. Three components are
- // required: a two component form would have to mean "leave the brightness
- // alone", which no other notation does.
- func parseHSVSpec(body string) (HSV, error) {
- parts := strings.Split(body, ",")
- if len(parts) != 3 {
- return HSV{}, fmt.Errorf("want hsv:<h>,<s>,<v> with three components in 0-255, got %q", body)
- }
- var components [3]uint8
- for i, part := range parts {
- n, err := strconv.ParseUint(part, 10, 8)
- if err != nil {
- return HSV{}, fmt.Errorf("invalid hsv component %q: want 0-255", part)
- }
- components[i] = uint8(n)
- }
- return HSV{H: components[0], S: components[1], V: components[2], hasValue: true}, nil
- }
- // unknownNotation names the accepted forms, because a rejected notation is
- // usually a typo of one of them.
- func unknownNotation(spec string) error {
- return fmt.Errorf("unknown color notation %q: use ff0000, rgb:ff0000 or hsv:0,255,255", spec)
- }
|