#include #include #include "calc.h" static inline int8_t tokenCount() { return sizeof(tokens) / sizeof(tokens[0]); } static inline char* getToken(int8_t n) { return tokens[n % tokenCount()]; } // 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() { 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); } text_layer_set_text(s_input_text_layer, temptext); } // Button handler static void up_down_handler(ClickRecognizerRef recognizer, void *context){ // Change current token if(click_recognizer_get_button_id(recognizer) == BUTTON_ID_DOWN) selected_token++; else selected_token--; // If selected token is outside of range, wrap around if(selected_token < 0) selected_token = tokenCount() - 1; else if(selected_token >= tokenCount()) selected_token = 0; updateText(); } // Backspace if possible, otherwise close the app static void back_handler(ClickRecognizerRef recognizer, void *context) { if(mytext[0] == '\0') { window_stack_remove(window_stack_get_top_window(), true); } else { int8_t i = 0; while(mytext[++i] != '\0') { ; } mytext[i-1] = '\0'; updateText(); } } // Adds the current string to the main string static void enter(){ strcat(mytext, getToken(selected_token)); selected_token = 0; updateText(); } // Calculate result, display it and reset static void calculate(){ Object obj = parseEval(mytext, &env); char temp[RESULT_LENGTH-2] = ""; stringObj(temp, &obj); snprintf(resulttext, RESULT_LENGTH, "R:%s", temp); selected_token = 0; text_layer_set_text(s_result_text_layer, resulttext); } // Button press handler static void select_handler(ClickRecognizerRef recognizer, void *context){ if(selected_token == sizeof(tokens) / sizeof(tokens[0]) - 1) calculate(); else enter(); } static void long_select_handler(ClickRecognizerRef recognizer, void *context){ persist_write_string(current_code, temptext); 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) { current_code = cell_index->row; code_window_push(); } 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) { 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); // 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)); layer_add_child(window_get_root_layer(s_code_window), text_layer_get_layer(s_input_text_layer)); // Result text layer setup GRect result_bounds = GRect(6, 128, 132, 132); s_result_text_layer = text_layer_create(result_bounds); text_layer_set_text(s_result_text_layer, "R: "); text_layer_set_font(s_result_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD)); text_layer_set_text_alignment(s_result_text_layer, GTextAlignmentRight); layer_add_child(window_get_root_layer(s_code_window), text_layer_get_layer(s_result_text_layer)); // Push the window, setting the window animation to 'true' window_stack_push(s_code_window, true); // If possible, load the previous code text // Object obj = parseEval("(def ad (fn (a) (* 3 a)))", &env); // Object obj2 = parseEval("(map ad (1 50 99))", &env); // printObj(&obj); // printObj(&obj2); // cleanObject(&obj); // cleanObject(&obj2); if(persist_exists(current_code)) { persist_read_string(current_code, mytext, SMAX_LENGTH); updateText(); } } void code_window_unload(Window *window) { // Save the current code text persist_write_string(current_code, temptext); text_layer_destroy(s_result_text_layer); text_layer_destroy(s_input_text_layer); window_destroy(window); s_code_window = NULL; } static void init(void) { env = defaultEnv(); s_menu_window = window_create(); window_set_window_handlers(s_menu_window, (WindowHandlers) { .load = menu_load, .unload = menu_unload }); window_stack_push(s_menu_window, true); } static void deinit(void) { deleteEnv(&env); text_layer_destroy(s_input_text_layer); window_destroy(s_menu_window); } int main(void) { init(); app_event_loop(); deinit(); }