├── .gitattributes
├── .gitignore
├── README.md
├── devhelp
├── README.md
├── appinfo.json
├── build.all.sh
├── build.sh
├── ide
│ └── codeblocks
│ │ ├── PLocalSim.cbp
│ │ └── build.all.sh
├── openShell.bat
├── run.sh
└── src
│ └── sampleProject.c
├── include
└── pls_unwarn_unsupported_functions.h
├── install.sh
├── openShell.bat
├── scripts
├── build.library.sh
├── build.resCompiler.sh
└── envvars.sh
├── sdkdata
├── common
│ ├── build.local.sh
│ └── run.local.sh
├── standalone
│ ├── PLocalSim
│ │ └── projectTemplate
│ │ │ ├── appinfo.json
│ │ │ └── src
│ │ │ └── sampleProject.c
│ └── create.project.sh
├── unix
│ └── PLocalSim
│ │ ├── appjs_header.js
│ │ └── envvars.sh
└── windows
│ ├── PLocalSim
│ └── envvars.sh
│ └── openShell.bat
├── simdata
├── common
│ ├── LICENSE.freetype.txt
│ ├── LICENSE.png.txt
│ ├── LICENSE.zlib.txt
│ ├── images
│ │ ├── backlight.png
│ │ ├── body.png
│ │ ├── screenshadow.png
│ │ ├── scrollshadow.png
│ │ ├── statusbar.png
│ │ └── vibe.png
│ └── systemFonts
│ │ ├── Google Android License.txt
│ │ ├── bitham-black.ttf
│ │ ├── bitham-bold.ttf
│ │ ├── bitham-light-subset.ttf
│ │ ├── bitham-light.ttf
│ │ ├── bitham-medium-numbers.ttf
│ │ ├── droid-serif-bold.ttf
│ │ ├── gothic-bold.ttf
│ │ ├── gothic.ttf
│ │ ├── roboto-bold.ttf
│ │ └── roboto-condensed.ttf
├── unix
│ ├── XMLHttpRequest.js
│ └── server.js
└── windows
│ ├── SDL2.dll
│ ├── SDL2_image.dll
│ ├── SDL2_ttf.dll
│ ├── libfreetype-6.dll
│ ├── libpng16-16.dll
│ └── zlib1.dll
└── src
├── SDL_gfx
├── SDL_gfxBlitFunc.c
├── SDL_gfxBlitFunc.h
├── SDL_gfxPrimitives.c
├── SDL_gfxPrimitives.h
├── SDL_gfxPrimitives_font.h
├── SDL_rotozoom.c
├── SDL_rotozoom.h
└── disclaimer.txt
├── additional
└── strftime.c
├── js_server
├── lib
│ ├── XMLHttpRequest.js
│ └── localStorage.js
└── server.js
├── jsmn
├── jsmn.c
└── jsmn.h
├── local
├── accel_tap.c
├── actionbar.c
├── animation.c
├── app_message.c
├── app_sync.c
├── battery.c
├── bitmap.c
├── bluetooth.c
├── buttons.c
├── dictionary.c
├── draw.c
├── dummy
│ └── src
│ │ └── resource_ids.auto.h
├── font.c
├── globals.h
├── hardwareOutput.c
├── impl_pebble.h
├── layer.c
├── main.c
├── math.c
├── pebble_os.c
├── persistent_storage.c
├── render.c
├── scrolllayer.c
├── simdata.c
├── timer.c
├── watchinfo.c
└── window.c
└── resourceCompiler
├── main.c
└── resCompiler.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | sdkdata/windows/PLocalSim/MinGW/
2 | sdkdata/windows/PLocalSim/SDL2/
3 | devhelp/build/
4 | test/
5 | testsdk/
6 | obj/
7 | bin/
8 | backups/
9 | include/pebble*
10 | *~
11 | *.zip
12 | *.layout
--------------------------------------------------------------------------------
/devhelp/README.md:
--------------------------------------------------------------------------------
1 | # Developer Helper
2 |
3 | ## Overview
4 | This is a small tool to make the development of the library easier. It essentially is a small stand-alone SDK that is ready-to-work-with when you could install a SDK (means all compilers and libraries are there). Also there are few optimizations (especially the library compilation caching) to speed up the work with this tool instead of rebuilding and reinstalling an entire SDK for one development iteration.
5 | As this is not intended to be used externally, please don't try to use it other as intended (for example from another folder than devhelp/ ), doing otherwise could have undefined behaviour.
6 |
7 | ## Usage
8 | This tool only works if a call to install.sh would also work (compiler and libraries are installed). If it does you navigate with a shell to the `devhelp` folder (for Windows you can just open `openShell.bat`). Then you can use:
9 |
10 | * `build.sh` - for building just the example project located in the `devhelp` folder
11 | * `build.all.sh` - for building the library, the resource compiler (c version) and the example projec
12 | * `build.all.sh --rebuild` - to delete the cache and make sure that everything will be compiled from the ground up
13 | * `run.sh` - for starting the built project
14 | * `run.sh --debug` - for starting the project within gdb
15 |
--------------------------------------------------------------------------------
/devhelp/appinfo.json:
--------------------------------------------------------------------------------
1 | {
2 | "uuid": "79a0f865-22da-415d-9764-6012a07a1bd6",
3 | "shortName": "sampleProject",
4 | "longName": "sampleProject",
5 | "companyName": "MakeAwesomeHappen",
6 | "versionCode": 1,
7 | "versionLabel": "1.0.0",
8 | "watchapp": {
9 | "watchface": false
10 | },
11 | "appKeys": {
12 | "dummy": 0
13 | },
14 | "resources": {
15 | "media": []
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/devhelp/build.all.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # As this environment is basically a small standalone sdk, we have to use the c resource compiler
4 |
5 | # Disable unicode (should speed up everything)
6 | LC_ALL_BACKUP=$LC_ALL
7 | export LC_ALL=C
8 |
9 | # Prepare cache
10 | if [ "$1" == "--rebuild" ]; then
11 | echo "[INFO] Remove library cache"
12 | rm -f ./build/tempLocal/libCache/*
13 | else
14 | mkdir -p ./build/tempLocal/libCache
15 | fi
16 |
17 | # Building
18 | cd ..
19 | echo "[INFO] Building libray"
20 | if ./scripts/build.library.sh --debug ./devhelp/build/tempLocal/libCache ; then
21 | echo "[INFO] Building resource compiler"
22 | if ./scripts/build.resCompiler.sh -c --debug ; then
23 | cd devhelp
24 | echo "[INFO] Building project"
25 | if ./build.sh ; then # no --debug needed
26 | echo "[INFO] Everything built"
27 | else
28 | echo "[FAIL] Project compilation failed"
29 | fi
30 | else
31 | echo "[FAIL] Resource compiler compilation failed"
32 | fi
33 | else
34 | echo "[FAIL] Library compilation failed"
35 | fi
36 |
37 | # Reenable unicode
38 | export LC_ALL=$LC_ALL_BACKUP
39 |
--------------------------------------------------------------------------------
/devhelp/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This is basically a hacked build.local.sh
4 | # don't expect anything fancy in here
5 |
6 | # Load (and fix) envvars
7 | if [ ! -e '../scripts/envvars.sh' ] ; then
8 | echo "[FAIL] Could not load envvars.sh"
9 | exit 1
10 | fi
11 | PLS_ENV_PREFIX='.'
12 | source '../scripts/envvars.sh'
13 |
14 | # Check for gcc
15 | if hash $PLS_GCC 2>/dev/null; then
16 | : # no-op
17 | else
18 | echo "[FAIL] Could not find required program gcc"
19 | exit 1
20 | fi
21 |
22 | # Check if we are in a project
23 | while [ ! -e "appinfo.json" ]
24 | do
25 | if [ `pwd` == '/' ]
26 | then
27 | echo "[FAIL] Could not find 'appinfo.json' in this directory or any parent" 1>&2
28 | exit 1
29 | fi
30 | cd ..
31 | done
32 |
33 | # Copy resources and app info
34 | PLS_OS_NAME='unix'
35 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
36 | PLS_OS_NAME='windows'
37 | fi
38 |
39 | mkdir -p ./build/local/
40 | cp -u ./appinfo.json ./build/local/
41 | cp -u -r ../simdata/common/* ./build/local/
42 | cp -u -r ../simdata/$PLS_OS_NAME/* ./build/local/
43 |
44 | # Check for and copy JS
45 | if [ -e './src/js/pebble-js-app.js' ] ; then
46 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
47 | echo "[WARNING] Windows does not support javascript apps yet"
48 | else
49 | cat $PLS_SDK_DIR/header.js > ./build/local/pebble-js-app-local.js
50 | cat ./src/js/pebble-js-app.js >> ./build/local/pebble-js-app-local.js
51 | fi
52 | fi
53 |
54 | # Compile resources
55 | PLS_RSC='../bin/resCompiler'
56 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
57 | PLS_RSC=$PLS_RSC'.exe'
58 | fi # No virualenv because this is not a pebble-installed sdk
59 |
60 | if [ ! -e $PLS_RSC ] ; then
61 | echo "[FAIL] Could not start resource compiler"
62 | elif $PLS_RSC ; then
63 | : # no-op
64 | else
65 | echo "[FAIL] Could not compile resources"
66 | exit 1
67 | fi
68 |
69 | # Prepare compile variables
70 | PLS_APP_INCLUDES='-I ./build/tempLocal/ -I ./build/tempLocal/src/ -isystem ../include '
71 | PLS_APP_LIB_INCLUDES='-L ../bin'
72 | PLS_APP_LIBS='-lPLocalSim -lSDL2 -lSDL2_ttf -lSDL2_image -lm -lpthread'
73 | PLS_APP_ARGS='-c -x c -O2 -Wall -std=c99 -DLOCALSIM -ggdb'
74 | PLS_APP_NAME='testapp'
75 | PLS_APP_OUT='./build/local/'$PLS_APP_NAME
76 |
77 | # Special values
78 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
79 | # Windows/MinGW
80 | PLS_APP_INCLUDES=$PLS_APP_INCLUDES
81 | PLS_APP_LIB_INCLUDES=$PLS_APP_LIB_INCLUDES' -L '$PLS_DIR_SDL'/lib'
82 | PLS_APP_LIBS='-lmingw32 -lSDL2main '$PLS_APP_LIBS
83 | PLS_APP_ARGS=$PLS_APP_ARGS' -mconsole -DWIN32 -D_WIN32'
84 | PLS_APP_OUT=$PLS_APP_OUT'.exe'
85 | fi
86 |
87 | # Compile object files
88 | mkdir -p ./build/tempLocal
89 | rm -f ./build/tempLocal/*.o
90 | filelist='./src/*.c'
91 | PLS_APP_OBJECTS=" "
92 | for file in `ls $filelist` ; do
93 | filename=${file##*/} # without the directory
94 | echo 'Compiling '$filename
95 | objectFile=./build/tempLocal/${filename%.*}'.o'
96 | if $PLS_GCC $PLS_APP_ARGS $PLS_APP_INCLUDES $file -o $objectFile ; then
97 | PLS_APP_OBJECTS=$PLS_APP_OBJECTS' '$objectFile
98 | else
99 | exit 1
100 | fi
101 | done
102 |
103 | echo Linking
104 | $PLS_GCC $PLS_APP_OBJECTS $PLS_APP_LIB_INCLUDES $PLS_APP_LIBS -o $PLS_APP_OUT
105 |
106 |
--------------------------------------------------------------------------------
/devhelp/ide/codeblocks/PLocalSim.cbp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/devhelp/ide/codeblocks/build.all.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # A small script to call build.all.sh in the right working directory
4 | PWD_BACKUP=`pwd`
5 |
6 | cd .. # up to ide
7 | cd .. # up to devhelp
8 |
9 | ./build.all.sh $@
10 |
11 | cd $PWD_BACKUP
12 |
--------------------------------------------------------------------------------
/devhelp/openShell.bat:
--------------------------------------------------------------------------------
1 | @REM This is just a small file to start bash in the current directory
2 | @PATH=%PATH%;%~dp0\..\sdkdata\windows\PLocalSim\MinGW\bin\
3 | @%~dp0\..\sdkdata\windows\PLocalSim\MinGW\msys\1.0\msys.bat %~dp0
--------------------------------------------------------------------------------
/devhelp/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # This is basically a hacked run.local.sh
4 | # don't expect anything fancy in here
5 |
6 | PLS_MY_DIR=`pwd`
7 |
8 | # Load (and fix) envvars
9 | if [ ! -e '../scripts/envvars.sh' ] ; then
10 | echo "[FAIL] Could not load envvars.sh"
11 | exit 1
12 | fi
13 | PLS_ENV_PREFIX=$PLS_MY_DIR'/.'
14 | source '../scripts/envvars.sh'
15 |
16 | # Check for gdb
17 | if hash $PLS_GDB 2>/dev/null; then
18 | : # no-op
19 | else
20 | echo "[FAIL] Could not find required program gdb"
21 | exit 1
22 | fi
23 |
24 |
25 | PLS_DIR_BACKUP=`pwd`
26 |
27 | # Check if we are in a project
28 | while [ ! -e "appinfo.json" ]
29 | do
30 | if [ `pwd` == '/' ]
31 | then
32 | echo "[FAIL] Could not find 'appinfo.json' in this directory or any parent" 1>&2
33 | exit 1
34 | fi
35 | cd ..
36 | done
37 |
38 | # Run the simulator if we find it
39 | PLS_APP_PATH=`pwd`
40 | PLS_APP_NAME='testapp'
41 | PLS_APP_EXEC='./build/local/'$PLS_APP_NAME
42 | if [ -e "$PLS_APP_EXEC" ] ; then
43 | cd build/local
44 |
45 | if [ "$1" == "--debug" ] ; then
46 | $PLS_GDB ./$PLS_APP_NAME
47 | else
48 | ./$PLS_APP_NAME
49 | fi
50 | else
51 | echo "[FAIL] Could not find simulator, maybe it is not compiled yet?"
52 | fi
53 |
54 | cd $PLS_DIR_BACKUP
55 |
--------------------------------------------------------------------------------
/devhelp/src/sampleProject.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | static Window *window;
4 | static TextLayer *text_layer;
5 |
6 | static void select_click_handler(ClickRecognizerRef recognizer, void *context) {
7 | text_layer_set_text(text_layer, "Select");
8 | }
9 |
10 | static void up_click_handler(ClickRecognizerRef recognizer, void *context) {
11 | text_layer_set_text(text_layer, "Up");
12 | }
13 |
14 | static void down_click_handler(ClickRecognizerRef recognizer, void *context) {
15 | text_layer_set_text(text_layer, "Down");
16 | }
17 |
18 | static void click_config_provider(void *context) {
19 | window_single_click_subscribe(BUTTON_ID_SELECT, select_click_handler);
20 | window_single_click_subscribe(BUTTON_ID_UP, up_click_handler);
21 | window_single_click_subscribe(BUTTON_ID_DOWN, down_click_handler);
22 | }
23 |
24 | static void window_load(Window *window) {
25 | Layer *window_layer = window_get_root_layer(window);
26 | GRect bounds = layer_get_bounds(window_layer);
27 |
28 | text_layer = text_layer_create((GRect) { .origin = { 0, 72 }, .size = { bounds.size.w, 20 } });
29 | text_layer_set_text(text_layer, "Press a button");
30 | text_layer_set_text_alignment(text_layer, GTextAlignmentCenter);
31 | layer_add_child(window_layer, text_layer_get_layer(text_layer));
32 | }
33 |
34 | static void window_unload(Window *window) {
35 | text_layer_destroy(text_layer);
36 | }
37 |
38 | static void init(void) {
39 | window = window_create();
40 | window_set_click_config_provider(window, click_config_provider);
41 | window_set_window_handlers(window, (WindowHandlers) {
42 | .load = window_load,
43 | .unload = window_unload,
44 | });
45 | const bool animated = true;
46 | window_stack_push(window, animated);
47 | }
48 |
49 | static void deinit(void) {
50 | window_destroy(window);
51 | }
52 |
53 | int main(void) {
54 | init();
55 |
56 | APP_LOG(APP_LOG_LEVEL_DEBUG, "Done initializing, pushed window: %p", window);
57 |
58 | app_event_loop();
59 | deinit();
60 |
61 | return 0;
62 | }
63 |
--------------------------------------------------------------------------------
/include/pls_unwarn_unsupported_functions.h:
--------------------------------------------------------------------------------
1 | /* This file unwarns all functions that are unsupported by the pebble sdk
2 | * In addition to that, we all hope that the clib did not defined these functions as macros :(
3 | */
4 |
5 | #undef printf
6 | #undef fopen
7 | #undef fclose
8 | #undef fread
9 | #undef fwrite
10 | #undef fseek
11 | #undef ftell
12 | #undef fsetpos
13 | #undef fscanf
14 | #undef fgetc
15 | #undef fgets
16 | #undef fputc
17 | #undef fputs
18 | #undef fprintf
19 | #undef sprintf
20 | #undef vfprintf
21 | #undef vsprintf
22 | #undef vsnprintf
23 | #undef open
24 | #undef close
25 | #undef creat
26 | #undef read
27 | #undef write
28 | #undef stat
29 | #undef alloca
30 | #undef mmap
31 | #undef brk
32 | #undef sbrk
33 |
34 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PLS_MY_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
4 |
5 | if [ ! -e $PLS_MY_DIR'/scripts/envvars.sh' ] ; then
6 | echo "[FAIL] Could not load envvars.sh"
7 | exit 1
8 | fi
9 | source $PLS_MY_DIR'/scripts/envvars.sh'
10 |
11 | # Find target path
12 | PLS_TARGET_PATH=$1
13 | PLS_IS_STANDALONE='true'
14 | if [ -z "$PLS_TARGET_PATH" ] ; then
15 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ] ; then
16 | echo "[FAIL] PLocalSim does need a specific directory on windows"
17 | exit 1
18 | else
19 | # try to find the pebble sdk
20 | PLS_PATH_PEBBLE=`which pebble`
21 | if [ $? -eq 0 ] ; then
22 | PLS_TARGET_PATH=`dirname $PLS_PATH_PEBBLE`
23 | PLS_IS_STANDALONE='false'
24 | else
25 | echo "[FAIL] PLocalSim could not locate the pebble sdk"
26 | exit 1
27 | fi
28 | fi
29 | fi
30 |
31 | # Check if the sdk is built already
32 | PLS_SIM_LIB=$PLS_MY_DIR'/bin/libPLocalSim.a'
33 | PLS_RSC_EXE=$PLS_MY_DIR'/bin/resCompiler'
34 | PLS_RECOMPILE_RSC='false'
35 | PLS_RSC_BUILD_ARGS=' '
36 | PLS_OS_NAME='unix'
37 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
38 | PLS_RSC_EXE=$PLS_RSC_EXE'.exe'
39 | PLS_OS_NAME='windows'
40 | elif [ "$PLS_IS_STANDALONE" == "true" ] ; then
41 | # Unix systems must use the c resourceCompiler because the python requires
42 | # the pebble libraries we don't have on stand-alone installations
43 | PLS_RECOMPILE_RSC='true'
44 | PLS_RSC_BUILD_ARGS='-c'
45 | fi
46 |
47 | if [ ! -e $PLS_SIM_LIB ] ; then
48 | echo "[INFO] PLocalSim library is not built yet, compiling..."
49 | if ./scripts/build.library.sh ; then
50 | echo "[INFO] Sucessfully compiled PLocalSim library"
51 | else
52 | echo "[FAIL] Could not compile PLocalSim library"
53 | exit 1
54 | fi
55 | fi
56 |
57 | if [ ! -e $PLS_RSC_EXE ] ; then
58 | PLS_RECOMPILE_RSC='true'
59 | fi
60 | if [ "$PLS_RECOMPILE_RSC" == "true" ] ; then
61 | echo "[INFO] PLocalSim resource compiler is not built yet, compiling..."
62 | if ./scripts/build.resCompiler.sh $PLS_RSC_BUILD_ARGS ; then
63 | echo "[INFO] Sucessfully compiled PLocalSim resource compiler"
64 | else
65 | echo "[FAIL] Could not compile PLocalSim resource compiler"
66 | exit 1
67 | fi
68 | fi
69 |
70 | # Create/Test directory
71 | mkdir -p $PLS_TARGET_PATH'/PLocalSim/simdata'
72 | if [ ! -d "$PLS_TARGET_PATH" ] ; then
73 | echo "[FAIL] Invalid directory: $PLS_TARGET_PATH"
74 | exit 1
75 | fi
76 |
77 | # Copy all of the sdk
78 | echo "[INFO] Copy common sdk data"
79 | cp -f -r $PLS_MY_DIR/bin/* $PLS_TARGET_PATH'/PLocalSim/'
80 | cp -f -r $PLS_MY_DIR/sdkdata/common/* $PLS_TARGET_PATH'/'
81 | cp -f -r $PLS_MY_DIR/simdata/common/* $PLS_TARGET_PATH'/PLocalSim/simdata/'
82 |
83 | echo "[INFO] Copy OS specific data (may take a few minutes)"
84 | cp -f -r $PLS_MY_DIR/sdkdata/$PLS_OS_NAME/* $PLS_TARGET_PATH'/'
85 | cp -f -r $PLS_MY_DIR/simdata/$PLS_OS_NAME/* $PLS_TARGET_PATH'/PLocalSim/simdata/'
86 |
87 | if [ "$PLS_IS_STANDALONE" == 'true' ]; then
88 | echo "[INFO] Copy data for stand-alone installations"
89 | mkdir -p $PLS_TARGET_PATH'/PLocalSim/include'
90 | cp -f -r $PLS_MY_DIR/include/* $PLS_TARGET_PATH'/PLocalSim/include/'
91 | cp -f -r $PLS_MY_DIR/sdkdata/standalone/* $PLS_TARGET_PATH'/'
92 | fi
93 |
--------------------------------------------------------------------------------
/openShell.bat:
--------------------------------------------------------------------------------
1 | @REM This is just a small file to start bash in the current directory
2 | @PATH=%PATH%;%~dp0\sdkdata\windows\PLocalSim\MinGW\bin\
3 | @%~dp0\sdkdata\windows\PLocalSim\MinGW\msys\1.0\msys.bat %~dp0
--------------------------------------------------------------------------------
/scripts/build.library.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PLS_MY_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
4 | PLS_LIB_CACHE=$2
5 |
6 | if [ ! -e $PLS_MY_DIR'/envvars.sh' ] ; then
7 | echo "[FAIL] Could not load envvars.sh"
8 | exit 1
9 | fi
10 | source $PLS_MY_DIR'/envvars.sh'
11 |
12 | # check if we have gcc and ar
13 | if hash $PLS_GCC 2>/dev/null; then
14 | if hash $PLS_AR 2>/dev/null; then
15 |
16 | # prepare some variables
17 | PLS_SIM_INCLUDES='-isystem ./include -I ./src/local -I ./src/local/dummy -I ./src/SDL_gfx -I ./src/jsmn'
18 |
19 | PLS_SIM_OUTPUT='./bin/libPLocalSim.a'
20 | PLS_SIM_TMP_OUT='./obj'
21 | PLS_SIM_GCC_ARGS='-c -std=c99 '
22 |
23 | if [ "$1" == "--debug" ]; then
24 | PLS_SIM_GCC_ARGS=$PLS_SIM_GCC_ARGS' -ggdb'
25 | else
26 | PLS_SIM_GCC_ARGS=$PLS_SIM_GCC_ARGS' -O2'
27 | fi
28 |
29 | # MinGW specific values
30 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
31 | PLS_SIM_GCC_ARGS='-DWIN32 -D_WIN32 -mconsole '$PLS_SIM_GCC_ARGS
32 | PLS_SIM_INCLUDES='-I '$PLS_DIR_SDL'/include -isystem '$PLS_DIR_SDL'/include/SDL2 '$PLS_SIM_INCLUDES
33 | fi
34 |
35 | # create directories and delete old object files
36 | mkdir -p ./bin
37 | mkdir -p $PLS_SIM_TMP_OUT
38 | filelist=$PLS_SIM_TMP_OUT'/*.o'
39 |
40 | # how to compile a directory, params:
41 | # directory to compile
42 | # 'silent' if you don't want to output every filename
43 | # extra compile options
44 | function compileDirectory {
45 | filelist=$1'/*.c'
46 | for file in `ls $filelist` ; do
47 | filename=${file##*/} # without the directory
48 | objectFile=$PLS_SIM_TMP_OUT'/'${filename%.*}'.o'
49 | hashFile=$PLS_LIB_CACHE'/'${filename%.*}'.md5'
50 |
51 | dobuildfile='true'
52 | error='true'
53 |
54 | # Check cache
55 | if [ ! -z "$PLS_LIB_CACHE" ] ; then
56 | if [ -e "$objectFile" ] ; then
57 | if [ -e "$hashFile" ] ; then
58 | savedhash=$(<$hashFile)
59 | calcedhash=`date -r $file +%s``date -r $objectFile +%s`
60 | if [ "$savedhash" == "$calcedhash" ] ; then
61 | dobuildfile='false'
62 | if [ ! 'silent' = "$2" ] ; then
63 | echo Using cached $filename
64 | fi
65 | if $PLS_AR rcs $PLS_SIM_OUTPUT $objectFile ; then
66 | error='false'
67 | fi
68 | fi
69 | fi
70 | fi
71 | fi
72 |
73 | # Compile file
74 | if [ "$dobuildfile" == "true" ]; then
75 | if [ ! 'silent' = "$2" ] ; then
76 | echo Compiling $filename
77 | fi
78 | if $PLS_GCC $PLS_SIM_GCC_ARGS $3 $PLS_SIM_INCLUDES $file -o $objectFile ; then
79 | if $PLS_AR rcs $PLS_SIM_OUTPUT $objectFile ; then
80 | error='false'
81 |
82 | # Update cache
83 | if [ ! -z "$PLS_LIB_CACHE" ] ; then
84 | newhash=`date -r $file +%s``date -r $objectFile +%s`
85 | touch "$hashFile"
86 | echo "$newhash" > "$hashFile"
87 | fi
88 | fi
89 | fi
90 | fi
91 |
92 | if [ 'true' = "$error" ] ; then
93 | echo Compilation failed
94 | rm -f $PLS_SIM_OUTPUT
95 | exit 1
96 | fi
97 |
98 | done
99 | return 1
100 | }
101 |
102 | # Compile the library
103 | compileDirectory ./src/local 'no' '-Wall -Wno-format'
104 |
105 | echo Compiling SDL_gfx
106 | compileDirectory './src/SDL_gfx' 'silent' '-Wall'
107 |
108 | echo Compiling jsmn
109 | compileDirectory './src/jsmn' 'silent' '-w'
110 |
111 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
112 | echo Compiling additional source
113 | compileDirectory './src/additional' 'silent' '-w'
114 | fi
115 |
116 | exit 0
117 |
118 | else
119 | echo "Could not find required program ar"
120 | exit 1
121 | fi
122 | else
123 | echo "Could not find required program gcc"
124 | exit 1
125 | fi
126 |
--------------------------------------------------------------------------------
/scripts/build.resCompiler.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PLS_MY_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
4 |
5 | if [ ! -e $PLS_MY_DIR'/envvars.sh' ] ; then
6 | echo "[FAIL] Could not load envvars.sh"
7 | exit 1
8 | fi
9 | source $PLS_MY_DIR'/envvars.sh'
10 |
11 | # The compilation process of the c program is cross-platform but
12 | # at the moment we use the python version on unix systems
13 | PLS_RSC_OUTPUT='./bin/resCompiler'
14 |
15 | PLS_USE_C='false'
16 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ] ; then
17 | PLS_USE_C='true'
18 | elif [ "$1" == "-c" ] ; then
19 | PLS_USE_C='true'
20 | fi
21 |
22 | if [ "$PLS_USE_C" == "true" ]; then
23 | # check if we have gcc
24 | if hash $PLS_GCC 2>/dev/null; then
25 | mkdir -p ./bin
26 |
27 | # prepare some variables
28 | PLS_RSC_INCLUDES='-I ./src/resourceCompiler -I ./src/jsmn'
29 | PLS_RSC_SOURCE=`ls ./src/resourceCompiler/*.c`' '`ls ./src/jsmn/*.c`
30 | PLS_RSC_GCC_ARGS='-O2 -std=c99 -Wno-unused-result'
31 | PLS_RSC_LIBS='-lSDL2main -lSDL2 -lSDL2_image'
32 |
33 | # MinGW specific values
34 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
35 | PLS_RSC_GCC_ARGS='-DWIN32 -D_WIN32 -mconsole -L '$PLS_DIR_SDL'/lib '$PLS_RSC_GCC_ARGS
36 | PLS_RSC_INCLUDES='-I '$PLS_DIR_SDL'/include -I '$PLS_DIR_SDL'/include/SDL2 '$PLS_RSC_INCLUDES
37 | PLS_RSC_LIBS='-lmingw32 '$PLS_RSC_LIBS
38 | PLS_RSC_OUTPUT=$PLS_RSC_OUTPUT'.exe'
39 |
40 | cp -u -r $PLS_DIR_SDL/bin/* ./bin/
41 | fi
42 |
43 | # Compile the resource compiler
44 | if $PLS_GCC $PLS_RSC_GCC_ARGS $PLS_RSC_INCLUDES $PLS_RSC_SOURCE $PLS_RSC_LIBS -o $PLS_RSC_OUTPUT ; then
45 | exit 0
46 | else
47 | echo "[FAIL] Compilation failed"
48 | exit 1
49 | fi
50 |
51 | else
52 | echo "Could not find required program gcc"
53 | exit 1
54 | fi
55 |
56 | else # if the python version shall be used
57 | cp -f './src/resourceCompiler/resCompiler.py' $PLS_RSC_OUTPUT
58 | fi
59 |
--------------------------------------------------------------------------------
/scripts/envvars.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # PLS_ENV_PREFIX is currently only used by devhelp
4 | # If you use custom variables, don't use PLS_ENV_PREFIX
5 |
6 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
7 | PLS_GCC=$PLS_ENV_PREFIX'./sdkdata/windows/PLocalSim/MinGW/bin/gcc.exe'
8 | PLS_AR=$PLS_ENV_PREFIX'./sdkdata/windows/PLocalSim/MinGW/bin/ar.exe'
9 | PLS_GDB=$PLS_ENV_PREFIX'./sdkdata/windows/PLocalSim/MinGW/bin/gdb.exe'
10 | PLS_DIR_SDL=$PLS_ENV_PREFIX'./sdkdata/windows/PLocalSim/SDL2'
11 | else
12 | PLS_GCC='gcc'
13 | PLS_AR='ar'
14 | PLS_GDB='gdb'
15 | fi
16 |
--------------------------------------------------------------------------------
/sdkdata/common/build.local.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Check if we have access to gcc
4 | PLS_SDK_ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
5 | PLS_SDK_DIR=$PLS_SDK_ROOT_DIR'/PLocalSim'
6 |
7 | if [ ! -e $PLS_SDK_DIR'/envvars.sh' ] ; then
8 | echo "[FAIL] Could not load envvars.sh"
9 | exit 1
10 | fi
11 | source $PLS_SDK_DIR'/envvars.sh'
12 |
13 | PLS_COMPILE_MODE='release'
14 | if [ "$1" == "--debug" ] ; then
15 | PLS_COMPILE_MODE='debug'
16 | fi
17 | if hash $PLS_GCC 2>/dev/null; then
18 | echo "[INFO] Compile app as "$PLS_COMPILE_MODE
19 | else
20 | echo "[FAIL] Could not find required program gcc"
21 | exit 1
22 | fi
23 |
24 | # Check if we are in a project
25 | while [ ! -e "appinfo.json" ]
26 | do
27 | if [ `pwd` == '/' ]
28 | then
29 | echo "[FAIL] Could not find 'appinfo.json' in this directory or any parent" 1>&2
30 | exit 1
31 | fi
32 | cd ..
33 | done
34 |
35 | # Copy resources and app info
36 | mkdir -p ./build/local/
37 | cp -f ./appinfo.json ./build/local/
38 | cp -f -r $PLS_SDK_DIR/simdata/* ./build/local/
39 |
40 | # Check for and copy JS
41 | if [ -e './src/js/pebble-js-app.js' ] ; then
42 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
43 | echo "[WARNING] Windows does not support javascript apps yet"
44 | else
45 | cat $PLS_SDK_DIR/header.js > ./build/local/pebble-js-app-local.js
46 | cat ./src/js/pebble-js-app.js >> ./build/local/pebble-js-app-local.js
47 | fi
48 | fi
49 |
50 | # Compile resources
51 | PLS_RSC=$PLS_SDK_DIR'/resCompiler'
52 | PLS_POST_COMMAND=' '
53 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
54 | PLS_RSC=$PLS_RSC'.exe'
55 | elif [ -e $PLS_SDK_DIR/../../.env/bin/activate ] ; then
56 | # use the virtual environment to access the required python libs
57 | source $PLS_SDK_DIR'/../../.env/bin/activate'
58 | PLS_POST_COMMAND='deactivate'
59 | fi
60 |
61 | error='true'
62 | if $PLS_RSC ; then
63 | error='false'
64 | fi
65 |
66 | $PLS_POST_COMMAND
67 |
68 | if [ "$error" == 'true' ] ; then
69 | echo "[FAIL] Could not compile resources"
70 | exit 1
71 | fi
72 |
73 | # Prepare compile variables
74 | PLS_APP_INCLUDES='-I ./build/tempLocal/ -I ./build/tempLocal/src/'
75 | PLS_APP_LIB_INCLUDES='-L '$PLS_SDK_DIR
76 | PLS_APP_LIBS='-lPLocalSim -lSDL2 -lSDL2_ttf -lSDL2_image -lm -lpthread'
77 | PLS_APP_ARGS='-c -x c -O2 -Wall -std=c99 -DLOCALSIM'
78 | PLS_APP_PATH=`pwd`
79 | PLS_APP_NAME=`basename $PLS_APP_PATH`
80 | PLS_APP_OUT='./build/local/'$PLS_APP_NAME
81 | PLS_SDK_HEADERS=$PLS_SDK_DIR'/include'
82 |
83 | # Special values
84 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
85 | # Windows/MinGW
86 | # ' -I '$PLS_SDK_DIR$PLS_DIR_SDL'/include '
87 | PLS_APP_INCLUDES=$PLS_APP_INCLUDES
88 | PLS_APP_LIB_INCLUDES=$PLS_APP_LIB_INCLUDES' -L '$PLS_DIR_SDL'/lib'
89 | PLS_APP_LIBS='-lmingw32 -lSDL2main '$PLS_APP_LIBS
90 | PLS_APP_ARGS=$PLS_APP_ARGS' -mconsole -DWIN32 -D_WIN32'
91 | PLS_APP_OUT=$PLS_APP_OUT'.exe'
92 | else
93 | # Unix
94 | if [ -e $PLS_SDK_ROOT_DIR/pebble ] ; then
95 | PLS_SDK_HEADERS=$PLS_SDK_DIR'/../../Pebble/include'
96 | fi
97 | fi
98 | PLS_APP_INCLUDES=$PLS_APP_INCLUDES' -isystem '$PLS_SDK_HEADERS
99 |
100 | # Debug flag
101 | if [ "$1" == "--debug" ] ; then
102 | PLS_APP_ARGS=$PLS_APP_ARGS' -ggdb'
103 | fi
104 |
105 | # Compile object files
106 | mkdir -p ./build/tempLocal
107 | rm -f ./build/tempLocal/*.o
108 | filelist='./src/*.c'
109 | PLS_APP_OBJECTS=" "
110 | for file in `ls $filelist` ; do
111 | filename=${file##*/} # without the directory
112 | echo 'Compiling '$filename
113 | objectFile=./build/tempLocal/${filename%.*}'.o'
114 | if $PLS_GCC $PLS_APP_ARGS $PLS_APP_INCLUDES $file -o $objectFile ; then
115 | PLS_APP_OBJECTS=$PLS_APP_OBJECTS' '$objectFile
116 | else
117 | exit 1
118 | fi
119 | done
120 |
121 | echo Linking
122 | $PLS_GCC $PLS_APP_OBJECTS $PLS_APP_LIB_INCLUDES $PLS_APP_LIBS -o $PLS_APP_OUT
123 |
124 |
--------------------------------------------------------------------------------
/sdkdata/common/run.local.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Check if we have access to gcc
4 | PLS_SDK_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
5 | PLS_SDK_DIR=$PLS_SDK_DIR'/PLocalSim'
6 |
7 | if [ ! -e $PLS_SDK_DIR'/envvars.sh' ] ; then
8 | echo "[FAIL] Could not load envvars.sh"
9 | exit 1
10 | fi
11 | source $PLS_SDK_DIR'/envvars.sh'
12 |
13 | if hash $PLS_GDB 2>/dev/null; then
14 | echo "[INFO] Compile app as local simulator"
15 | else
16 | echo "[FAIL] Could not find required program gdb"
17 | exit 1
18 | fi
19 |
20 | PLS_DIR_BACKUP=`pwd`
21 |
22 | # Check if we are in a project
23 | while [ ! -e "appinfo.json" ]
24 | do
25 | if [ `pwd` == '/' ]
26 | then
27 | echo "[FAIL] Could not find 'appinfo.json' in this directory or any parent" 1>&2
28 | exit 1
29 | fi
30 | cd ..
31 | done
32 |
33 | # Run the simulator if we find it
34 | PLS_APP_PATH=`pwd`
35 | PLS_APP_NAME=`basename $PLS_APP_PATH`
36 | PLS_APP_EXEC='./build/local/'$PLS_APP_NAME
37 | if [ -e "$PLS_APP_EXEC" ] ; then
38 | cd build/local
39 |
40 | if [ "$1" == "--debug" ] ; then
41 | $PLS_GDB ./$PLS_APP_NAME
42 | else
43 | ./$PLS_APP_NAME
44 | fi
45 | else
46 | echo "[FAIL] Could not find simulator, maybe it is not compiled yet?"
47 | fi
48 |
49 | cd $PLS_DIR_BACKUP
50 |
--------------------------------------------------------------------------------
/sdkdata/standalone/PLocalSim/projectTemplate/appinfo.json:
--------------------------------------------------------------------------------
1 | {
2 | "uuid": "79a0f865-22da-415d-9764-6012a07a1bd6",
3 | "shortName": "sampleProject",
4 | "longName": "sampleProject",
5 | "companyName": "MakeAwesomeHappen",
6 | "versionCode": 1,
7 | "versionLabel": "1.0.0",
8 | "watchapp": {
9 | "watchface": false
10 | },
11 | "appKeys": {
12 | "dummy": 0
13 | },
14 | "resources": {
15 | "media": []
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/sdkdata/standalone/PLocalSim/projectTemplate/src/sampleProject.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | static Window *window;
4 | static TextLayer *text_layer;
5 |
6 | static void select_click_handler(ClickRecognizerRef recognizer, void *context) {
7 | text_layer_set_text(text_layer, "Select");
8 | }
9 |
10 | static void up_click_handler(ClickRecognizerRef recognizer, void *context) {
11 | text_layer_set_text(text_layer, "Up");
12 | }
13 |
14 | static void down_click_handler(ClickRecognizerRef recognizer, void *context) {
15 | text_layer_set_text(text_layer, "Down");
16 | }
17 |
18 | static void click_config_provider(void *context) {
19 | window_single_click_subscribe(BUTTON_ID_SELECT, select_click_handler);
20 | window_single_click_subscribe(BUTTON_ID_UP, up_click_handler);
21 | window_single_click_subscribe(BUTTON_ID_DOWN, down_click_handler);
22 | }
23 |
24 | static void window_load(Window *window) {
25 | Layer *window_layer = window_get_root_layer(window);
26 | GRect bounds = layer_get_bounds(window_layer);
27 |
28 | text_layer = text_layer_create((GRect) { .origin = { 0, 72 }, .size = { bounds.size.w, 20 } });
29 | text_layer_set_text(text_layer, "Press a button");
30 | text_layer_set_text_alignment(text_layer, GTextAlignmentCenter);
31 | layer_add_child(window_layer, text_layer_get_layer(text_layer));
32 | }
33 |
34 | static void window_unload(Window *window) {
35 | text_layer_destroy(text_layer);
36 | }
37 |
38 | static void init(void) {
39 | window = window_create();
40 | window_set_click_config_provider(window, click_config_provider);
41 | window_set_window_handlers(window, (WindowHandlers) {
42 | .load = window_load,
43 | .unload = window_unload,
44 | });
45 | const bool animated = true;
46 | window_stack_push(window, animated);
47 | }
48 |
49 | static void deinit(void) {
50 | window_destroy(window);
51 | }
52 |
53 | int main(void) {
54 | init();
55 |
56 | APP_LOG(APP_LOG_LEVEL_DEBUG, "Done initializing, pushed window: %p", window);
57 |
58 | app_event_loop();
59 | deinit();
60 |
61 | return 0;
62 | }
63 |
--------------------------------------------------------------------------------
/sdkdata/standalone/create.project.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PLS_SDK_ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
4 | PLS_SDK_DIR=$PLS_SDK_ROOT_DIR'/PLocalSim'
5 |
6 | if [ ! -e $PLS_SDK_DIR'/envvars.sh' ] ; then
7 | echo "[FAIL] Could not load envvars.sh"
8 | exit 1
9 | fi
10 | source $PLS_SDK_DIR'/envvars.sh'
11 |
12 | # Create/Test directory
13 | PLS_TARGET_PATH=$1
14 | if [ -z "$PLS_TARGET_PATH" ] ; then
15 | echo "[FAIL] correct usage: create.project.sh "
16 | exit 1
17 | fi
18 |
19 | mkdir -p $PLS_TARGET_PATH
20 | if [ ! -d "$PLS_TARGET_PATH" ] ; then
21 | echo "[FAIL] Invalid directory: $PLS_TARGET_PATH"
22 | exit 1
23 | fi
24 |
25 | # Copy project template
26 | cp -f -r $PLS_SDK_DIR/projectTemplate/* $PLS_TARGET_PATH'/'
27 |
28 | PLS_EOL='\n'
29 | if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
30 | PLS_EOL='\r\n'
31 |
32 | # Get the sdk path in windows style
33 | PLS_DIR_BACKUP=`pwd`
34 | cd $PLS_SDK_ROOT_DIR
35 | PLS_SDK_DIR_WIN=`pwd -W`
36 | cd $PLS_DIR_BACKUP
37 |
38 | # Generate openShell.bat
39 | PLS_OPEN_SHELL_BAT='@"'$PLS_SDK_DIR_WIN'/openShell.bat'
40 | echo $PLS_OPEN_SHELL_BAT > $PLS_TARGET_PATH'/openShell.bat'
41 | fi
42 |
43 | # Generate build.local.bat
44 | echo -e "#!/bin/bash$PLS_EOL" > $PLS_TARGET_PATH'/build.local.sh'
45 | echo '"'$PLS_SDK_ROOT_DIR'/build.local.sh" $@' >> $PLS_TARGET_PATH'/build.local.sh'
46 |
47 | # Generate run.local.bat
48 | echo -e "#!/bin/bash$PLS_EOL" > $PLS_TARGET_PATH'/run.local.sh'
49 | echo '"'$PLS_SDK_ROOT_DIR'/run.local.sh" $@' >> $PLS_TARGET_PATH'/run.local.sh'
50 |
--------------------------------------------------------------------------------
/sdkdata/unix/PLocalSim/appjs_header.js:
--------------------------------------------------------------------------------
1 | /////////////////////////////////////////////////
2 | // Standard header to setup Pebble environment
3 |
4 | var Pebble = require('./simdata/server');
5 |
6 | var window = window || {};
7 | window.navigator = { };
8 | window.navigator.geolocation = Pebble.geolocation;
9 |
10 | var localStorage = new (require('./simdata/localStorage').Storage)("localStorage.dat");
11 |
12 | var XMLHttpRequest = require('./simdata/XMLHttpRequest').XMLHttpRequest;
13 |
14 | console.log = ((function() {
15 | var orig_log = console.log;
16 | return function() {
17 | if ((arguments.length > 0) &&
18 | (typeof(arguments[0]) === 'string'))
19 | arguments[0] = "[JS App] " + arguments[0];
20 |
21 | orig_log.apply(console, arguments);
22 | };
23 | })());
24 |
25 | /////////////////////////////////////////////////
26 |
27 |
28 |
--------------------------------------------------------------------------------
/sdkdata/unix/PLocalSim/envvars.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PLS_GCC="gcc"
4 | PLS_AR="ar"
5 | PLS_GDB="gdb"
6 |
--------------------------------------------------------------------------------
/sdkdata/windows/PLocalSim/envvars.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PLS_GCC=$PLS_SDK_DIR'/MinGW/bin/gcc.exe'
4 | PLS_AR=$PLS_SDK_DIR'/MinGW/bin/ar.exe'
5 | PLS_GDB=$PLS_SDK_DIR'/MinGW/bin/gdb.exe'
6 | PLS_DIR_SDL=$PLS_SDK_DIR'/SDL2'
7 |
--------------------------------------------------------------------------------
/sdkdata/windows/openShell.bat:
--------------------------------------------------------------------------------
1 | @REM This is just a small file to start bash in the current directory
2 | @PATH=%PATH%;%~dp0\PLocalSim\MinGW\bin\
3 | @%~dp0\PLocalSim\MinGW\msys\1.0\msys.bat %~dp0
--------------------------------------------------------------------------------
/simdata/common/LICENSE.freetype.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/LICENSE.freetype.txt
--------------------------------------------------------------------------------
/simdata/common/LICENSE.png.txt:
--------------------------------------------------------------------------------
1 | The source code to this library used with SDL_image can be found here:
2 | http://www.libsdl.org/projects/SDL_image/libs/
3 | ---
4 |
5 | This copy of the libpng notices is provided for your convenience. In case of
6 | any discrepancy between this copy and the notices in the file png.h that is
7 | included in the libpng distribution, the latter shall prevail.
8 |
9 | COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
10 |
11 | If you modify libpng you may insert additional notices immediately following
12 | this sentence.
13 |
14 | This code is released under the libpng license.
15 |
16 | libpng versions 1.2.6, August 15, 2004, through 1.5.7, December 15, 2011, are
17 | Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
18 | distributed according to the same disclaimer and license as libpng-1.2.5
19 | with the following individual added to the list of Contributing Authors
20 |
21 | Cosmin Truta
22 |
23 | libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are
24 | Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
25 | distributed according to the same disclaimer and license as libpng-1.0.6
26 | with the following individuals added to the list of Contributing Authors
27 |
28 | Simon-Pierre Cadieux
29 | Eric S. Raymond
30 | Gilles Vollant
31 |
32 | and with the following additions to the disclaimer:
33 |
34 | There is no warranty against interference with your enjoyment of the
35 | library or against infringement. There is no warranty that our
36 | efforts or the library will fulfill any of your particular purposes
37 | or needs. This library is provided with all faults, and the entire
38 | risk of satisfactory quality, performance, accuracy, and effort is with
39 | the user.
40 |
41 | libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
42 | Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are
43 | distributed according to the same disclaimer and license as libpng-0.96,
44 | with the following individuals added to the list of Contributing Authors:
45 |
46 | Tom Lane
47 | Glenn Randers-Pehrson
48 | Willem van Schaik
49 |
50 | libpng versions 0.89, June 1996, through 0.96, May 1997, are
51 | Copyright (c) 1996, 1997 Andreas Dilger
52 | Distributed according to the same disclaimer and license as libpng-0.88,
53 | with the following individuals added to the list of Contributing Authors:
54 |
55 | John Bowler
56 | Kevin Bracey
57 | Sam Bushell
58 | Magnus Holmgren
59 | Greg Roelofs
60 | Tom Tanner
61 |
62 | libpng versions 0.5, May 1995, through 0.88, January 1996, are
63 | Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
64 |
65 | For the purposes of this copyright and license, "Contributing Authors"
66 | is defined as the following set of individuals:
67 |
68 | Andreas Dilger
69 | Dave Martindale
70 | Guy Eric Schalnat
71 | Paul Schmidt
72 | Tim Wegner
73 |
74 | The PNG Reference Library is supplied "AS IS". The Contributing Authors
75 | and Group 42, Inc. disclaim all warranties, expressed or implied,
76 | including, without limitation, the warranties of merchantability and of
77 | fitness for any purpose. The Contributing Authors and Group 42, Inc.
78 | assume no liability for direct, indirect, incidental, special, exemplary,
79 | or consequential damages, which may result from the use of the PNG
80 | Reference Library, even if advised of the possibility of such damage.
81 |
82 | Permission is hereby granted to use, copy, modify, and distribute this
83 | source code, or portions hereof, for any purpose, without fee, subject
84 | to the following restrictions:
85 |
86 | 1. The origin of this source code must not be misrepresented.
87 |
88 | 2. Altered versions must be plainly marked as such and must not
89 | be misrepresented as being the original source.
90 |
91 | 3. This Copyright notice may not be removed or altered from any
92 | source or altered source distribution.
93 |
94 | The Contributing Authors and Group 42, Inc. specifically permit, without
95 | fee, and encourage the use of this source code as a component to
96 | supporting the PNG file format in commercial products. If you use this
97 | source code in a product, acknowledgment is not required but would be
98 | appreciated.
99 |
100 |
101 | A "png_get_copyright" function is available, for convenient use in "about"
102 | boxes and the like:
103 |
104 | printf("%s",png_get_copyright(NULL));
105 |
106 | Also, the PNG logo (in PNG format, of course) is supplied in the
107 | files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
108 |
109 | Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a
110 | certification mark of the Open Source Initiative.
111 |
112 | Glenn Randers-Pehrson
113 | glennrp at users.sourceforge.net
114 | December 15, 2011
115 |
--------------------------------------------------------------------------------
/simdata/common/LICENSE.zlib.txt:
--------------------------------------------------------------------------------
1 | The source code to this library used with SDL_ttf can be found here:
2 | http://www.libsdl.org/projects/SDL_ttf/libs/
3 | ---
4 |
5 | Copyright notice:
6 |
7 | (C) 1995-2010 Jean-loup Gailly and Mark Adler
8 |
9 | This software is provided 'as-is', without any express or implied
10 | warranty. In no event will the authors be held liable for any damages
11 | arising from the use of this software.
12 |
13 | Permission is granted to anyone to use this software for any purpose,
14 | including commercial applications, and to alter it and redistribute it
15 | freely, subject to the following restrictions:
16 |
17 | 1. The origin of this software must not be misrepresented; you must not
18 | claim that you wrote the original software. If you use this software
19 | in a product, an acknowledgment in the product documentation would be
20 | appreciated but is not required.
21 | 2. Altered source versions must be plainly marked as such, and must not be
22 | misrepresented as being the original software.
23 | 3. This notice may not be removed or altered from any source distribution.
24 |
25 | Jean-loup Gailly Mark Adler
26 | jloup@gzip.org madler@alumni.caltech.edu
27 |
28 | If you use the zlib library in a product, we would appreciate *not* receiving
29 | lengthy legal documents to sign. The sources are provided for free but without
30 | warranty of any kind. The library has been entirely written by Jean-loup
31 | Gailly and Mark Adler; it does not include third-party code.
32 |
--------------------------------------------------------------------------------
/simdata/common/images/backlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/images/backlight.png
--------------------------------------------------------------------------------
/simdata/common/images/body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/images/body.png
--------------------------------------------------------------------------------
/simdata/common/images/screenshadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/images/screenshadow.png
--------------------------------------------------------------------------------
/simdata/common/images/scrollshadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/images/scrollshadow.png
--------------------------------------------------------------------------------
/simdata/common/images/statusbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/images/statusbar.png
--------------------------------------------------------------------------------
/simdata/common/images/vibe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/images/vibe.png
--------------------------------------------------------------------------------
/simdata/common/systemFonts/Google Android License.txt:
--------------------------------------------------------------------------------
1 | Copyright (C) 2008 The Android Open Source Project
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
15 | ##########
16 |
17 | This directory contains the fonts for the platform. They are licensed
18 | under the Apache 2 license.
19 |
20 | ##########
21 |
22 | A note from Helco:
23 |
24 | All other fonts whose names begin with "gothic" or "bitham" are
25 | "droidserif-regular.ttf" or "droidserif-bold.ttf". This has to be done
26 | because gothic and bitham (gotham?) are commercial fonts and therefore
27 | can not be used in this free simulator.
28 | If you have these fonts you can replace them without changing a single
29 | character in the source code of this simulator.
--------------------------------------------------------------------------------
/simdata/common/systemFonts/bitham-black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/systemFonts/bitham-black.ttf
--------------------------------------------------------------------------------
/simdata/common/systemFonts/bitham-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/systemFonts/bitham-bold.ttf
--------------------------------------------------------------------------------
/simdata/common/systemFonts/bitham-light-subset.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/systemFonts/bitham-light-subset.ttf
--------------------------------------------------------------------------------
/simdata/common/systemFonts/bitham-light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/systemFonts/bitham-light.ttf
--------------------------------------------------------------------------------
/simdata/common/systemFonts/bitham-medium-numbers.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/systemFonts/bitham-medium-numbers.ttf
--------------------------------------------------------------------------------
/simdata/common/systemFonts/droid-serif-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/systemFonts/droid-serif-bold.ttf
--------------------------------------------------------------------------------
/simdata/common/systemFonts/gothic-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/systemFonts/gothic-bold.ttf
--------------------------------------------------------------------------------
/simdata/common/systemFonts/gothic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/systemFonts/gothic.ttf
--------------------------------------------------------------------------------
/simdata/common/systemFonts/roboto-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/systemFonts/roboto-bold.ttf
--------------------------------------------------------------------------------
/simdata/common/systemFonts/roboto-condensed.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/common/systemFonts/roboto-condensed.ttf
--------------------------------------------------------------------------------
/simdata/unix/server.js:
--------------------------------------------------------------------------------
1 | var net = require("net");
2 | var fs = require("fs");
3 |
4 | // event listener callbacks
5 | var readyFunc = null;
6 | var messageFunc = null;
7 |
8 | // part of Pebble API
9 | module.exports.addEventListener = function(event, fn) {
10 | if (typeof(fn) !== 'function')
11 | return;
12 |
13 | if (event === "ready")
14 | readyFunc = fn;
15 | else if (event == "appmessage")
16 | messageFunc = fn;
17 | else if (event == "webviewclosed")
18 | ;
19 | else
20 | throw "Invalid Event";
21 |
22 | console.log("[INFO] Added event listener for: " + event);
23 | };
24 |
25 | // helper class to translate keys to friendly name and vice versa
26 | function KeyTranslator(filename) {
27 | this.nameToKey = null;
28 | this.keyToName = null;
29 |
30 | // pull out friendly names from appKeys section of appinfo.json
31 | try {
32 | var contents = fs.readFileSync("appinfo.json");
33 | contents = JSON.parse(contents);
34 | if (contents.appKeys) {
35 | this.nameToKey = contents.appKeys;
36 | this.keyToName = { };
37 | for (var n in contents.appKeys) {
38 | if (contents.appKeys.hasOwnProperty(n)) {
39 | this.keyToName[contents.appKeys[n]] = n;
40 | }
41 | }
42 | }
43 | }
44 | catch(e) {
45 | // appinfo.json should be there but swallow error if it isnt
46 | console.log("[WARN] appinfo.json could not be read");
47 | }
48 | }
49 |
50 | // name --> key (integer)
51 | KeyTranslator.prototype.translateName = function(name) {
52 | if (!this.nameToKey || (this.nameToKey[name]==undefined)) {
53 | var ikey = parseInt(name);
54 | if (isNaN(ikey))
55 | throw "Invalid Key";
56 | return ikey;
57 | }
58 |
59 | return this.nameToKey[name];
60 | };
61 |
62 | // key --> name (string)
63 | // non-translated name is just key cast to string
64 | KeyTranslator.prototype.translateKey = function(key) {
65 | if (!this.keyToName)
66 | return new String(key);
67 |
68 | if (!this.keyToName[key])
69 | return new String(key);
70 |
71 | return this.keyToName[key];
72 | };
73 |
74 | // helper class for paring buffer to JSON
75 | function MessageParser(keyTranslator) {
76 | this.keyTranslator = keyTranslator;
77 | }
78 |
79 | // type map
80 | MessageParser.prototype.TupleTypes = {
81 | BYTE_ARRAY: 0,
82 | CSTRING: 1,
83 | UINT: 2,
84 | INT: 3
85 | };
86 |
87 | // buffer --> JSON
88 | MessageParser.prototype.parse = function(buffer) {
89 | var msg = { };
90 |
91 | for (var i = 0; i < buffer.length; ) {
92 | var key = this.keyTranslator.translateKey(buffer.readUInt32LE(i));
93 | var type = buffer.readUInt8(i + 4);
94 | var length = buffer.readUInt16LE(i + 5);
95 |
96 | var value;
97 | if (type == this.TupleTypes.BYTE_ARRAY) {
98 | value = [];
99 | for (var x = i+7; x < (i+length+7); ++x)
100 | value.push(buffer.readUInt8(x));
101 | }
102 | else if (type == this.TupleTypes.CSTRING) {
103 | value = buffer.toString("utf8", i+7, i+length+7-1);
104 | }
105 | else if (type == this.TupleTypes.UINT) {
106 | if (length == 1)
107 | value = buffer.readUInt8(i+7);
108 | else if (length == 2)
109 | value = buffer.readUInt16LE(i+7);
110 | else if (length == 4)
111 | value = buffer.readUInt32LE(i+7);
112 | }
113 | else if (type == this.TupleTypes.INT) {
114 | if (length == 1)
115 | value = buffer.readInt8(i+7);
116 | else if (length == 2)
117 | value = buffer.readInt16LE(i+7);
118 | else if (length == 4)
119 | value = buffer.readInt32LE(i+7);
120 | }
121 | else {
122 | console.log("[ERROR] Corrupt Message");
123 | throw "Corrupt Message";
124 | }
125 |
126 | msg[key] = value;
127 | i += 7 + length;
128 | }
129 |
130 | return msg;
131 | };
132 |
133 | MessageParser.prototype.serializeMsg = function(msg) {
134 | // compute size
135 | var size = 0;
136 | for (var k in msg) {
137 | if (msg.hasOwnProperty(k)) {
138 | size += 7;
139 |
140 | if (typeof(msg[k]) == "string")
141 | size += msg[k].length+1;
142 | else if (typeof(msg[k]) == "number")
143 | size += 4; // assume 32-bit
144 | else if (typeof(msg[k]) == "array")
145 | size += msg[k].length;
146 | else
147 | throw "Unable to serialize message";
148 | }
149 | }
150 |
151 | // allocate buffer
152 | var buffer = new Buffer(size+2);
153 |
154 | // serialize
155 | var offset = 0;
156 | buffer.writeUInt16LE(size, offset);
157 | offset += 2;
158 | for (var k in msg) {
159 | if (msg.hasOwnProperty(k)) {
160 | // key
161 | buffer.writeUInt32LE(this.keyTranslator.translateName(k), offset);
162 |
163 | // type, length, and data
164 | var dataSize = 0
165 | if (typeof(msg[k]) == "string") {
166 | buffer.writeUInt8(this.TupleTypes.CSTRING, offset+4);
167 | dataSize = msg[k].length+1;
168 | buffer.writeUInt16LE(dataSize, offset+5);
169 | buffer.write(msg[k], offset+7, dataSize-1);
170 | buffer.writeUInt8(0, offset+7+dataSize-1);
171 | }
172 | else if (typeof(msg[k]) == "number") {
173 | buffer.writeUInt8(this.TupleTypes.INT, offset+4); // assume signed
174 | dataSize = 4; // assume 32-bit
175 | buffer.writeUInt16LE(dataSize, offset+5);
176 | buffer.writeInt32LE(msg[k], offset+7);
177 | }
178 | else if (typeof(msg[k]) == "array") {
179 | buffer.writeUInt8(this.TupleTypes.BYTE_ARRAY, offset+4);
180 | dataSize = msg[k].length;
181 | buffer.writeUInt16LE(dataSize, offset+5);
182 | for (var x = 0; x < dataSize; ++x) {
183 | if (typeof(msg[k]) !== "number")
184 | throw "Invalid Byte Array";
185 | buffer.writeUInt8(msg[k][x], offset+7+x);
186 | }
187 | }
188 |
189 | offset += 7 + dataSize;
190 | }
191 | }
192 |
193 | return buffer;
194 | };
195 |
196 | // parser to be used by server
197 | var msgParser = new MessageParser(new KeyTranslator("appinfo.json"));
198 |
199 | // the receiving server
200 | var server = net.createServer(function(c) {
201 | var States = {
202 | ReadingSize: 1, // expecting size
203 | ReadingData: 2 // expecting data
204 | };
205 |
206 | var currentState = States.ReadingSize;
207 | var firstRead = true; // no handshake yet
208 | var bytesToRead;
209 |
210 | // will be called when there is some data to read
211 | var attemptRead = function(c) {
212 | if (currentState == States.ReadingSize) {
213 | // attempt to read 16-bit size
214 | var r = c.read(2);
215 | if (!r) // 2-bytes not available yet
216 | return false;
217 |
218 | bytesToRead = (new Buffer(r)).readUInt16LE(0);
219 | currentState = States.ReadingData;
220 | }
221 | else {
222 | // attempt to read actual data
223 | // if bytesToRead isn't available null is returned
224 | // we want to wait until the entire message is available
225 | var raw = c.read(bytesToRead);
226 | if (!raw)
227 | return false;
228 |
229 | var buffer = new Buffer(raw);
230 | currentState = States.ReadingSize;
231 | if (firstRead) {
232 | // handshake
233 | firstRead = false;
234 | if (buffer.toString() === "READY") {
235 | console.log("[INFO] Handshake Completed - ready event called")
236 | if (readyFunc)
237 | readyFunc({ ready: true, type: "ready" });
238 | }
239 | else {
240 | console.log("[ERROR] Handshake Failed");
241 | throw "Hanshake Failed";
242 | }
243 | }
244 | else {
245 | // have whole message, so now parse and notify on appmessage event
246 | var msg = msgParser.parse(buffer);
247 | if (messageFunc)
248 | messageFunc({ type: "appmessage", payload: msg });
249 | }
250 | }
251 |
252 | return true;
253 | };
254 |
255 | console.log("[INFO] Server Connected");
256 |
257 | // called when there is data to read
258 | c.on("readable", function() {
259 | // keep trying while there is data to read
260 | while (attemptRead(c)) { }
261 | });
262 | });
263 |
264 | // start the actual server
265 | server.listen(8321, function() {
266 | console.log("[INFO] Server Started");
267 | })
268 |
269 | // part of Pebble API
270 | module.exports.sendAppMessage = function(msg, fnAck, fnNack) {
271 | var buffer = msgParser.serializeMsg(msg);
272 |
273 | var client = net.connect({ port: 8322 }, function() {
274 | client.write(buffer);
275 |
276 | if (fnAck)
277 | fnAck(msg);
278 | });
279 | };
280 |
281 | // part of Pebble API
282 | module.exports.getAccountToken = function() {
283 | return "A1B2C3D4E5F6G7H8I9J0"; // obviously a dummy value
284 | };
285 |
286 | // mock Geolocation API
287 | module.exports.geolocation = {
288 | watchPosition: function() {
289 | // do nothing
290 | },
291 | getCurrentPosition: function(fnSuccess, fnFailure, options) {
292 | fnSuccess({
293 | coords: {
294 | latitude: 40.75907,
295 | longitude: -73.98507
296 | }
297 | });
298 | }
299 | };
300 |
--------------------------------------------------------------------------------
/simdata/windows/SDL2.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/windows/SDL2.dll
--------------------------------------------------------------------------------
/simdata/windows/SDL2_image.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/windows/SDL2_image.dll
--------------------------------------------------------------------------------
/simdata/windows/SDL2_ttf.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/windows/SDL2_ttf.dll
--------------------------------------------------------------------------------
/simdata/windows/libfreetype-6.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/windows/libfreetype-6.dll
--------------------------------------------------------------------------------
/simdata/windows/libpng16-16.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/windows/libpng16-16.dll
--------------------------------------------------------------------------------
/simdata/windows/zlib1.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/simdata/windows/zlib1.dll
--------------------------------------------------------------------------------
/src/SDL_gfx/SDL_gfxBlitFunc.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | SDL_gfxBlitFunc.h: custom blitters
4 |
5 | Copyright (C) 2001-2012 Andreas Schiffler
6 |
7 | This software is provided 'as-is', without any express or implied
8 | warranty. In no event will the authors be held liable for any damages
9 | arising from the use of this software.
10 |
11 | Permission is granted to anyone to use this software for any purpose,
12 | including commercial applications, and to alter it and redistribute it
13 | freely, subject to the following restrictions:
14 |
15 | 1. The origin of this software must not be misrepresented; you must not
16 | claim that you wrote the original software. If you use this software
17 | in a product, an acknowledgment in the product documentation would be
18 | appreciated but is not required.
19 |
20 | 2. Altered source versions must be plainly marked as such, and must not be
21 | misrepresented as being the original software.
22 |
23 | 3. This notice may not be removed or altered from any source
24 | distribution.
25 |
26 | Andreas Schiffler -- aschiffler at ferzkopp dot net
27 |
28 | */
29 |
30 | #ifndef _SDL_gfxBlitFunc_h
31 | #define _SDL_gfxBlitFunc_h
32 |
33 | /* Set up for C function definitions, even when using C++ */
34 | #ifdef __cplusplus
35 | extern "C" {
36 | #endif
37 |
38 | #include
39 | #include
40 |
41 | //Helco: Use the new headers
42 | #include
43 | #include
44 |
45 |
46 | extern const unsigned int GFX_ALPHA_ADJUST_ARRAY[256];
47 |
48 | /* ---- Function Prototypes */
49 |
50 | #ifdef _MSC_VER
51 | # if defined(DLL_EXPORT) && !defined(LIBSDL_GFX_DLL_IMPORT)
52 | # define SDL_GFXBLITFUNC_SCOPE __declspec(dllexport)
53 | # else
54 | # ifdef LIBSDL_GFX_DLL_IMPORT
55 | # define SDL_GFXBLITFUNC_SCOPE __declspec(dllimport)
56 | # endif
57 | # endif
58 | #endif
59 | #ifndef SDL_GFXBLITFUNC_SCOPE
60 | # define SDL_GFXBLITFUNC_SCOPE extern
61 | #endif
62 |
63 |
64 | SDL_GFXBLITFUNC_SCOPE int SDL_gfxBlitRGBA(SDL_Surface * src, SDL_Rect * srcrect, SDL_Surface * dst, SDL_Rect * dstrect);
65 |
66 | SDL_GFXBLITFUNC_SCOPE int SDL_gfxSetAlpha(SDL_Surface * src, Uint8 a);
67 |
68 | SDL_GFXBLITFUNC_SCOPE int SDL_gfxMultiplyAlpha(SDL_Surface * src, Uint8 a);
69 |
70 | /* -------- Macros */
71 |
72 | /* Define SDL macros locally as a substitute for an #include "SDL_blit.h", */
73 | /* which doesn't work since the include file doesn't get installed. */
74 |
75 | /*!
76 | \brief The structure passed to the low level blit functions.
77 | */
78 | typedef struct {
79 | Uint8 *s_pixels;
80 | int s_width;
81 | int s_height;
82 | int s_skip;
83 | Uint8 *d_pixels;
84 | int d_width;
85 | int d_height;
86 | int d_skip;
87 | void *aux_data;
88 | SDL_PixelFormat *src;
89 | Uint8 *table;
90 | SDL_PixelFormat *dst;
91 | } SDL_gfxBlitInfo;
92 |
93 | /*!
94 | \brief Unwrap RGBA values from a pixel using mask, shift and loss for surface.
95 | */
96 | #define GFX_RGBA_FROM_PIXEL(pixel, fmt, r, g, b, a) \
97 | { \
98 | r = ((pixel&fmt->Rmask)>>fmt->Rshift)<Rloss; \
99 | g = ((pixel&fmt->Gmask)>>fmt->Gshift)<Gloss; \
100 | b = ((pixel&fmt->Bmask)>>fmt->Bshift)<Bloss; \
101 | a = ((pixel&fmt->Amask)>>fmt->Ashift)<Aloss; \
102 | }
103 |
104 | /*!
105 | \brief Disassemble buffer pointer into a pixel and separate RGBA values.
106 | */
107 | #define GFX_DISASSEMBLE_RGBA(buf, bpp, fmt, pixel, r, g, b, a) \
108 | do { \
109 | pixel = *((Uint32 *)(buf)); \
110 | GFX_RGBA_FROM_PIXEL(pixel, fmt, r, g, b, a); \
111 | pixel &= ~fmt->Amask; \
112 | } while(0)
113 |
114 | /*!
115 | \brief Wrap a pixel from RGBA values using mask, shift and loss for surface.
116 | */
117 | #define GFX_PIXEL_FROM_RGBA(pixel, fmt, r, g, b, a) \
118 | { \
119 | pixel = ((r>>fmt->Rloss)<Rshift)| \
120 | ((g>>fmt->Gloss)<Gshift)| \
121 | ((b>>fmt->Bloss)<Bshift)| \
122 | ((a<Aloss)<Ashift); \
123 | }
124 |
125 | /*!
126 | \brief Assemble pixel into buffer pointer from separate RGBA values.
127 | */
128 | #define GFX_ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a) \
129 | { \
130 | Uint32 pixel; \
131 | \
132 | GFX_PIXEL_FROM_RGBA(pixel, fmt, r, g, b, a); \
133 | *((Uint32 *)(buf)) = pixel; \
134 | }
135 |
136 | /*!
137 | \brief Blend the RGB values of two pixels based on a source alpha value.
138 | */
139 | #define GFX_ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB) \
140 | do { \
141 | dR = (((sR-dR)*(A))/255)+dR; \
142 | dG = (((sG-dG)*(A))/255)+dG; \
143 | dB = (((sB-dB)*(A))/255)+dB; \
144 | } while(0)
145 |
146 | /*!
147 | \brief 4-times unrolled DUFFs loop.
148 |
149 | This is a very useful loop for optimizing blitters.
150 | */
151 | #define GFX_DUFFS_LOOP4(pixel_copy_increment, width) \
152 | { int n = (width+3)/4; \
153 | switch (width & 3) { \
154 | case 0: do { pixel_copy_increment; \
155 | case 3: pixel_copy_increment; \
156 | case 2: pixel_copy_increment; \
157 | case 1: pixel_copy_increment; \
158 | } while ( --n > 0 ); \
159 | } \
160 | }
161 |
162 |
163 |
164 | /* Ends C function definitions when using C++ */
165 | #ifdef __cplusplus
166 | }
167 | #endif
168 |
169 | #endif /* _SDL_gfxBlitFunc_h */
170 |
--------------------------------------------------------------------------------
/src/SDL_gfx/SDL_gfxPrimitives_font.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Helco/PLocalSim/01c8a16d5ff31bc1d3b75a703cc80adfbc9fd221/src/SDL_gfx/SDL_gfxPrimitives_font.h
--------------------------------------------------------------------------------
/src/SDL_gfx/SDL_rotozoom.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
4 |
5 | Copyright (C) 2001-2012 Andreas Schiffler
6 |
7 | This software is provided 'as-is', without any express or implied
8 | warranty. In no event will the authors be held liable for any damages
9 | arising from the use of this software.
10 |
11 | Permission is granted to anyone to use this software for any purpose,
12 | including commercial applications, and to alter it and redistribute it
13 | freely, subject to the following restrictions:
14 |
15 | 1. The origin of this software must not be misrepresented; you must not
16 | claim that you wrote the original software. If you use this software
17 | in a product, an acknowledgment in the product documentation would be
18 | appreciated but is not required.
19 |
20 | 2. Altered source versions must be plainly marked as such, and must not be
21 | misrepresented as being the original software.
22 |
23 | 3. This notice may not be removed or altered from any source
24 | distribution.
25 |
26 | Andreas Schiffler -- aschiffler at ferzkopp dot net
27 |
28 | */
29 |
30 | #ifndef _SDL_rotozoom_h
31 | #define _SDL_rotozoom_h
32 |
33 | #include
34 |
35 | /* Set up for C function definitions, even when using C++ */
36 | #ifdef __cplusplus
37 | extern "C" {
38 | #endif
39 |
40 | #ifndef M_PI
41 | #define M_PI 3.141592654
42 | #endif
43 |
44 | //Helco: Use the new headers
45 | #include
46 |
47 | /* ---- Defines */
48 |
49 | /*!
50 | \brief Disable anti-aliasing (no smoothing).
51 | */
52 | #define SMOOTHING_OFF 0
53 |
54 | /*!
55 | \brief Enable anti-aliasing (smoothing).
56 | */
57 | #define SMOOTHING_ON 1
58 |
59 | /* ---- Function Prototypes */
60 |
61 | #ifdef _MSC_VER
62 | # if defined(DLL_EXPORT) && !defined(LIBSDL_GFX_DLL_IMPORT)
63 | # define SDL_ROTOZOOM_SCOPE __declspec(dllexport)
64 | # else
65 | # ifdef LIBSDL_GFX_DLL_IMPORT
66 | # define SDL_ROTOZOOM_SCOPE __declspec(dllimport)
67 | # endif
68 | # endif
69 | #endif
70 | #ifndef SDL_ROTOZOOM_SCOPE
71 | # define SDL_ROTOZOOM_SCOPE extern
72 | #endif
73 |
74 | /*
75 |
76 | Rotozoom functions
77 |
78 | */
79 |
80 | SDL_ROTOZOOM_SCOPE SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth);
81 |
82 | SDL_ROTOZOOM_SCOPE SDL_Surface *rotozoomSurfaceXY
83 | (SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth);
84 |
85 |
86 | SDL_ROTOZOOM_SCOPE void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth,
87 | int *dstheight);
88 |
89 | SDL_ROTOZOOM_SCOPE void rotozoomSurfaceSizeXY
90 | (int width, int height, double angle, double zoomx, double zoomy,
91 | int *dstwidth, int *dstheight);
92 |
93 | /*
94 |
95 | Zooming functions
96 |
97 | */
98 |
99 | SDL_ROTOZOOM_SCOPE SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth);
100 |
101 | SDL_ROTOZOOM_SCOPE void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight);
102 |
103 | /*
104 |
105 | Shrinking functions
106 |
107 | */
108 |
109 | SDL_ROTOZOOM_SCOPE SDL_Surface *shrinkSurface(SDL_Surface * src, int factorx, int factory);
110 |
111 | /*
112 |
113 | Specialized rotation functions
114 |
115 | */
116 |
117 | SDL_ROTOZOOM_SCOPE SDL_Surface* rotateSurface90Degrees(SDL_Surface* src, int numClockwiseTurns);
118 |
119 | /* Ends C function definitions when using C++ */
120 | #ifdef __cplusplus
121 | }
122 | #endif
123 |
124 | #endif /* _SDL_rotozoom_h */
125 |
--------------------------------------------------------------------------------
/src/SDL_gfx/disclaimer.txt:
--------------------------------------------------------------------------------
1 | These source files are based of the SDL_gfx library written by Andreas Schiffler and
2 | originally stand under the license text you find in every source file.
3 | To be compatible with SDL2 (and still using surfaces instead of renderer/texture )
4 | I modified following files:
5 |
6 | 1. SDL_gfxBlitFunc.c
7 | 2. SDL_rotozoom.c
8 | 3. SDL_gfxPrimitives.c
9 |
10 | All changes should have been marked with a comment starting with "Helco"
11 | To achieve a full compatibility this modified version of SDL_gfx stands under the same
12 | license as its base
--------------------------------------------------------------------------------
/src/js_server/lib/localStorage.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var _ = require('lodash');
3 |
4 | var storage_to_save = []; // used to store info for saving later
5 |
6 | // helper function to pull out all data keys (which happen to
7 | // be all strings)
8 | function getDataKeys(storage) {
9 | return _.filter(_.keys(storage), function(k) {
10 | return (typeof(storage[k]) === 'string');
11 | });
12 | }
13 |
14 | // Storage class
15 | // takes optional filename for backing store
16 | // if left blank storage will not persist
17 | var Storage = function(filename) {
18 | var that = this;
19 |
20 | // compute length on the fly because of direct property access
21 | Object.defineProperty(this, "length", {
22 | get: function() {
23 | return getDataKeys(this).length;
24 | },
25 | set: function() { } // do nothing
26 | });
27 |
28 | // load
29 | if (filename) {
30 | try {
31 | var raw = fs.readFileSync(filename);
32 | if (raw)
33 | _.defaults(this, JSON.parse(raw));
34 | }
35 | catch(e) {
36 | // swallow error if can't read
37 | }
38 |
39 | // add to list to save
40 | storage_to_save.push({ file: filename, storage: this });
41 | }
42 | };
43 |
44 | Storage.prototype.setItem = function(key, value) {
45 | this[key.toString()] = value.toString();
46 | };
47 |
48 | Storage.prototype.getItem = function(key) {
49 | var skey = key.toString();
50 |
51 | if (!this[skey])
52 | return null;
53 |
54 | return this[skey];
55 | };
56 |
57 | Storage.prototype.removeItem = function(key) {
58 | var skey = key.toString();
59 |
60 | if (!this[skey])
61 | return;
62 | if (typeof(this[skey]) !== 'string')
63 | return;
64 |
65 | delete this[skey];
66 | };
67 |
68 | Storage.prototype.clear = function() {
69 | _.forEach(getDataKeys(this), function(k) {
70 | delete this[k];
71 | }, this);
72 | };
73 |
74 | Storage.prototype.key = function(n) {
75 | if (typeof(n) !== 'number')
76 | return null;
77 |
78 | if (n < 0)
79 | return null;
80 |
81 | var skeys = getDataKeys(this);
82 | if (n >= skeys.length)
83 | return null;
84 |
85 | return skeys[n];
86 | };
87 |
88 | function saveStorageItem(sitem) {
89 | // prepare data
90 | var dataKeys = getDataKeys(sitem.storage);
91 | var data = { };
92 | _.forEach(dataKeys, function(k) {
93 | data[k] = sitem.storage.getItem(k);
94 | });
95 |
96 | // actual write
97 | try {
98 | fs.writeFileSync(sitem.file, JSON.stringify(data));
99 | }
100 | catch (e) {
101 | console.log("[ERROR] Error Saving localStorage (" + sitem.file + "): " + e);
102 | }
103 | }
104 |
105 | // function to force save
106 | // (meant to be used for testing)
107 | module.exports._forceSave = function(storage) {
108 | var sitem = _.where(storage_to_save, { 'storage': storage });
109 | if (!sitem || !sitem.length)
110 | throw "Can't find Storage in storage_to_save list";
111 | saveStorageItem(sitem[0]);
112 | };
113 |
114 | // save on exit
115 | process.on('exit', function() {
116 | _.forEach(storage_to_save, saveStorageItem);
117 | });
118 |
119 | // save on kill
120 | process.on('SIGTERM', function() {
121 | _.forEach(storage_to_save, saveStorageItem);
122 | process.exit(0);
123 | });
124 |
125 | module.exports.Storage = Storage;
--------------------------------------------------------------------------------
/src/js_server/server.js:
--------------------------------------------------------------------------------
1 | var net = require("net");
2 | var fs = require("fs");
3 |
4 | // event listener callbacks
5 | var readyFunc = null;
6 | var messageFunc = null;
7 |
8 | // part of Pebble API
9 | module.exports.addEventListener = function(event, fn) {
10 | if (typeof(fn) !== 'function')
11 | return;
12 |
13 | if (event === "ready")
14 | readyFunc = fn;
15 | else if (event == "appmessage")
16 | messageFunc = fn;
17 | else if (event == "webviewclosed")
18 | ;
19 | else
20 | throw "Invalid Event";
21 |
22 | console.log("[INFO] Added event listener for: " + event);
23 | };
24 |
25 | // helper class to translate keys to friendly name and vice versa
26 | function KeyTranslator(filename) {
27 | this.nameToKey = null;
28 | this.keyToName = null;
29 |
30 | // pull out friendly names from appKeys section of appinfo.json
31 | try {
32 | var contents = fs.readFileSync("appinfo.json");
33 | contents = JSON.parse(contents);
34 | if (contents.appKeys) {
35 | this.nameToKey = contents.appKeys;
36 | this.keyToName = { };
37 | for (var n in contents.appKeys) {
38 | if (contents.appKeys.hasOwnProperty(n)) {
39 | this.keyToName[contents.appKeys[n]] = n;
40 | }
41 | }
42 | }
43 | }
44 | catch(e) {
45 | // appinfo.json should be there but swallow error if it isnt
46 | console.log("[WARN] appinfo.json could not be read");
47 | }
48 | }
49 |
50 | // name --> key (integer)
51 | KeyTranslator.prototype.translateName = function(name) {
52 | if (!this.nameToKey || (this.nameToKey[name]==undefined)) {
53 | var ikey = parseInt(name);
54 | if (isNaN(ikey))
55 | throw "Invalid Key";
56 | return ikey;
57 | }
58 |
59 | return this.nameToKey[name];
60 | };
61 |
62 | // key --> name (string)
63 | // non-translated name is just key cast to string
64 | KeyTranslator.prototype.translateKey = function(key) {
65 | if (!this.keyToName)
66 | return new String(key);
67 |
68 | if (!this.keyToName[key])
69 | return new String(key);
70 |
71 | return this.keyToName[key];
72 | };
73 |
74 | // helper class for paring buffer to JSON
75 | function MessageParser(keyTranslator) {
76 | this.keyTranslator = keyTranslator;
77 | }
78 |
79 | // type map
80 | MessageParser.prototype.TupleTypes = {
81 | BYTE_ARRAY: 0,
82 | CSTRING: 1,
83 | UINT: 2,
84 | INT: 3
85 | };
86 |
87 | // buffer --> JSON
88 | MessageParser.prototype.parse = function(buffer) {
89 | var msg = { };
90 |
91 | for (var i = 0; i < buffer.length; ) {
92 | var key = this.keyTranslator.translateKey(buffer.readUInt32LE(i));
93 | var type = buffer.readUInt8(i + 4);
94 | var length = buffer.readUInt16LE(i + 5);
95 |
96 | var value;
97 | if (type == this.TupleTypes.BYTE_ARRAY) {
98 | value = [];
99 | for (var x = i+7; x < (i+length+7); ++x)
100 | value.push(buffer.readUInt8(x));
101 | }
102 | else if (type == this.TupleTypes.CSTRING) {
103 | value = buffer.toString("utf8", i+7, i+length+7-1);
104 | }
105 | else if (type == this.TupleTypes.UINT) {
106 | if (length == 1)
107 | value = buffer.readUInt8(i+7);
108 | else if (length == 2)
109 | value = buffer.readUInt16LE(i+7);
110 | else if (length == 4)
111 | value = buffer.readUInt32LE(i+7);
112 | }
113 | else if (type == this.TupleTypes.INT) {
114 | if (length == 1)
115 | value = buffer.readInt8(i+7);
116 | else if (length == 2)
117 | value = buffer.readInt16LE(i+7);
118 | else if (length == 4)
119 | value = buffer.readInt32LE(i+7);
120 | }
121 | else {
122 | console.log("[ERROR] Corrupt Message");
123 | throw "Corrupt Message";
124 | }
125 |
126 | msg[key] = value;
127 | i += 7 + length;
128 | }
129 |
130 | return msg;
131 | };
132 |
133 | MessageParser.prototype.serializeMsg = function(msg) {
134 | // compute size
135 | var size = 0;
136 | for (var k in msg) {
137 | if (msg.hasOwnProperty(k)) {
138 | size += 7;
139 |
140 | if (typeof(msg[k]) == "string")
141 | size += msg[k].length+1;
142 | else if (typeof(msg[k]) == "number")
143 | size += 4; // assume 32-bit
144 | else if (typeof(msg[k]) == "array")
145 | size += msg[k].length;
146 | else
147 | throw "Unable to serialize message";
148 | }
149 | }
150 |
151 | // allocate buffer
152 | var buffer = new Buffer(size+2);
153 |
154 | // serialize
155 | var offset = 0;
156 | buffer.writeUInt16LE(size, offset);
157 | offset += 2;
158 | for (var k in msg) {
159 | if (msg.hasOwnProperty(k)) {
160 | // key
161 | buffer.writeUInt32LE(this.keyTranslator.translateName(k), offset);
162 |
163 | // type, length, and data
164 | var dataSize = 0
165 | if (typeof(msg[k]) == "string") {
166 | buffer.writeUInt8(this.TupleTypes.CSTRING, offset+4);
167 | dataSize = msg[k].length+1;
168 | buffer.writeUInt16LE(dataSize, offset+5);
169 | buffer.write(msg[k], offset+7, dataSize-1);
170 | buffer.writeUInt8(0, offset+7+dataSize-1);
171 | }
172 | else if (typeof(msg[k]) == "number") {
173 | buffer.writeUInt8(this.TupleTypes.INT, offset+4); // assume signed
174 | dataSize = 4; // assume 32-bit
175 | buffer.writeUInt16LE(dataSize, offset+5);
176 | buffer.writeInt32LE(msg[k], offset+7);
177 | }
178 | else if (typeof(msg[k]) == "array") {
179 | buffer.writeUInt8(this.TupleTypes.BYTE_ARRAY, offset+4);
180 | dataSize = msg[k].length;
181 | buffer.writeUInt16LE(dataSize, offset+5);
182 | for (var x = 0; x < dataSize; ++x) {
183 | if (typeof(msg[k]) !== "number")
184 | throw "Invalid Byte Array";
185 | buffer.writeUInt8(msg[k][x], offset+7+x);
186 | }
187 | }
188 |
189 | offset += 7 + dataSize;
190 | }
191 | }
192 |
193 | return buffer;
194 | };
195 |
196 | // parser to be used by server
197 | var msgParser = new MessageParser(new KeyTranslator("appinfo.json"));
198 |
199 | // the receiving server
200 | var server = net.createServer(function(c) {
201 | var States = {
202 | ReadingSize: 1, // expecting size
203 | ReadingData: 2 // expecting data
204 | };
205 |
206 | var currentState = States.ReadingSize;
207 | var firstRead = true; // no handshake yet
208 | var bytesToRead;
209 |
210 | // will be called when there is some data to read
211 | var attemptRead = function(c) {
212 | if (currentState == States.ReadingSize) {
213 | // attempt to read 16-bit size
214 | var r = c.read(2);
215 | if (!r) // 2-bytes not available yet
216 | return false;
217 |
218 | bytesToRead = (new Buffer(r)).readUInt16LE(0);
219 | currentState = States.ReadingData;
220 | }
221 | else {
222 | // attempt to read actual data
223 | // if bytesToRead isn't available null is returned
224 | // we want to wait until the entire message is available
225 | var raw = c.read(bytesToRead);
226 | if (!raw)
227 | return false;
228 |
229 | var buffer = new Buffer(raw);
230 | currentState = States.ReadingSize;
231 | if (firstRead) {
232 | // handshake
233 | firstRead = false;
234 | if (buffer.toString() === "READY") {
235 | console.log("[INFO] Handshake Completed - ready event called")
236 | if (readyFunc)
237 | readyFunc({ ready: true, type: "ready" });
238 | }
239 | else {
240 | console.log("[ERROR] Handshake Failed");
241 | throw "Hanshake Failed";
242 | }
243 | }
244 | else {
245 | // have whole message, so now parse and notify on appmessage event
246 | var msg = msgParser.parse(buffer);
247 | if (messageFunc)
248 | messageFunc({ type: "appmessage", payload: msg });
249 | }
250 | }
251 |
252 | return true;
253 | };
254 |
255 | console.log("[INFO] Server Connected");
256 |
257 | // called when there is data to read
258 | c.on("readable", function() {
259 | // keep trying while there is data to read
260 | while (attemptRead(c)) { }
261 | });
262 | });
263 |
264 | // start the actual server
265 | server.listen(8321, function() {
266 | console.log("[INFO] Server Started");
267 | })
268 |
269 | // part of Pebble API
270 | module.exports.sendAppMessage = function(msg, fnAck, fnNack) {
271 | var buffer = msgParser.serializeMsg(msg);
272 |
273 | var client = net.connect({ port: 8322 }, function() {
274 | client.write(buffer);
275 |
276 | if (fnAck)
277 | fnAck(msg);
278 | });
279 | };
280 |
281 | // part of Pebble API
282 | module.exports.getAccountToken = function() {
283 | return "A1B2C3D4E5F6G7H8I9J0"; // obviously a dummy value
284 | };
285 |
286 | // mock Geolocation API
287 | module.exports.geolocation = {
288 | watchPosition: function() {
289 | // do nothing
290 | },
291 | getCurrentPosition: function(fnSuccess, fnFailure, options) {
292 | fnSuccess({
293 | coords: {
294 | latitude: 40.75907,
295 | longitude: -73.98507
296 | }
297 | });
298 | }
299 | };
300 |
--------------------------------------------------------------------------------
/src/jsmn/jsmn.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "jsmn.h"
4 |
5 | /**
6 | * Allocates a fresh unused token from the token pull.
7 | */
8 | static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
9 | jsmntok_t *tokens, size_t num_tokens) {
10 | jsmntok_t *tok;
11 | if (parser->toknext >= num_tokens) {
12 | return NULL;
13 | }
14 | tok = &tokens[parser->toknext++];
15 | tok->start = tok->end = -1;
16 | tok->size = 0;
17 | #ifdef JSMN_PARENT_LINKS
18 | tok->parent = -1;
19 | #endif
20 | return tok;
21 | }
22 |
23 | /**
24 | * Fills token type and boundaries.
25 | */
26 | static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
27 | int start, int end) {
28 | token->type = type;
29 | token->start = start;
30 | token->end = end;
31 | token->size = 0;
32 | }
33 |
34 | /**
35 | * Fills next available token with JSON primitive.
36 | */
37 | static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
38 | jsmntok_t *tokens, size_t num_tokens) {
39 | jsmntok_t *token;
40 | int start;
41 |
42 | start = parser->pos;
43 |
44 | for (; js[parser->pos] != '\0'; parser->pos++) {
45 | switch (js[parser->pos]) {
46 | #ifndef JSMN_STRICT
47 | /* In strict mode primitive must be followed by "," or "}" or "]" */
48 | case ':':
49 | #endif
50 | case '\t' : case '\r' : case '\n' : case ' ' :
51 | case ',' : case ']' : case '}' :
52 | goto found;
53 | }
54 | if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
55 | parser->pos = start;
56 | return JSMN_ERROR_INVAL;
57 | }
58 | }
59 | #ifdef JSMN_STRICT
60 | /* In strict mode primitive must be followed by a comma/object/array */
61 | parser->pos = start;
62 | return JSMN_ERROR_PART;
63 | #endif
64 |
65 | found:
66 | token = jsmn_alloc_token(parser, tokens, num_tokens);
67 | if (token == NULL) {
68 | parser->pos = start;
69 | return JSMN_ERROR_NOMEM;
70 | }
71 | jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
72 | #ifdef JSMN_PARENT_LINKS
73 | token->parent = parser->toksuper;
74 | #endif
75 | parser->pos--;
76 | return JSMN_SUCCESS;
77 | }
78 |
79 | /**
80 | * Filsl next token with JSON string.
81 | */
82 | static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
83 | jsmntok_t *tokens, size_t num_tokens) {
84 | jsmntok_t *token;
85 |
86 | int start = parser->pos;
87 |
88 | parser->pos++;
89 |
90 | /* Skip starting quote */
91 | for (; js[parser->pos] != '\0'; parser->pos++) {
92 | char c = js[parser->pos];
93 |
94 | /* Quote: end of string */
95 | if (c == '\"') {
96 | token = jsmn_alloc_token(parser, tokens, num_tokens);
97 | if (token == NULL) {
98 | parser->pos = start;
99 | return JSMN_ERROR_NOMEM;
100 | }
101 | jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
102 | #ifdef JSMN_PARENT_LINKS
103 | token->parent = parser->toksuper;
104 | #endif
105 | return JSMN_SUCCESS;
106 | }
107 |
108 | /* Backslash: Quoted symbol expected */
109 | if (c == '\\') {
110 | parser->pos++;
111 | switch (js[parser->pos]) {
112 | /* Allowed escaped symbols */
113 | case '\"': case '/' : case '\\' : case 'b' :
114 | case 'f' : case 'r' : case 'n' : case 't' :
115 | break;
116 | /* Allows escaped symbol \uXXXX */
117 | case 'u':
118 | /* TODO */
119 | break;
120 | /* Unexpected symbol */
121 | default:
122 | parser->pos = start;
123 | return JSMN_ERROR_INVAL;
124 | }
125 | }
126 | }
127 | parser->pos = start;
128 | return JSMN_ERROR_PART;
129 | }
130 |
131 | /**
132 | * Parse JSON string and fill tokens.
133 | */
134 | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens,
135 | unsigned int num_tokens) {
136 | jsmnerr_t r;
137 | int i;
138 | jsmntok_t *token;
139 |
140 | for (; js[parser->pos] != '\0'; parser->pos++) {
141 | char c;
142 | jsmntype_t type;
143 |
144 | c = js[parser->pos];
145 | switch (c) {
146 | case '{': case '[':
147 | token = jsmn_alloc_token(parser, tokens, num_tokens);
148 | if (token == NULL)
149 | return JSMN_ERROR_NOMEM;
150 | if (parser->toksuper != -1) {
151 | tokens[parser->toksuper].size++;
152 | #ifdef JSMN_PARENT_LINKS
153 | token->parent = parser->toksuper;
154 | #endif
155 | }
156 | token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
157 | token->start = parser->pos;
158 | parser->toksuper = parser->toknext - 1;
159 | break;
160 | case '}': case ']':
161 | type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
162 | #ifdef JSMN_PARENT_LINKS
163 | if (parser->toknext < 1) {
164 | return JSMN_ERROR_INVAL;
165 | }
166 | token = &tokens[parser->toknext - 1];
167 | for (;;) {
168 | if (token->start != -1 && token->end == -1) {
169 | if (token->type != type) {
170 | return JSMN_ERROR_INVAL;
171 | }
172 | token->end = parser->pos + 1;
173 | parser->toksuper = token->parent;
174 | break;
175 | }
176 | if (token->parent == -1) {
177 | break;
178 | }
179 | token = &tokens[token->parent];
180 | }
181 | #else
182 | for (i = parser->toknext - 1; i >= 0; i--) {
183 | token = &tokens[i];
184 | if (token->start != -1 && token->end == -1) {
185 | if (token->type != type) {
186 | return JSMN_ERROR_INVAL;
187 | }
188 | parser->toksuper = -1;
189 | token->end = parser->pos + 1;
190 | break;
191 | }
192 | }
193 | /* Error if unmatched closing bracket */
194 | if (i == -1) return JSMN_ERROR_INVAL;
195 | for (; i >= 0; i--) {
196 | token = &tokens[i];
197 | if (token->start != -1 && token->end == -1) {
198 | parser->toksuper = i;
199 | break;
200 | }
201 | }
202 | #endif
203 | break;
204 | case '\"':
205 | r = jsmn_parse_string(parser, js, tokens, num_tokens);
206 | if (r < 0) return r;
207 | if (parser->toksuper != -1)
208 | tokens[parser->toksuper].size++;
209 | break;
210 | case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ':
211 | break;
212 | #ifdef JSMN_STRICT
213 | /* In strict mode primitives are: numbers and booleans */
214 | case '-': case '0': case '1' : case '2': case '3' : case '4':
215 | case '5': case '6': case '7' : case '8': case '9':
216 | case 't': case 'f': case 'n' :
217 | #else
218 | /* In non-strict mode every unquoted value is a primitive */
219 | default:
220 | #endif
221 | r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
222 | if (r < 0) return r;
223 | if (parser->toksuper != -1)
224 | tokens[parser->toksuper].size++;
225 | break;
226 |
227 | #ifdef JSMN_STRICT
228 | /* Unexpected char in strict mode */
229 | default:
230 | return JSMN_ERROR_INVAL;
231 | #endif
232 |
233 | }
234 | }
235 |
236 | for (i = parser->toknext - 1; i >= 0; i--) {
237 | /* Unmatched opened object or array */
238 | if (tokens[i].start != -1 && tokens[i].end == -1) {
239 | return JSMN_ERROR_PART;
240 | }
241 | }
242 |
243 | return JSMN_SUCCESS;
244 | }
245 |
246 | /**
247 | * Creates a new parser based over a given buffer with an array of tokens
248 | * available.
249 | */
250 | void jsmn_init(jsmn_parser *parser) {
251 | parser->pos = 0;
252 | parser->toknext = 0;
253 | parser->toksuper = -1;
254 | }
255 |
--------------------------------------------------------------------------------
/src/jsmn/jsmn.h:
--------------------------------------------------------------------------------
1 | #ifndef __JSMN_H_
2 | #define __JSMN_H_
3 |
4 | /**
5 | * JSON type identifier. Basic types are:
6 | * o Object
7 | * o Array
8 | * o String
9 | * o Other primitive: number, boolean (true/false) or null
10 | */
11 | typedef enum {
12 | JSMN_PRIMITIVE = 0,
13 | JSMN_OBJECT = 1,
14 | JSMN_ARRAY = 2,
15 | JSMN_STRING = 3
16 | } jsmntype_t;
17 |
18 | typedef enum {
19 | /* Not enough tokens were provided */
20 | JSMN_ERROR_NOMEM = -1,
21 | /* Invalid character inside JSON string */
22 | JSMN_ERROR_INVAL = -2,
23 | /* The string is not a full JSON packet, more bytes expected */
24 | JSMN_ERROR_PART = -3,
25 | /* Everything was fine */
26 | JSMN_SUCCESS = 0
27 | } jsmnerr_t;
28 |
29 | /**
30 | * JSON token description.
31 | * @param type type (object, array, string etc.)
32 | * @param start start position in JSON data string
33 | * @param end end position in JSON data string
34 | */
35 | typedef struct {
36 | jsmntype_t type;
37 | int start;
38 | int end;
39 | int size;
40 | #ifdef JSMN_PARENT_LINKS
41 | int parent;
42 | #endif
43 | } jsmntok_t;
44 |
45 | /**
46 | * JSON parser. Contains an array of token blocks available. Also stores
47 | * the string being parsed now and current position in that string
48 | */
49 | typedef struct {
50 | unsigned int pos; /* offset in the JSON string */
51 | int toknext; /* next token to allocate */
52 | int toksuper; /* superior token node, e.g parent object or array */
53 | } jsmn_parser;
54 |
55 | /**
56 | * Create JSON parser over an array of tokens
57 | */
58 | void jsmn_init(jsmn_parser *parser);
59 |
60 | /**
61 | * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
62 | * a single JSON object.
63 | */
64 | jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js,
65 | jsmntok_t *tokens, unsigned int num_tokens);
66 |
67 | #endif /* __JSMN_H_ */
68 |
--------------------------------------------------------------------------------
/src/local/accel_tap.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | //
4 | // This file implements the accel_tap_service part of AccelerometerService
5 | //
6 | // Thrust can be simulated in X/Y/Z axis with +/- direction
7 | //
8 |
9 | static AccelTapHandler tap_handler = NULL;
10 | static AccelAxisType tap_axis = ACCEL_AXIS_X;
11 | static int32_t tap_direction = 0;
12 | static bool tap_notify = false;
13 |
14 | // simulator access
15 |
16 | void accel_do_tap_on_axis(AccelAxisType axis, int32_t direction) {
17 | tap_axis = axis;
18 | if(direction >= 1) {
19 | tap_direction = 1;
20 | }
21 | else {
22 | if(direction <= -1) {
23 | tap_direction = -1;
24 | }
25 | else {
26 | tap_direction = 0;
27 | }
28 | }
29 | tap_notify = true;
30 | }
31 |
32 | // pebble API part
33 |
34 | void accel_tap_service_subscribe(AccelTapHandler handler) {
35 | tap_handler = handler;
36 | }
37 |
38 | void accel_tap_service_unsubscribe(void) {
39 | tap_handler = NULL;
40 | tap_notify = false;
41 | }
42 |
43 | void service_accel_tap() {
44 | if(tap_notify && tap_handler != NULL) {
45 | tap_handler(tap_axis, tap_direction);
46 | tap_axis = ACCEL_AXIS_X;
47 | tap_direction = 0;
48 | tap_notify = false;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/local/actionbar.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | #define ACTION_BAR_SPACING 3
4 | #define ACTION_BAR_LAYER_GET Layer* action_bar_layer=(Layer*)l
5 | #define ACTION_BAR_GET ACTION_BAR_LAYER_GET;ActionBarLayerData* action_bar=((ActionBarLayerData*)layer_get_data(action_bar_layer))
6 |
7 | void action_bar_click_config_provider (void* context);
8 | void action_bar_click_handler_up (ClickRecognizerRef recognizer,void* context);
9 | void action_bar_click_handler_down (ClickRecognizerRef recognizer,void* context);
10 | void action_bar_update_handler (Layer* me,GContext* ctx);
11 |
12 | ActionBarLayer* action_bar_layer_create(void) {
13 | Layer* layer=layer_create_with_data(GRect(0,0,PBL_SCREEN_WIDTH,PBL_SCREEN_HEIGHT),sizeof(ActionBarLayerData));
14 | ActionBarLayerData* action_bar=(ActionBarLayerData*)layer_get_data(layer);
15 | layer_set_update_proc (layer,action_bar_update_handler);
16 | action_bar->icons[0]=0;
17 | action_bar->icons[1]=0;
18 | action_bar->icons[2]=0;
19 | action_bar->context=0;
20 | action_bar->click_config_provider=0;
21 | action_bar->is_highlighted=0;
22 | action_bar->background_color=GColorBlack;
23 | return (ActionBarLayer*)layer;
24 | }
25 |
26 | void action_bar_layer_destroy (ActionBarLayer* layer) {
27 | if (layer)
28 | layer_destroy((Layer*)layer);
29 | }
30 |
31 | void action_bar_layer_set_context(ActionBarLayer *l, void *context) {
32 | ACTION_BAR_GET;
33 | action_bar->context=context;
34 | }
35 |
36 | void action_bar_layer_set_click_config_provider(ActionBarLayer *l, ClickConfigProvider click_config_provider) {
37 | ACTION_BAR_GET;
38 | action_bar->click_config_provider=click_config_provider;
39 | if (click_config_provider!=0 && //there IS a config provider
40 | action_bar_layer->window!=0 && //the action bar is added to a window
41 | window_stack_get_top_window()==action_bar_layer->window) //this window is currently visible
42 | click_config_provider (action_bar->context);
43 | }
44 |
45 | void action_bar_layer_set_icon(ActionBarLayer *l, ButtonId button_id, const GBitmap *icon) {
46 | ACTION_BAR_GET;
47 | bool hasSet=true;
48 | switch (button_id) {
49 | case(BUTTON_ID_UP):{action_bar->icons[0]=icon;}break;
50 | case(BUTTON_ID_SELECT):{action_bar->icons[1]=icon;}break;
51 | case(BUTTON_ID_DOWN):{action_bar->icons[2]=icon;}break;
52 | default:{hasSet=false;}break;
53 | }
54 | if (hasSet && //button_id is valid
55 | action_bar->click_config_provider!=0 && //there is a click config provider
56 | action_bar_layer->window!=0 && //the action bar is added to a window
57 | window_stack_get_top_window()==action_bar_layer->window) //this window is currently visible
58 | action_bar->click_config_provider (action_bar->context);
59 | }
60 |
61 | void action_bar_layer_clear_icon(ActionBarLayer *l, ButtonId button_id) {
62 | action_bar_layer_set_icon (l,button_id,0);
63 | }
64 |
65 | void action_bar_layer_set_background_color(ActionBarLayer *l, GColor background_color) {
66 | ACTION_BAR_GET;
67 | action_bar->background_color=background_color;
68 | layer_mark_dirty (action_bar_layer);
69 | }
70 |
71 | void action_bar_layer_add_to_window(ActionBarLayer *l, struct Window *window) {
72 | ACTION_BAR_LAYER_GET;
73 | GRect p=window->layer->frame;
74 | layer_insert_below_sibling(action_bar_layer,window->layer);
75 | layer_set_frame (action_bar_layer,GRect(p.size.w-ACTION_BAR_WIDTH,
76 | ACTION_BAR_SPACING,
77 | ACTION_BAR_WIDTH,
78 | p.size.h-2*ACTION_BAR_SPACING));
79 | window_set_click_config_provider_with_context (window,action_bar_click_config_provider,l);
80 | //action_bar_layer->window=window; //is already set in layer_insert_below_sibling
81 | }
82 |
83 | void action_bar_layer_remove_from_window(ActionBarLayer *l) {
84 | ACTION_BAR_GET;
85 | if (action_bar_layer->window!=0) {
86 | Layer* cursor=action_bar_layer->window->layer;
87 | while (cursor->next_sibling!=0) {
88 | if (cursor->next_sibling==((Layer*)action_bar)) {
89 | cursor->next_sibling=action_bar_layer->next_sibling;
90 | break;
91 | }
92 | cursor=cursor->next_sibling;
93 | }
94 | if (cursor->next_sibling==0)
95 | return;
96 | window_set_click_config_provider_with_context(action_bar_layer->window,0,0);
97 | if (window_stack_get_top_window()==action_bar_layer->window) {
98 | ClickConfig** clickConfig=getClickConfig ();
99 | int i;
100 | for (i=BUTTON_ID_UP;i<=BUTTON_ID_DOWN;i++) {
101 | if (clickConfig[i]->raw.up_handler==action_bar_click_handler_up)
102 | clickConfig[i]->raw.up_handler=0;
103 | if (clickConfig[i]->raw.down_handler==action_bar_click_handler_down)
104 | clickConfig[i]->raw.down_handler=0;
105 | }
106 | }
107 | action_bar_layer->window=0;
108 | }
109 | }
110 |
111 | void action_bar_click_config_provider (void* l) {
112 | ACTION_BAR_GET;
113 | for (ButtonId id=BUTTON_ID_UP;id<=BUTTON_ID_DOWN;id++)
114 | window_raw_click_subscribe(BUTTON_ID_UP,action_bar_click_handler_down,action_bar_click_handler_up,l);
115 | if (action_bar->click_config_provider)
116 | action_bar->click_config_provider(action_bar->context);
117 | }
118 |
119 | void action_bar_click_handler_up (ClickRecognizerRef rec,void* l) {
120 | ACTION_BAR_GET;
121 | uint16_t mask;
122 | switch (click_recognizer_get_button_id (rec))
123 | {
124 | case(BUTTON_ID_UP):{mask=0;}break;
125 | case(BUTTON_ID_SELECT):{mask=1;}break;
126 | case(BUTTON_ID_DOWN):{mask=2;}break;
127 | default:{return;}break;
128 | }
129 | mask=(1<is_highlighted&=mask;
131 | layer_mark_dirty(action_bar_layer);
132 | }
133 |
134 | void action_bar_click_handler_down (ClickRecognizerRef rec,void* l) {
135 | ACTION_BAR_GET;
136 | uint16_t mask;
137 | switch (click_recognizer_get_button_id (rec))
138 | {
139 | case(BUTTON_ID_UP):{mask=0;}break;
140 | case(BUTTON_ID_SELECT):{mask=1;}break;
141 | case(BUTTON_ID_DOWN):{mask=2;}break;
142 | default:{return;}break;
143 | }
144 | action_bar->is_highlighted|=1<background_color);
154 | graphics_fill_rect (ctx,GRect(0,0,l->frame.size.w+3,l->frame.size.h),3,0);
155 | if (bar->icons[0]!=0) {
156 | if (bar->is_highlighted&(1<<0))
157 | compOp=GCompOpAssignInverted;
158 | else
159 | compOp=GCompOpAssign;
160 | graphics_context_set_compositing_mode(ctx,compOp);
161 | graphics_draw_bitmap_in_rect (ctx,bar->icons[0],GRect(11-bar->icons[0]->bounds.size.w/2,20+11-bar->icons[0]->bounds.size.h,bar->icons[0]->bounds.size.w,bar->icons[0]->bounds.size.h));
162 | }
163 | if (bar->icons[1]!=0) {
164 | if (bar->is_highlighted&(1<<1))
165 | compOp=GCompOpAssignInverted;
166 | else
167 | compOp=GCompOpAssign;
168 | graphics_context_set_compositing_mode(ctx,compOp);
169 | graphics_draw_bitmap_in_rect (ctx,bar->icons[1],GRect(11-bar->icons[1]->bounds.size.w/2,l->frame.size.h/2-bar->icons[1]->bounds.size.h/2,bar->icons[1]->bounds.size.w,bar->icons[1]->bounds.size.h));
170 | }
171 | if (bar->icons[2]!=0) {
172 | if (bar->is_highlighted&(1<<2))
173 | compOp=GCompOpAssignInverted;
174 | else
175 | compOp=GCompOpAssign;
176 | graphics_context_set_compositing_mode(ctx,compOp);
177 | graphics_draw_bitmap_in_rect (ctx,bar->icons[2],GRect(11-bar->icons[2]->bounds.size.w/2,l->frame.size.h-20-11-bar->icons[2]->bounds.size.h,bar->icons[2]->bounds.size.w,bar->icons[2]->bounds.size.h));
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/src/local/animation.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | static Animation* firstScheduledAnimation=0;
4 |
5 | struct Animation* animation_create() {
6 | Animation* animation=(Animation*)malloc(sizeof(Animation));
7 | if (!animation) {
8 | printf ("[ERROR] Memory allocation failed!\n");
9 | return 0;
10 | }
11 | animation->list_node.next=0;
12 | animation->list_node.prev=0;
13 | animation->abs_start_time_ms=0;
14 | animation->is_completed=true;
15 | //SDK defaults
16 | animation->duration_ms=250;
17 | animation->curve= AnimationCurveEaseInOut;
18 | animation->delay_ms=0;
19 | animation->handlers.started=0;
20 | animation->handlers.stopped=0;
21 | animation->context=0;
22 | animation->implementation=0;
23 | return animation;
24 | }
25 |
26 | void animation_destroy (struct Animation* animation) {
27 | if (animation_is_scheduled(animation))
28 | animation_unschedule(animation);
29 | if (animation)
30 | free(animation);
31 | }
32 |
33 | void animation_set_delay(struct Animation *animation, uint32_t delay_ms) {
34 | animation->delay_ms=delay_ms;
35 | }
36 |
37 | void animation_set_duration(struct Animation *animation, uint32_t duration_ms) {
38 | animation->duration_ms=duration_ms;
39 | }
40 |
41 | void animation_set_curve(struct Animation *animation, AnimationCurve curve) {
42 | animation->curve=curve;
43 | }
44 |
45 | void animation_set_handlers(struct Animation *animation, AnimationHandlers callbacks, void *context) {
46 | animation->handlers=callbacks;
47 | animation->context=context;
48 | }
49 |
50 | void animation_set_implementation(struct Animation *animation, const AnimationImplementation *implementation) {
51 | animation->implementation=implementation;
52 | }
53 |
54 | void *animation_get_context(struct Animation *animation) {
55 | return animation->context;
56 | }
57 |
58 | void animation_schedule(struct Animation *animation) {
59 | if (animation->implementation==0)
60 | return;
61 | if (animation_is_scheduled(animation))
62 | animation_unschedule(animation);
63 | animation->is_completed=true; //Yes this is meant to be true! That is how the engine determines if a animation is in "delay" state
64 | animation->abs_start_time_ms=SDL_GetTicks();
65 | animation->list_node.next=(ListNode*)firstScheduledAnimation;
66 | animation->list_node.prev=0;
67 | if (firstScheduledAnimation!=0)
68 | firstScheduledAnimation->list_node.prev=(ListNode*)animation;
69 | firstScheduledAnimation=animation;
70 | if (animation->implementation->setup!=0)
71 | animation->implementation->setup (animation);
72 | }
73 |
74 | void animation_unschedule(struct Animation *animation) {
75 | if (animation->implementation==0)
76 | return;
77 | animation->is_completed=true;
78 | animation->abs_start_time_ms=0;
79 | if (animation==firstScheduledAnimation) {
80 | firstScheduledAnimation=(Animation*)animation->list_node.next;
81 | if (firstScheduledAnimation!=0)
82 | firstScheduledAnimation->list_node.prev=0;
83 | }
84 | else {
85 | animation->list_node.prev->next=animation->list_node.next;
86 | if (animation->list_node.next!=0)
87 | animation->list_node.next->prev=animation->list_node.prev;
88 | }
89 | animation->list_node.next=0;
90 | animation->list_node.prev=0;
91 | if (animation->handlers.stopped!=0)
92 | animation->handlers.stopped(animation,animation->is_completed,animation->context);
93 | if (animation->implementation->teardown!=0)
94 | animation->implementation->teardown(animation);
95 | }
96 |
97 | void animation_unschedule_all(void) {
98 | while (firstScheduledAnimation!=0)
99 | animation_unschedule(firstScheduledAnimation);
100 | }
101 |
102 | bool animation_is_scheduled(struct Animation *animation) {
103 | Animation* cursor=firstScheduledAnimation;
104 | while (cursor!=0) {
105 | if (cursor==animation)
106 | return true;
107 | cursor=(Animation*)cursor->list_node.next;
108 | }
109 | return false;
110 | }
111 |
112 | void service_animations () {
113 | Animation* cursor=firstScheduledAnimation,* tempCursor;
114 | bool isDirty=false;
115 | uint32_t time=0;
116 | while (cursor!=0) {
117 | if (cursor->is_completed) { //"delay" state
118 | if (SDL_GetTicks()-cursor->abs_start_time_ms>=cursor->delay_ms) {
119 | cursor->abs_start_time_ms=SDL_GetTicks();
120 | cursor->is_completed=false;
121 | if (cursor->handlers.started!=0)
122 | cursor->handlers.started(cursor,cursor->context);
123 | }
124 | }
125 | else {
126 | if (cursor->duration_ms==ANIMATION_DURATION_INFINITE)
127 | time=ANIMATION_DURATION_INFINITE;
128 | else if (SDL_GetTicks()-cursor->abs_start_time_ms>=cursor->duration_ms) {
129 | //the simulator runs on 60 fps. to ensure the maximal value is reached, this has to be done
130 | cursor->implementation->update (cursor,ANIMATION_NORMALIZED_MAX);
131 |
132 | isDirty=true;
133 | cursor->is_completed=true;
134 | tempCursor=cursor;
135 | cursor=(Animation*)cursor->list_node.next;
136 | animation_unschedule(tempCursor);
137 | continue;
138 | }
139 | else
140 | time=(ANIMATION_NORMALIZED_MIN + (((ANIMATION_NORMALIZED_MAX - ANIMATION_NORMALIZED_MIN) * (SDL_GetTicks()-cursor->abs_start_time_ms)) / cursor->duration_ms));
141 | cursor->implementation->update (cursor,time);
142 | isDirty=true;
143 | }
144 | cursor=(Animation*)cursor->list_node.next;
145 | }
146 | if (isDirty==true)
147 | markDirty (true);
148 | }
149 |
150 | struct PropertyAnimation* property_animation_create(const struct PropertyAnimationImplementation* implementation,void* subject,void* from_value,void* to_value)
151 | {
152 | PropertyAnimation* animation=(PropertyAnimation*)malloc(sizeof(PropertyAnimation));
153 | if (!animation) {
154 | printf ("[ERROR] Memory allocation failed!\n");
155 | return 0;
156 | }
157 | memset(animation, 0, sizeof(PropertyAnimation));
158 | animation->animation.implementation=(AnimationImplementation*)implementation;
159 | animation->subject=subject;
160 | if (implementation->base.update==(AnimationUpdateImplementation)property_animation_update_int16) {
161 | if (from_value==0)
162 | animation->values.from.int16=implementation->accessors.getter.int16 (subject);
163 | else
164 | animation->values.from.int16=*(int16_t*)from_value;
165 | if (to_value==0)
166 | animation->values.to.int16=implementation->accessors.getter.int16 (subject);
167 | else
168 | animation->values.to.int16=*(int16_t*)to_value;
169 | }
170 | else if (implementation->base.update==(AnimationUpdateImplementation)property_animation_update_gpoint) {
171 | if (from_value==0)
172 | animation->values.from.gpoint=implementation->accessors.getter.gpoint (subject);
173 | else
174 | animation->values.from.gpoint=*(GPoint*)from_value;
175 | if (to_value==0)
176 | animation->values.to.gpoint=implementation->accessors.getter.gpoint (subject);
177 | else
178 | animation->values.to.gpoint=*(GPoint*)to_value;
179 | }
180 | else if (implementation->base.update==(AnimationUpdateImplementation)property_animation_update_grect) {
181 | if (from_value==0)
182 | animation->values.from.grect=implementation->accessors.getter.grect (subject);
183 | else
184 | animation->values.from.grect=*(GRect*)from_value;
185 | if (to_value==0)
186 | animation->values.to.grect=implementation->accessors.getter.grect (subject);
187 | else
188 | animation->values.to.grect=*(GRect*)to_value;
189 | }
190 | else
191 | printf ("[WARN] Invalid property animation implementation!\n");
192 | return animation;
193 | }
194 |
195 | void property_animation_destroy (struct PropertyAnimation* animation) {
196 | if (animation_is_scheduled((Animation*)animation))
197 | animation_unschedule((Animation*)animation);
198 | if (animation)
199 | free(animation);
200 | }
201 |
202 | #define PROPERTY_ANIMATION_INT16_VALUE(from,to,time) from+(int16_t)((to-from)*((float)time/ANIMATION_NORMALIZED_MAX));
203 |
204 | void property_animation_update_int16 (PropertyAnimation* animation,const uint32_t time)
205 | {
206 | int16_t value=PROPERTY_ANIMATION_INT16_VALUE(animation->values.from.int16,animation->values.to.int16,time);
207 | PropertyAnimationImplementation* implementation=(PropertyAnimationImplementation*)animation->animation.implementation;
208 | implementation->accessors.setter.int16(animation->subject,value);
209 | }
210 |
211 | void property_animation_update_gpoint (PropertyAnimation* animation,const uint32_t time)
212 | {
213 | GPoint value;
214 | PropertyAnimationImplementation* implementation=(PropertyAnimationImplementation*)animation->animation.implementation;
215 | value.x=PROPERTY_ANIMATION_INT16_VALUE(animation->values.from.gpoint.x,animation->values.to.gpoint.x,time);
216 | value.y=PROPERTY_ANIMATION_INT16_VALUE(animation->values.from.gpoint.y,animation->values.to.gpoint.y,time);
217 | implementation->accessors.setter.gpoint(animation->subject,value);
218 | }
219 |
220 | void property_animation_update_grect (PropertyAnimation* animation,const uint32_t time)
221 | {
222 | GRect value;
223 | PropertyAnimationImplementation* implementation=(PropertyAnimationImplementation*)animation->animation.implementation;
224 | value.origin.x=PROPERTY_ANIMATION_INT16_VALUE(animation->values.from.grect.origin.x,animation->values.to.grect.origin.x,time);
225 | value.origin.y=PROPERTY_ANIMATION_INT16_VALUE(animation->values.from.grect.origin.y,animation->values.to.grect.origin.y,time);
226 | value.size.w=PROPERTY_ANIMATION_INT16_VALUE(animation->values.from.grect.size.w,animation->values.to.grect.size.w,time);
227 | value.size.h=PROPERTY_ANIMATION_INT16_VALUE(animation->values.from.grect.size.h,animation->values.to.grect.size.h,time);
228 | implementation->accessors.setter.grect(animation->subject,value);
229 | }
230 |
231 | GRectReturn layerFrameGetter (void* subject)
232 | {
233 | return ((Layer*)subject)->frame;
234 | }
235 |
236 | void layerFrameSetter (void* subject,GRect rect)
237 | {
238 | ((Layer*)subject)->frame=rect;
239 | layer_mark_dirty((Layer*)subject);
240 | }
241 |
242 | static PropertyAnimationImplementation layer_property_animation_implementation={
243 | .base={
244 | .update=(AnimationUpdateImplementation)property_animation_update_grect
245 | },
246 | .accessors={
247 | .getter={ .grect=layerFrameGetter},
248 | .setter={ .grect=layerFrameSetter}
249 | }
250 | };
251 |
252 | PropertyAnimation* property_animation_create_layer_frame (Layer* layer,GRect* from,GRect* to)
253 | {
254 | return property_animation_create (&layer_property_animation_implementation,layer,from,to);
255 | }
256 |
--------------------------------------------------------------------------------
/src/local/app_sync.c:
--------------------------------------------------------------------------------
1 | #ifndef WIN32
2 | #include "globals.h"
3 | #include
4 |
5 | struct AppSyncList {
6 | struct AppSync* s;
7 | struct AppSyncList* next;
8 | };
9 | static struct AppSyncList* g_pAppSyncList = NULL;
10 | pthread_mutex_t g_mxAppSyncList = PTHREAD_MUTEX_INITIALIZER;
11 |
12 | void app_sync_init(struct AppSync *s,
13 | uint8_t *buffer,
14 | const uint16_t buffer_size,
15 | const Tuplet * const keys_and_initial_values,
16 | const uint8_t count,
17 | AppSyncTupleChangedCallback tuple_changed_callback,
18 | AppSyncErrorCallback error_callback,
19 | void *context) {
20 |
21 | uint32_t final_buffer_size = buffer_size;
22 | if (dict_serialize_tuplets_to_buffer(keys_and_initial_values, count, buffer, &final_buffer_size) != DICT_OK)
23 | return;
24 |
25 | s->buffer = buffer;
26 | s->buffer_size = buffer_size;
27 |
28 | if (dict_write_begin(&s->current_iter, buffer, final_buffer_size) != DICT_OK)
29 | return;
30 |
31 | s->callback.context = context;
32 | s->callback.error = error_callback;
33 | s->callback.value_changed = tuple_changed_callback;
34 |
35 | // insert into list of regiested AppSync
36 | struct AppSyncList* pNode = (struct AppSyncList*) malloc(sizeof(struct AppSyncList));
37 | pthread_mutex_lock(&g_mxAppSyncList);
38 | pNode->s = s;
39 | pNode->next = g_pAppSyncList;
40 | g_pAppSyncList = pNode;
41 | pthread_mutex_unlock(&g_mxAppSyncList);
42 |
43 | // send to client
44 | DictionaryIterator* iter;
45 | app_message_outbox_begin(&iter);
46 | for (int i = 0; i < count; ++i) {
47 | dict_write_tuplet(iter, &(keys_and_initial_values[i]));
48 | }
49 | dict_write_end(iter);
50 | app_message_outbox_send();
51 |
52 | // notify
53 | Tuple* p = dict_read_first(&s->current_iter);
54 | while (p) {
55 | tuple_changed_callback(p->key, p, NULL, context);
56 |
57 | p = dict_read_next(&s->current_iter);
58 | }
59 | }
60 |
61 | void app_sync_deinit(struct AppSync *s) {
62 | pthread_mutex_lock(&g_mxAppSyncList);
63 | if (!g_pAppSyncList)
64 | return;
65 |
66 | if (g_pAppSyncList->s == s) {
67 | struct AppSyncList* next = g_pAppSyncList->next;
68 | free(g_pAppSyncList);
69 | g_pAppSyncList = next;
70 | }
71 | else {
72 | struct AppSyncList* prev = g_pAppSyncList;
73 | struct AppSyncList* curr = g_pAppSyncList->next;
74 | while (curr) {
75 | if (curr->s == s) {
76 | prev->next = curr->next;
77 | free(curr);
78 | break;
79 | }
80 | curr = curr->next;
81 | }
82 | }
83 | pthread_mutex_unlock(&g_mxAppSyncList);
84 |
85 | }
86 |
87 | AppMessageResult app_sync_set(struct AppSync *s,
88 | const Tuplet * const keys_and_values_to_update,
89 | const uint8_t count) {
90 |
91 | // update state on this side
92 | uint32_t in_size = dict_calc_buffer_size_from_tuplets(keys_and_values_to_update, count);
93 | uint8_t* buffer = (uint8_t*) malloc(in_size);
94 | DictionaryIterator iter;
95 | if (dict_serialize_tuplets_to_buffer_with_iter(&iter, keys_and_values_to_update, count, buffer, &in_size) != DICT_OK)
96 | return APP_MSG_BUFFER_OVERFLOW;
97 |
98 | uint32_t size = s->buffer_size;
99 | dict_merge(&(s->current_iter), &size, &iter, true, s->callback.value_changed, s->callback.context);
100 |
101 | free(buffer);
102 |
103 | // prepare data & send
104 | DictionaryIterator* iter_out;
105 | app_message_outbox_begin(&iter_out);
106 | uint32_t out_size = iter_out->end - (void*)iter_out->dictionary;
107 | if (dict_serialize_tuplets_to_buffer_with_iter(iter_out, keys_and_values_to_update, count, (uint8_t*)iter_out->dictionary, &out_size) != DICT_OK)
108 | return APP_MSG_BUFFER_OVERFLOW;
109 | return app_message_outbox_send();
110 | }
111 |
112 | const Tuple * app_sync_get(const struct AppSync *s, const uint32_t key) {
113 | return dict_find(&(s->current_iter), key);
114 | }
115 |
116 | void service_app_sync(DictionaryIterator* iter) {
117 | pthread_mutex_lock(&g_mxAppSyncList);
118 | struct AppSyncList* pAS = g_pAppSyncList;
119 | while (pAS) {
120 | uint32_t size = pAS->s->buffer_size;
121 | dict_merge(&(pAS->s->current_iter), &size, iter, true, pAS->s->callback.value_changed, pAS->s->callback.context);
122 |
123 | pAS = pAS->next;
124 | }
125 |
126 | pthread_mutex_unlock(&g_mxAppSyncList);
127 | }
128 | #endif
129 |
--------------------------------------------------------------------------------
/src/local/battery.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | //
4 | // This file implements the BatteryStateService
5 | //
6 | // The battery acts like a real one would with this semantics:
7 | //
8 | // .charge_percent | .is_charging | .is_plugged |
9 | // 10 ... 90 | false | false |
10 | // <90 | true | true |
11 | // 90 | false | true |
12 | //
13 | // Basically if "plugged in" is_charging will be true unless we reach 90%.
14 | // In all other cases it will be false.
15 | //
16 |
17 | static BatteryChargeState battery_state = {
18 | .charge_percent = 90,
19 | .is_charging = false,
20 | .is_plugged = false
21 | };
22 |
23 | static BatteryStateHandler battery_callback = NULL;
24 | static bool battery_notify = false;
25 |
26 | // simulator access
27 | // note that the SDK up to the current beta3 only reports 10-90, never 100 or 0
28 |
29 | uint8_t battery_charge_increase(void) {
30 | if(battery_state.charge_percent < 90) {
31 | battery_state.charge_percent += 10;
32 | battery_notify = true;
33 | }
34 | else {
35 | battery_state.is_charging = false;
36 | }
37 | return battery_state.charge_percent;
38 | }
39 |
40 | uint8_t battery_charge_decrease(void) {
41 | if(battery_state.charge_percent > 10) {
42 | battery_state.charge_percent -= 10;
43 | battery_notify = true;
44 | }
45 | if(battery_state.is_plugged) {
46 | battery_state.is_charging = true;
47 | }
48 | return battery_state.charge_percent;
49 | }
50 |
51 | void toggle_battery_charger_plugged(void) {
52 | battery_state.is_plugged = !battery_state.is_plugged;
53 |
54 | if(battery_state.is_plugged) {
55 | battery_state.is_charging = (battery_state.charge_percent < 90);
56 | }
57 | else {
58 | battery_state.is_charging = false;
59 | }
60 |
61 | battery_notify = true;
62 | }
63 |
64 | // pebble API part
65 |
66 | BatteryChargeState battery_state_service_peek(void) {
67 | return battery_state;
68 | }
69 |
70 | void battery_state_service_subscribe(BatteryStateHandler handler) {
71 | battery_callback = handler;
72 | battery_notify = true;
73 | }
74 |
75 | void battery_state_service_unsubscribe() {
76 | battery_callback = NULL;
77 | battery_notify = false;
78 | }
79 |
80 | void service_battery() {
81 | if(battery_notify && battery_callback != NULL) {
82 | battery_callback(battery_state);
83 | battery_notify = false;
84 | }
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/src/local/bitmap.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | typedef struct __attribute__((__packed__)) {
4 | uint16_t pitch;
5 | uint16_t info_flags;
6 | uint32_t type;
7 | uint16_t width;
8 | uint16_t height;
9 | } GBitmapHeader;
10 |
11 | #ifdef WIN32
12 | typedef struct __attribute__ ((__packed__)) {
13 | void *addr;
14 | uint16_t row_size_bytes;
15 | union {
16 | uint16_t flags;
17 | struct {
18 | bool is_heap_allocated:1;
19 | uint16_t reserved:11;
20 | uint8_t version:4;
21 | }data;
22 | }info;
23 | } WIN32_GBitmap;
24 | #define GBITMAP_SET_INFO_FLAGS(bmpPtr,set) ((WIN32_GBitmap*)bmpPtr)->info.flags=set
25 | #define GBITMAP_SET_IS_HEAP_ALLOCATED(bmpPtr,is) ((WIN32_GBitmap*)bmpPtr)->info.data.is_heap_allocated=is
26 | #define GBITMAP_GET_INFO_FLAGS(bmpPtr) (((WIN32_GBitmap*)bmpPtr)->info.flags)
27 | #define GBITMAP_GET_IS_HEAP_ALLOCATED(bmpPtr) (((WIN32_GBitmap*)bmpPtr)->info.data.is_heap_allocated)
28 | #else
29 | #define GBITMAP_SET_INFO_FLAGS(bmpPtr,set) bmpPtr->info_flags=set
30 | #define GBITMAP_SET_IS_HEAP_ALLOCATED(bmpPtr,is) bmpPtr->is_heap_allocated=is
31 | #define GBITMAP_GET_INFO_FLAGS(bmpPtr) (bmpPtr->info_flags)
32 | #define GBITMAP_GET_IS_HEAP_ALLOCATED(bmpPtr) (bmpPtr->is_heap_allocated)
33 | #endif
34 |
35 | GBitmap* gbitmap_create_as_sub_bitmap(const GBitmap *base_bitmap, GRect sub_rect) {
36 | GBitmap* sub_bitmap=(GBitmap*)malloc(sizeof(GBitmap));
37 | if (!sub_bitmap) {
38 | printf ("Memory allocation failed!\n");
39 | return 0;
40 | }
41 | grect_clip (&sub_rect,&base_bitmap->bounds);
42 | sub_bitmap->addr=base_bitmap->addr;
43 | GBITMAP_SET_INFO_FLAGS(sub_bitmap,GBITMAP_GET_INFO_FLAGS(base_bitmap));
44 | GBITMAP_SET_IS_HEAP_ALLOCATED(sub_bitmap,false);
45 | sub_bitmap->row_size_bytes=base_bitmap->row_size_bytes;
46 | sub_bitmap->bounds=sub_rect;
47 | return sub_bitmap;
48 | }
49 |
50 | GBitmap* gbitmap_create_with_data (const uint8_t* data) {
51 | GBitmap* bitmap=(GBitmap*)malloc(sizeof(GBitmap));
52 | if (!bitmap) {
53 | printf ("Memory allocation failed!\n");
54 | return 0;
55 | }
56 | GBitmapHeader* header=(GBitmapHeader*)data;
57 | bitmap->addr=malloc(header->pitch*header->height);
58 | if (!bitmap->addr) {
59 | printf ("Memory allocation failed!\n");
60 | return 0;
61 | }
62 | memcpy(bitmap->addr,((uint8_t*)data)+sizeof(GBitmapHeader),header->pitch*header->height);
63 | bitmap->row_size_bytes=header->pitch;
64 | GBITMAP_SET_INFO_FLAGS(bitmap,header->info_flags);
65 | GBITMAP_SET_IS_HEAP_ALLOCATED(bitmap,true);
66 | bitmap->bounds=GRect(0,0,header->width,header->height);
67 | free((uint8_t*)data); //TODO: Verify this!
68 | return bitmap;
69 | }
70 |
71 | GBitmap* gbitmap_create_with_resource (uint32_t resource_id) {
72 | printf ("[DEBUG] Load resource ID:%d as image\n",resource_id);
73 | char name[MAX_RESOURCE_NAME];
74 | copyResName(name, RES_ID_TO_HANDLE(resource_id));
75 | FILE* f=fopen(name,"rb");
76 | if (!f) {
77 | printf("[ERROR] Couldn't load \"%s\"(%s)!\n",name,SDL_GetError());
78 | return 0;
79 | }
80 | fseek(f,0,SEEK_END);
81 | size_t len=ftell(f);
82 | fseek(f,0,SEEK_SET);
83 | void* data=malloc(len);
84 | if (!data) {
85 | printf("[ERROR] Couldn't load \"%s\"(Memory allocation failed)!\n",name);
86 | return 0;
87 | }
88 | size_t readLen=fread(data,1,len,f);
89 | fclose(f);
90 | if (len!=readLen) {
91 | printf ("[ERROR] Read error!\n");
92 | free(data);
93 | return 0;
94 | }
95 | return gbitmap_create_with_data (data);
96 | }
97 |
98 | void gbitmap_destroy(GBitmap* bitmap) {
99 | if (bitmap&&bitmap->addr&&GBITMAP_GET_IS_HEAP_ALLOCATED(bitmap)) {
100 | free(bitmap->addr);
101 | bitmap->addr=0;
102 | }
103 | }
104 |
105 | #define BITMAP_LAYER_GET Layer* bitmap_layer=(Layer*)l
106 | #define BITMAP_GET BITMAP_LAYER_GET;BitmapLayerData* bitmap=(BitmapLayerData*)layer_get_data(bitmap_layer)
107 | #define ROT_BITMAP_LAYER_GET Layer* rotbitmap_layer=(Layer*)l
108 | #define ROT_BITMAP_GET BITMAP_LAYER_GET;RotBitmapLayerData* rotbitmap=(RotBitmapLayerData*)layer_get_data(bitmap_layer)
109 |
110 | void bitmap_layer_update_func (Layer* l,GContext* ctx) {
111 | BITMAP_GET;
112 | GRect rect=GRect(0,0,l->frame.size.w,l->frame.size.h);
113 | graphics_context_set_fill_color(ctx,bitmap->background_color);
114 | graphics_fill_rect (ctx,rect,0,0);
115 | rect.origin=l->frame.origin;
116 | grect_align (&rect,&l->frame,bitmap->alignment,l->clips);
117 | rect.origin.x-=l->frame.origin.x;
118 | rect.origin.y-=l->frame.origin.y;
119 | graphics_context_set_compositing_mode (ctx,bitmap->compositing_mode);
120 | graphics_draw_bitmap_in_rect (ctx,bitmap->bitmap,rect);
121 | }
122 |
123 | BitmapLayer * bitmap_layer_create(GRect frame) {
124 | Layer* layer=layer_create_with_data(frame,sizeof(BitmapLayerData));
125 | if (!layer)
126 | return 0;
127 | BitmapLayerData* bitmap=(BitmapLayerData*)layer_get_data(layer);
128 | layer_set_update_proc(layer,bitmap_layer_update_func);
129 | bitmap->bitmap=0;
130 | bitmap->background_color=GColorClear;
131 | bitmap->alignment=GAlignCenter;
132 | bitmap->compositing_mode=GCompOpAssign;
133 | return (BitmapLayer*)layer;
134 | }
135 |
136 | void bitmap_layer_destroy (BitmapLayer* layer) {
137 | if (layer)
138 | layer_destroy((Layer*)layer);
139 | }
140 |
141 | Layer* bitmap_layer_get_layer (const BitmapLayer* layer) {
142 | return (Layer*)layer;
143 | }
144 |
145 | void bitmap_layer_set_bitmap(BitmapLayer *l, const GBitmap *image) {
146 | BITMAP_GET;
147 | bitmap->bitmap=image;
148 | }
149 |
150 | void bitmap_layer_set_alignment(BitmapLayer *l, GAlign alignment) {
151 | BITMAP_GET;
152 | bitmap->alignment=alignment;
153 | }
154 |
155 | void bitmap_layer_set_background_color(BitmapLayer *l, GColor color) {
156 | BITMAP_GET;
157 | bitmap->background_color=color;
158 | }
159 |
160 | void bitmap_layer_set_compositing_mode(BitmapLayer *l, GCompOp mode) {
161 | BITMAP_GET;
162 | bitmap->compositing_mode=mode;
163 | }
164 |
165 | void rot_bitmap_layer_update_func (Layer* l,GContext* ctx) {
166 | ROT_BITMAP_GET;
167 | GPoint topOffset=getTopOffset ();
168 | setTopOffset(GPoint(0,0));
169 | GRect rect=GRect(0,0,l->frame.size.w,l->frame.size.h);
170 |
171 | SDL_Surface* sur=createSurface(rotbitmap->bitmap->bounds.size.w,rotbitmap->bitmap->bounds.size.h);
172 | SDL_FillRect(sur,0,0);
173 | graphics_context_set_compositing_mode (ctx,GCompOpAssign);
174 | graphics_draw_bitmap_in_rect_to (ctx,rotbitmap->bitmap,rect,sur);
175 | double angle=(double)rotbitmap->rotation/TRIG_MAX_ANGLE*360.0;
176 | SDL_Surface* rotated=rotozoomSurface(sur,-angle,1.0,SMOOTHING_OFF);
177 | SDL_FreeSurface(sur);
178 | GPoint offset=getPivotRotationOffset(rotbitmap->bitmap->bounds.size,GSize(rotated->w,rotated->h),rotbitmap->src_ic,angle);
179 |
180 | rotbitmap->dest_ic.x=l->frame.size.w/2; //TODO: Verify this
181 | rotbitmap->dest_ic.y=l->frame.size.h/2;
182 |
183 | setTopOffset(topOffset);
184 | if (rotbitmap->corner_clip_color!=GColorClear) {
185 | graphics_context_set_fill_color(ctx,rotbitmap->corner_clip_color);
186 | graphics_fill_rect(ctx,GRect(0,0,l->frame.size.w,l->frame.size.h),0,0);
187 | }
188 | graphics_context_set_compositing_mode (ctx,rotbitmap->compositing_mode);
189 | graphics_draw_surface_in_rect (ctx,rotated,GRect(rotbitmap->dest_ic.x-offset.x,rotbitmap->dest_ic.y-offset.y,rotated->w,rotated->h));
190 | SDL_FreeSurface(rotated);
191 | }
192 |
193 | RotBitmapLayer* rot_bitmap_layer_create (GBitmap* bitmap) {
194 | Layer* layer=layer_create_with_data(GRect(0,0,bitmap->bounds.size.w,bitmap->bounds.size.h),sizeof(RotBitmapLayerData));
195 | RotBitmapLayerData* rotbitmap=(RotBitmapLayerData*)layer_get_data(layer);
196 | layer_set_update_proc(layer,rot_bitmap_layer_update_func);
197 | rotbitmap->bitmap=bitmap;
198 | rotbitmap->corner_clip_color=GColorClear;
199 | rotbitmap->rotation=0;
200 | rotbitmap->src_ic=GPoint(0,0);
201 | rotbitmap->dest_ic=GPoint(bitmap->bounds.size.w/2,bitmap->bounds.size.h/2);
202 | rotbitmap->compositing_mode=GCompOpAssign;
203 | return (RotBitmapLayer*)layer;
204 | }
205 |
206 | void rot_bitmap_layer_destroy (RotBitmapLayer* layer) {
207 | if (layer!=0)
208 | layer_destroy((Layer*)layer);
209 | }
210 |
211 | void rot_bitmap_layer_set_corner_clip_color (RotBitmapLayer* l,GColor color) {
212 | ROT_BITMAP_GET;
213 | rotbitmap->corner_clip_color=color;
214 | }
215 |
216 | void rot_bitmap_layer_set_angle(RotBitmapLayer* l,int32_t angle) {
217 | ROT_BITMAP_GET;
218 | rotbitmap->rotation=angle;
219 | }
220 |
221 | void rot_bitmap_layer_increment_angle (RotBitmapLayer* l,int32_t angle_change) {
222 | ROT_BITMAP_GET;
223 | rotbitmap->rotation+=angle_change;
224 | }
225 |
226 | void rot_bitmap_set_src_ic(RotBitmapLayer* l,GPoint ic) {
227 | ROT_BITMAP_GET;
228 | rotbitmap->src_ic=ic;
229 | }
230 |
231 | void rot_bitmap_set_compositing_mode(RotBitmapLayer* l,GCompOp mode) {
232 | ROT_BITMAP_GET;
233 | rotbitmap->compositing_mode=mode;
234 | }
235 |
--------------------------------------------------------------------------------
/src/local/bluetooth.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | //
4 | // This file implements the BluetoothConnectionService
5 | //
6 |
7 | static bool bluetooth_state = true;
8 | static bool bluetooth_notify = false;
9 | static BluetoothConnectionHandler bluetooth_callback = NULL;
10 | static SniffInterval currentSniffInterval = SNIFF_INTERVAL_NORMAL;
11 |
12 | void toggle_bluetooth_connection () {
13 | bluetooth_state = !bluetooth_state;
14 | bluetooth_notify = true;
15 | }
16 |
17 | bool bluetooth_connection_service_peek(void) {
18 | return bluetooth_state;
19 | }
20 |
21 | void bluetooth_connection_service_subscribe(BluetoothConnectionHandler handler) {
22 | bluetooth_callback = handler;
23 | bluetooth_notify = true;
24 | }
25 |
26 | void bluetooth_connection_service_unsubscribe(void) {
27 | bluetooth_callback = NULL;
28 | }
29 |
30 | void service_bluetooth() {
31 | if( bluetooth_notify && bluetooth_callback != NULL ) {
32 | bluetooth_callback(bluetooth_state);
33 | bluetooth_notify = false;
34 | }
35 | }
36 |
37 | SniffInterval app_comm_get_sniff_interval () {
38 | return currentSniffInterval;
39 | }
40 |
41 | void app_comm_set_sniff_interval (const SniffInterval interval) {
42 | currentSniffInterval = interval;
43 | }
44 |
--------------------------------------------------------------------------------
/src/local/buttons.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 | #include
3 |
4 | #define LONG_CLICK_STD_DELAY 500 // as per documentation
5 |
6 | typedef struct ClickRecognizer
7 | {
8 | ButtonId id;
9 | uint32_t lastDown;
10 | bool isDown;
11 | uint16_t clickCount; //reseted by multi_click.timeout
12 | bool longClick;
13 | } ClickRecognizer;
14 |
15 | static ClickConfig clickConfig [NUM_BUTTONS];
16 | static ClickConfig* clickConfigPtr [NUM_BUTTONS];
17 | static ClickRecognizer clickRecognizer [NUM_BUTTONS];
18 |
19 | ClickConfig** getClickConfig ()
20 | {
21 | return clickConfigPtr;
22 | }
23 |
24 | void resetClickConfig ()
25 | {
26 | int i;
27 | memset(clickConfig,0,sizeof(ClickConfig)*NUM_BUTTONS);
28 | for (i=0;iisDown)
56 | return;
57 | rec->clickCount++;
58 | rec->lastDown=SDL_GetTicks();
59 | rec->isDown=true;
60 | if (conf->raw.down_handler!=0) {
61 | conf->raw.down_handler(rec,conf->raw.context);
62 | handled=true;
63 | }
64 | if (conf->multi_click.handler!=0&&
65 | ((rec->clickCount>=conf->multi_click.min&&(conf->multi_click.max==0||rec->clickCount<=conf->multi_click.max)&&!conf->multi_click.last_click_only)||
66 | (rec->clickCount==conf->multi_click.max&&conf->multi_click.max!=0&&conf->multi_click.last_click_only))) {
67 | conf->multi_click.handler(rec,conf->context);
68 | handled=true;
69 | }
70 | if (!handled&&id==BUTTON_ID_BACK&&getWindowStackSize()>1)
71 | window_stack_pop (true);
72 | }
73 |
74 | void onButtonUp (ButtonId id)
75 | {
76 | ClickRecognizer* rec;
77 | ClickConfig* conf;
78 | rec=clickRecognizer+id;
79 | conf=clickConfig+id;
80 | rec->isDown=false;
81 | if (conf->click.handler!=0&&!rec->longClick)
82 | conf->click.handler(rec,conf->context);
83 | if (conf->raw.up_handler!=0)
84 | conf->raw.up_handler(rec,conf->raw.context);
85 | if (rec->longClick&&conf->long_click.delay_ms>0&&conf->long_click.release_handler!=0)
86 | conf->long_click.release_handler(rec,conf->context);
87 | rec->longClick=false;
88 | }
89 |
90 | void service_buttons ()
91 | {
92 | ClickRecognizer* rec;
93 | ClickConfig* conf;
94 | int i;
95 | for (i=0;imulti_click.timeout>0&&rec->lastDown>0&&SDL_GetTicks()-rec->lastDown>conf->multi_click.timeout)
99 | rec->clickCount=0;
100 | if (rec->isDown) {
101 | if (conf->click.handler!=0&&conf->click.repeat_interval_ms>0&&SDL_GetTicks()-rec->lastDown>=conf->click.repeat_interval_ms) {
102 | conf->click.handler(rec,conf->context);
103 | rec->lastDown=SDL_GetTicks();
104 | rec->clickCount++;
105 | }
106 | if (conf->long_click.delay_ms>0 && SDL_GetTicks()-rec->lastDown>=conf->long_click.delay_ms &&
107 | (conf->long_click.handler || conf->long_click.release_handler) && !rec->longClick) {
108 | if (conf->long_click.handler)
109 | conf->long_click.handler(rec,conf->context);
110 | rec->longClick=true;
111 | }
112 | }
113 | }
114 | }
115 |
116 | void buttonsUpdateWindow (Window* w)
117 | {
118 | resetClickConfig ();
119 | if (w!=0&&w->click_config_provider!=0)
120 | w->click_config_provider(w->click_config_context);
121 | }
122 |
123 | uint8_t click_number_of_clicks_counted (ClickRecognizerRef recognizer) {
124 | return ((ClickRecognizer*)recognizer)->clickCount;
125 | }
126 |
127 | ButtonId click_recognizer_get_button_id (ClickRecognizerRef recognizer) {
128 | return ((ClickRecognizer*)recognizer)->id;
129 | }
130 |
131 | void window_single_click_subscribe(ButtonId button_id,ClickHandler handler) {
132 | clickConfig[button_id].click.repeat_interval_ms=0;
133 | clickConfig[button_id].click.handler=handler;
134 | }
135 |
136 | void window_single_repeating_click_subscribe(ButtonId button_id,uint16_t repeat_interval_ms,ClickHandler handler) {
137 | clickConfig[button_id].click.repeat_interval_ms=repeat_interval_ms;
138 | clickConfig[button_id].click.handler=handler;
139 | }
140 |
141 | void window_multi_click_subscribe(ButtonId button_id,uint8_t min_clicks,uint8_t max_clicks,uint16_t timeout,bool last_click_only,ClickHandler handler) {
142 | clickConfig[button_id].multi_click.min=min_clicks;
143 | clickConfig[button_id].multi_click.max=max_clicks;
144 | clickConfig[button_id].multi_click.timeout=timeout;
145 | clickConfig[button_id].multi_click.last_click_only=last_click_only;
146 | clickConfig[button_id].multi_click.handler=handler;
147 | }
148 |
149 | void window_long_click_subscribe(ButtonId button_id,uint16_t delay_ms,ClickHandler down_handler,ClickHandler up_handler) {
150 | clickConfig[button_id].long_click.delay_ms=(delay_ms == 0 ? LONG_CLICK_STD_DELAY : delay_ms);
151 | clickConfig[button_id].long_click.handler=down_handler;
152 | clickConfig[button_id].long_click.release_handler=up_handler;
153 | }
154 |
155 | void window_raw_click_subscribe(ButtonId button_id,ClickHandler down_handler,ClickHandler up_handler,void* context) {
156 | clickConfig[button_id].raw.down_handler=down_handler;
157 | clickConfig[button_id].raw.up_handler=up_handler;
158 | clickConfig[button_id].raw.context=context;
159 | }
160 |
161 | void window_set_click_context (ButtonId button_id,void* context) {
162 | clickConfig[button_id].context=context;
163 | }
164 |
--------------------------------------------------------------------------------
/src/local/dummy/src/resource_ids.auto.h:
--------------------------------------------------------------------------------
1 | /*
2 | Because of some reasons (perhaps SDL?) changing the entry point creates crashes,
3 | but because pebble.h includes this file and all your pebble apps include pebble.h
4 | I change the name of your "main" function to "pbl_main"
5 | */
6 | #ifdef main
7 | #undef main
8 | #endif
9 |
10 | #define main pbl_main
11 |
--------------------------------------------------------------------------------
/src/local/font.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | enum SystemFontID {
4 | SYSTEM_FONT_GOTHIC_14=0,
5 | SYSTEM_FONT_GOTHIC_14_BOLD,
6 | SYSTEM_FONT_GOTHIC_18,
7 | SYSTEM_FONT_GOTHIC_18_BOLD,
8 | SYSTEM_FONT_GOTHIC_24,
9 | SYSTEM_FONT_GOTHIC_24_BOLD,
10 | SYSTEM_FONT_GOTHIC_28,
11 | SYSTEM_FONT_GOTHIC_28_BOLD,
12 | SYSTEM_FONT_BITHAM_30,
13 | SYSTEM_FONT_BITHAM_42_BOLD,
14 | SYSTEM_FONT_BITHAM_42_LIGHT,
15 | SYSTEM_FONT_BITHAM_42_MEDIUM_NUMBERS,
16 | SYSTEM_FONT_BITHAM_34_MEDIUM_NUMBERS,
17 | SYSTEM_FONT_BITHAM_34_LIGHT_SUBSET,
18 | SYSTEM_FONT_BITHAM_18_LIGHT_SUBSET,
19 | SYSTEM_FONT_ROBOTO_CONDENSED_21,
20 | SYSTEM_FONT_ROBOTO_BOLD_SUBSET_49,
21 | SYSTEM_DROID_SERIF_28_BOLD,
22 | SYSTEM_FONT_COUNT
23 | };
24 | struct SystemFont {
25 | TTF_Font* font;
26 | const char* key;
27 | const char* file;
28 | int psize;
29 | int lsize;
30 | };
31 | struct SystemFont systemFonts [SYSTEM_FONT_COUNT]= {
32 | {0,FONT_KEY_GOTHIC_14,"./systemFonts/gothic.ttf",8,14},
33 | {0,FONT_KEY_GOTHIC_14_BOLD,"./systemFonts/gothic-bold.ttf",8,14}, // 1 bold
34 | {0,FONT_KEY_GOTHIC_18,"./systemFonts/gothic.ttf",10,18},
35 | {0,FONT_KEY_GOTHIC_18_BOLD,"./systemFonts/gothic-bold.ttf",10,18}, // 3 bold
36 | {0,FONT_KEY_GOTHIC_24,"./systemFonts/gothic.ttf",14,24},
37 | {0,FONT_KEY_GOTHIC_24_BOLD,"./systemFonts/gothic-bold.ttf",14,24}, // 5 bold
38 | {0,FONT_KEY_GOTHIC_28,"./systemFonts/gothic.ttf",18,28},
39 | {0,FONT_KEY_GOTHIC_28_BOLD,"./systemFonts/gothic-bold.ttf",18,28}, // 7 bold
40 | {0,FONT_KEY_BITHAM_30_BLACK,"./systemFonts/bitham-black.ttf",30,30},
41 | {0,FONT_KEY_BITHAM_42_BOLD,"./systemFonts/bitham-bold.ttf",42,42}, // 9 bold
42 | {0,FONT_KEY_BITHAM_42_LIGHT,"./systemFonts/bitham-light.ttf",42,42},
43 | {0,FONT_KEY_BITHAM_42_MEDIUM_NUMBERS,"./systemFonts/bitham-medium-numbers.ttf",42,42},
44 | {0,FONT_KEY_BITHAM_34_MEDIUM_NUMBERS,"./systemFonts/bitham-medium-numbers.ttf",34,34},
45 | {0,FONT_KEY_BITHAM_34_LIGHT_SUBSET,"./systemFonts/bitham-light-subset.ttf",34,34},
46 | {0,FONT_KEY_BITHAM_18_LIGHT_SUBSET,"./systemFonts/bitham-light-subset.ttf",18,18},
47 | {0,FONT_KEY_ROBOTO_CONDENSED_21,"./systemFonts/roboto-condensed.ttf",21,21},
48 | {0,FONT_KEY_ROBOTO_BOLD_SUBSET_49,"./systemFonts/roboto-bold.ttf",49,49},
49 | {0,FONT_KEY_DROID_SERIF_28_BOLD,"./systemFonts/droid-serif-bold.ttf",28,28},
50 | };
51 |
52 | int lineHeightFromFont(GFont font) {
53 | for (int i=0; iframe.size.w,l->frame.size.h);
130 | graphics_context_set_fill_color(ctx,text->background_color);
131 | graphics_fill_rect (ctx,rect,0,0);
132 | graphics_context_set_text_color(ctx,text->text_color);
133 | graphics_draw_text (ctx,text->text,text->font,rect,text->overflow_mode,text->text_alignment,0);
134 | }
135 |
136 | TextLayer* text_layer_create(GRect frame) {
137 | Layer* layer=layer_create_with_data(frame,sizeof(TextLayerData));
138 | TextLayerData* text_layer=(TextLayerData*)layer_get_data(layer);
139 | layer_set_update_proc (layer,text_layer_update_func);
140 | text_layer->font = fonts_get_system_font(FONT_KEY_GOTHIC_14);
141 | text_layer->text_alignment = GTextAlignmentLeft;
142 | text_layer->text_color = GColorBlack;
143 | text_layer->background_color = GColorWhite;
144 | text_layer->overflow_mode = GTextOverflowModeWordWrap;
145 | text_layer->should_cache_layout = false;
146 | return (TextLayer*)layer;
147 | }
148 |
149 | void text_layer_destroy (TextLayer* layer) {
150 | if (layer)
151 | layer_destroy((Layer*)layer);
152 | }
153 |
154 | const char *text_layer_get_text(TextLayer *l) {
155 | TEXT_GET;
156 | return text->text;
157 | }
158 |
159 | void text_layer_set_text(TextLayer *l, const char *txt) {
160 | TEXT_GET;
161 | text->text = txt;
162 | layer_mark_dirty (text_layer);
163 | }
164 |
165 | void text_layer_set_font(TextLayer *l, GFont font) {
166 | TEXT_GET;
167 | text->font = font;
168 | layer_mark_dirty (text_layer);
169 | }
170 |
171 | void text_layer_set_text_color(TextLayer *l, GColor color) {
172 | TEXT_GET;
173 | text->text_color = color;
174 | layer_mark_dirty (text_layer);
175 | }
176 |
177 | void text_layer_set_background_color(TextLayer *l, GColor color) {
178 | TEXT_GET;
179 | text->background_color = color;
180 | layer_mark_dirty (text_layer);
181 | }
182 |
183 | void text_layer_set_overflow_mode(TextLayer *l, GTextOverflowMode line_mode) {
184 | TEXT_GET
185 | text->overflow_mode = line_mode;
186 | layer_mark_dirty (text_layer);
187 | }
188 |
189 | void text_layer_set_text_alignment(TextLayer *l, GTextAlignment text_alignment) {
190 | TEXT_GET;
191 | text->text_alignment = text_alignment;
192 | layer_mark_dirty (text_layer);
193 | }
194 |
195 | void text_layer_set_size(TextLayer *l, const GSize max_size) {
196 | TEXT_LAYER_GET;
197 | GRect frame=layer_get_frame (text_layer);
198 | frame.size=max_size;
199 | layer_set_frame (text_layer,frame);
200 | layer_mark_dirty (text_layer);
201 | }
202 |
203 | Layer* text_layer_get_layer (TextLayer* l) {
204 | return (Layer*)l;
205 | }
206 |
207 | GSize text_layer_get_content_size (TextLayer *l) {
208 | TEXT_GET;
209 | Layer *ll = (Layer*)l;
210 | GRect rect=GRect(0,0,ll->frame.size.w,ll->frame.size.h);
211 | GSize s = _graphics_draw_text (NULL,text->text,text->font,rect,text->overflow_mode,text->text_alignment,0,1);
212 | return s;
213 | }
214 |
--------------------------------------------------------------------------------
/src/local/globals.h:
--------------------------------------------------------------------------------
1 | #ifndef __GLOBALS_H__
2 | #define __GLOBALS_H__
3 | #include
4 | #include
5 | #include
6 |
7 | #include "impl_pebble.h"
8 |
9 | #include "SDL_gfxPrimitives.h"
10 | #include "SDL_gfxBlitFunc.h"
11 | #include "SDL_rotozoom.h"
12 |
13 | #ifdef WIN32
14 | #include
15 | #else
16 | #define min(A, B) (((A) < (B) ? (A) : (B)))
17 | #define max(A, B) (((A) > (B) ? (A) : (B)))
18 | #endif
19 |
20 | #define clamp(A, X, B) min(max(A, X), B)
21 |
22 | #define PI 3.14159265
23 | #define DEGtoRAD(deg) ((PI/180.0)*(deg))
24 |
25 | #include
26 | #include
27 | #include
28 |
29 | //SYSTEM SYSTEM SYSTEM SYSTEM SYSTEM SYSTEM SYSTEM SYSTEM SYSTEM SYSTEM SYSTEM SYSTEM
30 | #define SCROLL_LAYER_CLICK_DELAY 350
31 | #define SCROLL_LAYER_SCROLL_AMOUNT 25
32 | #define SCROLL_LAYER_SCROLL_DELAY 360
33 | #define SCROLL_LAYER_SCROLL_DELAY_MAX 350
34 | #define SCROLL_LAYER_SCROLL_SPEED ((double)SCROLL_LAYER_SCROLL_DELAY/SCROLL_LAYER_SCROLL_AMOUNT)
35 |
36 | extern int pbl_main (void);
37 |
38 | //#define APP_INFO __pbl_app_info
39 | //extern PebbleAppInfo __pbl_app_info;
40 | void toggle_24h_style ();
41 | void toggle_bluetooth_connection ();
42 | void toggle_battery_charger_plugged ();
43 |
44 | uint8_t battery_charge_increase(void);
45 | uint8_t battery_charge_decrease(void);
46 |
47 | void accel_do_tap_on_axis(AccelAxisType axis, int32_t direction);
48 |
49 | bool persistent_storage_load();
50 | bool persistent_storage_save();
51 | void persistent_storage_free();
52 |
53 | bool setup_js_app();
54 |
55 | //WATCHINFO WATCHINFO WATCHINFO WATCHINFO WATCHINFO WATCHINFO WATCHINFO
56 |
57 | #define WINDOW_WIDTH 390
58 | #define WINDOW_HEIGHT 440
59 | #define BODY_WIDTH 275
60 | #define BODY_HEIGHT 440
61 | #define BODY_OFFSET_X (WINDOW_WIDTH/2 - BODY_WIDTH/2)
62 | #define BODY_OFFSET_Y 0
63 | #define PBL_SCREEN_OFFSET_X (BODY_OFFSET_X + 65)
64 | #define PBL_SCREEN_OFFSET_Y (BODY_OFFSET_Y + 121)
65 |
66 | void drawBody (SDL_Surface* screen, uint8_t buttonState);
67 | void nextBody ();
68 |
69 | //SERVICES SERVICES SERVICES SERVICES SERVICES SERVICES SERVICES SERVICES
70 | typedef void (*ServiceUpdateCallback) (void);
71 | enum SimServices {
72 | SIM_SERVICE_BUTTONS=0,
73 | SIM_SERVICE_HARDWARE_OUTPUT,
74 | SIM_SERVICE_ANIMATIONS,
75 | SIM_SERVICE_TIMERS,
76 | SIM_SERVICE_TICKS,
77 | SIM_SERVICE_BLUETOOTH,
78 | SIM_SERVICE_BATTERY,
79 | SIM_SERVICE_ACCEL_TAP,
80 | SIM_SERVICE_APP_MESSAGE,
81 | SIM_SERVICE_COUNT
82 | };
83 | typedef struct {
84 | struct {
85 | TimeUnits units;
86 | TickHandler handler;
87 | } ticks;
88 | ServiceUpdateCallback services[SIM_SERVICE_COUNT];
89 | } ServiceData;
90 | extern ServiceData serviceData;
91 | void service_buttons ();
92 | void service_hardware_output ();
93 | void service_animations ();
94 | void service_timers ();
95 | void service_ticks ();
96 | void service_bluetooth ();
97 | void service_battery ();
98 | void service_accel_tap ();
99 | void service_app_message();
100 | void service_app_sync(DictionaryIterator*);
101 |
102 | //SIMDATA SIMDATA SIMDATA SIMDATA SIMDATA SIMDATA SIMDATA SIMDATA SIMDATA SIMDATA SIMDATA
103 | enum SimImages
104 | {
105 | SIM_IMG_BODY=0,
106 | SIM_IMG_SCREEN_SHADOW,
107 | SIM_IMG_BACKLIGHT,
108 | SIM_IMG_STATUS_BAR,
109 | SIM_IMG_VIBE,
110 | SIM_IMG_SCROLL_SHADOW,
111 | SIM_IMG_COUNT
112 | };
113 | bool loadSimulatorImages ();
114 | void freeSimulatorImages ();
115 | SDL_Surface* getSimulatorImage (int imageID);
116 | void unloadSystemFonts ();
117 | extern FILE* logFile;
118 |
119 | //DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW DRAW
120 | #define PBL_SCREEN_WIDTH 144
121 | #define PBL_SCREEN_HEIGHT 168
122 |
123 | #define LOCK(X) if(SDL_MUSTLOCK(X)) SDL_LockSurface(X)
124 | #define UNLOCK(X) if(SDL_MUSTLOCK(X)) SDL_UnlockSurface(X)
125 |
126 | struct GContext
127 | {
128 | GColor fill_color;
129 | GColor stroke_color;
130 | GColor text_color;
131 | GCompOp compositing_mode;
132 | };
133 |
134 | static const uint32_t r_white = 0xffffffff;
135 | static const uint32_t r_black = 0x000000ff;
136 | static const uint32_t r_clear = 0x00000000;
137 |
138 | extern uint32_t getRawColor(uint8_t color);
139 |
140 | extern SDL_Color s_white;
141 | extern SDL_Color s_black;
142 | extern SDL_Color s_clear;
143 |
144 | SDL_Color getColor(uint8_t color);
145 | void sdlrect_clip (SDL_Rect* const rect_to_clip,const SDL_Rect* const clipper);
146 |
147 | void graphics_draw_bitmap_in_rect_to(GContext* ctx,const GBitmap* bitmap,GRect,SDL_Surface* to);
148 | void graphics_draw_surface_in_rect (GContext* ctx,SDL_Surface* sur,GRect rect);
149 | void graphics_draw_surface_in_rect_to (GContext* ctx,SDL_Surface* sur,GRect rect,SDL_Surface* to);
150 | GContext *app_get_current_graphics_context(void);
151 | // Used to either draw or calculate size
152 | GSize _graphics_draw_text(GContext *ctx, const char *text, const GFont font, const GRect box, const GTextOverflowMode overflow_mode, const GTextAlignment alignment, const GTextLayoutCacheRef layout, int getSizeOnly);
153 | int lineHeightFromFont(GFont font);
154 |
155 | //BUTTONS BUTTONS BUTTONS BUTTONS BUTTONS BUTTONS BUTTONS BUTTONS BUTTONS BUTTONS
156 | void onButtonDown (ButtonId id);
157 | void onButtonUp (ButtonId id);
158 | void buttonsUpdateWindow (Window* w);
159 | void initButtons ();
160 | ClickConfig** getClickConfig ();
161 |
162 | //HARDWARE OUTPUT HARDWARE OUTPUT HARDWARE OUTPUT HARDWARE OUTPUT HARDWARE OUTPUT
163 | #define MAX_VIBE_ELEMENTS 32
164 | #define VIBE_SHORT_MS 300
165 | #define VIBE_LONG_MS 500
166 | #define LIGHT_LENGTH 2000
167 |
168 | bool getVibeState ();
169 | bool getLightState ();
170 |
171 | void initHardwareOutput ();
172 |
173 | //RENDER RENDER RENDER RENDER RENDER RENDER RENDER RENDER RENDER RENDER
174 | #define MAX_WINDOWS 8
175 | #define MAX_SCREEN_POOL 8
176 | #define MIN_SCREEN_POOL 4
177 | #define MAX_RENDER_LIST 12
178 |
179 | #define createSurface(w,h) (SDL_CreateRGBSurface (0,w,h,32,0xff000000,0x00ff0000,0x0000ff00,0x000000ff))
180 | #define createScreen createSurface(PBL_SCREEN_WIDTH,PBL_SCREEN_HEIGHT)
181 |
182 | bool initRender (SDL_Surface* screen);
183 | void quitRender ();
184 |
185 | void pushWindow (Window* w);
186 | void popWindow ();
187 | int getWindowStackSize ();
188 |
189 | SDL_Surface* pushScreen ();
190 | void popScreen ();
191 | SDL_Surface* getTopScreen ();
192 | void meltScreens ();
193 |
194 | void pushLayer (Layer* l);
195 | void popLayer ();
196 | void markDirty (bool toggle);
197 | GPoint getTopOffset ();
198 | void setTopOffset (GPoint set);
199 |
200 | bool render ();
201 |
202 | //TIMERS
203 | void freeTimers();
204 |
205 | //RESHELPER RESHELPER RESHELPER RESHELPER RESHELPER RESHELPER RESHELPER
206 | #define MAX_RESOURCE_NAME 32
207 | #define RESOURCE_NAME_BASE "./resources/%d"
208 | #ifdef __x86_64__
209 | # define RES_ID_TO_HANDLE(id) ((ResHandle)(uint64_t)(uint32_t)(id))
210 | #else
211 | # define RES_ID_TO_HANDLE(id) ((ResHandle)(uint32_t)(id))
212 | #endif
213 | void copyResName (char* name,ResHandle h);
214 |
215 | //ADDITIONAL PEBBLE OS ADDITIONAL PEBBLE OS ADDITIONAL PEBBLE OS
216 | //functions, the original pebble API might have but doesn't
217 | void gpoint_move_into_rect (GPoint* const point,const GRect* const rect);
218 |
219 | //Helper functions
220 | GPoint getPivotRotationOffset (GSize rectOrig,GSize rectRotated,GPoint pivot,double angle);
221 |
222 | #endif //__GLOBALS_H_
223 |
--------------------------------------------------------------------------------
/src/local/hardwareOutput.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | typedef struct VibeElement
4 | {
5 | bool vibe;
6 | uint32_t len;
7 | } VibeElement;
8 | static VibeElement vibes[MAX_VIBE_ELEMENTS];
9 | static int vibeStart=0;
10 | static int vibeSize=0;
11 | static bool currentVibe=false;
12 | static uint32_t vibesTick=0;
13 |
14 | static int light_length=0; //-1=on 0=off >0=on for light_length ms
15 | static int light_tick=0;
16 |
17 | void initHardwareOutput ()
18 | {
19 | }
20 |
21 | void service_hardware_output () {
22 | if (vibeSize>0) {
23 | if (vibesTick==0) {
24 | vibesTick=SDL_GetTicks();
25 | currentVibe=vibes[vibeStart].vibe;
26 | }
27 | if (SDL_GetTicks()-vibesTick>=vibes[vibeStart].len) {
28 | vibeStart++;
29 | if (vibeStart==MAX_VIBE_ELEMENTS)
30 | vibeStart=0;
31 | vibeSize--;
32 | if (vibeSize==0&¤tVibe)
33 | currentVibe=false;
34 | vibesTick=0;
35 | }
36 | }
37 | if (light_length>0&&SDL_GetTicks()-light_tick>=light_length)
38 | light_length=0;
39 | }
40 |
41 | bool getVibeState() {
42 | return currentVibe;
43 | }
44 |
45 | bool getLightState() {
46 | return (light_length!=0);
47 | }
48 |
49 | void vibes_cancel ()
50 | {
51 | vibeStart=0;
52 | vibeSize=0;
53 | }
54 |
55 | void addVibe (uint32_t len,bool vibe)
56 | {
57 | vibes[(vibeStart+vibeSize)%MAX_VIBE_ELEMENTS]=(VibeElement){vibe,len};
58 | vibeSize++;
59 | }
60 |
61 | void vibes_double_pulse ()
62 | {
63 | addVibe(VIBE_SHORT_MS,true);
64 | addVibe(VIBE_SHORT_MS,false);
65 | addVibe(VIBE_SHORT_MS,true);
66 | }
67 |
68 | void vibes_short_pulse ()
69 | {
70 | addVibe(VIBE_SHORT_MS,true);
71 | }
72 |
73 | void vibes_long_pulse ()
74 | {
75 | addVibe(VIBE_LONG_MS,true);
76 | }
77 |
78 | void vibes_enqueue_custom_pattern (VibePattern pattern)
79 | {
80 | int i;
81 | for (i=0;iframe = frame;
10 | layer->bounds=GRect(0,0,frame.size.w,frame.size.h);
11 | layer->clips=true;
12 | layer->hidden=false;
13 | layer->parent=0;
14 | layer->first_child=0;
15 | layer->next_sibling=0;
16 | layer->window=0;
17 | layer->update_proc=0;
18 | layer->extra_data=0;
19 | return layer;
20 | }
21 |
22 | Layer* layer_create_with_data (GRect frame,size_t size) {
23 | Layer* layer=layer_create(frame);
24 | if (!layer)
25 | return 0;
26 | layer->extra_data=malloc(size);
27 | if (!layer->extra_data) {
28 | printf ("[ERROR] Extra data allocation failed!\n");
29 | free(layer);
30 | return 0;
31 | }
32 | return layer;
33 | }
34 |
35 | void layer_destroy (Layer* layer) {
36 | if (layer) {
37 | layer_remove_from_parent(layer);
38 | if (layer->extra_data)
39 | free(layer->extra_data);
40 | free(layer);
41 | }
42 | }
43 |
44 | void layer_mark_dirty(Layer *layer) {
45 | if (layer!=0&&window_stack_get_top_window()==layer->window)
46 | markDirty (true);
47 | }
48 |
49 | void layer_remove_from_parent(Layer *child) {
50 | if (child==0||child->parent==0)
51 | return;
52 | child->window=0;
53 | Layer *cursor = child->parent->first_child;
54 | if(cursor == child||cursor==0) { //why cursor==0? big_time has this behaviour :(
55 | child->parent->first_child = child->next_sibling;
56 | } else {
57 | while(cursor->next_sibling != child) {
58 | cursor = cursor->next_sibling;
59 | }
60 | cursor->next_sibling = child->next_sibling;
61 | }
62 | layer_mark_dirty (child->parent);
63 | child->parent = NULL;
64 | child->next_sibling=0;
65 | }
66 |
67 | void layer_add_child(Layer *parent, Layer *child) {
68 | if (parent==0||child==0) {
69 | return;
70 | }
71 | if (child->parent!=0 && child->parent!=parent) {
72 | // re-parent as required by API docs
73 | layer_remove_from_parent(child);
74 | }
75 | layer_mark_dirty (parent);
76 | child->parent=parent;
77 | child->window=parent->window;
78 | if (parent==child)
79 | return; //big_time .... why does the original sdk allow this?!
80 | else if(parent->first_child == NULL) {
81 | parent->first_child = child;
82 | } else {
83 | parent = parent->first_child;
84 | while(parent->next_sibling != NULL) {
85 | if (parent->next_sibling==child) //big_time .... why does the original sdk allow this?!
86 | return;
87 | parent = parent->next_sibling;
88 | }
89 | parent->next_sibling = child;
90 | }
91 | }
92 |
93 | GRect layer_get_frame(const Layer *layer) {
94 | return layer->frame;
95 | }
96 |
97 | void layer_set_frame(Layer *layer, GRect frame) {
98 | if (!grect_equal(&layer->frame,&frame)) {
99 | layer->frame = frame;
100 | //extend bounds
101 | if (layer->bounds.origin.x+layer->bounds.size.wframe.size.w)
102 | layer->bounds.size.w=layer->frame.size.w-layer->bounds.origin.x;
103 | if (layer->bounds.origin.y+layer->bounds.size.hframe.size.h)
104 | layer->bounds.size.h=layer->frame.size.h-layer->bounds.origin.y;
105 | layer_mark_dirty (layer);
106 | }
107 | }
108 |
109 | void layer_set_hidden(Layer *layer, bool hidden) {
110 | if (layer->hidden!=hidden) {
111 | layer->hidden = hidden;
112 | layer_mark_dirty(layer->parent);
113 | }
114 | }
115 |
116 | void layer_set_bounds(Layer *layer, GRect bounds) {
117 | if (!grect_equal(&layer->bounds,&bounds)) {
118 | layer->bounds = bounds;
119 | layer_mark_dirty(layer);
120 | }
121 | }
122 |
123 | GRect layer_get_bounds(const Layer *layer) {
124 | return layer->bounds;
125 | }
126 |
127 | void layer_set_update_proc(Layer *layer, LayerUpdateProc update_proc) {
128 | layer->update_proc = update_proc;
129 | }
130 |
131 | struct Window *layer_get_window(const Layer *layer) {
132 | return layer->window;
133 | }
134 |
135 | void layer_remove_child_layers(Layer *parent) {
136 | Layer *cursor = parent->first_child;
137 | while(cursor != NULL) {
138 | cursor->parent = NULL;
139 | Layer* const next = cursor->next_sibling;
140 | cursor->next_sibling = NULL;
141 | cursor = next;
142 | }
143 | parent->first_child = NULL;
144 | layer_mark_dirty (parent);
145 | }
146 |
147 | void* layer_get_data (const Layer* layer) {
148 | return layer->extra_data;
149 | }
150 |
151 | void layer_insert_below_sibling(Layer *layer_to_insert, Layer *below_sibling_layer) {
152 | if(layer_to_insert->parent != below_sibling_layer->parent) {
153 | // layers have to have the same parent otherwise this is a no-op
154 | return;
155 | }
156 | Layer* prev_sibling = below_sibling_layer;
157 | while(prev_sibling->next_sibling != layer_to_insert) {
158 | prev_sibling = prev_sibling->next_sibling;
159 | if(prev_sibling == NULL) {
160 | // that should not happen with a common parent!
161 | return;
162 | }
163 | }
164 | prev_sibling->next_sibling = layer_to_insert->next_sibling;
165 | layer_to_insert->next_sibling = below_sibling_layer->next_sibling;
166 | below_sibling_layer->next_sibling = layer_to_insert;
167 |
168 | layer_to_insert->parent = below_sibling_layer->parent;
169 | layer_to_insert->window = below_sibling_layer->window;
170 | layer_mark_dirty (below_sibling_layer);
171 | }
172 |
173 | void layer_insert_above_sibling(Layer *layer_to_insert, Layer *above_sibling_layer) {
174 | if(above_sibling_layer->parent->first_child == above_sibling_layer) {
175 | above_sibling_layer->parent->first_child = layer_to_insert;
176 | } else {
177 | Layer *cursor = above_sibling_layer->parent->first_child;
178 | while(cursor->next_sibling != above_sibling_layer) {
179 | cursor = cursor->next_sibling;
180 | }
181 |
182 | cursor->next_sibling = layer_to_insert;
183 | }
184 |
185 | layer_to_insert->next_sibling = above_sibling_layer;
186 | layer_to_insert->parent = above_sibling_layer->parent;
187 | layer_to_insert->window = above_sibling_layer->window;
188 | layer_mark_dirty(layer_to_insert);
189 | }
190 |
191 |
192 | bool layer_get_hidden(const Layer *layer) {
193 | return layer->hidden;
194 | }
195 |
196 | void layer_set_clips(Layer *layer, bool clips) {
197 | layer->clips = clips;
198 | layer_mark_dirty (layer);
199 | }
200 |
201 | bool layer_get_clips(const Layer *layer) {
202 | return layer->clips;
203 | }
204 |
--------------------------------------------------------------------------------
/src/local/math.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | int32_t atan2_lookup (int16_t y, int16_t x) {
4 | return (int32_t)(atan2((double)y, (double)x) / (2*PI) * TRIG_MAX_ANGLE);
5 | }
6 |
7 | int32_t sin_lookup(int32_t angle) {
8 | return (int32_t)(sin((double)angle/TRIG_MAX_RATIO* 2*PI)*TRIG_MAX_RATIO);
9 | }
10 |
11 | int32_t cos_lookup(int32_t angle) {
12 | return (int32_t)(cos((double)angle/TRIG_MAX_RATIO* 2*PI)*TRIG_MAX_RATIO);
13 | }
14 |
15 | GPath* gpath_create(const GPathInfo *init) {
16 | GPath* path=(GPath*)malloc(sizeof(GPath));
17 | if (!path) {
18 | printf ("[ERROR] Memory allocation failed!\n");
19 | return 0;
20 | }
21 | path->points=(GPoint*)malloc(sizeof(GPoint)*init->num_points);
22 | if (!path->points) {
23 | printf ("[ERROR] Memory allocation failed!\n");
24 | free(path);
25 | return 0;
26 | }
27 | path->rotation=0;
28 | path->offset=GPointZero;
29 | path->num_points = init->num_points;
30 | memcpy(path->points,init->points,sizeof(GPoint)*init->num_points);
31 | return path;
32 | }
33 |
34 | void gpath_destroy (GPath* path) {
35 | if (path) {
36 | if (path->points)
37 | free(path->points);
38 | free(path);
39 | }
40 | }
41 |
42 | void gpath_move_to(GPath *path, GPoint point) {
43 | path->offset = point;
44 | }
45 |
46 | void gpath_rotate_to(GPath *path, int32_t angle) {
47 | path->rotation = angle%TRIG_MAX_ANGLE;
48 | }
49 |
50 | GPoint grect_center_point(const GRect *rect) {
51 | GPoint output;
52 | output.x = rect->origin.x + (rect->size.w)/2;
53 | output.y = rect->origin.y + (rect->size.h)/2;
54 |
55 | return output;
56 | }
57 |
58 | bool gpoint_equal(const GPoint * const point_a, const GPoint * const point_b) {
59 | return (point_a->x==point_b->x&&point_a->y==point_b->y);
60 | }
61 |
62 | bool gsize_equal(const GSize *size_a, const GSize *size_b) {
63 | return (size_a->w==size_b->w&&size_a->h==size_b->h);
64 | }
65 |
66 | bool grect_equal (const GRect* const a,const GRect* const b) {
67 | if (a==0||b==0)
68 | return false;
69 | return (a->origin.x==b->origin.x&&
70 | a->origin.y==b->origin.y&&
71 | a->size.w==b->size.w&&
72 | a->size.h==b->size.h);
73 | }
74 |
75 | bool grect_contains_point(const GRect *rect,const GPoint *point) {
76 | return (point->x>=rect->origin.x&&
77 | point->x<=rect->origin.x+rect->size.w&&
78 | point->y>=rect->origin.y&&
79 | point->y<=rect->origin.y+rect->size.h);
80 | }
81 |
82 | GRect grect_crop(GRect rect, const int crop_size_px) {
83 | rect.origin.x+=crop_size_px;
84 | rect.origin.y+=crop_size_px;
85 | rect.size.w-=2*crop_size_px;
86 | rect.size.h-=2*crop_size_px;
87 | return rect;
88 | }
89 |
90 | bool grect_is_empty(const GRect * const rect) {
91 | return (rect->size.w==0&&rect->size.h==0);
92 | }
93 |
94 | void grect_standardize(GRect *rect) {
95 | if (rect->size.w<0) {
96 | rect->origin.x+=rect->size.w;
97 | rect->size.w=-rect->size.w;
98 | }
99 | if (rect->size.h<0) {
100 | rect->origin.y-=rect->size.h;
101 | rect->size.h=-rect->size.h;
102 | }
103 | }
104 |
105 | void grect_clip(GRect * const rect_to_clip, const GRect * const rect_clipper) {
106 | int16_t x,y;
107 | if (rect_to_clip==0||rect_clipper==0)
108 | return;
109 | if (rect_to_clip->origin.xorigin.x) {
110 | x=rect_clipper->origin.x-rect_to_clip->origin.x;
111 | rect_to_clip->origin.x=rect_clipper->origin.x;
112 | rect_to_clip->size.w-=x;
113 | }
114 | if (rect_to_clip->origin.yorigin.y) {
115 | y=rect_clipper->origin.y-rect_to_clip->origin.y;
116 | rect_to_clip->origin.y=rect_clipper->origin.y;
117 | rect_to_clip->size.h-=y;
118 | }
119 | if (rect_to_clip->origin.x+rect_to_clip->size.w>rect_clipper->origin.x+rect_clipper->size.w)
120 | rect_to_clip->size.w=rect_clipper->size.w-rect_to_clip->origin.x;
121 | if (rect_to_clip->origin.y+rect_to_clip->size.h>rect_clipper->origin.y+rect_clipper->size.h)
122 | rect_to_clip->size.h=rect_clipper->size.h-rect_to_clip->origin.y;
123 | }
124 |
125 | void grect_align(GRect *rect, const GRect *inside_rect, const GAlign alignment, const bool clip) {
126 | if (alignment==GAlignLeft||alignment==GAlignTopLeft||alignment==GAlignBottomLeft) //overall X: left alignment
127 | rect->origin.x=inside_rect->origin.x;
128 | else if (alignment==GAlignRight||alignment==GAlignTopRight||alignment==GAlignBottomRight) //overall X: right alignment
129 | rect->origin.x=inside_rect->origin.x+inside_rect->size.w-rect->size.w;
130 | else if (alignment==GAlignCenter||alignment==GAlignTop||alignment==GAlignBottom) //overall X: center alignment
131 | rect->origin.x=inside_rect->origin.x+inside_rect->size.w/2-rect->size.w/2;
132 | if (alignment==GAlignTop||alignment==GAlignTopLeft||alignment==GAlignTopRight) //overall Y: top alignment
133 | rect->origin.y=inside_rect->origin.y;
134 | else if (alignment==GAlignBottom||alignment==GAlignBottomLeft||alignment==GAlignTopRight) //overall Y: bottom alignment
135 | rect->origin.y=inside_rect->origin.y+inside_rect->size.h-rect->size.h;
136 | else if (alignment==GAlignCenter||alignment==GAlignLeft||alignment==GAlignRight) //overall Y: center alignment
137 | rect->origin.y=inside_rect->origin.y+inside_rect->size.h/2-rect->size.h/2;
138 | if (clip)
139 | grect_clip (rect,inside_rect);
140 | }
141 |
142 | void sdlrect_clip(SDL_Rect * const rect_to_clip, const SDL_Rect * const rect_clipper) {
143 | int16_t x,y;
144 | if (rect_to_clip==0||rect_clipper==0)
145 | return;
146 | if (rect_to_clip->xx) {
147 | x=rect_clipper->x-rect_to_clip->x;
148 | rect_to_clip->x=rect_clipper->x;
149 | rect_to_clip->w-=x;
150 | }
151 | if (rect_to_clip->yy) {
152 | y=rect_clipper->y-rect_to_clip->y;
153 | rect_to_clip->y=rect_clipper->y;
154 | rect_to_clip->h-=y;
155 | }
156 | if (rect_to_clip->x+rect_to_clip->w>rect_clipper->x+rect_clipper->w) {
157 | rect_to_clip->w=rect_clipper->w-rect_to_clip->x;
158 | }
159 | if (rect_to_clip->y+rect_to_clip->h>rect_clipper->y+rect_clipper->h) {
160 | rect_to_clip->h=rect_clipper->h-rect_to_clip->y;
161 | }
162 | }
163 |
164 | GPoint getPivotRotationOffset(GSize rectOrig,GSize rectRotated,GPoint pivot,double angle) {
165 | GPoint offset;
166 | pivot.x-=rectOrig.w/2;
167 | pivot.y-=rectOrig.h/2;
168 | angle*=PI/180.0;
169 | double s=sin(angle);
170 | double c=cos(angle);
171 | offset.x=pivot.x*c - pivot.y*s + rectRotated.w/2;
172 | offset.y=pivot.x*s + pivot.y*c + rectRotated.h/2;
173 | return offset;
174 | }
175 |
176 | void gpoint_move_into_rect (GPoint* const point,const GRect* const rect) {
177 | point->x=clamp(rect->origin.x,point->x,rect->origin.x+rect->size.w);
178 | point->y=clamp(rect->origin.y,point->y,rect->origin.y+rect->size.h);
179 | }
180 |
--------------------------------------------------------------------------------
/src/local/pebble_os.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | static bool clock24hStyle=true;
4 |
5 | void inverter_layer_update (Layer* me,GContext* ctx) {
6 | SDL_Surface* myScreen=getTopScreen ();
7 | SDL_Rect rect;
8 | uint32_t* pixel;
9 | int x,y;
10 | meltScreens();
11 | SDL_GetClipRect(myScreen,&rect);
12 | LOCK(myScreen);
13 | if (rect.w>0&&rect.h>0) {
14 | for (y=rect.y;ypixels)+y*myScreen->pitch+4*x);
17 | *pixel=~(*pixel) | 0x000000ff;
18 | }
19 | }
20 | }
21 | UNLOCK(myScreen);
22 | }
23 |
24 | InverterLayer* inverter_layer_create(GRect frame) {
25 | Layer* layer=layer_create(frame);
26 | if (!layer)
27 | return 0;
28 | layer_set_update_proc(layer,inverter_layer_update);
29 | return (InverterLayer*) layer;
30 | }
31 |
32 | void inverter_layer_destroy (InverterLayer* layer) {
33 | if (layer)
34 | layer_destroy((Layer*)layer);
35 | }
36 |
37 | Layer* inverter_layer_get_layer (InverterLayer* layer) {
38 | return (Layer*)layer;
39 | }
40 |
41 | void app_log(uint8_t log_level, const char *src_filename, int src_line_number, const char *fmt, ...) {
42 | static const char* logLevels []={"ERROR","WARNING","INFO","DEBUG","DBG-VERBOSE"};
43 | va_list args;
44 | log_level=log_level/50-(log_level>100?1:0); //To map log_level to the element in the array ^
45 | printf ("[LOG][%s][%s:%d] ",logLevels[log_level],src_filename,src_line_number);
46 | if (logFile!=0)
47 | fprintf (logFile,"[%s][%s:%d] ",logLevels[log_level],src_filename,src_line_number);
48 | va_start(args,fmt);
49 | vfprintf (stdout,fmt,args);
50 | printf ("\n");
51 | va_end (args);
52 | if (logFile!=0) {
53 | va_start(args,fmt);
54 | vfprintf (logFile,fmt,args);
55 | fprintf (logFile,"\n");
56 | va_end (args);
57 | }
58 | }
59 |
60 | void copyResName(char* name,ResHandle h) {
61 | #ifdef __x86_64__
62 | const int32_t id = (uint32_t)(uint64_t)(h);
63 | #else
64 | const int32_t id = (uint32_t)(h);
65 | #endif
66 | memset(name,0,MAX_RESOURCE_NAME);
67 | sprintf (name,RESOURCE_NAME_BASE,id);
68 | }
69 |
70 | ResHandle resource_get_handle(uint32_t file_id) {
71 | return RES_ID_TO_HANDLE(file_id);
72 | }
73 |
74 | size_t resource_load(ResHandle h, uint8_t *buffer, size_t max_length) {
75 | char name[MAX_RESOURCE_NAME];
76 | copyResName(name, h);
77 | FILE* f=fopen (name,"rb");
78 | if (f==0) {
79 | printf ("[WARN] Couldn't load raw resource\n");
80 | return 0;
81 | }
82 | max_length=fread(buffer,1,max_length,f);
83 | fclose(f);
84 | return max_length;
85 | }
86 |
87 | size_t resource_load_byte_range(ResHandle h, uint32_t start_bytes, uint8_t *data, size_t num_bytes) {
88 | char name[MAX_RESOURCE_NAME];
89 | copyResName(name, h);
90 | FILE* f=fopen(name,"rb");
91 | if (f==0) {
92 | printf ("[WARN] Couldn't load raw resource\n");
93 | return 0;
94 | }
95 | fseek(f,start_bytes,SEEK_SET);
96 | num_bytes=fread(data,1,num_bytes,f);
97 | fclose(f);
98 | return num_bytes;
99 | }
100 |
101 | size_t resource_size(ResHandle h) {
102 | size_t len;
103 | char name[MAX_RESOURCE_NAME];
104 | copyResName(name, h);
105 | FILE* f=fopen (name,"rb");
106 | if (f==0) {
107 | printf ("[WARN] Couldn't load raw resource\n");
108 | return 0;
109 | }
110 | fseek(f,0,SEEK_END);
111 | len=ftell (f);
112 | fclose(f);
113 | return len;
114 | }
115 |
116 | void psleep(int millis) {
117 | SDL_Delay(millis);
118 | }
119 |
120 | bool clock_is_24h_style(void) {
121 | return clock24hStyle;
122 | }
123 |
124 | void toggle_24h_style () {
125 | clock24hStyle=!clock24hStyle;
126 | }
127 |
128 | void clock_copy_time_string(char *buffer, uint8_t size) {
129 | time_t timeSec=time(0);
130 | struct tm* tim=localtime(&timeSec);
131 | if (clock_is_24h_style())
132 | strftime (buffer,size,"%H:%M",tim);
133 | else
134 | strftime(buffer,size,"%I:%M",tim);
135 | }
136 |
137 | uint16_t time_ms (time_t* tloc,uint16_t* out_ms) {
138 | uint32_t ms=SDL_GetTicks();
139 | ms-=ms/1000; //this is not pretty accurate...
140 | if (tloc)
141 | time (tloc);
142 | if (out_ms)
143 | *out_ms=(uint16_t)ms;
144 | return ms;
145 | }
146 |
147 | bool uuid_equal (const Uuid* u1, const Uuid* u2) {
148 | return memcmp(u1, u2, sizeof(Uuid)) == 0;
149 | }
150 |
151 | void uuid_to_string (const Uuid* u, char* buffer) {
152 | static const char* UUID_SPRINTF_FORMAT =
153 | "{%02hhX%02hhX%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}";
154 | sprintf(buffer, UUID_SPRINTF_FORMAT,
155 | u->byte0, u->byte1, u->byte2, u->byte3,
156 | u->byte4, u->byte5,
157 | u->byte6, u->byte7,
158 | u->byte8, u->byte9,
159 | u->byte10, u->byte11, u->byte12, u->byte13);
160 | }
161 |
--------------------------------------------------------------------------------
/src/local/persistent_storage.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 | #include
3 |
4 | #define STORAGE_DATA "persistent.store"
5 |
6 | //
7 | // This file implements the Storage API
8 | //
9 | // Values created by persist_* are stored in a global storage which is then
10 | // stored in "persistent.store" in build/local/ alongside the other simdata.
11 | // Persistent keys will survive as long as this file exists.
12 | //
13 |
14 | typedef enum {
15 | KEY_UNUSED = 0,
16 | KEY_BOOL,
17 | KEY_INTEGER,
18 | KEY_STRING,
19 | KEY_DATA
20 | } PersistentKeyType;
21 |
22 | typedef struct _PersistentKey {
23 | uint32_t id;
24 | PersistentKeyType type;
25 | union {
26 | bool boolean;
27 | int32_t integer;
28 | char string[PERSIST_STRING_MAX_LENGTH];
29 | uint8_t data[PERSIST_DATA_MAX_LENGTH];
30 | } val;
31 | size_t byte_size; // required for string / data, used by all others :)
32 | } __attribute__((__packed__)) PersistentKey;
33 |
34 | static int key_count = 0;
35 | static PersistentKey* key_store = NULL;
36 |
37 | // key lookup to reduce code duplication
38 | static PersistentKey* _lookup_key(const uint32_t key, const bool get_unused) {
39 | int i;
40 |
41 | if (key_store == NULL || key_count == 0) {
42 | return NULL;
43 | }
44 |
45 | for(i = 0; i < key_count; ++i) {
46 | if (get_unused && key_store[i].type == KEY_UNUSED) {
47 | // return first free
48 | return &key_store[i];
49 | }
50 | else {
51 | if (key_store[i].id == key && key_store[i].type != KEY_UNUSED) {
52 | return &key_store[i];
53 | }
54 | }
55 | }
56 |
57 | if (get_unused) {
58 | // no free keys, we have to create a new one..
59 | key_store = (PersistentKey*)realloc(key_store, sizeof(PersistentKey) * (key_count + 1));
60 | if (key_store == NULL) {
61 | // oops.. disable the store
62 | printf("[ERROR] out of memory while reallocating the key_store!\n");
63 | key_count = 0;
64 | return NULL;
65 | }
66 | else {
67 | // a new blank key :)
68 | key_store[key_count].id = 0;
69 | key_store[key_count].type = KEY_UNUSED;
70 | return &key_store[key_count++];
71 | }
72 | }
73 | return NULL;
74 | }
75 |
76 | // simulator access
77 |
78 | bool persistent_storage_load() {
79 | if(key_store != NULL) {
80 | printf("[WARNING] multiple calls to persistant_storage_load!\n");
81 | return false;
82 | }
83 |
84 | FILE* handle = fopen(STORAGE_DATA, "rb");
85 | if (handle == NULL) {
86 | printf("[ERROR] could not read '%s' - persist_* will start with fresh data!\n", STORAGE_DATA);
87 | key_count = 0;
88 | }
89 | else {
90 | fseek(handle, 0, SEEK_END);
91 | key_count = ftell(handle) / sizeof(PersistentKey);
92 | fseek(handle, 0, SEEK_SET);
93 |
94 | if (key_count == 0) {
95 | fclose(handle);
96 | }
97 | }
98 |
99 | if(key_count == 0) {
100 | // no keys, either it's a first initialization or the old file was corrupt
101 | key_count = 1;
102 | key_store = (PersistentKey*)malloc(sizeof(PersistentKey));
103 | if (key_store == NULL) {
104 | printf("[ERROR] failed to allocate memory for persistant storage!\n");
105 | return false;
106 | }
107 |
108 | key_store[0].id = 0;
109 | key_store[0].type = KEY_UNUSED;
110 | }
111 | else {
112 | // read stored data
113 | key_store = (PersistentKey*)malloc(sizeof(PersistentKey) * key_count);
114 | if (key_store == NULL) {
115 | printf("[ERROR] failed to allocate memory for persistant storage!\n");
116 | return false;
117 | }
118 |
119 | uint8_t* ptr = (uint8_t*)key_store;
120 | size_t total, read = 0;
121 |
122 | total = key_count * sizeof(PersistentKey);
123 | while ((read = fread(ptr, 1, total, handle)) != total) {
124 | ptr += read;
125 | total -= read;
126 |
127 | if (total == 0) {
128 | break;
129 | }
130 | }
131 | fclose(handle);
132 | }
133 |
134 | printf("[INFO] Got %d keys from '%s'\n", key_count, STORAGE_DATA);
135 | return true;
136 | }
137 |
138 | bool persistent_storage_save() {
139 | if (key_store == NULL || key_count == 0) {
140 | printf("[INFO] Persistant storeg is empty.\n");
141 | return true;
142 | }
143 |
144 | FILE* handle = fopen(STORAGE_DATA, "wb");
145 | if (handle == NULL) {
146 | printf("[ERROR] could not write to '%s'!\n", STORAGE_DATA);
147 | return false;
148 | }
149 |
150 | uint8_t* ptr = (uint8_t*)key_store;
151 | size_t total, written = 0;
152 |
153 | total = key_count * sizeof(PersistentKey);
154 | while ((written = fwrite(ptr, 1, total, handle)) != total) {
155 | ptr += written;
156 | total -= written;
157 |
158 | if (total == 0) {
159 | break;
160 | }
161 | }
162 | fclose(handle);
163 |
164 | printf("[INFO] Wrote %d keys to '%s'\n", key_count, STORAGE_DATA);
165 | return true;
166 | }
167 |
168 | void persistent_storage_free() {
169 | persistent_storage_save();
170 | if (key_store != NULL) {
171 | free(key_store);
172 | key_store = NULL;
173 | key_count = 0;
174 | }
175 | }
176 |
177 | // pebble API part
178 |
179 | status_t persist_delete(const uint32_t key) {
180 | PersistentKey* ptr = NULL;
181 |
182 | ptr = _lookup_key(key, false);
183 | if (ptr != NULL) {
184 | if (ptr->id == key && ptr->type != KEY_UNUSED) {
185 | ptr->id = 0;
186 | ptr->type = KEY_UNUSED;
187 |
188 | return S_SUCCESS;
189 | }
190 | }
191 | return E_DOES_NOT_EXIST;
192 | }
193 |
194 | bool persist_exists(const uint32_t key) {
195 | return (_lookup_key(key, false) != NULL);
196 | }
197 |
198 | int persist_get_size(const uint32_t key) {
199 | PersistentKey* ptr = NULL;
200 |
201 | ptr = _lookup_key(key, false);
202 | if (ptr != NULL) {
203 | return ptr->byte_size;
204 | }
205 | return E_DOES_NOT_EXIST;
206 | }
207 |
208 | bool persist_read_bool(const uint32_t key) {
209 | PersistentKey* ptr = NULL;
210 |
211 | ptr = _lookup_key(key, false);
212 | if (ptr != NULL && ptr->type == KEY_BOOL) {
213 | return ptr->val.boolean;
214 | }
215 | return false;
216 | }
217 |
218 | int persist_read_data(const uint32_t key, void* buffer, const size_t buffer_size) {
219 | PersistentKey* ptr = NULL;
220 |
221 | ptr = _lookup_key(key, false);
222 | if (ptr != NULL && ptr->type == KEY_DATA) {
223 | size_t cnt = (buffer_size < ptr->byte_size) ? buffer_size : ptr->byte_size;
224 |
225 | if (buffer == NULL) {
226 | return 0;
227 | }
228 |
229 | memcpy(buffer, ptr->val.data, cnt);
230 | return cnt;
231 | }
232 | return E_DOES_NOT_EXIST;
233 | }
234 |
235 | int32_t persist_read_int(const uint32_t key) {
236 | PersistentKey* ptr = NULL;
237 |
238 | ptr = _lookup_key(key, false);
239 | if (ptr != NULL && ptr->type == KEY_INTEGER) {
240 | return ptr->val.integer;
241 | }
242 | return 0;
243 | }
244 |
245 | int persist_read_string(const uint32_t key, char* buffer, const size_t buffer_size) {
246 | PersistentKey* ptr = NULL;
247 |
248 | ptr = _lookup_key(key, false);
249 | if (ptr != NULL && ptr->type == KEY_STRING) {
250 | size_t cnt = (buffer_size < ptr->byte_size) ? buffer_size : ptr->byte_size;
251 |
252 | if (buffer == NULL) {
253 | return 0;
254 | }
255 |
256 | memcpy(buffer, ptr->val.string, cnt);
257 | return cnt;
258 | }
259 | return E_DOES_NOT_EXIST;
260 | }
261 |
262 | status_t persist_write_bool(const uint32_t key, const bool value) {
263 | PersistentKey* ptr = NULL;
264 |
265 | ptr = _lookup_key(key, false);
266 | if (ptr == NULL) {
267 | ptr = _lookup_key(key, true);
268 | }
269 | if (ptr != NULL) {
270 | memset(ptr, 0, sizeof(PersistentKey));
271 |
272 | ptr->id = key;
273 | ptr->type = KEY_BOOL;
274 | ptr->val.boolean = value;
275 | ptr->byte_size = sizeof(bool);
276 |
277 | return S_SUCCESS;
278 | }
279 | return E_OUT_OF_STORAGE;
280 | }
281 |
282 | int persist_write_data(const uint32_t key, const void* value, const size_t size) {
283 | PersistentKey* ptr = NULL;
284 |
285 | if (value == NULL) {
286 | return E_INVALID_ARGUMENT;
287 | }
288 |
289 | ptr = _lookup_key(key, false);
290 | if (ptr == NULL) {
291 | ptr = _lookup_key(key, true);
292 | }
293 | if (ptr != NULL) {
294 | size_t cnt = (size < PERSIST_DATA_MAX_LENGTH) ? size : PERSIST_DATA_MAX_LENGTH;
295 | memset(ptr, 0, sizeof(PersistentKey));
296 |
297 | ptr->id = key;
298 | ptr->type = KEY_DATA;
299 | ptr->byte_size = cnt;
300 |
301 | memcpy(ptr->val.data, value, cnt);
302 | return cnt;
303 | }
304 | return E_OUT_OF_STORAGE;
305 | }
306 |
307 | status_t persist_write_int(const uint32_t key, const int32_t value) {
308 | PersistentKey* ptr = NULL;
309 |
310 | ptr = _lookup_key(key, false);
311 | if (ptr == NULL) {
312 | ptr = _lookup_key(key, true);
313 | }
314 | if (ptr != NULL) {
315 | memset(ptr, 0, sizeof(PersistentKey));
316 |
317 | ptr->id = key;
318 | ptr->type = KEY_INTEGER;
319 | ptr->val.integer = value;
320 | ptr->byte_size = sizeof(int32_t);
321 |
322 | return S_SUCCESS;
323 | }
324 | return E_OUT_OF_STORAGE;
325 | }
326 |
327 | int persist_write_string(const uint32_t key, const char* cstring) {
328 | PersistentKey* ptr = NULL;
329 |
330 | if (cstring == NULL) {
331 | return E_INVALID_ARGUMENT;
332 | }
333 |
334 | ptr = _lookup_key(key, false);
335 | if (ptr == NULL) {
336 | ptr = _lookup_key(key, true);
337 | }
338 | if (ptr != NULL) {
339 | size_t cnt = strlen(cstring);
340 | cnt = (cnt < PERSIST_STRING_MAX_LENGTH - 1) ? cnt : PERSIST_STRING_MAX_LENGTH;
341 |
342 | memset(ptr, 0, sizeof(PersistentKey));
343 |
344 | ptr->id = key;
345 | ptr->type = KEY_STRING;
346 | ptr->byte_size = cnt;
347 |
348 | memcpy(ptr->val.string, cstring, cnt);
349 | return cnt;
350 | }
351 | return E_OUT_OF_STORAGE;
352 | }
353 |
--------------------------------------------------------------------------------
/src/local/render.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | #define STATUS_TIME_BUFFER_SIZE 16
4 |
5 | typedef struct RenderEntry
6 | {
7 | SDL_Surface* clipScreen;
8 | Layer* layer;
9 | } RenderEntry;
10 |
11 | static Window* windowStack [MAX_WINDOWS];
12 | static int windowStackSize=0;
13 | static bool isDirty=true;
14 | static SDL_Surface* screenPool [MAX_SCREEN_POOL];
15 | static int screenPoolSize=0;
16 | static int usedScreenPool=0;
17 | static RenderEntry renderList [MAX_RENDER_LIST];
18 | static int renderListSize=0;
19 | static GPoint topOffset;
20 | static SDL_Surface* statusImg;
21 | static const GBitmap* statusBarIcon [MAX_WINDOWS];
22 | static int statusBarIconSize=0;
23 | static char statusTimeBuffer[STATUS_TIME_BUFFER_SIZE]={0};
24 | static GFont statusTimeFont;
25 | static bool statusBarVisible=true;
26 |
27 | bool initRender (SDL_Surface* screen)
28 | {
29 | for (screenPoolSize=0;screenPoolSize0&&windowStack[windowStackSize-1]->window_handlers.disappear!=0)
62 | windowStack[windowStackSize-1]->window_handlers.disappear(windowStack[windowStackSize-1]);
63 | windowStack[windowStackSize]=w;
64 | windowStackSize++;
65 | //topOffset=w->layer.frame.origin;
66 | if (!w->is_loaded) {
67 | if (w->window_handlers.load)
68 | w->window_handlers.load (w);
69 | w->is_loaded=true;
70 | }
71 | if (w->window_handlers.appear)
72 | w->window_handlers.appear (w);
73 | if (w->status_bar_icon) {
74 | statusBarIcon[statusBarIconSize]=w->status_bar_icon;
75 | statusBarIconSize++;
76 | }
77 | statusBarVisible=!window_stack_get_top_window ()->is_fullscreen;
78 | buttonsUpdateWindow(window_stack_get_top_window ());
79 | markDirty(true);
80 | }
81 |
82 | void popWindow () {
83 | Window* w=window_stack_get_top_window ();
84 | windowStackSize--;
85 | if (w->window_handlers.disappear)
86 | w->window_handlers.disappear(w);
87 | w->is_loaded = false;
88 | if (w->window_handlers.unload)
89 | w->window_handlers.unload(w);
90 | windowStack[windowStackSize]=0;
91 | if (windowStackSize>0) {
92 | w=windowStack[windowStackSize-1];
93 | topOffset=w->layer->frame.origin;
94 | if (w->window_handlers.appear)
95 | w->window_handlers.appear(w);
96 | }
97 | if (w->status_bar_icon)
98 | statusBarIconSize--;
99 | if (windowStackSize>0)
100 | statusBarVisible=!window_stack_get_top_window ()->is_fullscreen;
101 | buttonsUpdateWindow(window_stack_get_top_window ());
102 | markDirty(true);
103 | }
104 |
105 | int getWindowStackSize() {
106 | return windowStackSize;
107 | }
108 |
109 | SDL_Surface* pushScreen () {
110 | if (screenPool[usedScreenPool]==0)
111 | screenPool[usedScreenPool]=createScreen;
112 | SDL_Surface* screen=screenPool[usedScreenPool];
113 | usedScreenPool++;
114 | SDL_FillRect(screen,0,0x00000000);
115 | return screen;
116 | }
117 |
118 | void popScreen () {
119 | usedScreenPool--;
120 | }
121 |
122 | SDL_Surface* getTopScreen () {
123 | int i;
124 | for (i=renderListSize-1;i>=0;i--) {
125 | if (renderList[i].clipScreen!=0)
126 | return renderList[i].clipScreen;
127 | }
128 | return 0;
129 | }
130 |
131 | void pushLayer (Layer* l) {
132 | renderList[renderListSize].layer=l;
133 | renderList[renderListSize].clipScreen=pushScreen();
134 | if (l->clips) {
135 | SDL_Rect rect={topOffset.x+l->frame.origin.x,topOffset.y+l->frame.origin.y,l->frame.size.w,l->frame.size.h};
136 | SDL_SetClipRect (renderList[renderListSize].clipScreen,&rect);
137 | }
138 | renderListSize++;
139 | topOffset.x+=l->bounds.origin.x+l->frame.origin.x;
140 | topOffset.y+=l->bounds.origin.y+l->frame.origin.y;
141 | }
142 |
143 | void popLayer () {
144 | Layer* l=renderList[renderListSize-1].layer;
145 | topOffset.x-=l->bounds.origin.x+l->frame.origin.x;
146 | topOffset.y-=l->bounds.origin.y+l->frame.origin.y;
147 | popScreen ();
148 | SDL_Surface* src=getTopScreen ();
149 | renderListSize--;
150 | SDL_Surface* dst=getTopScreen ();
151 | SDL_SetClipRect(src,0);
152 | SDL_gfxBlitRGBA(src,0,dst,0);
153 | }
154 |
155 | void markDirty (bool toggle) {
156 | isDirty=toggle;
157 | }
158 |
159 | GPoint getTopOffset () {
160 | return topOffset;
161 | }
162 |
163 | void setTopOffset (GPoint set) {
164 | topOffset=set;
165 | }
166 |
167 | void renderLayer (Layer* l,GContext* ctx) {
168 | if (l->hidden==true)
169 | return;
170 | pushLayer (l);
171 | Layer* cursor=l->first_child;
172 | if (l->update_proc)
173 | l->update_proc (l,ctx);
174 | while (cursor!=0) {
175 | renderLayer (cursor,ctx);
176 | cursor=cursor->next_sibling;
177 | }
178 | popLayer ();
179 | }
180 |
181 | void window_render (Window* w,GContext* ctx)
182 | {
183 | Layer* cursor;
184 | if (w!=0) {
185 | SDL_FillRect(getTopScreen(),0,getRawColor (w->background_color));
186 | cursor=w->layer;
187 | while (cursor!=0) {
188 | renderLayer(cursor,ctx);
189 | cursor=cursor->next_sibling;
190 | }
191 | }
192 | }
193 |
194 | bool render () {
195 | SDL_Rect src,dst;
196 | if (isDirty==true) {
197 | SDL_FillRect(getTopScreen(),0,r_black);
198 | window_render(window_stack_get_top_window (),app_get_current_graphics_context());
199 | //Render status bar
200 | if (statusBarVisible) {
201 | dst=(SDL_Rect){0,0,144,16};
202 | SDL_FillRect (getTopScreen (),&dst,r_black);
203 | if (statusBarIconSize>0) {
204 | graphics_draw_bitmap_in_rect (app_get_current_graphics_context(),statusBarIcon[statusBarIconSize-1],GRect(8-statusBarIcon[statusBarIconSize-1]->bounds.size.w/2,8-statusBarIcon[statusBarIconSize-1]->bounds.size.h/2,statusBarIcon[statusBarIconSize-1]->bounds.size.w,statusBarIcon[statusBarIconSize-1]->bounds.size.h));
205 | }
206 | else {
207 | src=(SDL_Rect){0,0,16,16};
208 | dst.w=16;
209 | SDL_BlitSurface(statusImg,&src,getTopScreen(),&dst);
210 | }
211 | src=(SDL_Rect){16,0,16,16};
212 | dst=(SDL_Rect){144-18,0,16,16};
213 | SDL_BlitSurface(statusImg,&src,getTopScreen(),&dst);
214 | clock_copy_time_string(statusTimeBuffer,STATUS_TIME_BUFFER_SIZE);
215 | graphics_context_set_text_color (app_get_current_graphics_context(),GColorWhite);
216 | graphics_draw_text (app_get_current_graphics_context(),statusTimeBuffer,statusTimeFont,GRect(0,0,144,16),GTextOverflowModeTrailingEllipsis,GTextAlignmentCenter,0);
217 | }
218 |
219 | isDirty=false;
220 | return true;
221 | }
222 | return false;
223 | }
224 |
225 | bool window_stack_contains_window(Window *window) {
226 | int i;
227 | for (i=0;iframe.size.h;
14 | offset.y*=-1;
15 | gpoint_move_into_rect(&offset,&to);
16 | offset.y*=-1;
17 | to.size.h+=scroll_layer->frame.size.h;
18 | to.origin=offset;
19 | return to;
20 | }
21 |
22 | void scroll_layer_shadow_layer_update_func (Layer* me,GContext* ctx) {
23 | ScrollLayer* scroll_layer=(ScrollLayer*)me->parent;
24 | SDL_Surface* scroll_shadow=getSimulatorImage(SIM_IMG_SCROLL_SHADOW);
25 | GPoint topOffset=getTopOffset();
26 | SDL_Surface* screen=getTopScreen ();
27 | GPoint offset=scroll_layer_get_content_offset (scroll_layer);
28 | GSize size=scroll_layer_get_content_size (scroll_layer);
29 | GSize frameSize=me->frame.size;
30 | SDL_Rect src,dst;
31 | if (offset.y<0) {
32 | src=(SDL_Rect){0,15,144,15};
33 | dst=(SDL_Rect){topOffset.x,topOffset.y,144,15};
34 | SDL_gfxBlitRGBA(scroll_shadow,&src,screen,&dst);
35 | }
36 | if (offset.y-((Layer*)scroll_layer)->frame.size.h!=-size.h) {
37 | src=(SDL_Rect){0,0,144,15};
38 | dst=(SDL_Rect){topOffset.x,topOffset.y+frameSize.h-15,144,15};
39 | SDL_gfxBlitRGBA(scroll_shadow,&src,screen,&dst);
40 | }
41 | }
42 |
43 | void scroll_layer_click_config_provider (void* context) {
44 | window_single_repeating_click_subscribe(BUTTON_ID_UP,SCROLL_LAYER_CLICK_DELAY,scroll_layer_scroll_up_click_handler);
45 | window_set_click_context(BUTTON_ID_UP,context);
46 | window_single_repeating_click_subscribe(BUTTON_ID_DOWN,SCROLL_LAYER_CLICK_DELAY,scroll_layer_scroll_down_click_handler);
47 | window_set_click_context(BUTTON_ID_DOWN,context);
48 | ScrollLayerData* scroll=(ScrollLayerData*)layer_get_data((Layer*)context);
49 | window_set_click_context(BUTTON_ID_SELECT,(scroll->context==0?context:scroll->context));
50 | if (scroll->callbacks.click_config_provider!=0)
51 | scroll->callbacks.click_config_provider(context);
52 | }
53 |
54 | ScrollLayer* scroll_layer_create(GRect frame) {
55 | Layer* layer=layer_create_with_data(frame,sizeof(ScrollLayerData));
56 | if (!layer)
57 | return 0;
58 | ScrollLayerData* scroll=(ScrollLayerData*)layer_get_data(layer);
59 | scroll->content_sublayer=layer_create ((GRect){{0,0},frame.size});
60 | if (!scroll->content_sublayer) {
61 | free(layer);
62 | return 0;
63 | }
64 | scroll->shadow_sublayer=layer_create ((GRect){{0,0},frame.size});
65 | if (!scroll->shadow_sublayer) {
66 | free(scroll->content_sublayer);
67 | free(layer);
68 | return 0;
69 | }
70 | scroll->animation=0;
71 | layer_set_update_proc(scroll->shadow_sublayer,scroll_layer_shadow_layer_update_func);
72 | layer_add_child (layer,scroll->content_sublayer);
73 | layer_add_child (layer,scroll->shadow_sublayer);
74 | scroll->callbacks.click_config_provider=0;
75 | scroll->callbacks.content_offset_changed_handler=0;
76 | scroll->context=0;
77 | return (ScrollLayer*)layer;
78 | }
79 |
80 | void scroll_layer_destroy (ScrollLayer* l) {
81 | if (l!=0) {
82 | SCROLL_GET;
83 | if (scroll->animation)
84 | property_animation_destroy(scroll->animation);
85 | layer_destroy(scroll->content_sublayer);
86 | layer_destroy(scroll->shadow_sublayer);
87 | layer_destroy(scroll_layer);
88 | }
89 | }
90 |
91 | void scroll_layer_add_child(ScrollLayer *l, Layer *child) {
92 | SCROLL_GET;
93 | layer_add_child (scroll->content_sublayer,child);
94 | }
95 |
96 | void scroll_layer_set_click_config_onto_window(ScrollLayer *l, struct Window *window) {
97 | window_set_click_config_provider_with_context(window,scroll_layer_click_config_provider,l);
98 | }
99 |
100 | void scroll_layer_set_callbacks(ScrollLayer *l, ScrollLayerCallbacks callbacks) {
101 | SCROLL_GET;
102 | scroll->callbacks=callbacks;
103 | }
104 |
105 | void scroll_layer_set_context(ScrollLayer *l, void *context) {
106 | SCROLL_GET;
107 | scroll->context=context;
108 | }
109 |
110 | void scroll_layer_set_content_offset(ScrollLayer *l, GPoint offset, bool animated) {
111 | SCROLL_GET;
112 | if (gpoint_equal(&scroll->content_sublayer->frame.origin,&offset))
113 | return;
114 | offset.x=0;
115 | GPoint oldOffset=scroll_layer_get_content_offset(l);
116 | GRect to=scroll_layer_get_new_content_rect(l,offset);
117 | if (animated) {
118 | if (scroll->animation)
119 | property_animation_destroy(scroll->animation);
120 | scroll->animation=property_animation_create_layer_frame(scroll->content_sublayer,0,&to);
121 | double duration=to.origin.y-oldOffset.y;
122 | if (duration<25||duration>-25)
123 | duration=abs(duration)*SCROLL_LAYER_SCROLL_SPEED;
124 | else
125 | duration=1;
126 | animation_set_duration((Animation*)scroll->animation,duration);
127 | animation_schedule((Animation*)scroll->animation);
128 | }
129 | else {
130 | scroll->content_sublayer->frame.origin=offset;
131 | layer_mark_dirty(scroll_layer);
132 | }
133 | if (scroll->callbacks.content_offset_changed_handler!=0)
134 | scroll->callbacks.content_offset_changed_handler(l,scroll->context);
135 | }
136 |
137 | GPoint scroll_layer_get_content_offset(ScrollLayer *l) {
138 | SCROLL_GET;
139 | return scroll->content_sublayer->frame.origin;
140 | }
141 |
142 | void scroll_layer_set_content_size(ScrollLayer *l, GSize size) {
143 | SCROLL_GET;
144 | layer_set_frame(scroll->content_sublayer,(GRect){scroll->content_sublayer->frame.origin,size});
145 | }
146 |
147 | GSize scroll_layer_get_content_size(const ScrollLayer *l) {
148 | SCROLL_GET;
149 | return scroll->content_sublayer->frame.size;
150 | }
151 |
152 | void scroll_layer_set_frame(ScrollLayer *l, GRect rect) {
153 | SCROLL_GET;
154 | layer_set_frame(scroll_layer,rect);
155 | layer_set_frame(scroll->shadow_sublayer,(GRect){{0,0},rect.size});
156 | }
157 |
158 | void scroll_layer_scroll_up_click_handler(ClickRecognizerRef recognizer, void *l) {
159 | ScrollLayer* scroll_layer=(ScrollLayer*)l;
160 | GPoint offset=scroll_layer_get_content_offset(scroll_layer);
161 | offset.y+=SCROLL_LAYER_SCROLL_AMOUNT;
162 | scroll_layer_set_content_offset(scroll_layer,offset,true);
163 | }
164 |
165 | void scroll_layer_scroll_down_click_handler(ClickRecognizerRef recognizer, void *l) {
166 | ScrollLayer* scroll_layer=(ScrollLayer*)l;
167 | GPoint offset=scroll_layer_get_content_offset(scroll_layer);
168 | offset.y-=SCROLL_LAYER_SCROLL_AMOUNT;
169 | scroll_layer_set_content_offset(scroll_layer,offset,true);
170 | }
171 |
172 | void scroll_layer_set_shadow_hidden (ScrollLayer* l,bool hidden) {
173 | SCROLL_GET;
174 | layer_set_hidden(scroll->shadow_sublayer,hidden);
175 | }
176 |
177 | bool scroll_layer_get_shadow_hidden (const ScrollLayer* l) {
178 | SCROLL_GET;
179 | return layer_get_hidden(scroll->shadow_sublayer);
180 | }
181 |
--------------------------------------------------------------------------------
/src/local/simdata.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | #define SIM_FILE_BUFFER 64
4 | #define SIM_IMG_BASE_NAME "./images/%s"
5 |
6 | typedef struct SimDataImage
7 | {
8 | const char* fileName;
9 | SDL_Surface* surface;
10 | } SimDataImage;
11 |
12 | SimDataImage simImages [SIM_IMG_COUNT]={
13 | {"body.png",0},
14 | {"screenshadow.png",0},
15 | {"backlight.png",0},
16 | {"statusbar.png",0},
17 | {"vibe.png",0},
18 | {"scrollshadow.png",0}
19 | };
20 |
21 | bool loadSimulatorImages() {
22 | char fileBuffer[SIM_FILE_BUFFER]={0};
23 | for (int i=0;inext != NULL) {
27 | tp = tp->next;
28 | }
29 |
30 | tp->next = timer;
31 | timer->next = 0;
32 | }
33 |
34 | bool remove_timer(AppTimer*timer) {
35 | AppTimer *tp = timers;
36 |
37 | if (timer == NULL)
38 | return false;
39 |
40 | // if first element, set head of list to next pointer
41 | if (tp == timer) {
42 | timers = tp->next;
43 | free(timer);
44 | return true;
45 | }
46 |
47 | // find the timer that's supposed to be deleted from the list
48 | while ( (tp != NULL) && (tp->next != timer)) {
49 | if (tp->next == NULL) {
50 | printf("ERROR: Timer could not be removed. Timer handle not existent!");
51 | return false;
52 | }
53 | tp = tp->next;
54 | }
55 |
56 | //remove timer from list if it exists
57 | if (tp == NULL) {
58 | printf("ERROR: Timer could not be removed. Timer handle not existent!");
59 | return false;
60 | } else {
61 | tp->next = tp->next->next;
62 | free(timer);
63 | }
64 |
65 | return true;
66 | }
67 |
68 | AppTimer* find_expired_timer() {
69 | AppTimer* tp = timers;
70 |
71 | //find the first expired timer in the list
72 | while (tp != NULL) {
73 | //check if timer has expired
74 | if (SDL_GetTicks() >= tp->timeout) {
75 | return tp;
76 | }
77 |
78 | tp = tp->next;
79 | }
80 |
81 | return NULL;
82 | }
83 |
84 | bool is_timer_registered (AppTimer* timer) {
85 | AppTimer* tp=timers;
86 | while (tp!=0&&tp!=timer)
87 | tp=tp->next;
88 | return tp==timer;
89 | }
90 |
91 | void service_timers () {
92 | AppTimer *timer = NULL;
93 | //find all rexpired timers, call timer handler on them, and remove them
94 | while ( (timer = find_expired_timer()) != NULL ) {
95 | timer->callback(timer->context);
96 | remove_timer(timer);
97 | }
98 | }
99 |
100 | AppTimer* app_timer_register (uint32_t timeout_ms,AppTimerCallback callback,void* callback_data) {
101 | if (callback==0)
102 | return 0;
103 | AppTimer* timer=(AppTimer*)malloc(sizeof(AppTimer));
104 | if (timer==0) {
105 | printf ("[ERROR] Timer memory allocation failed!\n");
106 | return 0;
107 | }
108 | timer->timeout=SDL_GetTicks()+timeout_ms;
109 | timer->callback=callback;
110 | timer->context=callback_data;
111 | timer->next = NULL;
112 | add_timer(timer);
113 | return timer;
114 | }
115 |
116 | bool app_timer_reschedule (AppTimer* timer_handle,uint32_t new_timeout_ms) {
117 | if (is_timer_registered(timer_handle)) {
118 | timer_handle->timeout=SDL_GetTicks()+new_timeout_ms;
119 | return true;
120 | }
121 | else
122 | return false;
123 | }
124 |
125 | void app_timer_cancel(AppTimer* timer_handle) {
126 | remove_timer(timer_handle);
127 | }
128 |
129 | void tick_timer_service_subscribe (TimeUnits units,TickHandler handler) {
130 | serviceData.ticks.units=units;
131 | serviceData.ticks.handler=handler;
132 | }
133 |
134 | void tick_timer_service_unsubscribe (void) {
135 | serviceData.ticks.handler=0;
136 | }
137 |
138 | void service_ticks() {
139 | if (serviceData.ticks.handler!=0) {
140 | time_t timeSec=time(0);
141 | struct tm* tim=localtime(&timeSec);
142 | TimeUnits units=serviceData.ticks.units;
143 | TimeUnits changed=0;
144 |
145 | if (!firstTick) {
146 | if ((units&SECOND_UNIT) >0 && tim->tm_sec!=_then.tm_sec)
147 | changed |= SECOND_UNIT;
148 | if ((units&MINUTE_UNIT) >0 && tim->tm_min!=_then.tm_min)
149 | changed |= MINUTE_UNIT;
150 | if ((units&HOUR_UNIT) >0 && tim->tm_hour!=_then.tm_hour)
151 | changed |= HOUR_UNIT;
152 | if ((units&DAY_UNIT) >0 && tim->tm_yday!=_then.tm_yday)
153 | changed |= DAY_UNIT;
154 | if ((units&MONTH_UNIT) >0 && tim->tm_mon!=_then.tm_mon)
155 | changed |= MONTH_UNIT;
156 | if ((units&YEAR_UNIT) >0 && tim->tm_year!=_then.tm_year)
157 | changed |= YEAR_UNIT;
158 | }
159 |
160 | if (firstTick||changed!=0) {
161 | memcpy(&_then,tim,sizeof(struct tm));
162 | serviceData.ticks.handler (tim,changed);
163 | firstTick=false;
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/src/local/watchinfo.c:
--------------------------------------------------------------------------------
1 | #include "globals.h"
2 |
3 | #define WATCH_COLOR_COUNT (WATCH_INFO_COLOR_PINK + 1)
4 |
5 | static const SDL_Rect buttonRects [NUM_BUTTONS * 2]= {
6 | //Original pebble
7 | {16, 127, 6, 80},
8 | {252, 91, 6, 80},
9 | {252, 187, 6, 50},
10 | {252, 253, 6, 80},
11 |
12 | //Pebble Steel
13 | {12, 131, 13, 63},
14 | {247, 133, 13, 63},
15 | {250, 196, 11, 48},
16 | {247, 244, 12, 62}
17 | };
18 |
19 | static WatchInfoColor currentWatchColor = WATCH_INFO_COLOR_RED;
20 |
21 | bool getIsBodySteel () {
22 | return watch_info_get_model() == WATCH_INFO_MODEL_PEBBLE_STEEL;
23 | }
24 |
25 | void nextBody () {
26 | currentWatchColor = (currentWatchColor + 1) % WATCH_COLOR_COUNT;
27 | }
28 |
29 | void drawBody (SDL_Surface* screen, uint8_t buttonState) {
30 | SDL_Surface* bodyImg = getSimulatorImage(SIM_IMG_BODY);
31 | SDL_Rect dst, src;
32 | int i;
33 |
34 | for (i=0; ilayer=layer_create(GRect(0, 0, 144, 168));
10 | if (window->layer==0) {
11 | free(window);
12 | return 0;
13 | }
14 | window->is_fullscreen=true; //TODO: copy appinfo.json to output and read if app is watchface or watchapp
15 | window->is_loaded=false;
16 | window->background_color=GColorWhite;
17 | window->user_data=0;
18 | window->click_config_context=0;
19 | window->status_bar_icon=0;
20 | window->click_config_provider=0;
21 | window->layer->window=window;
22 | window->window_handlers.load=0;
23 | window->window_handlers.unload=0;
24 | window->window_handlers.appear=0;
25 | window->window_handlers.disappear=0;
26 | return window;
27 | }
28 |
29 | void window_destroy (Window* window) {
30 | if (window) {
31 | layer_destroy(window->layer);
32 | free(window);
33 | }
34 | }
35 |
36 | void window_set_click_config_provider(Window *window, ClickConfigProvider click_config_provider) {
37 | window->click_config_provider = click_config_provider;
38 | if (window_stack_get_top_window()==window)
39 | buttonsUpdateWindow (window);
40 | }
41 |
42 | void window_set_background_color(Window *window, GColor background_color) {
43 | if (window->background_color!=background_color) {
44 | window->background_color=background_color;
45 | layer_mark_dirty (window->layer);
46 | }
47 | }
48 |
49 | void window_set_fullscreen(Window *window, bool enabled) {
50 | window->is_fullscreen = enabled;
51 |
52 | if (enabled==true)
53 | window->layer->bounds.origin.y=0;
54 | else
55 | window->layer->bounds.origin.y=16;
56 | }
57 |
58 | void window_deinit(Window *window) {
59 | if (window->window_handlers.unload!=0)
60 | window->window_handlers.unload (window);
61 | if (window_stack_contains_window (window))
62 | window_stack_remove(window,false);
63 | }
64 |
65 | void window_set_click_config_provider_with_context(Window *window, ClickConfigProvider click_config_provider, void *context) {
66 | window->click_config_provider=click_config_provider;
67 | window->click_config_context=context;
68 | if (window_stack_get_top_window()==window)
69 | buttonsUpdateWindow (window);
70 | }
71 |
72 | ClickConfigProvider window_get_click_config_provider(const Window *window) {
73 | return window->click_config_provider;
74 | }
75 |
76 | void window_set_window_handlers(Window *window, WindowHandlers handlers) {
77 | window->window_handlers=handlers;
78 | }
79 |
80 | struct Layer *window_get_root_layer(const Window *window) {
81 | return window->layer;
82 | }
83 |
84 | bool window_get_fullscreen(const Window *window) {
85 | return window->is_fullscreen;
86 | }
87 |
88 | void window_set_status_bar_icon(Window *window, const GBitmap *icon) {
89 | window->status_bar_icon=icon;
90 | }
91 |
92 | bool window_is_loaded(Window *window) {
93 | return window->is_loaded;
94 | }
95 |
96 | void window_set_user_data (Window* window,void* user_data) {
97 | window->user_data=user_data;
98 | }
99 |
100 | void* window_get_user_data (const Window* window) {
101 | return window->user_data;
102 | }
103 |
104 | void window_stack_push(Window *window, bool animated) {
105 | pushWindow(window);
106 | }
107 |
108 | Window *window_stack_pop(bool animated) {
109 | Window* w=window_stack_get_top_window ();
110 | popWindow ();
111 | return w; //no documentation about return?
112 | }
113 |
114 | void window_stack_pop_all(const bool animated) {
115 | while (window_stack_get_top_window ())
116 | popWindow ();
117 | }
118 |
--------------------------------------------------------------------------------