// Draws hands onto the given layer static void draw_hands(Layer* layer, GContext* ctx) { gpath_rotate_to(hour_ptr, (TRIG_MAX_ANGLE * timedata[0] / 12) + (TRIG_MAX_ANGLE * timedata[1] / 720.0f)); graphics_context_set_fill_color(ctx, GColorWhite); gpath_draw_filled(ctx, hour_ptr); // minute hand gpath_rotate_to(minute_ptr, (TRIG_MAX_ANGLE * timedata[1] / 60) + (TRIG_MAX_ANGLE * timedata[2] / 3600.0f)); graphics_context_set_fill_color(ctx, GColorWhite); gpath_draw_filled(ctx, minute_ptr); // seconds get some extra attention here-- the same as above, but with an extra little counterweight type thing on the opposite site GPoint sec0 = (GPoint) { .x = (int16_t)(center.x + -sin_lookup(TRIG_MAX_ANGLE * timedata[2] / 60) * 18 / TRIG_MAX_RATIO), .y = (int16_t)(center.y + cos_lookup(TRIG_MAX_ANGLE * timedata[2] / 60) * 18 / TRIG_MAX_RATIO) }; GPoint sec1 = (GPoint) { .x = (int16_t)(center.x + sin_lookup(TRIG_MAX_ANGLE * timedata[2] / 60) * 72 / TRIG_MAX_RATIO), .y = (int16_t)(center.y + -cos_lookup(TRIG_MAX_ANGLE * timedata[2] / 60) * 72 / TRIG_MAX_RATIO) }; graphics_context_set_stroke_color(ctx, GColorYellow ); graphics_context_set_stroke_width(ctx, 3); graphics_draw_line(ctx, center, sec1); graphics_context_set_stroke_width(ctx, 6); graphics_draw_line(ctx, center, sec0); graphics_context_set_fill_color(ctx, GColorYellow ); graphics_fill_circle(ctx, center, 5); graphics_context_set_stroke_color(ctx, GColorBlack); graphics_draw_pixel(ctx, center); } // draws face onto the given layer static void draw_face(Layer* layer, GContext* ctx) { static char buf[] = "00"; graphics_context_set_stroke_color(ctx, GColorLightGray); // draw 60 minute ticks around clock for (int i = 0; i < 60; i++) { // tic0 = start of inner point // tic1 = end of outer point GPoint tic0, tic1; // tic0 is the starting point from center, tic1 is the outer point of the tic if (i % 5 == 0) { // hour tic0 = (GPoint) { .x = (int16_t)(center.x + sin_lookup(TRIG_MAX_ANGLE * i / 60) * 69 / TRIG_MAX_RATIO), .y = (int16_t)(center.y + -cos_lookup(TRIG_MAX_ANGLE * i / 60) * 69 / TRIG_MAX_RATIO) }; tic1 = (GPoint) { .x = (int16_t)(tic0.x + sin_lookup(TRIG_MAX_ANGLE * i / 60) * 15 / TRIG_MAX_RATIO), .y = (int16_t)(tic0.y + -cos_lookup(TRIG_MAX_ANGLE * i / 60) * 15 / TRIG_MAX_RATIO) }; graphics_context_set_stroke_width(ctx, 2); /*if (i != 30) { GRect HourText = GRect((int16_t)(center.x + sin_lookup(TRIG_MAX_ANGLE * i / 60) * 54 / TRIG_MAX_RATIO)-10, (int16_t)(center.y + -cos_lookup(TRIG_MAX_ANGLE * i / 60) * 54 / TRIG_MAX_RATIO)-10, 20, 20); snprintf(buf, sizeof(buf), "%d", i/5); graphics_context_set_text_color(ctx, GColorWhite); graphics_draw_text(ctx, buf, fonts_get_system_font(FONT_KEY_GOTHIC_18), HourText, GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); }*/ } else { // minute marks tic0 = (GPoint) { .x = (int16_t)(center.x + sin_lookup(TRIG_MAX_ANGLE * i / 60) * 74 / TRIG_MAX_RATIO), .y = (int16_t)(center.y + -cos_lookup(TRIG_MAX_ANGLE * i / 60) * 74 / TRIG_MAX_RATIO) }; tic1 = (GPoint) { .x = (int16_t)(tic0.x + sin_lookup(TRIG_MAX_ANGLE * i / 60) * 10 / TRIG_MAX_RATIO), .y = (int16_t)(tic0.y + -cos_lookup(TRIG_MAX_ANGLE * i / 60) * 10 / TRIG_MAX_RATIO) }; graphics_context_set_stroke_width(ctx, 1); } graphics_draw_line(ctx, tic0, tic1); } // draw the date (new and complex how scary) snprintf(buf, sizeof(buf), "%d", timedata[3]); int yDate = center.y + layer_get_frame(s_face_layer).size.h / 4; int xDate = center.x - 6; GRect date_window = GRect(xDate, yDate, 13, 18); graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_text_color(ctx, GColorBlack); graphics_fill_rect(ctx, date_window, 0, 0); graphics_draw_text(ctx, buf, fonts_get_system_font(FONT_KEY_GOTHIC_14), date_window, GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); graphics_context_set_fill_color(ctx, GColorRed); gpath_move_to(chevron, GPoint(xDate + 6, yDate - 3)); gpath_rotate_to(chevron, TRIG_MAX_ANGLE * 0.5f); gpath_draw_filled(ctx, chevron); } static void tick_handler(struct tm* tick_time, TimeUnits units_changed) { // just store the time, don't bother with making a new one in the update_proc or calling update_time timedata[0] = tick_time->tm_hour % 12; timedata[1] = tick_time->tm_min; timedata[2] = tick_time->tm_sec; timedata[3] = tick_time->tm_mday; layer_mark_dirty(s_hands_layer); } static void main_window_load(Window* window) { // self-explanatory: make the main window black with one full-screen layer to display the time window_set_background_color(window, GColorBlack); s_face_layer = layer_create(layer_get_bounds(window_get_root_layer(s_window))); s_hands_layer = layer_create(layer_get_bounds(window_get_root_layer(s_window))); logo = gbitmap_create_with_resource(RESOURCE_ID_LOGO); int offset = (center.x-20); logo_layer = bitmap_layer_create(GRect(offset, 50, 40, 12)); bitmap_layer_set_bitmap(logo_layer, logo); layer_add_child(s_face_layer, bitmap_layer_get_layer(logo_layer)); layer_set_update_proc(s_face_layer, draw_face); layer_set_update_proc(s_hands_layer, draw_hands); layer_add_child(window_get_root_layer(window), s_face_layer); layer_add_child(window_get_root_layer(window), s_hands_layer); } static void main_window_unload(Window* window) { gbitmap_destroy(logo); bitmap_layer_destroy(logo_layer); layer_destroy(s_face_layer); layer_destroy(s_hands_layer); gpath_destroy(hour_ptr); gpath_destroy(minute_ptr); gpath_destroy(second_ptr); } static void init() { // initialize stuff you know the drill s_window = window_create(); window_set_window_handlers(s_window, (WindowHandlers) { .load = main_window_load, .unload = main_window_unload });
static void hands_update_proc(Layer *layer, GContext *ctx) { time_t now = time(NULL); struct tm *t = localtime(&now); GRect bounds = layer_get_bounds(layer); GPoint center = grect_center_point(&bounds); int32_t second_angle = (TRIG_MAX_ANGLE * (((t->tm_hour % 12) * 6) + (t->tm_min / 10))) / (12 * 6); GPoint second_hand = { .x = (int16_t)(-sin_lookup(second_angle) * -45 / TRIG_MAX_RATIO) + center.x, .y = (int16_t)(cos_lookup(second_angle) * -45 / TRIG_MAX_RATIO) + center.y, }; #ifdef PBL_COLOR graphics_context_set_stroke_color(ctx, GColorYellow); graphics_context_set_fill_color(ctx, GColorYellow); #else graphics_context_set_stroke_color(ctx, GColorWhite); graphics_context_set_fill_color(ctx, GColorWhite); #endif graphics_draw_circle(ctx, second_hand, 4); graphics_fill_circle(ctx, second_hand, 4); /* // HOUR HAND // gpath_rotate_to(s_hour_arrow, (TRIG_MAX_ANGLE * (((t->tm_hour % 12) * 6) + (t->tm_min / 10))) / (12 * 6)); #ifdef PBL_COLOR graphics_context_set_fill_color(ctx, GColorYellow); graphics_context_set_stroke_color(ctx, GColorYellow); #else graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); #endif gpath_draw_filled(ctx, s_hour_arrow); gpath_draw_outline(ctx, s_hour_arrow); */ // MINUTE HAND // gpath_rotate_to(s_minute_arrow, TRIG_MAX_ANGLE * t->tm_min / 60); #ifdef PBL_COLOR graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); #else graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); #endif gpath_draw_filled(ctx, s_minute_arrow); gpath_draw_outline(ctx, s_minute_arrow); // SECOND HAND // gpath_rotate_to(s_second_arrow, (TRIG_MAX_ANGLE * t->tm_sec / 60)); #ifdef PBL_COLOR graphics_context_set_fill_color(ctx, GColorRed); graphics_context_set_stroke_color(ctx, GColorRed); #else graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); #endif gpath_draw_filled(ctx, s_second_arrow); gpath_draw_outline(ctx, s_second_arrow); if(clock_is_24h_style() == true) { //Use 2h hour format strftime(buffer, sizeof("00:00"), "%H:%M", t); } else { //Use 12 hour format strftime(buffer, sizeof("00:00"), "%I:%M", t); } strftime(date, sizeof("XXX XX"), "%a %d", t); text_layer_set_text(date_layer, date); text_layer_set_text(time_layer, buffer); } static void handle_second_tick(struct tm *tick_time, TimeUnits units_changed) { layer_mark_dirty(window_get_root_layer(window)); }
int dy(float angle, int radius){ return -cos_lookup(angle) * radius / TRIG_MAX_RATIO; }
static void hands_update_proc(Layer *layer, GContext *ctx) { time_t now = time(NULL); struct tm *t = localtime(&now); graphics_context_set_stroke_color(ctx, hand_color); #ifdef PBL_COLOR graphics_context_set_antialiased(ctx, false); #endif GRect bounds = layer_get_bounds(layer); GPoint center = grect_center_point(&bounds); //minute hand int16_t hand_length = bounds.size.w / 2 ; int32_t angle = TRIG_MAX_ANGLE * t->tm_min / 60; GPoint hand = { .x = (int16_t)(sin_lookup(angle) * (int32_t)hand_length / TRIG_MAX_RATIO) + center.x, .y = (int16_t)(-cos_lookup(angle) * (int32_t)hand_length / TRIG_MAX_RATIO) + center.y, }; #ifdef PBL_COLOR graphics_context_set_stroke_width(ctx, 3); #endif graphics_draw_line(ctx, hand, center); //hour hand hand_length = hand_length - 25; angle = (TRIG_MAX_ANGLE * (((t->tm_hour % 12) * 6) + (t->tm_min / 10))) / (12 * 6); hand = (GPoint){ .x = (int16_t)(sin_lookup(angle) * (int32_t)hand_length / TRIG_MAX_RATIO) + center.x, .y = (int16_t)(-cos_lookup(angle) * (int32_t)hand_length / TRIG_MAX_RATIO) + center.y, }; #ifdef PBL_COLOR graphics_context_set_stroke_width(ctx, 5); #endif graphics_draw_line(ctx, hand, center); #ifndef PBL_RECT graphics_context_set_fill_color(ctx, hand_color); graphics_fill_circle(ctx, center, 7); #endif } static void handle_second_tick(struct tm *tick_time, TimeUnits units_changed) { #ifndef PBL_COLOR memset(aplite_visited, 0, 168*20); #endif //adjusting shadow direction according to minute hand location if (tick_time->tm_min >= 0 && tick_time->tm_min < 15) { s_effect_offset.offset_x = SHADOW_LENGTH; s_effect_offset.offset_y = SHADOW_LENGTH; } else if (tick_time->tm_min >= 15 && tick_time->tm_min < 30) { s_effect_offset.offset_x = -SHADOW_LENGTH; s_effect_offset.offset_y = SHADOW_LENGTH; } else if (tick_time->tm_min >= 30 && tick_time->tm_min < 45) { s_effect_offset.offset_x = -SHADOW_LENGTH; s_effect_offset.offset_y = -SHADOW_LENGTH; } else { s_effect_offset.offset_x = SHADOW_LENGTH; s_effect_offset.offset_y = -SHADOW_LENGTH; } layer_mark_dirty(window_get_root_layer(window)); } static void window_load(Window *window) { Layer *window_layer = window_get_root_layer(window); GRect bounds = layer_get_bounds(window_layer); s_hands_layer = layer_create(bounds); layer_set_update_proc(s_hands_layer, hands_update_proc); layer_add_child(window_layer, s_hands_layer); //creating shadow layer s_effect_offset = (EffectOffset){ .orig_color = hand_color, .offset_color = shadow_color, .option = 1 // creating array for "visited" pixels and assigning it to shadow effect parameter #ifndef PBL_COLOR , .aplite_visited = aplite_visited #endif }; s_effect_layer = effect_layer_create(bounds); effect_layer_add_effect(s_effect_layer, effect_shadow, &s_effect_offset); effect_layer_add_effect(s_effect_layer, effect_blur, (void*)1); layer_add_child(window_layer, effect_layer_get_layer(s_effect_layer)); } static void window_unload(Window *window) { layer_destroy(s_hands_layer); }
static void update_layer_callback(Layer *layer, GContext* ctx) { GRect bounds = layer_get_frame(layer); // minutes = 59; graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); // Draw minutes arc int32_t minutes_angle = 360 * minutes / 60; if(minutes_angle <= 90){ graphics_draw_arc(ctx, center, INNER_RADIUS, INNER_RADIUS, 270, 270 + minutes_angle); } else { graphics_draw_arc(ctx, center, INNER_RADIUS, INNER_RADIUS, 270, 360); graphics_draw_arc(ctx, center, INNER_RADIUS, INNER_RADIUS, 0, minutes_angle - 90); } // Draw bitmap pattern graphics_context_set_compositing_mode(ctx, GCompOpAnd); graphics_draw_bitmap_in_rect(ctx, image, bounds); // Draw hours arc int32_t hours_angle = 360 * ((hours % 12) * 60 + minutes) / (12 * 60); if(hours_angle <= 90){ graphics_draw_arc(ctx, center, OUTER_RADIUS, OUTER_THICKNESS, 270, 270 + hours_angle); } else { graphics_draw_arc(ctx, center, OUTER_RADIUS, OUTER_THICKNESS, 270, 360); graphics_draw_arc(ctx, center, OUTER_RADIUS, OUTER_THICKNESS, 0, hours_angle - 90); } graphics_draw_pixel(ctx, GPoint(center.x-1, center.y - OUTER_RADIUS + 2)); // round end effect graphics_draw_pixel(ctx, GPoint(center.x-1, center.y - OUTER_RADIUS + 3)); // round end effect // Draw hour dot GPoint hourDot; hours_angle = TRIG_MAX_ANGLE * ((hours % 12) * 60 + minutes) / (12 * 60); hourDot.y = (int16_t)(-cos_lookup(hours_angle) * (OUTER_RADIUS - OUTER_THICKNESS/2) / TRIG_MAX_RATIO) + center.y; hourDot.x = (int16_t)(sin_lookup(hours_angle) * (OUTER_RADIUS - OUTER_THICKNESS/2) / TRIG_MAX_RATIO) + center.x; graphics_context_set_fill_color(ctx, GColorWhite); graphics_fill_circle(ctx, hourDot, DOT_RADIUS); if(hours >= 12){ graphics_context_set_fill_color(ctx, GColorBlack); graphics_fill_circle(ctx, hourDot, DOT_RADIUS - 2); } // Draw center dot if bluetooth connected if(bluetooth_connected){ graphics_context_set_fill_color(ctx, GColorBlack); graphics_fill_circle(ctx, center, DOT_RADIUS + 3); graphics_context_set_fill_color(ctx, GColorWhite); graphics_fill_circle(ctx, center, DOT_RADIUS); graphics_context_set_fill_color(ctx, GColorBlack); graphics_fill_circle(ctx, center, DOT_RADIUS - 2); } else { graphics_context_set_fill_color(ctx, GColorBlack); graphics_fill_rect(ctx, GRect(center.x - (DOT_RADIUS + 4), center.y - (DOT_RADIUS + 4), 2*(DOT_RADIUS + 4), 2*(DOT_RADIUS + 4)), 0, 0); graphics_context_set_fill_color(ctx, GColorWhite); graphics_fill_rect(ctx, GRect(center.x - DOT_RADIUS, center.y - DOT_RADIUS, 2*DOT_RADIUS, 2*DOT_RADIUS), 0, 0); graphics_context_set_fill_color(ctx, GColorBlack); graphics_fill_rect(ctx, GRect(center.x - (DOT_RADIUS - 2), center.y - (DOT_RADIUS - 2), 2*(DOT_RADIUS - 2), 2*(DOT_RADIUS - 2)), 0, 0); } // Draw dates graphics_context_set_text_color(ctx, GColorWhite); graphics_draw_text(ctx, date_str, custom_font, GRect(0, 142, 144, 23), GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); }
//1. Base layer contains coloured analogue watch face static void bg_update_proc(Layer *layer, GContext *ctx) { GRect bounds = layer_get_bounds(layer); int widthHalf = bounds.size.w / 2, heightHalf = bounds.size.h / 2; int32_t width = bounds.size.w * 3; time_t now = time(NULL); struct tm *t = localtime(&now); hr = t->tm_hour; min = t->tm_min; //hr = 7; min = 20; //DEBUG #ifdef DEBUG_MODE int sec = t->tm_sec; min = sec; if (min == 59) --lastSurpriseHr; //force re-selection of surprise min after every round of min hand #endif int32_t angleM = TRIG_MAX_ANGLE * min / 60; //int32_t angleH = TRIG_MAX_ANGLE * (hr % 12) / 12; //without minutes contribution int32_t angleH = (TRIG_MAX_ANGLE * (((hr % 12) * 6) + (min / 10))) / (12 * 6); //with minutes contribution int32_t angleMid; #ifdef DEBUG_COLOURS m_nColourIndex = t->tm_sec * MAX_COLOURS / 60; #else m_nColourIndex = (t->tm_yday * 24 + hr) % MAX_COLOURS; #endif //APP_LOG(APP_LOG_LEVEL_DEBUG, "h:m %d:%d => angles: %d, %d", hr, min, (int) (angleM * 360 / TRIG_MAX_ANGLE), (int) (angleH * 360 / TRIG_MAX_ANGLE)); bool bIsSmallSectorLight = true; if (angleM >= angleH) { if ((angleM - angleH) <= ANGLE_DEG_180) { angleMid = (angleM + angleH) / 2; } else { bIsSmallSectorLight = false; angleMid = (TRIG_MAX_ANGLE - angleM + angleH) / 2 + angleM; } } else //angleH > angleM { if ((angleH - angleM) <= ANGLE_DEG_180) { angleMid = (angleM + angleH) / 2; bIsSmallSectorLight = false; } else { angleMid = (TRIG_MAX_ANGLE - angleH + angleM) / 2 + angleH; } } int mInQ = angleM / ANGLE_DEG_90, hInQ = angleH / ANGLE_DEG_90; dateQuadrant = DATE_QUAD_INDEX[mInQ][hInQ]; dateQuadrantUseApc = (mInQ != hInQ)? DATE_QUAD_USE_PRI[mInQ][hInQ]: (angleM < angleH); surpQuadrant = SURPRISE_QUAD_INDEX[mInQ][hInQ]; surpQuadrantUseApc = (mInQ != hInQ)? SURPRISE_QUAD_USE_PRI[mInQ][hInQ]: (angleM < angleH); //create rectangle (for simplicity instead of sector; triangle is insufficient as at wide angles, it won't cover the corner!) GPathInfo sectorInfo = { .num_points = 4, .points = (GPoint []) { {0, 0}, {width * sin_lookup(angleH) / TRIG_MAX_RATIO, -width * cos_lookup(angleH) / TRIG_MAX_RATIO}, {width * sin_lookup(angleMid) / TRIG_MAX_RATIO, -width * cos_lookup(angleMid) / TRIG_MAX_RATIO}, {width * sin_lookup(angleM) / TRIG_MAX_RATIO, -width * cos_lookup(angleM) / TRIG_MAX_RATIO} } }; GPath *sector = gpath_create(§orInfo); GPoint center = grect_center_point(&bounds); gpath_move_to(sector, center); //bIsSmallSectorLight = ! bIsSmallSectorLight; //try inverting colour scheme to more light (i.e. bigger light sector) #ifdef INVERT_COLOURS GColor clrDark = (GColor8){.argb=COLOURS[m_nColourIndex][1]}; GColor clrLight = (GColor8){.argb=COLOURS[m_nColourIndex][0]}; #else GColor clrDark = (GColor8){.argb=COLOURS[m_nColourIndex][0]}; GColor clrLight = (GColor8){.argb=COLOURS[m_nColourIndex][1]}; #endif //draw background (rest, i.e. big sector) graphics_context_set_fill_color(ctx, !bIsSmallSectorLight? clrLight: clrDark); graphics_fill_rect(ctx, layer_get_bounds(layer), 0, GCornerNone); //draw small sector GColor c = bIsSmallSectorLight? clrLight: clrDark; graphics_context_set_fill_color(ctx, c); graphics_context_set_stroke_color(ctx, c); gpath_draw_filled(ctx, sector); gpath_draw_outline(ctx, sector); gpath_destroy(sector); //write 'hour' hint strftime(s_hour_buffer, sizeof(s_hour_buffer), "%l", t); //strftime(s_hour_buffer, sizeof(s_hour_buffer), "12", t); //DEBUG: Try widest hour displayed: 12 /** * In FONT_KEY_BITHAM_30_BLACK, digit '6' is ~18x21 px. * Thus, need vertical offset (of 5 px) as top of font character is 9px down. **/ #ifdef DEBUG_HOUR_HINT int32_t angle = angleM + ANGLE_HOUR_HINT; #else int32_t angle = angleH + ANGLE_HOUR_HINT; #endif int radius = heightHalf - 18; //less font size & margin if (((angle >= ANGLE_DEG_45) && (angle <= ANGLE_DEG_135)) || ((angle >= ANGLE_DEG_225) && (angle <= ANGLE_DEG_315))) { radius = widthHalf - 18; } int i; for (i = 0; i < 5; ++i) { text_layer_set_text(s_hour_label[i], s_hour_buffer); GRect frame = layer_get_frame((Layer*)s_hour_label[i]); frame.origin.x = OFFSET_OUTLINE[i][0] + center.x - (frame.size.w / 2) + radius * sin_lookup(angle) / TRIG_MAX_RATIO; frame.origin.y = OFFSET_OUTLINE[i][1] + center.y - (frame.size.h / 2) - 5 //offset 5px up - radius * cos_lookup(angle) / TRIG_MAX_RATIO; layer_set_frame((Layer*)s_hour_label[i], frame); if (i < 4) { text_layer_set_text_color(s_hour_label[i], (hr >= 12)? GColorBlack: GColorWhite); } else { text_layer_set_text_color(s_hour_label[i], (hr >= 12)? GColorWhite: GColorBlack); } } bool bToShowPicFor1stTime = false; if (lastSurpriseHr < 0) { bToShowPicFor1stTime = true; //show pic when watchface is first loaded } if (bToShowPicFor1stTime || (hr != lastSurpriseHr)) { lastSurpriseHr = hr; //randomly pick a min to show surprise pic: if (!bToShowPicFor1stTime) { nextSurpriseMin = rand() % 60; } else if (nextSurpriseMin < 59) //showing pic for 1st time, so randomly pick a min after current min { nextSurpriseMin = (rand() % (59 - min)) + min + 1; } surpriseShownCnt = 0; } if (bToShowPicFor1stTime || ((min == nextSurpriseMin) && (surpriseShownCnt == 0))) { if (!bToShowPicFor1stTime) { ++surpriseShownCnt; } m_bSupriseShowing = true; layer_set_hidden(m_sLayerWeather, true); bitmap_layer_set_bitmap(m_spbmLayer, m_spbmPics[rand() % MAX_PICS]); //move surprise pic to appropriate quadrant: moveLayer((Layer*)m_spbmLayer, layer, surpQuadrant); m_sptimer1 = app_timer_register(PIC_SHOW_INTERVAL, (AppTimerCallback) hidePic, NULL); } if (m_bWeatherEnabled) { moveLayer2((Layer*)m_sLayerWeather, layer, surpQuadrant, !m_bSupriseShowing && m_bWeatherEnabled); } if ((m_nVibes & MASKV_HOURLY) //option enabled to vibrate hourly && (min == 0) //hourly mark reached && (m_nLastHourlyShake != now)) //sometimes update proc gets called several times in the same min, so shake only once! { int from = (m_nVibes & MASKV_FROM) >> 8, to = m_nVibes & MASKV_TO; bool bShake = false; if (from <= to) { bShake = (hr >= from) && (hr <= to); } else { bShake = (hr >= from) || (hr <= to); } if (bShake) { m_nLastHourlyShake = now; vibes_double_pulse(); } } }
static void hands_update_proc(Layer *layer, GContext *ctx) { GRect bounds = layer_get_bounds(layer); GPoint center = grect_center_point(&bounds); time_t now = time(NULL); struct tm *t = localtime(&now); // Date if (strcmp(configs.dateoption, "nodate") == 0) { layer_set_hidden((Layer *)s_textlayer_date, true); } else { static char date[3]; strftime(date, 3, "%d", t); text_layer_set_text(s_textlayer_date, date); #ifdef PBL_COLOR graphics_context_set_stroke_width(ctx, 2); if (strcmp(configs.dialcolor, "white") == 0 || strcmp(configs.dialcolor, "white_nl") == 0) { graphics_context_set_fill_color(ctx, GColorDarkGray); graphics_context_set_stroke_color(ctx, GColorDarkGray); text_layer_set_text_color(s_textlayer_date, GColorDarkGray); } else if (strcmp(configs.dialcolor, "black") == 0 || strcmp(configs.dialcolor, "black_nl") == 0) { graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); text_layer_set_text_color(s_textlayer_date, GColorWhite); }; #else if (strcmp(configs.dialcolor, "white") == 0 || strcmp(configs.dialcolor, "white_nl") == 0) { graphics_context_set_fill_color(ctx, GColorBlack); graphics_context_set_stroke_color(ctx, GColorBlack); text_layer_set_text_color(s_textlayer_date, GColorBlack); } else if (strcmp(configs.dialcolor, "black") == 0 || strcmp(configs.dialcolor, "black_nl") == 0) { graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); text_layer_set_text_color(s_textlayer_date, GColorWhite); } #endif // Date box graphics_draw_rect(ctx, GRect(102, 74, 22, 20)); layer_set_hidden((Layer *)s_textlayer_date, false); } #ifdef PBL_COLOR graphics_context_set_stroke_width(ctx, 1); #endif // Hour hand if (strcmp(configs.dialcolor, "white") == 0 || strcmp(configs.dialcolor, "white_nl") == 0) { graphics_context_set_fill_color(ctx, GColorBlack); graphics_context_set_stroke_color(ctx, GColorBlack); } else if (strcmp(configs.dialcolor, "black") == 0 || strcmp(configs.dialcolor, "black_nl") == 0) { graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); } gpath_rotate_to(s_hour_arrow, (TRIG_MAX_ANGLE * (((t->tm_hour % 12) * 6) + (t->tm_min / 10))) / (12 * 6)); gpath_draw_filled(ctx, s_hour_arrow); gpath_draw_outline(ctx, s_hour_arrow); // Minute/hour hand if (strcmp(configs.dialcolor, "white") == 0 || strcmp(configs.dialcolor, "white_nl") == 0) { graphics_context_set_fill_color(ctx, GColorBlack); graphics_context_set_stroke_color(ctx, GColorBlack); } else if (strcmp(configs.dialcolor, "black") == 0 || strcmp(configs.dialcolor, "black_nl") == 0) { graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); } gpath_rotate_to(s_minute_arrow, TRIG_MAX_ANGLE * t->tm_min / 60); gpath_draw_filled(ctx, s_minute_arrow); gpath_draw_outline(ctx, s_minute_arrow); // Second hand if (strcmp(configs.secondhandoption, "quartz") == 0 || strcmp(configs.secondhandoption, "stop2go") == 0) { #ifdef PBL_COLOR graphics_context_set_fill_color(ctx, GColorRed); graphics_context_set_stroke_color(ctx, GColorRed); #else if (strcmp(configs.dialcolor, "white") == 0 || strcmp(configs.dialcolor, "white_nl") == 0) { graphics_context_set_fill_color(ctx, GColorBlack); graphics_context_set_stroke_color(ctx, GColorBlack); } else if (strcmp(configs.dialcolor, "black") == 0 || strcmp(configs.dialcolor, "black_nl") == 0) { graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); } #endif #ifdef PBL_COLOR graphics_context_set_stroke_width(ctx, 3); #endif //int16_t second_hand_length = (bounds.size.w / 2) - 22; int16_t second_hand_length = (bounds.size.w / 2) - 15; int16_t second_hand_opp_length = 16; double second_angle = 0; if (strcmp(configs.secondhandoption, "quartz") == 0) { second_angle = TRIG_MAX_ANGLE * t->tm_sec / 60; } // Stop2go else if (strcmp(configs.secondhandoption, "stop2go") == 0) { // Move the second hand around the watch in 58 seconds (60/58 = 1.03448275862) second_angle = TRIG_MAX_ANGLE * 1.03448275862 * (t->tm_sec / 60.0 + time_ms(NULL, NULL) / 60000.0); // Pause the second at 12 o'clock mark second_angle = (second_angle >= TRIG_MAX_ANGLE) ? TRIG_MAX_ANGLE : second_angle; } GPoint second_hand = { .x = (int16_t)(sin_lookup(second_angle) * (int32_t)second_hand_length / TRIG_MAX_RATIO) + center.x , .y = (int16_t)(-cos_lookup(second_angle) * (int32_t)second_hand_length / TRIG_MAX_RATIO) + center.y , }; graphics_draw_line(ctx, second_hand, center); GPoint second_hand_opp = { .x = (int16_t)(-sin_lookup(second_angle) * (int32_t)second_hand_opp_length / TRIG_MAX_RATIO) + center.x , .y = (int16_t)(cos_lookup(second_angle) * (int32_t)second_hand_opp_length / TRIG_MAX_RATIO) + center.y , }; graphics_draw_line(ctx, second_hand_opp, center); // Second hand circle graphics_fill_circle(ctx, second_hand, 3); // Dot in the middle #ifdef PBL_COLOR graphics_context_set_fill_color(ctx, GColorRed); graphics_context_set_stroke_color(ctx, GColorRed); #else if (strcmp(configs.dialcolor, "white") == 0 || strcmp(configs.dialcolor, "white_nl") == 0) { graphics_context_set_fill_color(ctx, GColorBlack); graphics_context_set_stroke_color(ctx, GColorBlack); } else if (strcmp(configs.dialcolor, "black") == 0 || strcmp(configs.dialcolor, "black_nl") == 0) { graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorWhite); } #endif graphics_fill_circle(ctx, GPoint(bounds.size.w / 2,bounds.size.h / 2), 4); } } static void load_background_image() { gbitmap_destroy(s_background_bitmap); if (strcmp(configs.dialcolor, "white") == 0) { s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_MONDAINE_WHITEBG); } else if (strcmp(configs.dialcolor, "white_nl") == 0) { s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_MONDAINE_WHITENLBG); } else if (strcmp(configs.dialcolor, "black") == 0) { s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_MONDAINE_BLACKBG); } else if (strcmp(configs.dialcolor, "black_nl") == 0) { s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_MONDAINE_BLACKNLBG); } bitmap_layer_set_bitmap(s_background_layer, s_background_bitmap); }
static void update_proc(Layer *layer, GContext *ctx) { int padding; PBL_IF_ROUND_ELSE(padding = 16, padding = 12); HOURS_TRACK_RADIUS = (window_bounds.size.w - padding) / 2; //66 HOURS_TRACK_STROKE = 2; MINUTES_TRACK_RADIUS = HOURS_TRACK_RADIUS - 10; //56 MINUTES_TRACK_STROKE = 2; SECONDS_TRACK_RADIUS = HOURS_TRACK_RADIUS - 20; //46 SECONDS_TRACK_STROKE = 2; SECONDS_HAND_RADIUS = 2; MINUTES_HAND_RADIUS = 3; HOURS_HAND_RADIUS = 4; // Color background graphics_context_set_fill_color(ctx, GColorBlack); graphics_fill_rect(ctx, window_bounds, 0, GCornerNone); //APP_LOG(APP_LOG_LEVEL_DEBUG, "bounds: %d %d %d %d", window_bounds.origin.x, window_bounds.origin.y, window_bounds.size.h, window_bounds.size.w ); //set colour for tracks graphics_context_set_stroke_color(ctx, GColorWhite ); graphics_context_set_antialiased(ctx, ANTIALIASING); // Don't use current time while animating Time mode_time = s_last_time; // generate position of hands GPoint second_hand = (GPoint) { .x = (int16_t)(sin_lookup(TRIG_MAX_ANGLE * mode_time.seconds / 60) * (int32_t)(SECONDS_TRACK_RADIUS) / TRIG_MAX_RATIO) + s_center.x, .y = (int16_t)(-cos_lookup(TRIG_MAX_ANGLE * mode_time.seconds / 60) * (int32_t)(SECONDS_TRACK_RADIUS) / TRIG_MAX_RATIO) + s_center.y, }; float minutes, hours; if (SWEEP_MINUTES == true) { minutes = mode_time.minutes + (float)mode_time.seconds / 60; } else { minutes = mode_time.minutes; } GPoint minute_hand = (GPoint) { .x = (int16_t)(sin_lookup(TRIG_MAX_ANGLE * minutes / 60) * (int32_t)(MINUTES_TRACK_RADIUS) / TRIG_MAX_RATIO) + s_center.x, .y = (int16_t)(-cos_lookup(TRIG_MAX_ANGLE * minutes/ 60) * (int32_t)(MINUTES_TRACK_RADIUS) / TRIG_MAX_RATIO) + s_center.y, }; if( SWEEP_HOURS == true) { hours = mode_time.hours + (float)mode_time.minutes / 60; } else { hours = mode_time.hours; } GPoint hour_hand = (GPoint) { .x = (int16_t)(sin_lookup(TRIG_MAX_ANGLE * hours / 12) * (int32_t)(HOURS_TRACK_RADIUS) / TRIG_MAX_RATIO) + s_center.x, .y = (int16_t)(-cos_lookup(TRIG_MAX_ANGLE * hours / 12) * (int32_t)(HOURS_TRACK_RADIUS) / TRIG_MAX_RATIO) + s_center.y, }; graphics_context_set_fill_color(ctx, GColorWhite); GRect seconds_rect = GRect(s_center.x - SECONDS_TRACK_RADIUS, s_center.y - SECONDS_TRACK_RADIUS, SECONDS_TRACK_RADIUS * 2, SECONDS_TRACK_RADIUS * 2); GRect minutes_rect = GRect(s_center.x - MINUTES_TRACK_RADIUS, s_center.y - MINUTES_TRACK_RADIUS, MINUTES_TRACK_RADIUS * 2, MINUTES_TRACK_RADIUS * 2); GRect hours_rect = GRect(s_center.x - HOURS_TRACK_RADIUS, s_center.y - HOURS_TRACK_RADIUS, HOURS_TRACK_RADIUS * 2, HOURS_TRACK_RADIUS * 2); //---------------------------------- int seconds_start_angle, seconds_end_angle; int seconds_delta = 12; int minutes_delta = 12; int hours_delta = 12; get_angles_60(mode_time.seconds, 0, seconds_delta, &seconds_start_angle, &seconds_end_angle); //---------------------------------- //int minutes_angle = mode_time.minutes * 360 / 60; int minutes_start_angle, minutes_end_angle; get_angles_60(mode_time.minutes, (SWEEP_MINUTES == true) ? mode_time.seconds : 0, minutes_delta, &minutes_start_angle, &minutes_end_angle); //get_angles_60(mode_time.minutes, mode_time.seconds, minutes_delta, &minutes_start_angle, &minutes_end_angle); //---------------------------------- //int hours_angle = mode_time.hours * 360 / 12; int hours_start_angle, hours_end_angle; get_angles_12(mode_time.hours,(SWEEP_HOURS == true) ? mode_time.minutes : 0, hours_delta, &hours_start_angle, &hours_end_angle); //APP_LOG(APP_LOG_LEVEL_DEBUG, "seconds: %d, start: %d, end: %d", mode_time.seconds, seconds_start_angle, seconds_end_angle); //set colour for arcs and "hands" graphics_context_set_fill_color(ctx, GColorWhite ); //draw seconds arc graphics_fill_radial(ctx, seconds_rect, GOvalScaleModeFitCircle, SECONDS_TRACK_STROKE, DEG_TO_TRIGANGLE(seconds_start_angle), DEG_TO_TRIGANGLE(seconds_end_angle)); //draw minutes arc graphics_fill_radial(ctx, minutes_rect, GOvalScaleModeFitCircle, MINUTES_TRACK_STROKE, DEG_TO_TRIGANGLE(minutes_start_angle), DEG_TO_TRIGANGLE(minutes_end_angle)); //draw hours arc graphics_fill_radial(ctx, hours_rect, GOvalScaleModeFitCircle, HOURS_TRACK_STROKE, DEG_TO_TRIGANGLE(hours_start_angle), DEG_TO_TRIGANGLE(hours_end_angle)); //draw minute hand graphics_fill_circle(ctx, minute_hand, MINUTES_HAND_RADIUS); //draw hour hand graphics_fill_circle(ctx, hour_hand, HOURS_HAND_RADIUS); //draw second hand graphics_context_set_fill_color(ctx, GColorRed ); graphics_fill_circle(ctx, second_hand, SECONDS_HAND_RADIUS); update_time(); } static void window_load(Window *window) { Layer *window_layer = window_get_root_layer(window); window_bounds = layer_get_bounds(window_layer); //APP_LOG(APP_LOG_LEVEL_DEBUG, "bounds: %d %d %d %d", window_bounds.origin.x, window_bounds.origin.y, window_bounds.size.h, window_bounds.size.w ); s_center = grect_center_point(&window_bounds); s_canvas_layer = layer_create(window_bounds); layer_set_update_proc(s_canvas_layer, update_proc); layer_add_child(window_layer, s_canvas_layer); // Create time TextLayer int font_height; PBL_IF_ROUND_ELSE(font_height = 45, font_height = 36); //fudge factor to get text vertically centred s_time_layer = text_layer_create(GRect(window_bounds.origin.x, (window_bounds.size.h-font_height)/2, window_bounds.size.w, font_height)); //s_center.y - MINUTES_TRACK_RADIUS + 18 + 18; s_day_layer = text_layer_create(GRect(0, s_center.y - 18 - 18 , window_bounds.size.w, 18)); //need to calculate proper y-location s_month_layer = text_layer_create(GRect(0, s_center.y +36 , window_bounds.size.w, 18)); //need to calculate proper y-location text_layer_set_background_color(s_day_layer, GColorRed); text_layer_set_text_color(s_day_layer, GColorLightGray ); text_layer_set_text(s_day_layer, "00"); text_layer_set_background_color(s_time_layer, GColorClear); text_layer_set_text_color(s_time_layer, GColorWhite); text_layer_set_text(s_time_layer, "00:00"); text_layer_set_background_color(s_month_layer, GColorClear); text_layer_set_text_color(s_month_layer, GColorLightGray ); text_layer_set_text(s_month_layer, "XXX"); PBL_IF_ROUND_ELSE(s_custom_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_DOSIS_SEMIBOLD_40)), s_custom_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_DOSIS_SEMIBOLD_30))); text_layer_set_font(s_time_layer, s_custom_font); text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter); text_layer_set_font(s_day_layer, fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_DOSIS_SEMIBOLD_18))); text_layer_set_text_alignment(s_day_layer, GTextAlignmentCenter); text_layer_set_font(s_month_layer, fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_DOSIS_SEMIBOLD_18))); text_layer_set_text_alignment(s_month_layer, GTextAlignmentCenter); // Add it as a child layer to the Window's root layer layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_time_layer)); layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_day_layer)); layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_month_layer)); // Make sure the time is displayed from the start update_time(); } static void window_unload(Window *window) { layer_destroy(s_canvas_layer); // Destroy TextLayer text_layer_destroy(s_time_layer); text_layer_destroy(s_day_layer); text_layer_destroy(s_month_layer); fonts_unload_custom_font(s_custom_font); } /*********************************** App **************************************/ static void init() { srand(time(NULL)); time_t t = time(NULL); struct tm *time_now = localtime(&t); tick_handler(time_now, SECOND_UNIT); s_main_window = window_create(); window_set_window_handlers(s_main_window, (WindowHandlers) { .load = window_load, .unload = window_unload, });
static void hands_layer_update_proc (Layer* layer, GContext* ctx) { GRect rect = layer_get_frame(layer); GPoint center = grect_center_point(&rect); GPath second_hand_path; GPath minute_hand_path; GPath hour_hand_path; PblTm time; char day_text[] = " "; char month_text[] = " "; char month_format[] = "%b"; int32_t second_angle; int32_t minute_angle; int32_t hour_angle; int32_t trig_ninety = TRIG_MAX_ANGLE / 4; int32_t trig_one_eighty = TRIG_MAX_ANGLE / 2; int32_t trig_second_angle; float second_length; int32_t trig_minute_angle; float minute_length = 60; int32_t trig_hour_angle; float hour_length = 60; get_time(&time); if (time.tm_hour > 12) { time.tm_hour-=12; } second_angle = time.tm_sec * 6; minute_angle = time.tm_min * 6; hour_angle = (time.tm_hour * 30) + (time.tm_min / 2); trig_second_angle = (TRIG_MAX_ANGLE / 60) * time.tm_sec; trig_minute_angle = (TRIG_MAX_ANGLE / 60) * time.tm_min; trig_hour_angle = (TRIG_MAX_ANGLE / 360) * hour_angle; if (((time.tm_sec >= 7 && time.tm_sec <= 23) || (time.tm_sec >= 37 && time.tm_sec <= 53)) && time.tm_sec != 0) { second_length = (72 * TRIG_MAX_ANGLE) / (cos_lookup(trig_second_angle - trig_ninety)); second_hand_path_points.points[4].y = (second_length > 0) ? -(second_length) : second_length; second_hand_path_points.points[3].y = (second_length > 0) ? -(second_length-5) : second_length+5; second_hand_path_points.points[5].y = (second_length > 0) ? -(second_length-5) : second_length+5; } else { second_length = (84 * TRIG_MAX_ANGLE) / (cos_lookup(trig_second_angle - trig_one_eighty)); second_hand_path_points.points[4].y = (second_length > 0) ? -(second_length) : second_length; second_hand_path_points.points[3].y = (second_length > 0) ? -(second_length-5) : second_length+5; second_hand_path_points.points[5].y = (second_length > 0) ? -(second_length-5) : second_length+5; } if (((time.tm_min >= 7 && time.tm_min <= 23) || (time.tm_min >= 37 && time.tm_min <= 53)) && time.tm_min != 0) { minute_length = (72 * TRIG_MAX_ANGLE) / (cos_lookup(trig_minute_angle - trig_ninety)); minute_hand_path_points.points[4].y = (minute_length > 0) ? -(minute_length) : minute_length; minute_hand_path_points.points[3].y = (minute_length > 0) ? -(minute_length-5) : minute_length+5; minute_hand_path_points.points[5].y = (minute_length > 0) ? -(minute_length-5) : minute_length+5; } else { minute_length = (84 * TRIG_MAX_ANGLE) / (cos_lookup(trig_minute_angle - trig_one_eighty)); minute_hand_path_points.points[4].y = (minute_length > 0) ? -(minute_length) : minute_length; minute_hand_path_points.points[3].y = (minute_length > 0) ? -(minute_length-5) : minute_length+5; minute_hand_path_points.points[5].y = (minute_length > 0) ? -(minute_length-5) : minute_length+5; } // the number of pixels the hour hand will remain from the window edge int hour_length_offset = 35; if (((hour_angle >= 49 && hour_angle <= 139) || (hour_angle >= 229 && hour_angle <= 311)) && hour_angle != 0) { hour_length = (72 * TRIG_MAX_ANGLE) / (cos_lookup(trig_hour_angle - trig_ninety)); hour_hand_path_points.points[4].y = (hour_length > 0) ? -(hour_length-hour_length_offset) : hour_length+hour_length_offset; hour_hand_path_points.points[3].y = (hour_length > 0) ? -(hour_length-(hour_length_offset+5)) : hour_length+(hour_length_offset+5); hour_hand_path_points.points[5].y = (hour_length > 0) ? -(hour_length-(hour_length_offset+5)) : hour_length+(hour_length_offset+5); } else { hour_length = (84 * TRIG_MAX_ANGLE) / (cos_lookup(trig_hour_angle - trig_one_eighty)); hour_hand_path_points.points[4].y = (hour_length > 0) ? -(hour_length-hour_length_offset) : hour_length+hour_length_offset; hour_hand_path_points.points[3].y = (hour_length > 0) ? -(hour_length-(hour_length_offset + 5)) : hour_length+(hour_length_offset + 5); hour_hand_path_points.points[5].y = (hour_length > 0) ? -(hour_length-(hour_length_offset + 5)) : hour_length+(hour_length_offset + 5); } gpath_init(&minute_hand_path, &minute_hand_path_points); gpath_move_to(&minute_hand_path, center); gpath_rotate_to(&minute_hand_path, TRIG_MAX_ANGLE / 360 * minute_angle); graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorBlack); gpath_draw_filled(ctx, &minute_hand_path); gpath_draw_outline(ctx, &minute_hand_path); gpath_init(&hour_hand_path, &hour_hand_path_points); gpath_move_to(&hour_hand_path, center); gpath_rotate_to(&hour_hand_path, TRIG_MAX_ANGLE / 360 * hour_angle); graphics_context_set_fill_color(ctx, GColorWhite); graphics_context_set_stroke_color(ctx, GColorBlack); gpath_draw_filled(ctx, &hour_hand_path); gpath_draw_outline(ctx, &hour_hand_path); gpath_init(&second_hand_path, &second_hand_path_points); gpath_move_to(&second_hand_path, center); gpath_rotate_to(&second_hand_path, TRIG_MAX_ANGLE / 360 * second_angle); graphics_context_set_fill_color(ctx, GColorBlack); graphics_context_set_stroke_color(ctx, GColorWhite); gpath_draw_filled(ctx, &second_hand_path); gpath_draw_outline(ctx, &second_hand_path); /* graphics_context_set_fill_color(ctx, GColorWhite); */ /* graphics_context_set_stroke_color(ctx, GColorBlack); */ /* graphics_fill_circle(ctx, center, 7); */ /* // graphics_draw_circle(ctx, center, 8); */ /* strcpy(day_text, itoa(time.tm_mday)); */ /* draw_outlined_text(ctx, */ /* day_text, */ /* fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD), */ /* GRect(0,75,144,168-80), */ /* GTextOverflowModeWordWrap, */ /* GTextAlignmentCenter, */ /* 1, */ /* false); */ }
void moon_LayerUpdateProc(struct Layer *layer, GContext *ctx) { /* GPath shadow; GPathInfo shadow_points = { 5, (GPoint []) { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, } }; */ int radius; int x, y, error; int mx, my; GPoint center; int edge; if(phase == 1) { graphics_context_set_fill_color(ctx, GColorBlack); graphics_fill_rect(ctx, GRect(0, 0, layer->frame.size.w, layer->frame.size.h), 0, GCornerNone); return; } if(phase == 15) return; graphics_context_set_fill_color(ctx, GColorWhite); center.x = layer->frame.size.w / 2; center.y = layer->frame.size.h / 2; radius = (layer->frame.size.w > layer->frame.size.h ? layer->frame.size.h / 2 : layer->frame.size.w / 2) - 4; // graphics_fill_circle(ctx, center, radius); graphics_context_set_stroke_color(ctx, GColorBlack); // circle algo from: http://en.wikipedia.org/wiki/Midpoint_circle_algorithm // Even though I studied it in school, it still feels like magic error = -radius; x = radius; y = 0; while ( x >= y) { if(phase < 15) { mx = x * (cos_lookup(TRIG_MAX_ANGLE * (phase / 28.0)) / (0xffff * 1.0)); my = y * (cos_lookup(TRIG_MAX_ANGLE * (phase / 28.0)) / (0xffff * 1.0)); edge = 0; } if(phase > 15) { mx = x * (cos_lookup(TRIG_MAX_ANGLE * ((phase - 15) / 32.0)) / (0xffff * 1.0)); my = y * (cos_lookup(TRIG_MAX_ANGLE * ((phase - 15) / 32.0)) / (0xffff * 1.0)); edge = layer->frame.size.w; } graphics_draw_line(ctx, GPoint(center.x + mx, center.y + y), GPoint(edge, center.y + y)); graphics_draw_line(ctx, GPoint(center.x + mx, center.y - y), GPoint(edge, center.y - y)); graphics_draw_line(ctx, GPoint(center.x + my, center.y + x), GPoint(edge, center.y + x)); graphics_draw_line(ctx, GPoint(center.x + my, center.y - x), GPoint(edge, center.y - x)); error += y; ++y; error += y; if( error >= 0) { error -= x; --x; error -= x; } } }
static void gpath_draw_filled_custom(GContext* ctx, GPath *path, GColor8 fill_color){ if(path->num_points == 0) return; GPoint offset = path->offset; int32_t rotation = path->rotation; int32_t s = sin_lookup(rotation); int32_t c = cos_lookup(rotation); // Rotate each point of the gpath and memorize the min/max GPoint* points_rot = malloc(sizeof(GPoint) * path->num_points); GPoint top_right = (GPoint){(1 << 15)-1,(1 << 15)-1}; GPoint bottom_left= (GPoint){-(1 << 15),-(1 << 15)}; for(uint32_t i=0; i<path->num_points; i++){ points_rot[i].x = (path->points[i].x * c - path->points[i].y * s) / TRIG_MAX_RATIO + offset.x; points_rot[i].y = (path->points[i].x * s + path->points[i].y * c) / TRIG_MAX_RATIO + offset.y; if(points_rot[i].x > bottom_left.x) bottom_left.x = points_rot[i].x; if(points_rot[i].x < top_right.x) top_right.x = points_rot[i].x; if(points_rot[i].y > bottom_left.y) bottom_left.y = points_rot[i].y; if(points_rot[i].y < top_right.y) top_right.y = points_rot[i].y; } // Create an array bitmap pebble v2 style (1 bit equals 1 pixel) int32_t bytes_per_row = (bottom_left.x - top_right.x + 1) / 8 + ((bottom_left.x - top_right.x + 1) % 8 == 0 ? 0 : 1); int32_t h = bottom_left.y - top_right.y + 1; uint8_t* pixels = malloc(bytes_per_row * h); memset(pixels, 0, bytes_per_row * h); // And draw the outline path in this 1 bit image GPoint prev_p = points_rot[path->num_points - 1]; GPoint p; for(uint32_t i=0; i<path->num_points; i++){ p = points_rot[i]; bmpDrawLine(pixels, bytes_per_row, prev_p.x - top_right.x, prev_p.y - top_right.y, p.x - top_right.x, p.y - top_right.y); prev_p = p; } free(points_rot); // Compute the starting point for the flow fill algorithm // TODO tobe improved GPoint start; start.x = (points_rot[0].x + points_rot[1].x) / 2; start.y = (points_rot[0].y + points_rot[1].y) / 2; if(points_rot[0].x < points_rot[1].x){ if(points_rot[0].y < points_rot[1].y){ start.x--; start.y++; } else { start.x++; start.y++; } } else { if(points_rot[0].y < points_rot[1].y){ start.x--; start.y--; } else { start.x++; start.y--; } } // Capture the frame buffer GBitmap* bitmap = graphics_capture_frame_buffer(ctx); // flood fill the gpath floodFill(bitmap, pixels, bytes_per_row, start, top_right, fill_color); // Release the frame buffer graphics_release_frame_buffer(ctx, bitmap); //Release the working variables free(pixels); }
static void draw_proc(Layer *layer, GContext *ctx) { srand(time(NULL)); // For screenshots GRect bounds = layer_get_bounds(layer); GPoint center = grect_center_point(&bounds); int lastMin = 0; if (SCREENSHOT_RUN) { lastMin = s_last_time.seconds; // For screenshots } else { lastMin = s_last_time.minutes; // For real } for (int m = 0; m <= 59; m++) { if (m <= lastMin) { graphics_context_set_fill_color(ctx, getDotMainColor()); } else { graphics_context_set_fill_color(ctx, getDotDarkColor()); } int v = DOT_DISTANCE; int numDots = s_dotArray[m]; if (m == lastMin || SCREENSHOT_RUN) { numDots = getNumDots(); s_dotArray[m] = numDots; } else if (numDots == 0 && m <= lastMin) { numDots = 1; } // For each dot for (int i = 0; i < numDots; i++) { // Draw dot for(int y = 0; y < 1; y++) { for(int x = 0; x < 1; x++) { GPoint point = (GPoint) { .x = (int16_t)(sin_lookup(TRIG_MAX_ANGLE * m / 60) * (int32_t)(v) / TRIG_MAX_RATIO) + center.x, .y = (int16_t)(-cos_lookup(TRIG_MAX_ANGLE * m / 60) * (int32_t)(v) / TRIG_MAX_RATIO) + center.y, }; graphics_fill_circle(ctx, GPoint(point.x + x, point.y + y), s_dotSize); } } // Draw next dot farther away v += DOT_SPACING; } } if (config_get(PERSIST_KEY_WEATHER) && hasWeather) { // Get weather "minute" int m = weatherTemp % 60; // Get weather dot color if (weatherTemp < 0) { graphics_context_set_fill_color(ctx, GColorCeleste); } else if (weatherTemp < 60) { graphics_context_set_fill_color(ctx, GColorMediumAquamarine); } else { graphics_context_set_fill_color(ctx, GColorOrange); } // Draw dot int v = DOT_DISTANCE - DOT_SPACING - 1; for(int y = 0; y < 1; y++) { for(int x = 0; x < 1; x++) { GPoint point = (GPoint) { .x = (int16_t)(sin_lookup(TRIG_MAX_ANGLE * m / 60) * (int32_t)(v) / TRIG_MAX_RATIO) + center.x, .y = (int16_t)(-cos_lookup(TRIG_MAX_ANGLE * m / 60) * (int32_t)(v) / TRIG_MAX_RATIO) + center.y, }; graphics_fill_circle(ctx, GPoint(point.x + x, point.y + y), s_dotSize); } } } } static void health_handler(HealthEventType event, void *context) { // Which type of event occured? switch(event) { case HealthEventSignificantUpdate: // APP_LOG(APP_LOG_LEVEL_INFO, "New HealthService HealthEventSignificantUpdate event"); break; case HealthEventMovementUpdate: APP_LOG(APP_LOG_LEVEL_INFO, "New HealthService HealthEventMovementUpdate event"); // Mark layer dirty so it updates layer_mark_dirty(s_canvas_layer); break; case HealthEventSleepUpdate: // APP_LOG(APP_LOG_LEVEL_INFO, "New HealthService HealthEventSleepUpdate event"); break; } } void comm_init() { app_message_register_inbox_received(in_recv_handler); // Register callbacks app_message_register_inbox_dropped(inbox_dropped_callback); app_message_register_outbox_failed(outbox_failed_callback); app_message_register_outbox_sent(outbox_sent_callback); app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum()); }