diff --git a/apps/cogclock/app.js b/apps/cogclock/app.js new file mode 100644 index 000000000..ba423fec1 --- /dev/null +++ b/apps/cogclock/app.js @@ -0,0 +1,111 @@ +Graphics.prototype.setFont16x32N = function() { + this.setFontCustom(atob( + "/////v////7////+4AAADuAAAA7gAAAO4AAADuAAAA7gAAAO4AAADuAAAA7gAAAO/////v////7////+AAAAAOAAAA7gAAAO4AAADuAAAA7gAAAO4AAADv////7////+/////gAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAADgA//+4AP//uAD//7gA4AO4AOADuADgA7gA4AO4AOADuADgA7gA4AO4AOADuADgA7//4AO//+ADv//gA4AAAAA4AOADuADgA7gA4AO4AOADuADgA7gA4AO4AOADuADgA7gA4AO4AOADuADgA7gA4AO/////v////7////+AAAAAP//gAD//4AA//+AAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAP////7////+/////gAAAAD//4AO//+ADv//gA7gA4AO4AOADuADgA7gA4AO4AOADuADgA7gA4AO4AOADuADgA7gA//+4AP//uAD//4AAAAA/////v////7////+4AOADuADgA7gA4AO4AOADuADgA7gA4AO4AOADuADgA7gA4AO4AP//uAD//7gA//+AAAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAP////7////+/////gAAAAD////+/////v////7gA4AO4AOADuADgA7gA4AO4AOADuADgA7gA4AO4AOADuADgA7////+/////v////4AAAAA//+ADv//gA7//4AO4AOADuADgA7gA4AO4AOADuADgA7gA4AO4AOADuADgA7gA4AO/////v////7////+AAAAAA==" + ), "0".charCodeAt(0), 16, 32); +}; + +Bangle.loadWidgets(); +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 + * @param {array} poly Array to add points to + * @param {number} n Tooth number + */ +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; + let r = (n-1)*arc+e/2; // rads + poly.push(x+r2*sin(r), y-r2*cos(r)); + r += s; + poly.push(x+r3*sin(r), y-r3*cos(r)); + r += p; + poly.push(x+r3*sin(r), y-r3*cos(r)); + r += s; + poly.push(x+r2*sin(r), y-r2*cos(r)); +} + +function drawCog() { + g.drawCircle(x, y, r1); + let poly = []; + for(let t = 1; t<=teeth; t++) { + addTooth(poly, t); + } + g.drawPoly(poly, true); +} +/** + * @param {number} n Tooth number to fill (1-based) + * @param col Fill color + */ +function fillTooth(n, col) { + if (!n) return; // easiest to check here + let poly = []; + addTooth(poly, n); + g.setColor(col).fillPoly(poly) + .setColor(g.theme.fg).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 (year!==last.year) { + g.setFont("16x32N").setFontAlign(0, -1) // center top + .drawString(year, x, y+34, true); + } + if (date!==last.date) { + g.setFont("16x32N").setFontAlign(0, 1) // center bottom + .drawString(date, x, y-34, true); + } + if (time!==last.time) { + g.setFont("16x32N:2").setFontAlign(0, 0) // center middle + .drawString(time, x, y, true); + } + 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.bg); + } + } + } + + last = { + year: year, + date: date, + time: time, + tooth: tooth, + }; + timeOut = setTimeout(draw, 1000-m); +} +g.clear(); +Bangle.drawWidgets(); +Bangle.setUI("clock"); +Bangle.on("lcdPower", on => { + if (timeOut) { + clearTimeout(timeOut); + timeOut = undefined; + } + if (on) draw(); +}); +drawCog(); +draw(); diff --git a/apps/cogclock/icon.js b/apps/cogclock/icon.js new file mode 100644 index 000000000..899cfc7c1 --- /dev/null +++ b/apps/cogclock/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/ACcikQXpCQUCC4MgBAgqMCQIXEAgQXNBwIDCAggXOABAXLHwQAHMYQXmmczI5oiCBwUjCwIABmQXDEgJ0KCwMwCwMDDAgyGLYoWBgAXBgAYBMZIXEkYWBC4YYBGAh7FFwgHCC4YEBPRIwCFwYXFGAaqHC56oIIwgXFJAbUJLwpgHI4qPDIwpIFR4wWDLwa6BAAQHDVIYYCC/gYCC453MPIR3HU5gADd5bXHC4rvJMAYAECwJeCd5MjGAjVDC4ZHGNARIFGAgNDFw5IJUogwFC4gwBDAhGBBghIFBQhhBbYguEPAweCDAgACCwZACNg5LFXQYsIC5QAFdg4XcCxJHNBwYTEC6A+BJYQEEC5YYBMYhbCCxo0GCaIXbAHgA=")) \ No newline at end of file diff --git a/apps/cogclock/icon.png b/apps/cogclock/icon.png new file mode 100644 index 000000000..8520fcf5d Binary files /dev/null and b/apps/cogclock/icon.png differ diff --git a/apps/cogclock/metadata.json b/apps/cogclock/metadata.json new file mode 100644 index 000000000..ab47c43a1 --- /dev/null +++ b/apps/cogclock/metadata.json @@ -0,0 +1,16 @@ +{ + "id": "cogclock", + "name": "Cog Clock", + "version": "0.01", + "description": "A clock inside a cog", + "icon": "icon.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS"], + "allow_emulator": true, + "storage": [ + {"name":"cogclock.app.js","url":"app.js"}, + {"name":"cogclock.img","url":"icon.js","evaluate":true} + ] +} diff --git a/apps/cogclock/screenshot.png b/apps/cogclock/screenshot.png new file mode 100644 index 000000000..f49709aef Binary files /dev/null and b/apps/cogclock/screenshot.png differ