From 1e9c24262b1771b928e885b0290e5cb0ebac5f5c Mon Sep 17 00:00:00 2001 From: Warwick New Date: Thu, 25 Jun 2026 11:50:31 +0100 Subject: [PATCH] Initial commit --- .gitignore | 5 +++ README.md | 36 +++++++++++++++++++ package-lock.json | 21 +++++++++++ package.json | 36 +++++++++++++++++++ src/c/eatordonteat.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ src/pkjs/config.json | 10 ++++++ wscript | 54 ++++++++++++++++++++++++++++ 7 files changed, 248 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/c/eatordonteat.c create mode 100644 src/pkjs/config.json create mode 100644 wscript diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..67ae351 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build/ +compile_commands.json +.lock* +node_modules/ +.cache/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..eaea1c0 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# eatordonteat + +A Pebble watchapp/watchface written in C using the Pebble SDK. + +## Building & running + +```sh +pebble build # build for all targetPlatforms +pebble install --emulator emery # install on the emery emulator +pebble install --phone # install to a paired phone +``` + +## Target platforms + +`targetPlatforms` in `package.json` controls which watches you build for. The +modern Pebble hardware is **emery** (Pebble Time 2), **gabbro** (Pebble Round +2), and **flint** (Pebble 2 Duo); the original Pebble platforms (aplite, +basalt, chalk, diorite) are included by default for backwards compatibility. + +## Project layout + +``` +src/c/ C source for the watchapp +src/pkjs/ PebbleKit JS (phone-side) source, if any +worker_src/c/ Background worker source, if any +resources/ Images, fonts, and other bundled resources +package.json Project metadata (UUID, platforms, resources, message keys) +wscript Build rules — usually no need to edit +``` + +By default this project is configured as a watchapp. To make it a watchface, +set `pebble.watchapp.watchface` to `true` in `package.json`. + +## Documentation + +Full SDK docs, tutorials, and API reference: diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..480e25a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "eatordonteat", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "eatordonteat", + "version": "1.0.0", + "dependencies": { + "@rebble/clay": "^1.0.10" + } + }, + "node_modules/@rebble/clay": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@rebble/clay/-/clay-1.0.10.tgz", + "integrity": "sha512-84EL9J6egrnWk/FzqCxRa9/vqO4fx7SBxdttthLEpBro+FVqUg+rMlqOzT8+zl4PkBQKAWdnqHwlHaS4heiXKg==", + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..2249e22 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "eatordonteat", + "author": "MakeAwesomeHappen", + "version": "1.0.0", + "keywords": [ + "pebble-app" + ], + "private": true, + "dependencies": { + "@rebble/clay": "^1.0.10" + }, + "pebble": { + "displayName": "Eat / Don't Eat watchface", + "uuid": "34fbfd25-b227-49fd-9c90-7f71b9731131", + "sdkVersion": "3", + "enableMultiJS": true, + "targetPlatforms": [ + "aplite", + "basalt", + "chalk", + "diorite", + "emery", + "flint", + "gabbro" + ], + "watchapp": { + "watchface": true + }, + "messageKeys": [ + "dummy" + ], + "resources": { + "media": [] + } + } +} diff --git a/src/c/eatordonteat.c b/src/c/eatordonteat.c new file mode 100644 index 0000000..dca05ba --- /dev/null +++ b/src/c/eatordonteat.c @@ -0,0 +1,86 @@ +#include + +static Window *s_main_window; +static TextLayer *s_time_layer; +static TextLayer *s_date_layer; + +static void update_time() { + // 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); + + // Write the current date into a buffer + static char s_date_buffer[16]; + strftime(s_date_buffer, sizeof(s_date_buffer), "%a %b %d", tick_time); + + // Display the date + text_layer_set_text(s_date_layer, s_date_buffer); +} + +static void tick_handler(struct tm *tick_time, TimeUnits units_changed) { + update_time(); +} + +static void main_window_load(Window *window) { + Layer *window_layer = window_get_root_layer(window); + GRect bounds = layer_get_bounds(window_layer); + + // Create the time TextLayer + s_time_layer = + text_layer_create(GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50)); + text_layer_set_background_color(s_time_layer, GColorClear); + text_layer_set_text_color(s_time_layer, GColorWhite); + text_layer_set_font(s_time_layer, + fonts_get_system_font(FONT_KEY_BITHAM_42_BOLD)); + text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter); + + // Add it as a child layer to the Window's root layer + layer_add_child(window_layer, text_layer_get_layer(s_time_layer)); + + // Create the date TextLayer + s_date_layer = text_layer_create( + GRect(0, PBL_IF_ROUND_ELSE(110, 104), bounds.size.w, 30)); + text_layer_set_background_color(s_date_layer, GColorClear); + text_layer_set_text_color(s_date_layer, GColorWhite); + text_layer_set_font(s_date_layer, + fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD)); + text_layer_set_text_alignment(s_date_layer, GTextAlignmentCenter); + + // Add to Window + layer_add_child(window_layer, text_layer_get_layer(s_date_layer)); +} + +static void main_window_unload(Window *window) { + text_layer_destroy(s_date_layer); + text_layer_destroy(s_time_layer); +} + +static void init() { + s_main_window = window_create(); + window_set_background_color(s_main_window, GColorBlack); + + window_set_window_handlers( + s_main_window, + (WindowHandlers){.load = main_window_load, .unload = main_window_unload}); + + window_stack_push(s_main_window, true); + + update_time(); + tick_timer_service_subscribe(MINUTE_UNIT, tick_handler); +} + +static void deinit() { window_destroy(s_main_window); } + +int main(void) { + init(); + app_event_loop(); + deinit(); +} diff --git a/src/pkjs/config.json b/src/pkjs/config.json new file mode 100644 index 0000000..756d2ea --- /dev/null +++ b/src/pkjs/config.json @@ -0,0 +1,10 @@ +[ + { + "type": "heading", + "defaultValue": "Example Header Item" + }, + { + "type": "text", + "defaultValue": "Example text item." + } +] diff --git a/wscript b/wscript new file mode 100644 index 0000000..5238bc8 --- /dev/null +++ b/wscript @@ -0,0 +1,54 @@ +# +# This file is the default set of rules to compile a Pebble application. +# +# Feel free to customize this to your needs. +# +import os.path + +top = '.' +out = 'build' + + +def options(ctx): + ctx.load('pebble_sdk') + + +def configure(ctx): + """ + This method is used to configure your build. ctx.load(`pebble_sdk`) automatically configures + a build for each valid platform in `targetPlatforms`. Platform-specific configuration: add your + change after calling ctx.load('pebble_sdk') and make sure to set the correct environment first. + Universal configuration: add your change prior to calling ctx.load('pebble_sdk'). + """ + ctx.load('pebble_sdk') + + +def build(ctx): + ctx.load('pebble_sdk') + + build_worker = os.path.exists('worker_src') + binaries = [] + + cached_env = ctx.env + for platform in ctx.env.TARGET_PLATFORMS: + ctx.env = ctx.all_envs[platform] + ctx.set_group(ctx.env.PLATFORM_NAME) + app_elf = '{}/pebble-app.elf'.format(ctx.env.BUILD_DIR) + ctx.pbl_build(source=ctx.path.ant_glob('src/c/**/*.c'), target=app_elf, bin_type='app') + + if build_worker: + worker_elf = '{}/pebble-worker.elf'.format(ctx.env.BUILD_DIR) + binaries.append({'platform': platform, 'app_elf': app_elf, 'worker_elf': worker_elf}) + ctx.pbl_build(source=ctx.path.ant_glob('worker_src/c/**/*.c'), + target=worker_elf, + bin_type='worker') + else: + binaries.append({'platform': platform, 'app_elf': app_elf}) + ctx.env = cached_env + + ctx.set_group('bundle') + ctx.pbl_bundle(binaries=binaries, + js=ctx.path.ant_glob(['src/pkjs/**/*.js', + 'src/pkjs/**/*.json', + 'src/common/**/*.js']), + js_entry_file='src/pkjs/index.js')