Source

pebble / worldmap / src / worldmap.c

/** \file
 * World map clock.
 *
 * Image from: http://commons.wikimedia.org/wiki/File:Northern_Hemisphere_Azimuthal_projections.svg
 *
 */
#include <pebble_os.h>
#include <pebble_app.h>
#include <pebble_fonts.h>

PBL_APP_INFO(
	"Polar Map",
	"hudson",
	1, // Version
	RESOURCE_ID_IMAGE_MENU_ICON,
	APP_INFO_WATCH_FACE
);

static Window window;

static RotBmpPairContainer map_container;

static char time_text[8];
static TextLayer time_layer;
static const int gmt_offset = -4; // hours from GMT

/** Called once per minute */
static void
handle_tick(
	AppContextRef ctx,
	PebbleTickEvent * const event
)
{
	(void) ctx;
#undef CONFIG_DEBUG
#ifdef CONFIG_DEBUG
	// Fake the time
	PblTm real_ptm = { .tm_hour = 17, .tm_min = 27 };
	PblTm * ptm = &real_ptm;
/*
	static int h = 0;
	if (++h == 24)
		h = 0;
	ptm->tm_hour = h;
*/
#else
	// real time
	const PblTm * const ptm = event->tick_time;
#endif

	// Adjust hour by GMT offset and reverse angle
	// Note that this image is has GMT "noon" at the bottom.
	// (world rotates "backwards" relative to the sun)
	const int32_t angle = 0
		+ (TRIG_MAX_ANGLE * gmt_offset) / 24
		+ (TRIG_MAX_ANGLE * (ptm->tm_hour + gmt_offset)) / 24
		+ (TRIG_MAX_ANGLE * ptm->tm_min) / (60 * 24)
		;

	const int q = (((angle + TRIG_MAX_ANGLE) & TRIG_MAX_RATIO) * 32) / TRIG_MAX_ANGLE;

	// Check for quadrants to determine where to move the time
	if (q <= 7)
	{
		// Upper left
		time_layer.layer.frame.origin = GPoint(0,-6);
	} else
	if (q <= 15)
	{
		// Lower left
		time_layer.layer.frame.origin = GPoint(0,150);
	} else
	if (q <= 23)
	{
		// Lower right
		time_layer.layer.frame.origin = GPoint(90, 150);
	} else
	if (q <= 31)
	{
		// Upper right
		time_layer.layer.frame.origin = GPoint(90, -6);
	}

#ifdef CONFIG_DBEUG
	ptm->tm_min = q;
#endif

	string_format_time(
		time_text,
		sizeof(time_text),
		"%H:%M",
		ptm
	);

	text_layer_set_text(&time_layer, time_text);

	rotbmp_pair_layer_set_angle(&map_container.layer, -angle);
	layer_mark_dirty(&map_container.layer.layer);
}


static void
text_layer(
	TextLayer * layer,
	GRect frame,
	GFont font
)
{
	text_layer_init(layer, frame);
	text_layer_set_text(layer, "");
#if 0
	// white bg to help with layout
	text_layer_set_text_color(layer, GColorBlack);
	text_layer_set_background_color(layer, GColorWhite);
#else
	// black bg for real
	text_layer_set_text_color(layer, GColorWhite);
	text_layer_set_background_color(layer, GColorBlack);
#endif

	text_layer_set_font(layer, font);

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


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

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

	resource_init_current_app(&RESOURCES);

	// This doesn't need the transparency, but there is no
	// rotbmp that isn't a pair?
	rotbmp_pair_init_container(
		RESOURCE_ID_IMAGE_MAP_WHITE,
		RESOURCE_ID_IMAGE_MAP_BLACK,
		&map_container
	);

	//map_container.layer.compositing_mode = GCompOpAssignInverted;
	//map_container.layer.compositing_mode = GCompOpAssign;

	rotbmp_pair_layer_set_src_ic(&map_container.layer, GPoint(100,100));

	// No dest_ic routines?  Relocate the point of rotation to
	// the center of the map for both layers.
	map_container.layer.white_layer.dest_ic = GPoint(144/2, 168/2);
	map_container.layer.black_layer.dest_ic = GPoint(144/2, 168/2);

	layer_add_child(&window.layer, &map_container.layer.layer);

	GFont font = fonts_load_custom_font(resource_get_handle(
		RESOURCE_ID_FONT_SOURCECODEPRO_LIGHT_18));

	text_layer(
		&time_layer,
		GRect(90, -6, 60, 20),
		font
	);
}


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

	rotbmp_pair_deinit_container(&map_container);
}


void
pbl_main(
	void * const params
)
{
	PebbleAppHandlers handlers = {
		.init_handler	= handle_init,
		.deinit_handler	= handle_deinit,
		.tick_info	= {
			.tick_handler = handle_tick,
#ifdef CONFIG_DEBUG
			.tick_units = MINUTE_UNIT,
#else
			.tick_units = SECOND_UNIT,
#endif
		},
	};

	app_event_loop(params, &handlers);
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.