color.go 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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 &cobra.Command{
  10. Use: "color <hex>|rgb:<hex>|hsv:<h>,<s>,<v>",
  11. Short: "Set RGB color",
  12. Long: "Set the color of the selected 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. Args: cobra.ExactArgs(1),
  25. RunE: func(cmd *cobra.Command, args []string) error {
  26. spec, err := intrgb.ParseColorSpec(args[0])
  27. if err != nil {
  28. return err
  29. }
  30. proto, target, channels, err := openTarget()
  31. if err != nil {
  32. return err
  33. }
  34. defer proto.Close()
  35. colors, err := setColorVerified(proto, channels, target.Display, spec.H, spec.S)
  36. if err != nil {
  37. return fmt.Errorf("set color: %w", err)
  38. }
  39. if !spec.HasValue() {
  40. printColorResult(cmd, colors, nil)
  41. return nil
  42. }
  43. brightness, err := setBrightnessVerified(proto, channels, target.Display, spec.V)
  44. if err != nil {
  45. return fmt.Errorf("set brightness from %s: %w", args[0], err)
  46. }
  47. printColorResult(cmd, colors, brightness)
  48. return nil
  49. },
  50. }
  51. }
  52. // printColorResult states the color every zone actually holds. The brightness
  53. // results are nil for a notation that did not write one, and then no brightness
  54. // is mentioned: the command must not imply it set something it left alone.
  55. func printColorResult(cmd *cobra.Command, colors []colorResult, brightness []zoneResult) {
  56. request := ""
  57. if len(colors) > 0 {
  58. request = fmt.Sprintf("hue %d sat %d", colors[0].RequestedHue, colors[0].RequestedSaturation)
  59. if len(brightness) > 0 {
  60. request += fmt.Sprintf(" brightness %d", brightness[0].Requested)
  61. }
  62. }
  63. if !anyColorMismatch(colors) && !anyMismatch(brightness) {
  64. fmt.Fprintf(cmd.OutOrStdout(), "Color set to %s\n", request)
  65. return
  66. }
  67. var b strings.Builder
  68. b.WriteString("Color")
  69. for i, c := range colors {
  70. fmt.Fprintf(&b, " %s hue %d sat %d", c.Name, c.Hue, c.Saturation)
  71. if i < len(brightness) {
  72. fmt.Fprintf(&b, " brightness %d", brightness[i].Applied)
  73. }
  74. }
  75. fmt.Fprintf(&b, " (requested %s)", request)
  76. fmt.Fprintln(cmd.OutOrStdout(), b.String())
  77. }
  78. // anyColorMismatch reports whether any zone stored another color.
  79. func anyColorMismatch(results []colorResult) bool {
  80. for _, r := range results {
  81. if r.Mismatch() {
  82. return true
  83. }
  84. }
  85. return false
  86. }