diff --git a/apps/cogclock/ChangeLog b/apps/cogclock/ChangeLog new file mode 100644 index 000000000..3158b6116 --- /dev/null +++ b/apps/cogclock/ChangeLog @@ -0,0 +1,2 @@ +0.01: New clock +0.02: Use ClockFace library, add settings diff --git a/apps/cogclock/app.js b/apps/cogclock/app.js index c186cd881..d24031684 100644 --- a/apps/cogclock/app.js +++ b/apps/cogclock/app.js @@ -4,18 +4,6 @@ Graphics.prototype.setFont15x32N = function() { "/////oAAAAKAAAACgAAAAoAAAAKAAAACgf//AoEAAQKB//8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+/wAB/oEAAQKBAAECgf//AoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAAC////AgAAAQIAAAH+/w///oEIAAKBCAACgQgAAoEIAAKBCAACgQg/AoEIIQKB+CECgAAhAoAAIQKAACECgAAhAoAAIQL//+H+/w/h/oEIIQKBCCECgQghAoEIIQKBCCECgQghAoEIIQKB+D8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+///gAIAAIACAACAAgAAgAIAAIAD/+CAAAAggAAAIIAAACD/+//gAAoAAAAKAAAACgAAAAoAAAAL////+///h/oAAIQKAACECgAAhAoAAIQKAACECgfghAoEIIQKBCD8CgQgAAoEIAAKBCAACgQgAAoEIAAL/D//+/////oAAAAKAAAACgAAAAoAAAAKAAAACgfg/AoEIIQKBCD8CgQgAAoEIAAKBCAACgQgAAoEIAAL/D//+/wAAAIEAAACBAAAAgQAAAIEAAACBAAAAgQAAAIH///6AAAACgAAAAoAAAAKAAAACgAAAAoAAAAL////+/////oAAAAKAAAACgAAAAoAAAAKAAAACgfg/AoEIIQKB+D8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+///h/oAAIQKAACECgAAhAoAAIQKAACECgfghAoEIIQKB+D8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+" ), "0".charCodeAt(0), 15, 32); }; -const SHOW_DATE = false; // TODO: make into setting? -Bangle.setUI("clock"); // set UI first, so widgets know about Bangle.CLOCK -Bangle.loadWidgets(); // load widgets, so Bangle.appRect knows about them - -const r1 = 84, // inner radius - r3 = Math.min(Bangle.appRect.w/2, Bangle.appRect.h/2), // outer radius - r2 = (r1*3+r3*2)/5, - teeth = 12, - edge = 0.45, point = 0.35; // as fraction of arc - -const x = Bangle.appRect.x+Bangle.appRect.w/2, - y = Bangle.appRect.y+Bangle.appRect.h/2; /** * Add coordinates for nth tooth to vertices @@ -24,9 +12,11 @@ const x = Bangle.appRect.x+Bangle.appRect.w/2, */ function addTooth(poly, n) { const - tau = Math.PI*2, arc = tau/teeth, - e = arc*edge, p = arc*point, s = (arc-(e+p))/2; // edge,point,slopes - const sin = Math.sin, cos = Math.cos; + tau = Math.PI*2, arc = tau/clock.teeth, + e = arc*clock.edge, p = arc*clock.point, s = (arc-(e+p))/2; // edge,point,slopes + const sin = Math.sin, cos = Math.cos, + x = clock.x, y = clock.y, + r2 = clock.r2, r3 = clock.r3; let r = (n-1)*arc+e/2; // rads poly.push(x+r2*sin(r), y-r2*cos(r)); r += s; @@ -37,18 +27,6 @@ function addTooth(poly, n) { poly.push(x+r2*sin(r), y-r2*cos(r)); } -function drawCog() { - g.reset(); - g.setColor(g.theme.bg2).fillCircle(x, y, r2) // fill cog - .setColor(g.theme.bg).fillCircle(x, y, r1) // clear center - .setColor(g.theme.fg2).drawCircle(x, y, r1); // draw inner border - let poly = []; // complete teeth outline - for(let t = 1; t<=teeth; t++) { - fillTooth(t, g.theme.bg2); - addTooth(poly, t); - } - g.drawPoly(poly, true); // draw outer border -} /** * @param {number} n Tooth number to fill (1-based) * @param col Fill color @@ -61,62 +39,73 @@ function fillTooth(n, col) { .setColor(g.theme.fg2).drawPoly(poly); // fillPoly colored over the outline } -let last = {tooth: 0}, timeOut; -function draw() { - if (!Bangle.isLCDOn()) return; // no drawing, also no new update scheduled - g.reset(); - const pad2 = num => (num<10 ? "0" : "")+num, - d = new Date(), - year = d.getFullYear(), - date = pad2(d.getDate())+pad2(d.getMonth()), - time = pad2(d.getHours())+pad2(d.getMinutes()), - tooth = Math.round(d.getSeconds()/60*teeth), - m = d.getMilliseconds(); - if (time!==last.time) { - g.setFont("15x32N:2").setFontAlign(0, 0) // center middle - .drawString(time, x, y, true); - } - if (SHOW_DATE) { - if (year!==last.year) { - g.setFont("15x32N").setFontAlign(0, -1) // center top - .drawString(year, x, y+32, true); +const ClockFace = require("ClockFace"); +const clock = new ClockFace({ + precision: 1, + settingsFile: "cogclock.settings.json", + init: function() { + this.r1 = 84; // inner radius + this.r3 = Math.min(Bangle.appRect.w/2, Bangle.appRect.h/2); // outer radius + this.r2 = (this.r1*3+this.r3*2)/5; + this.teeth = 12; + this.edge = 0.45; + this.point = 0.35; // as fraction of arc + this.x = Bangle.appRect.x+Bangle.appRect.w/2; + this.y = Bangle.appRect.y+Bangle.appRect.h/2; + }, + draw: function(d) { + const x = this.x, y = this.y; + g.setColor(g.theme.bg2).fillCircle(x, y, this.r2) // fill cog + .setColor(g.theme.bg).fillCircle(x, y, this.r1) // clear center + .setColor(g.theme.fg2).drawCircle(x, y, this.r1); // draw inner border + let poly = []; // complete teeth outline + for(let t = 1; t<=this.teeth; t++) { + fillTooth(t, g.theme.bg2); + addTooth(poly, t); } - if (date!==last.date) { - g.setFont("15x32N").setFontAlign(0, 1) // center bottom - .drawString(date, x, y-32, true); + g.drawPoly(poly, true); // draw outer border + if (!this.showDate) { + // draw top/bottom rectangles (instead of year/date) + g.reset() + .fillRect(x-30, y-60, x+29, y-33).clearRect(x-28, y-58, x+27, y-33) + .fillRect(x-30, y+60, x+29, y+30).clearRect(x-28, y+58, x+27, y+30); } - } else if (time!==last.time) { - g.fillRect(x-30, y-60, x+29, y-33).clearRect(x-28, y-58, x+27, y-33); - g.fillRect(x-30, y+60, x+29, y+30).clearRect(x-28, y+58, x+27, y+30); - } - if (tooth!==last.tooth) { - if (tooth>last.tooth) { - for(let t = last.tooth; t<=tooth; t++) { // fill missing teeth - fillTooth(t, g.theme.fg2); - } - } else { - for(let t = last.tooth; t>tooth; t--) { // erase extraneous teeth - fillTooth(t, g.theme.bg2); + this.tooth = 0; + this.update(d, {s: 1, m: 1, h: 1, d: 1}); + }, + update: function(d, c) { + g.reset(); + const pad2 = num => (num<10 ? "0" : "")+num, + year = d.getFullYear(), + date = pad2(d.getDate())+pad2(d.getMonth()), + time = pad2(d.getHours())+pad2(d.getMinutes()), + tooth = Math.round(d.getSeconds()/60*this.teeth); + const x = this.x, y = this.y; + if (c.m) { + g.setFont("15x32N:2").setFontAlign(0, 0) // center middle + .drawString(time, x, y, true); + } + if (this.showDate) { + if (c.d) { + g.setFont("15x32N").setFontAlign(0, -1) // center top + .drawString(year, x, y+32, true) + .setFont("15x32N").setFontAlign(0, 1) // center bottom + .drawString(date, x, y-32, true); } } - } - last = { - year: year, - date: date, - time: time, - tooth: tooth, - }; - timeOut = setTimeout(draw, 1000-m); -} -g.clear(); -Bangle.drawWidgets(); -Bangle.on("lcdPower", on => { - if (timeOut) { - clearTimeout(timeOut); - timeOut = undefined; + if (tooth!==this.tooth) { + if (tooth>this.tooth) { + for(let t = this.tooth; t<=tooth; t++) { // fill missing teeth + fillTooth(t, g.theme.fg2); + } + } else { + for(let t = this.tooth; t>tooth; t--) { // erase extraneous teeth + fillTooth(t, g.theme.bg2); + } + } + } + this.tooth = tooth; } - if (on) draw(); }); -drawCog(); -draw(); +clock.start(); diff --git a/apps/cogclock/metadata.json b/apps/cogclock/metadata.json index ab47c43a1..40733bcd1 100644 --- a/apps/cogclock/metadata.json +++ b/apps/cogclock/metadata.json @@ -1,8 +1,8 @@ { "id": "cogclock", "name": "Cog Clock", - "version": "0.01", - "description": "A clock inside a cog", + "version": "0.02", + "description": "A cross-shaped clock inside a cog", "icon": "icon.png", "screenshots": [{"url":"screenshot.png"}], "type": "clock", @@ -11,6 +11,10 @@ "allow_emulator": true, "storage": [ {"name":"cogclock.app.js","url":"app.js"}, + {"name":"cogclock.settings.js","url":"settings.js"}, {"name":"cogclock.img","url":"icon.js","evaluate":true} + ], + "data": [ + {"name": "cogclock.settings.json"} ] } diff --git a/apps/cogclock/settings.js b/apps/cogclock/settings.js new file mode 100644 index 000000000..4eadc32c2 --- /dev/null +++ b/apps/cogclock/settings.js @@ -0,0 +1,19 @@ +(function(back) { + let s = require('Storage').readJSON("cogclock.settings.json", true) || {}; + + function saver(key) { + return value => { + s[key] = value; + require('Storage').writeJSON("cogclock.settings.json", s); + } + } + + const menu = { + "": {"title": /*LANG*/"Cog Clock"}, + /*LANG*/"< Back": back, + /*LANG*/"Show date": require("ClockFace_menu").showDate(s.showDate, saver('showDate')), + /*LANG*/"Load widgets": require("ClockFace_menu").loadWidgets(s.loadWidgets, saver('loadWidgets')), + }; + + E.showMenu(menu); +});