Files
Maan-On-My-Wrist-XL/src/c/main.c
T
2026-03-10 22:04:47 -04:00

226 lines
8.9 KiB
C

#include "palette_manip.h"
#include <pebble.h>
// declare general statics
static Window *s_main_window;
static GFont s_custom_font;
static TextLayer *s_time_layer;
static TextLayer *s_date_layer;
static BitmapLayer *s_guy_head_layer;
static BitmapLayer *s_guy_butt_layer;
// declare silly guy parts
static GColor8 s_random_color_current;
static GColor8 s_random_color_next;
static GBitmap *s_head_current;
static GBitmap *s_butt_current;
static GBitmap *s_head_next;
static GBitmap *s_butt_next;
// declare lookup tables
static const uint8_t s_head_count = 22;
static const uint32_t s_random_heads[] = {
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 uint8_t s_butt_count = 26;
static const uint32_t s_random_butts[] = {
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 uint8_t s_color_count = 22;
static const GColor8 s_dark_bg_colors[] = {
// Red
GColorFolly, GColorRed,
// Orange
GColorOrange, GColorRajah, GColorSunsetOrange,
// Yellow
GColorChromeYellow, GColorIcterine, GColorPastelYellow, GColorYellow,
// Green
GColorInchworm, GColorJaegerGreen, GColorKellyGreen, GColorMintGreen,
// Blue
GColorElectricBlue, GColorTiffanyBlue, GColorVividCerulean,
// Purple
GColorLavenderIndigo, GColorPurpureus, GColorRichBrilliantLavender,
// Pink
GColorBrilliantRose, GColorMelon,
// Brown
GColorRoseVale};
static void update_minute_1() {
// get a tm structure
time_t temp = time(NULL);
struct tm *tick_time = localtime(&temp);
// write the current hours and minutes into a buffer & format
static char s_time_buffer[8];
strftime(s_time_buffer, sizeof(s_time_buffer), clock_is_24h_style() ? "%H:%M" : "%I:%M", tick_time);
// write the current date into a buffer & format
static char s_date_buffer[16];
strftime(s_date_buffer, sizeof(s_date_buffer), "%m/%d", tick_time);
text_layer_set_text(s_time_layer, s_time_buffer);
text_layer_set_text(s_date_layer, s_date_buffer);
}
static void update_minute_30() {
update_minute_1();
// update butt on half-hour boundaries
gbitmap_destroy(s_butt_current);
s_butt_current = s_butt_next;
replace_gbitmap_color(GColorGreen, s_random_color_next, s_butt_current, NULL);
replace_gbitmap_color(s_random_color_current, s_random_color_next, s_head_current, NULL);
// update current color so it can be referenced for later replacement
s_random_color_current = s_random_color_next;
bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt_current);
bitmap_layer_set_bitmap(s_guy_head_layer, s_head_current);
// calc next values
s_butt_next = gbitmap_create_with_resource(s_random_butts[rand() % s_butt_count]);
s_random_color_next = s_dark_bg_colors[rand() % s_color_count]; // next color
}
static void update_minute_60() {
update_minute_1();
// update head on hour boundaries
gbitmap_destroy(s_head_current);
s_head_current = s_head_next;
replace_gbitmap_color(GColorGreen, s_random_color_next, s_head_current, NULL);
replace_gbitmap_color(s_random_color_current, s_random_color_next, s_butt_current, NULL);
// update current color so it can be referenced for later replacement
s_random_color_current = s_random_color_next;
bitmap_layer_set_bitmap(s_guy_head_layer, s_head_current);
bitmap_layer_set_bitmap(s_guy_butt_layer, s_butt_current);
// calc next values
s_head_next = gbitmap_create_with_resource(s_random_heads[rand() % s_head_count]);
s_random_color_next = s_dark_bg_colors[rand() % s_color_count]; // next color
}
static void minute_handler(struct tm *tick_time, TimeUnits units_changed) {
if (tick_time->tm_min % 60 == 0) {
update_minute_60();
} else if (tick_time->tm_min % 30 == 0) {
update_minute_30();
} else {
update_minute_1();
}
}
// define contents of the Window upon load
static void main_window_load(Window *window) {
Layer *window_layer = window_get_root_layer(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_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);
// format time layer
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, s_custom_font);
text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);
// format date layer
s_date_layer = text_layer_create(GRect(PBL_IF_ROUND_ELSE(22, 8), PBL_IF_ROUND_ELSE(120, 104), PBL_IF_ROUND_ELSE(260, 200), 14));
text_layer_set_background_color(s_date_layer, GColorClear);
text_layer_set_font(s_date_layer, fonts_get_system_font(FONT_KEY_GOTHIC_14));
text_layer_set_text_alignment(s_date_layer, GTextAlignmentLeft);
// 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));
layer_add_child(window_layer, text_layer_get_layer(s_date_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);
text_layer_destroy(s_time_layer);
text_layer_destroy(s_date_layer);
fonts_unload_custom_font(s_custom_font);
}
static void up_single_click_handler(ClickRecognizerRef recognizer, void *context) {
Window *window = (Window *)context;
update_minute_60();
}
static void down_single_click_handler(ClickRecognizerRef recognizer, void *context) {
Window *window = (Window *)context;
update_minute_30();
}
static void click_config_provider(Window *window) {
window_single_click_subscribe(BUTTON_ID_UP, up_single_click_handler);
window_single_click_subscribe(BUTTON_ID_DOWN, down_single_click_handler);
}
// 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();
// 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(s_random_heads[rand() % s_head_count]);
s_butt_current = gbitmap_create_with_resource(s_random_butts[rand() % s_butt_count]);
s_head_next = gbitmap_create_with_resource(s_random_heads[rand() % s_head_count]);
s_butt_next = gbitmap_create_with_resource(s_random_butts[rand() % s_butt_count]);
// pick starting colors
s_random_color_current = s_dark_bg_colors[rand() % s_color_count];
replace_gbitmap_color(GColorGreen, s_random_color_current, s_head_current, NULL);
replace_gbitmap_color(GColorGreen, s_random_color_current, s_butt_current, NULL);
// don't overwrite current color, as it will need to be replaced
s_random_color_next = s_dark_bg_colors[rand() % s_color_count];
// load custom font
s_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_1();
// register with TickTimerService
tick_timer_service_subscribe(MINUTE_UNIT, minute_handler);
// register with ClickConfigProvider
window_set_click_config_provider(s_main_window, (ClickConfigProvider)click_config_provider);
}
// 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);
}
int main(void) {
init();
app_event_loop();
deinit();
}