// -*- 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 #include #include 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(KeyEvent &event) { if (!Kaleidoscope.has_leds || !is_active()) return kaleidoscope::EventHandlerResult::OK; // only care at press time if (!keyToggledOn(event.state)) return kaleidoscope::EventHandlerResult::EVENT_CONSUMED; // uh? if (event.addr.row() >= kaleidoscope_internal::device.matrix_rows || event.addr.col() >= kaleidoscope_internal::device.matrix_columns) return kaleidoscope::EventHandlerResult::EVENT_CONSUMED; // pressing a Fn makes that half the "editing" half; pressing it // again disables editing picker_key key = whichKey(event.addr.row(),event.addr.col()); switch (key) { case OFF: break; case LED_KEY: return kaleidoscope::EventHandlerResult::OK; // let other plugins deal with this case SHOW: map[event.addr.row()][event.addr.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 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, LED_KEY, 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 LED_KEY; } // 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 LED_KEY: 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;