Commits

Trammell Hudson committed f71a20c Merge

merged

Comments (0)

Files changed (12)

lib/src/datetime.c

 
 	return now;
 }
+
+
+static const int julian_1900 = 2415033;
+
+uint32_t
+julian_day(
+	const int year, // since 0
+	const int month, // 1 - 12
+	const int day // 1 - 31
+)
+{
+	int a = (14 - month) / 12;
+	int y = year + 4800 - a;
+	int m = month + 12 * a - 3;
+	return day + (153 * m + 2) / 5 + 365 * y + y / 4 - 32083;
+}
+
+
+uint32_t
+julian_day_pbl(
+	const PblTm * const tm
+)
+{
+	return julian_day(
+		tm->tm_year + 1900,
+		tm->tm_mon + 1,
+		tm->tm_mday
+	);
+}
+
+
+uint32_t
+moonphase(
+	const PblTm * const tm
+)
+{
+	// Compute julian day since 1 jan 1900, which was new moon
+	uint32_t julian = julian_day_pbl(tm);
+	julian -= julian_1900;
+
+	return julian % 2953;
+}

lib/src/pebble_th.h

 );
 
 
+/** Compute the phase of the moon.
+ * 0 == new moon,
+ * 2953 == almost a full moon.
+ */
+uint32_t
+moonphase(
+	const PblTm * const now
+);
+
+
+uint32_t
+julian_day_pbl(
+	const PblTm * const now
+);
+
+
+uint32_t
+julian_day(
+	const int year, // since 0
+	const int month, // 1 - 12
+	const int day // 1 - 31
+);
+
+
+uint32_t
+days_since_1900(
+	uint32_t year
+);
+
 #endif

th10/src/Makefile

+#
+# Basic analog clock with large numbers, classic hands
+#
+
+APP := th10
+
+SRCS += th10.c
+
+FONTS := \
+	fonts/GillSans.ttc:40 \
+	fonts/GillSans.ttc:16 \
+
+#fonts/Arial.ttf:16 \
+
+IMAGES := \
+	images/menu_icon.png \
+
+include ../../Makefile.pebble
Add a comment to this file

th10/src/fonts/GillSans.ttc

Binary file added.

Add a comment to this file

th10/src/images/menu_icon.png

Added
New image
+/** \file
+ * TH10 -- Torgoen T10 analog style
+ *
+ */
+#include "pebble_os.h"
+#include "pebble_app.h"
+#include "pebble_fonts.h"
+#include "pebble_th.h"
+
+#define UUID { 0xDD, 0xD6, 0x07, 0x2A, 0x2D, 0x0B, 0x4D, 0x79, 0x99, 0x6D, 0xDC, 0x69, 0xD4, 0x62, 0xB8, 0x5B }
+
+PBL_APP_INFO(
+	UUID,
+	"TH10",
+	"hudson",
+	1, 0, // Version
+	RESOURCE_ID_IMAGE_MENU_ICON,
+	APP_INFO_WATCH_FACE
+);
+
+
+static Window window;
+static Layer hand_layer;
+static Layer bg_layer;
+static PblTm now;
+static GFont font_time;
+static GFont font_date;
+
+static int use_24hour;
+
+
+// Dimensions of the watch face
+#define W PEBBLE_SCREEN_WIDTH
+#define H PEBBLE_SCREEN_HEIGHT
+#define R (W/2 - 2)
+
+// Hour hand
+static GPath hour_path;
+static GPoint hour_points[] = {
+	{  -8, -20 },
+	{ -10, -40 },
+	{   0, -60 },
+	{ +10, -40 },
+	{  +8, -20 },
+	{  -8, -20 },
+};
+
+// Minute hand
+static GPath minute_path;
+static GPoint minute_points[] = {
+	{ -5, -20 },
+	{ -7, -60 },
+	{  0, -76 },
+	{ +7, -60 },
+	{ +5, -20 },
+	{ -5, -20 },
+};
+
+// Hour hand ticks around the circle (slightly shorter)
+static GPath hour_tick_path;
+static GPoint hour_tick_points[] = {
+	{ -3, 70 },
+	{ +3, 70 },
+	{ +3, 84 },
+	{ -3, 84 },
+};
+
+// Non-hour major ticks around the circle
+static GPath major_tick_path;
+static GPoint major_tick_points[] = {
+	{ -3, 60 },
+	{ +3, 60 },
+	{ +3, 84 },
+	{ -3, 84 },
+};
+
+// Non-major ticks around the circle; will be drawn as lines
+static GPath minor_tick_path;
+static GPoint minor_tick_points[] = {
+	{ 0, 76 },
+	{ 0, 84 },
+};
+
+static void
+hand_layer_update(
+        Layer * const me,
+        GContext * ctx
+)
+{
+	(void) me;
+
+	// Draw the minute hand outline in black and filled with white
+	int minute_angle = (now.tm_min * TRIG_MAX_ANGLE) / 60;
+
+	gpath_rotate_to(&minute_path, minute_angle);
+	graphics_context_set_stroke_color(ctx, GColorBlack);
+	gpath_draw_outline(ctx, &minute_path);
+	graphics_context_set_fill_color(ctx, GColorWhite);
+	gpath_draw_filled(ctx, &minute_path);
+
+	// Draw the hour hand outline in black and filled with white
+	// above the minute hand
+	int hour_angle;
+	if (use_24hour)
+	{
+		hour_angle = ((now.tm_hour * 60 + now.tm_min) * TRIG_MAX_ANGLE) / (60 * 24);
+	} else {
+		int hour = now.tm_hour;
+		if (hour > 12)
+			hour -= 12;
+		hour_angle = ((hour * 60 + now.tm_min) * TRIG_MAX_ANGLE) / (60 * 12);
+	}
+
+	gpath_rotate_to(&hour_path, hour_angle);
+	graphics_context_set_stroke_color(ctx, GColorBlack);
+	gpath_draw_outline(ctx, &hour_path);
+	graphics_context_set_fill_color(ctx, GColorWhite);
+	gpath_draw_filled(ctx, &hour_path);
+
+}
+
+
+/** Called once per minute */
+static void
+handle_tick(
+	AppContextRef ctx,
+	PebbleTickEvent * const event
+)
+{
+	(void) ctx;
+
+	// If the day of month changes, for a redraw of the background
+	if (now.tm_mday != event->tick_time->tm_mday)
+		layer_mark_dirty(&bg_layer);
+
+	layer_mark_dirty(&hand_layer);
+
+	now = *event->tick_time;
+}
+
+
+/** Draw the initial background image */
+static void
+bg_layer_update(
+        Layer * const me,
+        GContext * ctx
+)
+{
+	(void) me;
+
+	graphics_context_set_stroke_color(ctx, GColorWhite);
+	graphics_context_set_fill_color(ctx, GColorWhite);
+
+	// Draw the center circle
+	graphics_draw_circle(ctx, GPoint(W/2,H/2), 3);
+
+	// Draw the outside marks
+	for (int min = 0 ; min < 60 ; min++)
+	{
+		const int angle = (min * TRIG_MAX_ANGLE) / 60;
+		if ((min % 15) == 0)
+		{
+			gpath_rotate_to(&hour_tick_path, angle);
+			gpath_draw_filled(ctx, &hour_tick_path);
+		} else
+		if ((min % 5) == 0)
+		{
+			gpath_rotate_to(&major_tick_path, angle);
+			gpath_draw_filled(ctx, &major_tick_path);
+		} else {
+			gpath_rotate_to(&minor_tick_path, angle);
+			gpath_draw_outline(ctx, &minor_tick_path);
+		}
+	}
+
+	// And the large labels
+	graphics_context_set_text_color(ctx, GColorWhite);
+	graphics_text_draw(ctx,
+		use_24hour ? "24" : "12",
+		font_time,
+		GRect(W/2-30,4,60,50),
+		GTextOverflowModeTrailingEllipsis,
+		GTextAlignmentCenter,
+		NULL
+	);
+
+	graphics_text_draw(ctx,
+		use_24hour ? "06" : "3",
+		font_time,
+		GRect(W/2,H/2-26,70,50),
+		GTextOverflowModeTrailingEllipsis,
+		GTextAlignmentRight,
+		NULL
+	);
+
+	graphics_text_draw(ctx,
+		use_24hour ? "12" : "6",
+		font_time,
+		GRect(W/2-30,110,60,50),
+		GTextOverflowModeTrailingEllipsis,
+		GTextAlignmentCenter,
+		NULL
+	);
+
+	graphics_text_draw(ctx,
+		use_24hour ? "18" : "9",
+		font_time,
+		GRect(W/2-70,H/2-26,60,50),
+		GTextOverflowModeTrailingEllipsis,
+		GTextAlignmentLeft,
+		NULL
+	);
+
+	// Draw a small box with the current date
+	int mday = now.tm_mday;
+	char mday_str[3] = {
+		'0' + (mday / 10),
+		'0' + (mday % 10),
+		'\0'
+	};
+
+#if 0
+	graphics_context_set_fill_color(ctx, GColorWhite);
+	const int date_x = W/2+25;
+	const int date_y = H/2+25;
+
+	graphics_fill_rect(
+		ctx,
+		GRect(date_x, date_y, 20, 18),
+		2,
+		GCornersAll
+	);
+
+	graphics_context_set_text_color(ctx, GColorBlack);
+	graphics_text_draw(
+		ctx,
+		mday_str,
+		font_date,
+		GRect(date_x, date_y-1, 20, 18),
+		GTextOverflowModeTrailingEllipsis,
+		GTextAlignmentCenter,
+		NULL
+	);
+#else
+	// lower right corner? Looks ok, but not classic
+	const int date_x = W - 20;
+	const int date_y = H - 18;
+
+	graphics_text_draw(
+		ctx,
+		mday_str,
+		font_date,
+		GRect(date_x, date_y-1, 20, 18),
+		GTextOverflowModeTrailingEllipsis,
+		GTextAlignmentCenter,
+		NULL
+	);
+#endif
+}
+
+#define GPATH_INIT(PATH, POINTS) ({ \
+	GPathInfo __info = { sizeof(POINTS) / sizeof(*POINTS), POINTS }; \
+	gpath_init(PATH, &__info); \
+	})
+
+static void
+handle_init(
+	AppContextRef ctx
+)
+{
+	(void) ctx;
+
+	GPATH_INIT(&hour_path, hour_points);
+	gpath_move_to(&hour_path, GPoint(W/2,H/2));
+
+	GPATH_INIT(&minute_path, minute_points);
+	gpath_move_to(&minute_path, GPoint(W/2,H/2));
+
+	GPATH_INIT(&major_tick_path, major_tick_points);
+	gpath_move_to(&major_tick_path, GPoint(W/2,H/2));
+
+	GPATH_INIT(&hour_tick_path, hour_tick_points);
+	gpath_move_to(&hour_tick_path, GPoint(W/2,H/2));
+
+	GPATH_INIT(&minor_tick_path, minor_tick_points);
+	gpath_move_to(&minor_tick_path, GPoint(W/2,H/2));
+
+	get_time(&now);
+	use_24hour = clock_is_24h_style();
+
+	window_init(&window, "Main");
+	window_stack_push(&window, true);
+	window_set_background_color(&window, GColorBlack);
+
+	resource_init_current_app(&RESOURCES);
+
+	font_time = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_GILLSANS_40));
+	font_date = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_GILLSANS_16));
+
+	layer_init(&bg_layer, GRect(0, 0, W, H));
+	layer_add_child(&window.layer, &bg_layer);
+	bg_layer.update_proc = bg_layer_update;
+	layer_mark_dirty(&bg_layer);
+
+	layer_init(&hand_layer, GRect(0, 0, W, H));
+	layer_add_child(&window.layer, &hand_layer);
+	hand_layer.update_proc = hand_layer_update;
+	layer_mark_dirty(&hand_layer);
+}
+
+
+static void
+handle_deinit(
+	AppContextRef ctx
+)
+{
+	(void) ctx;
+
+	fonts_unload_custom_font(font_time);
+	fonts_unload_custom_font(font_date);
+}
+
+
+void
+pbl_main(
+	void * const params
+)
+{
+	PebbleAppHandlers handlers = {
+		.init_handler	= &handle_init,
+		.deinit_handler = &handle_deinit,
+		.tick_info	= {
+			.tick_handler = &handle_tick,
+			.tick_units = MINUTE_UNIT,
+		},
+	};
+
+	app_event_loop(params, &handlers);
+}

timezones/src/tz.c

 
 
 // Local timezone GMT offset
-static const int gmt_offset = -5;
+static const int gmt_offset = -5 * 60;
 
 #define NUM_TIMEZONES 3
 #define LAYER_HEIGHT (PEBBLE_SCREEN_HEIGHT / NUM_TIMEZONES)
 
 static timezone_t timezones[NUM_TIMEZONES] =
 {
-	{ "New York", -5, {} },
-	{ "London", +0, {} },
-	{ "Tokyo", +8, {} },
+	{ .name = "New York", .offset = -5 * 60 },
+	{ .name = "London", .offset = +0 * 60 },
+	{ .name = "India", .offset = +(5 * 60 + 30) },
 };
 
 
 	const timezone_t * const tz = container_of(me, timezone_t, layer);
 
 	const int orig_hour = now.tm_hour;
+	const int orig_min = now.tm_min;
 
-	now.tm_hour += tz->offset - gmt_offset;
+	now.tm_min += (tz->offset - gmt_offset) % 60;
+	if (now.tm_min > 60)
+	{
+		now.tm_hour++;
+		now.tm_min -= 60;
+	} else
+	if (now.tm_min < 0)
+	{
+		now.tm_hour--;
+		now.tm_min += 60;
+	}
+
+	now.tm_hour += (tz->offset - gmt_offset) / 60;
 	if (now.tm_hour > 24)
 		now.tm_hour -= 24;
 	if (now.tm_hour < 0)
 
 	const int night_time = (now.tm_hour > 18 || now.tm_hour < 6);
 	now.tm_hour = orig_hour;
+	now.tm_min = orig_min;
 
 	const int w = me->bounds.size.w;
 	const int h = me->bounds.size.h;

zulu/src/Makefile

+#
+# Draw the sun up/sundown with moon phase
+#
+
+APP := zulu
+
+SRCS += zulu.c
+
+FONTS := \
+	fonts/Arial-Black.ttf:30 \
+
+#fonts/Arial.ttf:16 \
+
+IMAGES := \
+	images/menu_icon.png \
+
+include ../../Makefile.pebble
Add a comment to this file

zulu/src/fonts/Arial-Black.ttf

Binary file added.

Add a comment to this file

zulu/src/fonts/Arial.ttf

Binary file added.

Add a comment to this file

zulu/src/images/menu_icon.png

Added
New image
+/** \file
+ * Sun up/sundown clock with 24 hour face and moon phase.
+ *
+ */
+#include "pebble_os.h"
+#include "pebble_app.h"
+#include "pebble_fonts.h"
+#include "pebble_th.h"
+
+#define UUID { 0x06, 0x97, 0xE5, 0x7F, 0x60, 0xF7, 0x43, 0xC5, 0x80, 0xC4, 0x35, 0x9D, 0xB2, 0x7E, 0xCD, 0xEE }
+
+PBL_APP_INFO(
+	UUID,
+	"Moonphase",
+	"hudson",
+	1, 0, // Version
+	RESOURCE_ID_IMAGE_MENU_ICON,
+	APP_INFO_WATCH_FACE
+);
+
+
+// Local timezone GMT offset
+static const int gmt_offset = -5;
+
+static Window window;
+static Layer graphics_layer;
+static PblTm now;
+static GFont font_thin;
+static GFont font_thick;
+
+
+// Dimensions of the watch face
+#define W PEBBLE_SCREEN_WIDTH
+#define H PEBBLE_SCREEN_WIDTH
+#define R (W/2 - 2)
+#define MOON_RADIUS 16
+
+// Circle points computed at startup and the path is dynamically adjuste
+#define NUM_POINTS 256
+static GPoint circle_points[NUM_POINTS];
+static GPath circle_path;
+static GPathInfo circle_info = { NUM_POINTS, circle_points };
+
+// Hour markers
+static GPath hour_path;
+static GPoint hour_points[] = {
+	{ -4, R + 4 },
+	{  4, R + 4 },
+	{  0, R - 4 },
+	{ -4, R + 4 },
+};
+static GPathInfo hour_info = { sizeof(hour_points)/sizeof(*hour_points), hour_points };
+
+// Hour hand
+static GPath hand_path;
+static GPoint hand_points[] = {
+	{  0, -5 },
+	{ -5, -15 },
+	{  0, -R },
+	{ +5, -15 },
+	{  0, 0 },
+};
+static GPathInfo hand_info = { sizeof(hand_points)/sizeof(*hand_points), hand_points };
+
+
+static void
+graphics_layer_update(
+        Layer * const me,
+        GContext * ctx
+)
+{
+	(void) me;
+
+	const int w = me->bounds.size.w;
+	const int h = me->bounds.size.h;
+
+	graphics_context_set_stroke_color(ctx, GColorWhite);
+	graphics_context_set_fill_color(ctx, GColorWhite);
+
+	// Draw the outline circle
+	graphics_draw_circle(ctx, GPoint(w/2,h/2), R);
+
+	// Compute the sun up / sun down time and
+	// draw the semi-circle
+	int sun_up = (7 * NUM_POINTS) / 24;
+	int sun_down = (17 * NUM_POINTS) / 24;;
+
+	circle_path.num_points = sun_down - sun_up;
+	circle_path.points = &circle_points[sun_up];
+
+	GPoint temp = circle_path.points[0];
+	circle_path.points[0] = GPoint(w/2,h/2);
+	gpath_draw_filled(ctx, &circle_path);
+	circle_path.points[0] = temp;
+
+
+	// Draw the moon phase in a cutout inside the bottom half
+	graphics_context_set_fill_color(ctx, GColorBlack);
+	graphics_fill_circle(ctx, GPoint(w/2,3*h/4), MOON_RADIUS);
+	graphics_draw_circle(ctx, GPoint(w/2,3*h/4), MOON_RADIUS);
+
+	// Draw the hour marks
+	for (int hour = 0 ; hour < 23 ; hour++)
+	{
+		gpath_rotate_to(&hour_path, (hour * TRIG_MAX_ANGLE) / 24);
+		graphics_context_set_fill_color(ctx, GColorBlack);
+		gpath_draw_filled(ctx, &hour_path);
+		graphics_context_set_stroke_color(ctx, GColorWhite);
+		gpath_draw_outline(ctx, &hour_path);
+	}
+
+	// Draw the hour hand outline and filled with black
+	int hand_angle = ((now.tm_hour * 60 + now.tm_min) * TRIG_MAX_ANGLE) / (60 * 24);
+
+	gpath_rotate_to(&hand_path, hand_angle);
+	graphics_context_set_fill_color(ctx, GColorBlack);
+	gpath_draw_filled(ctx, &hand_path);
+	graphics_context_set_stroke_color(ctx, GColorWhite);
+	gpath_draw_outline(ctx, &hand_path);
+
+#if 0
+	const timezone_t * const tz = container_of(me, timezone_t, layer);
+
+	const int orig_hour = now.tm_hour;
+
+	now.tm_hour += tz->offset - gmt_offset;
+	if (now.tm_hour > 24)
+		now.tm_hour -= 24;
+	if (now.tm_hour < 0)
+		now.tm_hour += 24;
+
+	char buf[32];
+	string_format_time(
+		buf,
+		sizeof(buf),
+		"%H:%M",
+		&now
+	);
+
+
+	const int night_time = (now.tm_hour > 18 || now.tm_hour < 6);
+	now.tm_hour = orig_hour;
+
+	const int w = me->bounds.size.w;
+	const int h = me->bounds.size.h;
+		
+	// it is night there, draw in black video
+	graphics_context_set_fill_color(ctx, night_time ? GColorBlack : GColorWhite);
+	graphics_context_set_text_color(ctx, !night_time ? GColorBlack : GColorWhite);
+	graphics_fill_rect(ctx, GRect(0, 0, w, h), 0, 0);
+
+	graphics_text_draw(ctx,
+		tz->name,
+		font_thin,
+		GRect(0, 0, w, h/3),
+		GTextOverflowModeTrailingEllipsis,
+		GTextAlignmentCenter,
+		NULL
+	);
+
+	graphics_text_draw(ctx,
+		buf,
+		font_thick,
+		GRect(0, h/3, w, 2*h/3),
+		GTextOverflowModeTrailingEllipsis,
+		GTextAlignmentCenter,
+		NULL
+	);
+#endif
+}
+
+
+/** Called once per minute */
+static void
+handle_tick(
+	AppContextRef ctx,
+	PebbleTickEvent * const event
+)
+{
+	(void) ctx;
+
+	now = *event->tick_time;
+
+	layer_mark_dirty(&graphics_layer);
+}
+
+
+static void
+handle_init(
+	AppContextRef ctx
+)
+{
+	(void) ctx;
+	// Compute the points around the circle
+	for (int i = 0 ; i < NUM_POINTS ; i++)
+	{
+		const uint32_t angle = (i * TRIG_MAX_ANGLE) / NUM_POINTS;
+		const int s = sin_lookup(angle);
+		const int c = cos_lookup(angle);
+		circle_points[i].x = (W/2) + (R * s) / 0x10000;
+		circle_points[i].y = (H/2) - (R * c) / 0x10000;
+	}
+
+	gpath_init(&circle_path, &circle_info);
+
+	gpath_init(&hour_path, &hour_info);
+	gpath_move_to(&hour_path, GPoint(W/2,H/2));
+
+	gpath_init(&hand_path, &hand_info);
+	gpath_move_to(&hand_path, GPoint(W/2,H/2));
+
+	get_time(&now);
+
+	window_init(&window, "Main");
+	window_stack_push(&window, true);
+	window_set_background_color(&window, GColorBlack);
+
+	resource_init_current_app(&RESOURCES);
+
+	//font_thin = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_ARIAL_16));
+	font_thick = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_ARIAL_BLACK_30));
+
+	layer_init(&graphics_layer, GRect(0, 1, W, H));
+	layer_add_child(&window.layer, &graphics_layer);
+	graphics_layer.update_proc = graphics_layer_update;
+	layer_mark_dirty(&graphics_layer);
+}
+
+
+static void
+handle_deinit(
+	AppContextRef ctx
+)
+{
+	(void) ctx;
+
+	fonts_unload_custom_font(font_thin);
+	fonts_unload_custom_font(font_thick);
+}
+
+
+void
+pbl_main(
+	void * const params
+)
+{
+	PebbleAppHandlers handlers = {
+		.init_handler	= &handle_init,
+		.deinit_handler = &handle_deinit,
+		.tick_info	= {
+			.tick_handler = &handle_tick,
+			.tick_units = MINUTE_UNIT,
+		},
+	};
+
+	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.