Do you want to use C++ on the Pebble but sad that you can't? Well you're in luck! It's now possible! Continued from Pebble Development with C++ on the mind (Part 1).
All you have to do is alter the wscript file to enable proper compilation, actually. But if you want a proper API wrapper to the built-in Pebble one, you'll also want to add my pebble.cpp and pebble.h files to your src/ directory (and malloc.cpp unless you want to write your own allocator and deallocator).
I've put those files in my github pebble-cpp repository. What I recommend is that you checkout that repository next to your src/ folder, and then symlink to its wscript and the support files you want (pebble.cpp, pebble.h, and/or malloc.cpp). This is because I'll be periodically expanding on the API surface that is implemented, today I only wrap the 'classes' that the basic app uses (where the basic app is what Pebble's script gives you when you start an app).
The main entry point is the App class, that you pass your app's implementation into. Currently, all you need is window_load and window_unload, but you can also set a click_config_provider and subscribe to clicks. In those click handlers, since you're now a class, you can access your class's member attributes. In the example program, I matched Pebble's and created a CPPTextLayer on window_load. However, since in the example program the text layer is made after window_load, even though its creation doesn't depend on a window since you can resize it any time, I went with a pointer. To exercise C++'s smart pointers, I used a unique_ptr to ensure I'm not messing with raw pointers, even though I call release() in window_unload. One benefit is that I know whenever app_event_loop() exits and my app is destroyed, the text layer's destructor is called and my app will exit cleanly.
Pebble's libraries require 'plain' C function pointers in many cases, so passing in a member method won't work at all. Initially, I played with std::function and friends, but passing in a function from the heap caused all sorts of unhelpful compiler functions. My attempts to switch to clang weren't working either, so I have to live with gcc's awful errors. After leaving it alone for a while, I came back recently with the idea of using templates to have the compiler generate the necessary 'plain' C functions at compile-time. This works by creating a templated static method in App that has the necessary signature, but takes as a template argument the actual method to call on the PebbleApp. Along with a static instance of the PebbleApp, that static method can then call back into PebbleApp's instance method. Essentially, a function is created by the compiler that calls the proper method on the PebbleApp instance, as if it were std::bind'd together.
If you want a new set of functions wrapped, feel free to add it to the Issues list on the github. The currently wrapped classes are listed below:
- CPPWindow is for the Window struct and any functions that start with window_, such as window_create() and window_set_window_handlers().
- CPPLayer is for the 'base-class' Layer and functions starting with layer_, such as layer_destroy, layer_add_child, and layer_get_bounds.
- CPPTextLayer is a subclass of CPPLayer that wraps a TextLayer (which has a Layer instance inside it, or something like that, Pebble doesn't want you to know that TextLayer is really just a Layer with extra fields afterward, since text_layer_get_layer just returns the same pointer, just casted to a Layer struct). This wraps text_layer_* functions, like text_layer_create, text_layer_set_text, and text_layer_set_text_alignment.
- App holds a newly-created root window (a CPPWindow object) and proxies all the C API calls that require a function pointer to your app's methods. You can have member attributes and access them in all the functions you want, like you click handlers and window load/unload handlers. Instead of having static globals like "static TextLayer *text_layer;" in the Pebble basic application, you can have a "CPPTextLayer text_layer_;" member attribute.