#include "src/resource_ids.auto.h" #include // types typedef struct SetterTime { uint8_t HourWIP; uint8_t MinuteWIP; uint8_t HourSet; uint8_t MinuteSet; } __attribute__((__packed__)) SetterTime; // layer-age static Window *s_window; static Layer *s_top_bar_layer; static Layer *s_bottom_bar_layer; static BitmapLayer *s_clock_bmp_layer; static BitmapLayer *s_check_bmp_layer; static TextLayer *s_countdown_txt_layer; static TextLayer *s_setter_txt_layer; static Layer *s_highlight_layer; // bitmaps static GBitmap *s_clock_bmp; static GBitmap *s_check_bmp; // global vars static uint8_t s_highlight_pos = 0; static struct SetterTime s_setter_time; // constants static const uint8_t s_edge_bar_height = ((PBL_DISPLAY_HEIGHT / 7) * 2); static const GColor s_primary_color = GColorJaegerGreen; static const GColor s_highlight_color = GColorMediumAquamarine; ///////////////////////////////// static void seconds_handler(struct tm *tick_time, TimeUnits units_changed) { struct tm now_tm = *tick_time; // Build the target time today struct tm target_tm = now_tm; target_tm.tm_hour = s_setter_time.HourSet; target_tm.tm_min = s_setter_time.MinuteSet; target_tm.tm_sec = 0; time_t now = mktime(&now_tm); time_t target = mktime(&target_tm); if (target <= now) { target += SECONDS_PER_DAY; } int32_t diff = (int32_t)(target - now); uint8_t hours = diff / 3600; uint8_t minutes = (diff % 3600) / 60; uint8_t seconds = diff % 60; static char s_countdown_buffer[9]; snprintf(s_countdown_buffer, sizeof(s_countdown_buffer), "%02d:%02d:%02d", hours, minutes, seconds); text_layer_set_text(s_countdown_txt_layer, s_countdown_buffer); } static void update_countdown_display() { time_t now = time(NULL); seconds_handler(localtime(&now), SECOND_UNIT); } static void update_setter_display() { static char s_setter_buffer[PBL_IF_ROUND_ELSE(8, 12)]; snprintf(s_setter_buffer, sizeof(s_setter_buffer), PBL_IF_ROUND_ELSE("%02d : %02d", "%02d : %02d"), s_setter_time.HourWIP, s_setter_time.MinuteWIP); text_layer_set_text(s_setter_txt_layer, s_setter_buffer); } static void up_click_handler(void *recognizer, void *ctx) { switch (s_highlight_pos) { case 0: if (s_setter_time.HourWIP == 23) { s_setter_time.HourWIP = 0; } else { s_setter_time.HourWIP++; } break; case 1: if (s_setter_time.MinuteWIP == 59) { s_setter_time.MinuteWIP = 0; } else { s_setter_time.MinuteWIP++; } break; default: return; } update_setter_display(); } static void down_click_handler(void *recognizer, void *ctx) { switch (s_highlight_pos) { case 0: if (s_setter_time.HourWIP == 0) { s_setter_time.HourWIP = 23; } else { s_setter_time.HourWIP--; } break; case 1: if (s_setter_time.MinuteWIP == 0) { s_setter_time.MinuteWIP = 59; } else { s_setter_time.MinuteWIP--; } break; default: return; } update_setter_display(); } static void select_click_handler(void *recognizer, void *ctx) { if (s_highlight_pos == 2) { s_setter_time.HourSet = s_setter_time.HourWIP; s_setter_time.MinuteSet = s_setter_time.MinuteWIP; update_countdown_display(); s_highlight_pos = 0; } else { s_highlight_pos++; } layer_mark_dirty(s_highlight_layer); layer_mark_dirty(s_bottom_bar_layer); } static void back_click_handler(void *recognizer, void *ctx) { if (s_highlight_pos == 0) { window_stack_pop_all(true); // exit app } else { s_highlight_pos--; } layer_mark_dirty(s_highlight_layer); layer_mark_dirty(s_bottom_bar_layer); } static void click_config_provider(void *ctx) { window_single_repeating_click_subscribe(BUTTON_ID_UP, 60, up_click_handler); window_single_repeating_click_subscribe(BUTTON_ID_DOWN, 60, down_click_handler); window_single_click_subscribe(BUTTON_ID_SELECT, select_click_handler); window_single_click_subscribe(BUTTON_ID_BACK, back_click_handler); } static void top_bar_layer_update_proc(Layer *layer, GContext *ctx) { graphics_context_set_fill_color(ctx, s_primary_color); graphics_fill_rect(ctx, layer_get_bounds(layer), 0, GCornerNone); } static void bottom_bar_layer_update_proc(Layer *layer, GContext *ctx) { graphics_context_set_fill_color(ctx, (s_highlight_pos == 2 ? s_highlight_color : s_primary_color)); graphics_fill_rect(ctx, layer_get_bounds(layer), 0, GCornerNone); } static void highlight_layer_update_proc(Layer *layer, GContext *ctx) { GRect fill_area = layer_get_bounds(layer); fill_area.size.w = PBL_DISPLAY_WIDTH / 2; switch (s_highlight_pos) { case 2: return; // do not draw highlight case 1: // draw highlight on minutes site fill_area.origin.x = fill_area.size.w; break; } graphics_context_set_fill_color(ctx, s_highlight_color); graphics_fill_rect(ctx, fill_area, 0, GCornerNone); } static void setter_window_load() { s_setter_time.HourWIP = 0; s_setter_time.MinuteWIP = 0; s_setter_time.HourSet = 0; s_setter_time.MinuteSet = 0; Layer *window_layer = window_get_root_layer(s_window); // top&bottom bars static const GRect top_bar_grect = GRect(0, 0, PBL_DISPLAY_WIDTH, s_edge_bar_height); s_top_bar_layer = layer_create(top_bar_grect); layer_set_update_proc(s_top_bar_layer, top_bar_layer_update_proc); layer_add_child(window_layer, s_top_bar_layer); static const GRect bottom_bar_grect = GRect(0, PBL_DISPLAY_HEIGHT - s_edge_bar_height, PBL_DISPLAY_WIDTH, s_edge_bar_height); s_bottom_bar_layer = layer_create(bottom_bar_grect); layer_set_update_proc(s_bottom_bar_layer, bottom_bar_layer_update_proc); layer_add_child(window_layer, s_bottom_bar_layer); // clock icon s_clock_bmp = gbitmap_create_with_resource(RESOURCE_ID_CLOCK35); s_clock_bmp_layer = bitmap_layer_create(GRect(PBL_IF_ROUND_ELSE(0, 8), PBL_IF_ROUND_ELSE(6, 0), top_bar_grect.size.w, top_bar_grect.size.h)); bitmap_layer_set_bitmap(s_clock_bmp_layer, s_clock_bmp); bitmap_layer_set_alignment(s_clock_bmp_layer, PBL_IF_ROUND_ELSE(GAlignTop, GAlignLeft)); bitmap_layer_set_compositing_mode(s_clock_bmp_layer, GCompOpSet); layer_add_child(window_layer, bitmap_layer_get_layer(s_clock_bmp_layer)); // check icon s_check_bmp = gbitmap_create_with_resource(RESOURCE_ID_CHECK); s_check_bmp_layer = bitmap_layer_create(bottom_bar_grect); bitmap_layer_set_bitmap(s_check_bmp_layer, s_check_bmp); bitmap_layer_set_compositing_mode(s_check_bmp_layer, GCompOpSet); layer_add_child(window_layer, bitmap_layer_get_layer(s_check_bmp_layer)); // countdown s_countdown_txt_layer = text_layer_create(GRect(PBL_IF_ROUND_ELSE(0, 39), (top_bar_grect.size.h / 2) + PBL_IF_ROUND_ELSE(10, -10), PBL_IF_ROUND_ELSE(top_bar_grect.size.w, top_bar_grect.size.w - 39), 32)); text_layer_set_text_alignment(s_countdown_txt_layer, GTextAlignmentCenter); text_layer_set_text_color(s_countdown_txt_layer, GColorWhite); text_layer_set_background_color(s_countdown_txt_layer, GColorClear); text_layer_set_font(s_countdown_txt_layer, fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_LECOISH_MONO_BOLD_20))); layer_add_child(window_layer, text_layer_get_layer(s_countdown_txt_layer)); update_countdown_display(); // highlighter s_highlight_layer = layer_create(GRect(0, top_bar_grect.size.h, PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT - (2 * top_bar_grect.size.h))); layer_set_update_proc(s_highlight_layer, highlight_layer_update_proc); layer_add_child(window_layer, s_highlight_layer); // setter s_setter_txt_layer = text_layer_create(GRect(0, (PBL_DISPLAY_HEIGHT / 2) - PBL_IF_ROUND_ELSE(30, 20), PBL_DISPLAY_WIDTH, PBL_IF_ROUND_ELSE(60, 40))); text_layer_set_text_alignment(s_setter_txt_layer, GTextAlignmentCenter); text_layer_set_background_color(s_setter_txt_layer, GColorClear); text_layer_set_font(s_setter_txt_layer, fonts_load_custom_font(resource_get_handle(PBL_IF_ROUND_ELSE(RESOURCE_ID_FONT_LECOISH_MONO_BOLD_60, RESOURCE_ID_FONT_LECOISH_MONO_BOLD_40)))); layer_add_child(window_layer, text_layer_get_layer(s_setter_txt_layer)); update_setter_display(); tick_timer_service_subscribe(SECOND_UNIT, seconds_handler); } static void setter_window_unload() { layer_destroy(s_highlight_layer); text_layer_destroy(s_setter_txt_layer); text_layer_destroy(s_countdown_txt_layer); bitmap_layer_destroy(s_check_bmp_layer); bitmap_layer_destroy(s_clock_bmp_layer); gbitmap_destroy(s_check_bmp); gbitmap_destroy(s_clock_bmp); layer_destroy(s_bottom_bar_layer); layer_destroy(s_top_bar_layer); } static void init() { s_window = window_create(); switch (launch_reason()) { case APP_LAUNCH_WAKEUP: break; // TODO math time! default: window_set_window_handlers( s_window, (WindowHandlers){.load = setter_window_load, .unload = setter_window_unload}); window_set_click_config_provider(s_window, click_config_provider); window_stack_push(s_window, false); }; } static void deinit() { window_destroy(s_window); } int main(void) { init(); app_event_loop(); deinit(); }