From aff9e86ccc6d1182180564d8348e238fae54b86a Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Sun, 3 May 2026 21:37:41 -0400 Subject: [PATCH] Implement some crazy-ass logic to keep last watched text vertically centered (until it no longer makes sense to) --- src/c/main.c | 51 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/c/main.c b/src/c/main.c index 033886f..1ad6274 100644 --- a/src/c/main.c +++ b/src/c/main.c @@ -3,7 +3,7 @@ #include #include -// #define DEBUG_MODE 1 +#define DEBUG_MODE 2 // declare settings-derived statics static uint8_t s_is_jellyfin; @@ -31,6 +31,11 @@ static const uint8_t s_sleep_bar_drop = 49; #else static const uint8_t s_sleep_bar_drop = 31; #endif +#if PBL_DISPLAY_WIDTH >= 200 +#define LW_FONT_SIZE 28 +#else +#define LW_FONT_SIZE 24 +#endif // declare animation statics static GRect s_sleep_bar_start = GRect(0, 0, PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT); @@ -41,6 +46,33 @@ static time_t s_sleep_timestamp; static bool s_sleep_session_found; static bool s_sleep_data_accessible; +static const uint8_t s_wasted_top_text_pixels = 10; // 10 blank pixels above each line of text +static const uint8_t s_margin = PBL_DISPLAY_WIDTH / 35; +static const uint16_t s_available_height = PBL_DISPLAY_HEIGHT - s_sleep_bar_drop - s_margin + s_wasted_top_text_pixels; +// static const uint8_t s_max_rows = s_available_height / LW_FONT_SIZE; +static const uint16_t s_screen_center_y = PBL_DISPLAY_HEIGHT / 2; +static const uint16_t s_base_shift = s_screen_center_y - (LW_FONT_SIZE / 2) - (s_wasted_top_text_pixels / 2); // base - perfect if there is one row +static void write_last_watched(const char *text) { + text_layer_set_text(s_last_watched_layer, text); + + GSize text_size = text_layer_get_content_size(s_last_watched_layer); + uint8_t current_rows = text_size.h / LW_FONT_SIZE; + + // for each additional row beyond 1, shift up by half a row's height + uint16_t y = s_base_shift - ((current_rows - 1) * (LW_FONT_SIZE / 2)); + + // if the top extends above the sleep bar, force it below it + if (y < s_sleep_bar_drop) { + y = s_sleep_bar_drop - s_wasted_top_text_pixels + s_margin; + } + + layer_set_frame(text_layer_get_layer(s_last_watched_layer), GRect(PBL_IF_ROUND_ELSE(s_icon_width, 0) + s_margin, + y, + PBL_DISPLAY_WIDTH - (PBL_IF_ROUND_ELSE(s_icon_width * 2, s_icon_width) + (s_margin) * 2), + s_available_height)); + // APP_LOG(APP_LOG_LEVEL_DEBUG, "height=%d rows=%d/%d", text_size.h, current_rows, s_max_rows); +} + static bool cb_update_sleep_time(HealthActivity activity, time_t start_time, time_t end_time, void *context) { s_sleep_timestamp = start_time; return false; @@ -116,8 +148,7 @@ static void main_window_load(Window *window) { layer_set_update_proc(s_pin_icon_layer, pin_icon_update_proc); pin_animation_init(s_pin_icon_layer); - static const uint8_t side_margin = PBL_DISPLAY_WIDTH / 35; - s_last_watched_layer = text_layer_create(GRect(PBL_IF_ROUND_ELSE(s_icon_width, 0) + side_margin, s_sleep_bar_drop, PBL_DISPLAY_WIDTH - (PBL_IF_ROUND_ELSE(s_icon_width * 2, s_icon_width) + side_margin * 2), PBL_DISPLAY_HEIGHT - s_sleep_bar_drop)); + s_last_watched_layer = text_layer_create(GRect(0, 0, 0, 0)); // placeholder, updated when layer is written to #if PBL_DISPLAY_WIDTH >= 200 s_sleep_time_layer = text_layer_create(GRect(0, PBL_IF_ROUND_ELSE(21, -2), PBL_DISPLAY_WIDTH, 30)); text_layer_set_font(s_sleep_time_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD)); @@ -157,9 +188,9 @@ static void main_window_load(Window *window) { text_layer_set_text_color(s_last_watched_layer, GColorWhite); if (s_sleep_data_accessible) { - text_layer_set_text(s_last_watched_layer, "N/A"); // default - will be updated before display + write_last_watched("N/A"); // default - will be updated before display } else { - text_layer_set_text(s_last_watched_layer, "Sleep data inaccessible!\nEnsure Pebble Health is enabled."); + write_last_watched("Sleep data inaccessible!\nEnsure Pebble Health is enabled."); } // add layers as children to windows @@ -197,7 +228,7 @@ static void send_sleep_time_to_pkjs() { DictionaryIterator *out; AppMessageResult result = app_message_outbox_begin(&out); if (result != APP_MSG_OK) { - text_layer_set_text(s_last_watched_layer, "outbox_begin failure"); + write_last_watched("outbox_begin failure"); return; } if (s_sleep_session_found) { @@ -208,7 +239,7 @@ static void send_sleep_time_to_pkjs() { } result = app_message_outbox_send(); if (result != APP_MSG_OK) { - text_layer_set_text(s_last_watched_layer, "outbox_send failure"); + write_last_watched("outbox_send failure"); return; } } @@ -217,7 +248,7 @@ static void send_pin_to_pkjs() { DictionaryIterator *out; AppMessageResult result = app_message_outbox_begin(&out); if (result != APP_MSG_OK) { - text_layer_set_text(s_last_watched_layer, "outbox_begin failure"); + write_last_watched("outbox_begin failure"); return; } if (s_sleep_session_found) { @@ -228,7 +259,7 @@ static void send_pin_to_pkjs() { dict_write_cstring(out, MESSAGE_KEY_PKJS_PIN_TITLE, text_layer_get_text(s_last_watched_layer)); result = app_message_outbox_send(); if (result != APP_MSG_OK) { - text_layer_set_text(s_last_watched_layer, "outbox_send failure"); + write_last_watched("outbox_send failure"); return; } } @@ -295,7 +326,7 @@ static void inbox_received_handler(DictionaryIterator *iter, void *context) { Tuple *watched_tuple = dict_find(iter, MESSAGE_KEY_PKJS_LAST_WATCHED); if (watched_tuple) { - text_layer_set_text(s_last_watched_layer, watched_tuple->value->cstring); + write_last_watched(watched_tuple->value->cstring); PropertyAnimation *sleep_bar_prop = property_animation_create_layer_frame(s_sleep_bar_layer, &s_sleep_bar_start, &GRect(0, -PBL_DISPLAY_HEIGHT + s_sleep_bar_drop, PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT)); Animation *sleep_bar_anim = property_animation_get_animation(sleep_bar_prop); animation_set_duration(sleep_bar_anim, 512);