mirror of https://github.com/nealey/TwatchFonts
Works on all three platforms
This commit is contained in:
parent
01033395eb
commit
a84417f1a7
|
@ -0,0 +1,121 @@
|
||||||
|
{
|
||||||
|
"appKeys": {
|
||||||
|
"align": 1,
|
||||||
|
"font": 2,
|
||||||
|
"theme": 0
|
||||||
|
},
|
||||||
|
"capabilities": [
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"companyName": "dartcatcher@gmail.com",
|
||||||
|
"longName": "Twatch Fonts",
|
||||||
|
"projectType": "native",
|
||||||
|
"resources": {
|
||||||
|
"media": [
|
||||||
|
{
|
||||||
|
"characterRegex": "[\uf10b]",
|
||||||
|
"file": "fonts/fontawesome.ttf",
|
||||||
|
"name": "FONT_SYMBOLS_52",
|
||||||
|
"targetPlatforms": null,
|
||||||
|
"type": "font"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"characterRegex": "[0-9:]",
|
||||||
|
"file": "fonts/Ubuntu-Bold.ttf",
|
||||||
|
"name": "FONT_UBUNTU_B_64",
|
||||||
|
"targetPlatforms": [
|
||||||
|
"chalk"
|
||||||
|
],
|
||||||
|
"type": "font"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"characterRegex": "[0-9:]",
|
||||||
|
"file": "fonts/Ubuntu-Bold.ttf",
|
||||||
|
"name": "FONT_UBUNTU_B_48",
|
||||||
|
"targetPlatforms": [
|
||||||
|
"aplite",
|
||||||
|
"basalt"
|
||||||
|
],
|
||||||
|
"type": "font"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"characterRegex": "[0-9A-Za-z\u00e9\u00f4 ]",
|
||||||
|
"file": "fonts/Ubuntu-Regular.ttf",
|
||||||
|
"name": "FONT_UBUNTU_R_28",
|
||||||
|
"targetPlatforms": null,
|
||||||
|
"type": "font"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"characterRegex": "[0-9A-Za-z\u00e9\u00f4 ]",
|
||||||
|
"file": "fonts/AveriaSerif-Regular.ttf",
|
||||||
|
"name": "FONT_AVERIA_R_28",
|
||||||
|
"targetPlatforms": null,
|
||||||
|
"type": "font"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"characterRegex": "[0-9:]",
|
||||||
|
"file": "fonts/AveriaSerif-Bold.ttf",
|
||||||
|
"name": "FONT_AVERIA_B_64",
|
||||||
|
"targetPlatforms": [
|
||||||
|
"chalk"
|
||||||
|
],
|
||||||
|
"type": "font"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"characterRegex": "[0-9:]",
|
||||||
|
"file": "fonts/AveriaSerif-Bold.ttf",
|
||||||
|
"name": "FONT_AVERIA_B_48",
|
||||||
|
"targetPlatforms": [
|
||||||
|
"aplite",
|
||||||
|
"basalt"
|
||||||
|
],
|
||||||
|
"type": "font"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "images/icon.png",
|
||||||
|
"menuIcon": true,
|
||||||
|
"name": "ICON",
|
||||||
|
"targetPlatforms": null,
|
||||||
|
"type": "bitmap"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"characterRegex": "[0-9A-Za-z\u00e9\u00f4 ]",
|
||||||
|
"file": "fonts/Helvetica-Regular.ttf",
|
||||||
|
"name": "FONT_HELVETICA_R_28",
|
||||||
|
"targetPlatforms": null,
|
||||||
|
"type": "font"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"characterRegex": "[0-9:]",
|
||||||
|
"file": "fonts/Helvetica-Bold.ttf",
|
||||||
|
"name": "FONT_HELVETICA_B_64",
|
||||||
|
"targetPlatforms": [
|
||||||
|
"chalk"
|
||||||
|
],
|
||||||
|
"type": "font"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"characterRegex": "[0-9:]",
|
||||||
|
"file": "fonts/Helvetica-Bold.ttf",
|
||||||
|
"name": "FONT_HELVETICA_B_48",
|
||||||
|
"targetPlatforms": [
|
||||||
|
"aplite",
|
||||||
|
"basalt"
|
||||||
|
],
|
||||||
|
"type": "font"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sdkVersion": "3",
|
||||||
|
"shortName": "Twatch Fonts",
|
||||||
|
"targetPlatforms": [
|
||||||
|
"aplite",
|
||||||
|
"basalt",
|
||||||
|
"chalk"
|
||||||
|
],
|
||||||
|
"uuid": "2dce4324-374b-4e5e-9b98-3275561118f3",
|
||||||
|
"versionLabel": "1.0",
|
||||||
|
"watchapp": {
|
||||||
|
"watchface": true
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 973 B |
|
@ -0,0 +1,162 @@
|
||||||
|
#include <pebble.h>
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
static Window *s_main_window;
|
||||||
|
static TextLayer *s_date_layer, *s_time_layer, *s_alert_layer;
|
||||||
|
bool bt_connected = false;
|
||||||
|
|
||||||
|
static void bt_handler(bool connected) {
|
||||||
|
bt_connected = connected;
|
||||||
|
if (! bt_connected) {
|
||||||
|
vibes_double_pulse();
|
||||||
|
}
|
||||||
|
layer_mark_dirty(text_layer_get_layer(s_alert_layer));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_minute_tick(struct tm *tick_time, TimeUnits units_changed) {
|
||||||
|
// Need to be static because they're used by the system later.
|
||||||
|
static char s_time_text[] = "00:00";
|
||||||
|
static char s_date_text[] = "00 Çêû";
|
||||||
|
|
||||||
|
// Bluetooth alert
|
||||||
|
if (bt_connected) {
|
||||||
|
text_layer_set_text(s_alert_layer, "");
|
||||||
|
} else {
|
||||||
|
text_layer_set_text(s_alert_layer, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date
|
||||||
|
strftime(s_date_text, sizeof(s_date_text), "%d %b", tick_time);
|
||||||
|
text_layer_set_text(s_date_layer, NOZERO(s_date_text));
|
||||||
|
|
||||||
|
// Time
|
||||||
|
if (clock_is_24h_style()) {
|
||||||
|
strftime(s_time_text, sizeof(s_time_text), "%R", tick_time);
|
||||||
|
} else {
|
||||||
|
strftime(s_time_text, sizeof(s_time_text), "%I:%M", tick_time);
|
||||||
|
}
|
||||||
|
text_layer_set_text(s_time_layer, NOZERO(s_time_text));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main_window_load(Window *window) {
|
||||||
|
Layer *window_layer = window_get_root_layer(window);
|
||||||
|
|
||||||
|
#ifdef PBL_RECT
|
||||||
|
s_date_layer = text_layer_create(GRect(8, 66, 128, 100));
|
||||||
|
s_time_layer = text_layer_create(GRect(7, 92, 130, 76));
|
||||||
|
s_alert_layer = text_layer_create(GRect(110, 7, 52, 52));
|
||||||
|
text_layer_set_text_alignment(s_date_layer, GTextAlignmentLeft);
|
||||||
|
text_layer_set_text_alignment(s_time_layer, GTextAlignmentLeft);
|
||||||
|
#else
|
||||||
|
s_date_layer = text_layer_create(GRect(0, 20, 180, 100));
|
||||||
|
s_time_layer = text_layer_create(GRect(0, 48, 180, 76));
|
||||||
|
s_alert_layer = text_layer_create(GRect(0, 120, 180, 52));
|
||||||
|
text_layer_set_text_alignment(s_date_layer, GTextAlignmentCenter);
|
||||||
|
text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);
|
||||||
|
text_layer_set_text_alignment(s_alert_layer, GTextAlignmentCenter);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
text_layer_set_background_color(s_date_layer, GColorClear);
|
||||||
|
layer_add_child(window_layer, text_layer_get_layer(s_date_layer));
|
||||||
|
|
||||||
|
text_layer_set_background_color(s_time_layer, GColorClear);
|
||||||
|
layer_add_child(window_layer, text_layer_get_layer(s_time_layer));
|
||||||
|
|
||||||
|
text_layer_set_background_color(s_alert_layer, GColorClear);
|
||||||
|
text_layer_set_font(s_alert_layer, fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_SYMBOLS_52)));
|
||||||
|
layer_add_child(window_layer, text_layer_get_layer(s_alert_layer));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restore() {
|
||||||
|
int sel_theme = 0;
|
||||||
|
int sel_font = 0;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < KEY_LAST; i += 1) {
|
||||||
|
if (! persist_exists(i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (i) {
|
||||||
|
case KEY_THEME:
|
||||||
|
sel_theme = persist_read_int(i);
|
||||||
|
break;
|
||||||
|
case KEY_FONT:
|
||||||
|
sel_font = persist_read_int(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window_set_background_color(s_main_window, *themes[sel_theme][0]);
|
||||||
|
text_layer_set_text_color(s_date_layer, *themes[sel_theme][1]);
|
||||||
|
text_layer_set_text_color(s_time_layer, *themes[sel_theme][2]);
|
||||||
|
text_layer_set_text_color(s_alert_layer, *themes[sel_theme][2]);
|
||||||
|
|
||||||
|
text_layer_set_font(s_date_layer, fonts_load_custom_font(resource_get_handle(fonts[sel_font][0])));
|
||||||
|
text_layer_set_font(s_time_layer, fonts_load_custom_font(resource_get_handle(fonts[sel_font][1])));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void in_received_handler(DictionaryIterator *rec, void *context) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < KEY_LAST; i += 1) {
|
||||||
|
Tuple *cur = dict_find(rec, i);
|
||||||
|
|
||||||
|
if (! cur) {
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "Holy crap! Key %i isn't around!", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
persist_write_int(i, cur->value->int32);
|
||||||
|
}
|
||||||
|
|
||||||
|
restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void in_dropped_handler(AppMessageResult reason, void *context) {
|
||||||
|
// XXX: I don't understand what we could possibly do here
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main_window_unload(Window *window) {
|
||||||
|
text_layer_destroy(s_date_layer);
|
||||||
|
text_layer_destroy(s_time_layer);
|
||||||
|
text_layer_destroy(s_alert_layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
tick_timer_service_subscribe(MINUTE_UNIT, handle_minute_tick);
|
||||||
|
bluetooth_connection_service_subscribe(bt_handler);
|
||||||
|
bt_connected = bluetooth_connection_service_peek();
|
||||||
|
|
||||||
|
app_message_register_inbox_received(in_received_handler);
|
||||||
|
app_message_register_inbox_dropped(in_dropped_handler);
|
||||||
|
app_message_open(256, 64);
|
||||||
|
|
||||||
|
// Prevent starting blank
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm *t = localtime(&now);
|
||||||
|
handle_minute_tick(t, MINUTE_UNIT);
|
||||||
|
|
||||||
|
setlocale(LC_ALL, "");
|
||||||
|
|
||||||
|
restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deinit() {
|
||||||
|
window_destroy(s_main_window);
|
||||||
|
|
||||||
|
tick_timer_service_unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
init();
|
||||||
|
app_event_loop();
|
||||||
|
deinit();
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
var initialized = false;
|
||||||
|
|
||||||
|
function appMessageAck(e) {
|
||||||
|
console.log("Configuration sent");
|
||||||
|
}
|
||||||
|
|
||||||
|
function appMessageNak(e) {
|
||||||
|
console.log("Configuration not sent: ", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pebble.addEventListener("ready", function() {
|
||||||
|
console.log("ready called!");
|
||||||
|
initialized = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
Pebble.addEventListener("showConfiguration", function() {
|
||||||
|
console.log("showing configuration");
|
||||||
|
Pebble.openURL('http://woozle.org/neale/misc/twatch-config/fonts.html');
|
||||||
|
});
|
||||||
|
|
||||||
|
var themes = {"Dark": 0,
|
||||||
|
"Light": 1,
|
||||||
|
"Green": 2};
|
||||||
|
var aligns = {"Left": 0,
|
||||||
|
"Center": 1,
|
||||||
|
"Right": 2};
|
||||||
|
var fonts = {"Helvetica": 0,
|
||||||
|
"Avería": 1,
|
||||||
|
"Ubuntu": 2};
|
||||||
|
|
||||||
|
Pebble.addEventListener("webviewclosed", function(e) {
|
||||||
|
console.log("configuration closed");
|
||||||
|
// webview closed
|
||||||
|
var options = JSON.parse(decodeURIComponent(e.response));
|
||||||
|
options.theme = themes[options.theme];
|
||||||
|
options.align = aligns[options.align];
|
||||||
|
options.font = fonts[options.font];
|
||||||
|
console.log("Options = " + options.theme + options.align + options.font);
|
||||||
|
Pebble.sendAppMessage(options, appMessageAck, appMessageNak);
|
||||||
|
});
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include <pebble.h>
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define NOZERO(s) ((*s == '0')?(s+1):s)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
KEY_THEME = 0,
|
||||||
|
KEY_ALIGN,
|
||||||
|
KEY_FONT,
|
||||||
|
KEY_LAST
|
||||||
|
} MessageKey;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
THEME_DARK = 0,
|
||||||
|
THEME_LIGHT,
|
||||||
|
THEME_GREEN,
|
||||||
|
THEME_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ALIGN_LEFT = 0,
|
||||||
|
ALIGN_CENTER,
|
||||||
|
ALIGN_RIGHT,
|
||||||
|
ALIGN_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FONT_HELVETICA = 0,
|
||||||
|
FONT_AVERIA,
|
||||||
|
FONT_UBUNTU,
|
||||||
|
FONT_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
GColor8 *themes[THEME_LAST][3] = {
|
||||||
|
{&GColorBlack, &GColorWhite, &GColorWhite},
|
||||||
|
{&GColorWhite, &GColorBlack, &GColorBlack},
|
||||||
|
{&GColorDarkGreen, &GColorWhite, &GColorWhite}
|
||||||
|
};
|
||||||
|
|
||||||
|
GTextAlignment aligns[ALIGN_LAST] = {
|
||||||
|
GTextAlignmentLeft,
|
||||||
|
GTextAlignmentCenter,
|
||||||
|
GTextAlignmentRight
|
||||||
|
};
|
||||||
|
|
||||||
|
const int fonts[FONT_LAST][2] = {
|
||||||
|
#ifdef PBL_RECT
|
||||||
|
{RESOURCE_ID_FONT_HELVETICA_R_28, RESOURCE_ID_FONT_HELVETICA_B_48},
|
||||||
|
{RESOURCE_ID_FONT_AVERIA_R_28, RESOURCE_ID_FONT_AVERIA_B_48},
|
||||||
|
{RESOURCE_ID_FONT_UBUNTU_R_28, RESOURCE_ID_FONT_UBUNTU_B_48}
|
||||||
|
#else
|
||||||
|
{RESOURCE_ID_FONT_HELVETICA_R_28, RESOURCE_ID_FONT_HELVETICA_B_64},
|
||||||
|
{RESOURCE_ID_FONT_AVERIA_R_28, RESOURCE_ID_FONT_AVERIA_B_64},
|
||||||
|
{RESOURCE_ID_FONT_UBUNTU_R_28, RESOURCE_ID_FONT_UBUNTU_B_64}
|
||||||
|
#endif
|
||||||
|
};
|
|
@ -0,0 +1,62 @@
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file is the default set of rules to compile a Pebble project.
|
||||||
|
#
|
||||||
|
# Feel free to customize this to your needs.
|
||||||
|
#
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
try:
|
||||||
|
from sh import CommandNotFound, jshint, cat, ErrorReturnCode_2
|
||||||
|
hint = jshint
|
||||||
|
except (ImportError, CommandNotFound):
|
||||||
|
hint = None
|
||||||
|
|
||||||
|
top = '.'
|
||||||
|
out = 'build'
|
||||||
|
|
||||||
|
def options(ctx):
|
||||||
|
ctx.load('pebble_sdk')
|
||||||
|
|
||||||
|
def configure(ctx):
|
||||||
|
ctx.load('pebble_sdk')
|
||||||
|
|
||||||
|
def build(ctx):
|
||||||
|
if False and hint is not None:
|
||||||
|
try:
|
||||||
|
hint([node.abspath() for node in ctx.path.ant_glob("src/**/*.js")], _tty_out=False) # no tty because there are none in the cloudpebble sandbox.
|
||||||
|
except ErrorReturnCode_2 as e:
|
||||||
|
ctx.fatal("\nJavaScript linting failed (you can disable this in Project Settings):\n" + e.stdout)
|
||||||
|
|
||||||
|
# Concatenate all our JS files (but not recursively), and only if any JS exists in the first place.
|
||||||
|
ctx.path.make_node('src/js/').mkdir()
|
||||||
|
js_paths = ctx.path.ant_glob(['src/*.js', 'src/**/*.js'])
|
||||||
|
if js_paths:
|
||||||
|
ctx(rule='cat ${SRC} > ${TGT}', source=js_paths, target='pebble-js-app.js')
|
||||||
|
has_js = True
|
||||||
|
else:
|
||||||
|
has_js = False
|
||||||
|
|
||||||
|
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(p)
|
||||||
|
ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c'),
|
||||||
|
target=app_elf)
|
||||||
|
|
||||||
|
if build_worker:
|
||||||
|
worker_elf='{}/pebble-worker.elf'.format(p)
|
||||||
|
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='pebble-js-app.js' if has_js else [])
|
||||||
|
|
Loading…
Reference in New Issue