#pragma once
#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;
if (!keyToggledOn(key_state))
return kaleidoscope::EventHandlerResult::EVENT_CONSUMED;
if (row >= ROWS || col >= COLS)
return kaleidoscope::EventHandlerResult::EVENT_CONSUMED;
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;
}
if (which_half == BOTH_HALVES ||
(col < 8 && which_half == LEFT_HALF) ||
(col >= 8 && which_half == RIGHT_HALF)) {
return SHOW;
}
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;
};
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);
};
return colors[map[row][col]];
}
};
ColorPicker theColorPicker;