#include #include #include #include #include #include #include #include "led_info.h" #include "gradient.h" void set_program_state(int *state, int *prev_state, int newstate){ *prev_state = *state; *state = newstate; } void redraw_mod_menu(char **mod_menu, int items, int selection){ clear(); printw("view mode>select mode>modify mode : segment %i\n\n", selection); for(int i = 0; i < items; i++) { cbreak(); if(selection == i) attron(A_STANDOUT); printw("%s\n", mod_menu[i]); if(selection == i) attroff(A_STANDOUT); } refresh(); } void redraw_seg_select(int segment) { clear(); printw("view mode>select mode : segment %i\n\n", segment); hline('-', 10); printw("Press enter to modify segment %i, or [q] to return.\n", segment); refresh(); } void resize_segments(segment_t *segments, unsigned int segment_amount, ws2811_t *ledstrip) { for(int i = 0; i < segment_amount; i++) { segments[i].size = LED_COUNT / segment_amount; } ws2811_render(ledstrip); } void refresh_strip(ws2811_t *ledstring, segment_t *segments, unsigned int segment_amount) { unsigned int s = 0; unsigned int led = 0; unsigned int led_pos = 0; for(; s < segment_amount; s++) { for(led = 0; led < segments[s].size; led++) { ledstring->channel[0].leds[led_pos] = segments[s].color; led_pos++; } } for(led = led_pos; led < LED_COUNT; led++) { ledstring->channel[0].leds[led] = segments[s - 1].color; } ws2811_render(ledstring); } unsigned int find_starting_pos(segment_t *segments, unsigned int index) { unsigned int position = 0; for(int i = 0; i < index; i++) position += segments[i].size; return(position); } int main() { initscr(); clear(); noecho(); cbreak(); keypad(stdscr, TRUE); ws2811_return_t ret; if((ret = ws2811_init(&ledstring)) != WS2811_SUCCESS) { printf("Error initilizing ws8211 strip: %s\n", ws2811_get_return_t_str(ret)); return(ret); } segment_t *segments = malloc(sizeof(segment_t)); //just start with one segments[0].size = LED_COUNT - 1; segments[0].color = 0; int prev_program_state = EXITED; int program_state = VIEW_MODE; int ui_selection = 0; unsigned int i = 0; unsigned int starting_pos; unsigned int segment_selection = 0; unsigned int segment_quanity = 1; int selection_state = 0; //just for asthetics int user_key; char *main_msg = "Press the arrow keys to select the segment, and enter to edit it.\nTo create new segments, select the segment you want to divide.\n"; char *mod_menu[9] = { "Change red", "Change green", "Change blue", "Change size", "Equalize sizes", "Create segment and equalize sizes", "Subdivide segment", "Delete", "Go back" }; int mod_items = 9; for(;;) { if(prev_program_state != program_state) { prev_program_state = program_state; switch(program_state) { case MODIFY_MODE: refresh_strip(&ledstring, segments, segment_quanity); redraw_mod_menu(mod_menu, mod_items, ui_selection); break; case MODIFY_R: printw("Modifying red value.\n"); refresh_strip(&ledstring, segments, segment_quanity); refresh(); break; case MODIFY_G: printw("Modifying green value.\n"); refresh_strip(&ledstring, segments, segment_quanity); refresh(); break; case MODIFY_B: printw("Modifying blue value.\n"); refresh_strip(&ledstring, segments, segment_quanity); refresh(); break; case MODIFY_SIZE: printw("Modifying size.\n"); refresh_strip(&ledstring, segments, segment_quanity); refresh(); break; case VIEW_MODE: clear(); refresh_strip(&ledstring, segments, segment_quanity); printw("view mode\n\n"); printw("%s\n", main_msg); cbreak(); break; case SELECT_MODE: redraw_seg_select(segment_selection); halfdelay(4); break; case EXITED: for(i = 0; i < LED_COUNT; i++) { ledstring.channel[0].leds[i] = 0; } ws2811_render(&ledstring); ws2811_fini(&ledstring); clear(); endwin(); printf("goodbye\n"); return 0; break; default: break; } } if((user_key = getch()) != ERR) { switch(user_key) { case KEY_UP: switch(program_state) { case VIEW_MODE: set_program_state(&program_state, &prev_program_state, SELECT_MODE); segment_selection = segment_quanity; break; case SELECT_MODE: if(segment_selection < segment_quanity - 1) segment_selection++; refresh_strip(&ledstring, segments, segment_quanity); redraw_seg_select(segment_selection); break; case MODIFY_MODE: if(ui_selection > 0) ui_selection--; redraw_mod_menu(mod_menu, mod_items, ui_selection); break; case MODIFY_R: if ((segments[segment_selection].color >> 16) < 0xff) { segments[segment_selection].color += 0x10000; refresh_strip(&ledstring, segments, segment_quanity); } break; case MODIFY_G: if ((segments[segment_selection].color >> 8 & 0xff) < 0xff) { segments[segment_selection].color += 0x100; refresh_strip(&ledstring, segments, segment_quanity); } break; case MODIFY_B: if ((segments[segment_selection].color & 0xff) < 0xff) { segments[segment_selection].color += 1; refresh_strip(&ledstring, segments, segment_quanity); } break; case MODIFY_SIZE: if(find_starting_pos(segments, segment_quanity - 1) + segments[segment_quanity - 1].size < LED_COUNT - 1) { segments[segment_selection].size++; refresh_strip(&ledstring, segments, segment_quanity); } break; default: break; } break; case KEY_DOWN: switch(program_state) { case VIEW_MODE: set_program_state(&program_state, &prev_program_state, SELECT_MODE); segment_selection = 0; break; case SELECT_MODE: if(segment_selection > 0) segment_selection--; refresh_strip(&ledstring, segments, segment_quanity); redraw_seg_select(segment_selection); break; case MODIFY_MODE: if(ui_selection < mod_items - 1) ui_selection++; redraw_mod_menu(mod_menu, mod_items, ui_selection); break; case MODIFY_R: if (segments[segment_selection].color >> 16) { segments[segment_selection].color -= 0x10000; refresh_strip(&ledstring, segments, segment_quanity); } break; case MODIFY_G: if (segments[segment_selection].color >> 8 & 0xff) { segments[segment_selection].color -= 0x100; refresh_strip(&ledstring, segments, segment_quanity); } break; case MODIFY_B: if (segments[segment_selection].color & 0xff) { segments[segment_selection].color -= 1; refresh_strip(&ledstring, segments, segment_quanity); } break; case MODIFY_SIZE: if(segments[segment_selection].size >= 4) { segments[segment_selection].size--; refresh_strip(&ledstring, segments, segment_quanity); } break; default: break; } break; case 10: switch(program_state) { case VIEW_MODE: set_program_state(&program_state, &prev_program_state, SELECT_MODE); break; case SELECT_MODE: set_program_state(&program_state, &prev_program_state, MODIFY_MODE); break; case MODIFY_MODE: switch(ui_selection) { case M_RED: set_program_state(&program_state, &prev_program_state, MODIFY_R); break; case M_GREEN: set_program_state(&program_state, &prev_program_state, MODIFY_G); break; case M_BLUE: set_program_state(&program_state, &prev_program_state, MODIFY_B); break; case M_SIZE: set_program_state(&program_state, &prev_program_state, MODIFY_SIZE); break; case M_SIZE_EQ: resize_segments(segments, segment_quanity, &ledstring); break; case M_CREATE_EQ: set_program_state(&program_state, &prev_program_state, MODIFY_MODE); segments[segment_selection].size = segments[segment_selection].size / 2; segment_quanity++; segments = realloc(segments, sizeof(segment_t) * segment_quanity); memmove(&segments[segment_selection + 2], &segments[segment_selection] + sizeof(segment_t), &segments[segment_quanity - 1] - &segments[segment_selection + 1]); memcpy(&segments[segment_selection + 1], &segments[segment_selection], sizeof(segment_t)); segment_selection++; resize_segments(segments, segment_quanity, &ledstring); break; case M_CREATE_SUB: //create new segment //TODO: account for rounding set_program_state(&program_state, &prev_program_state, MODIFY_MODE); segments[segment_selection].size = segments[segment_selection].size / 2; segment_quanity++; segments = realloc(segments, sizeof(segment_t) * segment_quanity); memmove(&segments[segment_selection + 2], &segments[segment_selection] + sizeof(segment_t), &segments[segment_quanity - 1] - &segments[segment_selection + 1]); memcpy(&segments[segment_selection + 1], &segments[segment_selection], sizeof(segment_t)); segment_selection++; break; case M_DEL: //delete code //TODO: resize if(segment_quanity - 1 > 0) { set_program_state(&program_state, &prev_program_state, VIEW_MODE); if(segment_selection == (segment_quanity - 1)) { segments[segment_selection - 1].size += segments[segment_selection].size; } else { segments[segment_selection + 1].size += segments[segment_selection].size; } memmove(&segments[segment_selection], &segments[segment_selection + 1], &segments[segment_quanity] - &segments[segment_selection + 1]); segment_quanity--; segment_selection--; segments = realloc(segments, &segments[segment_quanity] - &segments[0]); refresh(); break; } case M_BACK: set_program_state(&program_state, &prev_program_state, VIEW_MODE); break; default: break; } break; case MODIFY_R: case MODIFY_G: case MODIFY_B: case MODIFY_SIZE: set_program_state(&program_state, &prev_program_state, MODIFY_MODE); break; default: break; } break; case 'q': switch(program_state) { case VIEW_MODE: set_program_state(&program_state, &prev_program_state, EXITED); break; case SELECT_MODE: set_program_state(&program_state, &prev_program_state, VIEW_MODE); break; case MODIFY_MODE: set_program_state(&program_state, &prev_program_state, SELECT_MODE); break; case MODIFY_R: case MODIFY_G: case MODIFY_B: case MODIFY_SIZE: set_program_state(&program_state, &prev_program_state, MODIFY_MODE); default: break; } break; default: break; } } else if(program_state == SELECT_MODE) { starting_pos = find_starting_pos(segments, segment_selection); for(i = starting_pos; i <= starting_pos + segments[segment_selection].size; i++) { ledstring.channel[0].leds[i] = (selection_state ? (i % 2) : ((i+1) % 2)) ? 0xffffff : 0; } selection_state = selection_state ? 0 : 1; ws2811_render(&ledstring); } } return 0; }