Initial commit.
This commit is contained in:
commit
b3581d255c
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
appinfo.json
|
||||
appinfo.site.json
|
||||
build/
|
||||
.lock-waf*
|
||||
/pebble_screenshot*.png
|
BIN
GFX/amiclock.idraw
Normal file
BIN
GFX/amiclock.idraw
Normal file
Binary file not shown.
19
LICENSE
Normal file
19
LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2015 Tomek Wójcik <tomek@bthlabs.pl>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
19
README.md
Normal file
19
README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# IntuiClock
|
||||
|
||||
IntuiClock is a Pebble Time watchface inspired by the Clock program from Amiga®
|
||||
Workbench 3.1.
|
||||
|
||||
## License
|
||||
|
||||
IntuiClock is licensed under MIT License.
|
||||
|
||||
## Author and credits
|
||||
|
||||
IntuiClock was written by [Tomek Wójcik](http://www.tomekwojcik.com/).
|
||||
|
||||
This project uses Topaz font (CC BY-NC-SA 3.0) by dMG/t!s^dS.
|
||||
|
||||
This project uses Slate frontend framework (MIT) by Pebble Technology.
|
||||
|
||||
Amiga® is a brand of Amiga Inc. This project is not an official Amiga Inc.
|
||||
product.
|
39
appinfo.in.json
Normal file
39
appinfo.in.json
Normal file
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"uuid": null,
|
||||
"shortName": null,
|
||||
"longName": null,
|
||||
"companyName": null,
|
||||
"versionLabel": null,
|
||||
"sdkVersion": "3",
|
||||
"targetPlatforms": ["basalt"],
|
||||
"watchapp": {
|
||||
"watchface": true
|
||||
},
|
||||
"resources": {
|
||||
"media": [
|
||||
{
|
||||
"type": "png",
|
||||
"name": "IMG_BACKGROUND",
|
||||
"file": "background.png"
|
||||
},
|
||||
{
|
||||
"type": "png",
|
||||
"name": "IMG_BATTERY",
|
||||
"file": "battery.png"
|
||||
},
|
||||
{
|
||||
"type": "font",
|
||||
"name": "FONT_TOPAZ_16",
|
||||
"file": "topaz1200.ttf"
|
||||
}
|
||||
]
|
||||
},
|
||||
"capabilities": [
|
||||
"configurable"
|
||||
],
|
||||
"appKeys": {
|
||||
"KEY_SECONDS_HAND": 0,
|
||||
"KEY_BATTERY_INDICATOR": 1,
|
||||
"KEY_DATE_FORMAT": 2
|
||||
}
|
||||
}
|
1
config/css/slate.min.css
vendored
Executable file
1
config/css/slate.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
BIN
config/fonts/PFDinDisplayPro-Light.woff
Executable file
BIN
config/fonts/PFDinDisplayPro-Light.woff
Executable file
Binary file not shown.
BIN
config/fonts/ptsans-regular.woff
Executable file
BIN
config/fonts/ptsans-regular.woff
Executable file
Binary file not shown.
106
config/index.html
Normal file
106
config/index.html
Normal file
|
@ -0,0 +1,106 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0" name="viewport">
|
||||
<title>IntuiClock Config</title>
|
||||
<link rel="stylesheet" href="css/slate.min.css">
|
||||
<script type="text/javascript" src="js/slate.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form id="main-form">
|
||||
<div class="item-container">
|
||||
<div class="item-container-header">Features</div>
|
||||
<div class="item-container-content">
|
||||
<label class="item">
|
||||
Seconds Hand
|
||||
<input id="input-seconds-hand" type="checkbox" class="item-toggle" name="seconds-hand" checked>
|
||||
</label>
|
||||
<label class="item">
|
||||
Battery Indicator
|
||||
<input id="input-battery-indicator" type="checkbox" class="item-toggle" name="battery-indicator" checked>
|
||||
</label>
|
||||
<label class="item">
|
||||
Date Format
|
||||
<select id="input-date-format" name="date-format" class="item-select">
|
||||
<option class="item-select-option" selected value="t">10 Aug 2015</option>
|
||||
<option class="item-select-option" value="d">10/08/2015</option>
|
||||
<option class="item-select-option" value="m">08/10/2015</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="item-container-footer">Disable the seconds hand to reduce battery use.</div>
|
||||
</div>
|
||||
|
||||
<div class="item-container">
|
||||
<div class="button-container">
|
||||
<input id="button-submit" type="button" class="item-button" value="SAVE">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
function getConfigData() {
|
||||
var input_seconds_hand = document.getElementById('input-seconds-hand'),
|
||||
input_battery_indicator = document.getElementById('input-battery-indicator'),
|
||||
input_date_format = document.getElementById('input-date-format');
|
||||
|
||||
var options = {
|
||||
'seconds_hand': input_seconds_hand.checked,
|
||||
'battery_indicator': input_battery_indicator.checked,
|
||||
'date_format': input_date_format.value
|
||||
};
|
||||
|
||||
// Save for next launch
|
||||
localStorage['seconds_hand'] = options['seconds_hand'];
|
||||
localStorage['battery_indicator'] = options['battery_indicator'];
|
||||
localStorage['date_format'] = options['date_format'];
|
||||
|
||||
console.log('Got options: ' + JSON.stringify(options));
|
||||
return options;
|
||||
}
|
||||
|
||||
function getQueryParam(variable, defaultValue) {
|
||||
var query = location.search.substring(1),
|
||||
vars = query.split('&');
|
||||
|
||||
for (var i = 0; i < vars.length; i++) {
|
||||
var pair = vars[i].split('=');
|
||||
if (pair[0] === variable) {
|
||||
return decodeURIComponent(pair[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue || false;
|
||||
}
|
||||
|
||||
var button_submit = document.getElementById('button-submit');
|
||||
button_submit.addEventListener('click', function() {
|
||||
console.log('Submit');
|
||||
|
||||
// Set the return URL depending on the runtime environment
|
||||
var return_to = getQueryParam('return_to', 'pebblejs://close#');
|
||||
document.location = return_to + encodeURIComponent(JSON.stringify(getConfigData()));
|
||||
});
|
||||
|
||||
(function() {
|
||||
var input_seconds_hand = document.getElementById('input-seconds-hand'),
|
||||
input_battery_indicator = document.getElementById('input-battery-indicator'),
|
||||
input_date_format = document.getElementById('input-date-format');
|
||||
|
||||
if (localStorage['seconds_hand']) {
|
||||
input_seconds_hand.checked = JSON.parse(localStorage['seconds_hand']);
|
||||
}
|
||||
|
||||
if (localStorage['battery_indicator']) {
|
||||
input_battery_indicator.checked = JSON.parse(localStorage['battery_indicator']);
|
||||
}
|
||||
|
||||
if (localStorage['date_format']) {
|
||||
input_date_format.value = localStorage['date_format'];
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</html>
|
2
config/js/slate.min.js
vendored
Executable file
2
config/js/slate.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
58
fabfile.py
vendored
Normal file
58
fabfile.py
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2015 Tomek Wójcik <tomek@bthlabs.pl>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
import codecs
|
||||
import json
|
||||
|
||||
from fabric.api import local, task
|
||||
|
||||
|
||||
def _load_appinfo(path):
|
||||
appinfo = None
|
||||
with codecs.open(path, 'r', 'utf-8') as appinfo_in_f:
|
||||
appinfo = json.loads(appinfo_in_f.read())
|
||||
|
||||
return appinfo
|
||||
|
||||
|
||||
@task
|
||||
def build(emulator=None, phone=None):
|
||||
appinfo = _load_appinfo('appinfo.in.json')
|
||||
assert appinfo
|
||||
|
||||
appinfo_site = _load_appinfo('appinfo.site.json')
|
||||
if appinfo_site:
|
||||
appinfo.update(appinfo_site)
|
||||
|
||||
with open('appinfo.json', 'w') as appinfo_f:
|
||||
appinfo_f.write(json.dumps(appinfo, indent=4))
|
||||
|
||||
local('pebble build')
|
||||
|
||||
|
||||
@task
|
||||
def emu(platform='basalt'):
|
||||
local('pebble install --emulator=%s' % platform)
|
||||
|
||||
|
||||
@task
|
||||
def phone(ip):
|
||||
local('pebble install --phone=%s' % ip)
|
BIN
resources/background.png
Normal file
BIN
resources/background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
resources/battery.png
Normal file
BIN
resources/battery.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
resources/topaz1200.ttf
Executable file
BIN
resources/topaz1200.ttf
Executable file
Binary file not shown.
349
src/intuiclock.c
Normal file
349
src/intuiclock.c
Normal file
|
@ -0,0 +1,349 @@
|
|||
/**
|
||||
* Copyright (c) 2015 Tomek Wójcik <tomek@bthlabs.pl>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <pebble.h>
|
||||
|
||||
static Window *s_main_window;
|
||||
static GBitmap *s_background_bitmap;
|
||||
static GBitmap *s_battery_bitmap;
|
||||
static GFont s_text_font;
|
||||
static GPath *s_minute_hand;
|
||||
static GPath *s_hour_hand;
|
||||
static BitmapLayer *s_background_layer;
|
||||
static TextLayer *s_title_layer;
|
||||
static Layer *s_hands_layer;
|
||||
static TextLayer *s_date_layer;
|
||||
static TextLayer *s_ampm_layer;
|
||||
static BitmapLayer *s_battery_icon_layer;
|
||||
static Layer *s_battery_indicator_layer;
|
||||
static struct tm *t = NULL;
|
||||
static uint8_t battery_charge = 0;
|
||||
static bool hide_seconds_hand = false;
|
||||
static bool hide_battery_indicator = false;
|
||||
static char date_format[2];
|
||||
|
||||
static const GPathInfo MINUTE_HAND_POINTS = {
|
||||
4,
|
||||
(GPoint []) {
|
||||
{ 0, 0 },
|
||||
{ -4.5, -26 },
|
||||
{ 0, -38 },
|
||||
{ 4.5, -26 }
|
||||
}
|
||||
};
|
||||
|
||||
static const GPathInfo HOUR_HAND_POINTS = {
|
||||
4,
|
||||
(GPoint []) {
|
||||
{ 0, 0 },
|
||||
{ -4.5, -22 },
|
||||
{ 0, -29 },
|
||||
{ 4.5, -22 }
|
||||
}
|
||||
};
|
||||
|
||||
#define AMPM_TEXT_SIZE 3
|
||||
#define DUMMY_AMPM_TEXT ""
|
||||
|
||||
#define DATE_TEXT_SIZE 12
|
||||
#define DUMMY_DATE_TEXT "23 Jul 1985"
|
||||
|
||||
#define KEY_SECONDS_HAND 0
|
||||
#define KEY_BATTERY_INDICATOR 1
|
||||
#define KEY_DATE_FORMAT 2
|
||||
|
||||
static void update_date_text_layer() {
|
||||
static char date_text[DATE_TEXT_SIZE];
|
||||
size_t result = 0;
|
||||
|
||||
if (strcmp(date_format, "d") == 0) {
|
||||
result = strftime(date_text, DATE_TEXT_SIZE, "%d/%m/%y", t);
|
||||
} else if (strcmp(date_format, "m") == 0) {
|
||||
result = strftime(date_text, DATE_TEXT_SIZE, "%m/%d/%y", t);
|
||||
} else {
|
||||
result = strftime(date_text, DATE_TEXT_SIZE, "%e %b %Y", t);
|
||||
}
|
||||
|
||||
if (result != 0) {
|
||||
text_layer_set_text(s_date_layer, date_text);
|
||||
} else {
|
||||
text_layer_set_text(s_date_layer, DUMMY_DATE_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_ampm_text_layer() {
|
||||
static char ampm_text[AMPM_TEXT_SIZE];
|
||||
|
||||
if (clock_is_24h_style()) {
|
||||
text_layer_set_text(s_ampm_layer, DUMMY_AMPM_TEXT);
|
||||
} else {
|
||||
size_t result = strftime(ampm_text, AMPM_TEXT_SIZE, "%p", t);
|
||||
if (result != 0) {
|
||||
text_layer_set_text(s_ampm_layer, ampm_text);
|
||||
} else {
|
||||
text_layer_set_text(s_ampm_layer, DUMMY_AMPM_TEXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tick_handler(struct tm *tick_time, TimeUnits changed_units) {
|
||||
// Getting the current time.
|
||||
time_t now = time(NULL);
|
||||
t = localtime(&now);
|
||||
|
||||
// Updating views.
|
||||
layer_mark_dirty(s_hands_layer);
|
||||
update_date_text_layer();
|
||||
update_ampm_text_layer();
|
||||
}
|
||||
|
||||
static void s_hands_layer_update(Layer *layer, GContext *ctx) {
|
||||
GRect bounds = layer_get_bounds(layer);
|
||||
GPoint center = grect_center_point(&bounds);
|
||||
|
||||
// Drawing the minute hand.
|
||||
graphics_context_set_fill_color(ctx, GColorBlack);
|
||||
graphics_context_set_stroke_color(ctx, GColorBlack);
|
||||
gpath_move_to(s_minute_hand, (GPoint){39.5, 39});
|
||||
gpath_rotate_to(s_minute_hand, TRIG_MAX_ANGLE * t->tm_min / 60);
|
||||
gpath_draw_outline(ctx, s_minute_hand);
|
||||
gpath_draw_filled(ctx, s_minute_hand);
|
||||
|
||||
// Drawing the hour hand.
|
||||
graphics_context_set_fill_color(ctx, GColorBlack);
|
||||
graphics_context_set_stroke_color(ctx, GColorBlack);
|
||||
gpath_move_to(s_hour_hand, (GPoint){39.5, 39});
|
||||
gpath_rotate_to(s_hour_hand, (TRIG_MAX_ANGLE * (((t->tm_hour % 12) * 6) + (t->tm_min / 10))) / (12 * 6));
|
||||
gpath_draw_outline(ctx, s_hour_hand);
|
||||
gpath_draw_filled(ctx, s_hour_hand);
|
||||
|
||||
// Drawing the second hand.
|
||||
if (hide_seconds_hand == false) {
|
||||
graphics_context_set_antialiased(ctx, false);
|
||||
int32_t second_angle = TRIG_MAX_ANGLE * t->tm_sec / 60;
|
||||
int16_t second_hand_length = (bounds.size.w / 2) - 1;
|
||||
GPoint second_hand = {
|
||||
.x = (int16_t)(sin_lookup(second_angle) * (int32_t)second_hand_length / TRIG_MAX_RATIO) + center.x,
|
||||
.y = (int16_t)(-cos_lookup(second_angle) * (int32_t)second_hand_length / TRIG_MAX_RATIO) + center.y,
|
||||
};
|
||||
|
||||
graphics_context_set_stroke_color(ctx, GColorPictonBlue);
|
||||
graphics_draw_line(ctx, second_hand, center);
|
||||
graphics_context_set_antialiased(ctx, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void s_battery_indicator_layer_update(Layer *layer, GContext *ctx) {
|
||||
GRect bounds = layer_get_bounds(layer);
|
||||
|
||||
graphics_context_set_fill_color(ctx, GColorGreen);
|
||||
if (battery_charge <= 10) {
|
||||
graphics_context_set_fill_color(ctx, GColorRed);
|
||||
} else if (battery_charge <= 60) {
|
||||
graphics_context_set_fill_color(ctx, GColorYellow);
|
||||
}
|
||||
|
||||
graphics_fill_rect(ctx, bounds, 0, GCornerNone);
|
||||
}
|
||||
|
||||
static void battery_state_handler(BatteryChargeState charge) {
|
||||
if (charge.charge_percent != battery_charge) {
|
||||
battery_charge = charge.charge_percent;
|
||||
layer_mark_dirty(s_battery_indicator_layer);
|
||||
}
|
||||
}
|
||||
|
||||
static void start_time_tracking() {
|
||||
TimeUnits unit = MINUTE_UNIT;
|
||||
|
||||
if (hide_seconds_hand == false) {
|
||||
unit = SECOND_UNIT;
|
||||
}
|
||||
|
||||
tick_handler(NULL, unit);
|
||||
tick_timer_service_subscribe(unit, tick_handler);
|
||||
}
|
||||
|
||||
static void start_battery_tracking() {
|
||||
if (hide_battery_indicator == false) {
|
||||
BatteryChargeState charge = battery_state_service_peek();
|
||||
battery_state_handler(charge);
|
||||
battery_state_service_subscribe(battery_state_handler);
|
||||
} else {
|
||||
battery_state_service_unsubscribe();
|
||||
}
|
||||
|
||||
layer_set_hidden(bitmap_layer_get_layer(s_battery_icon_layer), hide_battery_indicator);
|
||||
layer_set_hidden(s_battery_indicator_layer, hide_battery_indicator);
|
||||
}
|
||||
|
||||
static void inbox_received_handler(DictionaryIterator *iter, void *context) {
|
||||
// Handling seconds_hand setting.
|
||||
Tuple *seconds_hand_t = dict_find(iter, KEY_SECONDS_HAND);
|
||||
if (seconds_hand_t && seconds_hand_t->value->int32 > 0) {
|
||||
hide_seconds_hand = false;
|
||||
} else {
|
||||
hide_seconds_hand = true;
|
||||
}
|
||||
|
||||
persist_write_bool(KEY_SECONDS_HAND, hide_seconds_hand);
|
||||
start_time_tracking();
|
||||
|
||||
// Handling battery_indicator setting.
|
||||
Tuple *battery_indicator_t = dict_find(iter, KEY_BATTERY_INDICATOR);
|
||||
if (battery_indicator_t && battery_indicator_t->value->int32 > 0) {
|
||||
hide_battery_indicator = false;
|
||||
} else {
|
||||
hide_battery_indicator = true;
|
||||
}
|
||||
|
||||
persist_write_bool(KEY_BATTERY_INDICATOR, hide_battery_indicator);
|
||||
start_battery_tracking();
|
||||
|
||||
// Handling date_format setting.
|
||||
Tuple *date_format_t = dict_find(iter, KEY_DATE_FORMAT);
|
||||
if (date_format_t) {
|
||||
strcpy(date_format, date_format_t->value->cstring);
|
||||
}
|
||||
|
||||
persist_write_string(KEY_DATE_FORMAT, date_format);
|
||||
update_date_text_layer();
|
||||
}
|
||||
|
||||
static void main_window_load(Window *window) {
|
||||
// Loading resources.
|
||||
s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_IMG_BACKGROUND);
|
||||
s_battery_bitmap = gbitmap_create_with_resource(RESOURCE_ID_IMG_BATTERY);
|
||||
s_text_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_TOPAZ_16));
|
||||
|
||||
// Creating hand paths.
|
||||
s_minute_hand = gpath_create(&MINUTE_HAND_POINTS);
|
||||
s_hour_hand = gpath_create(&HOUR_HAND_POINTS);
|
||||
|
||||
Layer *window_layer = window_get_root_layer(window);
|
||||
GRect bounds = layer_get_bounds(window_layer);
|
||||
|
||||
// Creating background image layer.
|
||||
s_background_layer = bitmap_layer_create(bounds);
|
||||
bitmap_layer_set_bitmap(s_background_layer, s_background_bitmap);
|
||||
bitmap_layer_set_compositing_mode(s_background_layer, GCompOpSet);
|
||||
layer_add_child(window_layer, bitmap_layer_get_layer(s_background_layer));
|
||||
|
||||
// Creating title text layer.
|
||||
s_title_layer = text_layer_create(GRect(36, 2, 46, 18));
|
||||
text_layer_set_background_color(s_title_layer, GColorClear);
|
||||
text_layer_set_text(s_title_layer, "Clock");
|
||||
text_layer_set_font(s_title_layer, s_text_font);
|
||||
layer_add_child(window_layer, text_layer_get_layer(s_title_layer));
|
||||
|
||||
// Creating hands layer.
|
||||
s_hands_layer = layer_create(GRect(32, 38, 78, 78));
|
||||
layer_set_update_proc(s_hands_layer, s_hands_layer_update);
|
||||
layer_add_child(window_layer, s_hands_layer);
|
||||
|
||||
// Creating date layer.
|
||||
s_date_layer = text_layer_create(GRect(17, 130, 109, 16));
|
||||
text_layer_set_text_alignment(s_date_layer, GTextAlignmentCenter);
|
||||
text_layer_set_background_color(s_date_layer, GColorClear);
|
||||
text_layer_set_font(s_date_layer, s_text_font);
|
||||
layer_add_child(window_layer, text_layer_get_layer(s_date_layer));
|
||||
|
||||
// Creating AM/PM layer.
|
||||
s_ampm_layer = text_layer_create(GRect(107, 26, 16, 16));
|
||||
text_layer_set_text_alignment(s_ampm_layer, GTextAlignmentCenter);
|
||||
text_layer_set_background_color(s_ampm_layer, GColorClear);
|
||||
text_layer_set_text_color(s_ampm_layer, GColorWhite);
|
||||
text_layer_set_font(s_ampm_layer, s_text_font);
|
||||
layer_add_child(window_layer, text_layer_get_layer(s_ampm_layer));
|
||||
|
||||
// Creating battery icon layer.
|
||||
s_battery_icon_layer = bitmap_layer_create(GRect(20, 26, 16, 7));
|
||||
bitmap_layer_set_bitmap(s_battery_icon_layer, s_battery_bitmap);
|
||||
bitmap_layer_set_compositing_mode(s_battery_icon_layer, GCompOpSet);
|
||||
layer_add_child(window_layer, bitmap_layer_get_layer(s_battery_icon_layer));
|
||||
|
||||
// Creating battery indicator layer.
|
||||
s_battery_indicator_layer = layer_create(GRect(21, 27, 13, 5));
|
||||
layer_set_update_proc(s_battery_indicator_layer, s_battery_indicator_layer_update);
|
||||
layer_add_child(window_layer, s_battery_indicator_layer);
|
||||
|
||||
// Read date_format setting from persistent storage.
|
||||
int result = persist_read_string(KEY_DATE_FORMAT, date_format, 2);
|
||||
if (result == E_DOES_NOT_EXIST) {
|
||||
strcpy(date_format, "t");
|
||||
}
|
||||
|
||||
// Starting time tracking.
|
||||
hide_seconds_hand = persist_read_bool(KEY_SECONDS_HAND);
|
||||
start_time_tracking();
|
||||
|
||||
// Starting battery tracking.
|
||||
hide_battery_indicator = persist_read_bool(KEY_BATTERY_INDICATOR);
|
||||
start_battery_tracking();
|
||||
}
|
||||
|
||||
static void main_window_unload(Window *window) {
|
||||
battery_state_service_unsubscribe();
|
||||
tick_timer_service_unsubscribe();
|
||||
|
||||
if (t) {
|
||||
free(t);
|
||||
}
|
||||
|
||||
layer_destroy(s_battery_indicator_layer);
|
||||
bitmap_layer_destroy(s_battery_icon_layer);
|
||||
text_layer_destroy(s_ampm_layer);
|
||||
text_layer_destroy(s_date_layer);
|
||||
layer_destroy(s_hands_layer);
|
||||
text_layer_destroy(s_title_layer);
|
||||
bitmap_layer_destroy(s_background_layer);
|
||||
|
||||
gpath_destroy(s_hour_hand);
|
||||
gpath_destroy(s_minute_hand);
|
||||
|
||||
fonts_unload_custom_font(s_text_font);
|
||||
gbitmap_destroy(s_battery_bitmap);
|
||||
gbitmap_destroy(s_background_bitmap);
|
||||
}
|
||||
|
||||
static void init() {
|
||||
s_main_window = window_create();
|
||||
|
||||
window_set_window_handlers(s_main_window, (WindowHandlers) {
|
||||
.load = main_window_load,
|
||||
.unload = main_window_unload
|
||||
});
|
||||
|
||||
window_stack_push(s_main_window, true);
|
||||
|
||||
app_message_register_inbox_received(inbox_received_handler);
|
||||
app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum());
|
||||
}
|
||||
|
||||
static void deinit() {
|
||||
window_destroy(s_main_window);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
init();
|
||||
app_event_loop();
|
||||
deinit();
|
||||
}
|
44
src/js/pebble-js-app.js
Normal file
44
src/js/pebble-js-app.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Copyright (c) 2015 Tomek Wójcik <tomek@bthlabs.pl>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
Pebble.addEventListener('ready', function(e) {
|
||||
console.log('JS Ready!');
|
||||
});
|
||||
|
||||
Pebble.addEventListener('showConfiguration', function(e) {
|
||||
Pebble.openURL('https://pconf.bthlabs.pl/intuiclock/index.html');
|
||||
});
|
||||
|
||||
Pebble.addEventListener('webviewclosed', function(e) {
|
||||
var config_data = JSON.parse(decodeURIComponent(e.response));
|
||||
console.log('Configuration page returned: ' + JSON.stringify(config_data));
|
||||
|
||||
var dict = {};
|
||||
dict['KEY_SECONDS_HAND'] = config_data['seconds_hand'];
|
||||
dict['KEY_BATTERY_INDICATOR'] = config_data['battery_indicator'];
|
||||
dict['KEY_DATE_FORMAT'] = config_data['date_format'];
|
||||
|
||||
Pebble.sendAppMessage(dict, function() {
|
||||
console.log('Send successful!');
|
||||
}, function() {
|
||||
console.log('Send failed!');
|
||||
});
|
||||
});
|
41
wscript
Normal file
41
wscript
Normal file
|
@ -0,0 +1,41 @@
|
|||
|
||||
#
|
||||
# This file is the default set of rules to compile a Pebble project.
|
||||
#
|
||||
# Feel free to customize this to your needs.
|
||||
#
|
||||
|
||||
import os.path
|
||||
|
||||
top = '.'
|
||||
out = 'build'
|
||||
|
||||
def options(ctx):
|
||||
ctx.load('pebble_sdk')
|
||||
|
||||
def configure(ctx):
|
||||
ctx.load('pebble_sdk')
|
||||
|
||||
def build(ctx):
|
||||
ctx.load('pebble_sdk')
|
||||
|
||||
build_worker = os.path.exists('worker_src')
|
||||
binaries = []
|
||||
|
||||
for p in ctx.env.TARGET_PLATFORMS:
|
||||
ctx.set_env(ctx.all_envs[p])
|
||||
ctx.set_group(ctx.env.PLATFORM_NAME)
|
||||
app_elf='{}/pebble-app.elf'.format(ctx.env.BUILD_DIR)
|
||||
ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c'),
|
||||
target=app_elf)
|
||||
|
||||
if build_worker:
|
||||
worker_elf='{}/pebble-worker.elf'.format(ctx.env.BUILD_DIR)
|
||||
binaries.append({'platform': p, 'app_elf': app_elf, 'worker_elf': worker_elf})
|
||||
ctx.pbl_worker(source=ctx.path.ant_glob('worker_src/**/*.c'),
|
||||
target=worker_elf)
|
||||
else:
|
||||
binaries.append({'platform': p, 'app_elf': app_elf})
|
||||
|
||||
ctx.set_group('bundle')
|
||||
ctx.pbl_bundle(binaries=binaries, js=ctx.path.ant_glob('src/js/**/*.js'))
|
Loading…
Reference in New Issue
Block a user