aboutsummaryrefslogtreecommitdiff
path: root/color-picker.h
diff options
context:
space:
mode:
Diffstat (limited to 'color-picker.h')
-rw-r--r--color-picker.h335
1 files changed, 335 insertions, 0 deletions
diff --git a/color-picker.h b/color-picker.h
new file mode 100644
index 0000000..d442c79
--- /dev/null
+++ b/color-picker.h
@@ -0,0 +1,335 @@
+// -*- mode: c++ -*-
+#pragma once
+
+/*
+ this class implements a color theme editor as a LED mode
+
+ when this mode is active, nothing gets sent to the host
+
+ the Fn keys switch into editing mode, with that half housing the controls
+
+ the controls are:
+
+ * 8 keys for the 8 colors we currently use
+ * 3 rows of 4 keys to change the active color in the HSV space
+
+ pressing a key on the non-control half of the keyboard assigns the
+ current color to that key
+ */
+
+#include <kaleidoscope/plugin/LEDControl.h>
+#include <kaleidoscope/plugin/LEDControl/LEDUtils.h>
+#include <kaleidoscope/plugin/FocusSerial.h>
+
+class ColorPicker : public kaleidoscope::plugin::LEDMode {
+public:
+ ColorPicker(void) : current_index(0), which_half(BOTH_HALVES),
+ colors{}, map{},
+ hsv_colors{
+ { .h=0, .s=150, .v=128 },
+ { .h=32, .s=150, .v=128 },
+ { .h=64, .s=150, .v=128 },
+ { .h=96, .s=150, .v=128 },
+ { .h=128, .s=150, .v=128 },
+ { .h=160, .s=150, .v=128 },
+ { .h=192, .s=150, .v=128 },
+ { .h=224, .s=150, .v=128 },
+ }
+ {
+ for (uint8_t i=0;i<16;++i) {
+ hsv& col = hsv_colors[i];
+ colors[i] = hsvToRgb(col.h,col.s,col.v);
+ }
+ }
+
+ kaleidoscope::EventHandlerResult onKeyswitchEvent(Key &mapped_key, byte row, byte col, uint8_t key_state) {
+ if (!Kaleidoscope.has_leds || !is_active())
+ return kaleidoscope::EventHandlerResult::OK;
+
+ // only care at press time
+ if (!keyToggledOn(key_state))
+ return kaleidoscope::EventHandlerResult::EVENT_CONSUMED;
+
+ // uh?
+ if (row >= ROWS || col >= COLS)
+ return kaleidoscope::EventHandlerResult::EVENT_CONSUMED;
+
+ // pressing a Fn makes that half the "editing" half; pressing it
+ // again disables editing
+
+ picker_key key = whichKey(row,col);
+ switch (key) {
+ case OFF:
+ break;
+ case SHOW:
+ map[row][col] = current_index; break;
+ case SWITCH_LEFT:
+ which_half = which_half == RIGHT_HALF ? BOTH_HALVES : RIGHT_HALF; break;
+ case SWITCH_RIGHT:
+ which_half = which_half == LEFT_HALF ? BOTH_HALVES : LEFT_HALF; break;
+ case COLOR_1 ... COLOR_8:
+ current_index = key - COLOR_1; break;
+ case HUE_M10:
+ updateCurrentColor(-10,0,0); break;
+ case HUE_M1:
+ updateCurrentColor(-1,0,0); break;
+ case HUE_P1:
+ updateCurrentColor(+1,0,0); break;
+ case HUE_P10:
+ updateCurrentColor(+10,0,0); break;
+ case SAT_M10:
+ updateCurrentColor(0,-10,0); break;
+ case SAT_M1:
+ updateCurrentColor(0,-1,0); break;
+ case SAT_P1:
+ updateCurrentColor(0,+1,0); break;
+ case SAT_P10:
+ updateCurrentColor(0,+10,0); break;
+ case VAL_M10:
+ updateCurrentColor(0,0,-10); break;
+ case VAL_M1:
+ updateCurrentColor(0,0,-1); break;
+ case VAL_P1:
+ updateCurrentColor(0,0,+1); break;
+ case VAL_P10:
+ updateCurrentColor(0,0,+10); break;
+ };
+
+ return kaleidoscope::EventHandlerResult::EVENT_CONSUMED;
+ }
+
+ kaleidoscope::EventHandlerResult onFocusEvent(const char *command) {
+ if (Focus.handleHelp(command, PSTR("color-picker.dump")))
+ return kaleidoscope::EventHandlerResult::OK;
+
+ if (strncmp_P(command, PSTR("color-picker."), 13) != 0)
+ return kaleidoscope::EventHandlerResult::OK;
+
+ if (strcmp_P(command + 13, PSTR("dump")) != 0)
+ return kaleidoscope::EventHandlerResult::OK;
+
+ for (uint8_t i=0;i<16;++i) {
+ Focus.send(F("color"),i,colors[i],Focus.NEWLINE);
+ }
+ Focus.send(F("map\n"));
+ for (uint8_t r=0;r<ROWS;++r) {
+ for (uint8_t c=0;c<COLS;++c) {
+ Focus.send(map[r][c]);
+ }
+ Focus.send(Focus.NEWLINE);
+ }
+
+ return kaleidoscope::EventHandlerResult::EVENT_CONSUMED;
+ }
+
+protected:
+ void update(void) {
+ for (uint8_t r = 0; r < ROWS; r++) {
+ for (uint8_t c = 0; c < COLS; c++) {
+ LEDControl.setCrgbAt(r, c, getColor(r,c));
+ }
+ }
+ }
+ void refreshAt(byte r, byte c) final {
+ LEDControl.setCrgbAt(r, c, getColor(r,c));
+ }
+
+private:
+ uint8_t current_index;
+ enum { BOTH_HALVES, LEFT_HALF, RIGHT_HALF } which_half;
+ cRGB colors[16];
+ uint8_t map[ROWS][COLS];
+ struct hsv { uint8_t h; uint8_t s; uint8_t v; }
+ hsv_colors[16];
+
+ static inline uint8_t add_and_clamp(uint8_t value, int8_t delta) {
+ int16_t result = ((int16_t)value) + delta;
+ if (result < 0) return 0;
+ if (result > 255) return 255;
+ return result;
+ }
+ static inline uint8_t add_and_wrap(uint8_t value, int8_t delta) {
+ int16_t result = ((int16_t)value) + delta;
+ if (result < 0) return result+255;
+ if (result > 255) return result-255;
+ return result;
+ }
+
+ void updateCurrentColor(int8_t delta_h, int8_t delta_s, int8_t delta_v) {
+ hsv& color = hsv_colors[current_index];
+ color.h = add_and_wrap(color.h,delta_h);
+ color.s = add_and_clamp(color.s,delta_s);
+ color.v = add_and_clamp(color.v,delta_v);
+
+ colors[current_index] = hsvToRgb(color.h,color.s,color.v);
+ }
+
+ bool is_active() {
+ return LEDControl.get_mode() == this;
+ }
+
+ typedef enum { OFF, SHOW,
+ SWITCH_LEFT, SWITCH_RIGHT,
+ COLOR_1, COLOR_2, COLOR_3, COLOR_4,
+ COLOR_5, COLOR_6, COLOR_7, COLOR_8,
+ HUE_M10, HUE_M1, HUE_P1, HUE_P10,
+ SAT_M10, SAT_M1, SAT_P1, SAT_P10,
+ VAL_M10, VAL_M1, VAL_P1, VAL_P10 }
+ picker_key;
+
+ picker_key whichKey(byte row, byte col) {
+ if (row == 3 && col == 6) {
+ return SWITCH_LEFT;
+ }
+ else if (row == 3 && col == 9) {
+ return SWITCH_RIGHT;
+ }
+ else if (row == 0 && col == 6) {
+ return OFF; // LED key, always off
+ }
+
+ // non-editing half? show it
+ if (which_half == BOTH_HALVES ||
+ (col < 8 && which_half == LEFT_HALF) ||
+ (col >= 8 && which_half == RIGHT_HALF)) {
+ return SHOW;
+ }
+
+ // pretend we're always showing the right half, by changing col if we're not
+ if (which_half == LEFT_HALF) {
+ switch (col) {
+ case 8: col=6; break;
+ case 9: col=7; break;
+ case 10: col=2; break;
+ case 11: col=3; break;
+ case 12: col=4; break;
+ case 13: col=5; break;
+ case 14: col=0; break;
+ case 15: col=1; break;
+ }
+ }
+
+ switch (col) {
+ case 0:
+ switch (row) {
+ case 0:
+ return COLOR_1;
+ case 1:
+ return COLOR_2;
+ case 2:
+ return COLOR_3;
+ case 3:
+ return COLOR_4;
+ default:
+ return OFF;
+ };
+ case 1:
+ switch (row) {
+ case 0:
+ return COLOR_5;
+ case 1:
+ return COLOR_6;
+ case 2:
+ return COLOR_7;
+ case 3:
+ return COLOR_8;
+ default:
+ return OFF;
+ };
+ case 2:
+ switch (row) {
+ case 1:
+ return HUE_M10;
+ case 2:
+ return SAT_M10;
+ case 3:
+ return VAL_M10;
+ default:
+ return OFF;
+ };
+ case 3:
+ switch (row) {
+ case 1:
+ return HUE_M1;
+ case 2:
+ return SAT_M1;
+ case 3:
+ return VAL_M1;
+ default:
+ return OFF;
+ };
+ case 4:
+ switch (row) {
+ case 1:
+ return HUE_P1;
+ case 2:
+ return SAT_P1;
+ case 3:
+ return VAL_P1;
+ default:
+ return OFF;
+ };
+ case 5:
+ switch (row) {
+ case 1:
+ return HUE_P10;
+ case 2:
+ return SAT_P10;
+ case 3:
+ return VAL_P10;
+ default:
+ return OFF;
+ };
+ default:
+ return OFF;
+ };
+
+ // won't be reached
+ return SHOW;
+ }
+
+ cRGB getColor(byte row, byte col) {
+ picker_key key = whichKey(row,col);
+ switch (key) {
+ case SHOW:
+ return colors[map[row][col]];
+ case OFF:
+ case SWITCH_LEFT:
+ case SWITCH_RIGHT:
+ return CRGB(0,0,0);
+ case COLOR_1...COLOR_8:
+ return colors[key - COLOR_1];
+
+ case HUE_M10:
+ return hsvToRgb(add_and_wrap(hsv_colors[current_index].h,-10),255,128);
+ case HUE_M1:
+ return hsvToRgb(add_and_wrap(hsv_colors[current_index].h,-1),255,128);
+ case HUE_P1:
+ return hsvToRgb(add_and_wrap(hsv_colors[current_index].h,+1),255,128);
+ case HUE_P10:
+ return hsvToRgb(add_and_wrap(hsv_colors[current_index].h,+10),255,128);
+ case SAT_M10:
+ return hsvToRgb(hsv_colors[current_index].h,50,128);
+ case SAT_M1:
+ return hsvToRgb(hsv_colors[current_index].h,100,128);
+ case SAT_P1:
+ return hsvToRgb(hsv_colors[current_index].h,150,128);
+ case SAT_P10:
+ return hsvToRgb(hsv_colors[current_index].h,200,128);
+
+ case VAL_M10:
+ return hsvToRgb(hsv_colors[current_index].h,128,50);
+ case VAL_M1:
+ return hsvToRgb(hsv_colors[current_index].h,128,100);
+ case VAL_P1:
+ return hsvToRgb(hsv_colors[current_index].h,128,150);
+ case VAL_P10:
+ return hsvToRgb(hsv_colors[current_index].h,128,200);
+ };
+
+ // won't be reached
+ return colors[map[row][col]];
+ }
+};
+
+ColorPicker theColorPicker;