1. Trammell Hudson
  2. pebble

Source

pebble / words / src / words.c

/** \file
 * Word clock, like the qlock2
 */
#include <pebble_os.h>
#include <pebble_app.h>
#include <pebble_fonts.h>

PBL_APP_INFO(
	"Wordsquare",
	"hudson",
	1, // Version
	INVALID_RESOURCE,
	APP_INFO_WATCH_FACE
);

#define ROWS 10
#define COLS 11
#define FONT_H 16
#define FONT_W 11
#define FONT_ON		RESOURCE_ID_FONT_COURIER_BOLD_19
#define FONT_OFF	RESOURCE_ID_FONT_COURIER_19


typedef struct
{
	int row;
	int col;
	char text[8];
} word_t;

#define LAYER_FIVE	13
#define LAYER_TEN	14
#define LAYER_QUARTER	15
#define LAYER_HALF	16
#define LAYER_TWENTY	17
#define LAYER_IT	 0
#define LAYER_IS	18
#define LAYER_PAST	19
#define LAYER_TO	20
#define LAYER_OCLOCK	21
#define LAYER_FILLER	22

static const word_t words[] = {
	// Hours 1-12
	[1] = {  5, 0, "ONE" },
	[2] = {  6, 8, "TWO" },
	[3] = {  5, 6, "THREE" },
	[4] = {  6, 0, "FOUR" },
	[5] = {  6, 4, "FIVE" }, // hour
	[6] = {  5, 3, "SIX" },
	[7] = {  8, 0, "SEVEN" },
	[8] = {  7, 0, "EIGHT" },
	[9] = {  4, 7, "NINE" },
	[10] = {  9, 0, "TEN" }, // hour
	[11] = {  7, 5, "ELEVEN" },
	[12] = {  8, 5, "TWELVE" },

	// Minutes 13-
	[LAYER_FIVE]	= {  2, 6, "FIVE" }, // minute
	[LAYER_TEN]	= {  3, 5, "TEN" }, // minute
	[LAYER_QUARTER]	= {  1, 2, "QUARTER" },
	[LAYER_HALF]	= {  3, 0, "HALF" },
	[LAYER_TWENTY]	= {  2, 0, "TWENTY" },

	// Relative
	[LAYER_IT] = {  0, 0, "IT" },
	[LAYER_PAST]	= {  4, 0, "PAST" },
	[LAYER_TO]	= {  3, 9, "TO" },
	[LAYER_OCLOCK]	= {  9, 5, "OCLOCK" },
	[LAYER_IS]	= {  0, 3, "IS" },

	// Fillers
	[LAYER_FILLER]	= {  0, 2, "L" },
	{  0, 5, "AATIME" },
	{  1, 0, "A" },
	{  1, 1, "T" },
	{  1, 9, "TH" },
	{  2, 10, "X" },
	{  3, 4, "B" },
	{  3, 8, "F" },
	{  4, 4, "ERU" },
	{  9, 3, "SE" },
};

#define WORD_COUNT ((sizeof(words) / sizeof(*words)))

static Window window;
static TextLayer layers[WORD_COUNT];

static void
layer_mark(
	TextLayer * const layer,
	int on
)
{
	text_layer_set_font(
		layer,
		fonts_load_custom_font(resource_get_handle(on ? FONT_ON : FONT_OFF))
	);
}


/** Called once per minute */
static void
handle_tick(
	AppContextRef ctx,
	PebbleTickEvent * const event
)
{
	(void) ctx;
	const PblTm * const ptm = event->tick_time;

	int hour = ptm->tm_hour;
	int min = ptm->tm_min;

	// light up the next hour if we are half before
	if (min > 30)
	{
		hour++;
		min = 60 - min;
		layer_mark(&layers[LAYER_TO], 1);
		layer_mark(&layers[LAYER_PAST], 0);
	} else {
		layer_mark(&layers[LAYER_TO], 0);
		layer_mark(&layers[LAYER_PAST], min >= 5);
	}

	// Convert from 24-hour to 12-hour time
	if (hour == 0)
		hour = 12;
	else
	if (hour > 12)
		hour -= 12;

	for (int i = 1 ; i < 12 ; i++)
		layer_mark(&layers[i], i == hour ? 1 : 0);

	// mark all of the minutes as off,
	// and then turn on the ones that count
	layer_mark(&layers[LAYER_OCLOCK], 0);
	layer_mark(&layers[LAYER_FIVE], 0);
	layer_mark(&layers[LAYER_TEN], 0);
	layer_mark(&layers[LAYER_QUARTER], 0);
	layer_mark(&layers[LAYER_TWENTY], 0);
	layer_mark(&layers[LAYER_HALF], 0);

	if (min < 5)
		layer_mark(&layers[LAYER_OCLOCK], 1);
	else
	if (min < 10)
		layer_mark(&layers[LAYER_FIVE], 1);
	else
	if (min < 15)
		layer_mark(&layers[LAYER_TEN], 1);
	else
	if (min < 20)
		layer_mark(&layers[LAYER_QUARTER], 1);
	else
	if (min < 25)
		layer_mark(&layers[LAYER_TWENTY], 1);
	else
	if (min < 30)
	{
		layer_mark(&layers[LAYER_TWENTY], 1);
		layer_mark(&layers[LAYER_FIVE], 1);
	} else
	{
		layer_mark(&layers[LAYER_HALF], 1);
	}
		
/*
	string_format_time(
		time_buffer,
		sizeof(time_buffer),
		"%H:%M",
		event->tick_time
	);

	text_layer_set_text(&ampm_layer, ampm_text);
	text_layer_set_text(&hour_layer, hour_text);
	text_layer_set_text(&rel_layer, rel_text);
	text_layer_set_text(&min_layer, min_text);
*/
}


static void
text_layer(
	TextLayer * layer,
	int row,
	int col,
	const char * text
)
{
	GRect frame = GRect(
		col*FONT_W + 10,
		row*FONT_H,
		strlen(text)*(FONT_W+4),
		FONT_H+5
	);
	text_layer_init(layer, frame);
	text_layer_set_text(layer, text);
	text_layer_set_text_color(layer, GColorWhite);
	text_layer_set_background_color(layer, GColorClear);
	layer_mark(layer, 0); // all are "off" initially

	layer_add_child(&window.layer, &layer->layer);
}


static void
handle_init(
	AppContextRef ctx
)
{
	(void) ctx;

	window_init(&window, "Main");
	window_stack_push(&window, true);
	window_set_background_color(&window, GColorBlack);

	resource_init_current_app(&RESOURCES);

	for (unsigned i = 0 ; i < WORD_COUNT ; i++)
	{
		const word_t * const w = &words[i];
		text_layer(
			&layers[i],
			w->row,
			w->col,
			w->text
		);
	}

	// Flag the ones that are always on
	layer_mark(&layers[LAYER_IT], 1);
	layer_mark(&layers[LAYER_IS], 1);
}


void
pbl_main(
	void * const params
)
{
	PebbleAppHandlers handlers = {
		.init_handler	= &handle_init,
		.tick_info	= {
			.tick_handler = &handle_tick,
			.tick_units = MINUTE_UNIT,
		},
	};

	app_event_loop(params, &handlers);
}