From f59fb3131e7a997cd1e0ed31a08189cefa1d9cac Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Tue, 10 Mar 2026 19:33:10 -0400 Subject: [PATCH] Add clock --- .clang-format | 7 ++ LICENSE | 2 +- package.json | 9 +++ src/c/main.c | 183 +++++++++++++++++++++++++---------------------- tools/clangd.zsh | 1 + 5 files changed, 116 insertions(+), 86 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..31aa732 --- /dev/null +++ b/.clang-format @@ -0,0 +1,7 @@ +--- +BasedOnStyle: LLVM +TabWidth: 4 +IndentWidth: 4 +UseTab: ForIndentation +ColumnLimit: 0 +... diff --git a/LICENSE b/LICENSE index e5ce0f3..aed522d 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ MIT License Copyright (c) 2026 hilariouspig -THIS LICENSE DOES NOT APPLY TO ANY ".png" FILES IN THIS REPOSITORY. +THIS LICENSE DOES NOT APPLY TO ANY ".png" NOR ".ttf" FILES IN THIS REPOSITORY. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/package.json b/package.json index a7cef15..cdd2890 100644 --- a/package.json +++ b/package.json @@ -537,6 +537,15 @@ "gabbro" ], "type": "bitmap" + }, + { + "file": "fonts/RetroComputer.ttf", + "name": "FONT_RETRO_COMPUTER_32", + "targetPlatforms": [ + "emery", + "gabbro" + ], + "type": "font" } ] }, diff --git a/src/c/main.c b/src/c/main.c index e2c0f1c..c07d720 100644 --- a/src/c/main.c +++ b/src/c/main.c @@ -1,8 +1,10 @@ -#include #include "palette_manip.h" +#include // declare general static pointers static Window *s_main_window; +static GFont custom_font; +static TextLayer *s_time_layer; static BitmapLayer *s_guy_head_layer; static BitmapLayer *s_guy_butt_layer; @@ -16,123 +18,134 @@ static GBitmap *s_butt_next; // declare lookup tables static const uint32_t randomHeadPool[] = { - RESOURCE_ID_H001, RESOURCE_ID_H002, RESOURCE_ID_H003, - RESOURCE_ID_H004, RESOURCE_ID_H005, RESOURCE_ID_H006, - RESOURCE_ID_H007, RESOURCE_ID_H008, RESOURCE_ID_H009, - RESOURCE_ID_H010, RESOURCE_ID_H011, RESOURCE_ID_H012, - RESOURCE_ID_H013, RESOURCE_ID_H014, RESOURCE_ID_H015, - RESOURCE_ID_H016, RESOURCE_ID_H017, RESOURCE_ID_H018, - RESOURCE_ID_H019, RESOURCE_ID_H020, RESOURCE_ID_H021, - RESOURCE_ID_H022 -}; + RESOURCE_ID_H001, RESOURCE_ID_H002, RESOURCE_ID_H003, RESOURCE_ID_H004, + RESOURCE_ID_H005, RESOURCE_ID_H006, RESOURCE_ID_H007, RESOURCE_ID_H008, + RESOURCE_ID_H009, RESOURCE_ID_H010, RESOURCE_ID_H011, RESOURCE_ID_H012, + RESOURCE_ID_H013, RESOURCE_ID_H014, RESOURCE_ID_H015, RESOURCE_ID_H016, + RESOURCE_ID_H017, RESOURCE_ID_H018, RESOURCE_ID_H019, RESOURCE_ID_H020, + RESOURCE_ID_H021, RESOURCE_ID_H022}; static const uint32_t randomButtPool[] = { - RESOURCE_ID_B001, RESOURCE_ID_B002, RESOURCE_ID_B003, - RESOURCE_ID_B004, RESOURCE_ID_B005, RESOURCE_ID_B006, - RESOURCE_ID_B007, RESOURCE_ID_B008, RESOURCE_ID_B009, - RESOURCE_ID_B010, RESOURCE_ID_B011, RESOURCE_ID_B012, - RESOURCE_ID_B013, RESOURCE_ID_B014, RESOURCE_ID_B015, - RESOURCE_ID_B016, RESOURCE_ID_B017, RESOURCE_ID_B018, - RESOURCE_ID_B019, RESOURCE_ID_B020, RESOURCE_ID_B021, - RESOURCE_ID_B022, RESOURCE_ID_XB001, RESOURCE_ID_XB002, - RESOURCE_ID_XB003, RESOURCE_ID_XB004 -}; + RESOURCE_ID_B001, RESOURCE_ID_B002, RESOURCE_ID_B003, RESOURCE_ID_B004, + RESOURCE_ID_B005, RESOURCE_ID_B006, RESOURCE_ID_B007, RESOURCE_ID_B008, + RESOURCE_ID_B009, RESOURCE_ID_B010, RESOURCE_ID_B011, RESOURCE_ID_B012, + RESOURCE_ID_B013, RESOURCE_ID_B014, RESOURCE_ID_B015, RESOURCE_ID_B016, + RESOURCE_ID_B017, RESOURCE_ID_B018, RESOURCE_ID_B019, RESOURCE_ID_B020, + RESOURCE_ID_B021, RESOURCE_ID_B022, RESOURCE_ID_XB001, RESOURCE_ID_XB002, + RESOURCE_ID_XB003, RESOURCE_ID_XB004}; static const GColor8 darkBGColorPool[] = { // Red - GColorFolly, - GColorRed, + GColorFolly, GColorRed, // Orange - GColorOrange, - GColorRajah, - GColorSunsetOrange, + GColorOrange, GColorRajah, GColorSunsetOrange, // Yellow - GColorChromeYellow, - GColorIcterine, - GColorPastelYellow, - GColorYellow, + GColorChromeYellow, GColorIcterine, GColorPastelYellow, GColorYellow, // Green - GColorInchworm, - GColorJaegerGreen, - GColorKellyGreen, - GColorMintGreen, + GColorInchworm, GColorJaegerGreen, GColorKellyGreen, GColorMintGreen, // Blue - GColorElectricBlue, - GColorTiffanyBlue, - GColorVividCerulean, + GColorElectricBlue, GColorTiffanyBlue, GColorVividCerulean, // Purple - GColorLavenderIndigo, - GColorPurpureus, - GColorRichBrilliantLavender, + GColorLavenderIndigo, GColorPurpureus, GColorRichBrilliantLavender, // Pink - GColorBrilliantRose, - GColorMelon, + GColorBrilliantRose, GColorMelon, // Brown - GColorRoseVale -}; + GColorRoseVale}; + +static void update_minute() { + // get a tm structure + time_t temp = time(NULL); + struct tm *tick_time = localtime(&temp); + + // write the current hours and minutes into a buffer + static char s_time_buffer[8]; + strftime(s_time_buffer, sizeof(s_time_buffer), clock_is_24h_style() ? "%H:%M" : "%I:%M", tick_time); + + // display this time on the TextLayer + text_layer_set_text(s_time_layer, s_time_buffer); +} + +static void minute_handler(struct tm *tick_time, TimeUnits units_changed) { + update_minute(); +} // define contents of the Window upon load static void main_window_load(Window *window) { - // format silly guy layers - s_guy_head_layer = bitmap_layer_create(GRect(PBL_IF_ROUND_ELSE(0, -30), PBL_IF_ROUND_ELSE(0, -16), 260, 115)); - s_guy_butt_layer = bitmap_layer_create(GRect(PBL_IF_ROUND_ELSE(0, -30), PBL_IF_ROUND_ELSE(145, 129), 260, 115)); - bitmap_layer_set_compositing_mode(s_guy_head_layer, GCompOpSet); - bitmap_layer_set_background_color(s_guy_head_layer, GColorBlack); - bitmap_layer_set_bitmap(s_guy_head_layer, s_head_current); - bitmap_layer_set_compositing_mode(s_guy_butt_layer, GCompOpSet); - bitmap_layer_set_background_color(s_guy_butt_layer, GColorBlack); - bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt_current); + Layer *window_layer = window_get_root_layer(window); - // add silly guy layers as children to window - Layer *window_layer = window_get_root_layer(window); - layer_add_child(window_layer, bitmap_layer_get_layer(s_guy_head_layer)); - layer_add_child(window_layer, bitmap_layer_get_layer(s_guy_butt_layer)); + // format silly guy layers + s_guy_head_layer = bitmap_layer_create(GRect(PBL_IF_ROUND_ELSE(0, -30), PBL_IF_ROUND_ELSE(0, -16), 260, 115)); + s_guy_butt_layer = bitmap_layer_create(GRect(PBL_IF_ROUND_ELSE(0, -30), PBL_IF_ROUND_ELSE(145, 129), 260, 115)); + bitmap_layer_set_background_color(s_guy_head_layer, GColorBlack); + bitmap_layer_set_bitmap(s_guy_head_layer, s_head_current); + bitmap_layer_set_background_color(s_guy_butt_layer, GColorBlack); + bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt_current); + + // set up info layers + s_time_layer = text_layer_create(GRect(0, PBL_IF_ROUND_ELSE(110, 94), PBL_IF_ROUND_ELSE(260, 200), 32)); + text_layer_set_background_color(s_time_layer, GColorClear); + text_layer_set_font(s_time_layer, custom_font); + text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter); + + // add layers as children to window + layer_add_child(window_layer, bitmap_layer_get_layer(s_guy_head_layer)); + layer_add_child(window_layer, bitmap_layer_get_layer(s_guy_butt_layer)); + layer_add_child(window_layer, text_layer_get_layer(s_time_layer)); } // free memory on Window close; // this means matching all "_create"'s from main_window_load with "_destroy" static void main_window_unload(Window *window) { - bitmap_layer_destroy(s_guy_head_layer); - bitmap_layer_destroy(s_guy_butt_layer); + bitmap_layer_destroy(s_guy_head_layer); + bitmap_layer_destroy(s_guy_butt_layer); + text_layer_destroy(s_time_layer); } // set up the app on launch (don't put app logic in here); static void init() { - // create main Window element and assign to pointer - s_main_window = window_create(); + // create main Window element and assign to pointer + s_main_window = window_create(); - // set handlers to manage the elements inside the Window - window_set_window_handlers(s_main_window, (WindowHandlers) { - .load = main_window_load, - .unload = main_window_unload - }); + // set handlers to manage the elements inside the Window + window_set_window_handlers(s_main_window, (WindowHandlers){ + .load = main_window_load, + .unload = main_window_unload}); - // load initial batch of silly guy parts into memory - s_head_current = gbitmap_create_with_resource(randomHeadPool[rand()%22]); - s_butt_current = gbitmap_create_with_resource(randomButtPool[rand()%26]); - s_head_next = gbitmap_create_with_resource(randomHeadPool[rand()%22]); - s_butt_next = gbitmap_create_with_resource(randomButtPool[rand()%26]); + // load initial batch of silly guy parts into memory + s_head_current = gbitmap_create_with_resource(randomHeadPool[rand() % 22]); + s_butt_current = gbitmap_create_with_resource(randomButtPool[rand() % 26]); + s_head_next = gbitmap_create_with_resource(randomHeadPool[rand() % 22]); + s_butt_next = gbitmap_create_with_resource(randomButtPool[rand() % 26]); - // pick starting colors - s_random_color_current = darkBGColorPool[rand()%22]; - s_random_color_next = darkBGColorPool[rand()%22]; - replace_gbitmap_color(GColorGreen, s_random_color_current, s_head_current, NULL); - replace_gbitmap_color(GColorGreen, s_random_color_current, s_butt_current, NULL); + // pick starting colors + s_random_color_current = darkBGColorPool[rand() % 22]; + s_random_color_next = darkBGColorPool[rand() % 22]; + replace_gbitmap_color(GColorGreen, s_random_color_current, s_head_current, NULL); + replace_gbitmap_color(GColorGreen, s_random_color_current, s_butt_current, NULL); - // show the Window on the watch, with animated=true - window_stack_push(s_main_window, true); + // load custom font + custom_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_RETRO_COMPUTER_32)); + + // show the Window on the watch, with animated=true + window_stack_push(s_main_window, true); + + // make sure the time is displayed from the start + update_minute(); + + // register with TickTimerService + tick_timer_service_subscribe(MINUTE_UNIT, minute_handler); } // free memory on app exit; // this means matching all "_create"'s from init() with "_destroy" static void deinit() { - gbitmap_destroy(s_head_current); - gbitmap_destroy(s_butt_current); - gbitmap_destroy(s_head_next); - gbitmap_destroy(s_butt_next); - window_destroy(s_main_window); + gbitmap_destroy(s_head_current); + gbitmap_destroy(s_butt_current); + gbitmap_destroy(s_head_next); + gbitmap_destroy(s_butt_next); + window_destroy(s_main_window); } int main(void) { - init(); - app_event_loop(); - deinit(); + init(); + app_event_loop(); + deinit(); } diff --git a/tools/clangd.zsh b/tools/clangd.zsh index e9d46bf..15c52fc 100755 --- a/tools/clangd.zsh +++ b/tools/clangd.zsh @@ -10,6 +10,7 @@ echo "CompileFlags: -I$(pwd)/build/emery, -include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/arm-none-eabi/include/stdint.h, -include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/arm-none-eabi/include/stdlib.h, + -include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/arm-none-eabi/include/time.h, -include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/lib/gcc/arm-none-eabi/14.2.1/include/stddef.h, -include${HOME}/.pebble-sdk/SDKs/current/toolchain/arm-none-eabi/lib/gcc/arm-none-eabi/14.2.1/include/stdbool.h, ]" > ./.clangd