color.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/spf13/cobra"
  6. intrgb "netdome.biz/paul/qmk-rgb/internal/rgb"
  7. )
  8. func NewColorCmd() *cobra.Command {
  9. return withZoneArgs(&cobra.Command{
  10. Use: "color <zone> <hex>|rgb:<hex>|hsv:<h>,<s>,<v>",
  11. Short: "Set RGB color on a zone",
  12. Long: writesLighting("Set the color of the named zones from one of three notations:\n" +
  13. " ff0000 six digit hex, hue and saturation only\n" +
  14. " rgb:ff0000 the same, written out\n" +
  15. " hsv:0,255,255 hue, saturation and value, each 0-255\n" +
  16. "\n" +
  17. "The hex notations say nothing about brightness, so they leave it alone.\n" +
  18. "The keyboard has no value register for a color: the value of an hsv:\n" +
  19. "notation is written to the brightness of the same zones, and the\n" +
  20. "brightness the keyboard ended up holding is reported.\n" +
  21. "\n" +
  22. "Every notation is read back, so a color the keyboard rounded or refused\n" +
  23. "is reported instead of being claimed as set."),
  24. RunE: func(cmd *cobra.Command, args []string) error {
  25. spec, err := intrgb.ParseColorSpec(args[1])
  26. if err != nil {
  27. return err
  28. }
  29. proto, target, channels, err := openTarget(args[0])
  30. if err != nil {
  31. return err
  32. }
  33. defer proto.Close()
  34. colors, err := setColorVerified(proto, channels, target.Display, spec.H, spec.S)
  35. if err != nil {
  36. return fmt.Errorf("set color: %w", err)
  37. }
  38. if !spec.HasValue() {
  39. printColorResult(cmd, colors, nil)
  40. return nil
  41. }
  42. brightness, err := setBrightnessVerified(proto, channels, target.Display, spec.V)
  43. if err != nil {
  44. return fmt.Errorf("set brightness from %s: %w", args[1], err)
  45. }
  46. printColorResult(cmd, colors, brightness)
  47. return nil
  48. },
  49. }, 2, 2, "a zone and a color")
  50. }
  51. // printColorResult states the color every zone actually holds. The brightness
  52. // results are nil for a notation that did not write one, and then no brightness
  53. // is mentioned: the command must not imply it set something it left alone.
  54. func printColorResult(cmd *cobra.Command, colors []colorResult, brightness []zoneResult) {
  55. request := ""
  56. if len(colors) > 0 {
  57. request = fmt.Sprintf("hue %d sat %d", colors[0].RequestedHue, colors[0].RequestedSaturation)
  58. if len(brightness) > 0 {
  59. request += fmt.Sprintf(" brightness %d", brightness[0].Requested)
  60. }
  61. }
  62. if !anyColorMismatch(colors) && !anyMismatch(brightness) {
  63. fmt.Fprintf(cmd.OutOrStdout(), "Color set to %s\n", request)
  64. return
  65. }
  66. var b strings.Builder
  67. b.WriteString("Color")
  68. for i, c := range colors {
  69. fmt.Fprintf(&b, " %s hue %d sat %d", c.Name, c.Hue, c.Saturation)
  70. if i < len(brightness) {
  71. fmt.Fprintf(&b, " brightness %d", brightness[i].Applied)
  72. }
  73. }
  74. fmt.Fprintf(&b, " (requested %s)", request)
  75. fmt.Fprintln(cmd.OutOrStdout(), b.String())
  76. }
  77. // anyColorMismatch reports whether any zone stored another color.
  78. func anyColorMismatch(results []colorResult) bool {
  79. for _, r := range results {
  80. if r.Mismatch() {
  81. return true
  82. }
  83. }
  84. return false
  85. }