Giter Site home page Giter Site logo

enamel's Introduction

Enamel Build Status MIT License

Enamel is a python script that generates C helpers from a Clay configuration file to easily get the value of your settings.

Enamel will :

  • handle AppMessages automatically (app_message_open, handler registration, ...)
  • save/load the value of the settings in the persistant storage automatically
  • provide a getter for each of your settings
  • notify subscribers when settings are received from Clay

You can focus on your watchapp/face, Enamel will do the rest !


Getting Started (SDK 3.13+)

  1. You project must contain a valid configuration file in src/js/config.json (see https://github.com/pebble/clay)
  2. Install enamel with pebble package install enamel
  3. Copy and paste the following line into the top of your wscript :
import sys
sys.path.append('node_modules')
from enamel.enamel import enamel
  1. Change the build of your wscript from
ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c'), target=app_elf)

to

ctx(rule = enamel, source='src/js/config.json', target=['enamel.c', 'enamel.h'])
ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c') + ['enamel.c'], target=app_elf)
  1. Launch your Pebble build : 2 files (enamel.c and enamel.h) should be generated in build and compiled

⚠️
The first time you launch a build, you will get an error message because Jinja2 module is missing.
Just follow the instructions to fix your environment.

Getting Started (CloudPebble)

In the CloudPebble environment, you can't modify the wscript so you need to call directly the python script.

  1. Under Dependencies in the project navigation, enter enamel as the Package Name and ^1.0.0 for the Version. You may use any specific version you like, however using ^1.0.0 will ensure you receive all minor version updates.

  2. Copy the content of your Clay's config.js file into a local file (local_config.js)

  3. Install the python dependencies for the code generation

pip install -r requirements.txt
  1. Call the script to generate the enamel files
python enamel.py --config /path/to/local_config.js 
  1. Copy the 2 generated files in your CloudPebble project

Using Enamel

  1. Setup your project correctly for Clay : https://github.com/pebble/clay
  2. Include enamel.h in your c file :
#include "enamel.h"
#include <pebble-events/pebble-events.h>
  1. Initialize enamel in your init function and call events_app_message_open() after any other libraries you need to init.
static void init(void) {
  // Initialize Enamel to register App Message handlers and restores settings
  enamel_init();
  
  // call pebble-events app_message_open function
  events_app_message_open(); 
  
  ...
}
  1. Deinitialize enamel in your deinit function :
static void deinit(void) {
  ...

  // Deinit Enamel to unregister App Message handlers and save settings
  enamel_deinit();
}
  1. (Optional) Subscribe with a handler after enamel_init that will be automatically called when the settings are received. Multiple subscribers are supported. Do not forget to unsubscribe before calling enamel_deinit!
static EventHandle s_window_event_handle;
static EventHandle s_text_layer_event_handle;

...

static void enamel_settings_received_window_handler(void *context){
  APP_LOG(0, "Settings received %d", enamel_get_myinteger());
  Window *window = (Window *) context;
  window_set_background_color(window, enamel_get_background());
}

static void enamel_settings_received_text_layer_handler(void *context){
  APP_LOG(0, "Settings received %d", enamel_get_myinteger());
  TextLayer *text_layer = (TextLayer *) context;
  text_layer_set_text_color(text_layer, enamel_get_foreground());
}

...

static void init(void) {
  // Initialize Enamel to register App Message handlers and restores settings
  enamel_init();

  // Subscribe a handler for a window
  s_window_event_handle = enamel_settings_received_subscribe(enamel_settings_received_window_handler, window);

  // Subscribe a handler for a text layer
  s_text_layer_event_handle = enamel_settings_received_subscribe(enamel_settings_received_text_layer_handler, text_layer);
  
  // call pebble-events app_message_open function
  events_app_message_open(); 
  
  ...
}

static void deinit(void) {
    // Unsubscribe from Enamel events
    enamel_settings_received_unsubscribe(s_window_event_handle);
    enamel_settings_received_unsubscribe(s_text_layer_event_handle);

    enamel_deinit();

    ...
}
  1. Get the value of your setting with :
enamel_get_Mysetting(); // where 'Mysetting' is a messageKey in your configuration file

Enamel API

Methods

Method Description
void enamel_init() Initialize Enamel and read settings from persistant storage
void enamel_deinit() Deinitialize Enamel and save the settings in the persistant storage
<type> enamel_get_<messageKeyId>() Return the value for the setting messageKeyId
bool enamel_get_<messageKeyId>(uint16_t index_) Only relevant for checkboxgroup.
Return the value at given index for the setting messageKeyId

Type mapping

Clay Type Type returned by the getter
input char*
toggle bool
color GColor
select/radiogroup char* or enum
checkboxgroup bool
slider int32_t

Special case for select, radiogroup

If the value of the options are string in the config.json, Enamel will generate a char* getter

If the value of the options are integer, Enamel will generate an enum mapping all the possible values for this setting and the getter will return this enum

For the given setting :

{
  "type": "radiogroup",
  "messageKey": "favorite_food",
  "label": "Favorite Food",
  "defaultValue": "1",
  "options": [
    { 
      "label": "Sushi", 
      "value": 0 
    },
    { 
      "label": "Pizza", 
      "value": 1 
    },
    { 
      "label": "Burgers", 
      "value": 2 
    }
  ]
}

Enamel will generate

typedef enum {
	FAVORITE_FOOD_SUSHI = 0,
	FAVORITE_FOOD_PIZZA = 1,
	FAVORITE_FOOD_BURGER = 2,
} FAVORITE_FOODValue;
FAVORITE_FOODValue enamel_get_favorite_food();

You can then easily code switch case for this setting

switch(enamel_get_favorite_food()){
 case FAVORITE_FOOD_SUSHI : break; //do something
 case FAVORITE_FOOD_PIZZA : break; //do something
 case FAVORITE_FOOD_BURGER : break; //do something
}

Special case for slider

Enamel will also generate a constant for your slider containing the 'precision' of your slider, e.g.

#define MY_SLIDER_PRECISION 100

enamel's People

Contributors

gregoiresage avatar yag00 avatar dmorgan81 avatar keegan-lillo avatar

Stargazers

Laszlo Boros avatar Andy Burris avatar Anton Chekulaev avatar Mari Okada avatar Rajendra avatar Nathan Winant avatar  avatar Fabio Barbon avatar Andrei Popovici avatar Michael Phillips avatar Ish Ot Jr. avatar JR Mobley avatar Morris avatar Matthew Tole avatar  avatar André Lochotzke avatar Ben Combee avatar Thomas Hunsaker avatar Turner Vink avatar

Watchers

Rajendra avatar  avatar James Cloos avatar Ish Ot Jr. avatar  avatar  avatar Mari Okada avatar

enamel's Issues

SDK 4.0: Data not persisting

When I compile under 3.14 my data properly persits. But once I upgraded to the new 4.0 Pebble SDK everything is set to the default values, every time I run the app. I put some logging into the generated enamel.c and "if(persist_exists(ENAMEL_PKEY) && persist_exists(ENAMEL_DICT_PKEY))" in the init function never evaluates true.

Improve generated code

Currently, generated code works but the indentation is ugly.

I will try to fix that even if people don't have to read the code ;-p

Number Keyboard

On iOS (maybe android too), when clicking in the number field for the slider, the default keyboard appears instead of a number keyboard.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.