diff --git a/src/calc.c b/src/calc.c index 0038de6..16d1e35 100644 --- a/src/calc.c +++ b/src/calc.c @@ -2,43 +2,41 @@ #include #include "calc.h" -static inline int8_t tokenCount() { - if(!using_func_tokens) - return sizeof(tokens) / sizeof(tokens[0]); +/** Text Editing **/ - return sizeof(func_tokens) / sizeof(func_tokens[0]); +// Get the number of tokens in the current list +static inline int8_t tokenCount() +{ + return using_func_tokens? + sizeof(func_tokens) / sizeof(func_tokens[0]) : + sizeof(tokens) / sizeof(tokens[0]); } -static inline char* getToken(int8_t n) { - if(!using_func_tokens) - return tokens[n % tokenCount()]; - - return func_tokens[n % tokenCount()]; +// Get current token from tokens[] or func_tokens[], as appropriate +static inline const char* getToken(int8_t n) +{ + int8_t t = n % tokenCount(); + return using_func_tokens? func_tokens[t] : tokens[t]; } -// Currently selected button, starts on '(' -static int8_t selected_token = 1; - // Update the current code text with the contents of `mytext`, // and add the current selected_token to the end static void updateText() { + const char *token = getToken(selected_token); + strcpy(temptext, mytext); - const char *token = getToken(selected_token); - if(token[0] == ' ') { - strcat(temptext, "_"); - } else if(token[0] == '\n') { - strcat(temptext, "\\n"); - } else { - strcat(temptext, token); - } + strcat(temptext, token[0] == ' ' ? "_": // Display space as underscore + token[0] == '\n'? "\\n": // Display newline as \n + token); // Display others literally text_layer_set_text(s_input_text_layer, temptext); } -// Button handler -static void up_down_handler(ClickRecognizerRef recognizer, void *context){ +// Cycle through the current list of tokens +static void cycle_tokens(ClickRecognizerRef recognizer, void *context) +{ // Change current token if(click_recognizer_get_button_id(recognizer) == BUTTON_ID_DOWN) selected_token++; @@ -54,37 +52,41 @@ static void up_down_handler(ClickRecognizerRef recognizer, void *context){ updateText(); } -static void backspace() +/** + * In normal token list, backspace if possible, otherwise return to script list + * In function token list, return to normal token list + */ +static void click_backspace(ClickRecognizerRef recognizer, void *context) { - int8_t i = 0; - while(mytext[++i] != '\0') { ; } - mytext[i-1] = '\0'; - updateText(); -} - -// Backspace if possible, otherwise close the app -static void back_handler(ClickRecognizerRef recognizer, void *context) { if(!using_func_tokens) { if(mytext[0] == '\0') { window_stack_remove(window_stack_get_top_window(), true); } else { - backspace(); + mytext[strlen(mytext) - 1] = '\0'; + updateText(); } } else { - using_func_tokens = 0; + using_func_tokens = false; updateText(); } } // Adds the current string to the main string -static void enter(){ +static void add_token() +{ strcat(mytext, getToken(selected_token)); selected_token = 0; + if(using_func_tokens) { + using_func_tokens = false; + } updateText(); } +/** Code running and saving **/ + // Calculate result, display it and reset -static void calculate(){ +static void calculate() +{ Object obj = parseEval(mytext, &env); char temp[RESULT_LENGTH-2] = ""; @@ -94,21 +96,23 @@ static void calculate(){ } // Button press handler -static void select_handler(ClickRecognizerRef recognizer, void *context){ +static void click_select(ClickRecognizerRef recognizer, void *context) +{ if(!using_func_tokens && selected_token == tokenCount() - 1) { calculate(); } else if(!using_func_tokens && selected_token == tokenCount() - 2) { - using_func_tokens = 1; + using_func_tokens = true; selected_token = 0; updateText(); } else { - enter(); + add_token(); } } -static void long_select_handler(ClickRecognizerRef recognizer, void *context){ - int8_t i = 0; - while(temptext[++i] != '\0') { ; } +// Saves text in editor to persistent storage +static void click_save(ClickRecognizerRef recognizer, void *context) +{ + int8_t i = strlen(temptext); for(unsigned j = 0; j < strlen(getToken(selected_token)); j++) { temptext[i-(1 + j)] = '\0'; } @@ -117,89 +121,25 @@ static void long_select_handler(ClickRecognizerRef recognizer, void *context){ window_stack_pop(true); } -static void click_config_provider(void *context) { - // Register click handlers - window_single_repeating_click_subscribe(BUTTON_ID_UP, 100, up_down_handler); - window_single_repeating_click_subscribe(BUTTON_ID_DOWN, 100, up_down_handler); - window_single_click_subscribe(BUTTON_ID_SELECT, select_handler); - window_long_click_subscribe(BUTTON_ID_SELECT, 500, long_select_handler, NULL); - window_single_click_subscribe(BUTTON_ID_BACK, back_handler); -} - -static uint16_t get_num_rows_callback(MenuLayer *menu_layer, - uint16_t section_index, void *context) { - return NUM_ROWS; -} - -static void draw_row_callback(GContext *ctx, const Layer *cell_layer, - MenuIndex *cell_index, void *context) { - static char s_buff[16]; - snprintf(s_buff, sizeof(s_buff), "Script %d", 1 + (int)cell_index->row); - - // Draw this row's index - menu_cell_basic_draw(ctx, cell_layer, s_buff, NULL, NULL); -} - -static int16_t get_cell_height_callback(struct MenuLayer *menu_layer, - MenuIndex *cell_index, void *context) { - const int16_t cell_height = 44; - return cell_height; -} - -void code_window_push() { - if(!s_code_window) { - s_code_window = window_create(); - WindowHandlers wh = { - .load = code_window_load, - .unload = code_window_unload }; - window_set_window_handlers(s_code_window, wh); - } - - window_stack_push(s_code_window, true); -} - -static void select_callback(struct MenuLayer *menu_layer, - MenuIndex *cell_index, void *context) +// Sets the code_window click functions +static void code_click_subscribe(void *context) { - current_code = cell_index->row; - code_window_push(); + window_single_repeating_click_subscribe(BUTTON_ID_UP, 100, cycle_tokens); + window_single_repeating_click_subscribe(BUTTON_ID_DOWN, 100, cycle_tokens); + window_single_click_subscribe(BUTTON_ID_SELECT, click_select); + window_long_click_subscribe(BUTTON_ID_SELECT, 500, click_save, NULL); + window_single_click_subscribe(BUTTON_ID_BACK, click_backspace); } -static void menu_load(Window *window) -{ - Layer *window_layer = window_get_root_layer(window); - GRect bounds = layer_get_bounds(window_layer); - - s_menu_layer = menu_layer_create(bounds); - menu_layer_set_click_config_onto_window(s_menu_layer, window); -#if defined(PBL_COLOR) - menu_layer_set_normal_colors(s_menu_layer, GColorBlack, GColorWhite); - menu_layer_set_highlight_colors(s_menu_layer, GColorDukeBlue, GColorWhite); -#endif - menu_layer_set_callbacks(s_menu_layer, NULL, (MenuLayerCallbacks) { - .get_num_rows = get_num_rows_callback, - .draw_row = draw_row_callback, - .get_cell_height = get_cell_height_callback, - .select_click = select_callback, - }); - layer_add_child(window_layer, menu_layer_get_layer(s_menu_layer)); -} - -static void menu_unload(Window *window) -{ - menu_layer_destroy(s_menu_layer); -} - -void code_window_load(Window *window) +static void code_window_load(Window *window) { Layer *window_layer = window_get_root_layer(window); GRect bounds = layer_get_bounds(window_layer); // Register click config provider - window_set_click_config_provider(s_code_window, click_config_provider); + window_set_click_config_provider(s_code_window, code_click_subscribe); // Input text layer setup - // GRect text_bounds = GRect(6, 6, 132, 127); s_input_text_layer = text_layer_create(bounds); text_layer_set_text(s_input_text_layer, getToken(1)); text_layer_set_font(s_input_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD)); @@ -223,7 +163,7 @@ void code_window_load(Window *window) } } -void code_window_unload(Window *window) +static void code_window_unload(Window *window) { // Save the current code text persist_write_string(current_code, temptext); @@ -235,13 +175,86 @@ void code_window_unload(Window *window) s_code_window = NULL; } -void custom_load(Window *window) +void code_window_push() +{ + if(!s_code_window) { + s_code_window = window_create(); + WindowHandlers wh = { + .load = code_window_load, + .unload = code_window_unload }; + window_set_window_handlers(s_code_window, wh); + } + + window_stack_push(s_code_window, true); +} + +/** Menu Window **/ + +static void select_callback(struct MenuLayer *menu_layer, + MenuIndex *cell_index, void *context) +{ + current_code = cell_index->row; + code_window_push(); +} + +static uint16_t get_num_rows_callback(MenuLayer *menu_layer, + uint16_t section_index, void *context) +{ + return SCRIPT_COUNT; +} + +static void draw_row_callback(GContext *ctx, const Layer *cell_layer, + MenuIndex *cell_index, void *context) +{ + static char s_buff[16]; + snprintf(s_buff, sizeof(s_buff), "Script %d", 1 + (int)cell_index->row); + + // Draw this row's index + menu_cell_basic_draw(ctx, cell_layer, s_buff, NULL, NULL); +} + +static int16_t get_cell_height_callback(struct MenuLayer *menu_layer, + MenuIndex *cell_index, void *context) +{ + return CELL_HEIGHT; +} + +static void menu_load(Window *window) +{ + Layer *window_layer = window_get_root_layer(window); + GRect bounds = layer_get_bounds(window_layer); + + s_menu_layer = menu_layer_create(bounds); + menu_layer_set_click_config_onto_window(s_menu_layer, window); + + #if defined(PBL_COLOR) + menu_layer_set_normal_colors(s_menu_layer, GColorBlack, GColorWhite); + menu_layer_set_highlight_colors(s_menu_layer, GColorDukeBlue, GColorWhite); + #endif + + menu_layer_set_callbacks(s_menu_layer, NULL, (MenuLayerCallbacks) { + .get_num_rows = get_num_rows_callback, + .draw_row = draw_row_callback, + .get_cell_height = get_cell_height_callback, + .select_click = select_callback, + }); + layer_add_child(window_layer, menu_layer_get_layer(s_menu_layer)); +} + +static void menu_unload(Window *window) +{ + menu_layer_destroy(s_menu_layer); +} + +/** Custom Window **/ + +static void custom_load(Window *window) { Layer *window_layer = window_get_root_layer(window); GRect bounds = layer_get_bounds(window_layer); // Register click config provider - window_set_click_config_provider(s_custom_window, click_config_provider); + window_set_click_config_provider(s_custom_window, code_click_subscribe); // Header text layer setup s_heading_text_layer = text_layer_create(bounds); @@ -255,10 +268,9 @@ void custom_load(Window *window) window_stack_push(s_custom_window, true); } -void custom_unload(Window *window) +static void custom_unload(Window *window) { text_layer_destroy(s_heading_text_layer); - //text_layer_destroy(s_input_text_layer); window_destroy(window); s_custom_window = NULL; @@ -284,15 +296,19 @@ Object add_window(Object obj1, Object obj2, struct Environment *env) return numberObject(1); } -static struct Environment pebbleEnv() { +/** General **/ + +static struct Environment pebbleEnv() +{ struct Environment e = defaultEnv(); // Needs two args addFunc("window", &add_window, &e); - parseEval("(def w (fn (a) (window a 1)))", &e); + parseEval("(def win (fn (a) (window a 1)))", &e); return e; } -static void init(void) { +static void init(void) +{ env = pebbleEnv(); s_menu_window = window_create(); window_set_window_handlers(s_menu_window, (WindowHandlers) { @@ -302,13 +318,15 @@ static void init(void) { window_stack_push(s_menu_window, true); } -static void deinit(void) { +static void deinit(void) +{ deleteEnv(&env); text_layer_destroy(s_input_text_layer); window_destroy(s_menu_window); } -int main(void) { +int main(void) +{ init(); app_event_loop(); deinit(); diff --git a/src/calc.h b/src/calc.h index 91db198..3bac1f1 100644 --- a/src/calc.h +++ b/src/calc.h @@ -6,9 +6,9 @@ #define SMAX_LENGTH 256 #define RESULT_LENGTH 20 -#define END_PHRASE "END" +#define CELL_HEIGHT 44 -#define NUM_ROWS 5 +#define SCRIPT_COUNT 5 Window *s_menu_window; Window *s_code_window; @@ -28,6 +28,10 @@ TextLayer *s_list_message_layer; int current_code; +// Currently selected button, starts on '(' +static int8_t selected_token = 1; + + // PebbLisp environment static struct Environment env; @@ -40,7 +44,7 @@ char temptext[SMAX_LENGTH] = ""; // The result of execution char resulttext[RESULT_LENGTH] = ""; -char *tokens[] = { +const char *tokens[] = { " ", "(", ")", "+ ", "- ", "* ", "/ ", "1","2","3", @@ -49,21 +53,19 @@ char *tokens[] = { "a", "b", "c", "d", "e", "= ", "< ", "> ", "\"", - "cat", "map", "fn", "def", "if", "\n", + "cat", "map", "fil", + "fn", "def", "if", "\n", "...", - END_PHRASE + "END" }; -char *func_tokens[] = { +const char *func_tokens[] = { "spent ", "window ", "max ", "min ", "sq ", "cube ", "exp " }; -int using_func_tokens = 0; - -void code_window_load(Window *window); -void code_window_unload(Window *window); +bool using_func_tokens = false; #endif