├── .gitignore ├── LICENSE ├── README.md ├── examples ├── basics_cpp │ ├── basics.cpp │ ├── malloc.cpp │ ├── pebble.cpp │ ├── pebble.h │ └── wscript └── feature_image_cpp │ ├── appinfo.json │ ├── graphics │ └── no_litter.svg │ ├── resources │ └── images │ │ └── no_litter.png │ └── src │ ├── feature_image.cpp │ ├── malloc.cpp │ ├── pebble.cpp │ ├── pebble.h │ └── wscript └── src ├── malloc.cpp ├── pebble.cpp ├── pebble.h └── wscript /.gitignore: -------------------------------------------------------------------------------- 1 | .lock-waf_darwin_build 2 | 3 | # Ignore build generated files 4 | build/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Fahrzin Hemmati 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Pebble-CPP 2 | ========== 3 | 4 | Pebble, but with C++! This is a C++ wrapper for the original Pebble SDK. 5 | 6 | ## Currently Wrapped Classes 7 | 8 | - App 9 | - CPPWindow 10 | - CPPLayer 11 | - CPPTextLayer 12 | - CPPBitmapLayer 13 | 14 | ## Setup 15 | 16 | You must have the [Pebble SDK](http://developer.getpebble.com/sdk/) installed to use this library. 17 | 18 | Include the following in your `src\` folder: 19 | 20 | - `pebble.h` 21 | - `pebble.cpp` 22 | - `malloc.cpp` 23 | 24 | ## License 25 | 26 | You can check out the full license [here](https://github.com/fahhem/pebble-cpp/blob/master/LICENSE) 27 | 28 | This project is licensed under the terms of the **MIT** license. 29 | -------------------------------------------------------------------------------- /examples/basics_cpp/basics.cpp: -------------------------------------------------------------------------------- 1 | #include "pebble.h" 2 | 3 | class PebbleApp { 4 | public: 5 | void window_load(Window *window) { 6 | CPPWindow root_window(window); 7 | root_window.set_click_config_provider( 8 | (ClickConfigProvider)&App::click_config_provider); 9 | 10 | CPPLayer window_layer(root_window.get_root_layer()); 11 | auto bounds = window_layer.get_bounds(); 12 | title_layer.reset(new CPPTextLayer(0, 72, bounds.size.w, 20)); 13 | title_layer->set_text("Press a button"); 14 | title_layer->set_text_alignment(GTextAlignmentCenter); 15 | window_layer.add_child(*title_layer); 16 | } 17 | 18 | void window_unload(Window *window) { 19 | title_layer.release(); 20 | } 21 | 22 | void click_config_provider(void *ctx) { 23 | CPPWindow::single_click_subscribe< 24 | PebbleApp, &PebbleApp::select_click_handler>(BUTTON_ID_SELECT); 25 | CPPWindow::single_click_subscribe< 26 | PebbleApp, &PebbleApp::up_click_handler>(BUTTON_ID_UP); 27 | CPPWindow::single_click_subscribe< 28 | PebbleApp, &PebbleApp::down_click_handler>(BUTTON_ID_DOWN); 29 | } 30 | 31 | void select_click_handler(ClickRecognizerRef rec) { 32 | title_layer->set_text("Select"); 33 | } 34 | 35 | void up_click_handler(ClickRecognizerRef rec) { 36 | title_layer->set_text("Up"); 37 | } 38 | 39 | void down_click_handler(ClickRecognizerRef rec) { 40 | title_layer->set_text("Down"); 41 | } 42 | 43 | private: 44 | std::unique_ptr title_layer; 45 | }; 46 | 47 | extern "C" int main(void) { 48 | App app; 49 | app_event_loop(); 50 | } 51 | -------------------------------------------------------------------------------- /examples/basics_cpp/malloc.cpp: -------------------------------------------------------------------------------- 1 | ../../src/malloc.cpp -------------------------------------------------------------------------------- /examples/basics_cpp/pebble.cpp: -------------------------------------------------------------------------------- 1 | ../../src/pebble.cpp -------------------------------------------------------------------------------- /examples/basics_cpp/pebble.h: -------------------------------------------------------------------------------- 1 | ../../src/pebble.h -------------------------------------------------------------------------------- /examples/basics_cpp/wscript: -------------------------------------------------------------------------------- 1 | ../../src/wscript -------------------------------------------------------------------------------- /examples/feature_image_cpp/appinfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "uuid": "3cf2450e-5f6f-4f22-baaa-8c2a968cfc28", 3 | "shortName": "Image Demo", 4 | "longName": "Image Demo", 5 | "companyName": "Pebble Technology", 6 | "versionCode": 2, 7 | "versionLabel": "2.0", 8 | "watchapp": { 9 | "watchface": false 10 | }, 11 | "appKeys": {}, 12 | "resources": { 13 | "media": [ 14 | { 15 | "type": "png", 16 | "name": "IMAGE_NO_LITTER", 17 | "file": "images/no_litter.png" 18 | } 19 | ] 20 | }, 21 | "targetPlatforms": [ 22 | "aplite" 23 | ], 24 | "sdkVersion": "3" 25 | } -------------------------------------------------------------------------------- /examples/feature_image_cpp/graphics/no_litter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 32 | 35 | 36 | 45 | 48 | 49 | 50 | 70 | 74 | 78 | 79 | 81 | 82 | 84 | image/svg+xml 85 | 87 | 88 | 89 | 90 | 91 | 95 | 105 | 111 | 113 | 118 | 123 | 124 | 126 | 128 | 130 | 135 | 140 | 141 | 143 | 148 | 153 | 154 | 156 | 161 | 166 | 167 | 168 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /examples/feature_image_cpp/resources/images/no_litter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fahhem/pebble-cpp/9dae001b128b5e3c48a1c84b01c661d4bfe0c89d/examples/feature_image_cpp/resources/images/no_litter.png -------------------------------------------------------------------------------- /examples/feature_image_cpp/src/feature_image.cpp: -------------------------------------------------------------------------------- 1 | #include "pebble.h" 2 | 3 | class PebbleApp { 4 | public: 5 | void window_load(Window *window) { 6 | CPPWindow root_window(window); 7 | 8 | CPPLayer window_layer(root_window.get_root_layer()); 9 | auto bounds = window_layer.get_bounds(); 10 | 11 | bitmap_layer.reset(new CPPBitmapLayer(0, 0, bounds.size.w, bounds.size.h, 12 | RESOURCE_ID_IMAGE_NO_LITTER)); 13 | bitmap_layer->set_bitmap(bitmap_layer->image_bitmap_); 14 | bitmap_layer->set_alignment(GAlignCenter); 15 | window_layer.add_child(*bitmap_layer); 16 | } 17 | 18 | void window_unload(Window *window) { 19 | bitmap_layer.release(); 20 | } 21 | 22 | private: 23 | std::unique_ptr bitmap_layer; 24 | }; 25 | 26 | extern "C" int main(void) { 27 | App app; 28 | app_event_loop(); 29 | } -------------------------------------------------------------------------------- /examples/feature_image_cpp/src/malloc.cpp: -------------------------------------------------------------------------------- 1 | ../../../src/malloc.cpp -------------------------------------------------------------------------------- /examples/feature_image_cpp/src/pebble.cpp: -------------------------------------------------------------------------------- 1 | ../../../src/pebble.cpp -------------------------------------------------------------------------------- /examples/feature_image_cpp/src/pebble.h: -------------------------------------------------------------------------------- 1 | ../../../src/pebble.h -------------------------------------------------------------------------------- /examples/feature_image_cpp/src/wscript: -------------------------------------------------------------------------------- 1 | ../../../src/wscript -------------------------------------------------------------------------------- /src/malloc.cpp: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | #include 3 | } 4 | 5 | #include 6 | 7 | void* operator new(size_t size) { 8 | return malloc(size); 9 | } 10 | 11 | void operator delete(void *ptr) { 12 | free(ptr); 13 | } 14 | -------------------------------------------------------------------------------- /src/pebble.cpp: -------------------------------------------------------------------------------- 1 | #include "pebble.h" 2 | 3 | CPPWindow::CPPWindow() : window_owned_(true) { 4 | window_ = window_create(); 5 | }; 6 | 7 | CPPWindow::CPPWindow(Window *window) 8 | : window_(window), window_owned_(false) {}; 9 | 10 | CPPWindow::~CPPWindow() { 11 | if (window_owned_) 12 | window_destroy(window_); 13 | }; 14 | 15 | void CPPWindow::set_window_handlers( 16 | WindowHandler load, 17 | WindowHandler unload /* = nullptr */, 18 | WindowHandler appear /* = nullptr */, 19 | WindowHandler disappear /* = nullptr */) { 20 | window_set_window_handlers(window_, (WindowHandlers) { 21 | .load = load, 22 | .appear = appear, 23 | .disappear = disappear, 24 | .unload = unload 25 | }); 26 | } 27 | 28 | 29 | CPPLayer::CPPLayer() : layer_owned_(false) {} 30 | CPPLayer::CPPLayer(Layer *layer) : layer_(layer), layer_owned_(false) {} 31 | CPPLayer::~CPPLayer() { 32 | if (layer_owned_) 33 | layer_destroy(layer_); 34 | } 35 | 36 | void CPPLayer::add_child(CPPLayer &layer) { 37 | layer_add_child(layer_, layer.layer_); 38 | } 39 | 40 | CPPTextLayer::CPPTextLayer(int16_t x, int16_t y, int16_t w, int16_t h) 41 | : CPPLayer() { 42 | text_layer_ = text_layer_create((GRect) { .origin = { x, y }, .size = { w, h } }); 43 | layer_ = text_layer_get_layer(text_layer_); 44 | layer_owned_ = true; 45 | } 46 | 47 | CPPBitmapLayer::CPPBitmapLayer(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t resource_id) 48 | : CPPLayer() { 49 | bitmap_layer_ = bitmap_layer_create((GRect) { .origin = { x, y }, .size = { w, h } }); 50 | image_bitmap_ = gbitmap_create_with_resource(resource_id); 51 | layer_ = bitmap_layer_get_layer(bitmap_layer_); 52 | layer_owned_ = true; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/pebble.h: -------------------------------------------------------------------------------- 1 | #ifndef PEBBLE_CPP_H 2 | #define PEBBLE_CPP_H 3 | 4 | extern "C" { 5 | #include 6 | } 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define PROXY_METHOD(ReturnType, MethodName, Prefix, WrappedObject) \ 13 | template \ 14 | ReturnType MethodName(Args&&... args) { \ 15 | return Prefix ## MethodName(WrappedObject, std::forward(args)...); \ 16 | } 17 | 18 | template class App; 19 | 20 | class CPPWindow { 21 | public: 22 | CPPWindow(); 23 | explicit CPPWindow(Window *window); 24 | 25 | ~CPPWindow(); 26 | 27 | #define WINDOW_PROXY_METHOD(R, M) PROXY_METHOD(R, M, window_, window_) 28 | 29 | void set_window_handlers( 30 | WindowHandler load, 31 | WindowHandler unload = nullptr, 32 | WindowHandler appear = nullptr, 33 | WindowHandler disappear = nullptr); 34 | 35 | template 36 | static void single_click_subscribe(ButtonId button) { 37 | auto handler = &App::template click_handler; 38 | window_single_click_subscribe(button, static_cast(handler)); 39 | } 40 | 41 | // push(animated); 42 | WINDOW_PROXY_METHOD(void, stack_push); 43 | 44 | // set_click_config_provider(ClickConfigProvider provider); 45 | // set_click_config_provider_with_context(ClickConfigProvider provider, void* ctx); 46 | WINDOW_PROXY_METHOD(void, set_click_config_provider); 47 | WINDOW_PROXY_METHOD(void, set_click_config_provider_with_context); 48 | 49 | // Layer* get_root_layer(); 50 | WINDOW_PROXY_METHOD(Layer*, get_root_layer); 51 | 52 | // bool get_fullscreen(); 53 | WINDOW_PROXY_METHOD(bool, get_fullscreen); 54 | 55 | template 56 | UserData* get_user_data() { 57 | return (UserData*)window_get_user_data(window_); 58 | } 59 | 60 | // bool is_loaded(); 61 | WINDOW_PROXY_METHOD(bool, is_loaded); 62 | 63 | // void set_background_color(GColor color); 64 | WINDOW_PROXY_METHOD(void, set_background_color); 65 | 66 | // void set_fullscreen(bool enabled); 67 | WINDOW_PROXY_METHOD(void, set_fullscreen); 68 | 69 | // void set_status_bar_icon(const GBitmap* icon); 70 | WINDOW_PROXY_METHOD(void, set_status_bar_icon); 71 | 72 | private: 73 | Window *window_; 74 | bool window_owned_; 75 | }; 76 | 77 | class CPPLayer { 78 | public: 79 | CPPLayer(); 80 | explicit CPPLayer(Layer *layer); 81 | ~CPPLayer(); 82 | 83 | #define LAYER_PROXY_METHOD(R, M) PROXY_METHOD(R, M, layer_, layer_) 84 | 85 | void add_child(CPPLayer &layer); 86 | 87 | // GRect get_bounds(); 88 | LAYER_PROXY_METHOD(GRect, get_bounds); 89 | 90 | // void set_bounds(GRect); 91 | LAYER_PROXY_METHOD(void, set_bounds); 92 | 93 | // bool get_clips(); 94 | LAYER_PROXY_METHOD(bool, get_clips); 95 | 96 | // void get_clips(bool); 97 | LAYER_PROXY_METHOD(void, set_clips); 98 | 99 | // GRect get_frame(); 100 | LAYER_PROXY_METHOD(GRect, get_frame); 101 | 102 | // void set_frame(GRect); 103 | LAYER_PROXY_METHOD(void, set_frame); 104 | 105 | // bool get_hidden(); 106 | LAYER_PROXY_METHOD(bool, get_hidden); 107 | 108 | // void set_hidden(bool); 109 | LAYER_PROXY_METHOD(void, set_hidden); 110 | 111 | // Window* get_window(); 112 | LAYER_PROXY_METHOD(Window*, get_window); 113 | 114 | // void mark_dirty(); 115 | LAYER_PROXY_METHOD(void, mark_dirty); 116 | 117 | protected: 118 | Layer *layer_; 119 | bool layer_owned_; 120 | }; 121 | 122 | class CPPTextLayer : public CPPLayer { 123 | public: 124 | explicit CPPTextLayer(int16_t x, int16_t y, int16_t w, int16_t h); 125 | 126 | #define TEXT_LAYER_PROXY_METHOD(R, M) PROXY_METHOD(R, M, text_layer_, text_layer_) 127 | 128 | // void set_text_alignment(GTextAlignment); 129 | TEXT_LAYER_PROXY_METHOD(void, set_text_alignment); 130 | 131 | // GSize get_content_size(); 132 | TEXT_LAYER_PROXY_METHOD(GSize, get_content_size); 133 | 134 | // void set_size(GSize max_size); 135 | TEXT_LAYER_PROXY_METHOD(void, set_size); 136 | 137 | // const char* get_text(); 138 | TEXT_LAYER_PROXY_METHOD(const char*, get_text); 139 | 140 | // void set_text(char*); 141 | TEXT_LAYER_PROXY_METHOD(void, set_text); 142 | 143 | // void set_background_color(GColor); 144 | TEXT_LAYER_PROXY_METHOD(void, set_background_color); 145 | 146 | // void set_text_color(GColor); 147 | TEXT_LAYER_PROXY_METHOD(void, set_text_color); 148 | 149 | // void set_font(GFont); 150 | TEXT_LAYER_PROXY_METHOD(void, set_font); 151 | 152 | // void set_overflow_mode(GTextOverflowMode); 153 | TEXT_LAYER_PROXY_METHOD(void, set_overflow_mode); 154 | 155 | private: 156 | TextLayer *text_layer_; 157 | }; 158 | 159 | class CPPBitmapLayer : public CPPLayer { 160 | public: 161 | GBitmap *image_bitmap_; 162 | 163 | explicit CPPBitmapLayer(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t resource_id); 164 | 165 | #define BITMAP_LAYER_PROXY_METHOD(R, M) PROXY_METHOD(R, M, bitmap_layer_, bitmap_layer_) 166 | 167 | // const GBitmap* get_bitmap() 168 | BITMAP_LAYER_PROXY_METHOD(const GBitmap*, get_bitmap); 169 | 170 | // void set_bitmap(const GBitmap*) 171 | BITMAP_LAYER_PROXY_METHOD(void, set_bitmap) 172 | 173 | // void set_alignment(GAlign) 174 | BITMAP_LAYER_PROXY_METHOD(void, set_alignment) 175 | 176 | // void set_background_color(GColor) 177 | BITMAP_LAYER_PROXY_METHOD(void, set_background_color) 178 | 179 | //void set_compositing_mode(GCompOp) 180 | BITMAP_LAYER_PROXY_METHOD(void, set_compositing_mode) 181 | 182 | private: 183 | BitmapLayer *bitmap_layer_; 184 | }; 185 | 186 | template 187 | class App { 188 | public: 189 | explicit App(bool animated = true) { 190 | root_window_.set_window_handlers( 191 | &App::window_load, &App::window_unload); 192 | root_window_.stack_push(animated); 193 | } 194 | 195 | static void window_load(Window *window) { 196 | app_.window_load(window); 197 | } 198 | 199 | static void window_unload(Window *window) { 200 | app_.window_unload(window); 201 | } 202 | 203 | static void click_config_provider(void* ctx) { 204 | app_.click_config_provider(ctx); 205 | } 206 | 207 | template 208 | static void click_handler(ClickRecognizerRef rec, void* context) { 209 | (app_.*Method)(rec); 210 | } 211 | 212 | private: 213 | CPPWindow root_window_; 214 | static PebbleAppT app_; 215 | }; 216 | 217 | template 218 | PebbleAppT App::app_; 219 | 220 | #endif // PEBBLE_CPP_H 221 | -------------------------------------------------------------------------------- /src/wscript: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # This file is the default set of rules to compile a Pebble project. 4 | # 5 | # Feel free to customize this to your needs. 6 | # 7 | 8 | import os.path 9 | 10 | top = '.' 11 | out = 'build' 12 | 13 | def options(ctx): 14 | ctx.load('pebble_sdk') 15 | ctx.load('g++') 16 | 17 | def configure(ctx): 18 | ctx.load('pebble_sdk') 19 | 20 | CROSS_COMPILE_PREFIX = 'arm-none-eabi-' 21 | ctx.env.CXX = CROSS_COMPILE_PREFIX+'g++' 22 | ctx.load('g++') 23 | 24 | ctx.env.CXXFLAGS = list(ctx.env.CFLAGS) 25 | ctx.env.CXXFLAGS.remove('-std=c99') 26 | sdk_folder = ctx.root.find_dir(ctx.env['PEBBLE_SDK']) 27 | ctx.env.CXXFLAGS.extend(['-std=c++11', '-fPIE', '-fno-unwind-tables', '-fno-exceptions']) 28 | 29 | def build(ctx): 30 | ctx.load('pebble_sdk') 31 | 32 | build_worker = os.path.exists('worker_src') 33 | binaries = [] 34 | 35 | for p in ctx.env.TARGET_PLATFORMS: 36 | ctx.set_env(ctx.all_envs[p]) 37 | app_elf='{}/pebble-app.elf'.format(ctx.env.BUILD_DIR) 38 | ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.cpp'), 39 | target=app_elf) 40 | 41 | if build_worker: 42 | worker_elf='{}/pebble-worker.elf'.format(ctx.env.BUILD_DIR) 43 | binaries.append({'platform': p, 'app_elf': app_elf, 'worker_elf': worker_elf}) 44 | ctx.pbl_worker(source=ctx.path.ant_glob('worker_src/**/*.cpp'), 45 | target=worker_elf) 46 | else: 47 | binaries.append({'platform': p, 'app_elf': app_elf}) 48 | 49 | ctx.pbl_bundle(binaries=binaries, js=ctx.path.ant_glob('src/js/**/*.js')) 50 | --------------------------------------------------------------------------------