#include "palette_manip.h" #include "settings.h" #include // window statics static Window *s_main_window; static BitmapLayer *s_time_mg_layers[4]; static BitmapLayer *s_time_fg_layers[4]; static BitmapLayer *s_c_layer; static BitmapLayer *s_h_layer; static BitmapLayer *s_e_layer; static BitmapLayer *s_f_layer; static Layer *s_temp_mg_layer; static Layer *s_temp_layer; static Layer *s_fuel_mg_layer; static Layer *s_fuel_layer; static const uint8_t s_x_r = (PBL_DISPLAY_WIDTH / 2) + 2; static const uint8_t s_x_l = (s_x_r - 2 * (69 / 2)) - 5; #if PBL_DISPLAY_HEIGHT == 260 static const GRect s_time_grects[4] = {GRect(s_x_l, 18, 69, 110), GRect(s_x_r, 18, 69, 110), GRect(s_x_l, 132, 69, 110), GRect(s_x_r, 132, 69, 110)}; #elif PBL_DISPLAY_HEIGHT == 180 static const GRect s_time_grects[4] = {GRect(s_x_l, -22, 69, 110), GRect(s_x_r, -22, 69, 110), GRect(s_x_l, 92, 69, 110), GRect(s_x_r, 92, 69, 110)}; #else static const GRect s_time_grects[4] = {GRect(s_x_l, 2, 69, 110), GRect(s_x_r, 2, 69, 110), GRect(s_x_l, 116, 69, 110), GRect(s_x_r, 116, 69, 110)}; #endif static const uint8_t s_temp_guage_x_pos = 6; static const uint16_t s_fuel_guage_x_pos = PBL_DISPLAY_WIDTH - 23; // settings statics static ClaySettings settings; static GColor s_applied_fg = GColorWhite; static GColor s_applied_time_mg = GColorWhite; // bitmap statics static GBitmap *s_font_bitmaps[10]; static GBitmap *s_time_mg_super8; static GBitmap *s_c_icon; static GBitmap *s_h_icon; static GBitmap *s_e_icon; static GBitmap *s_f_icon; // tracking statics static bool s_pkjs_ready = false; static int s_batt_level; static uint8_t s_temp_level; // bar statics static const uint8_t s_bar_height = 8; static const uint8_t s_bar_width = 17; static const uint8_t s_bar_spacing = s_bar_height + 1; static void batt_callback(BatteryChargeState state) { s_batt_level = state.charge_percent; layer_mark_dirty(s_fuel_layer); layer_mark_dirty(s_temp_layer); // TODO temporary!! } // TODO use temperature (for now it updates with battery usage) static void temp_update_proc(Layer *layer, GContext *ctx) { graphics_context_set_fill_color(ctx, GColorWhite); const uint8_t bar_count = s_temp_level; uint16_t bar_bottom_pos = 195; for (uint8_t i = 0; i < bar_count; ++i) { graphics_fill_rect(ctx, GRect(0, bar_bottom_pos, s_bar_width, s_bar_height), 0, GCornerNone); bar_bottom_pos -= s_bar_spacing; } } static void fuel_update_proc(Layer *layer, GContext *ctx) { graphics_context_set_fill_color(ctx, GColorWhite); const uint8_t bar_count = s_batt_level / 5; uint16_t bar_bottom_pos = 195; for (uint8_t i = 0; i < bar_count; ++i) { graphics_fill_rect(ctx, GRect(0, bar_bottom_pos, s_bar_width, s_bar_height), 0, GCornerNone); bar_bottom_pos -= s_bar_spacing; } } static void temp_fuel_mg_update_proc_helper(Layer *layer, GContext *ctx, bool isFuel) { GRect bounds = layer_get_bounds(layer); graphics_context_set_fill_color(ctx, settings.ColorMGBars); graphics_fill_rect(ctx, bounds, 0, GCornerNone); if (isFuel) { graphics_context_set_stroke_color(ctx, GColorRed); } else { graphics_context_set_stroke_color(ctx, GColorDukeBlue); } const uint16_t bottom_color_y = bounds.origin.y + 183; graphics_draw_line(ctx, GPoint(bounds.origin.x + 1, bottom_color_y), GPoint(bounds.origin.x + s_bar_width, bottom_color_y)); if (isFuel) { graphics_context_set_stroke_color(ctx, GColorDukeBlue); } else { graphics_context_set_stroke_color(ctx, GColorRed); } const uint16_t top_color_y = bounds.origin.y + 1; graphics_draw_line(ctx, GPoint(bounds.origin.x + 1, top_color_y), GPoint(bounds.origin.x + s_bar_width, top_color_y)); } static void temp_mg_update_proc(Layer *layer, GContext *ctx) { temp_fuel_mg_update_proc_helper(layer, ctx, false); } static void fuel_mg_update_proc(Layer *layer, GContext *ctx) { temp_fuel_mg_update_proc_helper(layer, ctx, true); } static void apply_settings(bool first_run) { // LED&BG light_set_color(settings.ColorLED); // no-op on unsupported platforms window_set_background_color(s_main_window, settings.ColorBG); // TIME MG if (settings.ShowTimeMG) { //// load bitmap if not already loaded if (!s_time_mg_super8) { s_time_mg_super8 = gbitmap_create_with_resource(RESOURCE_ID_SUPER8); s_applied_time_mg = GColorWhite; } //// create and insert any mg layer that does not already exist Layer *sibling_layer = NULL; if (first_run) { sibling_layer = window_get_root_layer(s_main_window); } else { sibling_layer = bitmap_layer_get_layer(s_time_fg_layers[0]); } for (int i = 0; i < 4; ++i) { if (!s_time_mg_layers[i]) { s_time_mg_layers[i] = bitmap_layer_create(s_time_grects[i]); bitmap_layer_set_bitmap(s_time_mg_layers[i], s_time_mg_super8); bitmap_layer_set_compositing_mode(s_time_mg_layers[i], GCompOpSet); if (first_run) { layer_add_child(sibling_layer, bitmap_layer_get_layer(s_time_mg_layers[i])); } else { layer_insert_below_sibling(bitmap_layer_get_layer(s_time_mg_layers[i]), sibling_layer); } } } //// set bitmap color and mark layers dirty if (s_time_mg_super8 && settings.ColorMGTime.argb != s_applied_time_mg.argb) { replace_gbitmap_color(s_applied_time_mg, settings.ColorMGTime, s_time_mg_super8, NULL); for (int i = 0; i < 4; ++i) { if (s_time_mg_layers[i]) { layer_mark_dirty(bitmap_layer_get_layer(s_time_mg_layers[i])); } } s_applied_time_mg = settings.ColorMGTime; } } else { if (s_time_mg_super8) { for (int i = 0; i < 4; ++i) { bitmap_layer_destroy(s_time_mg_layers[i]); s_time_mg_layers[i] = NULL; } gbitmap_destroy(s_time_mg_super8); s_time_mg_super8 = NULL; } } // BAR MG layer_mark_dirty(s_temp_mg_layer); layer_mark_dirty(s_fuel_mg_layer); // FG if (settings.ColorFG.argb != s_applied_fg.argb) { for (int i = 0; i < 10; ++i) { replace_gbitmap_color(s_applied_fg, settings.ColorFG, s_font_bitmaps[i], NULL); } for (int i = 0; i < 4; ++i) { layer_mark_dirty(bitmap_layer_get_layer(s_time_fg_layers[i])); } replace_gbitmap_color(s_applied_fg, settings.ColorFG, s_c_icon, s_c_layer); replace_gbitmap_color(s_applied_fg, settings.ColorFG, s_h_icon, s_h_layer); replace_gbitmap_color(s_applied_fg, settings.ColorFG, s_e_icon, s_e_layer); replace_gbitmap_color(s_applied_fg, settings.ColorFG, s_f_icon, s_f_layer); s_applied_fg = settings.ColorFG; } } static void main_window_load() { Layer *window_layer = window_get_root_layer(s_main_window); s_temp_mg_layer = layer_create(GRect(s_temp_guage_x_pos - 1, 21, s_bar_width + 2, PBL_DISPLAY_HEIGHT - 43)); layer_set_update_proc(s_temp_mg_layer, temp_mg_update_proc); s_fuel_mg_layer = layer_create(GRect(s_fuel_guage_x_pos - 1, 21, s_bar_width + 2, PBL_DISPLAY_HEIGHT - 43)); layer_set_update_proc(s_fuel_mg_layer, fuel_mg_update_proc); s_c_layer = bitmap_layer_create(GRect(s_temp_guage_x_pos, PBL_DISPLAY_HEIGHT - 18, 17, 15)); s_h_layer = bitmap_layer_create(GRect(s_temp_guage_x_pos, 3, 17, 14)); s_e_layer = bitmap_layer_create(GRect(s_fuel_guage_x_pos, PBL_DISPLAY_HEIGHT - 18, 17, 15)); s_f_layer = bitmap_layer_create(GRect(s_fuel_guage_x_pos, 3, 17, 14)); bitmap_layer_set_bitmap(s_c_layer, s_c_icon); bitmap_layer_set_bitmap(s_h_layer, s_h_icon); bitmap_layer_set_bitmap(s_e_layer, s_e_icon); bitmap_layer_set_bitmap(s_f_layer, s_f_icon); bitmap_layer_set_compositing_mode(s_c_layer, GCompOpSet); bitmap_layer_set_compositing_mode(s_h_layer, GCompOpSet); bitmap_layer_set_compositing_mode(s_e_layer, GCompOpSet); bitmap_layer_set_compositing_mode(s_f_layer, GCompOpSet); apply_settings(true); for (int i = 0; i < 4; ++i) { layer_add_child(window_layer, bitmap_layer_get_layer(s_time_fg_layers[i])); } layer_add_child(window_layer, bitmap_layer_get_layer(s_c_layer)); layer_add_child(window_layer, bitmap_layer_get_layer(s_h_layer)); layer_add_child(window_layer, bitmap_layer_get_layer(s_e_layer)); layer_add_child(window_layer, bitmap_layer_get_layer(s_f_layer)); layer_add_child(window_layer, s_temp_mg_layer); layer_add_child(window_layer, s_temp_layer); layer_add_child(window_layer, s_fuel_mg_layer); layer_add_child(window_layer, s_fuel_layer); } static void main_window_unload() { layer_destroy(s_fuel_mg_layer); layer_destroy(s_temp_mg_layer); bitmap_layer_destroy(s_f_layer); bitmap_layer_destroy(s_e_layer); bitmap_layer_destroy(s_h_layer); bitmap_layer_destroy(s_c_layer); if (s_time_mg_super8) { gbitmap_destroy(s_time_mg_super8); for (int i = 0; i < 4; ++i) { bitmap_layer_destroy(s_time_mg_layers[i]); } } } static void update_minute_1() { time_t temp = time(NULL); struct tm *tick_time = localtime(&temp); uint8_t hour = (uint8_t)tick_time->tm_hour; if (!clock_is_24h_style()) { hour = hour % 12; if (hour == 0) { hour = 12; } } uint8_t minute = (uint8_t)tick_time->tm_min; static uint8_t s_time_digits[4]; s_time_digits[0] = hour / 10; s_time_digits[1] = hour % 10; s_time_digits[2] = minute / 10; s_time_digits[3] = minute % 10; for (int i = 0; i < 4; ++i) { bitmap_layer_set_bitmap(s_time_fg_layers[i], s_font_bitmaps[s_time_digits[i]]); } } static void update_temperature() { DictionaryIterator *out; AppMessageResult result = app_message_outbox_begin(&out); if (result != APP_MSG_OK) { s_temp_level = 0; // error; set to 0 bars to indicate TODO invert color and set to 20? return; } dict_write_int8(out, MESSAGE_KEY_PKJS_TEMP_BAR_COUNT, 1); result = app_message_outbox_send(); if (result != APP_MSG_OK) { s_temp_level = 0; // error; set to 0 bars to indicate TODO invert color and set to 20? return; } } static void minute_handler(struct tm *tick_time, TimeUnits units_changed) { update_minute_1(); if (s_pkjs_ready && tick_time->tm_min % 30 == 0) { update_temperature(); } } static void inbox_received_handler(DictionaryIterator *iter, void *context) { Tuple *ready_tuple = dict_find(iter, MESSAGE_KEY_PKJS_READY); if (ready_tuple) { update_temperature(); return; } // TEMPERATURE DATA Tuple *temp_bar_count = dict_find(iter, MESSAGE_KEY_PKJS_TEMP_BAR_COUNT); if (temp_bar_count) { s_temp_level = temp_bar_count->value->uint8; layer_mark_dirty(s_temp_layer); return; } // CLAY SETTINGS Tuple *show_time_mg_tuple = dict_find(iter, MESSAGE_KEY_CLAY_SHOW_TIME_MG); Tuple *color_led_tuple = dict_find(iter, MESSAGE_KEY_CLAY_LED_COLOR); Tuple *color_bg_tuple = dict_find(iter, MESSAGE_KEY_CLAY_BG_COLOR); Tuple *color_mg_bar_tuple = dict_find(iter, MESSAGE_KEY_CLAY_BAR_MG_COLOR); Tuple *color_mg_time_tuple = dict_find(iter, MESSAGE_KEY_CLAY_TIME_MG_COLOR); Tuple *color_fg_tuple = dict_find(iter, MESSAGE_KEY_CLAY_FG_COLOR); if (show_time_mg_tuple) { settings.ShowTimeMG = show_time_mg_tuple->value->uint8; } if (color_led_tuple) { settings.ColorLED = GColorFromHEX(color_led_tuple->value->int32); } if (color_bg_tuple) { settings.ColorBG = GColorFromHEX(color_bg_tuple->value->int32); } if (color_mg_bar_tuple) { settings.ColorMGBars = GColorFromHEX(color_mg_bar_tuple->value->int32); } if (color_mg_time_tuple) { settings.ColorMGTime = GColorFromHEX(color_mg_time_tuple->value->int32); } if (color_fg_tuple) { settings.ColorFG = GColorFromHEX(color_fg_tuple->value->int32); } persist_write_data(STORAGE_KEY_SETTINGS, &settings, sizeof(settings)); apply_settings(false); } static void init() { // load settings from persist (or set defaults if not present) if (persist_exists(STORAGE_KEY_SETTINGS)) { persist_read_data(STORAGE_KEY_SETTINGS, &settings, sizeof(settings)); } else { settings.ShowTimeMG = false; settings.ColorLED = GColorWhite; settings.ColorBG = GColorBlue; settings.ColorMGBars = GColorDarkGray; settings.ColorMGTime = GColorDarkGray; settings.ColorFG = GColorWhite; } // load bitmaps s_font_bitmaps[0] = gbitmap_create_with_resource(RESOURCE_ID_0); s_font_bitmaps[1] = gbitmap_create_with_resource(RESOURCE_ID_1); s_font_bitmaps[2] = gbitmap_create_with_resource(RESOURCE_ID_2); s_font_bitmaps[3] = gbitmap_create_with_resource(RESOURCE_ID_3); s_font_bitmaps[4] = gbitmap_create_with_resource(RESOURCE_ID_4); s_font_bitmaps[5] = gbitmap_create_with_resource(RESOURCE_ID_5); s_font_bitmaps[6] = gbitmap_create_with_resource(RESOURCE_ID_6); s_font_bitmaps[7] = gbitmap_create_with_resource(RESOURCE_ID_7); s_font_bitmaps[8] = gbitmap_create_with_resource(RESOURCE_ID_8); s_font_bitmaps[9] = gbitmap_create_with_resource(RESOURCE_ID_9); s_c_icon = gbitmap_create_with_resource(RESOURCE_ID_C); s_h_icon = gbitmap_create_with_resource(RESOURCE_ID_H); s_e_icon = gbitmap_create_with_resource(RESOURCE_ID_E); s_f_icon = gbitmap_create_with_resource(RESOURCE_ID_F); for (int i = 0; i < 4; ++i) { s_time_fg_layers[i] = bitmap_layer_create(s_time_grects[i]); bitmap_layer_set_compositing_mode(s_time_fg_layers[i], GCompOpSet); } s_temp_layer = layer_create(GRect(s_temp_guage_x_pos, 0, s_bar_width, PBL_DISPLAY_HEIGHT)); layer_set_update_proc(s_temp_layer, temp_update_proc); s_fuel_layer = layer_create(GRect(s_fuel_guage_x_pos, 0, s_bar_width, PBL_DISPLAY_HEIGHT)); layer_set_update_proc(s_fuel_layer, fuel_update_proc); update_minute_1(); batt_callback(battery_state_service_peek()); app_message_register_inbox_received(inbox_received_handler); app_message_open(255, 64); s_main_window = window_create(); window_set_window_handlers( s_main_window, (WindowHandlers){.load = main_window_load, .unload = main_window_unload}); window_stack_push(s_main_window, false); tick_timer_service_subscribe(MINUTE_UNIT, minute_handler); battery_state_service_subscribe(batt_callback); } static void deinit() { battery_state_service_unsubscribe(); tick_timer_service_unsubscribe(); layer_destroy(s_fuel_layer); layer_destroy(s_temp_layer); gbitmap_destroy(s_f_icon); gbitmap_destroy(s_e_icon); gbitmap_destroy(s_h_icon); gbitmap_destroy(s_c_icon); for (int i = 0; i < 4; ++i) { bitmap_layer_destroy(s_time_fg_layers[i]); } for (int i = 0; i < 10; ++i) { gbitmap_destroy(s_font_bitmaps[i]); } window_destroy(s_main_window); } int main(void) { init(); app_event_loop(); deinit(); }