#include "palette_manip.h" #include "settings.h" #include // window statics static Window *s_main_window; static Layer *s_window_layer; static BitmapLayer *s_digit_mg_layers[4]; static BitmapLayer *s_digit_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; static const GRect s_digit_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)}; // emery 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_digits_mg = GColorDarkGray; static GColor s_applied_digits_mg_mini = GColorDarkGray; static GColor s_applied_e_f = GColorWhite; static GColor s_applied_c_h = GColorWhite; static GColor s_applied_hour = GColorWhite; static GColor s_applied_minute = GColorWhite; static GColor s_applied_minute_mini = GColorWhite; // bitmap statics static GBitmap *s_hour_bitmaps[10]; static GBitmap *s_minute_bitmaps[10]; static GBitmap *s_minute_bitmaps_mini[10]; static GBitmap *s_digit_mg_super8; static GBitmap *s_digit_mg_super8_mini; 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_peek_active = false; static bool s_first_settings_application = true; static bool s_showing_date = false; static AppTimer *s_date_timer = NULL; static bool s_pkjs_ready = false; static bool s_fuel_is_warning = false; static int s_batt_level; static bool s_temp_is_warning = false; static int8_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; // resource ID arrays for digit bitmaps static const uint32_t s_digit_resource_ids[10] = {RESOURCE_ID_0, RESOURCE_ID_1, RESOURCE_ID_2, RESOURCE_ID_3, RESOURCE_ID_4, RESOURCE_ID_5, RESOURCE_ID_6, RESOURCE_ID_7, RESOURCE_ID_8, RESOURCE_ID_9}; static const uint32_t s_digit_mini_resource_ids[10] = {RESOURCE_ID_0_M, RESOURCE_ID_1_M, RESOURCE_ID_2_M, RESOURCE_ID_3_M, RESOURCE_ID_4_M, RESOURCE_ID_5_M, RESOURCE_ID_6_M, RESOURCE_ID_7_M, RESOURCE_ID_8_M, RESOURCE_ID_9_M}; static void toggle_fuel_warning_state(bool enable_warning, bool force) { if (!force && (enable_warning == s_fuel_is_warning)) { return; } GColor dst = enable_warning ? settings.ColorWarning : settings.ColorLetters; if (s_first_settings_application && !enable_warning && dst.argb == s_applied_e_f.argb) { // at startup, s_applied_e.argb is GColorWhite // for those using white fg, do not pointlessly replace white at startup if that is the destination anyway return; } replace_gbitmap_color(s_applied_e_f, dst, s_e_icon, s_e_layer); replace_gbitmap_color(s_applied_e_f, dst, s_f_icon, s_f_layer); s_applied_e_f = dst; s_fuel_is_warning = enable_warning; } static void toggle_temp_warning_state(bool enable_warning, bool force) { if (!force && (enable_warning == s_temp_is_warning)) { return; } GColor dst = enable_warning ? settings.ColorWarning : settings.ColorLetters; if (s_first_settings_application && !enable_warning && dst.argb == s_applied_c_h.argb) { // at startup, s_applied_c_h.argb is GColorWhite // for those using white fg, do not pointlessly replace white at startup if that is the destination anyway return; } replace_gbitmap_color(s_applied_c_h, dst, s_c_icon, s_c_layer); replace_gbitmap_color(s_applied_c_h, dst, s_h_icon, s_h_layer); s_applied_c_h = dst; s_temp_is_warning = enable_warning; } static void recolor_digit_bitmaps(GBitmap **bitmaps, GColor *applied, GColor new_color) { if (applied->argb == new_color.argb) return; for (int i = 0; i < 10; ++i) { replace_gbitmap_color(*applied, new_color, bitmaps[i], NULL); } *applied = new_color; } static void bt_callback(bool connected) { GColor dst = connected ? settings.ColorHours : settings.ColorWarning; if (s_first_settings_application && connected && dst.argb == s_applied_hour.argb) { // at startup, s_applied_hour.argb is GColorWhite // for those using white fg, do not pointlessly replace white at startup if that is the destination anyway return; } recolor_digit_bitmaps(s_hour_bitmaps, &s_applied_hour, dst); for (int i = 0; i < 4; ++i) { layer_mark_dirty(bitmap_layer_get_layer(s_digit_fg_layers[i])); } } static void batt_callback(BatteryChargeState state) { s_batt_level = state.charge_percent / 5; layer_mark_dirty(s_fuel_layer); toggle_fuel_warning_state(state.charge_percent <= settings.LowFuelPercent, false); } static void temp_update_proc(Layer *layer, GContext *ctx) { graphics_context_set_fill_color(ctx, settings.ColorBarsFill); 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, settings.ColorBarsFill); uint16_t bar_bottom_pos = 195; for (uint8_t i = 0; i < s_batt_level; ++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.ColorBarsMG); graphics_fill_rect(ctx, bounds, 0, GCornerNone); if (isFuel) { graphics_context_set_stroke_color(ctx, settings.ColorBarsHot); } else { graphics_context_set_stroke_color(ctx, settings.ColorBarsCool); } 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, settings.ColorBarsCool); } else { graphics_context_set_stroke_color(ctx, settings.ColorBarsHot); } 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 update_temperature() { if (!s_pkjs_ready) { return; } DictionaryIterator *out; AppMessageResult result = app_message_outbox_begin(&out); if (result != APP_MSG_OK) { toggle_temp_warning_state(true, false); return; } dict_write_int8(out, MESSAGE_KEY_PKJS_TEMP_BAR_COUNT, 1); result = app_message_outbox_send(); if (result != APP_MSG_OK) { toggle_temp_warning_state(true, false); return; } toggle_temp_warning_state(false, false); } 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; bitmap_layer_set_bitmap(s_digit_fg_layers[0], s_hour_bitmaps[s_time_digits[0]]); bitmap_layer_set_bitmap(s_digit_fg_layers[1], s_hour_bitmaps[s_time_digits[1]]); if (!s_peek_active) { if (settings.ShowDigitsMG) { bitmap_layer_set_bitmap(s_digit_mg_layers[2], s_digit_mg_super8); bitmap_layer_set_bitmap(s_digit_mg_layers[3], s_digit_mg_super8); } bitmap_layer_set_bitmap(s_digit_fg_layers[2], s_minute_bitmaps[s_time_digits[2]]); bitmap_layer_set_bitmap(s_digit_fg_layers[3], s_minute_bitmaps[s_time_digits[3]]); } else { if (settings.ShowDigitsMG) { bitmap_layer_set_bitmap(s_digit_mg_layers[2], s_digit_mg_super8_mini); bitmap_layer_set_bitmap(s_digit_mg_layers[3], s_digit_mg_super8_mini); } bitmap_layer_set_bitmap(s_digit_fg_layers[2], s_minute_bitmaps_mini[s_time_digits[2]]); bitmap_layer_set_bitmap(s_digit_fg_layers[3], s_minute_bitmaps_mini[s_time_digits[3]]); } } static void minute_handler(struct tm *tick_time, TimeUnits units_changed) { if (!s_showing_date) { update_minute_1(); } if (tick_time->tm_min % 30 == 0) { update_temperature(); } } static void date_timeout(void *context) { s_showing_date = false; s_date_timer = NULL; update_minute_1(); } static void accel_tap_handler(AccelAxisType axis, int32_t direction) { time_t temp = time(NULL); struct tm *tick_time = localtime(&temp); static char s_date_buffer[16]; strftime(s_date_buffer, sizeof(s_date_buffer), "%m%d", tick_time); if (!s_peek_active) { bitmap_layer_set_bitmap(s_digit_fg_layers[0], s_hour_bitmaps[s_date_buffer[0] - '0']); bitmap_layer_set_bitmap(s_digit_fg_layers[1], s_hour_bitmaps[s_date_buffer[1] - '0']); bitmap_layer_set_bitmap(s_digit_fg_layers[2], s_minute_bitmaps[s_date_buffer[2] - '0']); bitmap_layer_set_bitmap(s_digit_fg_layers[3], s_minute_bitmaps[s_date_buffer[3] - '0']); } else { bitmap_layer_set_bitmap(s_digit_fg_layers[0], s_hour_bitmaps[s_date_buffer[0] - '0']); bitmap_layer_set_bitmap(s_digit_fg_layers[1], s_hour_bitmaps[s_date_buffer[1] - '0']); bitmap_layer_set_bitmap(s_digit_fg_layers[2], s_minute_bitmaps_mini[s_date_buffer[2] - '0']); bitmap_layer_set_bitmap(s_digit_fg_layers[3], s_minute_bitmaps_mini[s_date_buffer[3] - '0']); } s_showing_date = true; if (s_date_timer) { app_timer_cancel(s_date_timer); } s_date_timer = app_timer_register(settings.DateTimeoutSecs * 1000, date_timeout, NULL); } static void peek_will_change(GRect final_unobstructed_screen_area, void *context) { // if obstructed, set s_peek_active and run update_minute_1 to use small minutes GRect full_bounds = layer_get_bounds(s_window_layer); if (!grect_equal(&full_bounds, &final_unobstructed_screen_area)) { s_peek_active = true; if (!s_showing_date) { update_minute_1(); } } else { s_peek_active = false; } } static void peek_change(AnimationProgress progress, void *context) { // animate the moving of the minute layers depending on s_peek_active if (!s_peek_active) { layer_set_frame(bitmap_layer_get_layer(s_digit_fg_layers[2]), s_digit_grects[2]); layer_set_frame(bitmap_layer_get_layer(s_digit_fg_layers[3]), s_digit_grects[3]); if (settings.ShowDigitsMG) { layer_set_frame(bitmap_layer_get_layer(s_digit_mg_layers[2]), s_digit_grects[2]); layer_set_frame(bitmap_layer_get_layer(s_digit_mg_layers[3]), s_digit_grects[3]); } } else { uint8_t y = s_digit_grects[2].origin.y - 1; layer_set_frame(bitmap_layer_get_layer(s_digit_fg_layers[2]), GRect(s_digit_grects[2].origin.x, y, 69, 54)); layer_set_frame(bitmap_layer_get_layer(s_digit_fg_layers[3]), GRect(s_digit_grects[3].origin.x, y, 69, 54)); if (settings.ShowDigitsMG) { layer_set_frame(bitmap_layer_get_layer(s_digit_mg_layers[2]), GRect(s_digit_grects[2].origin.x, y, 69, 54)); layer_set_frame(bitmap_layer_get_layer(s_digit_mg_layers[3]), GRect(s_digit_grects[3].origin.x, y, 69, 54)); } } } static void peek_did_change(void *context) { // if not obstructed, run update_minute_1 to use large minutes if (!s_peek_active && !s_showing_date) { update_minute_1(); } } static void apply_settings() { bool force_update_minutes = false; // LED&BG if (settings.UseCustomLED) { light_set_color(settings.ColorLED); // no-op on unsupported platforms } else { light_set_system_color(); } window_set_background_color(s_main_window, settings.ColorBG); // TIME MG if (settings.ShowDigitsMG) { //// load bitmap if not already loaded if (!s_digit_mg_super8) { s_digit_mg_super8 = gbitmap_create_with_resource(RESOURCE_ID_SUPER8); s_applied_digits_mg = GColorDarkGray; } //// create and insert any mg layer that does not already exist Layer *sibling_layer = NULL; if (s_first_settings_application) { sibling_layer = s_window_layer; } else { sibling_layer = bitmap_layer_get_layer(s_digit_fg_layers[0]); } for (int i = 0; i < 4; ++i) { if (!s_digit_mg_layers[i]) { s_digit_mg_layers[i] = bitmap_layer_create(s_digit_grects[i]); bitmap_layer_set_bitmap(s_digit_mg_layers[i], s_digit_mg_super8); bitmap_layer_set_compositing_mode(s_digit_mg_layers[i], GCompOpSet); if (s_first_settings_application) { layer_add_child(sibling_layer, bitmap_layer_get_layer(s_digit_mg_layers[i])); } else { layer_insert_below_sibling(bitmap_layer_get_layer(s_digit_mg_layers[i]), sibling_layer); } } } //// set bitmap color and mark layers dirty if (s_digit_mg_super8 && settings.ColorDigitsMG.argb != s_applied_digits_mg.argb) { replace_gbitmap_color(s_applied_digits_mg, settings.ColorDigitsMG, s_digit_mg_super8, NULL); for (int i = 0; i < 4; ++i) { if (s_digit_mg_layers[i]) { layer_mark_dirty(bitmap_layer_get_layer(s_digit_mg_layers[i])); } } s_applied_digits_mg = settings.ColorDigitsMG; } } else { if (s_digit_mg_super8) { for (int i = 0; i < 4; ++i) { bitmap_layer_destroy(s_digit_mg_layers[i]); s_digit_mg_layers[i] = NULL; } gbitmap_destroy(s_digit_mg_super8); s_digit_mg_super8 = NULL; } } // BAR MG layer_mark_dirty(s_temp_mg_layer); layer_mark_dirty(s_fuel_mg_layer); // FG & warning indicators // manage minute-specific bitmaps if colors are unique if (settings.ColorHours.argb != settings.ColorMinutes.argb) { // if hours and minutes must be different colors... // 1. check if the minute bitmaps are loaded and equal the hours if (s_minute_bitmaps[0] && (s_minute_bitmaps[0] != s_hour_bitmaps[0])) { // 2a. if loaded and unequal, we can just change the color of the loaded bitmaps recolor_digit_bitmaps(s_minute_bitmaps, &s_applied_minute, settings.ColorMinutes); } else { // 2b. otherwise, load them and set the colors now for (int i = 0; i < 10; ++i) { s_minute_bitmaps[i] = gbitmap_create_with_resource(s_digit_resource_ids[i]); } s_applied_minute = GColorWhite; recolor_digit_bitmaps(s_minute_bitmaps, &s_applied_minute, settings.ColorMinutes); force_update_minutes = true; } } else { if (s_minute_bitmaps[0] != s_hour_bitmaps[0]) { if (s_minute_bitmaps[0]) { for (int i = 0; i < 10; ++i) { gbitmap_destroy(s_minute_bitmaps[i]); } } for (int i = 0; i < 10; ++i) { s_minute_bitmaps[i] = s_hour_bitmaps[i]; } } } // re-sub bt tracking (will update hour/month color; also minute/day if not unique) connection_service_unsubscribe(); if (settings.TrackBTStatus) { connection_service_subscribe((ConnectionHandlers){.pebble_app_connection_handler = bt_callback}); bt_callback(connection_service_peek_pebble_app_connection()); } else { bt_callback(true); } // temp (c & h icons) toggle_temp_warning_state(s_temp_is_warning, true); // fuel (e icon) toggle_fuel_warning_state(s_fuel_is_warning, true); // changes to temperature range update_temperature(); // changes to low fuel threshold batt_callback(battery_state_service_peek()); // re-sub accelerometer accel_tap_service_unsubscribe(); if (settings.DateTimeoutSecs != 0) { accel_tap_service_subscribe(accel_tap_handler); } // re-sub timeline peek and create/destroy resources as needed unobstructed_area_service_unsubscribe(); if (settings.EnablePeek) { if (!s_minute_bitmaps_mini[0]) { for (int i = 0; i < 10; ++i) { s_minute_bitmaps_mini[i] = gbitmap_create_with_resource(s_digit_mini_resource_ids[i]); } s_applied_minute_mini = GColorWhite; } //// set bitmap color recolor_digit_bitmaps(s_minute_bitmaps_mini, &s_applied_minute_mini, settings.ColorMinutes); force_update_minutes = true; // mg handling if (settings.ShowDigitsMG) { if (!s_digit_mg_super8_mini) { s_digit_mg_super8_mini = gbitmap_create_with_resource(RESOURCE_ID_SUPER8_M); s_applied_digits_mg_mini = GColorDarkGray; } if (settings.ColorDigitsMG.argb != s_applied_digits_mg_mini.argb) { replace_gbitmap_color(s_applied_digits_mg_mini, settings.ColorDigitsMG, s_digit_mg_super8_mini, NULL); for (int i = 0; i < 4; ++i) { if (s_digit_mg_layers[i]) { layer_mark_dirty(bitmap_layer_get_layer(s_digit_mg_layers[i])); } } s_applied_digits_mg_mini = settings.ColorDigitsMG; } } else if (s_digit_mg_super8_mini) { gbitmap_destroy(s_digit_mg_super8_mini); s_digit_mg_super8_mini = NULL; } peek_will_change(layer_get_unobstructed_bounds(s_window_layer), NULL); peek_change(0, NULL); peek_did_change(NULL); UnobstructedAreaHandlers peek_handlers = { .will_change = peek_will_change, .change = peek_change, .did_change = peek_did_change, }; unobstructed_area_service_subscribe(peek_handlers, NULL); } else { peek_will_change(layer_get_bounds(s_window_layer), NULL); peek_change(0, NULL); peek_did_change(NULL); if (s_minute_bitmaps_mini[0]) { for (int i = 0; i < 10; ++i) { gbitmap_destroy(s_minute_bitmaps_mini[i]); s_minute_bitmaps_mini[i] = NULL; } } if (s_digit_mg_super8_mini) { gbitmap_destroy(s_digit_mg_super8_mini); s_digit_mg_super8_mini = NULL; } } if (force_update_minutes) { update_minute_1(); } if (s_first_settings_application) { s_first_settings_application = false; } } static void main_window_load() { s_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(); for (int i = 0; i < 4; ++i) { layer_add_child(s_window_layer, bitmap_layer_get_layer(s_digit_fg_layers[i])); } layer_add_child(s_window_layer, bitmap_layer_get_layer(s_c_layer)); layer_add_child(s_window_layer, bitmap_layer_get_layer(s_h_layer)); layer_add_child(s_window_layer, bitmap_layer_get_layer(s_e_layer)); layer_add_child(s_window_layer, bitmap_layer_get_layer(s_f_layer)); layer_add_child(s_window_layer, s_temp_mg_layer); layer_add_child(s_window_layer, s_temp_layer); layer_add_child(s_window_layer, s_fuel_mg_layer); layer_add_child(s_window_layer, s_fuel_layer); } static void main_window_unload() { if (settings.EnablePeek) { unobstructed_area_service_unsubscribe(); for (int i = 0; i < 10; ++i) { gbitmap_destroy(s_minute_bitmaps_mini[i]); } } if (s_minute_bitmaps[0] != s_hour_bitmaps[0]) { for (int i = 0; i < 10; ++i) { gbitmap_destroy(s_minute_bitmaps[i]); } } connection_service_unsubscribe(); accel_tap_service_unsubscribe(); 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_digit_mg_super8_mini) { gbitmap_destroy(s_digit_mg_super8_mini); } if (s_digit_mg_super8) { gbitmap_destroy(s_digit_mg_super8); for (int i = 0; i < 4; ++i) { bitmap_layer_destroy(s_digit_mg_layers[i]); } } } static void apply_uint8_from_tuple(DictionaryIterator *iter, uint32_t key, void *dest) { Tuple *t = dict_find(iter, key); if (!t) return; *(uint8_t *)dest = t->value->uint8; } static void apply_color_from_tuple(DictionaryIterator *iter, uint32_t key, GColor *dest) { Tuple *t = dict_find(iter, key); if (!t) return; *dest = GColorFromHEX(t->value->int32); } static void inbox_received_handler(DictionaryIterator *iter, void *context) { Tuple *ready_tuple = dict_find(iter, MESSAGE_KEY_PKJS_READY); if (ready_tuple) { s_pkjs_ready = true; update_temperature(); return; } // TEMPERATURE DATA Tuple *temp_bar_count = dict_find(iter, MESSAGE_KEY_PKJS_TEMP_BAR_COUNT); if (temp_bar_count) { int8_t new_temp_level = temp_bar_count->value->int8; if (new_temp_level >= 0) { s_temp_level = new_temp_level; toggle_temp_warning_state(false, false); layer_mark_dirty(s_temp_layer); } else { toggle_temp_warning_state(true, false); } return; } // CLAY SETTINGS apply_uint8_from_tuple(iter, MESSAGE_KEY_CLAY_ENABLE_PEEK, &settings.EnablePeek); apply_uint8_from_tuple(iter, MESSAGE_KEY_CLAY_SHOW_DIGITS_MG, &settings.ShowDigitsMG); apply_uint8_from_tuple(iter, MESSAGE_KEY_CLAY_TRACK_BT_STATUS, &settings.TrackBTStatus); apply_uint8_from_tuple(iter, MESSAGE_KEY_CLAY_DATE_TIMEOUT_SECS, &settings.DateTimeoutSecs); apply_uint8_from_tuple(iter, MESSAGE_KEY_CLAY_LOW_FUEL_PERCENT, &settings.LowFuelPercent); apply_uint8_from_tuple(iter, MESSAGE_KEY_CLAY_USE_CUSTOM_LED, &settings.UseCustomLED); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_LED, &settings.ColorLED); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_BG, &settings.ColorBG); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_BAR_MG, &settings.ColorBarsMG); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_BAR_FILL, &settings.ColorBarsFill); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_BAR_COOL, &settings.ColorBarsCool); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_BAR_HOT, &settings.ColorBarsHot); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_DIGITS_MG, &settings.ColorDigitsMG); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_LETTERS, &settings.ColorLetters); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_HOURS, &settings.ColorHours); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_MINUTES, &settings.ColorMinutes); apply_color_from_tuple(iter, MESSAGE_KEY_CLAY_COLOR_WARNING, &settings.ColorWarning); persist_write_data(STORAGE_KEY_SETTINGS, &settings, sizeof(settings)); apply_settings(); } 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.EnablePeek = true; settings.TrackBTStatus = false; settings.ShowDigitsMG = false; settings.UseCustomLED = false; settings.DateTimeoutSecs = 3; settings.LowFuelPercent = 20; settings.ColorLED = GColorWhite; settings.ColorBG = GColorBlue; settings.ColorBarsMG = GColorDarkGray; settings.ColorBarsFill = GColorWhite; settings.ColorBarsCool = GColorDukeBlue; settings.ColorBarsHot = GColorRed; settings.ColorDigitsMG = GColorDarkGray; settings.ColorLetters = GColorWhite; settings.ColorHours = GColorWhite; settings.ColorMinutes = GColorWhite; settings.ColorWarning = GColorChromeYellow; } // load required bitmaps (hours and letters) for (int i = 0; i < 10; ++i) { s_hour_bitmaps[i] = gbitmap_create_with_resource(s_digit_resource_ids[i]); } 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_digit_fg_layers[i] = bitmap_layer_create(s_digit_grects[i]); bitmap_layer_set_compositing_mode(s_digit_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() { connection_service_unsubscribe(); 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_digit_fg_layers[i]); } for (int i = 0; i < 10; ++i) { gbitmap_destroy(s_hour_bitmaps[i]); } window_destroy(s_main_window); } int main(void) { init(); app_event_loop(); deinit(); }