├── .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 | ![](https://img.shields.io/badge/status-unmaintained-red.svg) 2 | 3 | ![Multi Timer Banner](https://raw.githubusercontent.com/smallstoneapps/multi-timer/master/marketing/banner_03.png) 4 | 5 | [![Tests Status](https://img.shields.io/travis/smallstoneapps/multi-timer.svg?style=flat-square&label=tests)][travis] [![Version 3.4](https://img.shields.io/badge/version-3.4-blue.svg?style=flat-square)][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 | [![Available on the Pebble App Store](http://pblweb.com/badge/52d30a1d19412b4d84000025/black/medium/)][appstore] 14 | 15 | ## Screenshots 16 | 17 | Pebble Screenshot #1 18 | Pebble Screenshot #2 19 | Pebble Screenshot #3 20 | Pebble Screenshot #4 21 | Pebble Screenshot #5 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 | --------------------------------------------------------------------------------