Ron

27 Jan 2015

I chose to represent the time with a set of twelve circles, configured in a 4 x 3, to represent the hour, and a linear bar graph to represent the minutes. At a glance, the minutes can be quickly read to a 15-minute-mark since the minute bar spans the 4 circles, and I felt like that, visually, this was a way to present time information that could be translated easily. I presented this watch face to a few different people, who were able to understand what was being represented.

It took me awhile to understand how to draw shapes and graphics in this program; studying some of the examples helped me to build off them. I wish I could have incorporated the accelerometer to incorporate some motion or playfulness, but did not have time.

Here’s a time lapse of the watch face over 15 minutes:

And some stills from different parts of the day (12:45, 2:41, 10:17) :

 



#include "pebble.h"

Window *window;
Layer *display_layer;

// Defines for the 4 x 3 table of circles representing hour
#define HOUR_CIRCLE_RADIUS_PIXELS         16
#define HOUR_CIRCLE_EDGE_STROKE_PIXELS 2

#define HOUR_CIRCLE_PADDING_PIXELS 18 - HOUR_CIRCLE_RADIUS_PIXELS
#define HOUR_CIRCLE_CELL_SIZE     (2 * (HOUR_CIRCLE_RADIUS_PIXELS + HOUR_CIRCLE_PADDING_PIXELS))

#define HOUR_CELLS_PER_ROW     4
#define HOUR_CELLS_PER_COLUMN  3

#define HOURS_ONE_FOUR_ROW    0
#define HOURS_FIVE_EIGHT_ROW  1
#define HOURS_NINE_TWELVE_ROW 2
#define HOURS_NUM_COLS        4
#define HOURS_NUM_ROWS        4

// Defines for the bar representing minute
#define MAX_MINUTE_BAR_VAL 144  
  
void draw_and_fill_circle(GContext* ctx, GPoint center, bool fillcircle) {
  
  graphics_context_set_fill_color(ctx, GColorWhite);

  graphics_fill_circle(ctx, center, HOUR_CIRCLE_RADIUS_PIXELS);

  if (!fillcircle) {
    graphics_context_set_fill_color(ctx, GColorBlack);
    graphics_fill_circle(ctx, center, HOUR_CIRCLE_RADIUS_PIXELS - HOUR_CIRCLE_EDGE_STROKE_PIXELS);
  }

}

void draw_minute_bar(Layer *me, GContext* ctx, unsigned short minute_value) {
    
    //draw rectangle to represent 60 minutes
    GRect minute_bar_rect;
    minute_bar_rect.origin = GPoint(0,130);
    minute_bar_rect.size = GSize(144,16);
    graphics_context_set_stroke_color(ctx, GColorWhite);
    graphics_draw_rect(ctx, rect1);
        
    //draw a filled rectangle to represent the minute
    unsigned short minute_fill = (minute_value * MAX_MINUTE_BAR_VAL) / 60;
    
    GRect minute_fill_rect;
    minute_fill_rect.origin = GPoint(0,130);
    minute_fill_rect.size = GSize(minute_fill,16);
    graphics_context_set_fill_color(ctx, GColorWhite);
    graphics_fill_rect(ctx, rect3, 0, GCornerNone);
}

GPoint get_circle_center(unsigned short x, unsigned short y) {
  return GPoint((HOUR_CIRCLE_CELL_SIZE/2) + (HOUR_CIRCLE_CELL_SIZE * x),
		(HOUR_CIRCLE_CELL_SIZE/2) + (HOUR_CIRCLE_CELL_SIZE * y));
}


void draw_table_for_hour(GContext* ctx, unsigned short hour_value, unsigned short max_columns, unsigned short row) {
  for (int cell_column_index = 0; cell_column_index< max_columns; cell_column_index++) {
    draw_and_fill_circle(ctx,get_circle_center(cell_column_index, row), ((hour_value - (HOURS_NUM_ROWS * row) - cell_column_index) > 0));
  }
}


unsigned short get_display_hour(unsigned short hour) {
  unsigned short display_hour = hour % 12;

  // Convert "0" hour to "12"
  return display_hour ? display_hour : 12;

}


void display_layer_update_callback(Layer *me, GContext* ctx) {

  time_t now = time(NULL);
  struct tm *t = localtime(&now);

  unsigned short display_hour = get_display_hour(t->tm_hour);
  

  draw_table_for_hour(ctx, display_hour, HOURS_NUM_COLS, HOURS_ONE_FOUR_ROW);
  draw_table_for_hour(ctx, display_hour, HOURS_NUM_COLS, HOURS_FIVE_EIGHT_ROW);
  draw_table_for_hour(ctx, display_hour, HOURS_NUM_COLS, HOURS_NINE_TWELVE_ROW);
  
  draw_minute_bar(me, ctx, t->tm_min);


static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
  layer_mark_dirty(display_layer);
}

static void do_init(void) {
  window = window_create();
  window_stack_push(window, true);

  window_set_background_color(window, GColorBlack);

  Layer *root_layer = window_get_root_layer(window);
  GRect frame = layer_get_frame(root_layer);

  // Init the layer for the display
  display_layer = layer_create(frame);
  layer_set_update_proc(display_layer, &display_layer_update_callback);
  layer_add_child(root_layer, display_layer);

  tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
}

static void do_deinit(void) {
  layer_destroy(display_layer);
  window_destroy(window);
}

int main(void) {
  do_init();
  app_event_loop();
  do_deinit();
}