├── .gitignore
├── .jshintrc
├── .travis.yml
├── LICENSE
├── Makefile
├── README.md
├── appinfo.json
├── design
└── multi-timer_ideas_01.sketch
├── marketing
├── banner_02.png
├── banner_02.xcf
├── banner_03.png
├── banner_03.sketch
├── description-3.0.txt
├── header_01.png
├── header_02.png
├── logo_01.png
├── logo_02.png
├── logo_03.png
├── logo_04.png
├── logo_05.png
└── screenshots
│ ├── 2.2
│ ├── multi-timer_2-2_01.png
│ ├── multi-timer_2-2_02.png
│ ├── multi-timer_2-2_03.png
│ ├── multi-timer_2-2_04.png
│ └── multi-timer_2-6_01.png
│ ├── 2.7
│ ├── multi-timer_2-7_01.png
│ ├── multi-timer_2-7_02.png
│ ├── multi-timer_2-7_03.png
│ ├── multi-timer_2-7_04.png
│ └── multi-timer_2-7_05.png
│ └── 3.0
│ ├── multi-timer_3.0_01.png
│ ├── multi-timer_3.0_02.png
│ ├── multi-timer_3.0_03.png
│ ├── multi-timer_3.0_04.png
│ └── multi-timer_3.0_05.png
├── resources
├── about.txt
├── fonts
│ └── audi.ttf
└── images
│ ├── action_dec.png
│ ├── action_inc.png
│ ├── action_ok.png
│ ├── alarm.png
│ ├── icons.png
│ └── menu.png
├── src
├── common.c
├── common.h
├── generated
│ └── appinfo.h
├── icons.h
├── js
│ └── src
│ │ ├── generated
│ │ └── appinfo.js
│ │ ├── libs
│ │ └── pebble-ga.js
│ │ └── main.js
├── libs
│ ├── bitmap-loader
│ │ ├── bitmap-loader.c
│ │ └── bitmap-loader.h
│ ├── linked-list
│ │ ├── linked-list.c
│ │ └── linked-list.h
│ ├── pebble-assist
│ │ └── pebble-assist.h
│ └── scroll-text-layer
│ │ ├── scroll-text-layer.c
│ │ └── scroll-text-layer.h
├── main.c
├── migration.h
├── persist.h
├── settings.c
├── settings.h
├── timer.c
├── timer.h
├── timers.c
├── timers.h
└── windows
│ ├── win-about.c
│ ├── win-about.h
│ ├── win-controls.c
│ ├── win-controls.h
│ ├── win-duration.c
│ ├── win-duration.h
│ ├── win-main.c
│ ├── win-main.h
│ ├── win-settings.c
│ ├── win-settings.h
│ ├── win-timer-add.c
│ ├── win-timer-add.h
│ ├── win-timer.c
│ ├── win-timer.h
│ ├── win-vibrate.c
│ ├── win-vibrate.h
│ ├── win-vibration.c
│ └── win-vibration.h
├── tests
├── groups.h
├── scripts
│ ├── local-setup.sh
│ └── travis-install.sh
├── src
│ ├── code.c
│ ├── pebble.c
│ ├── pebble_extra.h
│ └── resource_ids.auto.h
├── tests.c
├── timers.c
└── unit.h
└── wscript
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build folder
2 | build
3 |
4 | # Waf lock files
5 | .lock-*
6 |
7 | # OS guff
8 | .DS_Store
9 |
10 | src/js/pebble-js-app.js
11 | src/js/coverage/
12 |
13 | tests/include/
14 | tests/run
15 |
16 | node_modules/
17 |
18 | # src/generated/
19 | # src/js/src/generated/
20 |
21 | *.sublime-*
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "globals": { "Pebble" : true },
3 | "browser": true,
4 | "devel": true,
5 | "freeze": true,
6 | "evil": false,
7 | "camelcase": true,
8 | "curly": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": "nofunc",
12 | "undef": true,
13 | "unused": true,
14 | "strict": false,
15 | "trailing": true,
16 | "eqeqeq": true
17 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 | install: ./tests/scripts/travis-install.sh
3 | script: make test
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2013 - 2015 Matthew Tole
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Pebble Tests v0.1.0
3 | # A Pebble library for doing unit tests.
4 | # http://smallstoneapps.github.io/pebble-tests/
5 | #
6 | # ----------------------
7 | #
8 | # The MIT License (MIT)
9 | #
10 | # Copyright © 2013 - 2015 Matthew Tole
11 | #
12 | # Permission is hereby granted, free of charge, to any person obtaining a copy
13 | # of this software and associated documentation files (the "Software"), to deal
14 | # in the Software without restriction, including without limitation the rights
15 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 | # copies of the Software, and to permit persons to whom the Software is
17 | # furnished to do so, subject to the following conditions:
18 | #
19 | # The above copyright notice and this permission notice shall be included in
20 | # all copies or substantial portions of the Software.
21 | #
22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 | # THE SOFTWARE.
29 | #
30 | # --------------------
31 | #
32 | # Makefile
33 | #
34 |
35 | CC=gcc
36 | ifeq ($(TRAVIS), true)
37 | CFLAGS=-std=c99
38 | else
39 | CFLAGS=-std=c11
40 | endif
41 | CINCLUDES=-I tests/include/ -I tests/ -I src/ -I src/libs/linked-list/
42 |
43 | TEST_FILES=tests/tests.c tests/timers.c
44 | SRC_FILES=src/timers.c src/timer.c
45 | LIB_FILES=src/libs/linked-list/linked-list.c
46 | TEST_EXTRAS=tests/src/pebble.c tests/src/code.c
47 |
48 | all: test
49 |
50 | test:
51 | @printf "\n"
52 | @$(CC) $(CFLAGS) $(CINCLUDES) $(TEST_FILES) $(SRC_FILES) $(LIB_FILES) $(TEST_EXTRAS) -o tests/run
53 | @tests/run || (echo 'Multi Timer test suite failed.' | terminal-notifier; exit 1)
54 | @rm tests/run
55 | @printf "\x1B[0m"
56 | @printf "\n"
57 |
58 | lint:
59 | oclint src/windows/win-main.c -- -c -std=c11 -I tests/include/ -I tests/ -I src/libs/pebble-assist/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | 
4 |
5 | [][travis] [][appstore]
6 |
7 | Multi Timer is simply the best timer and stopwatch app for Pebble.
8 |
9 | You can create as many independent timers and stopwatches as you need.
10 |
11 | With the release of 3.0, timers will now launch the app when they finish, meaning you can quit Multi Timer while timers are running and still be notified.
12 |
13 | [][appstore]
14 |
15 | ## Screenshots
16 |
17 |
18 |
19 |
20 |
21 |
22 | ## Download
23 |
24 | The recommended method for downloading Multi Timer is to use the Pebble appstore on your Android or iOS device.
25 |
26 | You can also download the PBW file [directly from GitHub][download-pbw].
27 |
28 | [appstore]: https://apps.getpebble.com/applications/52d30a1d19412b4d84000025
29 | [travis]: https://travis-ci.org/smallstoneapps/multi-timer/
30 | [download-pbw]: https://github.com/smallstoneapps/multi-timer/releases/download/v3.4/multi-timer.pbw
31 |
--------------------------------------------------------------------------------
/appinfo.json:
--------------------------------------------------------------------------------
1 | {
2 | "uuid": "0db6a55e-b32a-4b03-b037-95637bf306ff",
3 | "shortName": "Multi Timer",
4 | "longName": "Multi Timer",
5 | "companyName": "Matthew Tole",
6 | "versionCode": 1,
7 | "versionLabel": "3.4",
8 | "watchapp": {
9 | "watchface": false
10 | },
11 | "appKeys": { },
12 | "capabilities": [ ],
13 | "config": {
14 | "googleAnalytics": { "trackingId": "UA-48246810-3" }
15 | },
16 | "delimiters": {
17 | "inner": "`",
18 | "outer": "~"
19 | },
20 | "debug": false,
21 | "resources": {
22 | "media": [
23 | {
24 | "menuIcon": true,
25 | "type": "png",
26 | "name": "MENU_ICON",
27 | "file": "images/menu.png"
28 | },
29 | {
30 | "type": "png",
31 | "name": "ICONS_16",
32 | "file": "images/icons.png"
33 | },
34 | {
35 | "type": "png",
36 | "name": "IMAGE_ALARM",
37 | "file": "images/alarm.png"
38 | },
39 | {
40 | "type": "raw",
41 | "name": "TEXT_ABOUT",
42 | "file": "about.txt"
43 | },
44 | {
45 | "characterRegex": "[0-9]",
46 | "type": "font",
47 | "name": "FONT_AUDI_70_BOLD",
48 | "file": "fonts/audi.ttf"
49 | }
50 | ]
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/design/multi-timer_ideas_01.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/design/multi-timer_ideas_01.sketch
--------------------------------------------------------------------------------
/marketing/banner_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/banner_02.png
--------------------------------------------------------------------------------
/marketing/banner_02.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/banner_02.xcf
--------------------------------------------------------------------------------
/marketing/banner_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/banner_03.png
--------------------------------------------------------------------------------
/marketing/banner_03.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/banner_03.sketch
--------------------------------------------------------------------------------
/marketing/description-3.0.txt:
--------------------------------------------------------------------------------
1 | Multi Timer is simply the best timer and stopwatch app for Pebble.
2 |
3 | You can create as many independent timers and stopwatches as you need.
4 |
5 | With the release of 3.0, timers will now launch the app when they finish, meaning you can quit Multi Timer while timers are running and still be notified.
--------------------------------------------------------------------------------
/marketing/header_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/header_01.png
--------------------------------------------------------------------------------
/marketing/header_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/header_02.png
--------------------------------------------------------------------------------
/marketing/logo_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/logo_01.png
--------------------------------------------------------------------------------
/marketing/logo_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/logo_02.png
--------------------------------------------------------------------------------
/marketing/logo_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/logo_03.png
--------------------------------------------------------------------------------
/marketing/logo_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/logo_04.png
--------------------------------------------------------------------------------
/marketing/logo_05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/logo_05.png
--------------------------------------------------------------------------------
/marketing/screenshots/2.2/multi-timer_2-2_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/2.2/multi-timer_2-2_01.png
--------------------------------------------------------------------------------
/marketing/screenshots/2.2/multi-timer_2-2_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/2.2/multi-timer_2-2_02.png
--------------------------------------------------------------------------------
/marketing/screenshots/2.2/multi-timer_2-2_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/2.2/multi-timer_2-2_03.png
--------------------------------------------------------------------------------
/marketing/screenshots/2.2/multi-timer_2-2_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/2.2/multi-timer_2-2_04.png
--------------------------------------------------------------------------------
/marketing/screenshots/2.2/multi-timer_2-6_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/2.2/multi-timer_2-6_01.png
--------------------------------------------------------------------------------
/marketing/screenshots/2.7/multi-timer_2-7_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/2.7/multi-timer_2-7_01.png
--------------------------------------------------------------------------------
/marketing/screenshots/2.7/multi-timer_2-7_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/2.7/multi-timer_2-7_02.png
--------------------------------------------------------------------------------
/marketing/screenshots/2.7/multi-timer_2-7_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/2.7/multi-timer_2-7_03.png
--------------------------------------------------------------------------------
/marketing/screenshots/2.7/multi-timer_2-7_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/2.7/multi-timer_2-7_04.png
--------------------------------------------------------------------------------
/marketing/screenshots/2.7/multi-timer_2-7_05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/2.7/multi-timer_2-7_05.png
--------------------------------------------------------------------------------
/marketing/screenshots/3.0/multi-timer_3.0_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/3.0/multi-timer_3.0_01.png
--------------------------------------------------------------------------------
/marketing/screenshots/3.0/multi-timer_3.0_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/3.0/multi-timer_3.0_02.png
--------------------------------------------------------------------------------
/marketing/screenshots/3.0/multi-timer_3.0_03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/3.0/multi-timer_3.0_03.png
--------------------------------------------------------------------------------
/marketing/screenshots/3.0/multi-timer_3.0_04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/3.0/multi-timer_3.0_04.png
--------------------------------------------------------------------------------
/marketing/screenshots/3.0/multi-timer_3.0_05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/marketing/screenshots/3.0/multi-timer_3.0_05.png
--------------------------------------------------------------------------------
/resources/about.txt:
--------------------------------------------------------------------------------
1 | Multi Timer is a Pebble app developed by Matthew Tole.
2 |
3 | If you like this app, please consider donating to help fund future development.
4 |
5 | Go to http://matthewtole.com/pebble/ for details.
--------------------------------------------------------------------------------
/resources/fonts/audi.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/resources/fonts/audi.ttf
--------------------------------------------------------------------------------
/resources/images/action_dec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/resources/images/action_dec.png
--------------------------------------------------------------------------------
/resources/images/action_inc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/resources/images/action_inc.png
--------------------------------------------------------------------------------
/resources/images/action_ok.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/resources/images/action_ok.png
--------------------------------------------------------------------------------
/resources/images/alarm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/resources/images/alarm.png
--------------------------------------------------------------------------------
/resources/images/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/resources/images/icons.png
--------------------------------------------------------------------------------
/resources/images/menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/resources/images/menu.png
--------------------------------------------------------------------------------
/src/common.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/common.c
29 |
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include "timer.h"
36 | #include "icons.h"
37 | #include "settings.h"
38 |
39 | void menu_draw_row_icon_text(GContext* ctx, char* text, GBitmap* icon) {
40 | graphics_context_set_text_color(ctx, GColorBlack);
41 | if (icon) {
42 | graphics_draw_bitmap_in_rect(ctx, icon, GRect(8, 8, 16, 16));
43 | }
44 | graphics_draw_text(ctx, text,
45 | fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD),
46 | GRect(33, -1, PEBBLE_WIDTH - 33, 24), GTextOverflowModeFill,
47 | GTextAlignmentLeft, NULL);
48 | }
49 |
50 | void timer_draw_row(Timer* timer, GContext* ctx) {
51 | char* time_left = malloc(12);
52 | timer_time_str(timer->current_time, settings()->timers_hours, time_left, 12);
53 |
54 | graphics_context_set_text_color(ctx, GColorBlack);
55 | graphics_context_set_fill_color(ctx, GColorBlack);
56 |
57 | graphics_draw_text(ctx, time_left,
58 | fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD),
59 | GRect(33, -3, PEBBLE_WIDTH - 33, 28), GTextOverflowModeFill,
60 | GTextAlignmentLeft, NULL);
61 |
62 | GBitmap* bmp_icon = NULL;
63 | GBitmap* bmp_direction = NULL;
64 |
65 | switch (timer->status) {
66 | case TIMER_STATUS_STOPPED:
67 | bmp_icon = bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_STOP);
68 | break;
69 | case TIMER_STATUS_RUNNING:
70 | bmp_icon = bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_PLAY);
71 | break;
72 | case TIMER_STATUS_PAUSED:
73 | bmp_icon = bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_PAUSE);
74 | break;
75 | case TIMER_STATUS_DONE:
76 | bmp_icon = bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_DONE);
77 | break;
78 | }
79 |
80 | if (bmp_icon) {
81 | graphics_draw_bitmap_in_rect(ctx, bmp_icon, GRect(8, 8, 16, 16));
82 | }
83 |
84 | switch (timer->type) {
85 | case TIMER_TYPE_TIMER:
86 | bmp_direction = bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_TIMER);
87 | break;
88 | case TIMER_TYPE_STOPWATCH:
89 | bmp_direction = bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_STOPWATCH);
90 | break;
91 | }
92 |
93 | if (bmp_direction) {
94 | graphics_draw_bitmap_in_rect(ctx, bmp_direction, GRect(PEBBLE_WIDTH - 8 - 8, 9, 8, 16));
95 | }
96 |
97 | if (timer->type == TIMER_TYPE_TIMER) {
98 | uint8_t width = (144 * timer->current_time) / timer->length;
99 | graphics_fill_rect(ctx, GRect(0, 31, width, 2), 0, GCornerNone);
100 | }
101 |
102 | free(time_left);
103 | }
104 |
105 | void menu_draw_option(GContext* ctx, char* option, char* value) {
106 | graphics_context_set_text_color(ctx, GColorBlack);
107 | graphics_draw_text(ctx, option, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD), GRect(4, 0, 136, 28), GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL);
108 | graphics_draw_text(ctx, value, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD), GRect(4, 5, 136, 20), GTextOverflowModeTrailingEllipsis, GTextAlignmentRight, NULL);
109 | }
110 |
111 | void uppercase(char* str) {
112 | char* point = str;
113 | while (*point != '\0') {
114 | if (*point >= 97 && *point <= 122) {
115 | *point -= 32;
116 | }
117 | point += 1;
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/common.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/common.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | #include
35 | #include "timer.h"
36 |
37 | void menu_draw_row_icon_text(GContext* ctx, char* text, GBitmap* icon);
38 | void timer_draw_row(Timer* timer, GContext* ctx);
39 | void menu_draw_option(GContext* ctx, char* option, char* value);
40 | void uppercase(char* str);
41 |
--------------------------------------------------------------------------------
/src/generated/appinfo.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 |
10 | Copyright © 2013 - 2015 Matthew Tole
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining a copy
13 | of this software and associated documentation files (the "Software"), to deal
14 | in the Software without restriction, including without limitation the rights
15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 | copies of the Software, and to permit persons to whom the Software is
17 | furnished to do so, subject to the following conditions:
18 |
19 | The above copyright notice and this permission notice shall be included in
20 | all copies or substantial portions of the Software.
21 |
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 | THE SOFTWARE.
29 |
30 | --------------------
31 |
32 | src/generated/appinfo.h
33 |
34 | */
35 |
36 | #pragma once
37 |
38 | #define VERSION_LABEL "3.4"
39 | #define UUID "0db6a55e-b32a-4b03-b037-95637bf306ff"
40 | #define DEBUG_MODE false
41 | #define DELIMITER_INNER '`'
42 | #define DELIMITER_OUTER '~'
43 |
--------------------------------------------------------------------------------
/src/icons.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/icons.h
29 |
30 | This file contains the GRect definitions for the icons contained in the image
31 | resources/images/icons.png
32 |
33 | */
34 |
35 | #pragma once
36 |
37 | #define ICON_RECT_PLAY (GRect) { { 0, 0 }, { 16, 16 } }
38 | #define ICON_RECT_PAUSE (GRect) { { 16, 0 }, { 16, 16 } }
39 | #define ICON_RECT_STOP (GRect) { { 32, 0 }, { 16, 16 } }
40 | #define ICON_RECT_DONE (GRect) { { 16, 16 }, { 16, 16 } }
41 | #define ICON_RECT_TIMER (GRect) { { 0, 16 }, { 8, 16 } }
42 | #define ICON_RECT_STOPWATCH (GRect) { { 8, 16 }, { 8, 16 } }
43 | #define ICON_RECT_ADD (GRect) { { 48, 16 }, { 16, 16 } }
44 | #define ICON_RECT_RESET (GRect) { { 48, 0 }, { 16, 16 } }
45 | #define ICON_RECT_DELETE (GRect) { { 0, 32 }, { 16, 16 } }
46 | #define ICON_RECT_EDIT (GRect) { { 16, 32 }, { 16, 16 } }
47 | #define ICON_RECT_CONTROLS (GRect) { { 0, 48 }, { 16, 16 } }
48 | #define ICON_RECT_ABOUT (GRect) { { 48, 32 }, { 16, 16 } }
49 | #define ICON_RECT_SETTINGS (GRect) { { 32, 32 }, { 16, 16 } }
50 | #define ICON_RECT_ACTION_TICK (GRect) { { 16, 48 }, { 8, 8 } }
51 | #define ICON_RECT_ACTION_INC (GRect) { { 16, 56 }, { 8, 8 } }
52 | #define ICON_RECT_ACTION_DEC (GRect) { { 24, 48 }, { 8, 8 } }
53 | #define ICON_RECT_CLOCK (GRect) { { 32, 16 }, { 16, 16 } }
54 |
--------------------------------------------------------------------------------
/src/js/src/generated/appinfo.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 |
10 | Copyright © 2013 - 2015 Matthew Tole
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining a copy
13 | of this software and associated documentation files (the "Software"), to deal
14 | in the Software without restriction, including without limitation the rights
15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 | copies of the Software, and to permit persons to whom the Software is
17 | furnished to do so, subject to the following conditions:
18 |
19 | The above copyright notice and this permission notice shall be included in
20 | all copies or substantial portions of the Software.
21 |
22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 | THE SOFTWARE.
29 |
30 | --------------------
31 |
32 | src/js/src/generated/appinfo.js
33 |
34 | */
35 |
36 | /* exported AppInfo */
37 |
38 | var AppInfo = {
39 | "uuid": "0db6a55e-b32a-4b03-b037-95637bf306ff",
40 | "shortName": "Multi Timer",
41 | "longName": "Multi Timer",
42 | "companyName": "Matthew Tole",
43 | "versionCode": 1,
44 | "versionLabel": "3.4",
45 | "watchapp": {
46 | "watchface": false
47 | },
48 | "appKeys": { },
49 | "capabilities": [ ],
50 | "config": {
51 | "googleAnalytics": { "trackingId": "UA-48246810-3" }
52 | },
53 | "delimiters": {
54 | "inner": "`",
55 | "outer": "~"
56 | },
57 | "debug": false,
58 | "resources": {
59 | "media": [
60 | {
61 | "menuIcon": true,
62 | "type": "png",
63 | "name": "MENU_ICON",
64 | "file": "images/menu.png"
65 | },
66 | {
67 | "type": "png",
68 | "name": "ICONS_16",
69 | "file": "images/icons.png"
70 | },
71 | {
72 | "type": "png",
73 | "name": "IMAGE_ALARM",
74 | "file": "images/alarm.png"
75 | },
76 | {
77 | "type": "raw",
78 | "name": "TEXT_ABOUT",
79 | "file": "about.txt"
80 | },
81 | {
82 | "characterRegex": "[0-9]",
83 | "type": "font",
84 | "name": "FONT_AUDI_70_BOLD",
85 | "file": "fonts/audi.ttf"
86 | }
87 | ]
88 | }
89 | };
--------------------------------------------------------------------------------
/src/js/src/libs/pebble-ga.js:
--------------------------------------------------------------------------------
1 | var Analytics = function(analyticsId, appName, appVersion) {
2 | this.analyticsId = analyticsId;
3 | this.appName = appName;
4 | this.appVersion = appVersion;
5 | this.analyticsUserId = Pebble.getAccountToken();
6 | }
7 |
8 | Analytics.prototype._trackGA = function(type, params) {
9 | var req = new XMLHttpRequest();
10 | var url = 'http://www.google-analytics.com/collect';
11 | var trackingParams = 'v=1'
12 | + '&tid=' + this.analyticsId
13 | + '&cid=' + this.analyticsUserId
14 | + '&t=' + type
15 | + '&an=' + this.appName
16 | + '&av=' + this.appVersion;
17 |
18 | for (parameterKey in params) {
19 | if (params.hasOwnProperty(parameterKey)) {
20 | trackingParams += '&'+ parameterKey +'='+ params[parameterKey];
21 | }
22 | }
23 |
24 | function reqListener () {
25 | // DO NOTHING!
26 | }
27 |
28 | req.open('POST', url, true);
29 | req.onload = reqListener;
30 | req.setRequestHeader('Content-length', trackingParams.length);
31 | req.send(trackingParams);
32 | }
33 |
34 | Analytics.prototype.trackScreen = function (screenName) {
35 | this._trackGA('appview', {'cd': screenName});
36 | }
37 |
38 | Analytics.prototype.trackEvent = function (category, action) {
39 | this._trackGA('event', {'ec': category, 'ea': action});
40 | }
41 |
42 | // If require() will work some day. This would be nessecary.
43 | // module.exports.Analytics = Analytics;
--------------------------------------------------------------------------------
/src/js/src/main.js:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/js/src/main.js
29 |
30 | */
31 |
32 | /* global AppInfo */
33 | /* global Analytics */
34 | /* global Pebble */
35 |
36 | var MultiTimer = (function () {
37 |
38 | var analytics = null;
39 |
40 | function start() {
41 | analytics = new Analytics(AppInfo.config.googleAnalytics.trackingId, AppInfo.shortName, AppInfo.versionLabel);
42 | if (! AppInfo.debug) { analytics.trackEvent('app', 'start'); }
43 | }
44 |
45 | return {
46 | start: start
47 | };
48 |
49 | }());
50 |
51 | Pebble.addEventListener('ready', MultiTimer.start);
--------------------------------------------------------------------------------
/src/libs/bitmap-loader/bitmap-loader.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Bitmap Loader v2.1
4 | On-demand loading of bitmaps from resources.
5 | http://smallstoneapps.github.io/bitmap-loader/
6 |
7 | ----------------------
8 |
9 | The MIT License (MIT)
10 |
11 | Copyright © 2014 Matthew Tole
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 |
31 | ----------------------
32 |
33 | src/bitmap-loader.c
34 |
35 | */
36 |
37 | #include
38 | #include
39 | #include "bitmap-loader.h"
40 |
41 | typedef struct {
42 | uint32_t res_id;
43 | GBitmap* bitmap;
44 | uint8_t group;
45 | GRect* rect;
46 | bool is_sub;
47 | } AppBitmap;
48 |
49 | static AppBitmap* get_app_bitmap_by_res_id(uint32_t res_id);
50 | static AppBitmap* get_app_bitmap_by_group(uint8_t group);
51 | static AppBitmap* get_app_bitmap_tail(void);
52 |
53 | static LinkedRoot* bitmaps = NULL;
54 |
55 | void bitmaps_init() {
56 | bitmaps_cleanup();
57 | bitmaps = linked_list_create_root();
58 | }
59 |
60 | GBitmap* bitmaps_get_bitmap(uint32_t res_id) {
61 | if (! bitmaps) {
62 | return NULL;
63 | }
64 | AppBitmap* app_bmp = get_app_bitmap_by_res_id(res_id);
65 | if (app_bmp == NULL) {
66 | app_bmp = malloc(sizeof(AppBitmap));
67 | app_bmp->res_id = res_id;
68 | app_bmp->bitmap = gbitmap_create_with_resource(app_bmp->res_id);
69 | app_bmp->group = 0;
70 | app_bmp->is_sub = false;
71 | linked_list_append(bitmaps, app_bmp);
72 | }
73 | return app_bmp->bitmap;
74 | }
75 |
76 | GBitmap* bitmaps_get_bitmap_in_group(uint32_t res_id, uint8_t group) {
77 | if (! bitmaps) {
78 | return NULL;
79 | }
80 | if (group <= 0) {
81 | return NULL;
82 | }
83 | AppBitmap* app_bmp = get_app_bitmap_by_group(group);
84 | if (NULL == app_bmp) {
85 | app_bmp = malloc(sizeof(AppBitmap));
86 | app_bmp->res_id = res_id;
87 | app_bmp->bitmap = gbitmap_create_with_resource(app_bmp->res_id);
88 | app_bmp->group = group;
89 | app_bmp->is_sub = false;
90 | linked_list_append(bitmaps, app_bmp);
91 | }
92 | else {
93 | if (res_id != app_bmp->res_id) {
94 | gbitmap_destroy(app_bmp->bitmap);
95 | app_bmp->res_id = res_id;
96 | app_bmp->bitmap = gbitmap_create_with_resource(app_bmp->res_id);
97 | }
98 | }
99 | return app_bmp->bitmap;
100 | }
101 |
102 | GBitmap* bitmaps_get_sub_bitmap(uint32_t res_id, GRect rect) {
103 | if (! bitmaps) {
104 | return NULL;
105 | }
106 | GBitmap* parent = NULL;
107 | uint8_t count = linked_list_count(bitmaps);
108 | for (uint8_t b = 0; b < count; b += 1) {
109 | AppBitmap* bmp = (AppBitmap*)linked_list_get(bitmaps, b);
110 | if (bmp->res_id == res_id) {
111 | if (bmp->is_sub) {
112 | if (grect_equal(bmp->rect, &rect)) {
113 | return bmp->bitmap;
114 | }
115 | }
116 | else {
117 | parent = bmp->bitmap;
118 | }
119 | }
120 | }
121 | if (! parent) {
122 | parent = bitmaps_get_bitmap(res_id);
123 | if (! parent) {
124 | return NULL;
125 | }
126 | }
127 | AppBitmap* app_bmp = malloc(sizeof(AppBitmap));
128 | if (app_bmp == NULL) {
129 | return NULL;
130 | }
131 | app_bmp->res_id = res_id;
132 | app_bmp->bitmap = gbitmap_create_as_sub_bitmap(parent, rect);
133 | if (app_bmp->bitmap == NULL) {
134 | return NULL;
135 | }
136 | app_bmp->rect = malloc(sizeof(GRect));
137 | app_bmp->rect->origin = rect.origin;
138 | app_bmp->rect->size = rect.size;
139 | app_bmp->is_sub = true;
140 | linked_list_append(bitmaps, app_bmp);
141 | return app_bmp->bitmap;
142 | }
143 |
144 | void bitmaps_cleanup(void) {
145 | while (linked_list_count(bitmaps) > 0) {
146 | AppBitmap* bmp = linked_list_get(bitmaps, 0);
147 | gbitmap_destroy(bmp->bitmap);
148 | free(bmp);
149 | linked_list_remove(bitmaps, 0);
150 | }
151 | }
152 |
153 | // - - -
154 |
155 | static AppBitmap* get_app_bitmap_by_res_id(uint32_t res_id) {
156 | uint8_t count = linked_list_count(bitmaps);
157 | for (uint8_t b = 0; b < count; b += 1) {
158 | AppBitmap* bmp = (AppBitmap*)linked_list_get(bitmaps, b);
159 | if (bmp->res_id == res_id) {
160 | return bmp;
161 | }
162 | }
163 | return NULL;
164 | }
165 |
166 | static AppBitmap* get_app_bitmap_by_group(uint8_t group) {
167 | uint8_t count = linked_list_count(bitmaps);
168 | for (uint8_t b = 0; b < count; b += 1) {
169 | AppBitmap* bmp = (AppBitmap*)linked_list_get(bitmaps, b);
170 | if (bmp->group == group) {
171 | return bmp;
172 | }
173 | }
174 | return NULL;
175 | }
176 |
--------------------------------------------------------------------------------
/src/libs/bitmap-loader/bitmap-loader.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Bitmap Loader v2.1
4 | On-demand loading of bitmaps from resources.
5 | http://smallstoneapps.github.io/bitmap-loader/
6 |
7 | ----------------------
8 |
9 | The MIT License (MIT)
10 |
11 | Copyright © 2014 Matthew Tole
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 |
31 | --------------------
32 |
33 | src/bitmap-loader.h
34 |
35 | */
36 |
37 | #pragma once
38 |
39 | #include
40 |
41 | // Initialise the bitmap loading library.
42 | void bitmaps_init(void);
43 |
44 | // Returns a pointer to the bitmap as specified by a resource ID.
45 | // If the bitmap has not been requested before, it will be loaded.
46 | GBitmap* bitmaps_get_bitmap(uint32_t res_id);
47 |
48 | // Returns a pointer to the bitmap as specified by a resource ID.
49 | // If the bitmap has not been requested before, it will be loaded.
50 | // If another bitmap has been loaded with the same group number, it will be
51 | // unloaded.
52 | GBitmap* bitmaps_get_bitmap_in_group(uint32_t res_id, uint8_t group);
53 |
54 | GBitmap* bitmaps_get_sub_bitmap(uint32_t res_id, GRect rect);
55 |
56 | // Unload all the bitmaps from memory.
57 | void bitmaps_cleanup(void);
58 |
--------------------------------------------------------------------------------
/src/libs/linked-list/linked-list.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Linked List v0.3
4 | A Pebble library for working with linked lists.
5 | http://smallstoneapps.github.io/linked-list/
6 |
7 | ----------------------
8 |
9 | The MIT License (MIT)
10 |
11 | Copyright © 2014 Matthew Tole
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 |
31 | --------------------
32 |
33 | src/linked-list.h
34 |
35 | */
36 |
37 | #include
38 | #include "linked-list.h"
39 |
40 | typedef struct LinkedList LinkedList;
41 |
42 | struct LinkedList {
43 | LinkedList* next;
44 | LinkedList* prev;
45 | void* object;
46 | };
47 |
48 | struct LinkedRoot {
49 | LinkedList* head;
50 | };
51 |
52 | static LinkedList* create_list_item(void* object);
53 | static LinkedList* list_get(LinkedRoot* root, uint16_t index);
54 | static bool pointer_compare(void* p1, void* p2);
55 |
56 | LinkedRoot* linked_list_create_root(void) {
57 | LinkedRoot* root = malloc(sizeof(LinkedRoot));
58 | root->head = NULL;
59 | return root;
60 | }
61 |
62 | uint16_t linked_list_count(LinkedRoot* root) {
63 | if (NULL == root) {
64 | return 0;
65 | }
66 | LinkedList* list = root->head;
67 | uint16_t size = 0;
68 | while (NULL != list) {
69 | list = list->next;
70 | size += 1;
71 | }
72 | return size;
73 | }
74 |
75 | void linked_list_append(LinkedRoot* root, void* object) {
76 | if (NULL == root) {
77 | return;
78 | }
79 | LinkedList* child = create_list_item(object);
80 | if (NULL == root->head) {
81 | root->head = child;
82 | }
83 | else {
84 | LinkedList* tail = root->head;
85 | while (NULL != tail->next) {
86 | tail = tail->next;
87 | }
88 | tail->next = child;
89 | child->prev = tail;
90 | }
91 | }
92 |
93 | void linked_list_prepend(LinkedRoot* root, void* object) {
94 | if (NULL == root) {
95 | return;
96 | }
97 | LinkedList* child = create_list_item(object);
98 | child->next = root->head;
99 | if (NULL != root->head) {
100 | root->head->prev = child;
101 | }
102 | root->head = child;
103 | }
104 |
105 | void linked_list_insert(LinkedRoot* root, void* object, uint16_t after) {
106 | if (NULL == root) {
107 | return;
108 | }
109 | LinkedList* child = create_list_item(object);
110 | LinkedList* list = list_get(root, after);
111 | if (NULL == list) {
112 | linked_list_append(root, object);
113 | }
114 | else {
115 | child->next = list->next;
116 | list->next = child;
117 | child->prev = list;
118 | }
119 | }
120 |
121 | void* linked_list_get(LinkedRoot* root, uint16_t index) {
122 | if (NULL == root) {
123 | return NULL;
124 | }
125 | LinkedList* list = list_get(root, index);
126 | return NULL == list ? NULL : list->object;
127 | }
128 |
129 | void linked_list_remove(LinkedRoot* root, uint16_t index) {
130 | if (NULL == root) {
131 | return;
132 | }
133 | LinkedList* list = list_get(root, index);
134 | if (NULL == list) {
135 | return;
136 | }
137 | if (NULL == list->prev) {
138 | root->head = list->next;
139 | if (NULL != list->next) {
140 | list->next->prev = NULL;
141 | }
142 | }
143 | else {
144 | if (NULL != list->next) {
145 | list->next->prev = list->prev;
146 | }
147 | list->prev->next = list->next;
148 | }
149 | }
150 |
151 | void linked_list_clear(LinkedRoot* root) {
152 | if (NULL == root) {
153 | return;
154 | }
155 | while (root->head != NULL) {
156 | linked_list_remove(root, 0);
157 | }
158 | }
159 |
160 | bool linked_list_contains(LinkedRoot* root, void* object) {
161 | return linked_list_contains_compare(root, object, pointer_compare);
162 | }
163 |
164 | bool linked_list_contains_compare(LinkedRoot* root, void* object, ObjectCompare compare) {
165 | return linked_list_find_compare(root, object, compare) >= 0;
166 | }
167 |
168 | int16_t linked_list_find(LinkedRoot* root, void* object) {
169 | return linked_list_find_compare(root, object, pointer_compare);
170 | }
171 |
172 | int16_t linked_list_find_compare(LinkedRoot* root, void* object, ObjectCompare compare) {
173 | int16_t index = 0;
174 | LinkedList* list = root->head;
175 | while (list != NULL) {
176 | if (compare(object, list->object)) {
177 | return index;
178 | }
179 | list = list->next;
180 | index += 1;
181 | }
182 | return -1;
183 | }
184 |
185 | //----------------------------------------------------------------------------//
186 |
187 | // Create a new LinkedList with the specified object.
188 | static LinkedList* create_list_item(void* object) {
189 | LinkedList* item = malloc(sizeof(LinkedList));
190 | item->next = NULL;
191 | item->prev = NULL;
192 | item->object = object;
193 | return item;
194 | }
195 |
196 | // Returns the LinkedList at a given position within a list.
197 | static LinkedList* list_get(LinkedRoot* root, uint16_t index) {
198 | LinkedList* list = root->head;
199 | uint16_t pos = 0;
200 | while (NULL != list) {
201 | if (index == pos) {
202 | return list;
203 | }
204 | list = list->next;
205 | pos += 1;
206 | }
207 | return NULL;
208 | }
209 |
210 | // ObjectCompare function used for comparing the pointers of two objects.
211 | // Used by the find/contains functions that look for identical objects.
212 | static bool pointer_compare(void* p1, void* p2) {
213 | return p1 == p2;
214 | }
--------------------------------------------------------------------------------
/src/libs/linked-list/linked-list.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Linked List v0.3
4 | A Pebble library for working with linked lists.
5 | http://smallstoneapps.github.io/linked-list/
6 |
7 | ----------------------
8 |
9 | The MIT License (MIT)
10 |
11 | Copyright © 2014 Matthew Tole
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 |
31 | --------------------
32 |
33 | src/linked-list.h
34 |
35 | */
36 |
37 | #pragma once
38 |
39 | #include
40 |
41 | typedef struct LinkedRoot LinkedRoot;
42 | typedef bool (*ObjectCompare)(void* object1, void* object2);
43 |
44 | // Create a new LinkedRoot object, upon which all other linked list operations
45 | // are performed.
46 | LinkedRoot* linked_list_create_root(void);
47 |
48 | // Returns the number of items currently in a linked list.
49 | uint16_t linked_list_count(LinkedRoot* root);
50 |
51 | // Adds a new item to the end of the linked list.
52 | // This function does not copy the memory for the object, so you should ensure
53 | // that the object does not get destroyed.
54 | void linked_list_append(LinkedRoot* root, void* object);
55 |
56 | // Adds a new item to the front of the linked list.
57 | // This function does not copy the memory for the object, so you should ensure
58 | // that the object does not get destroyed.
59 | void linked_list_prepend(LinkedRoot* root, void* object);
60 |
61 | // Adds a new item after the specified position in the linked list.
62 | // This function does not copy the memory for the object, so you should ensure
63 | // that the object does not get destroyed.
64 | void linked_list_insert(LinkedRoot* root, void* object, uint16_t after);
65 |
66 | // Returns the object at the specified position in the linked list.
67 | void* linked_list_get(LinkedRoot* root, uint16_t index);
68 |
69 | // Removes the object at the specified position in the list.
70 | // This does not free the memory for the object, you should take care of that
71 | // yourself.
72 | void linked_list_remove(LinkedRoot* root, uint16_t index);
73 |
74 | // Removes all items in a list.
75 | // This does not free the memory for the objects in the list, you should take
76 | // care of that yourself.
77 | void linked_list_clear(LinkedRoot* root);
78 |
79 | // Returns true if the specified object is in the list, otherwise returns false.
80 | // Compares the pointers so this will only work with the exact same object, but
81 | // not a copy.
82 | bool linked_list_contains(LinkedRoot* root, void* object);
83 |
84 | // Returns true if the specified object is in the list, otherwise returns false.
85 | // Uses the specified ObjectCompare function to compare objects.
86 | bool linked_list_contains_compare(LinkedRoot* root, void* object, ObjectCompare compare);
87 |
88 | // Returns the index of the specified object in the list. If the object can not
89 | // be found, returns -1.
90 | // Compares the pointers so this will only work with the exact same object, but
91 | // not a copy.
92 | int16_t linked_list_find(LinkedRoot* root, void* object);
93 |
94 | // Returns the index of the specified object in the list. If the object can not
95 | // be found, returns -1.
96 | // Uses the specified ObjectCompare function to compare objects.
97 | int16_t linked_list_find_compare(LinkedRoot* root, void* object, ObjectCompare compare);
98 |
--------------------------------------------------------------------------------
/src/libs/pebble-assist/pebble-assist.h:
--------------------------------------------------------------------------------
1 | /***
2 | * Pebble Assist
3 | * Copyright (C) 2014 Matthew Tole
4 | *
5 | * Version 0.2.3
6 | ***/
7 |
8 | /**
9 | The MIT License (MIT)
10 |
11 | Copyright (c) 2013 Matthew Tole
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 | **/
31 |
32 | #pragma once
33 |
34 | // Pointer Logging
35 | static const bool SHOW_POINTERS = false;
36 |
37 | // Missing Constants
38 |
39 | #ifndef MENU_CELL_BASIC_CELL_HEIGHT
40 | #define MENU_CELL_BASIC_CELL_HEIGHT 44
41 | #endif
42 |
43 | #ifndef PEBBLE_HEIGHT
44 | #define PEBBLE_HEIGHT 168
45 | #endif
46 |
47 | #ifndef PEBBLE_WIDTH
48 | #define PEBBLE_WIDTH 144
49 | #endif
50 |
51 | #ifndef STATUS_HEIGHT
52 | #define STATUS_HEIGHT 16
53 | #endif
54 |
55 | // Shorthand App Logging
56 |
57 | #define DISABLE_LOGGING false
58 |
59 | #if DISABLE_LOGGING
60 | #define LOG(...)
61 | #define DEBUG(...)
62 | #define INFO(...)
63 | #define WARN(...)
64 | #define ERROR(...)
65 | #else
66 | #define LOG(...) app_log(APP_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
67 | #define DEBUG(...) app_log(APP_LOG_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
68 | #define INFO(...) app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, __VA_ARGS__)
69 | #define WARN(...) app_log(APP_LOG_LEVEL_WARNING, __FILE__, __LINE__, __VA_ARGS__)
70 | #define ERROR(...) app_log(APP_LOG_LEVEL_ERROR, __FILE__, __LINE__, __VA_ARGS__)
71 | #endif
72 |
73 | // Window Helpers
74 | #define window_destroy_safe(window) if (NULL != window) { if (SHOW_POINTERS) { DEBUG("Window Destroy Safe: %p", window); } window_destroy(window); window = NULL; }
75 |
76 | // Number Window Helpers
77 | #define number_window_destroy_safe(window) if (NULL != window) { if (SHOW_POINTERS) { DEBUG("Number Window Destroy Safe: %p", window); } number_window_destroy(window); window = NULL; }
78 |
79 | // Layer Helpers
80 | #define layer_create_fullscreen(window) layer_create(layer_get_bounds(window_get_root_layer(window)));
81 | #define layer_add_to_window(layer, window) layer_add_child(window_get_root_layer(window), layer)
82 | #define layer_show(layer) layer_set_hidden(layer, false)
83 | #define layer_hide(layer) layer_set_hidden(layer, true)
84 | #define layer_destroy_safe(layer) if (NULL != layer) { if (SHOW_POINTERS) { DEBUG("Layer Destroy Safe: %p", layer); } layer_destroy(layer); layer = NULL; }
85 |
86 | // Scroll Layer Helpers
87 | #define scroll_layer_create_fullscreeen(window) scroll_layer_create(layer_get_bounds(window_get_root_layer(window)))
88 | #define scroll_layer_add_to_window(layer, window) layer_add_child(window_get_root_layer(window), scroll_layer_get_layer(layer))
89 | #define scroll_layer_destroy_safe(layer) if (NULL != layer) { if (SHOW_POINTERS) { DEBUG("Scroll Layer Destroy Safe: %p", layer); } scroll_layer_destroy(layer); layer = NULL; }
90 |
91 | // Text Layer Helpers
92 | #define text_layer_create_fullscreen(window) text_layer_create(layer_get_bounds(window_get_root_layer(window)));
93 | #define text_layer_add_to_window(layer, window) layer_add_child(window_get_root_layer(window), text_layer_get_layer(layer))
94 | #define text_layer_set_system_font(layer, font) text_layer_set_font(layer, fonts_get_system_font(font))
95 | #define text_layer_set_colours(layer, foreground, background) text_layer_set_text_color(layer, foreground); text_layer_set_background_color(layer, background)
96 | #define text_layer_set_colors(layer, foreground, background) text_layer_set_text_color(layer, foreground); text_layer_set_background_color(layer, background)
97 | #define text_layer_destroy_safe(layer) if (NULL != layer) { if (SHOW_POINTERS) { DEBUG("Text Layer Destroy Safe: %p", layer); } text_layer_destroy(layer); layer = NULL; }
98 |
99 | // Bitmap Layer Helpers
100 | #define bitmap_layer_create_fullscreen(window) bitmap_layer_create(layer_get_bounds(window_get_root_layer(window)));
101 | #define bitmap_layer_add_to_window(layer, window) layer_add_child(window_get_root_layer(window), bitmap_layer_get_layer(layer))
102 | #define bitmap_layer_destroy_safe(layer) if (NULL != layer) { if (SHOW_POINTERS) { DEBUG("Bitmap Layer Destroy Safe: %p", layer); } bitmap_layer_destroy(layer); layer = NULL; }
103 |
104 | // GBitmap
105 | #define gbitmap_destroy_safe(gbitmap) if (NULL != gbitmap) {if (SHOW_POINTERS) { DEBUG("GBitmap Destroy Safe: %p", gbitmap); } gbitmap_destroy(gbitmap); gbitmap = NULL; }
106 |
107 | // Inverter Layer Helpers
108 | #define inverter_layer_add_to_window(layer, window) layer_add_child(window_get_root_layer(window), inverter_layer_get_layer(layer))
109 | #define inverter_layer_create_fullscreen(layer, window) inverter_layer_create(layer_get_bounds(window_get_root_layer(window)))
110 | #define inverter_layer_destroy_safe(layer) if (NULL != layer) { if (SHOW_POINTERS) { DEBUG("Inverter Layer Destroy Safe: %p", layer); } inverter_layer_destroy(layer); layer = NULL; }
111 |
112 | // Menu Layer Helpers
113 | #define menu_layer_create_fullscreen(window) menu_layer_create(layer_get_bounds(window_get_root_layer(window)))
114 | #define menu_layer_add_to_window(layer, window) layer_add_child(window_get_root_layer(window), menu_layer_get_layer(layer)); menu_layer_set_click_config_onto_window(layer, window)
115 | #define menu_layer_reload_data_and_mark_dirty(layer) menu_layer_reload_data(layer); layer_mark_dirty(menu_layer_get_layer(layer));
116 | #define menu_layer_destroy_safe(layer) if (NULL != layer) { if (SHOW_POINTERS) { DEBUG("Menu Layer Destroy Safe: %p", layer); } menu_layer_destroy(layer); layer = NULL; }
117 |
118 | // Simple Menu Layer Helpers
119 | #define simple_menu_layer_create_fullscreen(window, sections, num_sections, callback_context) simple_menu_layer_create(layer_get_bounds(window_get_root_layer(window)), sections, num_sections, callback_context)
120 | #define simple_menu_layer_add_to_window(layer, window) layer_add_child(window_get_root_layer(window), simple_menu_layer_get_layer(layer))
121 | #define simple_menu_layer_destroy_safe(layer) if (NULL != layer) { if (SHOW_POINTERS) { DEBUG("Simple Menu Layer Destroy Safe: %p", layer); } simple_menu_layer_destroy(layer); layer = NULL; }
122 |
123 | // Action Bar Layer Helpers
124 | #define action_bar_layer_create_in_window(action_bar, window) action_bar = action_bar_layer_create(); action_bar_layer_add_to_window(action_bar, window)
125 | #define action_bar_layer_clear_icons(action_bar) action_bar_layer_clear_icon(action_bar, BUTTON_ID_SELECT); action_bar_layer_clear_icon(action_bar, BUTTON_ID_DOWN); action_bar_layer_clear_icon(action_bar, BUTTON_ID_UP)
126 | #define action_bar_layer_destroy_safe(layer) if (NULL != layer) { if (SHOW_POINTERS) { DEBUG("Action Bar Layer Destroy Safe: %p", layer); } action_bar_layer_destroy(layer); layer = NULL; }
127 |
128 | // Dynamic Memory Helpers
129 | #define free_safe(ptr) if (NULL != ptr) { if (SHOW_POINTERS) { DEBUG("Free Safe: %p", ptr); } free(ptr); ptr = NULL; }
130 |
131 | // App Timer Helpers
132 | #define app_timer_cancel_safe(timer) if (timer != NULL) { app_timer_cancel(timer); timer = NULL; }
133 |
134 | // Font Helpers
135 | #define fonts_load_resource_font(resource) fonts_load_custom_font(resource_get_handle(resource))
136 |
137 | // App Message Helpers
138 | #define app_message_open_max() app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum())
139 |
140 | // Persistence Helpers
141 | #define persist_read_int_safe(key, value) (persist_exists(key) ? persist_read_int(key) : value);
142 | #define persist_read_bool_safe(key, value) (persist_exists(key) ? persist_read_bool(key) : value);
143 |
--------------------------------------------------------------------------------
/src/libs/scroll-text-layer/scroll-text-layer.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Scroll Text Layer v1.0
4 | A Pebble library for having a scrollable text layer in your Pebble apps.
5 | http://smallstoneapps.github.io/scroll-text-layer/
6 |
7 | ----------------------
8 |
9 | The MIT License (MIT)
10 |
11 | Copyright © 2013-2014 Matthew Tole
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 |
31 | --------------------
32 |
33 | src/scroll-text-layer.c
34 |
35 | */
36 |
37 | #include
38 | #include "scroll-text-layer.h"
39 |
40 | #define MAX_HEIGHT 2000
41 | #define PADDING_X 4
42 | #define PADDING_Y 4
43 |
44 | struct ScrollTextLayer {
45 | TextLayer* text_layer;
46 | ScrollLayer* scroll_layer;
47 | };
48 |
49 | static void scroll_text_layer_update(ScrollTextLayer* layer);
50 |
51 | ScrollTextLayer* scroll_text_layer_create(GRect rect) {
52 | ScrollTextLayer* stl = malloc(sizeof(ScrollTextLayer));
53 | stl->scroll_layer = scroll_layer_create(rect);
54 | GRect max_text_bounds = GRect(PADDING_X, PADDING_Y, rect.size.w - (PADDING_X * 2), MAX_HEIGHT);
55 | stl->text_layer = text_layer_create(max_text_bounds);
56 | scroll_layer_add_child(stl->scroll_layer, text_layer_get_layer(stl->text_layer));
57 | return stl;
58 | }
59 |
60 | void scroll_text_layer_destroy(ScrollTextLayer* layer) {
61 | if (NULL == layer) {
62 | return;
63 | }
64 | text_layer_destroy(scroll_text_layer_get_text_layer(layer));
65 | scroll_layer_destroy(scroll_text_layer_get_scroll_layer(layer));
66 | free(layer);
67 | }
68 |
69 | void scroll_text_layer_add_to_window(ScrollTextLayer* layer, Window* window) {
70 | if (NULL == layer || NULL == window) {
71 | return;
72 | }
73 | scroll_layer_set_click_config_onto_window(layer->scroll_layer, window);
74 | layer_add_child(window_get_root_layer(window), scroll_layer_get_layer(layer->scroll_layer));
75 | }
76 |
77 | void scroll_text_layer_set_text(ScrollTextLayer* layer, char* text) {
78 | if (NULL == layer) {
79 | return;
80 | }
81 | text_layer_set_text(layer->text_layer, text);
82 | scroll_text_layer_update(layer);
83 | }
84 |
85 | TextLayer* scroll_text_layer_get_text_layer(ScrollTextLayer* layer) {
86 | if (NULL == layer) {
87 | return NULL;
88 | }
89 | return layer->text_layer;
90 | }
91 |
92 | ScrollLayer* scroll_text_layer_get_scroll_layer(ScrollTextLayer* layer) {
93 | if (NULL == layer) {
94 | return NULL;
95 | }
96 | return layer->scroll_layer;
97 | }
98 |
99 | void scroll_text_layer_set_font(ScrollTextLayer* layer, GFont* font) {
100 | text_layer_set_font(scroll_text_layer_get_text_layer(layer), font);
101 | scroll_text_layer_update(layer);
102 | }
103 |
104 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
105 |
106 | static void scroll_text_layer_update(ScrollTextLayer* layer) {
107 | GSize max_size = text_layer_get_content_size(layer->text_layer);
108 | text_layer_set_size(layer->text_layer, max_size);
109 | GRect bounds = layer_get_bounds(scroll_layer_get_layer(layer->scroll_layer));
110 | scroll_layer_set_content_size(layer->scroll_layer, GSize(bounds.size.w, max_size.h + (PADDING_Y * 3)));
111 | }
--------------------------------------------------------------------------------
/src/libs/scroll-text-layer/scroll-text-layer.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Scroll Text Layer 1.0.0
4 | A Pebble library for having a scrollable text layer in your Pebble apps.
5 | http://smallstoneapps.github.io/scroll-text-layer/
6 |
7 | ----------------------
8 |
9 | The MIT License (MIT)
10 |
11 | Copyright © 2013-2014 Matthew Tole
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 |
31 | --------------------
32 |
33 | src/scroll-text-layer.h
34 |
35 | */
36 |
37 | #pragma once
38 |
39 | #include
40 |
41 | struct ScrollTextLayer;
42 | typedef struct ScrollTextLayer ScrollTextLayer;
43 |
44 | ScrollTextLayer* scroll_text_layer_create(GRect rect);
45 | void scroll_text_layer_destroy(ScrollTextLayer* layer);
46 | TextLayer* scroll_text_layer_get_text_layer(ScrollTextLayer* layer);
47 | ScrollLayer* scroll_text_layer_get_scroll_layer(ScrollTextLayer* layer);
48 | void scroll_text_layer_add_to_window(ScrollTextLayer* layer, Window* window);
49 | void scroll_text_layer_set_text(ScrollTextLayer* layer, char* text);
50 | void scroll_text_layer_set_font(ScrollTextLayer*, GFont* font);
51 |
52 | #define scroll_text_layer_create_fullscreen(window) scroll_text_layer_create(layer_get_bounds(window_get_root_layer(window)));
53 | #define scroll_text_layer_set_text_color(layer, color) text_layer_set_text_color(scroll_text_layer_get_text_layer(layer), color)
54 | #define scroll_text_layer_set_background_color(layer, color) text_layer_set_background_color(scroll_text_layer_get_text_layer(layer), color)
55 | #define scroll_text_layer_set_text_alignment(layer, alignment) text_layer_set_text_alignment(scroll_text_layer_get_text_layer(layer), alignment)
56 | #define scroll_text_layer_set_system_font(layer, font) scroll_text_layer_set_font(layer, fonts_get_system_font(font))
57 | #define scroll_text_layer_set_callbacks(layer, callbacks) scroll_layer_set_callbacks(scroll_text_layer_get_scroll_layer(layer), callbacks)
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/main.c
29 |
30 | */
31 |
32 | #include
33 | #include
34 | #include "windows/win-main.h"
35 | #include "timers.h"
36 | #include "settings.h"
37 | #include "persist.h"
38 |
39 | static void init(void);
40 | static void deinit(void);
41 |
42 | int main(void) {
43 | init();
44 | app_event_loop();
45 | deinit();
46 | }
47 |
48 | static void init(void) {
49 | srand(time(NULL));
50 | timers_init();
51 | bitmaps_init();
52 | settings_load();
53 | timers_restore();
54 | app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum());
55 | win_main_init();
56 | win_main_show();
57 | }
58 |
59 | static void deinit(void) {
60 | timers_save();
61 | settings_save();
62 | }
63 |
--------------------------------------------------------------------------------
/src/migration.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/migration.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | #include
35 | #include "timers.h"
36 |
37 | typedef enum {
38 | OLD_TIMER_STATUS_STOPPED,
39 | OLD_TIMER_STATUS_RUNNING,
40 | OLD_TIMER_STATUS_PAUSED,
41 | OLD_TIMER_STATUS_FINISHED
42 | } OldTimerStatus;
43 |
44 | typedef enum {
45 | OLD_TIMER_DIRECTION_UP,
46 | OLD_TIMER_DIRECTION_DOWN
47 | } OldTimerDirection;
48 |
49 | typedef enum {
50 | OLD_TIMER_VIBRATION_OFF,
51 | OLD_TIMER_VIBRATION_SHORT,
52 | OLD_TIMER_VIBRATION_LONG,
53 | OLD_TIMER_VIBRATION_DOUBLE,
54 | OLD_TIMER_VIBRATION_TRIPLE,
55 | OLD_TIMER_VIBRATION_CONTINUOUS
56 | } OldTimerVibration;
57 |
58 | typedef struct {
59 | uint16_t id;
60 | OldTimerDirection direction;
61 | uint32_t length;
62 | uint32_t time_left;
63 | OldTimerStatus status;
64 | OldTimerVibration vibrate;
65 | bool repeat;
66 | AppTimer* app_timer;
67 | char label[24];
68 | } __attribute__((__packed__)) OldTimer;
69 |
70 | typedef struct {
71 | OldTimer timers[5];
72 | uint8_t count;
73 | int time;
74 | } OldTimerBlock;
75 |
76 | typedef struct TimerTiny {
77 | uint16_t id;
78 | TimerType type;
79 | uint16_t length;
80 | uint16_t current_time;
81 | TimerStatus status;
82 | TimerVibration vibration;
83 | uint8_t repeat;
84 | uint8_t repeat_count;
85 | AppTimer* timer;
86 | WakeupId wakeup_id;
87 | char label[24];
88 | } TimerTiny;
89 |
90 | typedef struct {
91 | TimerTiny timers[TIMER_BLOCK_SIZE];
92 | uint8_t total_timers;
93 | time_t save_time;
94 | } TimerBlockTiny;
95 |
96 | // Struct of the original settings.
97 | typedef struct {
98 | bool save_timers_auto; // Automatically save timers on exit and load them when the app restarts?
99 | bool resume_timers; // Automatically resume running timers when app starts?
100 | bool timers_start_auto; // Should timers start immediately when you add them?
101 | TimerVibration timers_vibration; // Default timer vibration pattern
102 | bool timers_hours; // Use hours in timers?
103 | } OldSettings;
104 |
105 | // Struct of the fucked up settings where the timers_duration field was too small
106 | typedef struct {
107 | bool timers_start_auto; // Should timers start immediately when you add them?
108 | TimerVibration timers_vibration; // Default timer vibration pattern
109 | uint16_t timers_duration; // Default timer duration
110 | bool timers_hours; // Use hours in timers?
111 | bool show_clock; // Display a clock row in the main screen?
112 | } SettingsTiny;
113 |
--------------------------------------------------------------------------------
/src/persist.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/persist.h
29 |
30 | */
31 |
32 | #define PERSIST_SETTINGS 1
33 | #define PERSIST_TIMER_START 2
34 | #define PERSIST_SETTINGS_VERSION 101
35 | #define PERSIST_TIMERS_VERSION 102
36 |
--------------------------------------------------------------------------------
/src/settings.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/settings.c
29 |
30 | */
31 |
32 | #include
33 | #include
34 |
35 | #include "settings.h"
36 |
37 | #include "timer.h"
38 | #include "migration.h"
39 | #include "persist.h"
40 |
41 | static void migrate_settings_01(OldSettings old);
42 | static void migrate_settings_02(SettingsTiny tiny);
43 |
44 | // Set the default settings for the app.
45 | Settings _settings = {
46 | .timers_start_auto = false,
47 | .timers_vibration = TIMER_VIBE_SHORT,
48 | .timers_duration = 10 * 60,
49 | .timers_hours = false,
50 | .show_clock = false
51 | };
52 |
53 | void settings_load(void) {
54 | if (persist_exists(PERSIST_SETTINGS)) {
55 | if (! persist_exists(PERSIST_SETTINGS_VERSION)) {
56 | DEBUG("Migrating settings from 2.X to 3.X");
57 | OldSettings old_settings;
58 | int res = persist_read_data(PERSIST_SETTINGS, &old_settings, sizeof(old_settings));
59 | if (res >= 0) {
60 | migrate_settings_01(old_settings);
61 | return;
62 | }
63 | }
64 | else if (persist_read_int(PERSIST_SETTINGS_VERSION) == SETTINGS_VERSION_TINY) {
65 | SettingsTiny settings_tiny;
66 | int res = persist_read_data(PERSIST_SETTINGS, &settings_tiny, sizeof(settings_tiny));
67 | if (res >= 0) {
68 | migrate_settings_02(settings_tiny);
69 | return;
70 | }
71 | }
72 | int res = persist_read_data(PERSIST_SETTINGS, &_settings, sizeof(_settings));
73 | if (res < 0) {
74 | LOG("Settings load failed: %d", res);
75 | }
76 | }
77 | }
78 |
79 | Settings* settings() {
80 | return &_settings;
81 | }
82 |
83 | void settings_save(void) {
84 | int res = persist_write_data(PERSIST_SETTINGS, &_settings, sizeof(_settings));
85 | if (res < 0) {
86 | LOG("Settings load failed: %d", res);
87 | }
88 | persist_write_int(PERSIST_SETTINGS_VERSION, SETTINGS_VERSION_CURRENT);
89 | }
90 |
91 | static void migrate_settings_01(OldSettings old) {
92 | _settings.timers_hours = old.timers_hours;
93 | _settings.timers_vibration = old.timers_vibration;
94 | _settings.timers_start_auto = old.timers_start_auto;
95 | }
96 |
97 | static void migrate_settings_02(SettingsTiny tiny) {
98 | _settings.timers_hours = tiny.timers_hours;
99 | _settings.timers_vibration = tiny.timers_vibration;
100 | _settings.timers_start_auto = tiny.timers_start_auto;
101 | _settings.timers_duration = tiny.timers_duration;
102 | _settings.show_clock = tiny.show_clock;
103 | }
104 |
--------------------------------------------------------------------------------
/src/settings.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/settings.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | #include "timer.h"
35 |
36 | #define SETTINGS_VERSION_CURRENT 3
37 | #define SETTINGS_VERSION_TINY 2
38 |
39 | typedef struct {
40 | bool timers_start_auto; // Should timers start immediately when you add them?
41 | TimerVibration timers_vibration; // Default timer vibration pattern
42 | uint32_t timers_duration; // Default timer duration
43 | bool timers_hours; // Use hours in timers?
44 | bool show_clock; // Display a clock row in the main screen?
45 | } Settings;
46 |
47 | Settings* settings();
48 | void settings_load(void);
49 | void settings_save(void);
50 |
--------------------------------------------------------------------------------
/src/timer.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/timer.c
29 |
30 | */
31 |
32 | #include
33 | #include "timers.h"
34 | #include "timer.h"
35 | #include "icons.h"
36 | #include "settings.h"
37 | #include "windows/win-vibrate.h"
38 |
39 | static void timer_tick(void* context);
40 | static void timer_finish(Timer* timer);
41 | static void timer_schedule_tick(Timer* timer);
42 | static void timer_cancel_tick(Timer* timer);
43 | static void timer_schedule_wakeup(Timer* timer, uint16_t offset);
44 | static void timer_cancel_wakeup(Timer* timer);
45 | static void timer_set_id(Timer* timer);
46 | static void timer_completed_action(Timer* timer);
47 |
48 | void timer_time_str(uint32_t timer_time, bool showHours, char* str, int str_len) {
49 | int hours = timer_time / 3600;
50 | int minutes = (showHours ? (timer_time % 3600) : timer_time) / 60;
51 | int seconds = (showHours ? (timer_time % 3600) : timer_time) % 60;
52 | if (showHours) {
53 | snprintf(str, str_len, "%02d:%02d:%02d", hours, minutes, seconds);
54 | }
55 | else {
56 | snprintf(str, str_len, "%02d:%02d", minutes, seconds);
57 | }
58 | }
59 |
60 | void timer_start(Timer* timer) {
61 | switch (timer->type) {
62 | case TIMER_TYPE_TIMER:
63 | timer->current_time = timer->length;
64 | break;
65 | case TIMER_TYPE_STOPWATCH:
66 | timer->current_time = 0;
67 | break;
68 | }
69 | timer->status = TIMER_STATUS_RUNNING;
70 | timer_schedule_tick(timer);
71 | timer_schedule_wakeup(timer, 0);
72 | timers_mark_updated();
73 | }
74 |
75 | void timer_pause(Timer* timer) {
76 | timer->status = TIMER_STATUS_PAUSED;
77 | timer_cancel_tick(timer);
78 | timer_cancel_wakeup(timer);
79 | timers_mark_updated();
80 | }
81 |
82 | void timer_resume(Timer* timer) {
83 | timer->status = TIMER_STATUS_RUNNING;
84 | timer_schedule_tick(timer);
85 | timer_schedule_wakeup(timer, 0);
86 | timers_mark_updated();
87 | }
88 |
89 | void timer_reset(Timer* timer) {
90 | timer_pause(timer);
91 | switch (timer->type) {
92 | case TIMER_TYPE_TIMER:
93 | timer->current_time = timer->length;
94 | break;
95 | case TIMER_TYPE_STOPWATCH:
96 | timer->current_time = 0;
97 | break;
98 | }
99 | timer->status = TIMER_STATUS_STOPPED;
100 | timers_mark_updated();
101 | }
102 |
103 | void timer_restore(Timer* timer, uint16_t seconds_elapsed) {
104 | timer->timer = NULL;
105 | if (timer->status == TIMER_STATUS_RUNNING) {
106 | switch (timer->type) {
107 | case TIMER_TYPE_STOPWATCH:
108 | timer->current_time += seconds_elapsed;
109 | break;
110 | case TIMER_TYPE_TIMER: {
111 | if (seconds_elapsed >= timer->current_time) {
112 | timer->current_time = 0;
113 | timer->status = TIMER_STATUS_DONE;
114 | }
115 | else {
116 | timer->current_time -= seconds_elapsed;
117 | }
118 | break;
119 | }
120 | }
121 | }
122 | if (timer->status == TIMER_STATUS_RUNNING) {
123 | timer_resume(timer);
124 | }
125 | }
126 |
127 | Timer* timer_clone(Timer* timer) {
128 | Timer* new_timer = malloc(sizeof(Timer));
129 | memcpy(new_timer, timer, sizeof(Timer));
130 | return new_timer;
131 | }
132 |
133 | char* timer_vibe_str(TimerVibration vibe, bool shortStr) {
134 | switch (vibe) {
135 | case TIMER_VIBE_NONE:
136 | return "None";
137 | case TIMER_VIBE_SHORT:
138 | return shortStr ? "Short" : "Short Pulse";
139 | case TIMER_VIBE_LONG:
140 | return shortStr ? "Long" : "Long Pulse";
141 | case TIMER_VIBE_DOUBLE:
142 | return shortStr ? "Double" : "Double Pulse";
143 | case TIMER_VIBE_TRIPLE:
144 | return shortStr ? "Triple" : "Triple Pulse";
145 | case TIMER_VIBE_SOLID:
146 | return shortStr ? "Solid" : "Continous";
147 | }
148 | return "";
149 | }
150 |
151 | Timer* timer_create_timer(void) {
152 | Timer* timer = malloc(sizeof(Timer));
153 | timer->type = TIMER_TYPE_TIMER;
154 | timer->vibration = settings()->timers_vibration;
155 | timer->length = settings()->timers_duration;
156 | timer->wakeup_id = -1;
157 | timer->timer = NULL;
158 | timer->repeat = 0;
159 | timer->label[0] = 0;
160 | timer->status = TIMER_STATUS_STOPPED;
161 | timer_set_id(timer);
162 | return timer;
163 | }
164 |
165 | Timer* timer_create_stopwatch(void) {
166 | Timer* stopwatch = malloc(sizeof(Timer));
167 | stopwatch->type = TIMER_TYPE_STOPWATCH;
168 | stopwatch->length = stopwatch->current_time = 0;
169 | stopwatch->label[0] = 0;
170 | stopwatch->status = TIMER_STATUS_STOPPED;
171 | timer_set_id(stopwatch);
172 | return stopwatch;
173 | }
174 |
175 | static void timer_tick(void* context) {
176 | Timer* timer = (Timer*)context;
177 | timer->timer = NULL;
178 | switch (timer->type) {
179 | case TIMER_TYPE_STOPWATCH:
180 | timer->current_time += 1;
181 | break;
182 | case TIMER_TYPE_TIMER:
183 | timer->current_time -= 1;
184 | if (timer->current_time <= 0) {
185 | timer_finish(timer);
186 | }
187 | break;
188 | }
189 | if (timer->status == TIMER_STATUS_RUNNING) {
190 | timer_schedule_tick(timer);
191 | }
192 | timers_mark_updated();
193 | }
194 |
195 | static void timer_finish(Timer* timer) {
196 | timer->status = TIMER_STATUS_DONE;
197 | timer_completed_action(timer);
198 | }
199 |
200 | static void timer_schedule_tick(Timer* timer) {
201 | timer_cancel_tick(timer);
202 | timer->timer = app_timer_register(1000, timer_tick, (void*)timer);
203 | }
204 |
205 | static void timer_cancel_tick(Timer* timer) {
206 | if (! timer) {
207 | return;
208 | }
209 | if (timer->timer) {
210 | app_timer_cancel(timer->timer);
211 | timer->timer = NULL;
212 | }
213 | }
214 |
215 | static void timer_schedule_wakeup(Timer* timer, uint16_t offset) {
216 | if (! timer) {
217 | return;
218 | }
219 | if (timer->type == TIMER_TYPE_STOPWATCH) {
220 | return;
221 | }
222 | timer_cancel_wakeup(timer);
223 | time_t wakeup_time = time(NULL);
224 | wakeup_time += timer->current_time;
225 | wakeup_time -= 2;
226 | wakeup_time -= offset;
227 | timer->wakeup_id = wakeup_schedule(wakeup_time, timer->id, false);
228 | if (timer->wakeup_id >= 0) {
229 | return;
230 | }
231 | switch (timer->wakeup_id) {
232 | case E_RANGE: {
233 | Timer* timer_collision = timers_find_wakeup_collision(timer);
234 | if (timer_collision) {
235 | // There is an internal wakeup collision.
236 | // Should do some magic to make sure the earliest wakeup will fire.
237 | }
238 | else {
239 | // There is an external wakeup.
240 | // We will do the boring magic to schedule this wakeup early.
241 | }
242 | // TODO: Make this smarter!
243 | timer_schedule_wakeup(timer, offset - 20);
244 | break;
245 | }
246 | case E_OUT_OF_RESOURCES: {
247 | // If we've run out of wakeups, then we can just cancel the wake up
248 | // for whatever the last timer is and schedule this one instead.
249 | Timer* last_timer = timers_find_last_wakeup();
250 | if (NULL == last_timer) {
251 | return;
252 | }
253 | if (timer->id == last_timer->id) {
254 | return;
255 | }
256 | else {
257 | timer_cancel_wakeup(last_timer);
258 | timer_schedule_wakeup(timer, 0);
259 | }
260 | break;
261 | }
262 | case E_INVALID_ARGUMENT:
263 | // This will probably occur when trying to schedule around conflicts.
264 | break;
265 | }
266 | }
267 |
268 | static void timer_cancel_wakeup(Timer* timer) {
269 | if (! timer) {
270 | return;
271 | }
272 | if (timer->wakeup_id <= 0) {
273 | return;
274 | }
275 | wakeup_cancel(timer->wakeup_id);
276 | timer->wakeup_id = -1;
277 | }
278 |
279 | static void timer_set_id(Timer* timer) {
280 | timer->id = rand();
281 | while (timers_find(timer->id)) {
282 | timer->id = rand();
283 | }
284 | }
285 |
286 | static void timer_completed_action(Timer* timer) {
287 | switch (timer->vibration) {
288 | case TIMER_VIBE_NONE:
289 | // Do nothing!
290 | break;
291 | case TIMER_VIBE_SHORT:
292 | vibes_short_pulse();
293 | break;
294 | case TIMER_VIBE_LONG:
295 | vibes_long_pulse();
296 | break;
297 | case TIMER_VIBE_DOUBLE: {
298 | const uint32_t seg[] = { 600, 200, 600 };
299 | VibePattern pattern = {
300 | .durations = seg,
301 | .num_segments = ARRAY_LENGTH(seg)
302 | };
303 | vibes_enqueue_custom_pattern(pattern);
304 | break;
305 | }
306 | case TIMER_VIBE_TRIPLE: {
307 | const uint32_t seg[] = { 600, 200, 600, 200, 600 };
308 | VibePattern pattern = {
309 | .durations = seg,
310 | .num_segments = ARRAY_LENGTH(seg)
311 | };
312 | vibes_enqueue_custom_pattern(pattern);
313 | break;
314 | }
315 | case TIMER_VIBE_SOLID:
316 | win_vibrate_show();
317 | break;
318 | default:
319 | break;
320 | }
321 | if (timer->repeat == TIMER_REPEAT_INFINITE) {
322 | timer_start(timer);
323 | }
324 | timers_highlight(timer);
325 | }
326 |
--------------------------------------------------------------------------------
/src/timer.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/timer.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | #include
35 |
36 | typedef enum {
37 | TIMER_TYPE_TIMER = 0,
38 | TIMER_TYPE_STOPWATCH = 1,
39 | } TimerType;
40 |
41 | typedef enum {
42 | TIMER_VIBE_NONE = 0,
43 | TIMER_VIBE_SHORT = 1,
44 | TIMER_VIBE_LONG = 2,
45 | TIMER_VIBE_DOUBLE = 3,
46 | TIMER_VIBE_TRIPLE = 4,
47 | TIMER_VIBE_SOLID = 5
48 | } TimerVibration;
49 |
50 | typedef enum {
51 | TIMER_STATUS_STOPPED = 0,
52 | TIMER_STATUS_RUNNING = 1,
53 | TIMER_STATUS_PAUSED = 2,
54 | TIMER_STATUS_DONE = 3,
55 | } TimerStatus;
56 |
57 | typedef struct Timer {
58 | uint16_t id;
59 | TimerType type;
60 | uint32_t length;
61 | uint32_t current_time;
62 | TimerStatus status;
63 | TimerVibration vibration;
64 | uint8_t repeat;
65 | uint8_t repeat_count;
66 | AppTimer* timer;
67 | WakeupId wakeup_id;
68 | char label[24];
69 | } Timer;
70 |
71 | #define TIMER_REPEAT_INFINITE 100
72 |
73 | void timer_time_str(uint32_t timer_time, bool showHours, char* str, int str_len);
74 | void timer_start(Timer* timer);
75 | void timer_pause(Timer* timer);
76 | void timer_resume(Timer* timer);
77 | void timer_reset(Timer* timer);
78 | void timer_restore(Timer* timer, uint16_t seconds_elapsed);
79 | Timer* timer_clone(Timer* timer);
80 | char* timer_vibe_str(TimerVibration vibe, bool shortStr);
81 | Timer* timer_create_timer(void);
82 | Timer* timer_create_stopwatch(void);
83 |
--------------------------------------------------------------------------------
/src/timers.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/timers.c
29 |
30 | */
31 |
32 | #include
33 |
34 | #include
35 |
36 | #include "timers.h"
37 |
38 | #include "timer.h"
39 | #include "persist.h"
40 | #include "migration.h"
41 |
42 | typedef struct {
43 | Timer timers[TIMER_BLOCK_SIZE];
44 | uint8_t total_timers;
45 | time_t save_time;
46 | } TimerBlock;
47 |
48 | static void timers_cleanup(void);
49 | static void timers_migrate_1(void);
50 | static void timers_migrate_2(void);
51 |
52 | LinkedRoot* timers = NULL;
53 | LinkedRoot* update_handlers = NULL;
54 | LinkedRoot* highlight_handlers = NULL;
55 |
56 | void timers_init(void) {
57 | timers_cleanup();
58 | timers = linked_list_create_root();
59 | update_handlers = linked_list_create_root();
60 | highlight_handlers = linked_list_create_root();
61 | }
62 |
63 | uint8_t timers_count(void) {
64 | return linked_list_count(timers);
65 | }
66 |
67 | Timer* timers_get(uint8_t index) {
68 | if (! timers) {
69 | return NULL;
70 | }
71 | return linked_list_get(timers, index);
72 | }
73 |
74 | Timer* timers_find(uint16_t id) {
75 | uint8_t count = timers_count();
76 | for (uint8_t c = 0; c < count; c += 1) {
77 | Timer* timer = timers_get(c);
78 | if (timer->id == id) {
79 | return timer;
80 | }
81 | }
82 | return NULL;
83 | }
84 |
85 | int16_t timers_index_of(uint16_t id) {
86 | uint8_t count = timers_count();
87 | for (uint8_t c = 0; c < count; c += 1) {
88 | Timer* timer = timers_get(c);
89 | if (timer->id == id) {
90 | return c;
91 | }
92 | }
93 | return -1;
94 | }
95 |
96 | bool timers_add(Timer* timer) {
97 | linked_list_append(timers, timer);
98 | return true;
99 | }
100 |
101 | bool timers_remove(uint8_t position) {
102 | Timer* timer = timers_get(position);
103 | if (NULL == timer) {
104 | return false;
105 | }
106 | timer_pause(timer);
107 | linked_list_remove(timers, position);
108 | free(timer);
109 | timers_mark_updated();
110 | return true;
111 | }
112 |
113 | Timer* timers_find_last_wakeup(void) {
114 | Timer* last = NULL;
115 | uint16_t last_wakeup_time = 0;
116 | uint8_t count = timers_count();
117 | for (uint8_t c = 0; c < count; c += 1) {
118 | Timer* timer = timers_get(c);
119 | if (timer->wakeup_id < 0) {
120 | continue;
121 | }
122 | if (timer->current_time > last_wakeup_time) {
123 | last = timer;
124 | last_wakeup_time = timer->current_time;
125 | }
126 | }
127 | return last;
128 | }
129 |
130 | Timer* timers_find_wakeup_collision(Timer* timer) {
131 | time_t wakeup_time;
132 | wakeup_query(timer->wakeup_id, &wakeup_time);
133 | uint8_t count = timers_count();
134 | for (uint8_t c = 0; c < count; c += 1) {
135 | Timer* timer_to_check = timers_get(c);
136 | if (timer_to_check->wakeup_id < 0) {
137 | continue;
138 | }
139 | if (timer_to_check->id == timer->id) {
140 | continue;
141 | }
142 | time_t check_time;
143 | wakeup_query(timer_to_check->wakeup_id, &check_time);
144 | if (abs(check_time - wakeup_time) <= 60) {
145 | return timer_to_check;
146 | }
147 | }
148 | return NULL;
149 | }
150 |
151 | void timers_clear(void) {
152 | if (! timers) {
153 | return;
154 | }
155 | while (linked_list_count(timers) > 0) {
156 | Timer* timer = (Timer*) linked_list_get(timers, 0);
157 | linked_list_remove(timers, 0);
158 | free(timer);
159 | }
160 | }
161 |
162 | void timers_mark_updated(void) {
163 | uint8_t handler_count = linked_list_count(update_handlers);
164 | for (uint8_t h = 0; h < handler_count; h += 1) {
165 | TimersUpdatedHandler handler = linked_list_get(update_handlers, h);
166 | handler();
167 | }
168 | }
169 |
170 | void timers_highlight(Timer* timer) {
171 | uint8_t handler_count = linked_list_count(highlight_handlers);
172 | for (uint8_t h = 0; h < handler_count; h += 1) {
173 | TimerHighlightHandler handler = linked_list_get(highlight_handlers, h);
174 | handler(timer);
175 | }
176 | }
177 |
178 | void timers_register_update_handler(TimersUpdatedHandler handler) {
179 | linked_list_append(update_handlers, handler);
180 | }
181 |
182 | void timers_register_highlight_handler(TimerHighlightHandler handler) {
183 | linked_list_append(highlight_handlers, handler);
184 | }
185 |
186 | static void timers_cleanup(void) {
187 | timers_clear();
188 | free(timers);
189 | timers = NULL;
190 | }
191 |
192 | void timers_save(void) {
193 | if (timers_count() == 0) {
194 | persist_delete(PERSIST_TIMER_START);
195 | return;
196 | }
197 | TimerBlock* block = NULL;
198 | uint8_t block_count = 0;
199 | for (uint8_t b = 0; b < timers_count(); b += 1) {
200 | if (NULL == block) {
201 | block = malloc(sizeof(TimerBlock));
202 | block->total_timers = timers_count();
203 | block->save_time = time(NULL);
204 | }
205 |
206 | uint8_t timer_block_pos = b % TIMER_BLOCK_SIZE;
207 | block->timers[timer_block_pos] = *timers_get(b);
208 |
209 | bool is_last_timer_in_block = timer_block_pos == (TIMER_BLOCK_SIZE - 1);
210 | if (is_last_timer_in_block) {
211 | persist_write_data(PERSIST_TIMER_START + block_count, block, sizeof(TimerBlock));
212 | block_count += 1;
213 | free(block);
214 | block = NULL;
215 | }
216 | }
217 | if (block) {
218 | persist_write_data(PERSIST_TIMER_START + block_count, block, sizeof(TimerBlock));
219 | }
220 | persist_write_int(PERSIST_TIMERS_VERSION, TIMERS_VERSION_CURRENT);
221 | }
222 |
223 | void timers_restore(void) {
224 |
225 | if (! persist_exists(PERSIST_TIMERS_VERSION)) {
226 | timers_migrate_1();
227 | return;
228 | }
229 |
230 | if (TIMERS_VERSION_TINY == persist_read_int(PERSIST_TIMERS_VERSION)) {
231 | timers_migrate_2();
232 | return;
233 | }
234 |
235 | timers_clear();
236 |
237 | time_t now = time(NULL);
238 | uint16_t seconds_elapsed = 0;
239 |
240 | TimerBlock* block = NULL;
241 | if (persist_exists(PERSIST_TIMER_START)) {
242 | block = malloc(sizeof(TimerBlock));
243 | persist_read_data(PERSIST_TIMER_START, block, sizeof(TimerBlock));
244 | uint8_t num_timers = block->total_timers;
245 | uint8_t block_offset = 0;
246 | seconds_elapsed = now - block->save_time;
247 |
248 | for (uint8_t t = 0; t < num_timers; t += 1) {
249 | if (! block) {
250 | block = malloc(sizeof(TimerBlock));
251 | persist_read_data(PERSIST_TIMER_START + block_offset, block, sizeof(TimerBlock));
252 | }
253 | Timer* timer = timer_clone(&block->timers[t % TIMER_BLOCK_SIZE]);
254 | timers_add(timer);
255 | timer_restore(timer, seconds_elapsed);
256 | if (t % TIMER_BLOCK_SIZE == (TIMER_BLOCK_SIZE - 1)) {
257 | free(block);
258 | block = NULL;
259 | block_offset += 1;
260 | }
261 | }
262 | if (block) {
263 | free(block);
264 | block = NULL;
265 | }
266 | }
267 | }
268 |
269 | static void timers_migrate_1(void) {
270 |
271 | if (! persist_exists(PERSIST_TIMER_START)) {
272 | return;
273 | }
274 |
275 | int block = 0;
276 | OldTimerBlock* timerBlock = malloc(sizeof(OldTimerBlock));
277 | persist_read_data(PERSIST_TIMER_START, timerBlock, sizeof(OldTimerBlock));
278 |
279 | uint8_t timer_count = timerBlock->count;
280 |
281 | for (int t = 0; t < timer_count; t += 1) {
282 |
283 | if (t > 0 && t % TIMER_BLOCK_SIZE == 0) {
284 | block += 1;
285 | if (NULL != timerBlock) {
286 | free(timerBlock);
287 | timerBlock = NULL;
288 | }
289 | timerBlock = malloc(sizeof(OldTimerBlock));
290 | persist_read_data(PERSIST_TIMER_START + block, timerBlock, sizeof(OldTimerBlock));
291 | }
292 |
293 | OldTimer* old_timer = &timerBlock->timers[t % TIMER_BLOCK_SIZE];
294 |
295 | int seconds_elapsed = time(NULL) - timerBlock->time;
296 |
297 | Timer* timer = malloc(sizeof(Timer));
298 | timer->id = old_timer->id;
299 | timer->current_time = old_timer->time_left;
300 | timer->length = old_timer->length;
301 | timer->repeat = old_timer->repeat ? TIMER_REPEAT_INFINITE : 0;
302 | switch (old_timer->status) {
303 | case OLD_TIMER_STATUS_STOPPED:
304 | timer->status = TIMER_STATUS_STOPPED;
305 | break;
306 | case OLD_TIMER_STATUS_RUNNING:
307 | timer->status = TIMER_STATUS_RUNNING;
308 | break;
309 | case OLD_TIMER_STATUS_PAUSED:
310 | timer->status = TIMER_STATUS_PAUSED;
311 | break;
312 | case OLD_TIMER_STATUS_FINISHED:
313 | timer->status = TIMER_STATUS_DONE;
314 | break;
315 | }
316 | switch (old_timer->vibrate) {
317 | case OLD_TIMER_VIBRATION_OFF:
318 | timer->vibration = TIMER_VIBE_NONE;
319 | break;
320 | case OLD_TIMER_VIBRATION_SHORT:
321 | timer->vibration = TIMER_VIBE_SHORT;
322 | break;
323 | case OLD_TIMER_VIBRATION_LONG:
324 | timer->vibration = TIMER_VIBE_LONG;
325 | break;
326 | case OLD_TIMER_VIBRATION_DOUBLE:
327 | timer->vibration = TIMER_VIBE_DOUBLE;
328 | break;
329 | case OLD_TIMER_VIBRATION_TRIPLE:
330 | timer->vibration = TIMER_VIBE_TRIPLE;
331 | break;
332 | case OLD_TIMER_VIBRATION_CONTINUOUS:
333 | timer->vibration = TIMER_VIBE_SOLID;
334 | break;
335 | }
336 | switch (old_timer->direction) {
337 | case OLD_TIMER_DIRECTION_DOWN:
338 | timer->type = TIMER_TYPE_TIMER;
339 | break;
340 | case OLD_TIMER_DIRECTION_UP:
341 | timer->type = TIMER_TYPE_STOPWATCH;
342 | break;
343 | }
344 | timer->wakeup_id = -1;
345 | timer->timer = NULL;
346 | timer_restore(timer, seconds_elapsed);
347 | timers_add(timer);
348 | }
349 | if (NULL != timerBlock) {
350 | free(timerBlock);
351 | }
352 | }
353 |
354 | static void timers_migrate_2(void) {
355 |
356 | if (! persist_exists(PERSIST_TIMER_START)) {
357 | return;
358 | }
359 |
360 | int block_number = 0;
361 | TimerBlockTiny* block = malloc(sizeof(TimerBlockTiny));
362 | persist_read_data(PERSIST_TIMER_START, block, sizeof(TimerBlockTiny));
363 |
364 | uint8_t timer_count = block->total_timers;
365 |
366 | for (int t = 0; t < timer_count; t += 1) {
367 |
368 | if (t > 0 && t % TIMER_BLOCK_SIZE == 0) {
369 | block_number += 1;
370 | if (NULL != block) {
371 | free(block);
372 | block = NULL;
373 | }
374 | block = malloc(sizeof(TimerBlockTiny));
375 | persist_read_data(PERSIST_TIMER_START + block_number, block, sizeof(TimerBlockTiny));
376 | }
377 |
378 | TimerTiny* timer_tiny = &block->timers[t % TIMER_BLOCK_SIZE];
379 |
380 | int seconds_elapsed = time(NULL) - block->save_time;
381 |
382 | Timer* timer = malloc(sizeof(Timer));
383 | timer->id = timer_tiny->id;
384 | timer->current_time = timer_tiny->current_time;
385 | timer->length = timer_tiny->length;
386 | timer->repeat = timer_tiny->repeat;
387 | timer->repeat_count = timer_tiny->repeat_count;
388 | timer->status = timer_tiny->status;
389 | timer->vibration = timer_tiny->vibration;
390 | timer->type = timer_tiny->type;
391 | timer->wakeup_id = timer_tiny->wakeup_id;
392 | timer->timer = NULL;
393 | strcpy(timer->label, timer_tiny->label);
394 | timer_restore(timer, seconds_elapsed);
395 | timers_add(timer);
396 | }
397 | if (NULL != block) {
398 | free(block);
399 | }
400 | }
401 |
--------------------------------------------------------------------------------
/src/timers.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/timers.h
29 |
30 | */
31 |
32 | #include
33 | #include "timer.h"
34 |
35 | #define TIMER_BLOCK_SIZE 4
36 |
37 | #define TIMERS_VERSION_CURRENT 3
38 | #define TIMERS_VERSION_TINY 2
39 |
40 | typedef void (*TimersUpdatedHandler)(void);
41 | typedef void (*TimerHighlightHandler)(Timer* timer);
42 |
43 | // Setup the timers module and its associated data objects.
44 | // Must be called before all other operations.
45 | void timers_init(void);
46 |
47 | // Returns the number of timers.
48 | uint8_t timers_count(void);
49 |
50 | // Gets a single timer given its position.
51 | // Returns NULL if there is no timer at that position.
52 | Timer* timers_get(uint8_t index);
53 |
54 | // Gets a single timer given its ID.
55 | // Returns NULL if there is no timer with that ID.
56 | Timer* timers_find(uint16_t id);
57 |
58 | // Gets the index of a timer given its ID.
59 | // Returns -1 if there is no timer with that ID.
60 | int16_t timers_index_of(uint16_t id);
61 |
62 | // Adds a new timer.
63 | // Returns true if the operation was successful, false otherwise.
64 | bool timers_add(Timer* timer);
65 |
66 | // Removes a timer. This will destroy the timer object and all other
67 | // associated memory.
68 | // Returns true if successful, false otherwise (usually because there was
69 | // no timer at that position).
70 | bool timers_remove(uint8_t position);
71 |
72 | // Return the timer that has the highest time_remaining value.
73 | Timer* timers_find_last_wakeup(void);
74 |
75 | // Return the timer that has a colliding timer with the specified one.
76 | Timer* timers_find_wakeup_collision(Timer* timer);
77 |
78 | // Empty list the timers.
79 | void timers_clear(void);
80 |
81 | void timers_mark_updated(void);
82 | void timers_highlight(Timer* timer);
83 | void timers_register_update_handler(TimersUpdatedHandler handler);
84 | void timers_register_highlight_handler(TimerHighlightHandler handler);
85 |
86 | void timers_save(void);
87 | void timers_restore(void);
88 |
--------------------------------------------------------------------------------
/src/windows/win-about.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-about.c
29 |
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include "win-about.h"
36 | #include "../generated/appinfo.h"
37 |
38 | #define ABOUT_LENGTH 187
39 |
40 | static void window_load(Window* window);
41 | static void window_unload(Window* window);
42 | static void layer_header_update(Layer* layer, GContext* ctx);
43 |
44 | static Window* s_window;
45 | static Layer* s_layer_header;
46 | static ScrollTextLayer* s_layer_scroll;
47 | char* s_text;
48 |
49 | void win_about_init(void) {
50 | s_window = window_create();
51 | window_set_window_handlers(s_window, (WindowHandlers) {
52 | .load = window_load,
53 | .unload = window_unload,
54 | });
55 | }
56 |
57 | void win_about_show(void) {
58 | window_stack_push(s_window, true);
59 | }
60 |
61 | static void window_load(Window* window) {
62 | s_layer_header = layer_create(GRect(0, 0, PEBBLE_WIDTH, 24));
63 | layer_set_update_proc(s_layer_header, layer_header_update);
64 | layer_add_to_window(s_layer_header, s_window);
65 |
66 | s_text = malloc(ABOUT_LENGTH);
67 | resource_load(resource_get_handle(RESOURCE_ID_TEXT_ABOUT), (uint8_t*)s_text, ABOUT_LENGTH);
68 |
69 | s_layer_scroll = scroll_text_layer_create(GRect(0, 24, PEBBLE_WIDTH, PEBBLE_HEIGHT - STATUS_HEIGHT - 24));
70 | scroll_text_layer_add_to_window(s_layer_scroll, s_window);
71 | scroll_text_layer_set_font(s_layer_scroll, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
72 | scroll_text_layer_set_text(s_layer_scroll, s_text);
73 | }
74 |
75 | static void window_unload(Window* window) {
76 | layer_destroy(s_layer_header);
77 | scroll_text_layer_destroy(s_layer_scroll);
78 | free(s_text);
79 | }
80 |
81 | static void layer_header_update(Layer* layer, GContext* ctx) {
82 | char* version_string = malloc(24);
83 | snprintf(version_string, 24, "Multi Timer %s", VERSION_LABEL);
84 | graphics_context_set_fill_color(ctx, GColorBlack);
85 | graphics_context_set_text_color(ctx, GColorWhite);
86 | graphics_fill_rect(ctx, layer_get_bounds(layer), 0, GCornerNone);
87 | graphics_draw_text(ctx, version_string, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD), GRect(0, -5, PEBBLE_WIDTH, 24), GTextOverflowModeFill, GTextAlignmentCenter, 0);
88 | free(version_string);
89 | }
--------------------------------------------------------------------------------
/src/windows/win-about.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-about.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | #include
35 |
36 | void win_about_init(void);
37 | void win_about_show(void);
38 |
--------------------------------------------------------------------------------
/src/windows/win-controls.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-controls.c
29 |
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include "win-controls.h"
36 | #include "../timers.h"
37 | #include "../timer.h"
38 | #include "../icons.h"
39 | #include "../common.h"
40 |
41 | #define MENU_ROW_RESUME 0
42 | #define MENU_ROW_PAUSE 1
43 | #define MENU_ROW_RESET 2
44 | #define MENU_ROW_DELETE 3
45 |
46 | static void window_load(Window* window);
47 | static void window_unload(Window* window);
48 | static uint16_t menu_num_sections(struct MenuLayer* menu, void* callback_context);
49 | static uint16_t menu_num_rows(struct MenuLayer* menu, uint16_t section_index, void* callback_context);
50 | static int16_t menu_cell_height(struct MenuLayer *menu, MenuIndex *cell_index, void *callback_context);
51 | static void menu_draw_row(GContext* ctx, const Layer* cell_layer, MenuIndex* cell_index, void* callback_context);
52 | static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* callback_context);
53 |
54 | static Window* s_window;
55 | static MenuLayer* s_menu;
56 |
57 | void win_controls_init(void) {
58 | s_window = window_create();
59 | window_set_window_handlers(s_window, (WindowHandlers) {
60 | .load = window_load,
61 | .unload = window_unload
62 | });
63 | }
64 |
65 | void win_controls_show(void) {
66 | window_stack_push(s_window, true);
67 | }
68 |
69 | static void window_load(Window* window) {
70 | s_menu = menu_layer_create_fullscreen(s_window);
71 | menu_layer_set_callbacks(s_menu, NULL, (MenuLayerCallbacks) {
72 | .get_num_sections = menu_num_sections,
73 | .get_num_rows = menu_num_rows,
74 | .get_cell_height = menu_cell_height,
75 | .draw_row = menu_draw_row,
76 | .select_click = menu_select,
77 | });
78 | menu_layer_add_to_window(s_menu, s_window);
79 | }
80 |
81 | static void window_unload(Window* window) {
82 | menu_layer_destroy(s_menu);
83 | }
84 |
85 | static uint16_t menu_num_sections(struct MenuLayer* menu, void* callback_context) {
86 | return 1;
87 | }
88 |
89 | static uint16_t menu_num_rows(struct MenuLayer* menu, uint16_t section_index, void* callback_context) {
90 | return 4;
91 | }
92 |
93 | static int16_t menu_cell_height(struct MenuLayer *menu, MenuIndex *cell_index, void *callback_context) {
94 | return 32;
95 | }
96 |
97 | static void menu_draw_row(GContext* ctx, const Layer* cell_layer, MenuIndex* cell_index, void* callback_context) {
98 | switch (cell_index->row) {
99 | case MENU_ROW_RESUME:
100 | menu_draw_row_icon_text(ctx, "Resume All", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_PLAY));
101 | break;
102 | case MENU_ROW_PAUSE:
103 | menu_draw_row_icon_text(ctx, "Pause All", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_PAUSE));
104 | break;
105 | case MENU_ROW_RESET:
106 | menu_draw_row_icon_text(ctx, "Reset All", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_RESET));
107 | break;
108 | case MENU_ROW_DELETE:
109 | menu_draw_row_icon_text(ctx, "Delete All", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_DELETE));
110 | break;
111 | }
112 | }
113 |
114 | static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* callback_context) {
115 | uint8_t num_timers = timers_count();
116 | switch (cell_index->row) {
117 | case MENU_ROW_RESUME:
118 | for (uint8_t t = 0; t < num_timers; t += 1) {
119 | Timer* timer = timers_get(t);
120 | switch (timer->status) {
121 | case TIMER_STATUS_RUNNING:
122 | break;
123 | case TIMER_STATUS_PAUSED:
124 | timer_resume(timer);
125 | break;
126 | case TIMER_STATUS_DONE:
127 | timer_reset(timer);
128 | timer_start(timer);
129 | break;
130 | case TIMER_STATUS_STOPPED:
131 | timer_start(timer);
132 | break;
133 | }
134 | }
135 | break;
136 | case MENU_ROW_PAUSE:
137 | for (uint8_t t = 0; t < num_timers; t += 1) {
138 | Timer* timer = timers_get(t);
139 | if (timer->status == TIMER_STATUS_RUNNING) {
140 | timer_pause(timer);
141 | }
142 | }
143 | break;
144 | case MENU_ROW_RESET:
145 | for (uint8_t t = 0; t < num_timers; t += 1) {
146 | timer_reset(timers_get(t));
147 | }
148 | break;
149 | case MENU_ROW_DELETE:
150 | for (uint8_t t = 0; t < num_timers; t += 1) {
151 | timers_remove(0);
152 | }
153 | break;
154 | }
155 | window_stack_pop(true);
156 | }
157 |
--------------------------------------------------------------------------------
/src/windows/win-controls.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-controls.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | #include
35 |
36 | void win_controls_init(void);
37 | void win_controls_show(void);
38 |
--------------------------------------------------------------------------------
/src/windows/win-duration.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-duration.c
29 |
30 | */
31 |
32 | #include
33 |
34 | #include
35 | #include
36 |
37 | #include "win-duration.h"
38 |
39 | #include "../timer.h"
40 | #include "../common.h"
41 | #include "../icons.h"
42 | #include "../settings.h"
43 |
44 | #define MODE_HOURS 0
45 | #define MODE_MINUTES 1
46 | #define MODE_SECONDS 2
47 |
48 | static void window_load(Window* window);
49 | static void window_unload(Window* window);
50 | static void layer_update(Layer* me, GContext* ctx);
51 | static void layer_action_bar_click_config_provider(void *context);
52 | static void action_bar_layer_down_handler(ClickRecognizerRef recognizer, void *context);
53 | static void action_bar_layer_up_handler(ClickRecognizerRef recognizer, void *context);
54 | static void action_bar_layer_select_handler(ClickRecognizerRef recognizer, void *context);
55 | static void update_timer_length(void);
56 |
57 | static Window* s_window;
58 | static Layer* s_layer;
59 | static ActionBarLayer* s_action_bar;
60 | static uint32_t s_duration = 0;
61 | static DurationCallback s_callback;
62 |
63 | static int s_mode = MODE_MINUTES;
64 | static int s_hours = 0;
65 | static int s_minutes = 0;
66 | static int s_seconds = 0;
67 |
68 | static GFont s_font_duration;
69 |
70 | void win_duration_init(void) {
71 | s_window = window_create();
72 | window_set_window_handlers(s_window, (WindowHandlers) {
73 | .load = window_load,
74 | .unload = window_unload,
75 | });
76 | }
77 |
78 | void win_duration_show(uint16_t duration, DurationCallback callback) {
79 | s_duration = duration;
80 | s_callback = callback;
81 | window_stack_push(s_window, true);
82 | s_mode = settings()->timers_hours ? MODE_HOURS : MODE_MINUTES;
83 | s_hours = s_duration / 3600;
84 | s_minutes = settings()->timers_hours ? ((s_duration % 3600) / 60) : (s_duration / 60);
85 | s_seconds = settings()->timers_hours ? ((s_duration % 3600) % 60) : (s_duration % 60);
86 | layer_mark_dirty(s_layer);
87 | }
88 |
89 | static void window_load(Window* window) {
90 | s_layer = layer_create_fullscreen(s_window);
91 | layer_set_update_proc(s_layer, layer_update);
92 | layer_add_to_window(s_layer, s_window);
93 |
94 | s_action_bar = action_bar_layer_create();
95 | action_bar_layer_add_to_window(s_action_bar, s_window);
96 | action_bar_layer_set_click_config_provider(s_action_bar, layer_action_bar_click_config_provider);
97 | action_bar_layer_set_icon(s_action_bar, BUTTON_ID_UP, bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_ACTION_INC));
98 | action_bar_layer_set_icon(s_action_bar, BUTTON_ID_DOWN, bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_ACTION_DEC));
99 | action_bar_layer_set_icon(s_action_bar, BUTTON_ID_SELECT, bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_ACTION_TICK));
100 |
101 | s_font_duration = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_AUDI_70_BOLD));
102 | }
103 |
104 | static void window_unload(Window* window) {
105 | action_bar_layer_destroy(s_action_bar);
106 | layer_destroy(s_layer);
107 | fonts_unload_custom_font(s_font_duration);
108 | }
109 |
110 | static void layer_update(Layer* me, GContext* ctx) {
111 |
112 | graphics_context_set_text_color(ctx, GColorBlack);
113 | graphics_context_set_stroke_color(ctx, GColorBlack);
114 |
115 | char summary_str[32];
116 | timer_time_str(s_duration, settings()->timers_hours, summary_str, 32);
117 | graphics_draw_text(ctx, summary_str, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD), GRect(0, 0, 144 - 16, 28), GTextOverflowModeFill, GTextAlignmentCenter, NULL);
118 |
119 | // Draw Minutes
120 | char* time_str = "000";
121 | char mode_str[16];
122 | switch (s_mode) {
123 | case MODE_HOURS:
124 | snprintf(time_str, 3, "%02d", s_hours);
125 | snprintf(mode_str, 16, s_hours == 1 ? "HOUR" : "HOURS");
126 | break;
127 | case MODE_MINUTES:
128 | snprintf(time_str, 3, "%02d", s_minutes);
129 | snprintf(mode_str, 16, s_seconds == 1 ? "MINUTE" : "MINUTES");
130 | break;
131 | case MODE_SECONDS:
132 | snprintf(time_str, 3, "%02d", s_seconds);
133 | snprintf(mode_str, 16, s_seconds == 1 ? "SECOND" : "SECONDS");
134 | break;
135 | }
136 | graphics_draw_text(ctx, time_str, s_font_duration, GRect(0, 27, 144 - 16, 70), GTextOverflowModeTrailingEllipsis, GTextAlignmentCenter, NULL);
137 | graphics_draw_text(ctx, mode_str, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD), GRect(0, 98, 144 - 16, 18), GTextOverflowModeTrailingEllipsis, GTextAlignmentCenter, NULL);
138 | }
139 |
140 | static void layer_action_bar_click_config_provider(void *context) {
141 | window_single_repeating_click_subscribe(BUTTON_ID_DOWN, 100, action_bar_layer_down_handler);
142 | window_single_repeating_click_subscribe(BUTTON_ID_UP, 100, action_bar_layer_up_handler);
143 | window_single_click_subscribe(BUTTON_ID_SELECT, action_bar_layer_select_handler);
144 | }
145 |
146 | static void action_bar_layer_down_handler(ClickRecognizerRef recognizer, void *context) {
147 | switch (s_mode) {
148 | case MODE_HOURS:
149 | s_hours -= 1;
150 | if (s_hours < 0) {
151 | s_hours = 0;
152 | }
153 | break;
154 | case MODE_MINUTES:
155 | s_minutes -= 1;
156 | if (s_minutes < 0) {
157 | s_minutes += 60;
158 | }
159 | break;
160 | case MODE_SECONDS:
161 | s_seconds -= 1;
162 | if (s_seconds < 0) {
163 | s_seconds += 60;
164 | }
165 | break;
166 | }
167 | update_timer_length();
168 | layer_mark_dirty(s_layer);
169 | }
170 |
171 | static void action_bar_layer_up_handler(ClickRecognizerRef recognizer, void *context) {
172 | switch (s_mode) {
173 | case MODE_HOURS:
174 | s_hours += 1;
175 | break;
176 | case MODE_MINUTES:
177 | s_minutes += 1;
178 | if (s_minutes >= 60 && settings()->timers_hours) {
179 | s_minutes -= 60;
180 | }
181 | if (s_minutes >= 100) {
182 | s_minutes = 99;
183 | }
184 | break;
185 | case MODE_SECONDS:
186 | s_seconds += 1;
187 | if (s_seconds >= 60) {
188 | s_seconds -= 60;
189 | }
190 | break;
191 | }
192 | update_timer_length();
193 | layer_mark_dirty(s_layer);
194 | }
195 |
196 | static void action_bar_layer_select_handler(ClickRecognizerRef recognizer, void *context) {
197 | switch (s_mode) {
198 | case MODE_HOURS:
199 | s_mode = MODE_MINUTES;
200 | break;
201 | case MODE_MINUTES:
202 | s_mode = MODE_SECONDS;
203 | break;
204 | case MODE_SECONDS:
205 | s_callback(s_duration);
206 | window_stack_pop(true);
207 | break;
208 | }
209 | layer_mark_dirty(s_layer);
210 | }
211 |
212 | static void update_timer_length(void) {
213 | if (settings()->timers_hours) {
214 | s_duration = s_hours * 3600 + s_minutes * 60 + s_seconds;
215 | }
216 | else {
217 | s_duration = s_minutes * 60 + s_seconds;
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/src/windows/win-duration.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-duration.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | #include "../timer.h"
35 |
36 | typedef void (*DurationCallback)(uint32_t duration);
37 |
38 | void win_duration_init(void);
39 | void win_duration_show(uint16_t duration, DurationCallback callback);
40 |
--------------------------------------------------------------------------------
/src/windows/win-main.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-main.c
29 |
30 | */
31 |
32 | #include
33 |
34 | #include
35 | #include
36 |
37 | #include "win-about.h"
38 | #include "win-controls.h"
39 | #include "win-timer-add.h"
40 | #include "win-timer.h"
41 | #include "win-settings.h"
42 | #include "win-vibration.h"
43 | #include "win-duration.h"
44 | #include "win-vibrate.h"
45 |
46 | #include "../common.h"
47 | #include "../icons.h"
48 | #include "../timers.h"
49 | #include "../settings.h"
50 |
51 | #define MENU_SECTION_CLOCK 0
52 | #define MENU_SECTION_TIMERS 1
53 | #define MENU_SECTION_OTHER 2
54 |
55 | #define MENU_ROW_COUNT_OTHER 5
56 |
57 | #define MENU_ROW_OTHER_ADD_TIMER 0
58 | #define MENU_ROW_OTHER_ADD_STOPWATCH 1
59 | #define MENU_ROW_OTHER_CONTROLS 2
60 | #define MENU_ROW_OTHER_SETTINGS 3
61 | #define MENU_ROW_OTHER_ABOUT 4
62 |
63 | static void window_load(Window* window);
64 | static void window_unload(Window* window);
65 | static void tick_handler(struct tm *tick_time, TimeUnits units_changed);
66 | static uint16_t menu_num_sections(struct MenuLayer* menu, void* callback_context);
67 | static uint16_t menu_num_rows(struct MenuLayer* menu, uint16_t section_index, void* callback_context);
68 | static int16_t menu_cell_height(struct MenuLayer *menu, MenuIndex *cell_index, void *callback_context);
69 | static void menu_draw_row(GContext* ctx, const Layer* cell_layer, MenuIndex* cell_index, void* callback_context);
70 | static void menu_draw_row_clock(GContext* ctx, const Layer* cell_layer);
71 | static void menu_draw_row_timers(GContext* ctx, const Layer* cell_layer, uint16_t row_index);
72 | static void menu_draw_row_other(GContext* ctx, const Layer* cell_layer, uint16_t row_index);
73 | static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* callback_context);
74 | static void menu_select_timers(uint16_t row_index);
75 | static void menu_select_other(uint16_t row_index);
76 | static void menu_select_long(struct MenuLayer* menu, MenuIndex* cell_index, void* callback_context);
77 | static void timers_update_handler(void);
78 | static void timer_highlight_handler(Timer* timer);
79 |
80 | static Window* s_window;
81 | static MenuLayer* s_menu;
82 |
83 | void win_main_init(void) {
84 | s_window = window_create();
85 | window_set_window_handlers(s_window, (WindowHandlers) {
86 | .load = window_load,
87 | .unload = window_unload
88 | });
89 | timers_register_update_handler(timers_update_handler);
90 | timers_register_highlight_handler(timer_highlight_handler);
91 | win_timer_add_init();
92 | win_timer_init();
93 | win_about_init();
94 | win_controls_init();
95 | win_settings_init();
96 | win_vibration_init();
97 | win_duration_init();
98 | win_vibrate_init();
99 | tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
100 | }
101 |
102 | void win_main_show(void) {
103 | window_stack_push(s_window, false);
104 | }
105 |
106 | static void window_load(Window* window) {
107 | s_menu = menu_layer_create_fullscreen(s_window);
108 | menu_layer_set_callbacks(s_menu, NULL, (MenuLayerCallbacks) {
109 | .get_num_sections = menu_num_sections,
110 | .get_num_rows = menu_num_rows,
111 | .get_cell_height = menu_cell_height,
112 | .draw_row = menu_draw_row,
113 | .select_click = menu_select,
114 | .select_long_click = menu_select_long,
115 | });
116 | menu_layer_add_to_window(s_menu, s_window);
117 | }
118 |
119 | static void window_unload(Window* window) {
120 | menu_layer_destroy(s_menu);
121 | }
122 |
123 | static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
124 | if (settings()->show_clock) {
125 | menu_layer_reload_data(s_menu);
126 | }
127 | }
128 |
129 | static uint16_t menu_num_sections(struct MenuLayer* menu, void* callback_context) {
130 | return 3;
131 | }
132 |
133 | static uint16_t menu_num_rows(struct MenuLayer* menu, uint16_t section_index, void* callback_context) {
134 | switch (section_index) {
135 | case MENU_SECTION_CLOCK:
136 | return settings()->show_clock ? 1 : 0;
137 | case MENU_SECTION_TIMERS:
138 | return timers_count();
139 | case MENU_SECTION_OTHER:
140 | return MENU_ROW_COUNT_OTHER;
141 | default:
142 | return 0;
143 | }
144 | }
145 |
146 | static int16_t menu_cell_height(struct MenuLayer *menu, MenuIndex *cell_index, void *callback_context) {
147 | switch (cell_index->section) {
148 | case MENU_SECTION_TIMERS: {
149 | Timer* timer = timers_get(cell_index->row);
150 | if (! timer) {
151 | return 32;
152 | }
153 | switch (timer->type) {
154 | case TIMER_TYPE_TIMER:
155 | return 34;
156 | case TIMER_TYPE_STOPWATCH:
157 | return 32;
158 | }
159 | break;
160 | }
161 | }
162 | return 32;
163 | }
164 |
165 | static void menu_draw_row(GContext* ctx, const Layer* cell_layer, MenuIndex* cell_index, void* callback_context) {
166 | switch (cell_index->section) {
167 | case MENU_SECTION_CLOCK:
168 | menu_draw_row_clock(ctx, cell_layer);
169 | break;
170 | case MENU_SECTION_TIMERS:
171 | menu_draw_row_timers(ctx, cell_layer, cell_index->row);
172 | break;
173 | case MENU_SECTION_OTHER:
174 | menu_draw_row_other(ctx, cell_layer, cell_index->row);
175 | break;
176 | }
177 | }
178 |
179 | static void menu_draw_row_clock(GContext* ctx, const Layer* cell_layer) {
180 | char time_str[10];
181 | clock_copy_time_string(time_str, 10);
182 |
183 | graphics_context_set_text_color(ctx, GColorBlack);
184 | graphics_draw_text(ctx, time_str,
185 | fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD),
186 | GRect(33, -3, PEBBLE_WIDTH - 33, 28), GTextOverflowModeFill,
187 | GTextAlignmentLeft, NULL);
188 | graphics_draw_bitmap_in_rect(ctx,
189 | bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_CLOCK),
190 | GRect(8, 8, 16, 16));
191 | }
192 |
193 | static void menu_draw_row_timers(GContext* ctx, const Layer* cell_layer, uint16_t row_index) {
194 | Timer* timer = timers_get(row_index);
195 | if (! timer) { return; }
196 | timer_draw_row(timer, ctx);
197 | }
198 |
199 | static void menu_draw_row_other(GContext* ctx, const Layer* cell_layer, uint16_t row_index) {
200 | switch (row_index) {
201 | case MENU_ROW_OTHER_ADD_TIMER:
202 | menu_draw_row_icon_text(ctx, "Timer", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_ADD));
203 | break;
204 | case MENU_ROW_OTHER_ADD_STOPWATCH:
205 | menu_draw_row_icon_text(ctx, "Stopwatch", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_ADD));
206 | break;
207 | case MENU_ROW_OTHER_CONTROLS:
208 | menu_draw_row_icon_text(ctx, "Controls", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_CONTROLS));
209 | break;
210 | case MENU_ROW_OTHER_SETTINGS:
211 | menu_draw_row_icon_text(ctx, "Settings", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_SETTINGS));
212 | break;
213 | case MENU_ROW_OTHER_ABOUT:
214 | menu_draw_row_icon_text(ctx, "About", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_ABOUT));
215 | break;
216 | }
217 | }
218 |
219 | static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* callback_context) {
220 | switch (cell_index->section) {
221 | case MENU_SECTION_TIMERS:
222 | menu_select_timers(cell_index->row);
223 | break;
224 | case MENU_SECTION_OTHER:
225 | menu_select_other(cell_index->row);
226 | break;
227 | }
228 | }
229 |
230 | static void menu_select_timers(uint16_t row_index) {
231 | Timer* timer = timers_get(row_index);
232 | if (! timer) { return; }
233 |
234 | switch (timer->status) {
235 | case TIMER_STATUS_STOPPED: {
236 | timer_start(timer);
237 | break;
238 | }
239 | case TIMER_STATUS_RUNNING:
240 | timer_pause(timer);
241 | break;
242 | case TIMER_STATUS_PAUSED:
243 | timer_resume(timer);
244 | break;
245 | case TIMER_STATUS_DONE:
246 | timer_reset(timer);
247 | break;
248 | }
249 | }
250 |
251 | static void menu_select_other(uint16_t row_index) {
252 | switch (row_index) {
253 | case MENU_ROW_OTHER_ADD_TIMER:
254 | win_timer_add_show_new();
255 | break;
256 | case MENU_ROW_OTHER_ADD_STOPWATCH: {
257 | Timer* stopwatch = timer_create_stopwatch();
258 | if (settings()->timers_start_auto) {
259 | timer_start(stopwatch);
260 | }
261 | timers_add(stopwatch);
262 | timers_mark_updated();
263 | timers_highlight(stopwatch);
264 | break;
265 | }
266 | case MENU_ROW_OTHER_ABOUT:
267 | win_about_show();
268 | break;
269 | case MENU_ROW_OTHER_CONTROLS:
270 | win_controls_show();
271 | break;
272 | case MENU_ROW_OTHER_SETTINGS:
273 | win_settings_show();
274 | break;
275 | }
276 | }
277 |
278 | static void menu_select_long(struct MenuLayer* menu, MenuIndex* cell_index, void* callback_context) {
279 | if (cell_index->section == MENU_SECTION_TIMERS) {
280 | Timer* timer = timers_get(cell_index->row);
281 | win_timer_set_timer(timer);
282 | win_timer_show();
283 | }
284 | }
285 |
286 | static void timers_update_handler(void) {
287 | menu_layer_reload_data(s_menu);
288 | }
289 |
290 | static void timer_highlight_handler(Timer* timer) {
291 | uint16_t index = timers_index_of(timer->id);
292 | menu_layer_set_selected_index(s_menu, (MenuIndex) { .section = 1, .row = index }, MenuRowAlignCenter, true);
293 | }
--------------------------------------------------------------------------------
/src/windows/win-main.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-main.h
29 |
30 | */
31 |
32 | #include
33 |
34 | void win_main_init(void);
35 | void win_main_show(void);
--------------------------------------------------------------------------------
/src/windows/win-settings.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-settings.c
29 |
30 | */
31 |
32 | #include
33 |
34 | #include
35 |
36 | #include "win-settings.h"
37 | #include "win-vibration.h"
38 | #include "win-duration.h"
39 |
40 | #include "../settings.h"
41 | #include "../timers.h"
42 | #include "../common.h"
43 |
44 | #define MENU_NUM_SECTIONS 2
45 | #define MENU_SECTION_TIMERS 0
46 | #define MENU_SECTION_OTHER 1
47 |
48 | #define MENU_SECTION_ROWS_TIMERS 4
49 | #define MENU_SECTION_ROWS_OTHER 1
50 |
51 | #define MENU_ROW_TIMERS_START 0
52 | #define MENU_ROW_TIMERS_VIBRATE 1
53 | #define MENU_ROW_TIMERS_DURATION 2
54 | #define MENU_ROW_TIMERS_HOURS 3
55 |
56 | #define MENU_ROW_OTHER_CLOCK 0
57 |
58 | static uint16_t menu_get_num_sections_callback(MenuLayer *me, void *data);
59 | static uint16_t menu_get_num_rows_callback(MenuLayer *me, uint16_t section_index, void *data);
60 | static int16_t menu_get_header_height_callback(MenuLayer *me, uint16_t section_index, void *data);
61 | static int16_t menu_get_cell_height_callback(MenuLayer* me, MenuIndex* cell_index, void* data);
62 | static void menu_draw_row_callback(GContext* ctx, const Layer *cell_layer, MenuIndex *cell_index , void *data);
63 | static void menu_draw_header_callback(GContext* ctx, const Layer *cell_layer, uint16_t section_index , void *data);
64 | static void menu_select_click_callback(MenuLayer *menu_layer, MenuIndex *cell_index, void *callback_context);
65 | static void vibration_callback(TimerVibration vibration);
66 | static void duration_callback(uint32_t duration);
67 |
68 | static Window* window;
69 | static MenuLayer* layer_menu;
70 |
71 | void win_settings_init(void) {
72 | window = window_create();
73 |
74 | layer_menu = menu_layer_create_fullscreen(window);
75 | menu_layer_set_callbacks(layer_menu, NULL, (MenuLayerCallbacks) {
76 | .get_num_sections = menu_get_num_sections_callback,
77 | .get_num_rows = menu_get_num_rows_callback,
78 | .get_header_height = menu_get_header_height_callback,
79 | .get_cell_height = menu_get_cell_height_callback,
80 | .draw_header = menu_draw_header_callback,
81 | .draw_row = menu_draw_row_callback,
82 | .select_click = menu_select_click_callback,
83 | });
84 | menu_layer_set_click_config_onto_window(layer_menu, window);
85 | menu_layer_add_to_window(layer_menu, window);
86 | }
87 |
88 | void win_settings_show(void) {
89 | window_stack_push(window, true);
90 | }
91 |
92 | void win_settings_destroy(void) {
93 | layer_remove_from_parent(menu_layer_get_layer(layer_menu));
94 | menu_layer_destroy(layer_menu);
95 | window_destroy(window);
96 | }
97 |
98 | //----------------------------------------------------------------------------//
99 |
100 | static uint16_t menu_get_num_sections_callback(MenuLayer *me, void *data) {
101 | return MENU_NUM_SECTIONS;
102 | }
103 |
104 | static uint16_t menu_get_num_rows_callback(MenuLayer *me, uint16_t section_index, void *data) {
105 | switch (section_index) {
106 | case MENU_SECTION_TIMERS:
107 | return MENU_SECTION_ROWS_TIMERS;
108 | case MENU_SECTION_OTHER:
109 | return MENU_SECTION_ROWS_OTHER;
110 | }
111 | return 0;
112 | }
113 |
114 | static int16_t menu_get_header_height_callback(MenuLayer *me, uint16_t section_index, void *data) {
115 | return MENU_CELL_BASIC_HEADER_HEIGHT;
116 | }
117 |
118 | static int16_t menu_get_cell_height_callback(MenuLayer* me, MenuIndex* cell_index, void* data) {
119 | return 32;
120 | }
121 |
122 | static void menu_draw_row_callback(GContext* ctx, const Layer *cell_layer, MenuIndex *cell_index, void *data) {
123 | char value[16] = "";
124 |
125 | switch (cell_index->section) {
126 | case MENU_SECTION_TIMERS:
127 | switch (cell_index->row) {
128 | case MENU_ROW_TIMERS_START:
129 | menu_draw_option(ctx, "Auto Start", settings()->timers_start_auto ? "ON": "OFF");
130 | break;
131 | case MENU_ROW_TIMERS_VIBRATE:
132 | strcpy(value, timer_vibe_str(settings()->timers_vibration, true));
133 | uppercase(value);
134 | menu_draw_option(ctx, "Vibration", value);
135 | break;
136 | case MENU_ROW_TIMERS_DURATION:
137 | timer_time_str(settings()->timers_duration, settings()->timers_hours, value, 16);
138 | menu_draw_option(ctx, "Duration", value);
139 | break;
140 | case MENU_ROW_TIMERS_HOURS:
141 | menu_draw_option(ctx, "Show Hours", settings()->timers_hours ? "ON": "OFF");
142 | break;
143 | }
144 | break;
145 | case MENU_SECTION_OTHER:
146 | switch (cell_index->row) {
147 | case MENU_ROW_OTHER_CLOCK:
148 | menu_draw_option(ctx, "Show Clock", settings()->show_clock ? "ON": "OFF");
149 | break;
150 | }
151 | break;
152 | }
153 | }
154 |
155 | static void menu_draw_header_callback(GContext* ctx, const Layer *cell_layer, uint16_t section_index , void *data) {
156 | switch (section_index) {
157 | case MENU_SECTION_TIMERS:
158 | menu_cell_basic_header_draw(ctx, cell_layer, "Timer Defaults");
159 | break;
160 | case MENU_SECTION_OTHER:
161 | menu_cell_basic_header_draw(ctx, cell_layer, "Other Settings");
162 | break;
163 | }
164 | }
165 |
166 | static void menu_select_click_callback(MenuLayer *menu_layer, MenuIndex *cell_index, void *callback_context) {
167 | switch (cell_index->section) {
168 | case MENU_SECTION_TIMERS:
169 | switch (cell_index->row) {
170 | case MENU_ROW_TIMERS_START:
171 | settings()->timers_start_auto = ! settings()->timers_start_auto;
172 | menu_layer_reload_data(layer_menu);
173 | break;
174 | case MENU_ROW_TIMERS_VIBRATE:
175 | win_vibration_show(vibration_callback, settings()->timers_vibration);
176 | break;
177 | case MENU_ROW_TIMERS_DURATION:
178 | win_duration_show(settings()->timers_duration, duration_callback);
179 | break;
180 | case MENU_ROW_TIMERS_HOURS:
181 | settings()->timers_hours = ! settings()->timers_hours;
182 | menu_layer_reload_data(layer_menu);
183 | break;
184 | }
185 | break;
186 | case MENU_SECTION_OTHER:
187 | switch (cell_index->row) {
188 | case MENU_ROW_OTHER_CLOCK:
189 | settings()->show_clock = ! settings()->show_clock;
190 | menu_layer_reload_data(layer_menu);
191 | break;
192 | }
193 | break;
194 | }
195 | timers_mark_updated();
196 | }
197 |
198 | static void vibration_callback(TimerVibration vibration) {
199 | settings()->timers_vibration = vibration;
200 | }
201 |
202 | static void duration_callback(uint32_t duration) {
203 | settings()->timers_duration = duration;
204 | }
205 |
--------------------------------------------------------------------------------
/src/windows/win-settings.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-settings.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | void win_settings_init(void);
35 | void win_settings_show(void);
36 |
--------------------------------------------------------------------------------
/src/windows/win-timer-add.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-timer-add.c
29 |
30 | */
31 |
32 | #include
33 |
34 | #include
35 |
36 | #include "win-vibration.h"
37 | #include "win-duration.h"
38 | #include "../timers.h"
39 | #include "../timer.h"
40 | #include "../common.h"
41 | #include "../settings.h"
42 |
43 | #define MENU_SECTION_MAIN 0
44 | #define MENU_SECTION_FOOTER 1
45 |
46 | #define MENU_ROW_DURATION 0
47 | #define MENU_ROW_VIBRATION 1
48 | #define MENU_ROW_REPEAT 2
49 |
50 | static void window_load(Window* window);
51 | static void window_unload(Window* window);
52 | static uint16_t menu_get_num_sections_callback(MenuLayer *me, void *data);
53 | static uint16_t menu_get_num_rows_callback(MenuLayer *me, uint16_t section_index, void *data);
54 | static int16_t menu_get_header_height_callback(MenuLayer *me, uint16_t section_index, void *data);
55 | static int16_t menu_get_cell_height_callback(MenuLayer* me, MenuIndex* cell_index, void* data);
56 | static void menu_draw_header_callback(GContext* ctx, const Layer *cell_layer, uint16_t section_index, void *data);
57 | static void menu_draw_row_callback(GContext* ctx, const Layer *cell_layer, MenuIndex *cell_index, void *data);
58 | static void menu_draw_row_main(GContext* ctx, uint16_t row);
59 | static void menu_select_click_callback(MenuLayer *menu_layer, MenuIndex *cell_index, void *callback_context);
60 | static void menu_select_main(uint16_t row);
61 | static void menu_select_footer(void);
62 | static void vibration_callback(TimerVibration vibration);
63 | static void duration_callback(uint32_t duration);
64 |
65 | static Window* s_window;
66 | static MenuLayer* s_menu;
67 | static Timer* s_timer = NULL;
68 | static bool s_mode_edit = false;
69 |
70 | void win_timer_add_init(void) {
71 | s_window = window_create();
72 | window_set_window_handlers(s_window, (WindowHandlers) {
73 | .load = window_load,
74 | .unload = window_unload
75 | });
76 | }
77 |
78 | void win_timer_add_show_new(void) {
79 | window_stack_push(s_window, true);
80 | if (NULL != s_timer) {
81 | free(s_timer);
82 | s_timer = NULL;
83 | }
84 | s_timer = timer_create_timer();
85 | s_mode_edit = false;
86 | }
87 |
88 | void win_timer_add_show_edit(Timer* tmr) {
89 | window_stack_push(s_window, true);
90 | s_mode_edit = true;
91 | s_timer = timer_clone(tmr);
92 | }
93 |
94 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
95 |
96 | static void window_load(Window* window) {
97 | s_menu = menu_layer_create_fullscreen(s_window);
98 | menu_layer_set_callbacks(s_menu, NULL, (MenuLayerCallbacks) {
99 | .get_num_sections = menu_get_num_sections_callback,
100 | .get_num_rows = menu_get_num_rows_callback,
101 | .get_header_height = menu_get_header_height_callback,
102 | .get_cell_height = menu_get_cell_height_callback,
103 | .draw_header = menu_draw_header_callback,
104 | .draw_row = menu_draw_row_callback,
105 | .select_click = menu_select_click_callback,
106 | });
107 | menu_layer_add_to_window(s_menu, s_window);
108 | }
109 |
110 | static void window_unload(Window* s_window) {
111 | menu_layer_destroy(s_menu);
112 | }
113 |
114 | static uint16_t menu_get_num_sections_callback(MenuLayer *me, void *data) {
115 | return 2;
116 | }
117 |
118 | static uint16_t menu_get_num_rows_callback(MenuLayer *me, uint16_t section_index, void *data) {
119 | switch (section_index) {
120 | case MENU_SECTION_MAIN:
121 | return 3;
122 | case MENU_SECTION_FOOTER:
123 | return 1;
124 | }
125 | return 0;
126 | }
127 |
128 | static int16_t menu_get_header_height_callback(MenuLayer *me, uint16_t section_index, void *data) {
129 | switch (section_index) {
130 | case MENU_SECTION_FOOTER:
131 | return 4;
132 | break;
133 | }
134 | return 0;
135 | }
136 |
137 | static int16_t menu_get_cell_height_callback(MenuLayer* me, MenuIndex* cell_index, void* data) {
138 | if (cell_index->section == MENU_SECTION_FOOTER) {
139 | return 44;
140 | }
141 | return 32;
142 | }
143 |
144 | static void menu_draw_header_callback(GContext* ctx, const Layer *cell_layer, uint16_t section_index, void *data) {
145 | return;
146 | }
147 |
148 | static void menu_draw_row_callback(GContext* ctx, const Layer *cell_layer, MenuIndex *cell_index, void *data) {
149 | switch (cell_index->section) {
150 | case MENU_SECTION_MAIN:
151 | menu_draw_row_main(ctx, cell_index->row);
152 | break;
153 | case MENU_SECTION_FOOTER:
154 | graphics_context_set_text_color(ctx, GColorBlack);
155 | graphics_draw_text(ctx, s_mode_edit ? "Save Timer" : "Add Timer",
156 | fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD), GRect(4, 5, 136, 28),
157 | GTextOverflowModeTrailingEllipsis, GTextAlignmentCenter, NULL);
158 | break;
159 | }
160 | }
161 |
162 | static void menu_draw_row_main(GContext* ctx, uint16_t row) {
163 | char tmp[16];
164 | switch (row) {
165 | case MENU_ROW_DURATION:
166 | timer_time_str(s_timer->length, settings()->timers_hours, tmp, sizeof(tmp));
167 | menu_draw_option(ctx, "Duration", tmp);
168 | break;
169 | case MENU_ROW_VIBRATION:
170 | strcpy(tmp, timer_vibe_str(s_timer->vibration, true));
171 | uppercase(tmp);
172 | menu_draw_option(ctx, "Vibration", tmp);
173 | break;
174 | case MENU_ROW_REPEAT:
175 | menu_draw_option(ctx, "Repeat", (s_timer->repeat == TIMER_REPEAT_INFINITE) ? "ON" : "OFF");
176 | break;
177 | }
178 | }
179 |
180 | static void menu_select_click_callback(MenuLayer *menu_layer, MenuIndex *cell_index, void *callback_context) {
181 | switch (cell_index->section) {
182 | case MENU_SECTION_MAIN:
183 | menu_select_main(cell_index->row);
184 | break;
185 | case MENU_SECTION_FOOTER:
186 | menu_select_footer();
187 | break;
188 | }
189 | }
190 |
191 | static void menu_select_main(uint16_t row) {
192 | switch (row) {
193 | case MENU_ROW_DURATION:
194 | win_duration_show(s_timer->length, duration_callback);
195 | break;
196 | case MENU_ROW_VIBRATION:
197 | win_vibration_show(vibration_callback, s_timer->vibration);
198 | break;
199 | case MENU_ROW_REPEAT:
200 | if (s_timer->repeat == TIMER_REPEAT_INFINITE) {
201 | s_timer->repeat = 0;
202 | }
203 | else {
204 | s_timer->repeat = TIMER_REPEAT_INFINITE;
205 | }
206 | menu_layer_reload_data(s_menu);
207 | break;
208 | }
209 | }
210 |
211 | static void menu_select_footer(void) {
212 | if (s_timer->length == 0) {
213 | vibes_short_pulse();
214 | menu_layer_set_selected_index(s_menu, (MenuIndex) { MENU_SECTION_MAIN, MENU_ROW_DURATION }, MenuRowAlignCenter, true);
215 | return;
216 | }
217 | if (s_mode_edit) {
218 | Timer* timer = timers_find(s_timer->id);
219 | timer->length = s_timer->length;
220 | timer->repeat = s_timer->repeat;
221 | timer->vibration = s_timer->vibration;
222 | timer->type = s_timer->type;
223 | timer_reset(timer);
224 | window_stack_pop(true);
225 | timers_mark_updated();
226 | }
227 | else {
228 | Timer* timer = timer_clone(s_timer);
229 | timer_reset(timer);
230 | if (settings()->timers_start_auto) {
231 | timer_start(timer);
232 | }
233 | timers_add(timer);
234 | window_stack_pop(true);
235 | timers_mark_updated();
236 | timers_highlight(timer);
237 | }
238 | }
239 |
240 | static void vibration_callback(TimerVibration vibration) {
241 | s_timer->vibration = vibration;
242 | }
243 |
244 | static void duration_callback(uint32_t duration) {
245 | s_timer->length = duration;
246 | }
247 |
--------------------------------------------------------------------------------
/src/windows/win-timer-add.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-timer-add.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | #include
35 |
36 | #include "timer.h"
37 |
38 | void win_timer_add_init(void);
39 | void win_timer_add_show_new(void);
40 | void win_timer_add_show_edit(Timer* timer);
--------------------------------------------------------------------------------
/src/windows/win-timer.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-timer.c
29 |
30 | */
31 |
32 | #include
33 | #include
34 | #include
35 | #include "win-timer.h"
36 | #include "win-timer-add.h"
37 | #include "../timer.h"
38 | #include "../common.h"
39 | #include "../icons.h"
40 | #include "../timers.h"
41 |
42 | #define MENU_ROW_PAUSE 0
43 | #define MENU_ROW_RESET 1
44 | #define MENU_ROW_DELETE 2
45 | #define MENU_ROW_EDIT 3
46 |
47 | static void window_load(Window* window);
48 | static void window_unload(Window* window);
49 | static void layer_header_update(Layer* layer, GContext* ctx);
50 |
51 | static uint16_t menu_num_sections(struct MenuLayer* menu, void* callback_context);
52 | static uint16_t menu_num_rows(struct MenuLayer* menu, uint16_t section_index, void* callback_context);
53 | static int16_t menu_cell_height(struct MenuLayer *menu, MenuIndex *cell_index, void *callback_context);
54 | static void menu_draw_row(GContext* ctx, const Layer* cell_layer, MenuIndex* cell_index, void* callback_context);
55 | static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* callback_context);
56 |
57 | static void timers_update_handler(void);
58 | static bool can_edit(void);
59 |
60 | static Window* s_window;
61 | static Timer* s_timer;
62 | static Layer* s_layer_header;
63 | static InverterLayer* s_layer_header_invert;
64 | static MenuLayer* s_layer_menu;
65 |
66 | void win_timer_init(void) {
67 | s_timer = NULL;
68 | s_window = window_create();
69 | window_set_window_handlers(s_window, (WindowHandlers) {
70 | .load = window_load,
71 | .unload = window_unload,
72 | });
73 | timers_register_update_handler(timers_update_handler);
74 | }
75 |
76 | void win_timer_set_timer(Timer* timer) {
77 | s_timer = timer;
78 | }
79 |
80 | void win_timer_show(void) {
81 | if (! s_timer) {
82 | return;
83 | }
84 | window_stack_push(s_window, false);
85 | }
86 |
87 | static void window_load(Window* window) {
88 | s_layer_header = layer_create(GRect(0, 0, PEBBLE_WIDTH, 36));
89 | layer_set_update_proc(s_layer_header, layer_header_update);
90 | layer_add_to_window(s_layer_header, s_window);
91 |
92 | s_layer_header_invert = inverter_layer_create(layer_get_frame(s_layer_header));
93 | inverter_layer_add_to_window(s_layer_header_invert, s_window);
94 |
95 | s_layer_menu = menu_layer_create(GRect(0, 36, PEBBLE_WIDTH, PEBBLE_HEIGHT - STATUS_HEIGHT - 36));
96 | menu_layer_set_callbacks(s_layer_menu, NULL, (MenuLayerCallbacks) {
97 | .get_num_sections = menu_num_sections,
98 | .get_num_rows = menu_num_rows,
99 | .get_cell_height = menu_cell_height,
100 | .draw_row = menu_draw_row,
101 | .select_click = menu_select,
102 | });
103 | menu_layer_add_to_window(s_layer_menu, s_window);
104 | }
105 |
106 | static void window_unload(Window* window) {
107 | menu_layer_destroy(s_layer_menu);
108 | inverter_layer_destroy(s_layer_header_invert);
109 | layer_destroy(s_layer_header);
110 | }
111 |
112 | static void layer_header_update(Layer* layer, GContext* ctx) {
113 | timer_draw_row(s_timer, ctx);
114 | }
115 |
116 | static uint16_t menu_num_sections(struct MenuLayer* menu, void* callback_context) {
117 | return 1;
118 | }
119 |
120 | static uint16_t menu_num_rows(struct MenuLayer* menu, uint16_t section_index, void* callback_context) {
121 | return can_edit() ? 4 : 3;
122 | }
123 |
124 | static int16_t menu_cell_height(struct MenuLayer *menu, MenuIndex *cell_index, void *callback_context) {
125 | return 32;
126 | }
127 |
128 | static void menu_draw_row(GContext* ctx, const Layer* cell_layer, MenuIndex* cell_index, void* callback_context) {
129 | switch (cell_index->row) {
130 | case MENU_ROW_PAUSE: {
131 | switch (s_timer->status) {
132 | case TIMER_STATUS_RUNNING:
133 | menu_draw_row_icon_text(ctx, "Pause", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_PAUSE));
134 | break;
135 | case TIMER_STATUS_PAUSED:
136 | menu_draw_row_icon_text(ctx, "Resume", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_PLAY));
137 | break;
138 | case TIMER_STATUS_DONE:
139 | case TIMER_STATUS_STOPPED:
140 | menu_draw_row_icon_text(ctx, "Start", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_PLAY));
141 | break;
142 | }
143 | break;
144 | }
145 | case MENU_ROW_RESET:
146 | menu_draw_row_icon_text(ctx, "Reset", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_RESET));
147 | break;
148 | case MENU_ROW_DELETE:
149 | menu_draw_row_icon_text(ctx, "Delete", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_DELETE));
150 | break;
151 | case MENU_ROW_EDIT:
152 | menu_draw_row_icon_text(ctx, "Edit", bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_EDIT));
153 | break;
154 | }
155 | }
156 |
157 | static void menu_select(struct MenuLayer* menu, MenuIndex* cell_index, void* callback_context) {
158 | switch (cell_index->row) {
159 | case MENU_ROW_PAUSE: {
160 | switch (s_timer->status) {
161 | case TIMER_STATUS_RUNNING:
162 | timer_pause(s_timer);
163 | break;
164 | case TIMER_STATUS_PAUSED:
165 | timer_resume(s_timer);
166 | break;
167 | case TIMER_STATUS_DONE:
168 | case TIMER_STATUS_STOPPED:
169 | timer_start(s_timer);
170 | break;
171 | }
172 | break;
173 | }
174 | case MENU_ROW_RESET:
175 | timer_reset(s_timer);
176 | break;
177 | case MENU_ROW_DELETE:
178 | timers_remove(timers_index_of(s_timer->id));
179 | window_stack_pop(false);
180 | break;
181 | case MENU_ROW_EDIT:
182 | win_timer_add_show_edit(s_timer);
183 | break;
184 | }
185 | }
186 |
187 | static void timers_update_handler(void) {
188 | if (! window_is_loaded(s_window)) {
189 | return;
190 | }
191 | layer_mark_dirty(s_layer_header);
192 | menu_layer_reload_data(s_layer_menu);
193 | }
194 |
195 | static bool can_edit(void) {
196 | if (s_timer->type == TIMER_TYPE_STOPWATCH) {
197 | return false;
198 | }
199 | if (s_timer->status == TIMER_STATUS_STOPPED) {
200 | return true;
201 | }
202 | return false;
203 | }
--------------------------------------------------------------------------------
/src/windows/win-timer.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-timer.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | #include
35 | #include "../timer.h"
36 |
37 | void win_timer_init(void);
38 | void win_timer_set_timer(Timer* timer);
39 | void win_timer_show(void);
--------------------------------------------------------------------------------
/src/windows/win-vibrate.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-vibrate.c
29 |
30 | */
31 |
32 | #include
33 |
34 | #include "win-vibrate.h"
35 | #include
36 | #include
37 | #include "../common.h"
38 |
39 | void click_config_provider(Window* window);
40 | void click_handler(ClickRecognizerRef recognizer, void* context);
41 | void window_appear(Window* window);
42 | void window_disappear(Window* window);
43 | void do_vibrate(void);
44 | void vibe_timer_callback(void* data);
45 |
46 | Window* window;
47 | BitmapLayer* bmp_layer;
48 | AppTimer* vibe_timer = NULL;
49 | bool is_visible = false;
50 |
51 | void win_vibrate_init(void) {
52 | window = window_create();
53 | window_set_background_color(window, GColorBlack);
54 | window_set_click_config_provider(window, (ClickConfigProvider)click_config_provider);
55 | window_set_window_handlers(window, (WindowHandlers) {
56 | .appear = window_appear,
57 | .disappear = window_disappear
58 | });
59 |
60 | bmp_layer = bitmap_layer_create(GRect(40, 44, 64, 64));
61 | bitmap_layer_set_compositing_mode(bmp_layer, GCompOpAssignInverted);
62 | bitmap_layer_set_bitmap(bmp_layer, bitmaps_get_bitmap(RESOURCE_ID_IMAGE_ALARM));
63 | bitmap_layer_add_to_window(bmp_layer, window);
64 | }
65 |
66 | void win_vibrate_show(void) {
67 | if (window_stack_contains_window(window)) {
68 | return;
69 | }
70 | window_stack_push(window, false);
71 | }
72 |
73 | void win_vibrate_destroy(void) {
74 | bitmap_layer_destroy(bmp_layer);
75 | window_destroy(window);
76 | }
77 |
78 | bool win_vibrate_is_visible(void) {
79 | return is_visible;
80 | }
81 |
82 | //----------------------------------------------------------------------------//
83 |
84 | void click_config_provider(Window* window) {
85 | window_single_click_subscribe(BUTTON_ID_UP, click_handler);
86 | window_single_click_subscribe(BUTTON_ID_DOWN, click_handler);
87 | window_single_click_subscribe(BUTTON_ID_SELECT, click_handler);
88 | }
89 |
90 | void click_handler(ClickRecognizerRef recognizer, void* context) {
91 | window_stack_pop(true);
92 | }
93 |
94 | void window_appear(Window* window) {
95 | do_vibrate();
96 | is_visible = true;
97 | }
98 |
99 | void window_disappear(Window* window) {
100 | app_timer_cancel_safe(vibe_timer);
101 | is_visible = false;
102 | }
103 |
104 | void do_vibrate(void) {
105 | vibes_long_pulse();
106 | vibe_timer = app_timer_register(1000, vibe_timer_callback, NULL);
107 | }
108 |
109 | void vibe_timer_callback(void* data) {
110 | vibe_timer = NULL;
111 | do_vibrate();
112 | }
--------------------------------------------------------------------------------
/src/windows/win-vibrate.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-vibrate.h
29 |
30 | */
31 |
32 |
33 | #pragma once
34 |
35 | void win_vibrate_init(void);
36 | void win_vibrate_show(void);
37 |
--------------------------------------------------------------------------------
/src/windows/win-vibration.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-vibration.c
29 |
30 | */
31 |
32 | #include
33 |
34 | #include
35 | #include
36 |
37 | #include "win-vibration.h"
38 |
39 | #include "../timer.h"
40 | #include "../common.h"
41 | #include "../icons.h"
42 |
43 | static uint16_t menu_get_num_sections_callback(MenuLayer *me, void *data);
44 | static uint16_t menu_get_num_rows_callback(MenuLayer *me, uint16_t section_index, void *data);
45 | static int16_t menu_get_header_height_callback(MenuLayer *me, uint16_t section_index, void *data);
46 | static int16_t menu_get_cell_height_callback(MenuLayer* me, MenuIndex* cell_index, void* data);
47 | static void menu_draw_row_callback(GContext* ctx, const Layer *cell_layer, MenuIndex *cell_index, void *data);
48 | static void menu_select_click_callback(MenuLayer *menu_layer, MenuIndex *cell_index, void *callback_context);
49 |
50 | static Window* window;
51 | static MenuLayer* layer_menu;
52 | static VibrationCallback current_callback;
53 | static TimerVibration current_vibration;
54 |
55 | void win_vibration_init(void) {
56 | window = window_create();
57 |
58 | layer_menu = menu_layer_create_fullscreen(window);
59 | menu_layer_set_callbacks(layer_menu, NULL, (MenuLayerCallbacks) {
60 | .get_num_sections = menu_get_num_sections_callback,
61 | .get_num_rows = menu_get_num_rows_callback,
62 | .get_header_height = menu_get_header_height_callback,
63 | .get_cell_height = menu_get_cell_height_callback,
64 | .draw_row = menu_draw_row_callback,
65 | .select_click = menu_select_click_callback,
66 | });
67 | menu_layer_set_click_config_onto_window(layer_menu, window);
68 | menu_layer_add_to_window(layer_menu, window);
69 | }
70 |
71 | void win_vibration_show(VibrationCallback callback, TimerVibration vibration) {
72 | window_stack_push(window, true);
73 | MenuIndex index;
74 | index.section = 0;
75 | index.row = vibration;
76 | menu_layer_set_selected_index(layer_menu, index, MenuRowAlignTop, false);
77 | current_vibration = vibration;
78 | current_callback = callback;
79 | }
80 |
81 | void win_vibration_destroy(void) {
82 | menu_layer_destroy(layer_menu);
83 | window_destroy(window);
84 | }
85 |
86 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
87 |
88 | static uint16_t menu_get_num_sections_callback(MenuLayer *me, void *data) {
89 | return 1;
90 | }
91 |
92 | static uint16_t menu_get_num_rows_callback(MenuLayer *me, uint16_t section_index, void *data) {
93 | return 6;
94 | }
95 |
96 | static int16_t menu_get_header_height_callback(MenuLayer *me, uint16_t section_index, void *data) {
97 | return 0;
98 | }
99 |
100 | static int16_t menu_get_cell_height_callback(MenuLayer* me, MenuIndex* cell_index, void* data) {
101 | return 36;
102 | }
103 |
104 | static void menu_draw_row_callback(GContext* ctx, const Layer *cell_layer, MenuIndex *cell_index, void *data) {
105 | char label[24];
106 | strcpy(label, timer_vibe_str(cell_index->row, false));
107 | graphics_context_set_text_color(ctx, GColorBlack);
108 | graphics_draw_text(ctx, label, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD), GRect(4, 1, 112, 28), GTextOverflowModeTrailingEllipsis , GTextAlignmentLeft, NULL);
109 | if (current_vibration == cell_index->row) {
110 | graphics_draw_bitmap_in_rect(ctx, bitmaps_get_sub_bitmap(RESOURCE_ID_ICONS_16, ICON_RECT_DONE), GRect(120, 10, 16, 16));
111 | }
112 |
113 | }
114 |
115 | static void menu_select_click_callback(MenuLayer *menu_layer, MenuIndex *cell_index, void *callback_context) {
116 | current_callback(cell_index->row);
117 | window_stack_pop(true);
118 | }
--------------------------------------------------------------------------------
/src/windows/win-vibration.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | src/windows/win-vibration.h
29 |
30 | */
31 |
32 | #pragma once
33 |
34 | #include "../timer.h"
35 |
36 | typedef void (*VibrationCallback)(TimerVibration vibration);
37 |
38 | void win_vibration_init(void);
39 | void win_vibration_show(VibrationCallback callback, TimerVibration vibration);
--------------------------------------------------------------------------------
/tests/groups.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | test/groups.h
29 |
30 | */
31 |
32 | void timers_before(void);
33 | char* timers_tests(void);
--------------------------------------------------------------------------------
/tests/scripts/local-setup.sh:
--------------------------------------------------------------------------------
1 | SDK_INCLUDE_FOLDER=$1/Pebble/include
2 | INCLUDE_FOLDER=tests/include
3 |
4 | mkdir $INCLUDE_FOLDER
5 | cp $SDK_INCLUDE_FOLDER/*.h $INCLUDE_FOLDER
6 | echo '' > $INCLUDE_FOLDER/pebble_warn_unsupported_functions.h
--------------------------------------------------------------------------------
/tests/scripts/travis-install.sh:
--------------------------------------------------------------------------------
1 | SDK_VERSION=2.8.1
2 | PACKAGE_NAME=PebbleSDK-$SDK_VERSION
3 | SDK_INCLUDE_FOLDER=$PACKAGE_NAME/Pebble/include
4 | INCLUDE_FOLDER=tests/include
5 | SDK_ZIP_NAME=$PACKAGE_NAME.tar.gz
6 |
7 | wget http://assets.getpebble.com.s3-website-us-east-1.amazonaws.com/sdk2/$SDK_ZIP_NAME
8 | tar -zxf $SDK_ZIP_NAME
9 | mkdir $INCLUDE_FOLDER
10 | mv $SDK_INCLUDE_FOLDER/pebble.h $INCLUDE_FOLDER
11 | mv $SDK_INCLUDE_FOLDER/pebble_fonts.h $INCLUDE_FOLDER
12 | mv $SDK_INCLUDE_FOLDER/pebble_app_info.h $INCLUDE_FOLDER
13 | touch $INCLUDE_FOLDER/pebble_warn_unsupported_functions.h
--------------------------------------------------------------------------------
/tests/src/code.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | test/src/code.c
29 |
30 | */
31 |
32 | #include "settings.h"
33 | #include "timer.h"
34 |
35 | Settings _settings = {
36 | .timers_start_auto = false,
37 | .timers_vibration = TIMER_VIBE_SHORT,
38 | .timers_duration = 10 * 60,
39 | .timers_hours = false,
40 | .show_clock = false
41 | };
42 |
43 |
44 | void win_vibrate_show(void) {
45 |
46 | }
47 |
48 | Settings* settings(void) {
49 | return &_settings;
50 | }
--------------------------------------------------------------------------------
/tests/src/pebble.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Pebble Tests v0.1.0
4 | A Pebble library for doing unit tests.
5 | http://smallstoneapps.github.io/pebble-tests/
6 |
7 | ----------------------
8 |
9 | The MIT License (MIT)
10 |
11 | Copyright © 2014 Matthew Tole
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 |
31 | --------------------
32 |
33 | pebble.c
34 |
35 | */
36 |
37 | #include
38 | #include "pebble_extra.h"
39 | #include "libs/linked-list/linked-list.h"
40 |
41 | typedef enum PersistType {
42 | DATA, NUMBER, STRING
43 | } PersistType;
44 |
45 | typedef struct Persist {
46 | uint32_t key;
47 | PersistType type;
48 | void* data;
49 | uint32_t number;
50 | char* str;
51 | } Persist;
52 |
53 | static bool persist_compare(void* persist1, void* persist2);
54 |
55 | LinkedRoot* persistence = NULL;
56 |
57 | void persist_reset(void) {
58 | linked_list_clear(persistence);
59 | }
60 |
61 | void persist_clear(void) {
62 | linked_list_clear(persistence);
63 | }
64 |
65 | void persist_init(void) {
66 | persistence = linked_list_create_root();
67 | }
68 |
69 | Persist* fake_persist(const uint32_t key) {
70 | Persist* p = malloc(sizeof(Persist));
71 | p->key = key;
72 | return p;
73 | }
74 |
75 | static bool persist_compare(void* persist1, void* persist2) {
76 | return ((Persist*)persist1)->key == ((Persist*)persist2)->key;
77 | }
78 |
79 | bool persist_exists(const uint32_t key) {
80 | return linked_list_contains_compare(persistence, fake_persist(key), persist_compare);
81 | }
82 |
83 | int persist_read_data(const uint32_t key, void *buffer, const size_t buffer_size) {
84 | Persist* persist = (Persist*) linked_list_get(persistence, linked_list_find_compare(persistence, fake_persist(key), persist_compare));
85 | if (! persist) {
86 | return -1;
87 | }
88 | if (DATA != persist->type) {
89 | return -1;
90 | }
91 | memcpy(buffer, persist->data, buffer_size);
92 | return buffer_size;
93 | }
94 |
95 | int32_t persist_read_int(const uint32_t key) {
96 | Persist* persist = (Persist*) linked_list_get(persistence, linked_list_find_compare(persistence, fake_persist(key), persist_compare));
97 | if (! persist) {
98 | return -1;
99 | }
100 | if (NUMBER != persist->type) {
101 | return -1;
102 | }
103 | return persist->number;
104 | }
105 |
106 | status_t persist_write_int(const uint32_t key, const int32_t value) {
107 | persist_delete(key);
108 | Persist* persist = malloc(sizeof(Persist));
109 | persist->key = key;
110 | persist->type = NUMBER;
111 | persist->number = value;
112 | linked_list_append(persistence, persist);
113 | return 0;
114 | }
115 |
116 | int persist_write_data(const uint32_t key, const void *data, const size_t size) {
117 | persist_delete(key);
118 | Persist* persist = malloc(sizeof(Persist));
119 | persist->key = key;
120 | persist->type = DATA;
121 | persist->data = malloc(size);
122 | memcpy(persist->data, data, size);
123 | linked_list_append(persistence, persist);
124 | return size;
125 | }
126 |
127 | int persist_read_string(const uint32_t key, char *buffer, const size_t buffer_size) {
128 | Persist* persist = (Persist*) linked_list_get(persistence, linked_list_find_compare(persistence, fake_persist(key), persist_compare));
129 | if (! persist) {
130 | return -1;
131 | }
132 | if (STRING != persist->type) {
133 | return -1;
134 | }
135 | strncpy(buffer, persist->str, buffer_size);
136 | return buffer_size;
137 | }
138 |
139 | int persist_write_string(const uint32_t key, const char *cstring) {
140 | persist_delete(key);
141 | Persist* persist = malloc(sizeof(Persist));
142 | persist->key = key;
143 | persist->type = STRING;
144 | persist->str = malloc(strlen(cstring) + 1);
145 | strcpy(persist->str, cstring);
146 | linked_list_append(persistence, persist);
147 | return strlen(cstring);
148 | }
149 |
150 | status_t persist_delete(uint32_t key) {
151 | linked_list_remove(persistence, linked_list_find_compare(persistence, fake_persist(key), persist_compare));
152 | return S_SUCCESS;
153 | }
154 |
155 | void app_log(uint8_t log_level, const char *src_filename, int src_line_number, const char *fmt, ...) {
156 |
157 | }
158 |
159 | uint32_t app_message_inbox_size_maximum(void) {
160 | return APP_MESSAGE_INBOX_SIZE_MINIMUM;
161 | }
162 |
163 | uint32_t app_message_outbox_size_maximum(void) {
164 | return APP_MESSAGE_OUTBOX_SIZE_MINIMUM;
165 | }
166 |
167 | AppMessageResult app_message_open(const uint32_t size_inbound, const uint32_t size_outbound) {
168 | return APP_MSG_OK;
169 | }
170 |
171 | AppMessageInboxReceived app_message_register_inbox_received(AppMessageInboxReceived received_callback) {
172 | return NULL;
173 | }
174 |
175 | AppMessageInboxDropped app_message_register_inbox_dropped(AppMessageInboxDropped dropped_callback) {
176 | return NULL;
177 | }
178 |
179 | AppMessageOutboxSent app_message_register_outbox_sent(AppMessageOutboxSent sent_callback) {
180 | return NULL;
181 | }
182 |
183 | AppMessageOutboxFailed app_message_register_outbox_failed(AppMessageOutboxFailed failed_callback) {
184 | return NULL;
185 | }
186 |
187 | AppMessageResult app_message_outbox_begin(DictionaryIterator **iterator) {
188 | return APP_MSG_OK;
189 | }
190 |
191 | AppMessageResult app_message_outbox_send(void) {
192 | return APP_MSG_OK;
193 | }
194 |
195 | Tuple *dict_find(const DictionaryIterator *iter, const uint32_t key) {
196 | return NULL;
197 | }
198 |
199 | DictionaryResult dict_write_cstring(DictionaryIterator *iter, const uint32_t key, const char * const cstring) {
200 | return DICT_OK;
201 | }
202 |
203 | void app_timer_cancel(AppTimer *timer_handle) {
204 |
205 | }
206 |
207 | AppTimer* app_timer_register(uint32_t timeout_ms, AppTimerCallback callback, void* callback_data) {
208 | return NULL;
209 | }
210 |
211 | GFont fonts_get_system_font(const char *font_key) {
212 | return NULL;
213 | }
214 |
215 | GBitmap* gbitmap_create_with_resource(uint32_t resource_id) {
216 | return NULL;
217 | }
218 |
219 | void gbitmap_destroy(GBitmap* bitmap) {
220 |
221 | }
222 |
223 | void graphics_context_set_text_color(GContext* ctx, GColor color) {
224 |
225 | }
226 |
227 | void graphics_draw_bitmap_in_rect(GContext* ctx, const GBitmap *bitmap, GRect rect) {
228 |
229 | }
230 |
231 | void graphics_draw_text(GContext* ctx, const char* text, GFont const font, const GRect box, const GTextOverflowMode overflow_mode, const GTextAlignment alignment, const GTextLayoutCacheRef layout) {
232 |
233 | }
234 |
235 | void vibes_enqueue_custom_pattern(VibePattern pattern) {
236 |
237 | }
238 |
239 | void vibes_long_pulse(void) {
240 |
241 | }
242 |
243 | void vibes_short_pulse(void) {
244 |
245 | }
246 |
247 | WakeupId wakeup_schedule(time_t timestamp, int32_t reason, bool notify_if_missed) {
248 | return 0;
249 | }
250 |
251 | void wakeup_cancel(WakeupId id) {
252 |
253 | }
254 |
255 | bool wakeup_query(WakeupId id, time_t *timestamp) {
256 | return true;
257 | }
--------------------------------------------------------------------------------
/tests/src/pebble_extra.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Pebble Tests v0.1.0
4 | A Pebble library for doing unit tests.
5 | http://smallstoneapps.github.io/pebble-tests/
6 |
7 | ----------------------
8 |
9 | The MIT License (MIT)
10 |
11 | Copyright © 2014 Matthew Tole
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 |
31 | --------------------
32 |
33 | tests/pebble-extra.h
34 |
35 | */
36 |
37 | void persist_reset(void);
38 | void persist_init(void);
--------------------------------------------------------------------------------
/tests/src/resource_ids.auto.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smallstoneapps/multi-timer/8d49ea1b9a87c6ea155eaea6005cf0d4e32354f6/tests/src/resource_ids.auto.h
--------------------------------------------------------------------------------
/tests/tests.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | test/test.c
29 |
30 | */
31 |
32 | #include
33 | #include "unit.h"
34 | #include "src/pebble_extra.h"
35 | #include "groups.h"
36 | #include "../src/generated/appinfo.h"
37 |
38 | // Keep track of how many tests have run, and how many have passed.
39 | int tests_run = 0;
40 | int tests_passed = 0;
41 |
42 | void before_each(void) {
43 | persist_init();
44 | timers_before();
45 | }
46 |
47 | void after_each(void) {
48 | persist_reset();
49 | }
50 |
51 |
52 | static char* all_tests(void) {
53 | mu_run_test_group(timers_tests);
54 | return 0;
55 | }
56 |
57 | void none(void) {}
58 |
59 | // Test application entry point.
60 | // Executes all the tests and prints the results in pretty colours.
61 | int main(int argc, char **argv) {
62 | printf("%s---------------------------------\n", KCYN);
63 | printf("| Running Multi Timer %s Tests |\n", VERSION_LABEL);
64 | printf("---------------------------------\n%s", KNRM);
65 | char* result = all_tests();
66 | if (0 != result) {
67 | printf("%s- Failed Test:%s %s\n", KRED, KNRM, result);
68 | }
69 | printf("- Tests Run: %s%d%s\n", (tests_run == tests_passed) ? KGRN : KRED, tests_run, KNRM);
70 | printf("- Tests Passed: %s%d%s\n", (tests_run == tests_passed) ? KGRN : KRED, tests_passed, KNRM);
71 |
72 | printf("%s---------------------------------%s\n", KCYN, KNRM);
73 | return result != 0;
74 | }
--------------------------------------------------------------------------------
/tests/timers.c:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Multi Timer v3.4
4 | http://matthewtole.com/pebble/multi-timer/
5 |
6 | ----------------------
7 |
8 | The MIT License (MIT)
9 | Copyright © 2013 - 2015 Matthew Tole
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | --------------------
27 |
28 | test/timers.c
29 |
30 | */
31 |
32 | #include
33 | #include "unit.h"
34 | #include "groups.h"
35 | #include "../src/timers.h"
36 | #include "../src/migration.h"
37 | #include "../src/persist.h"
38 |
39 | void timers_before(void) {
40 | timers_init();
41 | }
42 |
43 | char* count_zero_when_empty(void) {
44 | mu_assert(0 == timers_count(), "timers_count was not 0 when no timers added");
45 | return 0;
46 | }
47 |
48 | char* count_one_when_added_single_timer(void) {
49 | Timer* timer = malloc(sizeof(Timer));
50 | timers_add(timer);
51 | mu_assert(1 == timers_count(), "timers_count was not 1 when a timer was added");
52 | return 0;
53 | }
54 |
55 | char* count_10_when_added_ten_timers(void) {
56 | for (uint8_t t = 0; t < 10; t += 1) {
57 | Timer* timer = malloc(sizeof(Timer));
58 | timers_add(timer);
59 | }
60 | mu_assert(10 == timers_count(), "timers_count was not 10 when ten timers were added");
61 | return 0;
62 | }
63 |
64 | char* get_timer_null_when_empty(void) {
65 | mu_assert(NULL == timers_get(0), "timers_get was not null when empty at position 0");
66 | mu_assert(NULL == timers_get(100), "timers_get was not null when empty at position 100");
67 | return 0;
68 | }
69 |
70 | char* get_timer_returns_item(void) {
71 | Timer* timer = malloc(sizeof(Timer));
72 | timers_add(timer);
73 | mu_assert(NULL != timers_get(0), "timers_get was null with one item at position 0");
74 | mu_assert(NULL == timers_get(1), "timers_get was not null with one item at position 1");
75 | return 0;
76 | }
77 |
78 | char* find_null_when_empty(void) {
79 | mu_assert(NULL == timers_find(1), "timers_find was not null when empty with id 1");
80 | mu_assert(NULL == timers_find(8888), "timers_get was not null when empty with id 8888");
81 | return 0;
82 | }
83 |
84 | char* find_timer_when_exists(void) {
85 | Timer* timer = malloc(sizeof(Timer));
86 | timer->id = 1;
87 | timers_add(timer);
88 | mu_assert(NULL != timers_find(1), "timers_find was null when exists with id 1");
89 | return 0;
90 | }
91 |
92 | char* timer_remove_false_when_empty(void) {
93 | mu_assert(false == timers_remove(0), "timers_remove failed when empty");
94 | return 0;
95 | }
96 |
97 | char* timer_remove_true_when_single_timer(void) {
98 | Timer* timer = malloc(sizeof(Timer));
99 | timers_add(timer);
100 | mu_assert(true == timers_remove(0), "timers_remvoe succeeds when single timer");
101 | return 0;
102 | }
103 |
104 | char* timer_remove_false_when_not_existant(void) {
105 | Timer* timer = malloc(sizeof(Timer));
106 | timers_add(timer);
107 | mu_assert(false == timers_remove(5), "timers_remvoe fails when invalid position");
108 | return 0;
109 | }
110 |
111 | char* timer_remove_reduces_count(void) {
112 | timers_add(malloc(sizeof(Timer)));
113 | timers_add(malloc(sizeof(Timer)));
114 | timers_remove(0);
115 | mu_assert(1 == timers_count(), "timers_remove did not reduce timers count");
116 | return 0;
117 | }
118 |
119 | char* timers_save_persists_zero_timers(void) {
120 | timers_save();
121 | timers_clear();
122 | timers_restore();
123 | mu_assert(0 == timers_count(), "timers_save with no timers did not restore to zero timers");
124 | return 0;
125 | }
126 |
127 |
128 | char* timers_save_persists_zero_timers_after_lots(void) {
129 | timers_add(malloc(sizeof(Timer)));
130 | timers_add(malloc(sizeof(Timer)));
131 | timers_save();
132 | timers_clear();
133 | timers_save();
134 | timers_restore();
135 | mu_assert(0 == timers_count(), "timers_save with no timers (after lots) did not restore to zero timers");
136 | return 0;
137 | }
138 |
139 |
140 | char* timers_save_persists_one_timer(void) {
141 | Timer* timer = malloc(sizeof(Timer));
142 | timer->id = 10;
143 | timers_add(timer);
144 | timers_save();
145 | timers_clear();
146 | timers_restore();
147 | mu_assert(1 == timers_count(), "timers_save with one timer did not restore a timer");
148 | mu_assert(timer->id == timers_get(0)->id, "timers_save with one timer did not restore the timer correctly");
149 | return 0;
150 | }
151 |
152 | char* timers_save_persists_multiple_timers(void) {
153 | Timer* timer1 = malloc(sizeof(Timer));
154 | timer1->id = 10;
155 | timers_add(timer_clone(timer1));
156 |
157 | Timer* timer2 = malloc(sizeof(Timer));
158 | timer2->id = 20;
159 | timers_add(timer_clone(timer2));
160 |
161 | Timer* timer3 = malloc(sizeof(Timer));
162 | timer3->id = 30;
163 | timers_add(timer_clone(timer3));
164 |
165 | Timer* timer4 = malloc(sizeof(Timer));
166 | timer4->id = 40;
167 | timers_add(timer_clone(timer4));
168 |
169 | Timer* timer5 = malloc(sizeof(Timer));
170 | timer5->id = 50;
171 | timers_add(timer_clone(timer5));
172 |
173 | timers_save();
174 | timers_clear();
175 | timers_restore();
176 | mu_assert(5 == timers_count(), "timers_save with multiple timer did not restore the timers");
177 | mu_assert(timer1->id == timers_get(0)->id, "timers_save with multiple timer did not restore timer 1 correctly");
178 | mu_assert(timer2->id == timers_get(1)->id, "timers_save with multiple timer did not restore timer 2 correctly");
179 | mu_assert(timer3->id == timers_get(2)->id, "timers_save with multiple timer did not restore timer 3 correctly");
180 | mu_assert(timer4->id == timers_get(3)->id, "timers_save with multiple timer did not restore timer 4 correctly");
181 | mu_assert(timer5->id == timers_get(4)->id, "timers_save with multiple timer did not restore timer 5 correctly");
182 | return 0;
183 | }
184 |
185 | char* timer_str(void) {
186 | Timer* timer = malloc(sizeof(Timer));
187 | char str[16];
188 |
189 | timer_time_str(0, false, str, 16);
190 | mu_assert(0 == strcmp("00:00", str), "timer_str did not display 0 correctly (no hours)");
191 |
192 | timer_time_str(60, false, str, 16);
193 | mu_assert(0 == strcmp("01:00", str), "timer_str did not display 60 correctly (no hours)");
194 |
195 | timer_time_str(3600, false, str, 16);
196 | mu_assert(0 == strcmp("60:00", str), "timer_str did not display 3600 correctly (no hours)");
197 |
198 | timer_time_str(3600, true, str, 16);
199 | mu_assert(0 == strcmp("01:00:00", str), "timer_str did not display 3600 correctly (hours)");
200 |
201 | return 0;
202 | }
203 |
204 | char* timers_migrate_from_1_to_3(void) {
205 | OldTimerBlock* block = malloc(sizeof(OldTimerBlock));
206 | block->count = 2;
207 | block->time = time(NULL);
208 | block->timers[0].direction = OLD_TIMER_DIRECTION_DOWN;
209 | block->timers[0].length = 3000;
210 | block->timers[0].time_left = 200;
211 | block->timers[0].status = OLD_TIMER_STATUS_PAUSED;
212 | block->timers[0].repeat = true;
213 | block->timers[0].vibrate = OLD_TIMER_VIBRATION_DOUBLE;
214 | block->timers[1].direction = OLD_TIMER_DIRECTION_UP;
215 | block->timers[1].time_left = 50;
216 | block->timers[1].status = OLD_TIMER_STATUS_RUNNING;
217 | persist_write_data(PERSIST_TIMER_START, block, sizeof(OldTimerBlock));
218 | free(block);
219 |
220 | timers_restore();
221 | mu_assert(2 == timers_count(), "Migrate 1->3: Incorrect number of timers");
222 |
223 | Timer* tmr1 = timers_get(0);
224 | Timer* tmr2 = timers_get(1);
225 |
226 | mu_assert(tmr1->type == TIMER_TYPE_TIMER, "Migrate 1->3: Timer 1 wrong type");
227 | mu_assert(tmr1->length == 3000, "Migrate 1->3: Timer 1 wrong length");
228 | mu_assert(tmr1->current_time == 200, "Migrate 1->3: Timer 1 wrong time");
229 | mu_assert(tmr1->status == TIMER_STATUS_PAUSED, "Migrate 1->3: Timer 1 wrong status");
230 | mu_assert(tmr1->repeat == TIMER_REPEAT_INFINITE, "Migrate 1->3: Timer 1 wrong repeat");
231 | mu_assert(tmr1->vibration == TIMER_VIBE_DOUBLE , "Migrate 1->3: Timer 1 wrong vibration");
232 | mu_assert(tmr2->type == TIMER_TYPE_STOPWATCH , "Migrate 1->3: Timer 2 wrong type");
233 | mu_assert(tmr2->current_time == 50, "Migrate 1->3: Timer 2 wrong time");
234 | mu_assert(tmr2->status == TIMER_STATUS_RUNNING , "Migrate 1->3: Timer 2 wrong status");
235 |
236 | return 0;
237 | }
238 |
239 | char* timers_migrate_from_2_to_3(void) {
240 | TimerBlockTiny* block = malloc(sizeof(TimerBlockTiny));
241 | block->total_timers = 2;
242 | block->save_time = time(NULL);
243 | block->timers[0].type = TIMER_TYPE_TIMER;
244 | block->timers[0].length = 60;
245 | block->timers[0].current_time = 45;
246 | block->timers[0].id = 5;
247 | strcpy(block->timers[0].label, "LABEL #1");
248 | block->timers[0].repeat = TIMER_REPEAT_INFINITE;
249 | block->timers[0].vibration = TIMER_VIBE_SOLID;
250 | block->timers[0].status = TIMER_STATUS_PAUSED;
251 | block->timers[0].wakeup_id = 70;
252 | block->timers[1].type = TIMER_TYPE_STOPWATCH;
253 | block->timers[1].current_time = 500;
254 | block->timers[1].id = 10;
255 | strcpy(block->timers[1].label, "LABEL #2");
256 | block->timers[1].status = TIMER_STATUS_RUNNING;
257 | block->timers[1].wakeup_id = 60;
258 |
259 | persist_write_data(PERSIST_TIMER_START, block, sizeof(TimerBlockTiny));
260 | persist_write_int(PERSIST_TIMERS_VERSION, TIMERS_VERSION_TINY);
261 | free(block);
262 |
263 | timers_restore();
264 | mu_assert(2 == timers_count(), "Migrate 2->3: Incorrect number of timers");
265 |
266 | Timer* tmr1 = timers_get(0);
267 | Timer* tmr2 = timers_get(1);
268 |
269 | mu_assert(tmr1->type == TIMER_TYPE_TIMER, "Migrate 2->3: Timer 1 wrong type");
270 | mu_assert(tmr1->length == 60, "Migrate 2->3: Timer 1 wrong length");
271 | mu_assert(tmr1->current_time == 45, "Migrate 2->3: Timer 1 wrong current time");
272 | mu_assert(tmr1->id == 5, "Migrate 2->3: Timer 1 wrong ID");
273 | mu_assert(0 == strcmp(tmr1->label, "LABEL #1"), "Migrate 2->3: Timer 1 wrong label");
274 | mu_assert(tmr1->repeat == TIMER_REPEAT_INFINITE, "Migrate 2->3: Timer 1 wrong repeat");
275 | mu_assert(tmr1->vibration == TIMER_VIBE_SOLID, "Migrate 2->3: Timer 1 wrong vibration");
276 | mu_assert(tmr1->status == TIMER_STATUS_PAUSED, "Migrate 2->3: Timer 1 wrong status");
277 | mu_assert(tmr1->wakeup_id == 70, "Migrate 2->3: Timer 1 wrong wakeup ID");
278 |
279 | mu_assert(tmr2->type == TIMER_TYPE_STOPWATCH, "Migrate 2->3: Timer 2 wrong wakeup type");
280 | mu_assert(tmr2->current_time == 500, "Migrate 2->3: Timer 2 wrong current time");
281 | mu_assert(tmr2->id == 10, "Migrate 2->3: Timer 2 wrong id");
282 | mu_assert(0 == strcmp(tmr2->label, "LABEL #2"), "Migrate 2->3: Timer 2 wrong label");
283 | mu_assert(tmr2->status == TIMER_STATUS_RUNNING, "Migrate 2->3: Timer 2 wrong status");
284 | mu_assert(tmr2->wakeup_id == 60, "Migrate 2->3: Timer 2 wrong wakeup ID");
285 |
286 | return 0;
287 | }
288 |
289 | char* timers_tests(void) {
290 | mu_run_test(count_zero_when_empty);
291 | mu_run_test(count_one_when_added_single_timer);
292 | mu_run_test(count_10_when_added_ten_timers);
293 | mu_run_test(get_timer_null_when_empty);
294 | mu_run_test(get_timer_returns_item);
295 | mu_run_test(find_null_when_empty);
296 | mu_run_test(find_timer_when_exists);
297 | mu_run_test(timer_remove_false_when_empty);
298 | mu_run_test(timer_remove_true_when_single_timer);
299 | mu_run_test(timer_remove_false_when_not_existant);
300 | mu_run_test(timer_remove_reduces_count);
301 | mu_run_test(timers_save_persists_zero_timers);
302 | mu_run_test(timers_save_persists_zero_timers_after_lots);
303 | mu_run_test(timers_save_persists_one_timer);
304 | mu_run_test(timers_save_persists_multiple_timers);
305 | mu_run_test(timer_str);
306 | mu_run_test(timers_migrate_from_1_to_3);
307 | mu_run_test(timers_migrate_from_2_to_3);
308 | return 0;
309 | }
310 |
--------------------------------------------------------------------------------
/tests/unit.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Pebble Tests v0.1.0
4 | A Pebble library for doing unit tests.
5 | http://smallstoneapps.github.io/pebble-tests/
6 |
7 | ----------------------
8 |
9 | The MIT License (MIT)
10 |
11 | Copyright © 2014 Matthew Tole
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 |
31 | --------------------
32 |
33 | unit.h
34 |
35 | This file is based on minunit.h, which was found here
36 | http://www.jera.com/techinfo/jtns/jtn002.html
37 | and has been modified for my purposes.
38 |
39 | */
40 |
41 | // Colour code definitions to make the output all pretty.
42 | #define KNRM "\x1B[0m"
43 | #define KRED "\x1B[31m"
44 | #define KGRN "\x1B[32m"
45 | #define KYEL "\x1B[33m"
46 | #define KBLU "\x1B[34m"
47 | #define KMAG "\x1B[35m"
48 | #define KCYN "\x1B[36m"
49 | #define KWHT "\x1B[37m"
50 |
51 | #define mu_assert(test, message) do { \
52 | if (!(test)) { \
53 | return message; \
54 | } \
55 | } while (0)
56 |
57 | #define mu_run_test_group(group) do { \
58 | char* message = group(); \
59 | if (message) { \
60 | return message; \
61 | } \
62 | } while(0)
63 |
64 | #define mu_run_test(test) do { \
65 | before_each(); \
66 | char *message = test(); \
67 | after_each(); \
68 | tests_run++; \
69 | if (message) { \
70 | return message; \
71 | } \
72 | tests_passed++; \
73 | } while (0)
74 |
75 | extern int tests_run;
76 | extern int tests_passed;
77 |
78 | void none(void);
79 | void before_each(void);
80 | void after_each(void);
81 |
--------------------------------------------------------------------------------
/wscript:
--------------------------------------------------------------------------------
1 | # WARNING: This wscript does not follow good practices and should not be copied
2 | # or reproduced in your own projects.
3 | #
4 | # Multi Timer v3.4
5 | # http://matthewtole.com/pebble/multi-timer/
6 | #
7 | # ----------------------
8 | #
9 | # The MIT License (MIT)
10 | #
11 | # Copyright © 2013 - 2015 Matthew Tole
12 | #
13 | # Permission is hereby granted, free of charge, to any person obtaining a copy
14 | # of this software and associated documentation files (the "Software"), to deal
15 | # in the Software without restriction, including without limitation the rights
16 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | # copies of the Software, and to permit persons to whom the Software is
18 | # furnished to do so, subject to the following conditions:
19 | #
20 | # The above copyright notice and this permission notice shall be included in
21 | # all copies or substantial portions of the Software.
22 | #
23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | # THE SOFTWARE.
30 | #
31 | # --------------------
32 | #
33 | # wscript
34 | #
35 |
36 | import json
37 | import datetime
38 | import os
39 | from sh import karma
40 | from sh import uglifyjs
41 | from sh import jshint
42 | from sh import make
43 |
44 | top = '.'
45 | out = 'build'
46 |
47 | def options(ctx):
48 | ctx.load('pebble_sdk')
49 |
50 | def configure(ctx):
51 | ctx.load('pebble_sdk')
52 |
53 | def distclean(ctx):
54 | ctx.load('pebble_sdk')
55 | try:
56 | os.remove('./src/js/pebble-js-app.js')
57 | except OSError as e:
58 | pass
59 | try:
60 | os.remove('./src/js/src/generated/appinfo.js')
61 | except OSError as e:
62 | pass
63 | try:
64 | os.remove('./src/generated/appinfo.h')
65 | except OSError as e:
66 | pass
67 |
68 | def build(ctx):
69 | ctx.load('pebble_sdk')
70 |
71 | js_libs = [
72 | '../src/js/src/libs/pebble-ga.js'
73 | ]
74 |
75 | js_sources = [
76 | '../src/js/src/generated/appinfo.js',
77 | '../src/js/src/main.js',
78 | ]
79 | built_js = '../src/js/pebble-js-app.js'
80 |
81 | c_sources = ctx.path.ant_glob('src/**/*.c')
82 |
83 | # Generate appinfo.js
84 | ctx(rule=generate_appinfo_js, source='../appinfo.json', target='../src/js/src/generated/appinfo.js')
85 |
86 | # Generate appinfo.h
87 | ctx(rule=generate_appinfo_h, source='../appinfo.json', target='../src/generated/appinfo.h')
88 |
89 | # Run the C tests.
90 | # ctx(rule=make_test);
91 |
92 | # Run jshint on all the JavaScript files
93 | ctx(rule=js_jshint, source=js_sources)
94 |
95 | # Run the suite of JS tests.
96 | # ctx(rule=js_karma)
97 |
98 | # Combine the source JS files into a single JS file.
99 | ctx(rule=concatenate_js, source=' '.join(js_libs + js_sources), target=built_js)
100 |
101 | # Build and bundle the Pebble app.
102 | ctx.pbl_program(source=c_sources,
103 | includes=lib_folders(ctx),
104 | target='pebble-app.elf')
105 | ctx.pbl_bundle(elf='pebble-app.elf', js=built_js)
106 |
107 | # Return a list of all of the subfolders within the "src/libs/" folder
108 | def lib_folders(ctx):
109 | folders = []
110 | libs = ctx.path.find_node('./src/libs')
111 | for folder in libs.listdir():
112 | folders.append(libs.find_node(folder).abspath())
113 | return folders
114 |
115 | def generate_appinfo_h(task):
116 | ext_out = '.c'
117 | src = task.inputs[0].abspath()
118 | target = task.outputs[0].abspath()
119 | appinfo = json.load(open(src))
120 |
121 | f = open(target, 'w')
122 | write_comment_header(f, 'src/generated/appinfo.h', appinfo)
123 | f.write('#pragma once\n\n')
124 | f.write('#define VERSION_LABEL "{0}"\n'.format(appinfo["versionLabel"]))
125 | f.write('#define UUID "{0}"\n'.format(appinfo["uuid"]))
126 | f.write('#define DEBUG_MODE {0}\n'.format('true' if appinfo["debug"] else 'false'))
127 | f.write('#define DELIMITER_INNER \'{0}\'\n'.format(appinfo['delimiters']['inner']))
128 | f.write('#define DELIMITER_OUTER \'{0}\'\n'.format(appinfo['delimiters']['outer']))
129 | for key in appinfo['appKeys']:
130 | f.write('#define APP_KEY_{0} {1}\n'.format(key.upper(), appinfo['appKeys'][key]))
131 | f.close()
132 |
133 | def generate_appinfo_js(task):
134 | src = task.inputs[0].abspath()
135 | target = task.outputs[0].abspath()
136 | data = open(src).read().strip()
137 | appinfo = json.load(open(src))
138 |
139 | f = open(target, 'w')
140 | write_comment_header(f, 'src/js/src/generated/appinfo.js', appinfo)
141 | f.write('/* exported AppInfo */\n\n')
142 | f.write('var AppInfo = ')
143 | f.write(data)
144 | f.write(';')
145 | f.close()
146 |
147 | # Function to write the comment header for both the C and JS generated files.
148 | # Thank goodness that they have the same comment syntax!
149 | def write_comment_header(f, filename, appinfo):
150 | f.write('/*\n')
151 | f.write('\n')
152 | f.write('Multi Timer v{0}\n'.format(appinfo['versionLabel']))
153 | f.write('http://matthewtole.com/pebble/multi-timer/\n')
154 | f.write('\n')
155 | f.write('----------------------\n')
156 | f.write('\n')
157 | f.write('The MIT License (MIT)\n')
158 | f.write('\n')
159 | f.write('Copyright © 2013 - {0} Matthew Tole\n'.format(datetime.datetime.now().year))
160 | f.write('\n')
161 | f.write('Permission is hereby granted, free of charge, to any person obtaining a copy\n')
162 | f.write('of this software and associated documentation files (the "Software"), to deal\n')
163 | f.write('in the Software without restriction, including without limitation the rights\n')
164 | f.write('to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n')
165 | f.write('copies of the Software, and to permit persons to whom the Software is\n')
166 | f.write('furnished to do so, subject to the following conditions:\n')
167 | f.write('\n')
168 | f.write('The above copyright notice and this permission notice shall be included in\n')
169 | f.write('all copies or substantial portions of the Software.\n')
170 | f.write('\n')
171 | f.write('THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n')
172 | f.write('IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n')
173 | f.write('FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n')
174 | f.write('AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n')
175 | f.write('LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n')
176 | f.write('OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n')
177 | f.write('THE SOFTWARE.\n')
178 | f.write('\n')
179 | f.write('--------------------\n')
180 | f.write('\n')
181 | f.write('{0}\n'.format(filename))
182 | f.write('\n')
183 | f.write('*/\n')
184 | f.write('\n')
185 |
186 | def concatenate_js(task):
187 | inputs = (input.abspath() for input in task.inputs)
188 | uglifyjs(*inputs, o=task.outputs[0].abspath(), b=True, indent_level=2)
189 |
190 | def make_test(task):
191 | ext_out = '.c'
192 | make()
193 |
194 | def js_jshint(task):
195 | inputs = (input.abspath() for input in task.inputs)
196 | jshint(*inputs, config=".jshintrc")
197 |
198 | def js_karma(task):
199 | ext_out = '.js'
200 | karma("start", single_run=True, reporters="dots")
201 |
--------------------------------------------------------------------------------