From bca4d7d3f5157dac5f1b9bd81902cacae3909056 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Wed, 15 Jul 2026 23:08:44 -0400 Subject: [PATCH] Initial code commit --- .clang-format | 7 +++ .gitignore | 5 ++ README.md | 4 +- clangd.zsh | 20 ++++++++ package.json | 24 ++++++++++ src/c/neat_bar.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++ src/c/neat_bar.h | 26 ++++++++++ wscript | 48 +++++++++++++++++++ 8 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100755 clangd.zsh create mode 100644 package.json create mode 100644 src/c/neat_bar.c create mode 100644 src/c/neat_bar.h create mode 100644 wscript 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/.gitignore b/.gitignore new file mode 100644 index 0000000..eaf2f4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/build +/.clangd +/.lock-waf* +/package-lock.json +/node_modules diff --git a/README.md b/README.md index 28000b3..63baedd 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# neat_bar +# neat_bar (WIP - DO NOT USE YET) -Customizable replacement for the built-in Pebble action bar. \ No newline at end of file +Customizable replacement for the built-in Pebble action bar. diff --git a/clangd.zsh b/clangd.zsh new file mode 100755 index 0000000..10a19d6 --- /dev/null +++ b/clangd.zsh @@ -0,0 +1,20 @@ +#!/usr/bin/env zsh +echo "CompileFlags: + Add: + [ + -DPBL_DISPLAY_WIDTH=200, + -DPBL_DISPLAY_HEIGHT=228, + -xc, + -nostdinc, + -DPBL_COLOR, + -DPBL_RECT, + -I${HOME}/.pebble-sdk/SDKs/current/sdk-core/pebble/emery/include, + -include$(pwd)/build/include/message_keys.auto.h, + -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/arm-none-eabi/include/string.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 diff --git a/package.json b/package.json new file mode 100644 index 0000000..e7e43c8 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "neat_bar", + "author": "RandyTheSilly", + "version": "1.0.0", + "files": ["dist.zip"], + "keywords": ["pebble-package"], + "dependencies": {}, + "pebble": { + "projectType": "package", + "sdkVersion": "3", + "targetPlatforms": [ + "aplite", + "basalt", + "chalk", + "diorite", + "emery", + "flint", + "gabbro" + ], + "resources": { + "media": [] + } + } +} diff --git a/src/c/neat_bar.c b/src/c/neat_bar.c new file mode 100644 index 0000000..01322c1 --- /dev/null +++ b/src/c/neat_bar.c @@ -0,0 +1,120 @@ +/* SPDX-FileCopyrightText: 2024 Google LLC */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "neat_bar.h" +#include + +#if PBL_PLATFORM_EMERY +const uint16_t UP_Y = 45; +const uint16_t SELECT_Y = 105; +const uint16_t DOWN_Y = 165; +#else +const uint16_t UP_Y = 50; +const uint16_t SELECT_Y = 90; +const uint16_t DOWN_Y = 120; +#endif + +static NeatBarLayer *s_current_neat_bar = NULL; + +static void s_up_down_handler(ClickRecognizerRef recognizer, void *context) {} +static void s_up_up_handler(ClickRecognizerRef recognizer, void *context) {} +static void s_down_down_handler(ClickRecognizerRef recognizer, void *context) {} +static void s_down_up_handler(ClickRecognizerRef recognizer, void *context) {} +static void s_select_down_handler(ClickRecognizerRef recognizer, void *context) {} +static void s_select_up_handler(ClickRecognizerRef recognizer, void *context) {} + +static void s_main_layer_update_proc(Layer *layer, GContext *ctx) { + graphics_context_set_fill_color(ctx, s_current_neat_bar->background_color); + graphics_fill_rect(ctx, layer_get_bounds(layer), 0, GCornerNone); // TODO enable legacy corners +} + +static void s_base_click_config_provider(void *config_context) { + NeatBarLayer *neat_bar = config_context; + void *context = neat_bar->context ? neat_bar->context : neat_bar; + window_raw_click_subscribe(BUTTON_ID_UP, s_up_down_handler, s_up_up_handler, neat_bar); + window_raw_click_subscribe(BUTTON_ID_DOWN, s_down_down_handler, s_down_up_handler, neat_bar); + window_raw_click_subscribe(BUTTON_ID_SELECT, s_select_down_handler, s_select_up_handler, neat_bar); + window_set_click_context(BUTTON_ID_UP, context); + window_set_click_context(BUTTON_ID_DOWN, context); + window_set_click_context(BUTTON_ID_SELECT, context); + if (neat_bar->click_config_provider) { + neat_bar->click_config_provider(context); + } +} + +inline static void s_update_click_config_provider(NeatBarLayer *neat_bar) { + if (neat_bar->window) { + window_set_click_config_provider_with_context(neat_bar->window, s_base_click_config_provider, neat_bar); + } +} + +void neat_bar_layer_add_to_window(NeatBarLayer *neat_bar, Window *window) { + layer_add_child(window_get_root_layer(window), neat_bar->main_layer); + neat_bar->window = window; + s_update_click_config_provider(neat_bar); +} + +void neat_bar_layer_set_click_config_provider(NeatBarLayer *neat_bar, ClickConfigProvider click_config_provider) { + neat_bar->click_config_provider = click_config_provider; + s_update_click_config_provider(neat_bar); +} + +void neat_bar_layer_set_background_color(NeatBarLayer *neat_bar, GColor background_color) { + if (gcolor_equal(background_color, neat_bar->background_color)) { + return; + } + neat_bar->background_color = background_color; + layer_mark_dirty(neat_bar->main_layer); +} + +void neat_bar_layer_set_icon(NeatBarLayer *neat_bar, ButtonId button_id, GBitmap *icon) { + BitmapLayer *current_bitmap_layer; + uint16_t y_pos; + + switch (button_id) { + case BUTTON_ID_UP: + current_bitmap_layer = neat_bar->up_layer; + y_pos = UP_Y; + break; + case BUTTON_ID_DOWN: + current_bitmap_layer = neat_bar->down_layer; + y_pos = DOWN_Y; + break; + default: + current_bitmap_layer = neat_bar->select_layer; + y_pos = SELECT_Y; + } + + if (!current_bitmap_layer) { + current_bitmap_layer = bitmap_layer_create(GRect(1, y_pos, ACTION_BAR_WIDTH, 18)); + layer_add_child(neat_bar->main_layer, bitmap_layer_get_layer(current_bitmap_layer)); + switch (button_id) { + case BUTTON_ID_UP: + neat_bar->up_layer = current_bitmap_layer; + break; + case BUTTON_ID_DOWN: + neat_bar->down_layer = current_bitmap_layer; + break; + default: + neat_bar->select_layer = current_bitmap_layer; + break; + } + } + bitmap_layer_set_alignment(current_bitmap_layer, GAlignCenter); + bitmap_layer_set_bitmap(current_bitmap_layer, icon); + bitmap_layer_set_compositing_mode(current_bitmap_layer, GCompOpSet); +} + +NeatBarLayer *neat_bar_layer_create() { + NeatBarLayer *neat_bar = malloc(sizeof(NeatBarLayer)); + neat_bar->main_layer = layer_create(GRect(PBL_DISPLAY_WIDTH - ACTION_BAR_WIDTH, 0, ACTION_BAR_WIDTH, PBL_DISPLAY_HEIGHT)); + neat_bar->up_layer = NULL; + neat_bar->down_layer = NULL; + neat_bar->select_layer = NULL; + neat_bar->click_config_provider = NULL; + neat_bar->background_color = GColorBlack; + neat_bar->context = NULL; + layer_set_update_proc(neat_bar->main_layer, s_main_layer_update_proc); + s_current_neat_bar = neat_bar; + return neat_bar; +} diff --git a/src/c/neat_bar.h b/src/c/neat_bar.h new file mode 100644 index 0000000..2909cb0 --- /dev/null +++ b/src/c/neat_bar.h @@ -0,0 +1,26 @@ +/* SPDX-FileCopyrightText: 2024 Google LLC */ +/* SPDX-License-Identifier: Apache-2.0 */ + +#pragma once + +#include + +typedef struct { + struct Window *window; + Layer *main_layer; + BitmapLayer *up_layer; + BitmapLayer *down_layer; + BitmapLayer *select_layer; + ClickConfigProvider click_config_provider; + GColor8 background_color; + //int8_t spread; // positive integers push the icons further apart; negative integers pull them together + //uint8_t animation_type; // 0 = press, 1 = invert + //uint8_t shape; // 0 = rect/round, 1 = rect/rect, 2 = rect/round (legacy), 3 = rect/rect (legacy) + void *context; +} NeatBarLayer; + +NeatBarLayer *neat_bar_layer_create(); +void neat_bar_layer_set_icon(NeatBarLayer *layer, ButtonId button_id, GBitmap *icon); +void neat_bar_layer_set_background_color(NeatBarLayer *neat_bar, GColor background_color); +void neat_bar_layer_set_click_config_provider(NeatBarLayer *neat_bar, ClickConfigProvider click_config_provider); +void neat_bar_layer_add_to_window(NeatBarLayer *neat_bar, Window *window); diff --git a/wscript b/wscript new file mode 100644 index 0000000..f5f986e --- /dev/null +++ b/wscript @@ -0,0 +1,48 @@ +# +# This file is the default set of rules to compile a Pebble project. +# +# Feel free to customize this to your needs. +# +import os +import shutil +import waflib + +top = '.' +out = 'build' + + +def distclean(ctx): + if os.path.exists('dist.zip'): + os.remove('dist.zip') + if os.path.exists('dist'): + shutil.rmtree('dist') + waflib.Scripting.distclean(ctx) + + +def options(ctx): + ctx.load('pebble_sdk_lib') + + +def configure(ctx): + ctx.load('pebble_sdk_lib') + + +def build(ctx): + ctx.load('pebble_sdk_lib') + + cached_env = ctx.env + for platform in ctx.env.TARGET_PLATFORMS: + ctx.env = ctx.all_envs[platform] + ctx.set_group(ctx.env.PLATFORM_NAME) + lib_name = '{}/{}'.format(ctx.env.BUILD_DIR, ctx.env.PROJECT_INFO['name']) + ctx.pbl_build(source=ctx.path.ant_glob('src/c/**/*.c'), target=lib_name, bin_type='lib') + ctx.env = cached_env + + ctx.set_group('bundle') + ctx.pbl_bundle(includes=ctx.path.ant_glob('include/**/*.h'), + js=ctx.path.ant_glob(['src/js/**/*.js', 'src/js/**/*.json']), + bin_type='lib') + + if ctx.cmd == 'clean': + for n in ctx.path.ant_glob(['dist/**/*', 'dist.zip'], quiet=True): + n.delete()