From 80403150795bb04cc76d739e880083100dae2e2e Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Thu, 21 May 2020 15:25:01 -0400 Subject: [PATCH 0001/2129] Create app.js --- apps/g26/app.js | 345 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 apps/g26/app.js diff --git a/apps/g26/app.js b/apps/g26/app.js new file mode 100644 index 000000000..6e2bdf037 --- /dev/null +++ b/apps/g26/app.js @@ -0,0 +1,345 @@ +g.clear(); + +require("FontHaxorNarrow7x17").add(Graphics); +g.setFont("HaxorNarrow7x17", 1); // bitmap font, 8x magnified + +g.setFontAlign(0,0); // center font + +let interval = null; +let stepCounter = 0; + +let fgColor = "#FFFFFF"; +let bgColor = "#000000"; + +let fillDigits = true; +let myHeartRate = 123; +let hrmPower = false; + +const startX = [ 24, 90, 24, 90 ]; +const startY = [ 14, 14, 120, 120 ]; + +const hht = 60; +const vht = 40; +const w = 60; +const h = 90; + +let lastHour = 99; +let lastMinute = 99; + + +function pad0(n) { + return (n > 9) ? n : ("0"+n); +} + +function setFG() { + g.setColor(fgColor); +} + +function setBG() { + g.setColor(bgColor); +} + +function ellipse(x1, y1, x2, y2, fill) { + if (fill) g.fillEllipse(x1, y1, x2, y2); + else g.drawEllipse(x1, y1, x2, y2); +} + +function poly(arr, fill) { + if (fill) g.fillPoly(arr, true); + else g.drawPoly(arr, true); +} + +function rect(x1, y1, x2, y2, fill) { + if (fill) g.fillRect(x1, y1, x2, y2); + else g.drawRect(x1, y1, x2, y2); +} + +setBG(); +rect(0, 0, 240, 240, true); + + +/** DIGITS **/ + +/* zero */ +function draw0(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig, xOrig+w, yOrig+h, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+15, yOrig+15, xOrig+w-15, yOrig+h-15, fillDigits); +} + +/* one */ +function draw1(xOrig, yOrig) { + setFG(); + poly([xOrig+w/2-6, yOrig, + xOrig+w/2-12, yOrig, + xOrig+w/2-20, yOrig+12, + xOrig+w/2-6, yOrig+12 + ], fillDigits); + rect(xOrig+w/2-6, yOrig, xOrig+w/2+6, yOrig+h-3, fillDigits); + +} + +/* two */ +function draw2(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig, xOrig+56, yOrig+56, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+13, xOrig+43, yOrig+43, fillDigits); + + setBG(); + rect(xOrig, yOrig+27, xOrig+40, yOrig+61, true); + + setFG(); + poly([xOrig, yOrig+88, + xOrig+56, yOrig+88, + xOrig+56, yOrig+75, + xOrig+25, yOrig+75, + xOrig+46, yOrig+50, + xOrig+42, yOrig+36 + ], fillDigits); +} + +/* three */ +function draw8(xOrig, yOrig) { + setFG(); + ellipse(xOrig+3, yOrig, xOrig+53, yOrig+48, fillDigits); + ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+17, yOrig+13, xOrig+40, yOrig+35, fillDigits); + ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); +} + +function draw3(xOrig, yOrig) { + draw8(xOrig, yOrig); + setBG(); + rect(xOrig, yOrig+24, xOrig+24, yOrig+61, true); +} + +/* four */ +function draw4(xOrig, yOrig) { + setFG(); + rect(xOrig+8, yOrig+54, xOrig+w-4, yOrig+67, fillDigits); + rect(xOrig+36, yOrig+12, xOrig+49, yOrig+88, fillDigits); + poly([xOrig, yOrig+67, + xOrig+12, yOrig+67, + xOrig+49, yOrig+12, + xOrig+49, yOrig+1, + xOrig+42, yOrig+1 + ], fillDigits); +} + +function draw5(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); + + setBG(); + rect(xOrig, yOrig+24, xOrig+20, yOrig+61, true); + + setFG(); + poly([xOrig+20, yOrig+1, + xOrig+7, yOrig+47, + xOrig+19, yOrig+47, + xOrig+32, yOrig+1 + ], fillDigits); + rect(xOrig+20, yOrig+1, xOrig+53, yOrig+13, fillDigits); +} + +/* six */ +function draw6(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); + poly([xOrig+2, yOrig+48, + xOrig+34, yOrig, + xOrig+46, yOrig+7, + xOrig+14, yOrig+56 + ], fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); +} + +/* seven */ +function draw7(xOrig, yOrig) { + setFG(); + poly([xOrig+4, yOrig+1, + xOrig+w-1, yOrig+1, + xOrig+w-7, yOrig+13, + xOrig+4, yOrig+13 + ], fillDigits); + poly([xOrig+w-1, yOrig+1, + xOrig+15, yOrig+88, + xOrig+5, yOrig+81, + xOrig+w-19, yOrig+9 + ], fillDigits); +} + +function draw9(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig, xOrig+56, yOrig+56, fillDigits); + poly([xOrig+54, yOrig+41, + xOrig+22, yOrig+89, + xOrig+10, yOrig+82, + xOrig+42, yOrig+33 + ], fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+13, xOrig+43, yOrig+43, fillDigits); +} + +/** END DIGITS **/ +function getRandomColor() { + const digits = "0123456789ABCDEF"; + let r1 = digits[Math.floor(Math.random() * 16)]; + let r2 = digits[Math.floor(Math.random() * 16)]; + let g1 = digits[Math.floor(Math.random() * 16)]; + let g2 = digits[Math.floor(Math.random() * 16)]; + let b1 = digits[Math.floor(Math.random() * 16)]; + let b2 = digits[Math.floor(Math.random() * 16)]; + let str = "#"+r1+r2+g1+g2+b1+b2; + /* console.log(str); */ + return str; +} + +function drawDigit(pos, dig) { + let x = startX[pos]; + let y = startY[pos]; + + setBG(); + rect(x, y, x+w, y+h, true); + switch(dig) { + case 0: + draw0(x, y); + break; + case 1: + draw1(x, y); + break; + case 2: + draw2(x, y); + break; + case 3: + draw3(x, y); + break; + case 4: + draw4(x, y); + break; + case 5: + draw5(x, y); + break; + case 6: + draw6(x, y); + break; + case 7: + draw7(x, y); + break; + case 8: + draw8(x, y); + break; + case 9: + draw9(x, y); + break; + } +} + + +function drawTime() { + let d = new Date(); + let hour = d.getHours(); + let minute = d.getMinutes(); + let month = d.getMonth(); + let date = d.getDate(); + + if(hour == lastHour && minute == lastMinute) { + return; + } + + fgColor = "#FFFFFF"; + if(hour != lastHour) { + drawDigit(0, Math.floor(hour / 10)); + drawDigit(1, hour % 10); + } + + fgColor = "#00FFFF"; + if(minute != lastMinute) { + drawDigit(2, Math.floor(minute / 10)); + drawDigit(3, minute % 10); + } + lastHour = hour; + lastMinute = minute; + + setBG(); + rect(0, 226, 240, 240, true); + for(let c = 0; c <= 240; c++) { + g.setColor(0, 0, 1-c/240); + g.fillRect(180, c, 240, c); + } + g.setColor("#C0C0C0"); + + g.setFontAlign(-1,-1); + g.drawString("DT", 184, 10); + g.drawString("STP", 184, 70); + g.drawString("BPM", 184, 140); + g.drawString("BTY", 184, 210); + + g.setFontAlign(1,-1); + g.drawString(month + "/" + date, 236, 10); + g.drawString(stepCounter, 236, 70); + g.drawString(myHeartRate, 236, 140); + g.drawString(E.getBattery(), 236, 210); + +} + +function stop () { + if (interval) { + clearInterval(interval); + } +} + +function start () { + if (interval) { + clearInterval(interval); + } + // first time init + interval = setInterval(drawTime, 10000); + drawTime(); +} + +start(); + +// Bangle.loadWidgets(); +// Bangle.drawWidgets(); + +Bangle.on('lcdPower', function (on) { + if (on) { + start(); + } else { + stop(); + } +}); + +function btn1Func() { + fillDigits = !fillDigits; + g.clear(); + lastHour = 99; + lastMinute = 99; + drawTime(); +} + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); + +setWatch(btn1Func, BTN1, {repeat:true,edge:"falling"}); + +Bangle.on('step', function(cnt) { + stepCounter = cnt; +}); + +Bangle.on('swipe', function(dir) { + Bangle.buzz(); + hrmPower = ! hrmPower; + Bangle.setHRMPower(hrmPower); +}); + +Bangle.on('HRM', function(hrm) { + myHeartRate = hrm.bpm; +}); From 2bb279c5a360695d4febba10a535a820b356476f Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Thu, 21 May 2020 15:26:51 -0400 Subject: [PATCH 0002/2129] Create g26.js --- apps/g26/g26.js | 345 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 345 insertions(+) create mode 100644 apps/g26/g26.js diff --git a/apps/g26/g26.js b/apps/g26/g26.js new file mode 100644 index 000000000..6e2bdf037 --- /dev/null +++ b/apps/g26/g26.js @@ -0,0 +1,345 @@ +g.clear(); + +require("FontHaxorNarrow7x17").add(Graphics); +g.setFont("HaxorNarrow7x17", 1); // bitmap font, 8x magnified + +g.setFontAlign(0,0); // center font + +let interval = null; +let stepCounter = 0; + +let fgColor = "#FFFFFF"; +let bgColor = "#000000"; + +let fillDigits = true; +let myHeartRate = 123; +let hrmPower = false; + +const startX = [ 24, 90, 24, 90 ]; +const startY = [ 14, 14, 120, 120 ]; + +const hht = 60; +const vht = 40; +const w = 60; +const h = 90; + +let lastHour = 99; +let lastMinute = 99; + + +function pad0(n) { + return (n > 9) ? n : ("0"+n); +} + +function setFG() { + g.setColor(fgColor); +} + +function setBG() { + g.setColor(bgColor); +} + +function ellipse(x1, y1, x2, y2, fill) { + if (fill) g.fillEllipse(x1, y1, x2, y2); + else g.drawEllipse(x1, y1, x2, y2); +} + +function poly(arr, fill) { + if (fill) g.fillPoly(arr, true); + else g.drawPoly(arr, true); +} + +function rect(x1, y1, x2, y2, fill) { + if (fill) g.fillRect(x1, y1, x2, y2); + else g.drawRect(x1, y1, x2, y2); +} + +setBG(); +rect(0, 0, 240, 240, true); + + +/** DIGITS **/ + +/* zero */ +function draw0(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig, xOrig+w, yOrig+h, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+15, yOrig+15, xOrig+w-15, yOrig+h-15, fillDigits); +} + +/* one */ +function draw1(xOrig, yOrig) { + setFG(); + poly([xOrig+w/2-6, yOrig, + xOrig+w/2-12, yOrig, + xOrig+w/2-20, yOrig+12, + xOrig+w/2-6, yOrig+12 + ], fillDigits); + rect(xOrig+w/2-6, yOrig, xOrig+w/2+6, yOrig+h-3, fillDigits); + +} + +/* two */ +function draw2(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig, xOrig+56, yOrig+56, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+13, xOrig+43, yOrig+43, fillDigits); + + setBG(); + rect(xOrig, yOrig+27, xOrig+40, yOrig+61, true); + + setFG(); + poly([xOrig, yOrig+88, + xOrig+56, yOrig+88, + xOrig+56, yOrig+75, + xOrig+25, yOrig+75, + xOrig+46, yOrig+50, + xOrig+42, yOrig+36 + ], fillDigits); +} + +/* three */ +function draw8(xOrig, yOrig) { + setFG(); + ellipse(xOrig+3, yOrig, xOrig+53, yOrig+48, fillDigits); + ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+17, yOrig+13, xOrig+40, yOrig+35, fillDigits); + ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); +} + +function draw3(xOrig, yOrig) { + draw8(xOrig, yOrig); + setBG(); + rect(xOrig, yOrig+24, xOrig+24, yOrig+61, true); +} + +/* four */ +function draw4(xOrig, yOrig) { + setFG(); + rect(xOrig+8, yOrig+54, xOrig+w-4, yOrig+67, fillDigits); + rect(xOrig+36, yOrig+12, xOrig+49, yOrig+88, fillDigits); + poly([xOrig, yOrig+67, + xOrig+12, yOrig+67, + xOrig+49, yOrig+12, + xOrig+49, yOrig+1, + xOrig+42, yOrig+1 + ], fillDigits); +} + +function draw5(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); + + setBG(); + rect(xOrig, yOrig+24, xOrig+20, yOrig+61, true); + + setFG(); + poly([xOrig+20, yOrig+1, + xOrig+7, yOrig+47, + xOrig+19, yOrig+47, + xOrig+32, yOrig+1 + ], fillDigits); + rect(xOrig+20, yOrig+1, xOrig+53, yOrig+13, fillDigits); +} + +/* six */ +function draw6(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); + poly([xOrig+2, yOrig+48, + xOrig+34, yOrig, + xOrig+46, yOrig+7, + xOrig+14, yOrig+56 + ], fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); +} + +/* seven */ +function draw7(xOrig, yOrig) { + setFG(); + poly([xOrig+4, yOrig+1, + xOrig+w-1, yOrig+1, + xOrig+w-7, yOrig+13, + xOrig+4, yOrig+13 + ], fillDigits); + poly([xOrig+w-1, yOrig+1, + xOrig+15, yOrig+88, + xOrig+5, yOrig+81, + xOrig+w-19, yOrig+9 + ], fillDigits); +} + +function draw9(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig, xOrig+56, yOrig+56, fillDigits); + poly([xOrig+54, yOrig+41, + xOrig+22, yOrig+89, + xOrig+10, yOrig+82, + xOrig+42, yOrig+33 + ], fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+13, xOrig+43, yOrig+43, fillDigits); +} + +/** END DIGITS **/ +function getRandomColor() { + const digits = "0123456789ABCDEF"; + let r1 = digits[Math.floor(Math.random() * 16)]; + let r2 = digits[Math.floor(Math.random() * 16)]; + let g1 = digits[Math.floor(Math.random() * 16)]; + let g2 = digits[Math.floor(Math.random() * 16)]; + let b1 = digits[Math.floor(Math.random() * 16)]; + let b2 = digits[Math.floor(Math.random() * 16)]; + let str = "#"+r1+r2+g1+g2+b1+b2; + /* console.log(str); */ + return str; +} + +function drawDigit(pos, dig) { + let x = startX[pos]; + let y = startY[pos]; + + setBG(); + rect(x, y, x+w, y+h, true); + switch(dig) { + case 0: + draw0(x, y); + break; + case 1: + draw1(x, y); + break; + case 2: + draw2(x, y); + break; + case 3: + draw3(x, y); + break; + case 4: + draw4(x, y); + break; + case 5: + draw5(x, y); + break; + case 6: + draw6(x, y); + break; + case 7: + draw7(x, y); + break; + case 8: + draw8(x, y); + break; + case 9: + draw9(x, y); + break; + } +} + + +function drawTime() { + let d = new Date(); + let hour = d.getHours(); + let minute = d.getMinutes(); + let month = d.getMonth(); + let date = d.getDate(); + + if(hour == lastHour && minute == lastMinute) { + return; + } + + fgColor = "#FFFFFF"; + if(hour != lastHour) { + drawDigit(0, Math.floor(hour / 10)); + drawDigit(1, hour % 10); + } + + fgColor = "#00FFFF"; + if(minute != lastMinute) { + drawDigit(2, Math.floor(minute / 10)); + drawDigit(3, minute % 10); + } + lastHour = hour; + lastMinute = minute; + + setBG(); + rect(0, 226, 240, 240, true); + for(let c = 0; c <= 240; c++) { + g.setColor(0, 0, 1-c/240); + g.fillRect(180, c, 240, c); + } + g.setColor("#C0C0C0"); + + g.setFontAlign(-1,-1); + g.drawString("DT", 184, 10); + g.drawString("STP", 184, 70); + g.drawString("BPM", 184, 140); + g.drawString("BTY", 184, 210); + + g.setFontAlign(1,-1); + g.drawString(month + "/" + date, 236, 10); + g.drawString(stepCounter, 236, 70); + g.drawString(myHeartRate, 236, 140); + g.drawString(E.getBattery(), 236, 210); + +} + +function stop () { + if (interval) { + clearInterval(interval); + } +} + +function start () { + if (interval) { + clearInterval(interval); + } + // first time init + interval = setInterval(drawTime, 10000); + drawTime(); +} + +start(); + +// Bangle.loadWidgets(); +// Bangle.drawWidgets(); + +Bangle.on('lcdPower', function (on) { + if (on) { + start(); + } else { + stop(); + } +}); + +function btn1Func() { + fillDigits = !fillDigits; + g.clear(); + lastHour = 99; + lastMinute = 99; + drawTime(); +} + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); + +setWatch(btn1Func, BTN1, {repeat:true,edge:"falling"}); + +Bangle.on('step', function(cnt) { + stepCounter = cnt; +}); + +Bangle.on('swipe', function(dir) { + Bangle.buzz(); + hrmPower = ! hrmPower; + Bangle.setHRMPower(hrmPower); +}); + +Bangle.on('HRM', function(hrm) { + myHeartRate = hrm.bpm; +}); From cbdde8b5cfa79e0e2468b15a472413174de124e2 Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Thu, 21 May 2020 15:27:44 -0400 Subject: [PATCH 0003/2129] Delete app.js --- apps/g26/app.js | 345 ------------------------------------------------ 1 file changed, 345 deletions(-) delete mode 100644 apps/g26/app.js diff --git a/apps/g26/app.js b/apps/g26/app.js deleted file mode 100644 index 6e2bdf037..000000000 --- a/apps/g26/app.js +++ /dev/null @@ -1,345 +0,0 @@ -g.clear(); - -require("FontHaxorNarrow7x17").add(Graphics); -g.setFont("HaxorNarrow7x17", 1); // bitmap font, 8x magnified - -g.setFontAlign(0,0); // center font - -let interval = null; -let stepCounter = 0; - -let fgColor = "#FFFFFF"; -let bgColor = "#000000"; - -let fillDigits = true; -let myHeartRate = 123; -let hrmPower = false; - -const startX = [ 24, 90, 24, 90 ]; -const startY = [ 14, 14, 120, 120 ]; - -const hht = 60; -const vht = 40; -const w = 60; -const h = 90; - -let lastHour = 99; -let lastMinute = 99; - - -function pad0(n) { - return (n > 9) ? n : ("0"+n); -} - -function setFG() { - g.setColor(fgColor); -} - -function setBG() { - g.setColor(bgColor); -} - -function ellipse(x1, y1, x2, y2, fill) { - if (fill) g.fillEllipse(x1, y1, x2, y2); - else g.drawEllipse(x1, y1, x2, y2); -} - -function poly(arr, fill) { - if (fill) g.fillPoly(arr, true); - else g.drawPoly(arr, true); -} - -function rect(x1, y1, x2, y2, fill) { - if (fill) g.fillRect(x1, y1, x2, y2); - else g.drawRect(x1, y1, x2, y2); -} - -setBG(); -rect(0, 0, 240, 240, true); - - -/** DIGITS **/ - -/* zero */ -function draw0(xOrig, yOrig) { - setFG(); - ellipse(xOrig, yOrig, xOrig+w, yOrig+h, fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+15, yOrig+15, xOrig+w-15, yOrig+h-15, fillDigits); -} - -/* one */ -function draw1(xOrig, yOrig) { - setFG(); - poly([xOrig+w/2-6, yOrig, - xOrig+w/2-12, yOrig, - xOrig+w/2-20, yOrig+12, - xOrig+w/2-6, yOrig+12 - ], fillDigits); - rect(xOrig+w/2-6, yOrig, xOrig+w/2+6, yOrig+h-3, fillDigits); - -} - -/* two */ -function draw2(xOrig, yOrig) { - setFG(); - ellipse(xOrig, yOrig, xOrig+56, yOrig+56, fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+13, yOrig+13, xOrig+43, yOrig+43, fillDigits); - - setBG(); - rect(xOrig, yOrig+27, xOrig+40, yOrig+61, true); - - setFG(); - poly([xOrig, yOrig+88, - xOrig+56, yOrig+88, - xOrig+56, yOrig+75, - xOrig+25, yOrig+75, - xOrig+46, yOrig+50, - xOrig+42, yOrig+36 - ], fillDigits); -} - -/* three */ -function draw8(xOrig, yOrig) { - setFG(); - ellipse(xOrig+3, yOrig, xOrig+53, yOrig+48, fillDigits); - ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+17, yOrig+13, xOrig+40, yOrig+35, fillDigits); - ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); -} - -function draw3(xOrig, yOrig) { - draw8(xOrig, yOrig); - setBG(); - rect(xOrig, yOrig+24, xOrig+24, yOrig+61, true); -} - -/* four */ -function draw4(xOrig, yOrig) { - setFG(); - rect(xOrig+8, yOrig+54, xOrig+w-4, yOrig+67, fillDigits); - rect(xOrig+36, yOrig+12, xOrig+49, yOrig+88, fillDigits); - poly([xOrig, yOrig+67, - xOrig+12, yOrig+67, - xOrig+49, yOrig+12, - xOrig+49, yOrig+1, - xOrig+42, yOrig+1 - ], fillDigits); -} - -function draw5(xOrig, yOrig) { - setFG(); - ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); - - setBG(); - rect(xOrig, yOrig+24, xOrig+20, yOrig+61, true); - - setFG(); - poly([xOrig+20, yOrig+1, - xOrig+7, yOrig+47, - xOrig+19, yOrig+47, - xOrig+32, yOrig+1 - ], fillDigits); - rect(xOrig+20, yOrig+1, xOrig+53, yOrig+13, fillDigits); -} - -/* six */ -function draw6(xOrig, yOrig) { - setFG(); - ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); - poly([xOrig+2, yOrig+48, - xOrig+34, yOrig, - xOrig+46, yOrig+7, - xOrig+14, yOrig+56 - ], fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); -} - -/* seven */ -function draw7(xOrig, yOrig) { - setFG(); - poly([xOrig+4, yOrig+1, - xOrig+w-1, yOrig+1, - xOrig+w-7, yOrig+13, - xOrig+4, yOrig+13 - ], fillDigits); - poly([xOrig+w-1, yOrig+1, - xOrig+15, yOrig+88, - xOrig+5, yOrig+81, - xOrig+w-19, yOrig+9 - ], fillDigits); -} - -function draw9(xOrig, yOrig) { - setFG(); - ellipse(xOrig, yOrig, xOrig+56, yOrig+56, fillDigits); - poly([xOrig+54, yOrig+41, - xOrig+22, yOrig+89, - xOrig+10, yOrig+82, - xOrig+42, yOrig+33 - ], fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+13, yOrig+13, xOrig+43, yOrig+43, fillDigits); -} - -/** END DIGITS **/ -function getRandomColor() { - const digits = "0123456789ABCDEF"; - let r1 = digits[Math.floor(Math.random() * 16)]; - let r2 = digits[Math.floor(Math.random() * 16)]; - let g1 = digits[Math.floor(Math.random() * 16)]; - let g2 = digits[Math.floor(Math.random() * 16)]; - let b1 = digits[Math.floor(Math.random() * 16)]; - let b2 = digits[Math.floor(Math.random() * 16)]; - let str = "#"+r1+r2+g1+g2+b1+b2; - /* console.log(str); */ - return str; -} - -function drawDigit(pos, dig) { - let x = startX[pos]; - let y = startY[pos]; - - setBG(); - rect(x, y, x+w, y+h, true); - switch(dig) { - case 0: - draw0(x, y); - break; - case 1: - draw1(x, y); - break; - case 2: - draw2(x, y); - break; - case 3: - draw3(x, y); - break; - case 4: - draw4(x, y); - break; - case 5: - draw5(x, y); - break; - case 6: - draw6(x, y); - break; - case 7: - draw7(x, y); - break; - case 8: - draw8(x, y); - break; - case 9: - draw9(x, y); - break; - } -} - - -function drawTime() { - let d = new Date(); - let hour = d.getHours(); - let minute = d.getMinutes(); - let month = d.getMonth(); - let date = d.getDate(); - - if(hour == lastHour && minute == lastMinute) { - return; - } - - fgColor = "#FFFFFF"; - if(hour != lastHour) { - drawDigit(0, Math.floor(hour / 10)); - drawDigit(1, hour % 10); - } - - fgColor = "#00FFFF"; - if(minute != lastMinute) { - drawDigit(2, Math.floor(minute / 10)); - drawDigit(3, minute % 10); - } - lastHour = hour; - lastMinute = minute; - - setBG(); - rect(0, 226, 240, 240, true); - for(let c = 0; c <= 240; c++) { - g.setColor(0, 0, 1-c/240); - g.fillRect(180, c, 240, c); - } - g.setColor("#C0C0C0"); - - g.setFontAlign(-1,-1); - g.drawString("DT", 184, 10); - g.drawString("STP", 184, 70); - g.drawString("BPM", 184, 140); - g.drawString("BTY", 184, 210); - - g.setFontAlign(1,-1); - g.drawString(month + "/" + date, 236, 10); - g.drawString(stepCounter, 236, 70); - g.drawString(myHeartRate, 236, 140); - g.drawString(E.getBattery(), 236, 210); - -} - -function stop () { - if (interval) { - clearInterval(interval); - } -} - -function start () { - if (interval) { - clearInterval(interval); - } - // first time init - interval = setInterval(drawTime, 10000); - drawTime(); -} - -start(); - -// Bangle.loadWidgets(); -// Bangle.drawWidgets(); - -Bangle.on('lcdPower', function (on) { - if (on) { - start(); - } else { - stop(); - } -}); - -function btn1Func() { - fillDigits = !fillDigits; - g.clear(); - lastHour = 99; - lastMinute = 99; - drawTime(); -} - -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); - -setWatch(btn1Func, BTN1, {repeat:true,edge:"falling"}); - -Bangle.on('step', function(cnt) { - stepCounter = cnt; -}); - -Bangle.on('swipe', function(dir) { - Bangle.buzz(); - hrmPower = ! hrmPower; - Bangle.setHRMPower(hrmPower); -}); - -Bangle.on('HRM', function(hrm) { - myHeartRate = hrm.bpm; -}); From 0da1a4d7251a4d35cf26c4db4ae60ee1808a62e9 Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Thu, 21 May 2020 15:37:25 -0400 Subject: [PATCH 0004/2129] Create g26.json --- apps/g26/g26.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 apps/g26/g26.json diff --git a/apps/g26/g26.json b/apps/g26/g26.json new file mode 100644 index 000000000..e037c8f17 --- /dev/null +++ b/apps/g26/g26.json @@ -0,0 +1,13 @@ +}, +{ "id": "g26", + "name": "G26 Watch", + "shortName":"G26 Watch", + "type": "clock", + "version":"0.01", + "description": "This is a watchface loosely based on a $5 step tracker", + "tags": "", + "storage": [ + {"name":"g26.app.js","url":"g26.js"} + ] +} +] From e9a20f90f3628140228d27a7a8b7d3621f06cf43 Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Thu, 21 May 2020 15:51:35 -0400 Subject: [PATCH 0005/2129] Create apps.json --- apps/g26/apps.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 apps/g26/apps.json diff --git a/apps/g26/apps.json b/apps/g26/apps.json new file mode 100644 index 000000000..e037c8f17 --- /dev/null +++ b/apps/g26/apps.json @@ -0,0 +1,13 @@ +}, +{ "id": "g26", + "name": "G26 Watch", + "shortName":"G26 Watch", + "type": "clock", + "version":"0.01", + "description": "This is a watchface loosely based on a $5 step tracker", + "tags": "", + "storage": [ + {"name":"g26.app.js","url":"g26.js"} + ] +} +] From 17e920d7e569d341dc32044f74c47183e3978f8b Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Thu, 21 May 2020 15:55:33 -0400 Subject: [PATCH 0006/2129] Create app.js --- apps/g26/app.js | 336 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 apps/g26/app.js diff --git a/apps/g26/app.js b/apps/g26/app.js new file mode 100644 index 000000000..b96422f4c --- /dev/null +++ b/apps/g26/app.js @@ -0,0 +1,336 @@ +g.clear(); + +require("FontHaxorNarrow7x17").add(Graphics); +g.setFont("HaxorNarrow7x17", 1); // bitmap font, 8x magnified + +g.setFontAlign(0,0); // center font + +let interval = null; +let stepCounter = 0; + +let fgColor = "#FFFFFF"; +let bgColor = "#000000"; + +let fillDigits = true; +let myHeartRate = 123; +let hrmPower = false; + +const startX = [ 24, 90, 24, 90 ]; +const startY = [ 14, 14, 120, 120 ]; + +const hht = 60; +const vht = 40; +const w = 60; +const h = 90; + +let lastHour = 99; +let lastMinute = 99; + + +function pad0(n) { + return (n > 9) ? n : ("0"+n); +} + +function setFG() { + g.setColor(fgColor); +} + +function setBG() { + g.setColor(bgColor); +} + +function ellipse(x1, y1, x2, y2, fill) { + if (fill) g.fillEllipse(x1, y1, x2, y2); + else g.drawEllipse(x1, y1, x2, y2); +} + +function poly(arr, fill) { + if (fill) g.fillPoly(arr, true); + else g.drawPoly(arr, true); +} + +function rect(x1, y1, x2, y2, fill) { + if (fill) g.fillRect(x1, y1, x2, y2); + else g.drawRect(x1, y1, x2, y2); +} + +setBG(); +rect(0, 0, 240, 240, true); + + +/** DIGITS **/ + +/* zero */ +function draw0(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig, xOrig+w, yOrig+h, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+15, yOrig+15, xOrig+w-15, yOrig+h-15, fillDigits); +} + +/* one */ +function draw1(xOrig, yOrig) { + setFG(); + poly([xOrig+w/2-6, yOrig, + xOrig+w/2-12, yOrig, + xOrig+w/2-20, yOrig+12, + xOrig+w/2-6, yOrig+12 + ], fillDigits); + rect(xOrig+w/2-6, yOrig, xOrig+w/2+6, yOrig+h-3, fillDigits); + +} + +/* two */ +function draw2(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig, xOrig+56, yOrig+56, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+13, xOrig+43, yOrig+43, fillDigits); + + setBG(); + rect(xOrig, yOrig+27, xOrig+40, yOrig+61, true); + + setFG(); + poly([xOrig, yOrig+88, + xOrig+56, yOrig+88, + xOrig+56, yOrig+75, + xOrig+25, yOrig+75, + xOrig+46, yOrig+50, + xOrig+42, yOrig+36 + ], fillDigits); +} + +/* three */ +function draw8(xOrig, yOrig) { + setFG(); + ellipse(xOrig+3, yOrig, xOrig+53, yOrig+48, fillDigits); + ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+17, yOrig+13, xOrig+40, yOrig+35, fillDigits); + ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); +} + +function draw3(xOrig, yOrig) { + draw8(xOrig, yOrig); + setBG(); + rect(xOrig, yOrig+24, xOrig+24, yOrig+61, true); +} + +/* four */ +function draw4(xOrig, yOrig) { + setFG(); + rect(xOrig+8, yOrig+54, xOrig+w-4, yOrig+67, fillDigits); + rect(xOrig+36, yOrig+12, xOrig+49, yOrig+88, fillDigits); + poly([xOrig, yOrig+67, + xOrig+12, yOrig+67, + xOrig+49, yOrig+12, + xOrig+49, yOrig+1, + xOrig+42, yOrig+1 + ], fillDigits); +} + +function draw5(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); + + setBG(); + rect(xOrig, yOrig+24, xOrig+20, yOrig+61, true); + + setFG(); + poly([xOrig+20, yOrig+1, + xOrig+7, yOrig+47, + xOrig+19, yOrig+47, + xOrig+32, yOrig+1 + ], fillDigits); + rect(xOrig+20, yOrig+1, xOrig+53, yOrig+13, fillDigits); +} + +/* six */ +function draw6(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); + poly([xOrig+2, yOrig+48, + xOrig+34, yOrig, + xOrig+46, yOrig+7, + xOrig+14, yOrig+56 + ], fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); +} + +/* seven */ +function draw7(xOrig, yOrig) { + setFG(); + poly([xOrig+4, yOrig+1, + xOrig+w-1, yOrig+1, + xOrig+w-7, yOrig+13, + xOrig+4, yOrig+13 + ], fillDigits); + poly([xOrig+w-1, yOrig+1, + xOrig+15, yOrig+88, + xOrig+5, yOrig+81, + xOrig+w-19, yOrig+9 + ], fillDigits); +} + +function draw9(xOrig, yOrig) { + setFG(); + ellipse(xOrig, yOrig, xOrig+56, yOrig+56, fillDigits); + poly([xOrig+54, yOrig+41, + xOrig+22, yOrig+89, + xOrig+10, yOrig+82, + xOrig+42, yOrig+33 + ], fillDigits); + if(fillDigits) setBG(); + ellipse(xOrig+13, yOrig+13, xOrig+43, yOrig+43, fillDigits); +} + +/** END DIGITS **/ +function getRandomColor() { + const digits = "0123456789ABCDEF"; + let r1 = digits[Math.floor(Math.random() * 16)]; + let r2 = digits[Math.floor(Math.random() * 16)]; + let g1 = digits[Math.floor(Math.random() * 16)]; + let g2 = digits[Math.floor(Math.random() * 16)]; + let b1 = digits[Math.floor(Math.random() * 16)]; + let b2 = digits[Math.floor(Math.random() * 16)]; + let str = "#"+r1+r2+g1+g2+b1+b2; + /* console.log(str); */ + return str; +} + +function drawDigit(pos, dig) { + let x = startX[pos]; + let y = startY[pos]; + + setBG(); + rect(x, y, x+w, y+h, true); + switch(dig) { + case 0: + draw0(x, y); + break; + case 1: + draw1(x, y); + break; + case 2: + draw2(x, y); + break; + case 3: + draw3(x, y); + break; + case 4: + draw4(x, y); + break; + case 5: + draw5(x, y); + break; + case 6: + draw6(x, y); + break; + case 7: + draw7(x, y); + break; + case 8: + draw8(x, y); + break; + case 9: + draw9(x, y); + break; + } +} + + +function drawTime() { + let d = new Date(); + let hour = d.getHours(); + let minute = d.getMinutes(); + let month = d.getMonth(); + let date = d.getDate(); + + if(hour == lastHour && minute == lastMinute) { + return; + } + + fgColor = "#FFFFFF"; + if(hour != lastHour) { + drawDigit(0, Math.floor(hour / 10)); + drawDigit(1, hour % 10); + } + + fgColor = "#00FFFF"; + if(minute != lastMinute) { + drawDigit(2, Math.floor(minute / 10)); + drawDigit(3, minute % 10); + } + lastHour = hour; + lastMinute = minute; + + setBG(); + rect(0, 226, 240, 240, true); + for(let c = 0; c <= 240; c++) { + g.setColor(0, 0, 1-c/240); + g.fillRect(180, c, 240, c); + } + g.setColor("#C0C0C0"); + + g.setFontAlign(-1,-1); + g.drawString("DT", 184, 10); + g.drawString("STP", 184, 70); + g.drawString("BPM", 184, 140); + g.drawString("BTY", 184, 210); + + g.setFontAlign(1,-1); + g.drawString(month + "/" + date, 236, 10); + g.drawString(stepCounter, 236, 70); + g.drawString(myHeartRate, 236, 140); + g.drawString(E.getBattery(), 236, 210); + +} + +function stop () { + if (interval) { + clearInterval(interval); + } +} + +function start () { + if (interval) { + clearInterval(interval); + } + // first time init + interval = setInterval(drawTime, 10000); + drawTime(); +} + +start(); + +// Bangle.loadWidgets(); +// Bangle.drawWidgets(); + +Bangle.on('lcdPower', function (on) { + if (on) { + start(); + } else { + stop(); + } +}); + +function btn1Func() { + fillDigits = !fillDigits; + g.clear(); + lastHour = 99; + lastMinute = 99; + drawTime(); +} + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); + +setWatch(btn1Func, BTN1, {repeat:true,edge:"falling"}); + +Bangle.on('step', function(cnt) { + stepCounter = cnt; +}); + From 5ad73b28fa58a213c2833d6de334791c5f2960d5 Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Thu, 21 May 2020 15:55:50 -0400 Subject: [PATCH 0007/2129] Delete g26.js --- apps/g26/g26.js | 345 ------------------------------------------------ 1 file changed, 345 deletions(-) delete mode 100644 apps/g26/g26.js diff --git a/apps/g26/g26.js b/apps/g26/g26.js deleted file mode 100644 index 6e2bdf037..000000000 --- a/apps/g26/g26.js +++ /dev/null @@ -1,345 +0,0 @@ -g.clear(); - -require("FontHaxorNarrow7x17").add(Graphics); -g.setFont("HaxorNarrow7x17", 1); // bitmap font, 8x magnified - -g.setFontAlign(0,0); // center font - -let interval = null; -let stepCounter = 0; - -let fgColor = "#FFFFFF"; -let bgColor = "#000000"; - -let fillDigits = true; -let myHeartRate = 123; -let hrmPower = false; - -const startX = [ 24, 90, 24, 90 ]; -const startY = [ 14, 14, 120, 120 ]; - -const hht = 60; -const vht = 40; -const w = 60; -const h = 90; - -let lastHour = 99; -let lastMinute = 99; - - -function pad0(n) { - return (n > 9) ? n : ("0"+n); -} - -function setFG() { - g.setColor(fgColor); -} - -function setBG() { - g.setColor(bgColor); -} - -function ellipse(x1, y1, x2, y2, fill) { - if (fill) g.fillEllipse(x1, y1, x2, y2); - else g.drawEllipse(x1, y1, x2, y2); -} - -function poly(arr, fill) { - if (fill) g.fillPoly(arr, true); - else g.drawPoly(arr, true); -} - -function rect(x1, y1, x2, y2, fill) { - if (fill) g.fillRect(x1, y1, x2, y2); - else g.drawRect(x1, y1, x2, y2); -} - -setBG(); -rect(0, 0, 240, 240, true); - - -/** DIGITS **/ - -/* zero */ -function draw0(xOrig, yOrig) { - setFG(); - ellipse(xOrig, yOrig, xOrig+w, yOrig+h, fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+15, yOrig+15, xOrig+w-15, yOrig+h-15, fillDigits); -} - -/* one */ -function draw1(xOrig, yOrig) { - setFG(); - poly([xOrig+w/2-6, yOrig, - xOrig+w/2-12, yOrig, - xOrig+w/2-20, yOrig+12, - xOrig+w/2-6, yOrig+12 - ], fillDigits); - rect(xOrig+w/2-6, yOrig, xOrig+w/2+6, yOrig+h-3, fillDigits); - -} - -/* two */ -function draw2(xOrig, yOrig) { - setFG(); - ellipse(xOrig, yOrig, xOrig+56, yOrig+56, fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+13, yOrig+13, xOrig+43, yOrig+43, fillDigits); - - setBG(); - rect(xOrig, yOrig+27, xOrig+40, yOrig+61, true); - - setFG(); - poly([xOrig, yOrig+88, - xOrig+56, yOrig+88, - xOrig+56, yOrig+75, - xOrig+25, yOrig+75, - xOrig+46, yOrig+50, - xOrig+42, yOrig+36 - ], fillDigits); -} - -/* three */ -function draw8(xOrig, yOrig) { - setFG(); - ellipse(xOrig+3, yOrig, xOrig+53, yOrig+48, fillDigits); - ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+17, yOrig+13, xOrig+40, yOrig+35, fillDigits); - ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); -} - -function draw3(xOrig, yOrig) { - draw8(xOrig, yOrig); - setBG(); - rect(xOrig, yOrig+24, xOrig+24, yOrig+61, true); -} - -/* four */ -function draw4(xOrig, yOrig) { - setFG(); - rect(xOrig+8, yOrig+54, xOrig+w-4, yOrig+67, fillDigits); - rect(xOrig+36, yOrig+12, xOrig+49, yOrig+88, fillDigits); - poly([xOrig, yOrig+67, - xOrig+12, yOrig+67, - xOrig+49, yOrig+12, - xOrig+49, yOrig+1, - xOrig+42, yOrig+1 - ], fillDigits); -} - -function draw5(xOrig, yOrig) { - setFG(); - ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); - - setBG(); - rect(xOrig, yOrig+24, xOrig+20, yOrig+61, true); - - setFG(); - poly([xOrig+20, yOrig+1, - xOrig+7, yOrig+47, - xOrig+19, yOrig+47, - xOrig+32, yOrig+1 - ], fillDigits); - rect(xOrig+20, yOrig+1, xOrig+53, yOrig+13, fillDigits); -} - -/* six */ -function draw6(xOrig, yOrig) { - setFG(); - ellipse(xOrig, yOrig+33, xOrig+56, yOrig+89, fillDigits); - poly([xOrig+2, yOrig+48, - xOrig+34, yOrig, - xOrig+46, yOrig+7, - xOrig+14, yOrig+56 - ], fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+13, yOrig+46, xOrig+43, yOrig+76, fillDigits); -} - -/* seven */ -function draw7(xOrig, yOrig) { - setFG(); - poly([xOrig+4, yOrig+1, - xOrig+w-1, yOrig+1, - xOrig+w-7, yOrig+13, - xOrig+4, yOrig+13 - ], fillDigits); - poly([xOrig+w-1, yOrig+1, - xOrig+15, yOrig+88, - xOrig+5, yOrig+81, - xOrig+w-19, yOrig+9 - ], fillDigits); -} - -function draw9(xOrig, yOrig) { - setFG(); - ellipse(xOrig, yOrig, xOrig+56, yOrig+56, fillDigits); - poly([xOrig+54, yOrig+41, - xOrig+22, yOrig+89, - xOrig+10, yOrig+82, - xOrig+42, yOrig+33 - ], fillDigits); - if(fillDigits) setBG(); - ellipse(xOrig+13, yOrig+13, xOrig+43, yOrig+43, fillDigits); -} - -/** END DIGITS **/ -function getRandomColor() { - const digits = "0123456789ABCDEF"; - let r1 = digits[Math.floor(Math.random() * 16)]; - let r2 = digits[Math.floor(Math.random() * 16)]; - let g1 = digits[Math.floor(Math.random() * 16)]; - let g2 = digits[Math.floor(Math.random() * 16)]; - let b1 = digits[Math.floor(Math.random() * 16)]; - let b2 = digits[Math.floor(Math.random() * 16)]; - let str = "#"+r1+r2+g1+g2+b1+b2; - /* console.log(str); */ - return str; -} - -function drawDigit(pos, dig) { - let x = startX[pos]; - let y = startY[pos]; - - setBG(); - rect(x, y, x+w, y+h, true); - switch(dig) { - case 0: - draw0(x, y); - break; - case 1: - draw1(x, y); - break; - case 2: - draw2(x, y); - break; - case 3: - draw3(x, y); - break; - case 4: - draw4(x, y); - break; - case 5: - draw5(x, y); - break; - case 6: - draw6(x, y); - break; - case 7: - draw7(x, y); - break; - case 8: - draw8(x, y); - break; - case 9: - draw9(x, y); - break; - } -} - - -function drawTime() { - let d = new Date(); - let hour = d.getHours(); - let minute = d.getMinutes(); - let month = d.getMonth(); - let date = d.getDate(); - - if(hour == lastHour && minute == lastMinute) { - return; - } - - fgColor = "#FFFFFF"; - if(hour != lastHour) { - drawDigit(0, Math.floor(hour / 10)); - drawDigit(1, hour % 10); - } - - fgColor = "#00FFFF"; - if(minute != lastMinute) { - drawDigit(2, Math.floor(minute / 10)); - drawDigit(3, minute % 10); - } - lastHour = hour; - lastMinute = minute; - - setBG(); - rect(0, 226, 240, 240, true); - for(let c = 0; c <= 240; c++) { - g.setColor(0, 0, 1-c/240); - g.fillRect(180, c, 240, c); - } - g.setColor("#C0C0C0"); - - g.setFontAlign(-1,-1); - g.drawString("DT", 184, 10); - g.drawString("STP", 184, 70); - g.drawString("BPM", 184, 140); - g.drawString("BTY", 184, 210); - - g.setFontAlign(1,-1); - g.drawString(month + "/" + date, 236, 10); - g.drawString(stepCounter, 236, 70); - g.drawString(myHeartRate, 236, 140); - g.drawString(E.getBattery(), 236, 210); - -} - -function stop () { - if (interval) { - clearInterval(interval); - } -} - -function start () { - if (interval) { - clearInterval(interval); - } - // first time init - interval = setInterval(drawTime, 10000); - drawTime(); -} - -start(); - -// Bangle.loadWidgets(); -// Bangle.drawWidgets(); - -Bangle.on('lcdPower', function (on) { - if (on) { - start(); - } else { - stop(); - } -}); - -function btn1Func() { - fillDigits = !fillDigits; - g.clear(); - lastHour = 99; - lastMinute = 99; - drawTime(); -} - -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); - -setWatch(btn1Func, BTN1, {repeat:true,edge:"falling"}); - -Bangle.on('step', function(cnt) { - stepCounter = cnt; -}); - -Bangle.on('swipe', function(dir) { - Bangle.buzz(); - hrmPower = ! hrmPower; - Bangle.setHRMPower(hrmPower); -}); - -Bangle.on('HRM', function(hrm) { - myHeartRate = hrm.bpm; -}); From f367b1a662dcfa9f1696469ab6427a7b43206195 Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Thu, 21 May 2020 15:56:00 -0400 Subject: [PATCH 0008/2129] Delete g26.json --- apps/g26/g26.json | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 apps/g26/g26.json diff --git a/apps/g26/g26.json b/apps/g26/g26.json deleted file mode 100644 index e037c8f17..000000000 --- a/apps/g26/g26.json +++ /dev/null @@ -1,13 +0,0 @@ -}, -{ "id": "g26", - "name": "G26 Watch", - "shortName":"G26 Watch", - "type": "clock", - "version":"0.01", - "description": "This is a watchface loosely based on a $5 step tracker", - "tags": "", - "storage": [ - {"name":"g26.app.js","url":"g26.js"} - ] -} -] From 4fa0d1b204e997425887272215615b6f4de0102d Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Fri, 17 Jul 2020 14:37:15 -0400 Subject: [PATCH 0009/2129] Create readme.md --- apps/nixie/readme.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 apps/nixie/readme.md diff --git a/apps/nixie/readme.md b/apps/nixie/readme.md new file mode 100644 index 000000000..68af873a6 --- /dev/null +++ b/apps/nixie/readme.md @@ -0,0 +1,3 @@ +This watch face emulates nixie tube characters and is a bit fun to watch draw. Also displays date, "steps" (the stepcounter / 10 until I really train the accelerometer) and remaining battery. + +Also supports alarms from a JSON file named "yngv.alarms.json". From a33b203780c5bedccc7711ca46e8c1c191ee7404 Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Fri, 17 Jul 2020 14:38:24 -0400 Subject: [PATCH 0010/2129] Add files via upload --- apps/nixie/nixie.app.js | 392 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 apps/nixie/nixie.app.js diff --git a/apps/nixie/nixie.app.js b/apps/nixie/nixie.app.js new file mode 100644 index 000000000..c9fa068fe --- /dev/null +++ b/apps/nixie/nixie.app.js @@ -0,0 +1,392 @@ + +g.clear(); + +require("Font8x12").add(Graphics); +g.setFont("8x12", 1); +let interval = null; +let stepCounter = 0; + +let msgs = require("Storage").readJSON('yngv27.msgs.json'); +let alarms = require("Storage").readJSON('yngv27.alarm.json'); + +function showMsg(msg) { + g.setFontAlign(0,-1); + g.setColor(1,1,1); + g.drawString("<< ALARM >>", 120, 180, true); + g.drawString(msg, 120, 200, true); + Bangle.buzz(); + setTimeout(Bangle.buzz, 800); + setTimeout(Bangle.buzz, 1600); + setTimeout(Bangle.buzz, 2400); + setTimeout(Bangle.buzz, 3200); +} + +function checkMsgs() { + for(let idx=0; idx < alarms.length; idx++) { + let tdiff = Date.now() - Date.parse(alarms[idx].time); + // 10 sec margin of error + if(tdiff > 0 && tdiff < 10000) { + showMsg(alarms[idx].msg); + } + } +} + +for(let idx=0; idx < alarms.length; idx++) { + let tdiff = Date.parse(alarms[idx].time) - Date.now(); + let msg = alarms[idx].msg; + if(tdiff > 0) { + /*console.log(`will alarm ${msg} in ${tdiff}`);*/ + setTimeout(checkMsgs, tdiff); + } +} + +let xs = 0.5; +let ys = 0.75; + +let prevH1 = -1; +let prevH2 = -1; +let prevM1 = -1; +let prevM2 = -1; + + +let points0 = [ + 0, 40, + 1, 35, + 7, 20, + 16, 8, + 28, 2, + 40, 0, + + 51, 2, + 63, 10, + 72, 20, + 77, 35, + 78, 40, + + 78, 59, + 77, 64, + 72, 79, + 63, 89, + 51, 97, + + 40, 99, + 28, 97, + 16, 91, + 7, 79, + 1, 64, + 0, 59, + 0, 40 +]; + +let points1 = [ 40, 99, 40, 0]; + +let points2 = [ 0, 25, + 2, 22, + 6, 13, + 17, 5, + 28, 2, + 40, 0, + 52, 2, + 63, 5, + 74, 13, + 79, 23, + 79, 28, + 74, 38, + 63, 46, + 51, 54, + 40, 58, + 29, 62, + 17, 68, + 8, 80, + 0, 99, + 79, 99 + ]; + +let points4 = [ 60, 99, 60, 0, 0, 75, 79, 75 ]; + +let points8 = [ + 40, 40, + 26, 42, + 15, 46, + 4, 56, + 1, 66, + 1, 77, + 6, 87, + 17, 94, + 28, 97, + 38, 99, + 42, 99, + 52, 97, + 63, 94, + 74, 87, + 79, 77, + 79, 66, + 75, 56, + 64, 46, + 54, 42, + 40, 40, + + 52, 39, + 62, 34, + 69, 29, + 72, 23, + 72, 19, + 69, 12, + 62, 6, + 52, 2, + 40, 0, + + 28, 2, + 18, 6, + 11, 12, + 8, 19, + 8, 23, + 11, 29, + 18, 34, + 28, 39, + 40, 40, + ]; + +let points6 = [ + 50, 0, + 4, 56, + 1, 66, + 1, 77, + 6, 87, + 17, 94, + 28, 97, + 40, 99, + 52, 97, + 63, 94, + 74, 87, + 79, 77, + 79, 66, + 75, 56, + 64, 46, + 52, 42, + 40, 40, + 26, 42, + 15, 46, + 4, 56, + ]; + +let points3 = [ + 1, 77, + 6, 87, + 17, 94, + 28, 97, + 40, 99, + 52, 97, + 63, 94, + 74, 87, + 79, 77, + 79, 66, + 75, 56, + 64, 46, + 52, 42, + 39, 40, + 79, 0, + 1, 0 + ]; + +let points7 = [ 0, 0, 79, 0, 30, 99 ]; + +let points9 = []; +let points5 = [ + 1, 77, + 6, 87, + 17, 94, + 28, 97, + 38, 99, + 42, 99, + 52, 97, + 63, 94, + 74, 87, + 79, 77, + 79, 66, + 75, 56, + 64, 46, + 54, 42, + 40, 40, + 26, 42, + 15, 46, + 27, 0, + 79, 0, + ]; + + +function drawPoints(points, x0, y0) { + + let x = points[0]*xs+x0, y = points[1]*ys+y0; + //g.drawEllipse(x-2, y-2, x+2, y+2); + g.moveTo(x, y); + for(let idx=1; idx*2 < points.length; idx ++) { + let x = points[idx*2]*xs+x0; + let y = points[idx*2+1]*ys+y0; + //g.drawEllipse(x-2, y-2, x+2, y+2); + g.lineTo(x, y); + } +} + +/* create 5 from 2 , and 9 from 6 */ +/* nope, we have a better 5; less authentic, but whatev +for (let idx=0; idx*2 < points2.length; idx++) { + points5[idx*2] = points2[idx*2]; + points5[idx*2+1] = 99-points2[idx*2+1]; +} +*/ +for (let idx=0; idx*2 < points6.length; idx++) { + points9[idx*2] = 79-points6[idx*2]; + points9[idx*2+1] = 99-points6[idx*2+1]; +} + +pointsArray = [points0, points1, points2, points3, points4, points5, points6, points7, points8, points9]; + +function eraseDigit(d, x, y) { + // first time draw + if(d < 0) return; + g.setColor("#000000"); + drawPoints(pointsArray[d], x-2, y-2); + drawPoints(pointsArray[d], x+2, y-2); + drawPoints(pointsArray[d], x-2, y+2); + drawPoints(pointsArray[d], x+2, y+2); + drawPoints(pointsArray[d], x-1, y-1); + drawPoints(pointsArray[d], x+1, y-1); + drawPoints(pointsArray[d], x-1, y+1); + drawPoints(pointsArray[d], x+1, y+1); +} + +function drawDigit(d, x, y) { + //g.drawEllipse(20+4*xs, 20, 20+(72 * xs), 20+(40*ys)); + //g.drawEllipse(20, 20+(40*ys), 20+(80 * xs), 20+(99*ys)); + //g.drawEllipse(20, 20, 20+(79 * xs), 20+(99*ys)); + g.setColor("#202020"); + for (let idx = pointsArray.length - 1; idx >= 0 ; idx--) { + if(idx == d) { + + g.setColor("#FF0000"); + drawPoints(pointsArray[d], x-2, y-2); + drawPoints(pointsArray[d], x+2, y-2); + drawPoints(pointsArray[d], x-2, y+2); + drawPoints(pointsArray[d], x+2, y+2); + g.setColor("#FF6000"); + drawPoints(pointsArray[d], x-1, y-1); + drawPoints(pointsArray[d], x+1, y-1); + drawPoints(pointsArray[d], x-1, y+1); + drawPoints(pointsArray[d], x+1, y+1); + + g.setColor("#FFC000"); + drawPoints(pointsArray[d], x, y); + + g.setColor("#202020"); + } else { + drawPoints(pointsArray[idx], x, y); + } + } + +} + +function drawTime() { + const mstr="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; + + let d = new Date(); + let hour = d.getHours(); + let minute = d.getMinutes(); + let month = d.getMonth(); + let date = d.getDate(); + + let h1 = Math.floor(hour / 10); + let h2 = hour % 10; + let m1 = Math.floor(minute / 10); + let m2 = minute % 10; + + if(h1 == prevH1 && h2 == prevH2 && m1 == prevM1 && m2 == prevM2) { + return; + } + + if(h1 != prevH1) { + eraseDigit(prevH1, 10, 80); + drawDigit(h1, 10, 80); + } + if(h2 != prevH2) { + eraseDigit(prevH2, 65, 80); + drawDigit(h2, 65, 80); + } + if(m1 != prevM1) { + eraseDigit(prevM1, 135, 80); + drawDigit(m1, 135, 80); + } + if(m2 != prevM2) { + eraseDigit(prevM2, 190, 80); + drawDigit(m2, 190, 80); + } + + g.setColor("#000000"); + g.fillRect(0, 10, 240, 24); + g.fillRect(0, 222, 240, 240); + g.setColor("#202020"); + g.drawLine(0, 24, 239, 24); + g.drawLine(0, 226, 239, 226); + g.setColor("#C06000"); + g.setFontAlign(0, -1); + g.drawString(mstr.slice(month*3,month*3+3) + " " + date, 120, 10); + g.setFontAlign(-1,-1); + g.drawString("STEP " + stepCounter, 0, 230); + g.setFontAlign(1,-1); + g.drawString("BTY "+E.getBattery(), 240, 230); + + + prevH1 = h1; + prevH2 = h2; + prevM1 = m1; + prevM2 = m2; + +} + +function stop () { + if (interval) { + clearInterval(interval); + } +} + +function start () { + if (interval) { + clearInterval(interval); + } + // first time init + interval = setInterval(drawTime, 10000); + drawTime(); +} + +start(); + + +Bangle.on('lcdPower', function (on) { + if (on) { + start(); + } else { + stop(); + } +}); + +function btn1Func() { + g.clear(); + prevH1 = -1; + prevH2 = -1; + prevM1 = -1; + prevM2 = -1; + drawTime(); +} + +function btn3Func() { + showMsg("This is a test message"); +} + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// redraw +setWatch(btn1Func, BTN1, {repeat:true,edge:"falling"}); +setWatch(btn3Func, BTN3, {repeat:true,edge:"falling"}); +Bangle.on('step', function(cnt) { + stepCounter = cnt / 10; +}); From 229fd1c672e1c81d9852d1534e45318ddb980fc2 Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Fri, 17 Jul 2020 14:42:25 -0400 Subject: [PATCH 0011/2129] Create nixie.info --- apps/nixie/nixie.info | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/nixie/nixie.info diff --git a/apps/nixie/nixie.info b/apps/nixie/nixie.info new file mode 100644 index 000000000..d9ac5129b --- /dev/null +++ b/apps/nixie/nixie.info @@ -0,0 +1 @@ +{"id":"jvNixie","name":"Nixie Clock","type":"clock","src":"nixie.app.js","sortorder":-1,"version":"0.1","files":"nixie.info,nixie.app.js"} From 8babc1ecf4c195ad0b4ca63afed725594a2c93cb Mon Sep 17 00:00:00 2001 From: yngv27 <61598758+yngv27@users.noreply.github.com> Date: Fri, 17 Jul 2020 14:58:08 -0400 Subject: [PATCH 0012/2129] Add files via upload Added night mode --- apps/nixie/nixie.app.js | 97 +++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/apps/nixie/nixie.app.js b/apps/nixie/nixie.app.js index c9fa068fe..f1cd245f1 100644 --- a/apps/nixie/nixie.app.js +++ b/apps/nixie/nixie.app.js @@ -1,4 +1,3 @@ - g.clear(); require("Font8x12").add(Graphics); @@ -9,7 +8,11 @@ let stepCounter = 0; let msgs = require("Storage").readJSON('yngv27.msgs.json'); let alarms = require("Storage").readJSON('yngv27.alarm.json'); +let alarming = false; +let nightMode = false; + function showMsg(msg) { + alarming = true; g.setFontAlign(0,-1); g.setColor(1,1,1); g.drawString("<< ALARM >>", 120, 180, true); @@ -214,9 +217,7 @@ let points5 = [ 79, 0, ]; - function drawPoints(points, x0, y0) { - let x = points[0]*xs+x0, y = points[1]*ys+y0; //g.drawEllipse(x-2, y-2, x+2, y+2); g.moveTo(x, y); @@ -228,13 +229,14 @@ function drawPoints(points, x0, y0) { } } -/* create 5 from 2 , and 9 from 6 */ -/* nope, we have a better 5; less authentic, but whatev +/* create 5 from 2 */ +/* uncomment if you want the 5 to look more authentic (but uglier) for (let idx=0; idx*2 < points2.length; idx++) { points5[idx*2] = points2[idx*2]; points5[idx*2+1] = 99-points2[idx*2+1]; } */ +/* create 9 from 6 */ for (let idx=0; idx*2 < points6.length; idx++) { points9[idx*2] = 79-points6[idx*2]; points9[idx*2+1] = 99-points6[idx*2+1]; @@ -243,10 +245,13 @@ for (let idx=0; idx*2 < points6.length; idx++) { pointsArray = [points0, points1, points2, points3, points4, points5, points6, points7, points8, points9]; function eraseDigit(d, x, y) { - // first time draw if(d < 0) return; g.setColor("#000000"); - drawPoints(pointsArray[d], x-2, y-2); + if(nightMode) { + drawPoints(pointsArray[d], x, y); + return; + } + drawPoints(pointsArray[d], x-2, y-2); drawPoints(pointsArray[d], x+2, y-2); drawPoints(pointsArray[d], x-2, y+2); drawPoints(pointsArray[d], x+2, y+2); @@ -257,13 +262,14 @@ function eraseDigit(d, x, y) { } function drawDigit(d, x, y) { - //g.drawEllipse(20+4*xs, 20, 20+(72 * xs), 20+(40*ys)); - //g.drawEllipse(20, 20+(40*ys), 20+(80 * xs), 20+(99*ys)); - //g.drawEllipse(20, 20, 20+(79 * xs), 20+(99*ys)); + if(nightMode) { + g.setColor("#206040"); + drawPoints(pointsArray[d], x, y); + return; + } g.setColor("#202020"); for (let idx = pointsArray.length - 1; idx >= 0 ; idx--) { if(idx == d) { - g.setColor("#FF0000"); drawPoints(pointsArray[d], x-2, y-2); drawPoints(pointsArray[d], x+2, y-2); @@ -274,7 +280,7 @@ function drawDigit(d, x, y) { drawPoints(pointsArray[d], x+1, y-1); drawPoints(pointsArray[d], x-1, y+1); drawPoints(pointsArray[d], x+1, y+1); - + g.setColor("#FFC000"); drawPoints(pointsArray[d], x, y); @@ -283,12 +289,11 @@ function drawDigit(d, x, y) { drawPoints(pointsArray[idx], x, y); } } - } - + function drawTime() { const mstr="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; - + let d = new Date(); let hour = d.getHours(); let minute = d.getMinutes(); @@ -303,7 +308,7 @@ function drawTime() { if(h1 == prevH1 && h2 == prevH2 && m1 == prevM1 && m2 == prevM2) { return; } - + if(h1 != prevH1) { eraseDigit(prevH1, 10, 80); drawDigit(h1, 10, 80); @@ -315,32 +320,47 @@ function drawTime() { if(m1 != prevM1) { eraseDigit(prevM1, 135, 80); drawDigit(m1, 135, 80); - } + } if(m2 != prevM2) { eraseDigit(prevM2, 190, 80); drawDigit(m2, 190, 80); - } - - g.setColor("#000000"); - g.fillRect(0, 10, 240, 24); - g.fillRect(0, 222, 240, 240); - g.setColor("#202020"); - g.drawLine(0, 24, 239, 24); - g.drawLine(0, 226, 239, 226); - g.setColor("#C06000"); - g.setFontAlign(0, -1); - g.drawString(mstr.slice(month*3,month*3+3) + " " + date, 120, 10); - g.setFontAlign(-1,-1); - g.drawString("STEP " + stepCounter, 0, 230); - g.setFontAlign(1,-1); - g.drawString("BTY "+E.getBattery(), 240, 230); + } + if(!nightMode) { + g.setColor("#000000"); + g.fillRect(0, 10, 240, 24); + g.fillRect(0, 222, 240, 240); + g.setColor("#202020"); + g.drawLine(0, 24, 239, 24); + g.drawLine(0, 226, 239, 226); + g.setColor("#C06000"); + g.setFontAlign(0, -1); + g.drawString(mstr.slice(month*3,month*3+3) + " " + date, 120, 10); + g.setFontAlign(-1,-1); + g.drawString("STEP " + stepCounter, 0, 230); + g.setFontAlign(1,-1); + g.drawString("BTY "+E.getBattery(), 240, 230); + } - prevH1 = h1; prevH2 = h2; prevM1 = m1; prevM2 = m2; - + +} + +function btn1Func() { + if(alarming) { + alarming = false; + } else { + nightMode = !nightMode; + g.setRotation(nightMode ? 1 : 0, 0); + } + g.clear(); + prevH1 = -1; + prevH2 = -1; + prevM1 = -1; + prevM2 = -1; + drawTime(); } function stop () { @@ -353,7 +373,6 @@ function start () { if (interval) { clearInterval(interval); } - // first time init interval = setInterval(drawTime, 10000); drawTime(); } @@ -369,14 +388,6 @@ Bangle.on('lcdPower', function (on) { } }); -function btn1Func() { - g.clear(); - prevH1 = -1; - prevH2 = -1; - prevM1 = -1; - prevM2 = -1; - drawTime(); -} function btn3Func() { showMsg("This is a test message"); From 1efadb816d2c344ff98d947aedb77500742ca0f5 Mon Sep 17 00:00:00 2001 From: Francesco Bedussi Date: Fri, 5 Feb 2021 22:47:32 +0100 Subject: [PATCH 0013/2129] fix(large clock): font size --- apps/largeclock/ChangeLog | 1 + apps/largeclock/largeclock.js | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/largeclock/ChangeLog b/apps/largeclock/ChangeLog index d06cc9edf..851829fcc 100644 --- a/apps/largeclock/ChangeLog +++ b/apps/largeclock/ChangeLog @@ -5,3 +5,4 @@ 0.05: Add support for 12 hour time 0.06: Allow to disable BTN1 and BTN3 buttons 0.07: Don't clear all intervals during initialisation +0.08: fix font size diff --git a/apps/largeclock/largeclock.js b/apps/largeclock/largeclock.js index 24127ac15..34409797c 100644 --- a/apps/largeclock/largeclock.js +++ b/apps/largeclock/largeclock.js @@ -140,13 +140,13 @@ function drawTime(d) { g.clearRect(0, 24, moonX - moonR - 10, 239); g.setColor(1, 1, 1); g.setFontAlign(-1, -1); - g.setFont("Vector", 100); + g.setFont("Vector", 130); g.drawString(hours, 40, 24, true); g.setColor(1, 50, 1); - g.drawString(minutes, 40, 135, true); + g.drawString(minutes, 40, 130, true); g.setFont("Vector", 20); g.setRotation(3); - g.drawString(`${dow} ${day} ${month}`, 50, 10, true); + g.drawString(`${dow} ${day} ${month}`, 60, 10, true); g.drawString(year, is12Hour ? 46 : 75, 205, true); lastMinutes = minutes; } From e10a7527fe24496c475b5df3e95ef0d8e54d5685 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sat, 15 May 2021 20:27:33 +0100 Subject: [PATCH 0014/2129] Sweep clock - reduce memory footprint --- apps/sweepclock/sweepclock.js | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/apps/sweepclock/sweepclock.js b/apps/sweepclock/sweepclock.js index df6b09e3d..780b9ac0a 100644 --- a/apps/sweepclock/sweepclock.js +++ b/apps/sweepclock/sweepclock.js @@ -15,46 +15,40 @@ const color_schemes = [ name: "black", background : [0.0,0.0,0.0], second_hand: [1.0,0.0,0.0], - minute_hand: [1.0,1.0,1.0], - hour_hand: [1.0,1.0,1.0], - numeral:[1.0,1.0,1.0] }, { name: "red", background : [1.0,0.0,0.0], second_hand: [1.0,1.0,0.0], - minute_hand: [1.0,1.0,1.0], - hour_hand: [1.0,1.0,1.0], - numeral:[1.0,1.0,1.0] }, { name: "grey", background : [0.5,0.5,0.5], second_hand: [0.0,0.0,0.0], - minute_hand: [1.0,1.0,1.0], - hour_hand: [1.0,1.0,1.0], - numeral:[1.0,1.0,1.0] }, { name: "purple", background : [1.0,0.0,1.0], second_hand: [1.0,1.0,0.0], - minute_hand: [1.0,1.0,1.0], - hour_hand: [1.0,1.0,1.0], - numeral:[1.0,1.0,1.0] }, { name: "blue", background : [0.4,0.7,1.0], second_hand: [0.5,0.5,0.5], - minute_hand: [1.0,1.0,1.0], - hour_hand: [1.0,1.0,1.0], - numeral:[1.0,1.0,1.0] } ]; let color_scheme_index = 0; +var WHITE = [1.0,1.0,1.0]; +function default_white(color){ + if(color == null){ + return WHITE + } else { + return color; + } +} + class Hand { /** * Pure virtual class for all Hand classes to extend. @@ -106,7 +100,7 @@ class ThinHand extends Hand { g.setColor(background[0],background[1],background[2]); g.drawLine(this.centerX, this.centerY, this.last_x, this.last_y); // Now draw the new hand line - var hand_color = color_schemes[color_scheme_index][this.color_theme]; + var hand_color = default_white(color_schemes[color_scheme_index][this.color_theme]); g.setColor(hand_color[0],hand_color[1],hand_color[2]); var x2 = this.centerX + this.length*Math.sin(angle); var y2 = this.centerY - this.length*Math.cos(angle); @@ -196,7 +190,7 @@ class ThickHand extends Hand { // top left var x4 = this.centerX + this.vertex_radius_top*Math.sin(angle - this.delta_top); var y4 = this.centerY - this.vertex_radius_top*Math.cos(angle - this.delta_top); - var hand_color = color_schemes[color_scheme_index][this.color_theme]; + var hand_color = default_white(color_schemes[color_scheme_index][this.color_theme]); g.setColor(hand_color[0],hand_color[1],hand_color[2]); g.fillPoly([x1,y1, x2,y2, @@ -297,7 +291,7 @@ function draw_date(date){ var coords = date_coords[date_coord_index].coords; if(coords != null) { var date_format = local.dow(date,1) + " " + date.getDate(); - var numeral_color = color_schemes[color_scheme_index].numeral; + var numeral_color = default_white(color_schemes[color_scheme_index].numeral); g.setColor(numeral_color[0], numeral_color[1], numeral_color[2]); g.drawString(date_format, coords[0], coords[1]); last_date = date; @@ -319,7 +313,7 @@ function next_datecoords() { function set_datecoords(date_name){ console.log("setting date:" + date_name); for (var i=0; i < date_coords.length; i++) { - if(date_coords[i].getName() == date_name){ + if(date_coords[i].name == date_name){ date_coord_index = i; force_redraw = true; console.log("date match"); @@ -596,7 +590,7 @@ class HourScriber { } if(changed || this.draw_test(this.angle_from, this.angle_to, this.last_draw_time) ){ - var numeral_color = color_schemes[color_scheme_index].numeral; + var numeral_color = default_white(color_schemes[color_scheme_index].numeral); g.setColor(numeral_color[0],numeral_color[1],numeral_color[2]); this.numeral_font.draw(this.curr_hour_str,this.curr_hour_x,this.curr_hour_y); this.last_draw_time = new Date(); From 3fe4cd2515f4889663cde306b5155e73adeb9eb2 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sat, 15 May 2021 20:30:57 +0100 Subject: [PATCH 0015/2129] SweepClock - uppped version number --- apps.json | 2 +- apps/sweepclock/ChangeLog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 7941cdb17..2c538a97a 100644 --- a/apps.json +++ b/apps.json @@ -242,7 +242,7 @@ { "id": "sweepclock", "name": "Sweep Clock", "icon": "sweepclock.png", - "version":"0.03", + "version":"0.04", "description": "Smooth sweep secondhand with single hour numeral. Use button1 to toggle the numeral font, button 3 to change the colour theme and button 4 to change the date placement", "tags": "clock", "type":"clock", diff --git a/apps/sweepclock/ChangeLog b/apps/sweepclock/ChangeLog index 8eeb95c09..23841b299 100644 --- a/apps/sweepclock/ChangeLog +++ b/apps/sweepclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: Initial Release 0.02: Added Colour Themes 0.03: Added Date +0.04: Memory Footprint reduction From 3730e6a6ba7c1023c0366183212790a87d8d4e6e Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sun, 16 May 2021 12:04:40 +0100 Subject: [PATCH 0016/2129] Sweep clock: memory effeciency part 2. Changing out JSON maps for switch statements in Fonts to save another 8% of memory --- apps/sweepclock/sweepclock.js | 115 +++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/apps/sweepclock/sweepclock.js b/apps/sweepclock/sweepclock.js index 780b9ac0a..0f948c7c0 100644 --- a/apps/sweepclock/sweepclock.js +++ b/apps/sweepclock/sweepclock.js @@ -276,6 +276,7 @@ var date_coords = [ { name: "topleft", coords:[5,30]}, { name: "offscreen", coords: [240,30]} ]; + var date_coord_index = 0; function draw_date(date){ @@ -388,24 +389,28 @@ class NoFont extends NumeralFont{ class CopasetFont extends NumeralFont{ constructor(){ super(); - // dimesion map provides the dimesions of the character for - // each number for plotting and collision detection - this.dimension_map = { - 1 : [20,58], - 2 : [30,58], - 3 : [30,58], - 4 : [30,58], - 5 : [30,58], - 6 : [40,58], - 7 : [30,58], - 8 : [40,58], - 9 : [40,58], - 10: [50,58], - 11: [40,58], - 12: [40,58] - }; } - getDimensions(hour){return this.dimension_map[hour];} + getDimensions(hour){ + switch(hour){ + case 1: return [20,58]; + case 2: + case 3: + case 4: + case 5: + case 7: + return [30,58]; + case 6: + case 8: + case 9: + case 11: + case 12: + return [40,58]; + case 10: + return [50,58]; + default: + return [30,58]; + } + } hour_txt(hour){ return hour.toString(); } draw(hour_txt,x,y){ /* going to leave this in here for future testing. @@ -430,40 +435,50 @@ class CopasetFont extends NumeralFont{ class RomanNumeralFont extends NumeralFont{ constructor(){ super(); - // text map provides the mapping between hour and roman numeral - this.txt_map = { - 1 : 'I', - 2 : 'II', - 3 : 'III', - 4 : 'IV', - 5 : 'V', - 6 : 'VI', - 7 : 'VII', - 8 : 'VIII', - 9 : 'IX', - 10: 'X', - 11: 'XI', - 12: 'XII' - }; - // dimesion map provides the dimesions of the characters for - // each hour for plotting and collision detection - this.dimension_map = { - 1 : [10,40], - 2 : [25,40], - 3 : [40,40], - 4 : [40,40], - 5 : [30,40], - 6 : [40,40], - 7 : [60,40], - 8 : [70,40], - 9 : [40,40], - 10: [20,40], - 11: [40,40], - 12: [60,40] - }; } - getDimensions(hour){ return this.dimension_map[hour];} - hour_txt(hour){ return this.txt_map[hour]; } + getText(hour){ + switch (hour){ + case 1 : return 'I'; + case 2 : return 'II'; + case 3 : return 'III'; + case 4 : return 'IV'; + case 5 : return 'V'; + case 6 : return 'VI'; + case 7 : return 'VII'; + case 8 : return 'VIII'; + case 9 : return 'IX'; + case 10: return 'X'; + case 11: return 'XI'; + case 12: return 'XII'; + default: return ''; + } + } + getDimensions(hour){ + switch (hour){ + case 1: + return [10,40]; + case 2: + return [25,40]; + case 3: + case 4: + case 6: + case 9: + case 11: + case 12: + return [40,40]; + case 5: + return [30,40]; + case 7: + return [60,40]; + case 8: + return [70,40]; + case 10: + return [20,40]; + default: + return [40,40]; + } + } + hour_txt(hour){ return this.getText(hour); } draw(hour_txt,x,y){ g.setFontAlign(-1,-1,0); g.setFont("Vector",40); From 144e8b05e7288384535ca693d79eee3adbd86c28 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sun, 16 May 2021 12:14:13 +0100 Subject: [PATCH 0017/2129] Sweepclock: fixed typo in description --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 2c538a97a..33cf540bc 100644 --- a/apps.json +++ b/apps.json @@ -243,7 +243,7 @@ "name": "Sweep Clock", "icon": "sweepclock.png", "version":"0.04", - "description": "Smooth sweep secondhand with single hour numeral. Use button1 to toggle the numeral font, button 3 to change the colour theme and button 4 to change the date placement", + "description": "Smooth sweep secondhand with single hour numeral. Use button 1 to toggle the numeral font, button 3 to change the colour theme and button 4 to change the date placement", "tags": "clock", "type":"clock", "allow_emulator":true, From a2ba365a07c93c8b3505caefce2b26fe3b0b615e Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sun, 16 May 2021 14:45:34 +0100 Subject: [PATCH 0018/2129] sweepclock: fixing README page --- apps/sweepclock/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/sweepclock/README.md b/apps/sweepclock/README.md index cbdb2a3f8..121c7b0e9 100644 --- a/apps/sweepclock/README.md +++ b/apps/sweepclock/README.md @@ -12,7 +12,7 @@ Use Button 1 (the top right button) to change the numeral type | Default clock face | Roman Numeral Font | No Digits | | ---- | ---- | ---- | -| ![](./numeral-01.jpg) | ![](numeral-02.jpg) | ![](numeral-03.jpg) | +| ![](numeral-01.jpg) | ![](numeral-02.jpg) | ![](numeral-03.jpg) | @@ -21,14 +21,14 @@ Button 3 (bottom right button) is used to change the colour | Red | Grey | Purple | | ---- | ---- | ---- | -| ![](./color-01.jpg) | ![](color-02.jpg) | ![](color-03.jpg) | +| ![](color-01.jpg) | ![](color-02.jpg) | ![](color-03.jpg) | ### Button 4 -Button 4 (bottom left of screen) is used to change the date positioning (or to remove from the screen) +Button 4 (bottom left of the screen) is used to change the date position. Note after cycling through the date positions there is the no date option. | Top Right | Bottom Right | Bottom Left | Top Left | | ---- | ---- | ---- | ---- | -| ![](./date-01.jpg) | ![](date-02.jpg) | ![](date-03.jpg) | ![](date-04.jpg) | +| ![](date-01.jpg) | ![](date-02.jpg) | ![](date-03.jpg) | ![](date-04.jpg) | ## Further Details From 193b880ffb8b076c8e7c0d7986e818f2d05bdae0 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sun, 16 May 2021 20:04:32 +0100 Subject: [PATCH 0019/2129] sweepclock: Added a memory printout to the console so the memory usage can be followed when connected --- apps/sweepclock/sweepclock.js | 348 ++++++++++++++++++---------------- 1 file changed, 182 insertions(+), 166 deletions(-) diff --git a/apps/sweepclock/sweepclock.js b/apps/sweepclock/sweepclock.js index 0f948c7c0..777bafd8b 100644 --- a/apps/sweepclock/sweepclock.js +++ b/apps/sweepclock/sweepclock.js @@ -1,8 +1,8 @@ /** -* Adrian Kirk 2021-03 -* Simple Clock showing 1 numeral for the hour -* with a smooth sweep second. -*/ + * Adrian Kirk 2021-03 + * Simple Clock showing 1 numeral for the hour + * with a smooth sweep second. + */ const screen_center_x = g.getWidth()/2; const screen_center_y = 10 + g.getHeight()/2; @@ -11,39 +11,39 @@ const TWO_PI = 2*Math.PI; require("FontCopasetic40x58Numeric").add(Graphics); const color_schemes = [ - { - name: "black", - background : [0.0,0.0,0.0], - second_hand: [1.0,0.0,0.0], - }, - { - name: "red", - background : [1.0,0.0,0.0], - second_hand: [1.0,1.0,0.0], - }, - { - name: "grey", - background : [0.5,0.5,0.5], - second_hand: [0.0,0.0,0.0], - }, - { - name: "purple", - background : [1.0,0.0,1.0], - second_hand: [1.0,1.0,0.0], - }, - { - name: "blue", - background : [0.4,0.7,1.0], - second_hand: [0.5,0.5,0.5], - } - ]; + { + name: "black", + background : [0.0,0.0,0.0], + second_hand: [1.0,0.0,0.0], + }, + { + name: "red", + background : [1.0,0.0,0.0], + second_hand: [1.0,1.0,0.0], + }, + { + name: "grey", + background : [0.5,0.5,0.5], + second_hand: [0.0,0.0,0.0], + }, + { + name: "purple", + background : [1.0,0.0,1.0], + second_hand: [1.0,1.0,0.0], + }, + { + name: "blue", + background : [0.4,0.7,1.0], + second_hand: [0.5,0.5,0.5], + } +]; let color_scheme_index = 0; -var WHITE = [1.0,1.0,1.0]; +const WHITE = [1.0,1.0,1.0]; function default_white(color){ if(color == null){ - return WHITE + return WHITE; } else { return color; } @@ -51,24 +51,24 @@ function default_white(color){ class Hand { /** - * Pure virtual class for all Hand classes to extend. - * a hand class will have 1 main function - * moveTo which will move the hand to the given angle. - */ + * Pure virtual class for all Hand classes to extend. + * a hand class will have 1 main function + * moveTo which will move the hand to the given angle. + */ moveTo(angle){} } class ThinHand extends Hand { /** - * The thin hand is created from a simple line, so its easy and fast - * to draw. - */ + * The thin hand is created from a simple line, so its easy and fast + * to draw. + */ constructor(centerX, - centerY, - length, - tolerance, - draw_test, - color_theme){ + centerY, + length, + tolerance, + draw_test, + color_theme){ super(); this.centerX = centerX; this.centerY = centerY; @@ -93,8 +93,8 @@ class ThinHand extends Hand { // first test to see of the angle called is beyond the tolerance // for a redraw if(Math.abs(angle - this.angle) > this.tolerance || - // and then call the predicate to see if a redraw is needed - this.draw_test(this.angle,this.last_draw_time) ){ + // and then call the predicate to see if a redraw is needed + this.draw_test(this.angle,this.last_draw_time) ){ // rub out the old hand line var background = color_schemes[color_scheme_index].background; g.setColor(background[0],background[1],background[2]); @@ -119,17 +119,17 @@ class ThinHand extends Hand { class ThickHand extends Hand { /** - * The thick hand is created from a filled polygone, so its slower to - * draw so to be used sparingly with few redraws - */ + * The thick hand is created from a filled polygone, so its slower to + * draw so to be used sparingly with few redraws + */ constructor(centerX, - centerY, - length, - tolerance, - draw_test, - color_theme, - base_height, - thickness){ + centerY, + length, + tolerance, + draw_test, + color_theme, + base_height, + thickness){ super(); this.centerX = centerX; this.centerY = centerY; @@ -168,21 +168,21 @@ class ThickHand extends Hand { var background = color_schemes[color_scheme_index].background; g.setColor(background[0],background[1],background[2]); g.fillPoly([this.last_x1, - this.last_y1, - this.last_x2, - this.last_y2, - this.last_x3, - this.last_y3, - this.last_x4, - this.last_y4 - ]); + this.last_y1, + this.last_x2, + this.last_y2, + this.last_x3, + this.last_y3, + this.last_x4, + this.last_y4 + ]); // bottom left var x1 = this.centerX + - this.vertex_radius_base*Math.sin(angle - this.delta_base); + this.vertex_radius_base*Math.sin(angle - this.delta_base); var y1 = this.centerY - this.vertex_radius_base*Math.cos(angle - this.delta_base); // bottom right var x2 = this.centerX + - this.vertex_radius_base*Math.sin(angle + this.delta_base); + this.vertex_radius_base*Math.sin(angle + this.delta_base); var y2 = this.centerY - this.vertex_radius_base*Math.cos(angle + this.delta_base); // top right var x3 = this.centerX + this.vertex_radius_top*Math.sin(angle + this.delta_top); @@ -193,10 +193,10 @@ class ThickHand extends Hand { var hand_color = default_white(color_schemes[color_scheme_index][this.color_theme]); g.setColor(hand_color[0],hand_color[1],hand_color[2]); g.fillPoly([x1,y1, - x2,y2, - x3,y3, - x4,y4 - ]); + x2,y2, + x3,y3, + x4,y4 + ]); this.last_x1 = x1; this.last_y1 = y1; this.last_x2 = x2; @@ -216,7 +216,7 @@ class ThickHand extends Hand { // The force draw is set to true to force all objects to redraw themselves let force_redraw = false; // The seconds hand is the main focus and is set to redraw on every cycle -let seconds_hand = new ThinHand(screen_center_x, +let seconds_hand = new ThinHand(screen_center_x, screen_center_y, 95, 0, @@ -228,8 +228,8 @@ let seconds_hand = new ThinHand(screen_center_x, // or when a force_redraw is called let minutes_hand_redraw = function(angle, last_draw_time){ return force_redraw || (seconds_hand.angle > angle && - Math.abs(seconds_hand.angle - angle) 500); + Math.abs(seconds_hand.angle - angle) 500); }; let minutes_hand = new ThinHand(screen_center_x, screen_center_y, @@ -242,10 +242,10 @@ let minutes_hand = new ThinHand(screen_center_x, // overlaps from its behind andle coverage to its ahead angle coverage. let hour_hand_redraw = function(angle_from, angle_to, last_draw_time){ return force_redraw || (seconds_hand.angle >= angle_from && - seconds_hand.angle <= angle_to && - new Date().getTime() - last_draw_time.getTime() > 500); + seconds_hand.angle <= angle_to && + new Date().getTime() - last_draw_time.getTime() > 500); }; -let hours_hand = new ThickHand(screen_center_x, +let hours_hand = new ThickHand(screen_center_x, screen_center_y, 40, TWO_PI/600, @@ -269,8 +269,8 @@ var local = require('locale'); var last_date = null; var last_datestr = null; var last_coords = null; -var date_coords = [ - { name: "topright", coords:[180,30]}, +const date_coords = [ + { name: "topright", coords:[180,30]}, { name: "bottomright", coords:[180,220]}, { name: "bottomleft", coords: [5,220]}, { name: "topleft", coords:[5,30]}, @@ -280,26 +280,26 @@ var date_coords = [ var date_coord_index = 0; function draw_date(date){ - if(force_redraw || last_date == null || last_date.getDate() != date.getDate()){ - //console.log("redrawing date"); - g.setFontAlign(-1,-1,0); - g.setFont("Vector",15); - if(last_coords != null && last_datestr != null) { - var background = color_schemes[color_scheme_index].background; - g.setColor(background[0], background[1], background[2]); - g.drawString(last_datestr, last_coords[0], last_coords[1]); - } - var coords = date_coords[date_coord_index].coords; - if(coords != null) { - var date_format = local.dow(date,1) + " " + date.getDate(); - var numeral_color = default_white(color_schemes[color_scheme_index].numeral); - g.setColor(numeral_color[0], numeral_color[1], numeral_color[2]); - g.drawString(date_format, coords[0], coords[1]); - last_date = date; - last_datestr = date_format; - last_coords = coords; - } - } + if(force_redraw || last_date == null || last_date.getDate() != date.getDate()){ + //console.log("redrawing date"); + g.setFontAlign(-1,-1,0); + g.setFont("Vector",15); + if(last_coords != null && last_datestr != null) { + var background = color_schemes[color_scheme_index].background; + g.setColor(background[0], background[1], background[2]); + g.drawString(last_datestr, last_coords[0], last_coords[1]); + } + var coords = date_coords[date_coord_index].coords; + if(coords != null) { + var date_format = local.dow(date,1) + " " + date.getDate(); + var numeral_color = default_white(color_schemes[color_scheme_index].numeral); + g.setColor(numeral_color[0], numeral_color[1], numeral_color[2]); + g.drawString(date_format, coords[0], coords[1]); + last_date = date; + last_datestr = date_format; + last_coords = coords; + } + } } function next_datecoords() { @@ -354,17 +354,17 @@ function draw_hours(date){ } /** -* We want to be able to change the font so we set up -* pure virtual for all fonts implementtions to use -*/ + * We want to be able to change the font so we set up + * pure virtual for all fonts implementtions to use + */ class NumeralFont { /** - * The screen dimensions of what we are going to - * display for the given hour. - */ + * The screen dimensions of what we are going to + * display for the given hour. + */ getDimensions(hour){return [0,0];} /** - * The characters that are going to be returned for + * The characters that are going to be returned for * the hour. */ hour_txt(hour){ return ""; } @@ -386,29 +386,34 @@ class NoFont extends NumeralFont{ getName(){return "NoFont";} } +const COPASET_DIM_20x58 = [20,58]; +const COPASET_DIM_30x58 = [30,58]; +const COPASET_DIM_40x58 = [40,58]; +const COPASET_DIM_50x58 = [50,58]; + class CopasetFont extends NumeralFont{ constructor(){ super(); } getDimensions(hour){ switch(hour){ - case 1: return [20,58]; + case 1: return COPASET_DIM_20x58; case 2: case 3: case 4: case 5: case 7: - return [30,58]; + return COPASET_DIM_30x58; case 6: case 8: case 9: case 11: case 12: - return [40,58]; + return COPASET_DIM_40x58; case 10: - return [50,58]; + return COPASET_DIM_50x58; default: - return [30,58]; + return COPASET_DIM_30x58; } } hour_txt(hour){ return hour.toString(); } @@ -431,7 +436,13 @@ class CopasetFont extends NumeralFont{ getName(){return "Copaset";} } - +const ROMAN_DIM_10x40 = [10,40]; +const ROMAN_DIM_20x40 = [20,40]; +const ROMAN_DIM_25x40 = [25,40]; +const ROMAN_DIM_30x40 = [30,40]; +const ROMAN_DIM_40x40 = [40,40]; +const ROMAN_DIM_60x40 = [60,40]; +const ROMAN_DIM_70x40 = [70,40]; class RomanNumeralFont extends NumeralFont{ constructor(){ super(); @@ -456,26 +467,26 @@ class RomanNumeralFont extends NumeralFont{ getDimensions(hour){ switch (hour){ case 1: - return [10,40]; + return ROMAN_DIM_10x40; case 2: - return [25,40]; + return ROMAN_DIM_25x40; case 3: case 4: case 6: case 9: case 11: case 12: - return [40,40]; + return ROMAN_DIM_40x40; case 5: - return [30,40]; + return ROMAN_DIM_30x40; case 7: - return [60,40]; + return ROMAN_DIM_60x40; case 8: - return [70,40]; + return ROMAN_DIM_70x40; case 10: - return [20,40]; + return ROMAN_DIM_20x40; default: - return [40,40]; + return ROMAN_DIM_40x40; } } hour_txt(hour){ return this.getText(hour); } @@ -487,9 +498,9 @@ class RomanNumeralFont extends NumeralFont{ getName(){return "Roman";} } -// The problem with the trig inverse functions on +// The problem with the trig inverse functions on // a full circle is that the sector information will be lost -// Choosing to use arcsin because you can get back the +// Choosing to use arcsin because you can get back the // sector with the help of the original coordinates function reifyasin(x,y,asin_angle){ if(x >= 0 && y >= 0){ @@ -503,7 +514,7 @@ function reifyasin(x,y,asin_angle){ } } -// rebase and angle so be between -pi and pi +// rebase and angle so be between -pi and pi // rather than 0 to 2PI function rebaseNegative(angle){ if(angle > Math.PI){ @@ -524,10 +535,10 @@ function rebasePositive(angle){ } /** -* The Hour Scriber is responsible for drawing the numeral -* on the screen at the requested angle. -* It allows for the font to be changed on the fly. -*/ + * The Hour Scriber is responsible for drawing the numeral + * on the screen at the requested angle. + * It allows for the font to be changed on the fly. + */ class HourScriber { constructor(radius, numeral_font, draw_test){ this.radius = radius; @@ -549,8 +560,8 @@ class HourScriber { var background = color_schemes[color_scheme_index].background; g.setColor(background[0],background[1],background[2]); this.curr_numeral_font.draw(this.curr_hour_str, - this.curr_hour_x, - this.curr_hour_y); + this.curr_hour_x, + this.curr_hour_y); //console.log("erasing old hour"); var hours_frac = hours / 12; var angle = TWO_PI*hours_frac; @@ -564,7 +575,7 @@ class HourScriber { this.curr_hour_x = screen_center_x + delta_center_x; this.curr_hour_y = screen_center_y - delta_center_y; this.curr_hour_str = this.numeral_font.hour_txt(hours); - // now work out the angle of the beginning and the end of the + // now work out the angle of the beginning and the end of the // text box so we know when to redraw // bottom left angle var x1 = delta_center_x; @@ -592,10 +603,10 @@ class HourScriber { angle3 = rebaseNegative(angle3); angle3 = rebaseNegative(angle4); this.angle_from = rebasePositive( Math.min(angle1,angle2,angle3,angle4) ); - this.angle_to = rebasePositive( Math.max(angle1,angle2,angle3,angle4) ); + this.angle_to = rebasePositive( Math.max(angle1,angle2,angle3,angle4) ); } else { this.angle_from = Math.min(angle1,angle2,angle3,angle4); - this.angle_to = Math.max(angle1,angle2,angle3,angle4); + this.angle_to = Math.max(angle1,angle2,angle3,angle4); } //console.log(angle1 + "/" + angle2 + " / " + angle3 + " / " + angle4); //console.log( this.angle_from + " to " + this.angle_to); @@ -604,7 +615,7 @@ class HourScriber { changed = true; } if(changed || - this.draw_test(this.angle_from, this.angle_to, this.last_draw_time) ){ + this.draw_test(this.angle_from, this.angle_to, this.last_draw_time) ){ var numeral_color = default_white(color_schemes[color_scheme_index].numeral); g.setColor(numeral_color[0],numeral_color[1],numeral_color[2]); this.numeral_font.draw(this.curr_hour_str,this.curr_hour_x,this.curr_hour_y); @@ -617,43 +628,43 @@ class HourScriber { let numeral_fonts = [new CopasetFont(), new RomanNumeralFont(), new NoFont()]; let numeral_fonts_index = 0; /** -* predicate for deciding when the digit has to be redrawn -*/ -let hour_numeral_redraw = function(angle_from, angle_to, last_draw_time){ + * predicate for deciding when the digit has to be redrawn + */ +let hour_numeral_redraw = function(angle_from, angle_to, last_draw_time){ var seconds_hand_angle = seconds_hand.angle; - // we have to cope with the 12 problem where the + // we have to cope with the 12 problem where the // left side of the box has a value almost 2PI and the right // side has a small positive value. The values are rebased so // that they can be compared if(angle_from > angle_to && angle_from > 1.5*Math.PI){ angle_from = angle_from - TWO_PI; if(seconds_hand_angle > Math.PI) - seconds_hand_angle = seconds_hand_angle - TWO_PI; - } + seconds_hand_angle = seconds_hand_angle - TWO_PI; + } //console.log("initial:" + angle_from + "/" + angle_to + " seconds " + seconds_hand_angle); - var redraw = force_redraw || - (seconds_hand_angle >= angle_from && seconds_hand_angle <= angle_to) || - (minutes_hand.last_draw_time.getTime() > last_draw_time.getTime()); + var redraw = force_redraw || + (seconds_hand_angle >= angle_from && seconds_hand_angle <= angle_to) || + (minutes_hand.last_draw_time.getTime() > last_draw_time.getTime()); if(redraw){ - //console.log(angle_from + "/" + angle_to + " seconds " + seconds_hand_angle); + //console.log(angle_from + "/" + angle_to + " seconds " + seconds_hand_angle); } return redraw; }; let hour_scriber = new HourScriber(70, - numeral_fonts[numeral_fonts_index], - hour_numeral_redraw - ); + numeral_fonts[numeral_fonts_index], + hour_numeral_redraw +); /** -* Called from button 1 to change the numerals that are -* displayed on the clock face -*/ + * Called from button 1 to change the numerals that are + * displayed on the clock face + */ function next_font(){ numeral_fonts_index = numeral_fonts_index + 1; if(numeral_fonts_index >= numeral_fonts.length){ numeral_fonts_index = 0; } hour_scriber.setNumeralFont( - numeral_fonts[numeral_fonts_index]); + numeral_fonts[numeral_fonts_index]); force_redraw = true; } @@ -674,10 +685,10 @@ function draw_background(){ var background = color_schemes[color_scheme_index].background; g.setColor(background[0],background[1],background[2]); g.fillPoly([0,25, - 0,240, - 240,240, - 240,25 - ]); + 0,240, + 240,240, + 240,25 + ]); } } @@ -689,9 +700,9 @@ function next_colorscheme(){ } /** -* called from load_settings on startup to -* set the color scheme to named value -*/ + * called from load_settings on startup to + * set the color scheme to named value + */ function set_colorscheme(colorscheme_name){ console.log("setting color scheme:" + colorscheme_name); for (var i=0; i < color_schemes.length; i++) { @@ -705,9 +716,9 @@ function set_colorscheme(colorscheme_name){ } /** -* called from load_settings on startup -* to set the font to named value -*/ + * called from load_settings on startup + * to set the font to named value + */ function set_font(font_name){ console.log("setting font:" + font_name); for (var i=0; i < numeral_fonts.length; i++) { @@ -722,8 +733,8 @@ function set_font(font_name){ } /** -* Called on startup to set the watch to the last preference settings -*/ + * Called on startup to set the watch to the last preference settings + */ function load_settings(){ try{ var settings = require("Storage").readJSON("sweepclock.settings.json"); @@ -746,9 +757,15 @@ function load_settings(){ } } +function print_memoryusage(){ + var m = process.memory(); + var pc = Math.round(m.usage*100/m.total); + console.log("memory usage: " + pc + "%"); +} + /** -* Called on button press to save down the last preference settings -*/ + * Called on button press to save down the last preference settings + */ function save_settings(){ var settings = { font : numeral_fonts[numeral_fonts_index].getName(), @@ -757,6 +774,7 @@ function save_settings(){ }; console.log("saving:" + JSON.stringify(settings)); require("Storage").writeJSON("sweepclock.settings.json",settings); + print_memoryusage(); } // Boiler plate code for setting up the clock, @@ -785,14 +803,12 @@ function scheduleDrawClock(){ } function reset_clock(){ - g.clear(); force_redraw = true; } Bangle.on('lcdPower', (on) => { if (on) { console.log("lcdPower: on"); - Bangle.drawWidgets(); reset_clock(); startTimers(); } else { @@ -821,7 +837,7 @@ startTimers(); setWatch(Bangle.showLauncher, BTN2,{repeat:false,edge:"falling"}); function button1pressed(){ - next_font(); + next_font(); save_settings(); } From e029071678801794ba03d1854d9d29553906eacd Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Mon, 17 May 2021 13:41:06 +0100 Subject: [PATCH 0020/2129] sweepclock: touching README.md file to get the git App Loader site working --- apps/sweepclock/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sweepclock/README.md b/apps/sweepclock/README.md index 121c7b0e9..34be0c42c 100644 --- a/apps/sweepclock/README.md +++ b/apps/sweepclock/README.md @@ -36,7 +36,7 @@ For further details of design and working please visit [The Project Page](https: ## Requests -Reach out to adrian@adriankirk.com if you have feature requests or notice bugs. +Please reach out to adrian@adriankirk.com if you have feature requests or notice bugs. ## Creator From 0692ae20aa7e5cdcaa7bce263af247659d3eccd8 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sat, 22 May 2021 00:38:30 +0100 Subject: [PATCH 0021/2129] Intial version of font clock --- apps.json | 26 ++ apps/fontclock/ChangeLog | 1 + apps/fontclock/README.md | 43 ++ apps/fontclock/app.png | Bin 0 -> 33522 bytes apps/fontclock/custom.html | 200 +++++++++ apps/fontclock/display-01.png | Bin 0 -> 6287 bytes apps/fontclock/display-02.png | Bin 0 -> 8956 bytes apps/fontclock/display-03.png | Bin 0 -> 6665 bytes apps/fontclock/display-04.png | Bin 0 -> 7018 bytes apps/fontclock/display-05.png | Bin 0 -> 6261 bytes apps/fontclock/fontclock-icon.js | 1 + apps/fontclock/fontclock.font.abril_ff50.js | 87 ++++ apps/fontclock/fontclock.font.cpstc58.js | 59 +++ apps/fontclock/fontclock.font.js | 26 ++ apps/fontclock/fontclock.font.json | 23 ++ apps/fontclock/fontclock.font.mntn25.js | 76 ++++ apps/fontclock/fontclock.font.mntn50.js | 56 +++ apps/fontclock/fontclock.font.vector25.js | 55 +++ apps/fontclock/fontclock.font.vector50.js | 42 ++ apps/fontclock/fontclock.hand.js | 10 + apps/fontclock/fontclock.hourscriber.js | 137 +++++++ apps/fontclock/fontclock.js | 432 ++++++++++++++++++++ apps/fontclock/fontclock.png | Bin 0 -> 2669 bytes apps/fontclock/fontclock.thickhand.js | 103 +++++ apps/fontclock/fontclock.thinhand.js | 67 +++ 25 files changed, 1444 insertions(+) create mode 100644 apps/fontclock/ChangeLog create mode 100644 apps/fontclock/README.md create mode 100644 apps/fontclock/app.png create mode 100644 apps/fontclock/custom.html create mode 100644 apps/fontclock/display-01.png create mode 100644 apps/fontclock/display-02.png create mode 100644 apps/fontclock/display-03.png create mode 100644 apps/fontclock/display-04.png create mode 100644 apps/fontclock/display-05.png create mode 100644 apps/fontclock/fontclock-icon.js create mode 100644 apps/fontclock/fontclock.font.abril_ff50.js create mode 100644 apps/fontclock/fontclock.font.cpstc58.js create mode 100644 apps/fontclock/fontclock.font.js create mode 100644 apps/fontclock/fontclock.font.json create mode 100644 apps/fontclock/fontclock.font.mntn25.js create mode 100644 apps/fontclock/fontclock.font.mntn50.js create mode 100644 apps/fontclock/fontclock.font.vector25.js create mode 100644 apps/fontclock/fontclock.font.vector50.js create mode 100644 apps/fontclock/fontclock.hand.js create mode 100644 apps/fontclock/fontclock.hourscriber.js create mode 100644 apps/fontclock/fontclock.js create mode 100644 apps/fontclock/fontclock.png create mode 100644 apps/fontclock/fontclock.thickhand.js create mode 100644 apps/fontclock/fontclock.thinhand.js diff --git a/apps.json b/apps.json index bb37a489a..8ab683361 100644 --- a/apps.json +++ b/apps.json @@ -216,6 +216,32 @@ {"name":"wclock.img","url":"clock-word-icon.js","evaluate":true} ] }, + { "id": "fontclock", + "name": "Font Clock", + "icon": "fontclock.png", + "version":"0.01", + "description": "Choose the font and design of clock face from a library of available designs", + "tags": "clock", + "type":"clock", + "allow_emulator":true, + "readme": "README.md", + "custom":"custom.html", + "storage": [ + {"name":"fontclock.app.js","url":"fonclock.js"}, + {"name":"fontclock.img","url":"fontclock-icon.js","evaluate":true}, + {"name":"fontclock.hand.js","url":"fontclock.hand.js"}, + {"name":"fontclock.thinhand.js","url":"fontclock.thinhand.js"}, + {"name":"fontclock.thickhand.js","url":"fontclock.thickhand.js"}, + {"name":"fontclock.hourscriber.js","url":"fontclock.hourscriber.js"}, + {"name":"fontclock.font.js","url":"fontclock.font.js"}, + {"name":"fontclock.font.abril_ff50.js","url":"fontclock.font.abril_ff50.js"}, + {"name":"fontclock.font.cpstc58.js","url":"fontclock.font.cpstc58.js"}, + {"name":"fontclock.font.mntn25.js","url":"fontclock.font.mntn25.js"}, + {"name":"fontclock.font.mntn50.js","url":"fontclock.font.mntn50.js"}, + {"name":"fontclock.font.vector25.js","url":"fontclock.font.vector25.js"}, + {"name":"fontclock.font.vector50.js","url":"fontclock.font.vector50.js"} + ] + }, { "id": "slidingtext", "name": "Sliding Clock", "icon": "slidingtext.png", diff --git a/apps/fontclock/ChangeLog b/apps/fontclock/ChangeLog new file mode 100644 index 000000000..d53df991b --- /dev/null +++ b/apps/fontclock/ChangeLog @@ -0,0 +1 @@ +0.01: Initial Release diff --git a/apps/fontclock/README.md b/apps/fontclock/README.md new file mode 100644 index 000000000..cbdb2a3f8 --- /dev/null +++ b/apps/fontclock/README.md @@ -0,0 +1,43 @@ +# Sweep Clock + +The Sweep Clock provides a clock with a perfectly smooth sweep second hand with a single Numeral Display. + +![](app.png) + +## Usage + +### Button 1 + +Use Button 1 (the top right button) to change the numeral type + +| Default clock face | Roman Numeral Font | No Digits | +| ---- | ---- | ---- | +| ![](./numeral-01.jpg) | ![](numeral-02.jpg) | ![](numeral-03.jpg) | + + + +### Button 3 +Button 3 (bottom right button) is used to change the colour + +| Red | Grey | Purple | +| ---- | ---- | ---- | +| ![](./color-01.jpg) | ![](color-02.jpg) | ![](color-03.jpg) | + +### Button 4 +Button 4 (bottom left of screen) is used to change the date positioning (or to remove from the screen) + +| Top Right | Bottom Right | Bottom Left | Top Left | +| ---- | ---- | ---- | ---- | +| ![](./date-01.jpg) | ![](date-02.jpg) | ![](date-03.jpg) | ![](date-04.jpg) | + +## Further Details + +For further details of design and working please visit [The Project Page](https://www.notion.so/adrianwkirk/Sweep-hand-clock-6aa5b6b3d1074d4e87fc947975b1e4b7) + +## Requests + +Reach out to adrian@adriankirk.com if you have feature requests or notice bugs. + +## Creator + +Made by [Adrian Kirk](mailto:adrian@adriankirk.com) \ No newline at end of file diff --git a/apps/fontclock/app.png b/apps/fontclock/app.png new file mode 100644 index 0000000000000000000000000000000000000000..763c00b1de9f5c73ca4af264c6d65cc5eb08c090 GIT binary patch literal 33522 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Ν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 literal 0 HcmV?d00001 diff --git a/apps/fontclock/custom.html b/apps/fontclock/custom.html new file mode 100644 index 000000000..92fe4b619 --- /dev/null +++ b/apps/fontclock/custom.html @@ -0,0 +1,200 @@ + + + + + + +

Please select watch display

+ + + + + + +
+ + + +
+ +

Click

+ + + + + + diff --git a/apps/fontclock/display-01.png b/apps/fontclock/display-01.png new file mode 100644 index 0000000000000000000000000000000000000000..e7100a25fa02c69c807f941b6e97e65b37223500 GIT binary patch literal 6287 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 literal 0 HcmV?d00001 diff --git a/apps/fontclock/display-03.png b/apps/fontclock/display-03.png new file mode 100644 index 0000000000000000000000000000000000000000..9cbe805447be14a132521192ef890baa4812f32d GIT binary patch literal 6665 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 literal 0 HcmV?d00001 diff --git a/apps/fontclock/fontclock-icon.js b/apps/fontclock/fontclock-icon.js new file mode 100644 index 000000000..d9bdd8c65 --- /dev/null +++ b/apps/fontclock/fontclock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("lEowkA/4AGmYIHABHzmVCCaE0kUin4TPmUimQTQ+UzmcvJ6EjCaP/kYABCaEymYTl+Q7SMgITTmQTQPAK0RMgITm+QTS+ciPCcikQpPY4MjmYTO+czmcyHh4TCmcvJ54nCPCBjBJx4oECc8zJ6ATTn48RE4YTTHh4SDH4ImRFBwTGFBgTGFBgSGFBYmHUgITRmcyFBASFAoUjE5PzkQLBHJxiDAQP/GxAA==")) diff --git a/apps/fontclock/fontclock.font.abril_ff50.js b/apps/fontclock/fontclock.font.abril_ff50.js new file mode 100644 index 000000000..d61a2ca49 --- /dev/null +++ b/apps/fontclock/fontclock.font.abril_ff50.js @@ -0,0 +1,87 @@ +var NumeralFont = require("fontclock.font.js"); + +const DIM_30x38 = [30,38]; +const DIM_49x38 = [49,38]; + +class DigitNumeralFont extends NumeralFont{ + constructor(){ + super(); + // dimension map provides the dimensions of the character for + // each number for plotting and collision detection + + /*this.dimension_map = { + 3 : [30,38], + 6 : [30,38], + 9 : [30,38], + 12: [49,38] + };*/ + this.widths = atob("DRIhFRwdHhsfGh8fDQ=="); + this.font = atob("AAAAAAAAAAAAAAAAAAAAAAAH4AAAAAAD/AAAAAAB/4AAAAAAf+AAAAAAH/gAAAAAB/4AAAAAAf+AAAAAAD/AAAAAAA/gAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAPwAAAAAAf8AAAAAA/+AAAAAB/8AAAAAD/wAAAAAH/gAAAAAP/AAAAAAf+AAAAAA/8AAAAAB/4AAAAAD/wAAAAAH/gAAAAAP/AAAAAAH+AAAAAAB8AAAAAAAIAAAAAAAAAAAAAAAAAAH/8AAAAAP//8AAAAP///wAAAH///+AAAD////4AAB/////AAA/////wAAf////+AAH/////wAD/////8AA//////AAP/gAA/wADwAAAAeAA4AAAADgAMAAAAA4ADAAAAAOAAwAAAADgAMAAAAA4ADgAAAAeAA/gAAA/AAP/////wAD/////8AAf/////AAH/////gAA/////4AAH////8AAB////+AAAP////AAAA////gAAAD///gAAAAH//AAAAAAAAAAAAGAAAAAwABgAAAAMAAYAAAADAAGAAAAAwADgAAAAMAA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAAAAAAAMAAAAAAADAAAAAAAAwAAAAAAAMAAAAAAAAAAAAAAAAAAAHwAAD8AAH/AAB/AAD/wAA/wAA/+AAf8AAf/gAP/AAH/4AH/wAD/+AD/8AA//gB//AAOPwA//wADD4Aff8AAwAAPn/AAMAAPx/wADAAH8f8AA4AH+H/AAPgP/B/wAD///gf8AA///4H/AAP//8B/wAD//+Af8AAf//AH/AAH//wB/wAA//4A/8AAH/4Af/AAA/8A//wAAD8Af/8AAAAAD+AAAAAAAAAAAAAAAAAAAAAAAAPwAAA/gAP+AAAf8AD/wAAP/gB/+AAH/4Af/wAB/+AH/8AAf/gB//AAP/4wP/wAD/8OD+OAAw/DgPDgAMDAwAA4ADAAcAAOAAwAHAADgAOAH4AA4AD///AAeAA///+A/AAP/////wAD/////8AA//9///AAP//f//gAB//n//4AAf/w//+AAD/8P//AAAf+B//gAAB+AP/wAAAAAB/4AAAAAADwAAAAAAAAAAAAAAAeAAAAAAAfgAAAAAAf4AAAAAAPmAAAAAAPhgAAAAAPwYAAAAAPwGAAAAAHwBgAAAAHwAYDAAAH4AGAwAAH4ABgMAAH4AAYDAAD4AAGAwAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AAAAAAYDAAAAAAGAwAAAAABgMAAAAAAYBAAAAAB/4AAAAAAf+AAAAAAAAAAAAAAAD4AAAAAAB/gAAAAAA/8AAP//wf/gAD//8H/4AA//3B//AAP8Bgf/wAD/A4D/8AAfwOA/jgAH8DAH44AB/gwAAOAAf4MAADgAH+DAAA4AB/g4AAeAAf8PwA/AAH/D///wAB/w///8AAf8P///AAD/j///wAA/4f//4AAP+H//+AAH/A///AAD/wP//gAA/gB//wAAAAAH/4AAAAAAfwAAAAAAAAAAAAAAAAAAAAAD//wAAAAH///AAAAH///8AAAD////gAAD////8AAB/////gAAf////4AAP/////AAH/////wAB/////8AA//////gAP8B4AD4AD4A4AAOAA4AMAADgAOAHAAA4ADABwAAOAAwAcAAHgAMAH4AP4ADD5///8AA5/f///AAP/////wAD/////8AAf/v//+AAH/7///AAA/+f//wAAH/H//4AAA/gf/4AAABgD/8AAAAAAH4AAAAAAAAAAAAAAAAAAAAf/wAAAAAP/8AAAAAD/8AAAAAA/8AAAAAAP+AAA/AAD/gAA/4AA/4AA//AAP+AAf/wAD/gAf/+AA/4AP//gAP+AH//4AD/gD//+AA/4B///gAP+B/+BwAD/g/8AAAA/4f8AAAAP+P8AAAAD/n8AAAAA/78AAAAAP/+AAAAAD/+AAAAAA/+AAAAAAP+AAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAB/gH/4AAA/8D//AAAf/h//wAAP/8f/+AAH//v//gAB//7//8AAf/////AAP/////wAD/////+AA//////gAP//+AB4ADgAeAAOAAwADgADgAMAA4AA4ADAAOAAOAA4AHwADgAP//+AD4AD/////+AA//////AAP/////wAD//7//8AAf/+///AAH//P//gAA//x//4AAH/4f/8AAA/8D/+AAAD8Af/AAAAAAB/AAAAAAAAAAAAA/gAAAAAA//APwAAA//8H+AAAf//j/wAAP//4/+AAD///f/gAB/////8AAf//+//AAP///v/wAD///7+eAA////PjgAPgAPwA4ADgAA4AOAAwAAOADgAMAADgA4ADAAA4AeAAwAAcAfgAPAAeA/wAD/////8AA//////AAP/////gAB/////wAAf////8AAD////+AAAf////AAAH////gAAAf///gAAAD///gAAAAH//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AH4AAAB/gD/AAAAf8B/4AAAP/Af+AAAD/wH/gAAA/8B/4AAAH/Af+AAAB/wD/AAAAP4A/gAAAAwABgAAAAAAAA=="); + var scale = 1; // size multiplier for this font + this.size = 50+(scale<<8)+(1<<16); + this.y_offset = -12; + /* scale + this.widths = atob("ExkuHicoKiYrJCsrEw=="); + this.font = atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/AAAAAAAAAAf+AAAAAAAAAB/8AAAAAAAAAP/4AAAAAAAAA//gAAAAAAAAD/+AAAAAAAAAP/4AAAAAAAAA//gAAAAAAAAD/+AAAAAAAAAP/wAAAAAAAAAf/AAAAAAAAAA/4AAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAA8AAAAAAAAAAfwAAAAAAAAAP/AAAAAAAAAH/8AAAAAAAAD/+AAAAAAAAB//AAAAAAAAA//gAAAAAAAAf/wAAAAAAAAP/4AAAAAAAAH/8AAAAAAAAD/+AAAAAAAAB//AAAAAAAAA//gAAAAAAAAf/wAAAAAAAAP/4AAAAAAAAH/8AAAAAAAAD/+AAAAAAAAB//AAAAAAAAA//gAAAAAAAAH/wAAAAAAAAAf4AAAAAAAAAB8AAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAB//wAAAAAAAB///8AAAAAAAf///+AAAAAAH////+AAAAAB/////+AAAAAP/////8AAAAB//////4AAAAP//////wAAAB///////gAAAP///////AAAA///////8AAAH///////4AAAf///////gAAB////////AAAP///////8AAA////////wAAD+AAAAAA/gAAPAAAAAAAeAAA4AAAAAAA4AAHgAAAAAADgAAcAAAAAAAOAABwAAAAAAA4AAHAAAAAAADgAAcAAAAAAAOAAB4AAAAAAA4AADgAAAAAAHgAAPgAAAAAB+AAA/8AAAAA/wAAD////////AAAP///////8AAAf///////wAAB///////+AAAD///////4AAAP///////AAAAf//////8AAAB///////gAAAD//////8AAAAH//////gAAAAP/////8AAAAAP/////AAAAAAf////4AAAAAAP///8AAAAAAAH//+AAAAAAAAADAAAAAAAAAAAAAAAAAAAIAAAAAAAAAABwAAAAAADAAAHAAAAAAAMAAAcAAAAAAAwAABwAAAAAADAAAHAAAAAAAMAAAcAAAAAAAwAABgAAAAAADAAAP///////8AAA////////wAAD////////AAAP///////8AAA////////wAAD////////AAAP///////8AAB////////wAAH////////AAAf///////8AAB////////wAAH////////AAAf///////8AAB////////wAAH////////AAAAAAAAAAAMAAAAAAAAAAAwAAAAAAAAAADAAAAAAAAAAAMAAAAAAAAAAAwAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAP+AAAAf8AAAD/8AAAD/wAAAf/4AAAf/AAAD//gAAD/8AAAP//AAAf/wAAB//8AAD//AAAH//wAAf/8AAA///AAD//wAAD//4AAf//AAAP//gAD//8AAA8P+AAfv/wAADg/wAD8//AAAcB8AAfj/8AABwAAAD+P/wAAHAAAAfw//AAAcAAAH+D/8AABwAAA/4P/wAAHgAAP/A//AAAfAAD/4D/8AAB/AD//AP/wAAD////8A//AAAP////gD/8AAA////8AP/wAAD////gA//AAAP///8AD/8AAAf///wAP/wAAB///+AA//AAAD///wAH/8AAAP//+AAf/wAAAf//wAD//AAAA//+AAf/8AAAB//wAP//wAAAD/8AD///AAAAA8AAP//8AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAABwAAAP8AAAAA/4AAD/8AAAAH/wAAP/4AAAA//gAB//wAAAH/+AAH//gAAA//8AAf/+AAAH//wAD//8AAAf//AAH//wAAB//8AAf//AAAP//gAB//8AAA//+BwD/D4AADw/4GAP8HgAAOD/A4APwOAABwHwDgAAA4AAHAAAOAAADgAAcAAA4AAAOAABwAAHgAAA4AAHgAA+AAADgAAfAAH8AAAeAAB/wD/4AAD4AAH////4AAfgAAf////+B/+AAA////////wAAD///3////AAAP///f///8AAA///9////wAAD///j///+AAAH//+P///4AAAf//w////gAAA///B///8AAAB//4H///gAAAD//AP//+AAAAH/4Af//wAAAAH+AA//+AAAAAAAAB//gAAAAAAAAD/4AAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAfAAAAAAAAAAH8AAAAAAAAAA/wAAAAAAAAAP3AAAAAAAAAD+cAAAAAAAAA/hwAAAAAAAAH4HAAAAAAAAB+AcAAAAAAAAfwBwAAAAAAAH8AHAAAAAAAB/AAcAAAAAAAPwABwAAAAAAD+AAHADAAAAA/gAAcAMAAAAP4AABwAwAAAD+AAAHADAAAAfwAAAcAMAAAH8AAABwAwAAB////////AAAP///////8AAA////////wAAD////////AAAP///////8AAA////////wAAD////////AAAP///////8AAA////////wAAD////////AAAP///////8AAA////////wAAD////////AAAP///////8AAAAAAAABwAwAAAAAAAAHADAAAAAAAAAcAMAAAAAAAABwAwAAAAAAAAHADAAAAAAAAAcAAAAAAAAAB//gAAAAAAAAH/+AAAAAAAAAf/4AAAAAAAAAAAAAAAAAAAAAB+AAAAAAAAAAf+AAAAAAAAAD/+AAAAAAAAAf/8AAAH///4B//wAAA////gH//gAAD///+A//+AAAP/ABwB//8AAA/8AHAH//wAAD/wA4Af//AAAH/gDgB/9+AAAf+AOAD/h4AAB/4AwAH+DgAAH/gHAAHAOAAAf/AcAAAA4AAB/8BwAAADgAAH/wHAAAAOAAAf/AeAAAA4AAB/+B8AAAHgAAD/4H4AAB+AAAP/gf////4AAA/+B/////AAAD/8H////8AAAP/wP////wAAA//A/////AAAD/8D////4AAAP/4P////gAAA//gf///8AAAD/+B////wAAAP/wD///+AAAB/+AH///wAAAP/wAf///AAAB/gAA///wAAAAAAAA//+AAAAAAAAA//gAAAAAAAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAAAAAAAH///4AAAAAAB////8AAAAAA/////4AAAAAH/////4AAAAB//////wAAAAP//////gAAAB///////AAAAP//////8AAAB///////4AAAH///////gAAA////////AAAD///////8AAAf///////wAAB////////AAAP/4B+AAD+AAA/4AHgAAD4AAD8AA4AAAHgAAPgAHgAAAOAAA8AAcAAAA4AAHgABwAAADgAAcAAPAAAAOAABwAA8AAAA4AAHAADwAAAHgAAcAAPwAAD+AABwPw/////4AADg/z/////AAAPD/P////8AAA//+/////wAAD//7////+AAAP//n////4AAAf//f////gAAB//5////8AAAD//j////gAAAP/+H///+AAAAf/wf///wAAAA//A///+AAAAA/wB///gAAAAAYAB//8AAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAAD//+AAAAAAAAP//4AAAAAAAA//8AAAAAAAAD//AAAAAAAAAP/4AAAAAAAAA//gAAAH+AAAD/8AAAB/8AAAP/wAAAf/4AAA//AAAH//wAAD/8AAA///AAAP/wAAH//+AAA//AAA///4AAD/8AAP///gAAP/wAB///+AAA//AAP///4AAD/8AB////gAAP/wAP///+AAA//AD//wD4AAD/8Af/4ADAAAP/wD/8AAAAAA//Af/AAAAAAD/8D/wAAAAAAP/wf8AAAAAAA//H/gAAAAAAD/8/4AAAAAAAP/3+AAAAAAAA///gAAAAAAAD//8AAAAAAAAP//AAAAAAAAA//wAAAAAAAAD/8AAAAAAAAAP/gAAAAAAAAA/4AAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAH8AA//wAAAAB/8AH//wAAAAf/8A///AAAAD//4H//+AAAAf//g///8AAAD///D///wAAAP//8f///gAAB///5///+AAAH///n///8AAAf///////wAAD////////AAAP///////8AAA////////4AAD////////gAAP////gAB+AAB+AAP4AAB4AAHgAAfAAADgAAeAAA8AAAOAABwAADwAAA4AAHAAAPAAADgAAcAAA8AAAOAAB4AADwAAA4AAH4AAfgAAHgAAP////gAB+AAA////////4AAD////////gAAP///////8AAA////////wAAD////////AAAH///n///8AAAf//+f///gAAA///5///+AAAD///D///4AAAH//4P///AAAAP//gf//4AAAAf/4A///AAAAA//AB//4AAAAAfgAD//AAAAAAAAAD/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAAAAAAAf/8AA+AAAAAH//8AP+AAAAA///4B/8AAAAH///4P/4AAAA////h//wAAAH////H//gAAA////+f/+AAAD////5//4AAAf////3//wAAB/////f//AAAH////9//8AAA/////z/j4AAD/////H+HgAAP////8PgOAAA/gAAfwAA4AADwAAAPAADgAAeAAAA8AAOAAB4AAABwAA4AAHAAAAHAADgAAcAAAA4AAeAABwAAADgAD4AAHgAAAeAAfgAAeAAADwAH8AAA+AAA+AH/wAAD////////AAAP///////4AAA////////gAAD///////8AAAH///////wAAAf//////+AAAA///////4AAAD///////AAAAH//////4AAAAP//////AAAAAf/////wAAAAA/////8AAAAAA/////gAAAAAA////wAAAAAAAf//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAfgAAAAAB/wAD/gAAAAAP/gAf/AAAAAB/+AD/8AAAAAH/8AP/4AAAAAf/wA//gAAAAD//AD/+AAAAAP/8AP/4AAAAAf/wA//gAAAAB/+AD/+AAAAAH/4AP/wAAAAAP/AAf+AAAAAAf4AA/wAAAAAAIAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="); + var scale = 1; // size multiplier for this font + this.size = 70+(scale<<8)+(1<<16); + this.y_offset = -15 + */ + + // font size 90 + /*this.dimension_map = { + 1 : [50,70], + 2 : [50,70], + 3 : [50,70], + 4 : [50,70], + 5 : [50,70], + 6 : [54,70], + 7 : [54,70], + 8 : [54,70], + 9 : [54,70], + 10: [87,70], + 11: [87,70], + 12: [87,70] + }; + + this.widths = atob("GCA8JjI0NjE3Ljc3GA=="); + this.font = atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAD/gAAAAAAAAAAAAH/4AAAAAAAAAAAAP/8AAAAAAAAAAAAf/8AAAAAAAAAAAAf/+AAAAAAAAAAAAf/+AAAAAAAAAAAA//+AAAAAAAAAAAA//+AAAAAAAAAAAA//+AAAAAAAAAAAA//+AAAAAAAAAAAAf/+AAAAAAAAAAAAf/+AAAAAAAAAAAAf/8AAAAAAAAAAAAP/4AAAAAAAAAAAAH/4AAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAA/AAAAAAAAAAAAAH/AAAAAAAAAAAAA//AAAAAAAAAAAAH//AAAAAAAAAAAA//8AAAAAAAAAAAH//gAAAAAAAAAAA//8AAAAAAAAAAAH//gAAAAAAAAAAA//8AAAAAAAAAAAH//gAAAAAAAAAAA//8AAAAAAAAAAAH//gAAAAAAAAAAA//8AAAAAAAAAAAH//AAAAAAAAAAAA//4AAAAAAAAAAAH//AAAAAAAAAAAA//4AAAAAAAAAAAH//AAAAAAAAAAAA//4AAAAAAAAAAAH//AAAAAAAAAAAA//4AAAAAAAAAAAH//AAAAAAAAAAAA//4AAAAAAAAAAAD//AAAAAAAAAAAAD/4AAAAAAAAAAAAD/AAAAAAAAAAAAAD4AAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH///AAAAAAAAAAB////8AAAAAAAAAP/////gAAAAAAAA//////4AAAAAAAD//////+AAAAAAAH///////gAAAAAAP///////wAAAAAAf///////4AAAAAA////////8AAAAAB////////+AAAAAD/////////AAAAAH/////////gAAAAH/////////wAAAAP/////////wAAAAP/////////4AAAAf/////////4AAAAf/////////4AAAAf/////////8AAAA//////////8AAAA///gAAAAf/8AAAA/wAAAAAAAH+AAAA+AAAAAAAAB+AAAB8AAAAAAAAAeAAAB4AAAAAAAAAeAAAB4AAAAAAAAAOAAAB4AAAAAAAAAOAAABwAAAAAAAAAOAAABwAAAAAAAAAOAAABwAAAAAAAAAOAAAB4AAAAAAAAAOAAAB4AAAAAAAAAeAAAB4AAAAAAAAAeAAAB8AAAAAAAAA+AAAA+AAAAAAAAB+AAAA/4AAAAAAAP8AAAA////AAB///8AAAA//////////8AAAAf/////////8AAAAf/////////4AAAAf/////////4AAAAP/////////wAAAAP/////////wAAAAH/////////gAAAAH/////////gAAAAD/////////AAAAAB////////+AAAAAA////////8AAAAAAf///////8AAAAAAP///////wAAAAAAH///////gAAAAAAB///////AAAAAAAAf/////8AAAAAAAAH/////gAAAAAAAAA////8AAAAAAAAAAB///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAOAAAAAAAAAcAAAAOAAAAAAAAAcAAAAeAAAAAAAAAcAAAAeAAAAAAAAAcAAAAcAAAAAAAAAcAAAAcAAAAAAAAAcAAAAcAAAAAAAAAcAAAAcAAAAAAAAAcAAAAcAAAAAAAAAcAAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/AAAAAB/8AAAAAf/wAAAAD/8AAAAB//4AAAAH/8AAAAD//4AAAAP/8AAAAH//8AAAAf/8AAAAH//8AAAA//8AAAAP//8AAAB//8AAAAP//8AAAD//8AAAAf//8AAAH//8AAAAf//8AAAP//8AAAA///8AAAf//8AAAA///8AAA///8AAAA///4AAB/f/8AAAA+D/4AAD+f/8AAAA8D/wAAH8f/8AAAB4D/gAAP8f/8AAAB4AOAAAf4f/8AAABwAAAAA/wf/8AAABwAAAAB/wf/8AAABwAAAAD/gf/8AAABwAAAAP/Af/8AAAB4AAAAf+Af/8AAAB4AAAB/+Af/8AAAB8AAAH/8Af/8AAAB+AAAf/4Af/8AAAB/gAH//wAf/8AAAB//////wAf/8AAAA//////gAf/8AAAA//////AAf/8AAAA/////+AAf/8AAAA/////+AAf/8AAAA/////8AAf/8AAAAf////4AAf/8AAAAf////wAAf/8AAAAP////gAAf/8AAAAP////gAA//8AAAAH////AAA//8AAAAH///+AAB//8AAAAD///4AAD//8AAAAB///wAAH//8AAAAA///gAAf//8AAAAAf/+AAD///8AAAAAD/4AAP///8AAAAAAAAAAP///8AAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAD8AAAAD/4AAAAAAP/gAAAP/+AAAAAA//wAAAf//AAAAAB//4AAAf//gAAAAD//8AAA///gAAAAH//8AAA///wAAAAH//8AAA///4AAAAP//8AAA///4AAAAf//8AAA///4AAAAf//8AAA///8AAAAf//8AAA///8AAAA///8AAA///8AAAA///8BwAf/j+AAAA///4BwAf/A+AAAA+D/4BwAP/AeAAAA4D/wBwAD/AeAAAB4D/gBwAAAAOAAABwAAADwAAAAOAAABwAAADwAAAAOAAABwAAADwAAAAOAAABwAAAHgAAAAOAAAB4AAAHwAAAAOAAAB4AAAP4AAAAeAAAB+AAA/4AAAAeAAAB/wAD/+AAAA+AAAB//////AAAB+AAAB//////wAAP+AAAB///////gH/+AAAB//////////8AAAA////9/////8AAAA////9/////8AAAA////8/////8AAAA////4/////4AAAAf///4/////4AAAAf///4/////4AAAAf///wf////wAAAAP///gf////wAAAAP///gP////gAAAAH///AP////gAAAAD//+AH////AAAAAB//8AD///+AAAAAAf/4AD///8AAAAAAH/AAB///4AAAAAAAAAAA///wAAAAAAAAAAAP//AAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAfAAAAAAAAAAAAAB/AAAAAAAAAAAAAH/AAAAAAAAAAAAAf/AAAAAAAAAAAAB/nAAAAAAAAAAAAD+HAAAAAAAAAAAAP8HAAAAAAAAAAAA/wHAAAAAAAAAAAD/AHAAAAAAAAAAAH8AHAAAAAAAAAAAf4AHAAAAAAAAAAB/gAHAAAAAAAAAAH+AAHAAAAAAAAAAf4AAHAAAAAAAAAA/gAAHAAAAAAAAAD/AAAHAAcAAAAAAP8AAAHAAcAAAAAA/wAAAHAAcAAAAAD/AAAAHAAcAAAAAH+AAAAHAAcAAAAAf4AAAAHAAcAAAAB/gAAAAHAAcAAAAH+AAAAAHAAcAAAAP/////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAAAAAAAAAHAAcAAAAAAAAAAAHAAcAAAAAAAAAAAHAAcAAAAAAAAAAAHAAcAAAAAAAAAAAHAAcAAAAAAAAAAAHAAcAAAAAAAAAAAHAAAAAAAAAAAAAAHAAAAAAAAAAAAAf//gAAAAAAAAAAAf//gAAAAAAAAAAAf//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/gAAAAAAAAAAAAH/8AAAAAAAAAAAAP/+AAAAAAAAAAAAf//AAAAAAAAAAAAf//gAAAAf////gA///wAAAA/////wA///wAAAA/////wA///4AAAA///4HgA///4AAAA//AAHgA///4AAAA//AAPAA///8AAAAf/gAPAA///8AAAAf/gAOAA///+AAAAf/gAeAAf/g+AAAAf/wAeAAP/geAAAAf/wAcAAH/geAAAAf/wAcAAD+AOAAAAf/wAcAAAAAOAAAAf/4AcAAAAAOAAAAf/4AcAAAAAOAAAAP/4A8AAAAAOAAAAP/4A8AAAAAOAAAAP/8A+AAAAAeAAAAP/8AfAAAAA+AAAAP/8AfgAAAB+AAAAP/8Af8AAAf+AAAAP/+Af/////+AAAAP/+Af/////8AAAAP/+Af/////8AAAAP/+Af/////8AAAAH//Af/////8AAAAH//AP/////4AAAAH//AP/////4AAAAH//AP/////4AAAAH//AH/////wAAAAH//AH/////wAAAAH//AH/////gAAAAH//AD/////AAAAAP/+AB/////AAAAA//8AA////+AAAAB//gAA////8AAAAB/wAAAP///4AAAAAAAAAAH///gAAAAAAAAAAB//+AAAAAAAAAAAAf/4AAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//wAAAAAAAAAAD////gAAAAAAAAAf////4AAAAAAAAD//////AAAAAAAAP//////gAAAAAAA///////4AAAAAAB///////8AAAAAAH///////+AAAAAAP////////AAAAAAf////////gAAAAA/////////gAAAAB/////////wAAAAD/////////wAAAAD/////////4AAAAH/////////4AAAAP/////////8AAAAP/////////8AAAAf/////////8AAAAf/////////8AAAAf//wD/gAA/+AAAA//gAH4AAAD+AAAA/8AAPgAAAA+AAAA/wAAPAAAAAeAAAA/AAAeAAAAAOAAAA+AAAcAAAAAOAAAB8AAA8AAAAAOAAAB4AAA4AAAAAOAAAB4AAB4AAAAAOAAAB4AAB8AAAAAeAAABwAAB8AAAAAeAAABwAAB+AAAAA+AAABwAAB/AAAAD+AAABwAMB/+AAD/+AAAB4D/h//////8AAAB4D/x//////8AAAB8D/5//////8AAAA///5//////8AAAA///8//////4AAAA///8//////4AAAA///8//////wAAAAf//8//////wAAAAf//8f/////gAAAAP//8f/////gAAAAP//8P/////AAAAAH//8P////+AAAAAD//4H////8AAAAAB//wD////4AAAAAA//gB////wAAAAAAP/AA////gAAAAAAAQAAP//+AAAAAAAAAAAB//wAAAAAAAAAAAAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf///AAAAAAAAAAA////AAAAAAAAAAA///+AAAAAAAAAAA///gAAAAAAAAAAA///AAAAAAAAAAAA//+AAAAAAAAAAAA//8AAAAAAAAAAAA//8AAAAAP/AAAAA//4AAAAA//gAAAA//4AAAAD//wAAAA//4AAAAP//4AAAA//4AAAAf//8AAAA//4AAAA///8AAAA//4AAAD///+AAAA//4AAAH///+AAAA//4AAAP///+AAAA//4AAA////+AAAA//4AAB////+AAAA//4AAD////+AAAA//4AAH////+AAAA//4AAP////+AAAA//4AA/////+AAAA//4AB///gD+AAAA//4AD//8AAeAAAA//4AH//gAAAAAAA//4AP/+AAAAAAAA//4Af/4AAAAAAAA//4A//gAAAAAAAA//4D/+AAAAAAAAA//4H/4AAAAAAAAA//4P/gAAAAAAAAA//4f+AAAAAAAAAA//4/8AAAAAAAAAA//5/wAAAAAAAAAA////AAAAAAAAAAA///8AAAAAAAAAAA///4AAAAAAAAAAA///gAAAAAAAAAAA//+AAAAAAAAAAAA//4AAAAAAAAAAAA//wAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+AAAAAAAAPAAAH//wAAAAAAD/8AAP//4AAAAAAP//AA///+AAAAAA///gB///+AAAAAB///wB////AAAAAD///4D////gAAAAD///8H////wAAAAH///8H////wAAAAP///+P////4AAAAP///+P////4AAAAf////P////4AAAAf////f////8AAAAf////f////8AAAA/////f////8AAAA//////////8AAAA//////////+AAAA//////////+AAAA///////8f/+AAAB//////gAAH+AAAB/4AB/+AAAA+AAAB+AAAH8AAAAeAAAB8AAAD4AAAAeAAAB4AAAD4AAAAOAAAB4AAAB4AAAAOAAABwAAABwAAAAOAAAB4AAAB4AAAAOAAAB4AAAB4AAAAOAAAB4AAAD4AAAAOAAAB8AAAH8AAAAeAAAB/gAAP8AAAA+AAAB//////AAAD+AAAA//////+AA/+AAAA//////////+AAAA//////////+AAAA//////////8AAAA/////f////8AAAAf////f////8AAAAf////f////8AAAAf////P////4AAAAP///+P////4AAAAP///+H////4AAAAH///8H////wAAAAH///4H////wAAAAD///4D////gAAAAB///wB////gAAAAA///gA////AAAAAAf//AAf//+AAAAAAH/8AAP//4AAAAAAA/AAAH//wAAAAAAAAAAAB/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAP/+AAAAAAAAAAAB///gAAfgAAAAAAH///4AD/4AAAAAAP///8AH/+AAAAAA/////AP//AAAAAA/////gf//gAAAAB/////gf//gAAAAD/////w///wAAAAH/////4///wAAAAH/////4///4AAAAP/////8///4AAAAP/////8///8AAAAf/////8///8AAAAf/////+f//8AAAAf/////+f/z8AAAA//////+P/g+AAAA//////+H/geAAAA//////+D/AeAAAA//gAH/+AAAOAAAB/gAAAD+AAAOAAAB+AAAAA+AAAOAAAB8AAAAA+AAAOAAAB4AAAAAeAAAOAAAB4AAAAAeAAAOAAABwAAAAAcAAAeAAABwAAAAAcAAAeAAABwAAAAA8AAA+AAAB4AAAAA4AAB+AAAB4AAAAB4AAH+AAAB8AAAAHwAAf8AAAB+AAAAPgAD/8AAAA/4AAD/AD//8AAAA//////////4AAAA//////////4AAAA//////////4AAAAf/////////wAAAAf/////////wAAAAf/////////gAAAAP/////////AAAAAP/////////AAAAAH////////+AAAAAH////////8AAAAAD////////4AAAAAB////////wAAAAAA////////AAAAAAAf//////+AAAAAAAH//////4AAAAAAAD//////gAAAAAAAAf////8AAAAAAAAAH////gAAAAAAAAAAP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAMAAAAAAAAB/gAAD/gAAAAAAAH/4AAH/4AAAAAAAP/8AAP/8AAAAAAAP/8AAf/8AAAAAAAf/+AAf/+AAAAAAAf/+AAf/+AAAAAAAf/+AA//+AAAAAAAf/+AA//+AAAAAAAf/+AA//+AAAAAAAf/+AA//+AAAAAAAf/+AAf/+AAAAAAAf/+AAf/+AAAAAAAP/8AAf/8AAAAAAAP/8AAP/4AAAAAAAH/4AAH/4AAAAAAAD/gAAD/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="); + var scale = 1; // size multiplier for this font + this.size=90+(scale<<8)+(1<<16); + this.y_offset = -20 + */ + + } + getDimensions(hour){ + //return this.dimension_map[hour]; + switch (hour){ + case 10: + case 11: + case 12: + return DIM_49x38; + default: + return DIM_30x38; + + } + } + hour_txt(hour){ return hour.toString(); } + draw(hour_txt,x,y){ + /* going to leave this in here for future testing. + uncomment this so that it draws a box behind the string + so we can guess the digit dimensions*/ + /*var dim = [30,38]; + g.setColor(0.5,0,0); + g.fillPoly([x,y, + x+dim[0],y, + x+dim[0],y+dim[1], + x,y+dim[1] + ]); + g.setColor(1.0,1.0,1.0);*/ + g.setFontAlign(-1.0,-1.0,0); + g.setFontCustom(this.font, 46, this.widths, this.size); + g.drawString(hour_txt,x,y+this.y_offset ); + } + getName(){return "Digit";} +} + +module.exports = [DigitNumeralFont]; \ No newline at end of file diff --git a/apps/fontclock/fontclock.font.cpstc58.js b/apps/fontclock/fontclock.font.cpstc58.js new file mode 100644 index 000000000..6e91349ab --- /dev/null +++ b/apps/fontclock/fontclock.font.cpstc58.js @@ -0,0 +1,59 @@ +var NumeralFont = require("fontclock.font.js"); + +const DIM_20x58 = [20,58]; +const DIM_30x58 = [30,58]; +const DIM_40x58 = [40,58]; +const DIM_50x58 = [50,58]; +class DigitNumeralFont extends NumeralFont{ + constructor(){ + super(); + // dimension map provides the dimesions of the character for + // each number for plotting and collision detection + this.font = atob("AAAA/+AAAAAAB///wAAAAB////8AAAA/////+AAAP/////8AAD//////8AAf/8AAf/8AD/8AAAH/4Af+AAAAD/wD/gAAAAD/gf4AAAAAH+D/AAAAAAP8P4AAAAAAf5/AAAAAAA/n4AAAAAAB+/gAAAAAAH/+AAAAAAAf/wAAAAAAA//AAAAAAAD/8AAAAAAAP/4AAAAAAB//gAAAAAAH9+AAAAAAAfn8AAAAAAD+fwAAAAAAP4/gAAAAAB/D/AAAAAAP8H/AAAAAB/gP+AAAAAf8Af/AAAAH/gA//gAAD/8AB//8AH//gAB//////8AAB//////AAAB/////wAAAA////4AAAAAP//4AAAAAAAAAAAAAAGAAAAAAAAA8AAAAAAAAH8AAAAAAAA/wAAAAAAAH+AAAAAAAA/wAAAAAAAH+AAAAAAAA/wAAAAAAAH////////w/////////H////////8/////////3//////////////////8AAAAAAAAAAAAAAAAAADAAAAAAAAAcQAAAAAAAHzwAAAAAAA/PwAAAAAAH9/AAAAAAB/34AAAAAAP/fgAAAAAD//+AAAAAAf//wAAAAAH///AAAAAA///8AAAAAH///4AAAAB/4//gAAAAP/D/+AAAAD/wP34AAAAf+A/fwAAAD/wD8/gAAA/8APz/AAAH/gA/H+AAB/4AD8f8AAP/AAPw/8AD/wAA/B/+A/+AAD8D////wAAPwH///8AAA/AH///gAAD8AH//4AAAPwAH/+AAAAAAAAAAAAAAD8AAAAAAAAPwAAAAAAAA/AAgAAAAD/8AHAAAAAP/wB8AAAAA//APwAAAAD/8D/AAAAAP/wf8AAAAB//H/wAAAAH/8//gAAAAfv//+AAAAD+///8AAAAP7//fwAAAB/P/w/gAAAP8/+D/AAAB/j/wH+AAAP8P8AP8AAB/w/gAf8AAf+D4AA/8AH/wPAAB////+AwAAD////gCAAAH///8AAAAAH///AAAAAAD//wAAAAAAA/wAAAAAAAAAAAAAAAAAAAQAAAAAAAAHAAAAAAAAD8AAAAAAAA/wAAAAAAAP/AAAAAAAD/8AAAAAAB//wAAAAAAf//AAAAAAH//8AAAAAB//PwAAAAAf/w/AAAAAP/8D8AAAAD//APwAAAA//gA/AAAAP/4AD8AAAH/+AAPwAAB//gAA/AAAf/4AAD8AAH/8AAAPwAD//AAAA/AAP/wAAAD8AA/8AAAAPwAD/AAAAA/gAPgAAA/////4AAAD////+AAAAP////wAAAA/////AAAAD////8AAAAAA/AAAAAAAAD8AAAAAAAAPwAAAAAAAAAAAAAA8AAAAAAAB/wAAAAAAD//AAAAAP///8AAAAA////wAAAAD////AAAAAP///8AAAAA//4PwAAAAH/8A/gAAAAf/wB+AAAAB+/AH4AAAAP78AfwAAAA/vwA/AAAAH8/AD+AAAA/z8AP8AAAD+PwAf4AAAf4/AA/wAAH/D8AD/gAA/4PwAH/gAf/A/AAP/8f/4AAAAf////AAAAAf///wAAAAA///8AAAAAAf//AAAAAAAH/gAAAAAAAAAAAAAAAAH/4AAAAAAP//8AAAAAD///+AAAAB////8AAAAf////8AAAH//8f/4AAA//8AD/wAAP//AAD/gAB//wAAH/AAP/+AAAH+AB//wAAAP4AP/+AAAAfwB//wAAAB/AP9/AAAAD+B/n4AAAAH4H8/gAAAAfg/j8AAAAB/H8PwAAAAH8fw/AAAAAPz+D8AAAAA/P4PwAAAAD9/A/AAAAAf38D8AAAAB/fgP4AAAAH5+A/gAAAAfv4B/AAAAD+/gH8AAAAPz+AP4AAAB/PwA/wAAAP8/AB/gAAB/gAAD/AAAP8AAAP+AAD/gAAAf+AA/8AAAA//gf/gAAAA////8AAAAB////gAAAAB///4AAAAAB//+AAAAAAA//AAAAAAAAAAAAPwAAAAAAAA/AAAAAAAAD8AAAAAAAAfwAAAAAAAP/AAAAAAAH/8AAAAAAD//wAAAAAD///AAAAAB///8AAAAA///vwAAAA///w/AAAAP//wD8AAAP//4APwAAH//8AA/AAD//+AAD8AD//+AAAPwB///AAAA/A///gAAAD8f//wAAAAP///4AAAAA///4AAAAAD//8AAAAAAP/+AAAAAAA/+AAAAAAAD/AAAAAAAAPgAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAH//wAAAAAB///wAAAAAf///wAAAAD////wAAAAf////gAAAH/wAf/AAAA/8AAP+AAAD/AAAf8AAAf4AAAf4AAD/AAAA/gB/P4AAAB/A///AAAAH8H//8AAAAP4///gAAAAfn//+AAAAB+f//wAAAAH/+B/AAAAAf/4H8AAAAA//APwAAAAD/8A/AAAAAP/4H8AAAAB/fw/wAAAAH9///gAAAAfj//+AAAAB+P//4AAAAP4P//wAAAA/gf//gAAAH8APD/AAAA/wAAH8AAAH+AAAf8AAA/wAAA/4AAH/AAAB/4AB/4AAAD/8A//AAAAH////wAAAAP///+AAAAAP///gAAAAAP//4AAAAAAH/+AAAAAAAAAAAAAAA/wAAAAAAA//8AAAAAAP//+AAAAAD///8AAAAA////8AAAAH////4AAAA/+AD/wAAAH/AAD/gAAA/4AAD/AAAH+AAAH+AAAfwAAAP8APz+AAAAfwA/P4AAAA/gH9/AAAAD+Af34AAAAH4B+fgAAAAfwH7+AAAAA/A/v4AAAAD8D+/AAAAAPwPz8AAAAA/B/PwAAAAD8P8/gAAAAPw/j+AAAAA/H8H4AAAAH8/wfgAAAAf3+B/AAAAB+fwH8AAAAP//AP4AAAB//4A/wAAAH//AB/gAAA//4AD/AAAP//AAH+AAB//wAAf+AAf/+AAAf/AP//gAAA/////8AAAB/////AAAAB////wAAAAB///4AAAAAB//4AAAAAAAAAAAAAAA="); + this.widths = atob("Jg8dGiAaKBsoKA=="); + } + getDimensions(hour){ + switch(hour){ + case 1: + return DIM_20x58; + case 2: + case 3: + case 4: + case 5: + case 7: + return DIM_30x58; + case 6: + case 8: + case 9: + case 11: + case 12: + return DIM_40x58; + case 10: + return DIM_50x58; + default: + return DIM_30x58; + } + } + hour_txt(hour){ return hour.toString(); } + draw(hour_txt,x,y){ + /* going to leave this in here for future testing. + uncomment this so that it draws a box behind the string + so we can guess the digit dimensions + dim = [50,58]; + g.setColor(0.5,0,0); + g.fillPoly([x,y, + x+dim[0],y, + x+dim[0],y+dim[1], + x,y+dim[1] + ]); + g.setColor(1.0,1.0,1.0);*/ + //g.setFontCopasetic40x58Numeric(); + //g.setFontAlign(-1,-1,0); + g.setFontAlign(-1,-1,0); + g.setFontCustom(this.font, 48, this.widths, 58); + g.drawString(hour_txt,x,y); + } + getName(){return "Digit";} +} + +module.exports = [DigitNumeralFont]; \ No newline at end of file diff --git a/apps/fontclock/fontclock.font.js b/apps/fontclock/fontclock.font.js new file mode 100644 index 000000000..10b063ca5 --- /dev/null +++ b/apps/fontclock/fontclock.font.js @@ -0,0 +1,26 @@ +/** + * We want to be able to change the font so we set up + * pure virtual for all fonts implementtions to use + */ +class NumeralFont { + /** + * The screen dimensions of what we are going to + * display for the given hour. + */ + getDimensions(hour){return [0,0];} + /** + * The characters that are going to be returned for + * the hour. + */ + hour_txt(hour){ return ""; } + /** + * method to draw text at the required coordinates + */ + draw(hour_txt,x,y){ return "";} + /** + * Called from the settings loader to identify the font + */ + getName(){return "";} +} + +module.exports = NumeralFont; \ No newline at end of file diff --git a/apps/fontclock/fontclock.font.json b/apps/fontclock/fontclock.font.json new file mode 100644 index 000000000..3f111ba1b --- /dev/null +++ b/apps/fontclock/fontclock.font.json @@ -0,0 +1,23 @@ +{ + "name": "Vector 4", + "numerals": [12,3,6,9], + "fonts": ["vector50"], + "radius": 75, + "color_schemes" : [ + { + "name": "black", + "background" : [0.0,0.0,0.0], + "second_hand": [1.0,0.0,0.0], + }, + { + "name": "red", + "background" : [1.0,0.0,0.0], + "second_hand": [1.0,1.0,0.0] + }, + { + "name": "grey", + "background" : [0.5,0.5,0.5], + "second_hand": [0.0,0.0,0.0] + } + ] +} \ No newline at end of file diff --git a/apps/fontclock/fontclock.font.mntn25.js b/apps/fontclock/fontclock.font.mntn25.js new file mode 100644 index 000000000..e7abac8bf --- /dev/null +++ b/apps/fontclock/fontclock.font.mntn25.js @@ -0,0 +1,76 @@ +var NumeralFont = require("fontclock.font.js"); + +const DIM_25x25 = [25,25]; +const DIM_10x25 = [10,25]; +const DIM_20x25 = [20,25]; +const DIM_31x25 = [31,25]; +const DIM_15x25 = [15,25]; + +class DigitNumeralFont extends NumeralFont{ + constructor(){ + super(); + // dimension map provides the dimensions of the character for + // each number for plotting and collision detection + + /*this.dimension_map = { + 0 : [25,25], + 1 : [10,25], + 2 : [15,25], + 3 : [15,25], + 4 : [15,25], + 5 : [15,25], + 6 : [20,25], + 7 : [15,25], + 8 : [20,25], + 9 : [20,25], + 10 : [31,25], + 11 : [20,25], + 12: [25,25] + };*/ + this.widths = atob("BgsVCw8PEBEUEBQUBw=="); + this.font = atob("AAAAAAAAAAAAp9bgAAAAAAAAAAAADr+vAAAAAAAAAAAAAOv68AAAAAAAAAAAAA6/rwAAAAAAAAAAAADr+fAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAXwAAAAAAAAAAAAXz//wAAAAAAAAAXz//7q+AAAAAAAXz//8q+//wAAAAXz//8q+//yr3wAXz//8q+//yr3//ZAL/8q+//yr3//ZMAAAW+//2q3//ZQAAAAAC/2q3//pQAAAAAAAAF3//pQAAAAAAAAAAAnpQAAAAAAAAAAAAAAAAABL3//tgQAAAAAAAAj//su9//0gAAAAAC7/vv///73/gAAAAB/8/9u7u7/+34AAAA78/r/////c/+9QAAf9/P/LvLu/+///AADu/++//+7/7Pv79QAv37+/sQAAb/7978AF/f3vwAAAAD+/v+4Aj9779QAAAADs+/vwCP3vv1AAAAAOz7+/AF/P3fsAAAAC+/v94AL9+/v5AAAD/9/f/QAP3+/8/9ze/7+/v2AAj9+//Lztu+/P//AAAP/f3P////6//fcAAAL/z/y7u7vv7PoAAAAD/+z////9z/oAAAAAAK//3LvO/+QAAAAAAAAH3///6zAAAAAAAAAAAAAAAAAAAAAAC96fQAAAAAAAAAAAAL769AAAAAAAAAAAAAvvr5ZmZmZmZmZmAAC++v//////////8AAL76/bu7u7u7u7uwAAvvr/7u7u7u7u7uAAC++v/u7u7u7u7u4AAL76/KqqqqqqqqqgAAvvr///////////AAAjQlVVVVVVVVVVUAAAAAAAAAAAAAAAAAAAhTAAAAAAAAAyUlAAD7+udQAAAAHfv68AAPv777AAAAX/+/rwAC+/y/kAAAn+77+vAAb8/q9gAB79//v68ACf7frzAF/9/t+/rwAH/d+/QK/u/P/7+vAAX8/t/u/f/P7Pv68AAvv7+uzv3vz/+/rwAA/P3///z/v/Pr+vAACPv9u67939EOv68AAA/6///7/3AA6/rwAAAv/Ku+/iAADr+fAAAACu//5gAAAAAAAAAAAAAAAAAAAAAAAAAAhTAAAAAAAAAAIrIAD7+udgAAAAGo379gAPr7/rAAAAAfv935AB+vvvcjMkFQ/Pv+sAT6/d9K/r+vDs+/3QB/zvvzr+v68Nz7+/AJ/d+/Ov6/rx3Pv78Ab779+I/N/PX8+/zwAvv8/P/5/v7/z7/+AA+/z+m/r7/Kv9/PkACvv7///8+//7398gAB/9/bvvzvy8/89wAABv++/93+nf/b+gAAAALv/e/9//3v+wAAAAAASd21AVrcogAAAAAAAAAAAb753JAAAAAAAAAALP/frusAAAAAAAAE3/zO+u6wAAAAAABe/7z/367rAAAAAAf/+9/7vvrusAAAAG/+rv+s/9+u6wAAAAra//rf+5367rAAAABv/q7/q//vrusAAAAK2v/5z/w1+u6wAAAAb/6d/7IAX67rAAAACsr/+AL//vru//4AAG/+YAAaqr+u7aqgAAnUAAAD///67v//AAAAAAAABVWPruxVUAAAAAAAAAACtphgAAAAAAAAAAAAAAAAAAAAA0U3d3d3d1AADMAAAL76//////0ACr9AAAvvr9zMzMyABd/vAAC++v7u7u7qAPz79QAL76//////wPz975AAvvr8rN7Oyw+vv+wAC++vQN37/ODs+/vgAL769A6/v9wN37+/AAvvr0Dq+/3Q/Pv78AC++vQN38/vv8+/3QAL769Ar8397+7/36AAvvr0Bfv8/s/7/PMAC++vQA77+9/a+fwAAL769ABP3f///f8gAAVnSRAAb/mrzP8wAAAAAAAAAC3///wQAAAAAAAAAAAAJiAAAAAAAAAAA2ZmZiAAAAAAAAAK7//////+YAAAAAA//Lu7u7up77AAAABP+//+7u7v/5/QAAAP7fyN///+y/+/cAAH+/n/2qqqvv7vzwAA/f3+r/////v8+/cAD7+/v82rye38/e6wBPv9zrn9388fv7/NAI/O+va+/Pzw3Pv68Aj93689z7/dDc+vrwBPv+v06/z90Pz7++AA+/3vnO/Pz+/PvuwAD7+/o4/O/56/38+QAN/v5QP8/f//7PzxAAP89QAL+f3czfj6AAAK9wAAH/v///z/EAAADQAAAC79q879EAAAAAAAAAAJ3//YAAAAAAAAAAAAAAAAAAAAAL3p9AAAAAAAAAAAAAvvr0AAAAAAAAAAAAC++vQAAAAAAAAAAAAL769AAAAAAAAFrgAAvvr0AAAAAFrv/9AAC++vQAAFvv/9u98AAL769Wvv/8u9//6gAArN7//8u+//67z/AACv/8u+//27z//roAAFu+//273//rvP/wAAv/273//rvP//xxAABb3//rvP//xxAAAAAL/rvP//thAAAAAAAAXP/+thAAAAAAAAAACutgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGt/qYCvv2kAAAAAAb/69/+/+vP/AAAAAT+z//q/8//6/8QAAP8/7u9/P+7z/v7AADv36//+/v///778gAfv7/Lr/7++3/vz6AG+/7+/9+/v//Pz+0Aj8789d77+/Ds+/zwCf3Pryvuv68N36+vAJ/c+vK+6/rwzfr68An9z68r7r+vDN+vrwCPzvz1v+z78ez6+/AE+/7//fzv3+/Pv98AD7+/ne+/v57e/e/QAO7v3//9/u/v+vr2AAT9/7u9+v68uvz/AAAM/O////v///z/EAAACv+6vP/+u6z/IAAAAATP//1H3//7IAAAAAAAABAAAAEAAAAAAAAABJkwAAAAAAAAAAAAr///+gAAAAEQAAAB783dvP0QAADNAAAA37/93/n8AAC79QAAT5/c/9358wBt/vAADu/v+8/+79Afz79QAPn7+//Pv58Pv975AD+f7/zP3fjw+vv+wAf7789T+/6vTs+/vgCf3fvyP8/789z7+/AG+++/SP7Pvw+fr74AL5/e+837+/X3+v3AAPv7+//d3d797/35AA3+7/vMzMzK75+/MAA/r97//////r/fwAAAz5/7uqqqqt/d8gAAAe/N//////6v9gAAAACv/bqqqr3/4gAAAAAAOM/////aUAAAAAAAAAAAAAAAAAAAAAAAAAAQEQABARAAAAAAAABvvuoF+u6wAAAAAAAG++6gX67rAAAAAAAAb77qBfrusAAAAAAABvvuoF+u6wAAAAAAAE16pwPXunAAAAAAAAAAAAAAAAAAAA=="); + var scale = 1; // size multiplier for this font + this.size = 25+(scale<<8)+(4<<16); + this.y_offset = 0; + + } + getDimensions(hour){ + //return this.dimension_map[hour]; + switch(hour){ + case 0: + case 12: + return DIM_25x25; + case 1: + return DIM_10x25; + case 6: + case 8: + case 9: + case 11: + return DIM_20x25; + case 10: + return DIM_31x25; + default: + return DIM_15x25; + } + } + hour_txt(hour){ return hour.toString(); } + draw(hour_txt,x,y){ + /* going to leave this in here for future testing. + uncomment this so that it draws a box behind the string + so we can guess the digit dimensions*/ + /*var dim = [30,25]; + g.setColor(0.5,0,0); + g.fillPoly([x,y, + x+dim[0],y, + x+dim[0],y+dim[1], + x,y+dim[1] + ]); + g.setColor(1.0,1.0,1.0);*/ + g.setFontAlign(-1.0,-1.0,0); + g.setFontCustom(this.font, 46, this.widths, this.size); + g.drawString(hour_txt,x,y+this.y_offset ); + } + getName(){return "Digit";} +} + +module.exports = [DigitNumeralFont]; \ No newline at end of file diff --git a/apps/fontclock/fontclock.font.mntn50.js b/apps/fontclock/fontclock.font.mntn50.js new file mode 100644 index 000000000..43b8aeb9b --- /dev/null +++ b/apps/fontclock/fontclock.font.mntn50.js @@ -0,0 +1,56 @@ +var NumeralFont = require("fontclock.font.js"); + +const DIM_30x47 = [30,47]; +const DIM_49x47 = [49,47]; +const DIM_37x47 = [37,47]; +class DigitNumeralFont extends NumeralFont{ + constructor(){ + super(); + // dimension map provides the dimensions of the character for + // each number for plotting and collision detection + + /*this.dimension_map = { + 3 : [30,47], + 6 : [37,47], + 9 : [37,47], + 12: [49,47] + };*/ + this.widths = atob("DRYqFR0fHyMnICgnDQ=="); + this.font = atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAChkoAAAAAAAAAAAAAvP7wAAAAAAAAAAAAC8/vAAAAAAAAAAAAALz+8AAAAAAAAAAAAAvP7wAAAAAAAAAAAAC8/vAAAAAAAAAAAAALz+8AAAAAAAAAAAAAvP7wAAAAAAAAAAAAC8/vAAAAAAAAAAAAALz+8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAH/AAAAAAAAAAAAAB//8AAAAAAAAAAAAf///gAAAAAAAAAAH///5LAAAAAAAAAB///+S/8AAAAAAAAf///kv//wAAAAAAH///5L///4AAAAAB///+S///+G8AAAAf///kv///hv/wAAH///5L///4b///AAP//+S///+G///5AAA//kv///hv//+QAAAD5L///4b///kAAAAAC///+G///5AAAAAAA///hv//+QAAAAAAAD/4b///kAAAAAAAAAKG///5AAAAAAAAAAAv//+QAAAAAAAAAAAD//kAAAAAAAAAAAAAP5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAAAAAAAAAAC////4AAAAAAAAAAL//////gAAAAAAAAP//6Vr//8AAAAAAAH/9Gv/pH/9AAAAAAD/4v////4v/AAAAAA/8///////P/AAAAAP9v/4BUC//n/AAAAD/f/m///+b/3/AAAAv3/n/////2/3+AAAH9/3//+r//9/39AAA/v9/+G/+S/9/78AAD9/f+f///9v9/fwAAvf3/f/////f9/fgAD9/vz/4AAv/P78/AAf/39/0AAAH/f3/9AC9/f78AAAAD+/f34ALz+9/QAAAAH9+/PgA/Pvz8AAAAAPz+8/AD99/PgAAAAAvP338AP739+AAAAAC9/ffwA/ff34AAAAAL399/AD8+/PwAAAAA/P7z8APz/9/AAAAAD9//PgAvf37/AAAAA//39+AB+/Pz/AAAAP8/P70AD9/v3/wAAP/f79/AAP39/3/////3/f38AAf79/2////5/3+/QAA/f9/9r//p/9/78AAB/f9//5Rb//f9/QAAD/f9v/////n/f8AAAD/f/b////n/3/AAAAD/f/4WqlL/9/wAAAAH/X//////9f9AAAAAH/1/////9f/QAAAAAC/+H///0v/gAAAAAAB//+QAb//0AAAAAAAAf//////0AAAAAAAAAB/////QAAAAAAAAAAAAa6QAAAAAAAAAAAAAAAAAAAAAAAAClopAAAAAAAAAAAAAPvz4AAAAAAAAAAAAA+/PgAAAAAAAAAAAAD78+AAAAAAAAAAAAAPvz4AAAAAAAAAAAAA+/PgAAAAAAAAAAAAD78///////////wAAPvz///////////AAA+/P6qqqqqqqqqoAAD78///////////gAAPvz///////////AAA+/P//////////8AAD78+AAAAAAAAAAAAAPvz///////////AAA+/P//////////8AAD78/qqqqqqqqqqgAAPvz//////////+AAA+/P//////////8AAD68///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAAAAAAAAA/PQAAAAAAAG8+vAAD9+/ZAAAAAC/z+8AAP/3+9AAAAA//P7wAB+/PvwAAAAf/8/vAAL3+9/AAAAL/bz+8AA/P/z8AAAD/r/P7wAD9+/PgAAB/7/8/vAAP379+AAAv+//z+8AA/vf30AAP+/9vP7wAD+9/vQAH/v+v8/vAAP7399AD/7/f/z+8AA/fv30A/7/3//P7wAD9+/Pgv+/7/28/vAALz+9/v/v9/9/z+8AAvP3+//v/v+v/P7wAB+/f3/7/v/f/8/vAAD+/v4H/3/3/bz+8AAP39///7/2/0vP7wAAf79v/9/9/8C8/vAAA/f9G5/+v+ALz+8AAC/f/7//f/QAvP7wAAD/P///r/wAC8/vAAAH/n//n/0AALz+8AAAH/5Ab/8AAAvP7wAAAH////9AAAB8tfAAAAC///9AAAAAAAAAAAAAK/kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyQAAAAAAAAABj4AA/P7gAAAAAAAu/PwAD9+/fQAAAAH3+9/AAP73+8AAAAAfv378AB+/PvwAAAAA//P70AL3+9/AAAAAD+9/fgA/P7z8KWiloPz78+AD8+/Pg/vP7wvP/z8APz78+D+8/vC8/vPwA/fv34P7z+8L3+8/AD99/fQ/vP7wvf738AP3399D+8/vB9/ffwA/ff30P7z+8H3+9/AD9+/fg/vf30vP738APz/8/D9+/Pj8+/PwA/P77//z/9//778+AC+/f3//f3+/9/f74AD+/v3/+/v6/f7+/AAPz9/5b9/f+b/fz8AAv79////+v//3+/gAA/f9///3/f/9/38AAC/f+RR/3/Rlv9/gAAD/f////3////f8AAAD/b////3///3/AAAAH/2//X/5//n/0AAAAD/+lr///lb/8AAAAAC////9////+AAAAAAAv//9Af//+AAAAAAAABaQAAAaQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7z58AAAAAAAAAAAB//P7wAAAAAAAAAAC//8/vAAAAAAAAAAC//rz+8AAAAAAAAAD//X/P7wAAAAAAAAH//X/8/vAAAAAAAAH//b//z+8AAAAAAAH//L/+vP7wAAAAAAL/+P/9f8/vAAAAAAL/+f/9f/z+8AAAAAL/9f/8v//P7wAAAAD/9f/4v/68/vAAAAAP9v/4//4vz+8AAAAA8v/5//0v/P7wAAAAAv/1//1//8/vAAAAAP/1//x///z+8AAAAA/y//i//wvP7wAAAADi//i//gC8/vAAAAAD//X//gALz+8AAAAA//X//QAAvP7wAAAAD/L//Af//8/vv/gAAOL/+AC///z+///AAAP/+AAH///P7//8AAD/9AAAAAC8/vAAAAAP9AAAB///z+///AAA4AAAAL///P7//8AAAAAAAAKqr8/vaqgAAAAAAAAAALz+8AAAAAAAAAAAAAvPrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAA8AAAD14//////0AAL8AAAPvz//////gACf8AAA+/P/////+AAvfwAAD78+AAAAAAAD/vwAAPvz//////gA39/AAA+/P/////+AP3++AAD78/qqqqqgA/fz8AAPvz//////Qt/vvwAA+/P/////+D78/vQAD78//////4P739+AAPvz4A9ufPQ/Pvz8AA+/PgH3+9+C8+vPwAD78+Avf/z0L3+9/AAPvz4C8//fAff338AA+/PgLz7+8B9/vfwAD78+AvPv7wL3+9/AAPvz4D8+/fg/P/z8AA+/PgLz+8/D9+/PwAD78+AvP77///39+AAPvz4B+/P3/9/v/wAA+/PgD9+/3/f39/AAD78+AP38/0L/f78AAPvz4Av79///39/QAA+/PgA/f8//9//8AAD78+AB/f9L5f9/QAAPvz4AD/f/6//f8AAA+/PgAD/P///3/AAAD289AAH/j//y/wAAAAAAAAAH/9AH/8AAAAAAAAAAD////+AAAAAAAAAAAB///+AAAAAAAAAAAAAGvpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa////6QAAAAAAAAB///////+AAAAAAAB/////////gAAAAAA//kAAAABv/0AAAAAP/X//////n/0AAAAD/b///////6/0AAAA/3//6qqqv/9/wAAAL9/9a////kv9/wAAB/P+v//////P9/QAAP6/f///////P+/AAA/P3/5AAAAf/fz8AAP3+/2/////3/v74AA/f79//////79/fwAD/+/f/6qqr/3++/AAvf39/Pz799//3+9AD8/vfw/vf/w/fv38APz/8/D/9+/D8+/PwA/fvz4ff734L3/9/AD99/fS8//fQff738AP3399Lz799B9/ffwA/ff30vPv7wH3+9/AD9+/Pj8+/vQvP7z8APz68+Lz79+D8+/PwA/P338vP7z8f779+AB+/f/x+/f//+/f70AD+9/fD+9/f/7/+/AAP3+/QP3+/b2/f38AA/fz8Av/3///7//gAB/v3QA/f3///v38AAD9/gAC/v2//b+/gAAH9+AAD+/+AL/r8AAAP+wAAH+v///6/QAAAP0AAAP/f//9/4AAAAfQAAAP/lvlv+AAAAAkAAAAL//r//QAAAAAAAAAAD////wAAAAAAAAAAAAv//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPrz4AAAAAAAAAAAAA+/PgAAAAAAAAAAAAD78+AAAAAAAAAAAAAPvz4AAAAAAAAAAAAA+/PgAAAAAAAAAAAAD78+AAAAAAAAAAAAAPvz4AAAAAAAAAGAAA+/PgAAAAAAAB/8AAD78+AAAAAAAv//wAAPvz4AAAAAL///4AAA+/PgAAAC///+G8AAD78+AAAv///hv/wAAPvz4AL///4b///AAA+/Pm///+G///9EAAD79////Rv//+R/wAAPr///0f///kv//AAA///9H///5L///4AAD//R///+S///+GwAAPkf///kv///hv/AAAL///5L///4b//8AAD//+W///+G///9AAAP/hv///Rv//+QAAAAob///0f///kAAAAAC///9H///5AAAAAAAP//R///+QAAAAAAAA/kf///kAAAAAAAAAAL///5AAAAAAAAAAAP//+QAAAAAAAAAAAA//kAAAAAAAAAAAAAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//0AL//9AAAAAAAf///+L////QAAAAAP/+r////r//wAAAAD/0v5f/4r6b/wAAAA/6///n////1/wAAAP9////3////9/gAAC/f/gG/3/kB/9/AAAP7/b/9/3//+f+/AAC/f3//9/v///f79AAP39/+/9/f///f38AA/v/9uf+/v/n+/vwAL79/f/v38//38/vQA/P77//f7z///78/AD8//Pz9/vfw/Prz8AP379+H79+/D8/vfwA/vf30Pvz68L399/AD+9/fQ+/Prwff378AP7399D78+vB9/fvwA/vf30Pvz68H39+/AD+9/fQ+/Prwff378AP7399D78+vB9/fvwA/vf30Pvz+8H39+/AD9+/fg/vP7wvf338APz/8/D+8/vT8/vfwA/P77/v339//378/AC9/f7//P77/+/f34AH++/r/9/f3/r9/vQAP39/0H++v4D/f38AA/v+///39///+/fwAA/f9///39//+v39AAD/v9b5/v+b+P+/wAAD/f/6//v/6//r8AAAH/f////7///2/gAAAL/X//3/3//5/4AAAAH/5FC//9BB/+AAAAAH//////////QAAAAAB////A////QAAAAAAAK/5AAG/5QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//QAAAAAAAAAAAAv///4AAAAAAAAAAAf////9AAAABQAAAAH/0aR/9AAAAPQAAAB/2//+v9AAAC/AAAAf9////f8AAA3/AAAD/f/Qf/f4AAL38AAAv3/P/n/fwAAv78AAD+/r//3/fwAd/fwAAv7+///7+/AD9/vgAD9/f8pv3+/Af39/AAP7//v//v38Lf778AB+/f3/9/f/w//P70AL3++/r+9/vT99/fgA/P7z8Pz79+Pz78/AD9+/Pgvf/z4vPrz8AP3799B9/vPi9/vfwA/vf30D7+8+H399/AD9+/fQff/z4ff338AP3799C8+/fS8/vfwA/P7z4P73+8Pz/8/AD8/vfw//fvw/fvz8AL39//n3+8/P79/fgAP/39/6VVVv/f7/8AA/f7+//////3+/fwAD+/f9/////9/79/AAH9/f+FVVVRv9/P0AAP3+f///////f9/AAAf3/f//////7/P0AAA/3/W////+j/3/AAAA/7/+lVVVr/9/wAAAB/3///////+f9AAAAB/9//////+L/QAAAAB//QVVVVQv/wAAAAAA/////////4AAAAAAAf///////4AAAAAAAABv////+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB89fAHz18AAAAAAAAPz78AvP7wAAAAAAAA/PvwC8/vAAAAAAAAD8+/ALz+8AAAAAAAAPz78AvP7wAAAAAAAA/PvwC8/vAAAAAAAAD8+/ALz+8AAAAAAAAPz78AvP7wAAAAAAAA/PvwC8/vAAAAAAAAC8+vALz68AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="); + var scale = 1; // size multiplier for this font + this.size = 50+(scale<<8)+(2<<16); + this.y_offset = -2; + + } + getDimensions(hour){ + switch(hour){ + case 3: + return DIM_30x47; + case 12: + return DIM_49x47; + default: + return DIM_37x47; + } + //return this.dimension_map[hour]; + } + hour_txt(hour){ return hour.toString(); } + draw(hour_txt,x,y){ + /* going to leave this in here for future testing. + uncomment this so that it draws a box behind the string + so we can guess the digit dimensions + var dim = [37,47]; + g.setColor(0.5,0,0); + g.fillPoly([x,y, + x+dim[0],y, + x+dim[0],y+dim[1], + x,y+dim[1] + ]); + g.setColor(1.0,1.0,1.0);*/ + g.setFontAlign(-1.0,-1.0,0); + g.setFontCustom(this.font, 46, this.widths, this.size); + g.drawString(hour_txt,x,y+this.y_offset ); + } + getName(){return "Digit";} +} + +module.exports = [DigitNumeralFont]; \ No newline at end of file diff --git a/apps/fontclock/fontclock.font.vector25.js b/apps/fontclock/fontclock.font.vector25.js new file mode 100644 index 000000000..0c66b1d07 --- /dev/null +++ b/apps/fontclock/fontclock.font.vector25.js @@ -0,0 +1,55 @@ +var NumeralFont = require("fontclock.font.js"); + +const DIM_14x22 = [14,22]; +const DIM_27x22 = [27,22]; +class DigitNumeralFont extends NumeralFont{ + constructor(){ + super(); + // dimension map provides the dimesions of the character for + // each number for plotting and collision detection + /*this.dimension_map = { + 1 : [14,22], + 2 : [14,22], + 3 : [14,22], + 4 : [14,22], + 5 : [14,22], + 6 : [14,22], + 7 : [14,22], + 8 : [14,22], + 9 : [14,22], + 10: [27,22], + 11: [27,22], + 12: [27,22] + };*/ + } + getDimensions(hour){ + if (hour < 10){ + return DIM_14x22; + } else { + return DIM_27x22; + } + } + hour_txt(hour){ return hour.toString(); } + draw(hour_txt,x,y){ + if(hour_txt == null) + return; + + /* going to leave this in here for future testing. + uncomment this so that it draws a box behind the string + so we can guess the digit dimensions + var dim = [14,22]; + g.setColor(0.5,0,0); + g.fillPoly([x,y, + x+dim[0],y, + x+dim[0],y+dim[1], + x,y+dim[1] + ]); + g.setColor(1.0,1.0,1.0);*/ + g.setFontAlign(-1,-1,0); + g.setFont("Vector",25); + g.drawString(hour_txt,x,y); + } + getName(){return "Digit";} +} + +module.exports = [DigitNumeralFont]; \ No newline at end of file diff --git a/apps/fontclock/fontclock.font.vector50.js b/apps/fontclock/fontclock.font.vector50.js new file mode 100644 index 000000000..85466958f --- /dev/null +++ b/apps/fontclock/fontclock.font.vector50.js @@ -0,0 +1,42 @@ +var NumeralFont = require("fontclock.font.js"); + +const DIM_28x44 = [28,44]; +const DIM_54x44 = [54,44]; + +class DigitNumeralFont extends NumeralFont{ + constructor(){ + super(); + // dimension map provides the dimesions of the character for + // each number for plotting and collision detection + } + getDimensions(hour){ + if (hour < 10){ + return DIM_28x44; + } else { + return DIM_54x44; + } + } + hour_txt(hour){ return hour.toString(); } + draw(hour_txt,x,y){ + if(hour_txt == null) + return; + + /* going to leave this in here for future testing. + uncomment this so that it draws a box behind the string + so we can guess the digit dimensions + var dim = [14,22]; + g.setColor(0.5,0,0); + g.fillPoly([x,y, + x+dim[0],y, + x+dim[0],y+dim[1], + x,y+dim[1] + ]); + g.setColor(1.0,1.0,1.0);*/ + g.setFontAlign(-1,-1,0); + g.setFont("Vector",50); + g.drawString(hour_txt,x,y); + } + getName(){return "Digit";} +} + +module.exports = [DigitNumeralFont]; \ No newline at end of file diff --git a/apps/fontclock/fontclock.hand.js b/apps/fontclock/fontclock.hand.js new file mode 100644 index 000000000..c5ab2e769 --- /dev/null +++ b/apps/fontclock/fontclock.hand.js @@ -0,0 +1,10 @@ +class Hand { + /** + * Pure virtual class for all Hand classes to extend. + * a hand class will have 1 main function + * moveTo which will move the hand to the given angle. + */ + moveTo(angle){} +} + +module.exports = Hand; \ No newline at end of file diff --git a/apps/fontclock/fontclock.hourscriber.js b/apps/fontclock/fontclock.hourscriber.js new file mode 100644 index 000000000..38f960da3 --- /dev/null +++ b/apps/fontclock/fontclock.hourscriber.js @@ -0,0 +1,137 @@ + +const TWO_PI = 2* Math.PI; + +// The problem with the trig inverse functions on +// a full circle is that the sector information will be lost +// Choosing to use arcsin because you can get back the +// sector with the help of the original coordinates +function reifyasin(x,y,asin_angle){ + if(x >= 0 && y >= 0){ + return asin_angle; + } else if(x >= 0 && y < 0){ + return Math.PI - asin_angle; + } else if(x < 0 && y < 0){ + return Math.PI - asin_angle; + } else { + return TWO_PI + asin_angle; + } +} + +// rebase and angle so be between -pi and pi +// rather than 0 to 2PI +function rebaseNegative(angle){ + if(angle > Math.PI){ + return angle - TWO_PI; + } else { + return angle; + } +} + +// rebase an angle so that it is between 0 to 2pi +// rather than -pi to pi +function rebasePositive(angle){ + if(angle < 0){ + return angle + TWO_PI; + } else { + return angle; + } +} + +/** + * The Hour Scriber is responsible for drawing the numeral + * on the screen at the requested angle. + * It allows for the font to be changed on the fly. + */ +class HourScriber { + constructor(radius, numeral_font, draw_test, bg_colour_supplier, numeral_colour_supplier, hour){ + this.radius = radius; + this.numeral_font = numeral_font; + this.draw_test = draw_test; + this.curr_numeral_font = numeral_font; + this.bg_colour_supplier = bg_colour_supplier; + this.numeral_colour_supplier = numeral_colour_supplier; + this.hours = hour; + this.curr_hour_x = -1; + this.curr_hour_y = -1; + this.curr_hours = -1; + this.curr_hour_str = null; + this.last_draw_time = null; + } + setNumeralFont(numeral_font){ + this.numeral_font = numeral_font; + } + toString(){ + return "HourScriber{numeralfont=" + this.numeral_font.getName() + ",hours=" + this.hours + "}"; + } + draw(){ + var changed = false; + if(this.curr_hours != this.hours || this.curr_numeral_font !=this.numeral_font){ + var background = this.bg_colour_supplier(); + g.setColor(background[0],background[1],background[2]); + this.curr_numeral_font.draw(this.curr_hour_str, + this.curr_hour_x, + this.curr_hour_y); + //console.log("erasing old hour"); + var hours_frac = this.hours / 12; + var angle = TWO_PI*hours_frac; + var dimensions = this.numeral_font.getDimensions(this.hours); + // we set the radial coord to be in the middle + // of the drawn text. + var width = dimensions[0]; + var height = dimensions[1]; + var delta_center_x = this.radius*Math.sin(angle) - width/2; + var delta_center_y = this.radius*Math.cos(angle) + height/2; + this.curr_hour_x = screen_center_x + delta_center_x; + this.curr_hour_y = screen_center_y - delta_center_y; + this.curr_hour_str = this.numeral_font.hour_txt(this.hours); + // now work out the angle of the beginning and the end of the + // text box so we know when to redraw + // bottom left angle + var x1 = delta_center_x; + var y1 = delta_center_y; + var r1 = Math.sqrt(x1*x1 + y1*y1); + var angle1 = reifyasin(x1,y1,Math.asin(x1/r1)); + // bottom right angle + var x2 = delta_center_x; + var y2 = delta_center_y - height; + var r2 = Math.sqrt(x2*x2 + y2*y2); + var angle2 = reifyasin(x2,y2,Math.asin(x2/r2)); + // top left angle + var x3 = delta_center_x + width; + var y3 = delta_center_y; + var r3 = Math.sqrt(x3*x3 + y3*y3); + var angle3 = reifyasin(x3,y3, Math.asin(x3/r3)); + // top right angle + var x4 = delta_center_x + width; + var y4 = delta_center_y - height; + var r4 = Math.sqrt(x4*x4 + y4*y4); + var angle4 = reifyasin(x4,y4,Math.asin(x4/r4)); + if(Math.min(angle1,angle2,angle3,angle4) < Math.PI && Math.max(angle1,angle2,angle3,angle4) > 1.5*Math.PI){ + angle1 = rebaseNegative(angle1); + angle2 = rebaseNegative(angle2); + angle3 = rebaseNegative(angle3); + angle3 = rebaseNegative(angle4); + this.angle_from = rebasePositive( Math.min(angle1,angle2,angle3,angle4) ); + this.angle_to = rebasePositive( Math.max(angle1,angle2,angle3,angle4) ); + } else { + this.angle_from = Math.min(angle1,angle2,angle3,angle4); + this.angle_to = Math.max(angle1,angle2,angle3,angle4); + } + //console.log(angle1 + "/" + angle2 + " / " + angle3 + " / " + angle4); + //console.log( this.angle_from + " to " + this.angle_to); + this.curr_hours = this.hours; + this.curr_numeral_font = this.numeral_font; + changed = true; + } + if(changed || + this.draw_test(this.angle_from, this.angle_to, this.last_draw_time) ){ + var numeral_color = this.numeral_colour_supplier(); + g.setColor(numeral_color[0],numeral_color[1],numeral_color[2]); + this.numeral_font.draw(this.curr_hour_str,this.curr_hour_x,this.curr_hour_y); + this.last_draw_time = new Date(); + //console.log("redraw digit:" + this.hours); + } + } +} + +module.exports = HourScriber; \ No newline at end of file diff --git a/apps/fontclock/fontclock.js b/apps/fontclock/fontclock.js new file mode 100644 index 000000000..25260c42c --- /dev/null +++ b/apps/fontclock/fontclock.js @@ -0,0 +1,432 @@ +/** +* Adrian Kirk 2021-03 +* Simple Clock showing 1 numeral for the hour +* with a smooth sweep second. +*/ + +var ThinHand = require("fontclock.thinhand.js"); +var ThickHand = require("fontclock.thickhand.js"); +var HourScriber = require("fontclock.hourscriber.js"); + +const screen_center_x = g.getWidth()/2; +const screen_center_y = 10 + (g.getHeight()+10)/2; +const TWO_PI = 2* Math.PI; + + +SETTING_PREFIX = "fontclock"; +// load the date formats and languages required +const FONTS_FILE = SETTING_PREFIX +".font.json"; +const DEFAULT_FONTS = [ "cpstc58" ]; +const DEFAULT_NUMERALS = [12,3,6,9]; +const DEFAULT_RADIUS = 70; +var color_schemes = [ + { + name: "black", + background : [0.0,0.0,0.0], + } +]; +var fonts = DEFAULT_NUMERALS; +var numerals = DEFAULT_NUMERALS; +var radius = DEFAULT_RADIUS; +try{ + var fonts_info = require("Storage").readJSON(FONTS_FILE); + if(fonts_info != null){ + console.log("loaded font:" + JSON.stringify(fonts_info)); + fonts = fonts_info.fonts; + numerals = fonts_info.numerals; + radius = fonts_info.radius; + color_schemes = fonts_info.color_schemes; + } else { + fonts = DEFAULT_FONTS; + numerals = DEFAULT_NUMERALS; + radius = DEFAULT_RADIUS; + console.log("no fonts loaded defaulting to:" + fonts); + } +} catch(e){ + console.log("failed to load fonts:" + e); +} +if(fonts == null || fonts.length == 0){ + fonts = DEFAULT_FONTS; + console.log("defaulting fonts to locale:" + fonts); +} + +let color_scheme_index = 0; + +// The force draw is set to true to force all objects to redraw themselves +let force_redraw = true; +let bg_colour_supplier = ()=>color_schemes[color_scheme_index].background; +var WHITE = [1.0,1.0,1.0]; +function default_white(color){ + if(color == null){ + return WHITE + } else { + return color; + } +} + +// The seconds hand is the main focus and is set to redraw on every cycle +let seconds_hand = new ThinHand(screen_center_x, + screen_center_y, + 95, + 0, + (angle, last_draw_time) => false, + bg_colour_supplier, + ()=>default_white(color_schemes[color_scheme_index].second_hand)); + +// The minute hand is set to redraw at a 250th of a circle, +// when the second hand is ontop or slighly overtaking +// or when a force_redraw is called +const minute_hand_angle_tolerance = TWO_PI/25 +let minutes_hand_redraw = function(angle, last_draw_time){ + return force_redraw || (seconds_hand.angle > angle && + Math.abs(seconds_hand.angle - angle) < minute_hand_angle_tolerance && + new Date().getTime() - last_draw_time.getTime() > 500); +}; + +let minutes_hand = new ThinHand(screen_center_x, + screen_center_y, + 80, minute_hand_angle_tolerance, + minutes_hand_redraw, + bg_colour_supplier, + ()=>default_white(color_schemes[color_scheme_index].minute_hand)); +// The hour hand is a thick hand so we have to redraw when the minute hand +// overlaps from its behind angle coverage to its ahead angle coverage. +let hour_hand_redraw = function(angle_from, angle_to, last_draw_time){ + return force_redraw || (seconds_hand.angle >= angle_from && + seconds_hand.angle <= angle_to && + new Date().getTime() - last_draw_time.getTime() > 500); +}; +let hours_hand = new ThickHand(screen_center_x, + screen_center_y, + 40, + TWO_PI/600, + hour_hand_redraw, + bg_colour_supplier, + () => default_white(color_schemes[color_scheme_index].hour_hand), + 5, + 4); + +function draw_clock(){ + var date = new Date(); + draw_background(); + draw_hour_digits(); + draw_seconds(date); + draw_mins(date); + draw_hours(date); + force_redraw = false; +} +// drawing the second the millisecond as we need the fine gradation +// for the sweep second hand. +function draw_seconds(date){ + var seconds = date.getSeconds() + date.getMilliseconds()/1000; + var seconds_frac = seconds / 60; + var seconds_angle = TWO_PI*seconds_frac; + seconds_hand.moveTo(seconds_angle); +} +// drawing the minute includes the second and millisec to make the +// movement as continuous as possible. +function draw_mins(date,seconds_angle){ + var mins = date.getMinutes() + date.getSeconds()/60 + date.getMilliseconds()/(60*1000); + var mins_frac = mins / 60; + var mins_angle = TWO_PI*mins_frac; + var redraw = minutes_hand.moveTo(mins_angle); + if(redraw){ + //console.log("redraw mins"); + } +} + +function draw_hours(date){ + var hours = (date.getHours() % 12) + date.getMinutes()/60 + date.getSeconds()/3600; + var hours_frac = hours / 12; + var hours_angle = TWO_PI*hours_frac; + var redraw = hours_hand.moveTo(hours_angle); + if(redraw){ + //console.log("redraw hours"); + } +} + + + +let numeral_fonts = []; +for(var i=0; i< fonts.length; i++) { + var file = SETTING_PREFIX +".font." + fonts[i] + ".js" + console.log("loading font set:" + fonts[i] + "->" + file); + var loaded_fonts = require(file); + for (var j = 0; j < loaded_fonts[j]; j++) { + var loaded_font = new loaded_fonts[j]; + numeral_fonts.push(loaded_font); + console.log("loaded font name:" + loaded_font.getName()) + } +} + +let numeral_fonts_index = 0; +const ONE_POINT_FIVE_PI = 1.5*Math.PI; +/** +* predicate for deciding when the digit has to be redrawn +*/ +let hour_numeral_redraw = function(angle_from, angle_to, last_draw_time){ + var seconds_hand_angle = seconds_hand.angle; + // we have to cope with the 12 problem where the + // left side of the box has a value almost 2PI and the right + // side has a small positive value. The values are rebased so + // that they can be compared + if(angle_from > angle_to && angle_from > ONE_POINT_FIVE_PI){ + angle_from = angle_from - TWO_PI; + if(seconds_hand_angle > Math.PI) + seconds_hand_angle = seconds_hand_angle - TWO_PI; + } + //console.log("initial:" + angle_from + "/" + angle_to + " seconds " + seconds_hand_angle); + var redraw = force_redraw || + (seconds_hand_angle >= angle_from && seconds_hand_angle <= angle_to && seconds_hand.last_draw_time.getTime() > last_draw_time.getTime()) || + (minutes_hand.last_draw_time.getTime() > last_draw_time.getTime()); + if(redraw){ + //console.log(angle_from + "/" + angle_to + " seconds " + seconds_hand_angle); + } + return redraw; +}; + +// now add the numbers to the clock face +var numeral_colour_supplier = () => default_white(color_schemes[color_scheme_index].numeral); +var hour_scribers = []; +console.log("numerals:" + numerals + " length:" + numerals.length) +console.log("radius:" + radius) +for(var digit_idx=0; digit_idx" + scriber); +} +//console.log("hour_scribers:" + hour_scribers ); + +/** +* Called from button 1 to change the numerals that are +* displayed on the clock face +*/ +function next_font() { + var curr_font = numeral_fonts_index; + numeral_fonts_index = numeral_fonts_index + 1; + if (numeral_fonts_index >= numeral_fonts.length) { + numeral_fonts_index = 0; + } + + if (curr_font != numeral_fonts_index) { + for (var i = 0; i < hour_scribers.length; i++) { + hour_scribers[i].setNumeralFont( + numeral_fonts[numeral_fonts_index]); + } + force_redraw = true; + return true; + } else { + return false; + } +} + +const hour_zone_angle = hour_scribers.length/TWO_PI; +function draw_hour_digits() { + if(force_redraw){ + for(var i=0; i" + scriber); + scriber.draw(); + } + } else { + var hour_scriber_idx = (0.5 + (seconds_hand.angle * hour_zone_angle)) | 0; + if (hour_scriber_idx >= hour_scribers.length) + hour_scriber_idx = 0; + + //console.log("angle:" + seconds_hand.angle + " idx:" + hour_scriber_idx); + if (hour_scriber_idx >= 0) { + hour_scribers[hour_scriber_idx].draw(); + } + } +} + + + +function draw_background(){ + if(force_redraw){ + background = color_schemes[color_scheme_index].background; + g.setColor(background[0],background[1],background[2]); + g.fillPoly([0,25, + 0,240, + 240,240, + 240,25 + ]); + } +} + +function next_colorscheme(){ + var prev_color_scheme_index = color_scheme_index; + color_scheme_index += 1; + color_scheme_index = color_scheme_index % color_schemes.length; + //console.log("color_scheme_index=" + color_scheme_index); + force_redraw = true; + if(prev_color_scheme_index == color_scheme_index){ + return true; + } else { + return false; + } +} + +/** +* called from load_settings on startup to +* set the color scheme to named value +*/ +function set_colorscheme(colorscheme_name){ + console.log("setting color scheme:" + colorscheme_name); + for (var i=0; i < color_schemes.length; i++) { + if(color_schemes[i].name == colorscheme_name){ + color_scheme_index = i; + force_redraw = true; + console.log("match"); + break; + } + } +} + +/** +* called from load_settings on startup +* to set the font to named value +*/ +function set_font(font_name){ + console.log("setting font:" + font_name); + for (var i=0; i < numeral_fonts.length; i++) { + if(numeral_fonts[i].getName() == font_name) { + numeral_fonts_index = i; + force_redraw = true; + console.log("match"); + for (var j = 0; j < hour_scribers.length; j++) { + hour_scribers[j].setNumeralFont(numeral_fonts[numeral_fonts_index]); + } + break; + } + } +} + +/** +* Called on startup to set the watch to the last preference settings +*/ +function load_settings(){ + try{ + var file = SETTING_PREFIX + ".settings.json"; + settings = require("Storage").readJSON(file); + if(settings != null){ + console.log(file + " loaded:" + JSON.stringify(settings)); + if(settings.color_scheme != null){ + set_colorscheme(settings.color_scheme); + } + if(settings.font != null){ + set_font(settings.font); + } + } else { + console.log(file + " not found - no settings to load"); + } + } catch(e){ + console.log("failed to load settings:" + e); + } +} + +/** +* Called on button press to save down the last preference settings +*/ +function save_settings(){ + var settings = { + font : numeral_fonts[numeral_fonts_index].getName(), + color_scheme : color_schemes[color_scheme_index].name, + }; + var file = SETTING_PREFIX + ".settings.json"; + console.log(file + ": saving:" + JSON.stringify(settings)); + require("Storage").writeJSON(file,settings); +} + +// Boiler plate code for setting up the clock, +// below +let intervalRef = null; + +function clearTimers(){ + if(intervalRef) { + clearInterval(intervalRef); + intervalRef = null; + } +} + +function startTimers(){ + setTimeout(scheduleDrawClock,100); + draw_clock(); +} + +// The clock redraw is set to 100ms. This is the smallest number +// that give the (my) human eye the illusion of a continious sweep +// second hand. +function scheduleDrawClock(){ + if(intervalRef) clearTimers(); + intervalRef = setInterval(draw_clock, 100); + draw_clock(); +} + +function reset_clock(){ + force_redraw = true; +} + +Bangle.on('lcdPower', (on) => { + if (on) { + console.log("lcdPower: on"); + reset_clock(); + startTimers(); + } else { + console.log("lcdPower: off"); + reset_clock(); + clearTimers(); + } +}); + +Bangle.on('faceUp',function(up){ + console.log("faceUp: " + up + " LCD: " + Bangle.isLCDOn()); + if (up && !Bangle.isLCDOn()) { + //console.log("faceUp and LCD off"); + clearTimers(); + Bangle.setLCDPower(true); + } +}); + +g.clear(); +load_settings(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +startTimers(); + +function button1pressed() { + if (next_font()) { + save_settings(); + } +} + +function button2pressed() { + clearTimers(); + // the clock is being unloaded so we clear out the big + // data structures for the launcher + hour_scribers = []; + Bangle.showLauncher(); +} + +function button3pressed(){ + if(next_colorscheme()) { + save_settings(); + } +} + +// Handle button 1 being pressed +setWatch(button1pressed, BTN1,{repeat:true,edge:"falling"}); + +// Handle button 1 being pressed +setWatch(button2pressed, BTN2,{repeat:true,edge:"falling"}); + +// Handle button 3 being pressed +setWatch(button3pressed, BTN3,{repeat:true,edge:"falling"}); + diff --git a/apps/fontclock/fontclock.png b/apps/fontclock/fontclock.png new file mode 100644 index 0000000000000000000000000000000000000000..70a1cd5327a61bc1b0d393b57e2093864e565b9c GIT binary patch literal 2669 zcmZ`*c{r478-GXk?p)c+{?6b0`1>Ob#g46*ZED8Wt*`}}=0PxoWfVXY{ zfXV;>X=+ZL9h&W6k_cEY8yi5At@8ssAaP(DTLZB_03-)+qOmo=5+wg!$AdJ!VYmPw zmJD!z!yIKx&az-{4rfbp<#BySXyk4Cp>v@3B_kEtLV#-FLzzm!eb76qq9$j;1di66$OI@1_nX{wV@Q+aTr`* zUmvE0fFTeNHUdIF?aOdyLVW4Fwu1aG4u(Ycq>-r%GR0S!6W85?;?FPygE@)5udO;6 zWUn8YeCglXVmAomcwlg-7VK9v5|jKdG>&JB_O-9AbZAa6)FB#~#4eaqmJuBNHNpSc zew4R`$CKz3Z+{Nl!I#W1LVTnA!~7GAlN)7AW|F*}Fk~N+FP)PKp`(R{{nGPGCgES1 zKY9MiG^2P^X!cZhPZFoGugQKgeM6&RoLT%do2|irwX!E~B#4H6zePrZBc{Isgchv(`i zxF%HKsg(i4gtInws%mGY)4<0qdZJy{N_E7pmFcU7E18)6HqG*yZ+zjjWgs#JK606g|s|TG?#Q19D1d+;5eF>Pv+vGdCU{;UUV% z)SZb^S-z<8dz!4|ec{%&p7~&IJxt=e2b4mx$G}`3-T%5P@!`tVD`}u}N>Sk{-Rt1Q z!!aX<8{mT3h0eTjJtEv$uCo(R>q2-I%nJ*)o2|5lgRwVs7kD4<(WW`yN8sUzdk-Qz z9)Fa`J`ywQyp5;d)=^#m|4q?xxQtWnX4Xu_uV}=%0G5y*N zf>Z>umgyU2bUdl*BNrljje9C$mFv;tbSXB)Vca$j}6@(Skd7K&84YGW61+)W)(% zuUX+kN}+^%+P0W6Jl0xgy_k0Z{}ck!;DXiExZRMzpmeQUXEE(li*bm zDGjsY4>G++N#^eG1-|)1!)>Nm(CDX^Kr2j7W(jBHHD_lW5fz4TyR1akS3c`u97cxyvnhGZ&z*n z! zB|H4m)x7F&j6->kCwk$P%j<@EF_S+ZKMIOQ8WZE}2VM~(-PI-eBd7d3L)x!q60k{j zs1V^jg~bkr(k23TDl?0U)K+jJ0`7@jZ3EAaEvjDHf8_9gzz~ybepqXDbWG#XkixdL z?ws|d8D~JPQc2?d4Lc8bqLxe|LHXhnjM?r^2FS&+&OlVA%Hd89t3pT0rc&O48^P19 z2i_+6setc2em}G~^ggMi!xm*BK5E_=?mD7EIKTHdKPe%)xY3a(>Zn{LM5ge`$%L7-nhS`xJ~7Z(*1h2WfX^!9!|e>b(_N>%l46OF^w2ee>-7Aa>hk3bd_I7B`pp|q<8Ds0JZ#^k_^x03vT^>KzyIA6-Gin$_mX}?-;uCu}@oDBVkIq zYiE(YT|`4xZ{E=ov+AV*O`{33eO%d+hrHU42)`mjy~}ZlPnCjlQN8hFE9N5UtH7>_ z#nEdAbE?m4LRQ{y(i{BMGpAgN`X_Jpwdsa#%CoAg%POjPwSC7IW+b2mmmZ&Nu+_(Y zZf$R`)l_vKo~^Gb3+0Op5lrggzp}9*%6NS`Vmn5qIVlr)cVh(Pb1~G6-=eQEpgwYG zwwIsxQcY9SfyL*B3PT|~tK@7<@7&(!=<8#JO&t%iDD*C{$Eu!VX+rZYGz05uRM!yd guW3u`ALm1XW#=8{i!Y this.tolerance || this.draw_test(this.angle - this.delta_base,this.angle + this.delta_base ,this.last_draw_time) ){ + //var background = color_schemes[color_scheme_index].background; + var background = this.color_bg_supplier; + g.setColor(background[0],background[1],background[2]); + g.fillPoly([this.last_x1, + this.last_y1, + this.last_x2, + this.last_y2, + this.last_x3, + this.last_y3, + this.last_x4, + this.last_y4 + ]); + // bottom left + var x1 = this.centerX + + this.vertex_radius_base*Math.sin(angle - this.delta_base); + var y1 = this.centerY - this.vertex_radius_base*Math.cos(angle - this.delta_base); + // bottom right + var x2 = this.centerX + + this.vertex_radius_base*Math.sin(angle + this.delta_base); + var y2 = this.centerY - this.vertex_radius_base*Math.cos(angle + this.delta_base); + // top right + var x3 = this.centerX + this.vertex_radius_top*Math.sin(angle + this.delta_top); + var y3 = this.centerY - this.vertex_radius_top*Math.cos(angle + this.delta_top); + // top left + var x4 = this.centerX + this.vertex_radius_top*Math.sin(angle - this.delta_top); + var y4 = this.centerY - this.vertex_radius_top*Math.cos(angle - this.delta_top); + //var hand_color = color_schemes[color_scheme_index][this.color_theme]; + var hand_color = this.color_fg_supplier(); + g.setColor(hand_color[0],hand_color[1],hand_color[2]); + g.fillPoly([x1,y1, + x2,y2, + x3,y3, + x4,y4 + ]); + this.last_x1 = x1; + this.last_y1 = y1; + this.last_x2 = x2; + this.last_y2 = y2; + this.last_x3 = x3; + this.last_y3 = y3; + this.last_x4 = x4; + this.last_y4 = y4; + this.angle = angle; + this.last_draw_time = new Date(); + return true; + } else { + return false; + } + } +} + +module.exports = ThickHand; \ No newline at end of file diff --git a/apps/fontclock/fontclock.thinhand.js b/apps/fontclock/fontclock.thinhand.js new file mode 100644 index 000000000..cf58d451a --- /dev/null +++ b/apps/fontclock/fontclock.thinhand.js @@ -0,0 +1,67 @@ +var Hand = require("fontclock.hand.js"); + +class ThinHand extends Hand { + /** + * The thin hand is created from a simple line, so its easy and fast + * to draw. + */ + constructor(centerX, + centerY, + length, + tolerance, + draw_test, + color_bg_supplier, + color_fg_supplier){ + super(); + this.centerX = centerX; + this.centerY = centerY; + this.length = length; + this.color_bg_supplier = color_bg_supplier; + this.color_fg_supplier = color_fg_supplier; + // The last x and y coordinates (not the centre) of the last draw + this.last_x = centerX; + this.last_y = centerY; + // tolerance is the angle tolerance (from the last draw) + // in radians for a redraw to be called. + this.tolerance = tolerance; + // draw test is a predicate (angle, time). This is called + // when the hand thinks that it does not have to draw (from its internal tests) + // to see if it has to draw because of another object. + this.draw_test = draw_test; + // The current angle of the hand. Set to -1 initially + this.angle = -1; + this.last_draw_time = null; + this.active = false; + } + // method to move the hand to a new angle + moveTo(angle){ + // first test to see of the angle called is beyond the tolerance + // for a redraw + if(Math.abs(angle - this.angle) > this.tolerance || + // and then call the predicate to see if a redraw is needed + this.draw_test(this.angle,this.last_draw_time) ){ + // rub out the old hand line + var background = this.color_bg_supplier(); + g.setColor(background[0],background[1],background[2]); + g.drawLine(this.centerX, this.centerY, this.last_x, this.last_y); + // Now draw the new hand line + var hand_color = this.color_fg_supplier(); + g.setColor(hand_color[0],hand_color[1],hand_color[2]); + var x2 = this.centerX + this.length*Math.sin(angle); + var y2 = this.centerY - this.length*Math.cos(angle); + g.drawLine(this.centerX, this.centerY, x2, y2); + // and store the last draw details for the next call + this.last_x = x2; + this.last_y = y2; + this.angle = angle; + this.last_draw_time = new Date(); + this.active = true; + return true; + } else { + this.active = false; + return false; + } + } +} + +module.exports = ThinHand; \ No newline at end of file From 9390d3639eb9b604c428d21e2ccfba8d201908b0 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sat, 22 May 2021 00:50:08 +0100 Subject: [PATCH 0022/2129] fontclock. typo in apps config --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 8ab683361..4f050b0ef 100644 --- a/apps.json +++ b/apps.json @@ -227,7 +227,7 @@ "readme": "README.md", "custom":"custom.html", "storage": [ - {"name":"fontclock.app.js","url":"fonclock.js"}, + {"name":"fontclock.app.js","url":"fontclock.js"}, {"name":"fontclock.img","url":"fontclock-icon.js","evaluate":true}, {"name":"fontclock.hand.js","url":"fontclock.hand.js"}, {"name":"fontclock.thinhand.js","url":"fontclock.thinhand.js"}, From 8ec3572119899d260ae57f716866877f492f6ec1 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sat, 22 May 2021 13:31:41 +0100 Subject: [PATCH 0023/2129] fontclock: changed black background second hand to yellow --- apps/fontclock/custom.html | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/fontclock/custom.html b/apps/fontclock/custom.html index 92fe4b619..0d88d07df 100644 --- a/apps/fontclock/custom.html +++ b/apps/fontclock/custom.html @@ -44,6 +44,7 @@ { name: "black", background : [0.0,0.0,0.0], + second_hand: [1.0,1.0,0.0], }, { name: "red", From 739ab474d5d0f0f3412d2debdad569570e1391ed Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sun, 23 May 2021 00:28:03 +0100 Subject: [PATCH 0024/2129] font clock - added new icons --- apps/fontclock/README.md | 27 ++++++--------------------- apps/fontclock/app.png | Bin 33522 -> 24379 bytes apps/fontclock/custom.html | 5 +++-- apps/fontclock/fontclock-icon.js | 2 +- apps/fontclock/fontclock.png | Bin 2669 -> 6619 bytes 5 files changed, 10 insertions(+), 24 deletions(-) diff --git a/apps/fontclock/README.md b/apps/fontclock/README.md index cbdb2a3f8..ecf6688b5 100644 --- a/apps/fontclock/README.md +++ b/apps/fontclock/README.md @@ -1,34 +1,19 @@ -# Sweep Clock +# Font Clock -The Sweep Clock provides a clock with a perfectly smooth sweep second hand with a single Numeral Display. +The Font Clock allows you to choose the font and clock style. ![](app.png) ## Usage -### Button 1 - -Use Button 1 (the top right button) to change the numeral type - -| Default clock face | Roman Numeral Font | No Digits | -| ---- | ---- | ---- | -| ![](./numeral-01.jpg) | ![](numeral-02.jpg) | ![](numeral-03.jpg) | +### Choose the Clock Face from the selection +Before uploading the upload page will ask which clock face you like to choose. Please choose using the provided pull down. As you look through the different selections a sample image will be shown to the right hand side. +Once you have chosen your watch face press the upload button and the selection will be uploaded to the watch ### Button 3 -Button 3 (bottom right button) is used to change the colour - -| Red | Grey | Purple | -| ---- | ---- | ---- | -| ![](./color-01.jpg) | ![](color-02.jpg) | ![](color-03.jpg) | - -### Button 4 -Button 4 (bottom left of screen) is used to change the date positioning (or to remove from the screen) - -| Top Right | Bottom Right | Bottom Left | Top Left | -| ---- | ---- | ---- | ---- | -| ![](./date-01.jpg) | ![](date-02.jpg) | ![](date-03.jpg) | ![](date-04.jpg) | +Button 3 (bottom right button) is used to change the background colour. ## Further Details diff --git a/apps/fontclock/app.png b/apps/fontclock/app.png index 763c00b1de9f5c73ca4af264c6d65cc5eb08c090..127b1af1e7c0467789ffb393bbfdd11fab3f1dd8 100644 GIT binary patch literal 24379 zcmZU31z26Z(k@WExVsj2cXy|_6nA%bDemrCptu(I;!>cv?&56Roz30-&iT)O?!D`I zvXYfdCM!0Xc_-1T$}-4^1c(q25Xf?}l4=kTkfPwA0S^n#(OllAfq+1=v5}Bam6MPl zQ+0K+w6V8fkoSSN(?2Gi_alWPqL)3Z2LL1~NI zf4rkY`{^C*HNwN)46+n4TM^F8<%&!9L5|UjlBFKs|Me)MaMMS{qAk4llYqNQl>ohd zjCAQz>(>G;Ou6_5)32y#%>{xTVRR#1F9_8bRg&ay3o`NE?A$e^{)Z4A2W}E2WZa>= zig|>XwL2W_QYJ)E+qPmAv536UXeScgI%FS}RDt%%%JJGy;wS87_8BoEGwCSLnvcF@ zGjgVtr+w&%y!0MD4=t zTpE`J)Uc`(;MD(SnNCICk99zg;bo)uZxGGGE3QHH%o!z)BRvTHfiP6_ja&d~_3^0q z%VTJgs>S(=TL>?mm_>z(8X8f3Uab134j1}>jW0=rb$_PGJu|VXzaQ+3!#KOppY3L+ zgtkjs3vD=UVB1|fsZ!AWW1 zEQwTzPz3)9nG7)&aR`H&fGA47CxY5MQ9(IIM8rgtm;9kXJP)o!l=+p3G>?kpJ_D&h zRQeY6;>(IR>(-YQtljqlQqw+m#xcoiyr(3Y@`EI5wlqBPII;-zGiM1wh=-r0+Z^!R z+8cxq_!GO;!rOGk`Ik}7`Lkl}LQ)!xZ_E>oMIY8s)fXvt*Y*A^&6dNF#JxzI%(DOL zM-HJpM|o?w6g^t~&}6T<5mUw5*ZkIo)aye?FVw_=PnAdpm+a72SZPwf&1Nt4`NZj@ zG>*%xed}~P`Qoj)uTq%w{xiVNG`3MF ztFWs*QGt@6$K5J_dU`syI*)T#&^ICmG({Fwd%=5+aimIG1)YBLf%>rEarB!!X*Pp= z0|N+Ef4j6GBPaYY09v@q6+-TWRtt(Kz#JCOiDk2p_!w{D^ih?wa(IH2PV%Uj? zCM%ZZ#7O)`0hGm|klq_(G>24+s1aYH)K4bZv)Y4q#pnobp=?Wzl*PSZc^uy~OUsF#A8uLvWR2d5W)PuOvUo(&f+7@cC|+Mme5BBV`yq>eq<@N4W{S|v ztWk#`BU-MJPlrw`MAPi0LHeyrPK zGY~r{>fw(OJZC8SK*%43KWHPEP4M&ZRN;t&D1#=0`0bhe2p3V36k*m9x1oM)=~+s7 za$n>(WH(goDOxc}G5zE|r9h5{?5V_1xyZqM!}!hro8&jbZ)`Q1N);u8X^m-3CPgMC zr5ddot>RYwv-UOYA6B++=1fi4tC>U!2dP#`nW=55gyWgx`Fnve+`|z&Dstb<)eqF^ z>0W59Xdh^u78e(%7XubXD`OW9E48agRYmGSs&5}OBW+bI)M?cA7c3U?7pRXNj`a!R zEtNi&l+7VpPg--esJFni2qSk!q{7OC)w5}r%9kqd#*8p1HI=7RE4VdTCR=_zAfKMh z+0-*W77D_iUO!D214Ob*mJ2|vE{z&W;`=PSF( zN|<9hvgc3i4erekjM%DFSokrwe`I-*0X$!HSUj7XpL1JQSjw%_F7r~X4+~+d!6%Yt zHsjkR+lAfTh2KT5K@UY&kUk}Ju^94uOMVu6hI&(bdwX8K6Cq$l7DskP(jr(O+~65P zK0_YGSLWC-_a15R`*tqdm)xCPMv0oxZ5B?jN;ph7&ADc|V7g#uZ%X9I$YyBeKheG( zZh~Q+;-Kc}y76r?&5^*Eo}GzD$mBV+a@3s7EjxW`eu{*HvKgMEV^ynJt2xk(@aEHv z>CM~00~0OI7EU(KKF&0bP)2!%8IzUnlHOJ$g}#qILhX`XezUKWgIT_5&sgWyb4PqH z@@V;3`O-lF(=_)iH=uRxK8JYj*E;j4W2r%|knM#DOG|xI-)S(vH-8inH-AeaMcg$$ z6^W+MaXIB;^1jZI&dK9!^fuO+#;L}|t!>NxQOg{IOd;Xh@aj*#WuLAa16<-v*-X<+ z=}exw`#Qm8`ei#u&NkMz4o76i`c2{unDg8XC!blN5nsk@>-)!3;6B~m#^LI|1u*^m z$G}N>Tb)3rr6 za1222N0LQd!I(w2#u-DdLGi~jM;}66L%)r)7@e>@GwDI}M9F|9MG2g_x0tcy`D#qQ zOZBh{`5LRuE=E^}_DA3N6L^^&zbv*_TrpoY z@61rmVwQh8Rrb!r%WD_Ba!heZ5v=6Xos~Xyxql)ZD#jU9WUCZW!8DHL9 zF255ZbLEk|gAN=w++SyTxWZ1${u8fxPkq<|xb^fPJF$t-k*^~k51IU5B_2_KP!Ul5 zPRWgZ#c?o$d^jE}(m}xsYyL~$W`cekMCEYsx#`AgK z?dKEC0nHa4JO`bo?Kf%A2t#ft_u0CAcZdDWC{qbjTWf?*kCVO`tZYBw_^d5PHp&m& z^jSEyUS#Vrn@m(sU=b8{E;*8PO8r*(V!kv!I<1~_Q9uxMyasfs(4Uda=L_OKJ*{-B zaijV5QYhj(@GzJhyM=qg;$v84cV*4@nmg(gsV}5|!t7_@XnkX2XHPmG_$vP=Jylzx zuApb6!xQK`b$3rF$K$w}=iR)E^S*Sm-qB_RpzEFw^4by_?D_qo_rO4cC-fb(dH(Q5 zTtGZZ5+P{slXiJ@Znm|Xsba1o?7{3W@27V)b*nq=wtOhlHQ2dksOUZSq;}oZ*R_Xw zCc@p_6mU0LC>GRu8+QTpX9^Iyv;^vhwF$htzE^kf)IAJzb$h*CD7+v&dj?#BoX^cB zMy=lFg_DIf16yA<9;uEedqTQHAQ7}Dhy@Xi8;Y~DA-Y!)AegWVi2wA&vy1uQ5@AXD z1QARA5i!{ha8VV6T)~GH{VfPlvW;(nX|IK*Zc@)XNCOMGFzwJ@DVYI0sA`e=%0n&= z=&2SQu^Q3!CyiY*6!}k{46Y9US7;z9L!FxRxE6Me0(gd>@4i; zOkfHoHy=lL6K^I*H_Cr8`5!)#7H(#)HqP!gPL5=M`I?wIdAJKvQ2cG^KhMAZ)56>4 ze_L{N`**j%9c1}i!otSP%JLuH;HrXubNN+mye;f?C2btQV+L+Rn1hp5@E`jBujGGQ z{I8li|5cOy|El?4CI4?tO*acy2`2||lkUR*J6->7_P-1NT~UzbZ_od0B>pwb|Kx(l zSr}1}$2nJnqq#>U&4{jeO}w(Wgf42cbx(SXX3l{?)=iH2GtaJy z_-JH2);aT3#b11I$zr-yMf96(Dj~3F^ox9L$6A|JYko`_-~Ars03COWn}>NlUX=0B zjByZ@{qW)BQ1Mw1Kb@C+#=zfy#Dfu%NTH>J(c$%>!P%b2K7am_L66P+L(BxF7;GYN zC+G~OFoxQ*0>7aLaUiMt8}fZgc){#gA+I^WZzz*k2u$M@Wg*l&Fhv%`6TUGtUPyyf zFaoQ6MFHF|Fok09D-tVIoahQgKQvye`pgF_Xgo-2(Lh){NNF;AFn6T&%EJ&2s5l5r zGLaA9pFnE`bB{P%AQZXG$sxenWFCIgAO2p|FsOUR+WXmYAPrt}RGLzl4n;}-8#x!{ zIA?%46z8-?xU39q@8iDuSKfd>B`5XMwy4P=SFHYDMg2{Q_;2mw9bt%*H(M*~s}?m; zF^ia2+EoMKzwqlu}&Y(dPKn6s*5C4hwvEJYvOrqY97T@ zE#SMc49m!Mld z3oBHwc+uxl>8!h(%rA$q0h(3;cdU?0k%&fav7%CP*av~FL|W`2x_FS3=wrY+0!#q0 zi8-b*6erdeT6G=@U(n4ca=Yt+bQE%2q?s1<7U)oW_M2{u$)*_;C(_z%_2bI9+e(Xf z=I{P+y7_W50@qGXDRDJUCj0r~`e1ovVKTtp)l9O~} zWxvwh3WYKbD74%Y5IiBJAy_h?7X4X-oFBub^z-+-PT~o!qXMdYH&Ds9nkT1CE}hw| zy`&T==PqV@+W7-ArSp9nGU2iYXU*-ABeYM1|8;%yEN@d|T5lBwW)Z!q$@d`d7aMzn zRvDYUCyDivKTn?W7D$>n)J}_h);X_)HN|fTHxrrDEI(^=UESDD4l(CyEON-B*dPg@ z?2a__eEW#pf*LUv5zC#VwJ6GamJ46`KlE%pc$084)i_C+Y zOG_Ln@;J1Yc%Fo|hOa69T&Y!Ra@AKqJk8)$2KOm%wW1F|3d~0MZGog+!yIDSW$Dea z5iAIGsI1>;;!&m%65T9A7CC5zPp%j&T|_|PL9*fswXS`xO)wptd^Q*4OjyPqL2ri@ zzG(66%Bm&dqE+)cWWvzukV4r%PMRQ{yKxZ1G*-z0IkAo9sYj7=(`{52F5%ggfHq;9 z97lI?FI5^$>fs}3P^W~t_G-+A3uV_!_j5ni)h^fxbRj1@!)?hCk1+dX<|~~qrT8k# z>m9*HN1#!sNV56!uSZ%`CH9@NNxVAQQG+j|hDc6PgsNhHxE%uhn;VF@T84JyhL|t& zW(*}X+`rLi8a!k}cnsjIeZ6<&4K=VsVL*1B%|bciC`wnumq@p1)25uyL=_~AX>#4y zOn3igYltv0aU|Lq9)%ZD4|;<}Pzs<|41RY0xT^Nxh-ETRuQdQn^Am+ZV_N%W{Chos ztXo)-GGlTmfT(Jc^G1xgah=P*IXK09GgS~q$)bR8^P>pC@^XU-DS`_`A>)A#bUZ1NL%VYiKUuv3R5`IkW?pq12zCUB)?ZUMjO6M**biS3nwALb4z4sT;f9cRr z!hg3#E5r-&~6jNhdRRMBRlli23!@DK@UeH05gG@_;)?q_rb4@<#G65|iM zY4X!eXAK+spET~`58XKO7RU6lKZ-6g3I@NX-jTKeXM6CaRnF-TWxkjNSwEM6cvftE zKkD|>An_oc0I<(DS#ZJ%9;VSrOwMa{zJ!**&D=|MGoljUBpSZ;yl#6#Th4ue>wVMb zqmPO^mN#2VBj6&3B<6pip16)bL8&QILLxNL)iy05GHxoe>ziF1y`QOK0++B9~?#O%%-D*Gr1Zfk=45%5<>o|8Es<&|Wt8ThL5>n`t6&(mm; zIa7Kyoj~>w*&@$<{hnQzMuDxVdAplIK2jBu`WK-35OeX)cPP8X7CVP7peGX5u=3PP z%E%F@>x4d6l6oWeVh;CW`(fE30C|(PTP+^j{Msi4hl!F6sCh9clrLyIyo6jZv#{?O zJ2K|7MMVW@-VFWVC*NN1nq2TUhXTeE_2Pr?z=%Hywgah)K==Yy$ zRU%KE$b!2lRwaSEsRi`~&4c47xJS<|w#sWvql>Rg#J`W1Ya5e+eg)?pG-~NT+nOya zD7dDDR+j+LquO3UMqedf7!z6Ap9)#O0^V)-(Ypy@q9*~h^j=?cuD=neIGJBexr7x~ z3?`nl(Y6B`GMx>{DCtunZj3!&>drvx-s~vc8 zd)H8GeA{>*Tfj+(u?;7Pgss>yOHa!Q)(+x^jIIRnsZ2oY2$-2XE}MA$u|stKqofQ7 zHIWSdxqd8tal5U*(y|k$@s!MRSfWs9mA}LFBE)azGHFKq;;Gkg0VfBQR}hC&dzX7p zage`ak&(;;P?1t=0<}%=$6Bi&c5a*>kBU4bK=eJEu}w@0VHQobpBxX3j2e%qj8HO7 zc2R|N-f`b%BQ%h^i@$DVl=(TEM{cZV3eZ9+2j^hx?ZX@w9I{Yhk{N43#l^)8rSX-{ zbsKPaCFYQWl@8>P#n*I00k4k=?{+<-$dD?O2%M0%I20lk8~VhUMSKXV?Oi>u=dvwl z$D1znDl@hLV8MGLK{Zsb`EmZC8CzJ+mP8h6;ndx6mYK9H2VvG9nifSM(a(*R|G@?~ z$%z=#SkxHRzLXI6Z19S7Ol1iUgB7Z#adrf*=Z(&ujU6&45hAijEx1>r>-mq|f;J3h zk?=-n>%t-jPvdDKz{lZv2?`Aj>eKJ}n!(#U|EX`Sg*z;mMIG>$GG;G-I@o#&^C z3lU~7lHlsZ2&p&<70R7_oqT1fU4Zn+_NF3C4zfk_f3ZuAY(X={5+^d z0cN&q1j{q)3F)~^gY<82lHfDidvMV z|6@jp9jFu83e|}FTh|ApF)=_$t;ce}_M<_KzOP!F%S!#!Rf)XgCk7c zs*Ehv6#6**f=6rT5xs+Fah0@;oLMYr@2jT5r1M>ql}ggsnDpZxtLK0aE`B=@Ac$66 zGrc5;FeIxWI|e9%AGrbz2;ciHz~V8<2Dv2lX-K$Gz#pdiy;IXhqo>gBE2UqZLb}h@ zj{@s;xjw(euS%fgp$YdKHKG1?(Q^bQp60D)brU2;&4QWnHC zH>L2Y3U+q4Q9vhDhI|JP`kcFi_sjl!05ne>HxUT~8y~FG>mDCxf9ap zM=;ZslxG7gA|XyDQTQ3mD`KEZV5vP^XF1nMuRL(4R=N2xupUoDH?`>%P_KJObpP}whG^1e0DCLLo%gH8o4`}DkJ>6itZ z>ldh;SQynqCZ|-1uq$i|7ZfMy2()Pp+6Fw|)i}J+#^I&z zEv^C79X{Vtfc}6sGb#Z5(fV#(!^THZ(1_I4$}NYqzW35G_PghByOqL%SH)~k4>8X7 zwE~2xv#-(R-Ou3dp?#U%>4epd`G&%!CUR3Iyt2Pz{h!7M_!Vc)$e)aeaTPHCC;F%)6Z*>OP9dTe9OB_MZ_555{F*|7zk{1dLVej;~rzp); zGh?41Anquha?GKAhhwK^|ZS_HweRBis8kyE9zJ&T{5;xpaEz9yvgzRgw| zR6mi&23b{PA#UKJXfb}VTzt7h4BQ$Xmf2q9dy`&@iro-df= z2itFy_Ns4wJVXO^T#@Ovq&z(WuASVP^k(1L&+ctoPCjx6Ab;&}+~0b9=zZOyZ5iik z3v$}L`nQ^(=zFmhPr>-ONY6WbpZ{&|eq!*uw&Fp724&yFuqqwwW6~gvWoG7rDZVnccf6HEaL%x0$ij1$uixGXVo` zrU)^Ubkmyg^+h^Sib6bsDhw0m(Yc-*JouM2kE7c@=cW^+eqK6F^bgnv7+X|X5I?|s z?*jyiSrDb~T#bCt047jKCF5OwZ;&{zmRz>rGuiPir_1yq+cry!J%HH$`PojHej-n& zvq&Q|$mwFB!#i*SBFJO$;*1sYnbJfk-intl|`l$x#GiC1!q$hX@&!giH0p z>#}T?(+uaxl(Ved-a)6coco;tUIu8R#(otuDh7+OcC|4BewF}gL!z=68H8^1jgKCc zn~no#=Sie}&_k4Ukz_<`QfkUKw@$Pd-~5`_Ift>5`*_v_Gr~RxgYkf`HHpU_E5wgE z-9j-J<9_m=Dn>f}1EjuLHAh+Y!L2xDmkE$>q9*q}bS-Y5fOmDr-(3wOsvX{rQCw#( zmA9O8tHsh{t`9tLInXIfns}p+>HO#PYSeEs0P|11Fyq@tiKZ?arFnl5U-a7J z1SaMocx0&J=_1iZS}_P7WPLE8lR-{LsYucGN8&BrGRC0ofxMmNe$FMF_$M z58}525C>qpuP%shO-1$+IklCuL>197jmcEK<`2p+mm7Ctl^oBPg7|`T^s$hfwBM&i zzfk>l%kFIfjhYfcp}zS|j`eB3S%1D5Fc|B5;M?WLmE;2Jo#st7>D>NzKv#{7$@**y zb86GIm$z|)=u`Y=cw$daVqb2BAn^v$40_~A+IBIyMt}NnJ-p7Opo=WDhl^U`>M0{? zQT(*mqUMA8b?5s_3t$F8Dp26;P0-vto0cw~HK02Dsjk6~Qpi*b3*LJdu->cB(0zM; z6BWfer{@w}k&eLHk4cu(=X^@g`{vrLrcyvSN8%%~Mw`y2)p20r{X*b@3T^g+&Htl0 zsQ%(G1!49fi+<7iA1#;unStT2;eB@TOg^YsUVld2V*3QG)MRGS6ZyBT+~h^*`9OA@ zMzOrUcrqKlZiLzw(1-Am+k2CpjlGj^vZ2IEYk|Mjg(k@kdwR~h2^U~ z6h_K!C^3x0^UPoL%QZb_mw9I;HU`O`94-K^Rg2EFp^i0R-0Z9ATO(drKk7OYZ@czp zrrzEKvJ6;+=^8_6h)qUzf`Qen7a*bz)3u$YE>kLS%E*Yb1R1S4ilGsmir1747Sid} zuOd0fsTpk?V29KRfm!r<%=f$3(;=bDQ<}e4%h=e6_uWsyZ*d!>XTHcl>6(x z=)8Ut5lVIpX)~#@w7-fo`m|Xh3MSYfeZ|LuUns^x;5~~dBt|?W>q9f>rQ#MB^H9A4 z=zbE$f+ePFBY|CJrWiSVdo|`Df7a!av-_z+_>*V4E>khUe8?r z@7JeV<5`S~Mlp}3ICC}2kdgkO)Xld7c+Uf%9#Ae7wdlLa89!-vTuJwrGHaG53@R|` zRc4AK^?ar&mLBsYO2{1+nzu6`WdGxY@sGKs`VyqTN|9^nTUAEvtz*UDz`S=#0cEqv z-$L?CD21~Kn>TvknFlK>5SoWJ2J#@}rCCt8>fe*)9{)GYPa5zdINt4t{vMO1{Pr6T zRS96*CFs&(TNslGIFiuUfeG*HhZZu<5Xv2T|a*8PPh zbWH+3rZKT-+@rViiJX6*X`$L8CCx#J0>J(+irMwg8D146hkT};r2Pxj6Ou1VEgE*k z(y1QfleWCPorG$zP-jL!J#}p1JhM>c)$=q*NEUm6=KS9Ow$$S zwv#J9Zb?8VkT$7;4DbHH&ZYHfXZ1|$m9wP@gMB))GNQt|;C+t^vgJC*6864!4SP?F zO>{kb9-+yxR*DQIY7ZsmTyg8I3=KAX2dhe;iOABqrZAtH59uzsnwbc*!P%=l_h|S2 zUK*7Ljp|*+5)YPtf$s9KUv;e7dpDCigwS+fs=aetD>9W2ahr0h+^=fBr za}ca*+|e&Y-5{s@ZuFxbQ9PrsJfq=a$nHhq4hZ;qf0m0<^W{r~ZDdI-A#rGs$q1Qy zP+e(#=ir@S2n6OIOk?jCBN}3l?02VX=l2Z%q~OSMC&(Sl(r$+>tNkCg?3)fe{#r)u z+I#Uq7fI1RNALa*&XKbXS74J3ZH*XkJ_?$qNwX#TFC9tB(=)p_DJYDqMMTWdN4FAF z;V``o!h&$bDAFHv|gUYZ-qorI(_r=h>66K8Ep9NpKf%!QU;3v9<#(X>FTly+VFbeL$9^8Bt$468GqEgc)k&?E zmbpZ%xHq98QSOAD+k2gQWa!58^g!}^8$eiy7Yh_Ic{h9*Bk+nuP^D>IrmY`Uo4A1V znZyO_NTx^LZp79W^V)|WR4cL!-?y?>tQE1J{8szgP)a~gW6<9}Smh3%Pn>EQs?izn z^W7B#39%hW=5g-@W{*f?z2NhNY=+A{(kGt$z6M?FB}$h{p}ai!@_cw!;D9{tcYJ## z=KZ0P74J&%TUQzE;n8bRN@w_kTAM@9f8&+BWsGfT@-|mbW*7G67iK?r?4F6xfI?Ov zY{>6I%+R~CCwEr)5)in67$)uIeXJ)cf(Ep~iMf(F31WOkzntiM(7e82VqJEP3j7q> z_6f6Sa06lfp;{%gv_u2cE^F)C%~0=TZXPbK09(E0lni7bEnEAu1#NM63Ls3IzgMit zhA0dfdi%;{wZc{N>e~G6Ug8HRY~8qj?Eas9soq&h!@MGxaeesc$ z%sTR!{VHyaZ3>l^HKQ4{8hRsBFK;cZ5glb6UU_jZ(TpSa*U^O4)ocHJ9I?6$p~Xb^ zGk(x^pI^^oZ15YZVG*eWCUJ-wiIg=C*kQ_AUxE5%sI$J!Z`SwObD+U43D?^~R<`07c-X=Y2vx(DQYe_;f zOYjg|;SiTu0+nZPcL#*vGFTYH7NsqNOOOKiNZ%s7)ES45L!^TdF6WS<@<_mrY?80I z`w~B6?+Um`Onk(>8#f0taFv4#p#-mFR$u@*Zncz6>JcKJK7%lQ?fu z!?|n^Pz@RZ?=CUc0Sp5qKd6niD_YMw;ZKl@X6f6Q{KbBTv7@+9uOdpP_njz$)j`Q0 zHtzblR6G+eFM6D{Ks8nlRvh}}T^RUMqtc6pJAGm?qB@v=-g1Yt-m5j8>9cxk-Exd~ zPI{Cqo?~tT>)e9Gp3z`S)@8kFU$lv#Pu@|XOca8-ei49A zTH6h#G*k>UOiZA>Z9x{sjR*wntH>U(7$FfA#|D~Flk4$Wg{ncjnkk5;e8>!zibX{k zd~Vq^DAnP$Lbv;ElAr1ZY1sHm_vFQH2(SK?C;!;#i@2A_XPM&+fWFDlp053y&ZzD7 zSHB=dP!E%0+QQZzFPy}~U<$;AVNftkpDywh4lTnOf0@~!osh-iTd5V;*Cxj7#3&Cx z_0r6HP4Qlej*lHp=O$h1(`6}t*3k5X4le+ObrNtB)PeZmGzo_gRW^K{UARX{J|`*0 zR85)$WVooe2g%Hd2w_=)dSB})fMjrkeO^0Vlyh~}KHNR8VH(~o7@pAWW{Z%g0QWC8 zo-!)H7-b>$^a;Ew#pHYg^aApCSUc;W(C@C>Ck*VJatOqZBubHaU2`T@8MBgPHSm{9 z>3%x57j|Rn;(=EJ6$-E;(?=#HtGItp`d^5ccXZyJu5a>OT567{_~<7A9Rcg(-y^;$ zYbbKEH>oGD@_+a|mrTw#(m*aM^J9Mh?6beh^>Sgk0CRyNfDa~0g>%M-MO%w!;(Vk8 zHDsOV2-!L0m7}OWeU_eTNmSs$Cbm0SC^;h=LoMthA=E~zKMRV3KpCgcZn=kya$EV| ziKuH7+PDLsmpoHD@Kc%ZbbX-eu3|Js+8x7#_~Q^rvuE(#jalbFl#fu1-Og|dATwf( zjRFCWnW3Xf1EpI$u*U`?yZ1QKONkR+-Q5C|IZVsEbEn>uIv3(!G}+6|U(VPelDJ5CSKux(d ztJOm3z+*d&n1MkCAe`U#b*huu7zL2uk#4j0baV^Nz(g03C> zZ?2Y-hGf~x?t~j^{v6+97`P+?oo?k!CN6YJrS>5($D994v z9G>bhGFir)kcLNw|CG*H3hV18eL=v7YSGZSTCAA-EEQxyMaA?heVKxUhi@S^y#fl%SGb;EDB_iqtcTeS8SZ-ghiE z9Wc66<<@e-;1r0rL0%_3gihOeF$BvG>t4tma4TCHCGGuEXedTc6@#dS;0sm5*xc?J zP>b^nlbS}2pSE%EQ&3Vm$7)-v85?R5t1{~=Ix7KWlWSrU%@i0waHby`sadaOep@p; zC6qWZM5&q)Qwe4OwIF0F8)m`^g$Dkh?wiNet)055E{ld|!D&319E8V<6}9j|=B}$2 z-CnekTuQsG((0Ib2Xf$y-0ArpAAsTWrqus0Eg1Gzom>RkxqH#WK&8-TL> zNJ&X(*1xiKBvK+X7Cu;?zfwfm{~Heb@wpkhVSPWEl9B;^9(cx5!uHgYEy;Pp)&JQv zWy_gI93kXdjfT6fa%h_H8i4M#t1=@$%)17}#=jQ-92x^51%?g!j1mW9+sY2b_n6R5 z0{?ya$vsW1*^sRp-?5(;`h3%6=T8CsvSU^J(u$fIMbbPUPQbMpIw4^@>DouEDKUHZ zC}AHe&T!$dF5|HwK|Kzh^IJ^o#y7)(C2Tq6sHQaNpGA={GRV}dFF-AaD_I7-U`-d z)|=N?R$!6f8)Z+)rl`@NS|G%`X0^)b9W>pVL|c*Qfm;*$9!{G1aby}B6H~cQ`->HV z4|`9)umrHZlIjq#SZU5Q~3!b(dEo;Wn zC}=b82IPJJ4$=K8%~@hr(P;&t>`RQ-P`dLSfom~L*_O7Chy*_(Md)i*Gp~{lB}*;e zus(c4buAp}`?Ee0DrN{RA^ zPHqJCsQ?=tM12ooECi~MSNuby>U|Fab*jUl3*8ethaXN1Kqq!K3XN*9r#C?xt!U*N zX#FMf@_U^o+aL7`*gx?>eTY}{gV=2@e#6_2E48Q_frPyw_wXCFB>m%R9I&wI_=@YE zQl?u_4=GXck98@YrJ27T61xaB!^DkM$q>D2hhpwx7dUU8I}OExaVP6`Z$Xn){mdKO zsFNQpt890FO?V2N5j=5j{BucG(_um5{J3cI zXh687jjk;!@2)VfAnNR*PUeeROEbN&-zM0xzxq2~CFmv}EFZrr0z@q4m#s+kRFrCJ zEwU81gx$TWd6*8TQAb*FOIt|k9Ym|^bX^W4MIs{7&!qE_#k&b6Hd~c;0`~4^fBHIqu%aNEkGr3c9~IJi@M#k>wF;GwV5n zG(^S@x7EgV@xjjXwQ~q2OMwJpw&G%~tvPgJ+~~6lEOIWhPKBGBbm<7{ez(ZFKO5WC zRSkyk;y6t=YMMV>>?~f$PEqEyw=`T%cstzSpe$WK5m7~kIx~)?Y2Oc#@o}k^#}@tw zP-P(^4mi5-N=_cV%}D21-#&sz_(CLCD%jZ3@w3}eZcfHXeyp(n9()Ro{A<4$0ExRzfj0#@UHq6MJ?q; zTs*81_ydaZ3!ipu@slKJ#HW6A{^M)l`&wec0rM~!9N3h`^@)l`)!Z04!;U0L1+E|6 zuU{hXp?~kN8E*V(e%)z%BTOtVZOIzrB~7jxHf>}j&=V$TEKb8GXs+OEi73Bi82Nn# zeznfOs)rom@)jijg|Vv`@kpubz|7?wNz-9NZ4WTbSz&0jrDHr@~Y3> zOfvNK=z;|?X0Xwos>d(mhp2Uh*ICn7&%iglvt(n?#75aP($WNmD+uEH`y{9OQTib zMaS!CKYbc^dV$7|^-4-4ndk|_+KnwF2_wF6>~Cp#Z2Y-DV}{0x1&KKSfXRPNk)X)4_7+Tantr!R9P-Zg=uiG+ZS1crP3gY%}T*#oY}j!y~2u3^u#o z_8NYq53YSfM5gK@`*>pXOGdRpkWL|f_)k2tR4~Oa?V*<{x?vWUq0l^YE~O3qW$w$N zlgaXWKbNJ3hn~XQqB7l0$h(FH2z&bIej?vP8huz`!`*7CB|qTsnc3YPX*;=i<=K+_ zfSFAht^a5x?s1+KdPQS7f+g^!hkoA6Qwz$oC*6VU%U7VjOnLpPsM$`jVnjb1JKv(D z@3(10@v8(`Ny!OP5=R??k+}~6N5JGDZ9zXVdigEA$SCU%`62m8{`q}8(2yv|C<5Uq zodUktKhX(r!iD;#N+VT4EDbxk%4&1MV8Pm|s21DDO#sD|7}5C9JPt!2-Y(`Ch^JMH zOc@!v!5H4wab2UC%WHVukJXzMi!FsU%D~6mq3dI0CxP~-k!5Ck4Y*!4yM8}GVb07o zOXr!Jt_bksgnR1Ss|x-zkwfO(w7^-6Kp=6grSBze>KpSa0M?Z#d3|TYwGe-#GR@Cp zH0%n+?B?T8uBRKdF6Tq&lX~tnzxNa_FsAiA<~Ng}3jn^@eurt+k9w7UM&_a>iF1V> z+V$E_``SH#6C>~r)WsUr$FYbs_V^4P8n)l2-Bt~&s=R|JAtACU@kBei@U589s0~f3 z>xL{XvAsPa_#FE22|z5V{vkU7QNbHJySHyl2Jekiz7aJ=G4pYB_yql^!h2l?70%?m znUdZTQB5rjorGM)9|zGyK-s1H?qP4&d)UMheKePQM)a2mi-C^;!sTZNhF3e95@k;Jty+t{4 zPsRqD@D2NcaKe;7aLX(X3(B%ML_XViBrf=2oR7$}kU;w7F!5@eB*!q}%wxNB!>qd{wehX1`Z$c}BG&hOBZSm4Xpj9pqs#!sEJTUI z60KuIiM{5yGEHGC1?oviF5kyCBTwl7g<)GwPOIino-DSRaq$dsIz+=&bJiyD9=KSj;gvA zZUkjpe*ikh53UcqVsfc9OD?C*Tp!9hSM7Kcw5iOQwU^@|7Kh#t8^gkFVCUJIKT|W0 z4p?P29!AikfA8WrBE#2)R>(}2eB+O&Iv&21BD$zFOXH0G^)Q~%03WkkmX?OU3T!fP z@%svYBohosx*R~T7=){T>-wUo!m;wvm|FB}VwOKwa`xGR3y0&TbG|tuk0hB@daG$i z?WZEL9d84I`ei(H2iOF~`0& z7-bzTxz$3R0zo~=5{$uvBfgym59KlKn{6OLoJJR{rD8Fcp{s)CqU&x=Ju$scS9%Y> z>18zFMz3recs?ZWR`kO*;J;r`fMCQ~PLq#v51k{)4I#Y4MTg$O4 zxQWX(|DR^A{2%K7+oQ>n!ichueaRZKi>%qQWGh+9R+6!meTifrStI*i#1Msyu{FlN zO;W^Qh{-y(VJzME^!a}8<9qM@2ky@^@7MeNI7eMI2<*|g_nEKg*;Oc+K4uj#Pm-3;o}l>@!7)jS)2wl~dKMob?5g9#?o zc$6;L)gb=$!N!EBYNN*3$rn}Rld>PLuSfLgOdO~(@)e0wW>tH?NJ0tlUjbe9DSjyv zzwXcVQhp1~F!H1jCB4_Us43xaDWT4LL{FjliG`^u4=?+HuZo^;tjoOXfPdH9?6T^{ zz-5u`Gp|#fs^YiL4rC3wHkcig?!M6T=7LLP-TgS3NfDxAaxe$qud;al&0}HqXG*Vz z`LP!0mm8@^I!#+*&I~dr+#=_%RVOc^$WlESBcQqcl;Fbm%%h-iZjRS8R0xu|BR3(B z`^=-MX+y=bqq=LZTqQjj3O#6@lsr1ieIPRyy?3)<-6~lYEw#+YDdfuIuR2 zj6z~W%gXw2gytQC>$81YYZ-GrJ_tjzaX4%P^l;M@A=7p;C+aXJm zo0e4HEF?NobDq$-b4CJtxgm|C4( zUOr|<=Q71`Z@$;>&l61P>{s-?K&j1C#P+$G0X$i;u3F;|Bz>Xp9mkjEsVCVFAjQOb z>n7!=Ts{aLSw?v#`fP)oADu^V51H$#yz*Wpg`9MhS;Plv;} z+C$^>+L1->@MF8Bd7n1|^X1$~Vj(?~36GCSB5&us)OQ-ycR+biCEK(*GrdyKi!W4y z>EVgaenF4B>hnG{^trh?cUqVfa=_OHl|Tn9$bOs^&=MuG?14F|jtI;jvy`Jv2b z+j=!hwx};ZLeL1J@yh=+26Mt|?)#3vMClu{j!Iln>e)1e?;WKt&HyYUNSR=sD4!Eh zt1u_KPHV^GZ>$22sFv~bl6cnM`qMAIj)rF}2zsB{)S=Os#0_w&cF%P9uGyakCcc~0 zI}AM9dTV|irg%SC0!66Rx43(}80meXo8QTniYw99#*WdWnx~|^IR9CUeO-16MqzYx#e)&)o!-UqgBh$KlSeDa3ceBmr%WJu-6?hg_6o2)NwN z6rXK-IFsqN$@}O-!{xG)7dq$pORg#T%3o4DeJ>8s?kZgo!4X1ISujUMblGWcv377gh=p?Z>&UKD=UG}RliQ6_G zuv;jtBbY|>0u=!mt;W>KqlR|XqTkIUdfOx^!i&iODr3DNC&`gf6e_(m8rEc-E48_@ zvJT$l9eU`MhD{c(01WEhO~H8!DP%lQd%>`J#TaWEzQe6z_n8%I55*AC&!?!z?%L=Y zw0~6AUXH^_Rwy}GG^a|!0$!B~DV05U!f!uaT=|}_kM#GRuT+3BpW5=r!KJxgfLmH)!G6n(POK|NGZ$AS;w-I_C_nzNU@u3K`Sbtf8 z)|5-4(ja1eoqur9IBPv&I)oAs7mq`kn@a!AAr@j;{`?^b(*&PRD0Rekl^&^&$CZy< z@&Q~!$}8-iawEu~?yF~33Ri!BPO>B%e&b;?bVb5YIs@Y00b1$Q-M7XN9jrKSt-*`S zu)Z{Lx?Ip3=1N&Lf+8?M;-hy$qA%!Qw1_jO`4OanUP|@mSyrq=RNPbRySoZuG;v$~ zj6ZJ-C0mzkKf61^ciZ&Jw|c@hj6w1v=uX{NeA*%EGVrN)-Jo(|kZ(_m*H%5UNsGSz zw5Y75>aJI&vU}sFpy187nOQ|lVnf(B>r4{)TKeA22O{Jh+6Khpk2LyLr#(X9@MHvM zCM(gW9??0!`|7z!g3E7IEAng3cI)-|6{fy;d9Xxs%9m#^@;P`PI|z_IA3c-! z)_ToK8bkDHWiJnb7PsjJRav-i#VgGwFD_l6OU2qx%(8dT6${Y;k^8zoneOXxbolg0KOn=MdFRR*l z_3VlJx;5J_kbz5>v!v_?%nV}TXPY7)AmpA24j$%uWRF5vZ0r-I?In}1Gg-j&6oDMl z!g^{PFP-?0@hP=6vrPO(md0#a!L{h&{hH{ThQl#nHlUMr&Q@Oj^d2%r@YHnH^5;@WAUsJ?K0O!8t8XO>T(HyfF!@qfB|Wy3zj7W?=zhdJTI9_4&|M|bt>AYE1b3&=`SIYr3;idk|Vi!}sUlO;{xi2*l zF9Pa#&0(d2q!3CtC00EMQ-4B&-8v+p^fDlpO=t36>&ou=BXsF=NIgedMx&r~gW0jv z9CdmWaP-MrKaVixT!)oJpaJ;p{8WnzDOjatEcGCk=2f)%@|vcVJ{wS8i#w$&klX6f6ZN}8@E<33V$ zw+fEe+{>g{@z~Vn6@nDrYDKz=Ya6ub&Zc`@o%UIaqr32N8wOiZ0<^i3_8mK>FqhiV z3G|gLE&vPvhG0V&Y)of(mU9Wx?47$|UM~ALz8`JAT5CXPKk&rf6*6H4suL~9^i8@= zDvzq(=~_F`L2X!j(%mX~unl2&XE^Q!!Vp^?*{$A(Y=mrlsJ`52{Dy^@Bgq8L>NMZq zQp*rKeU%CayiiF>qF;(ZU43iqW5p)s(NwI;^XKv0eEm#87S#=5-&5t^rE~Fo5K@;r zD+EN;zE8dHgBpPxuo=~uvtvQ`M~s6P$s$WJ7Egb{*fIF^3X_ET59xe)10}`nM1wki zI|ektP_6W*{{ujuM0(KpCggq6)cvNfX9TuM5fu)cu<_zw`ix7sKwKr-?E375>?{EL z-GXSIYLPY2K630n>2yeOWyA7x*s~%PfizwAgm{Qxntq%Gh0p2$0fU54r^UI)=~w*M zg#ViXp{DGyh@S5`jRbrQef7P4sJqXJaq>de%U#kGb?+|geec>_WOTHkZSc79^3md1 zqiz9%y4@kIL3`QTS8MO3f?okn#Y`xQaYNpD^N;%4l7r)Y(zjInV{7H3!m1{Db+E)b z-X~vEKP0z}msJQ_qpc&4r}MoJQi}uLc&;w2XO~+L6EJ!WGwD`ZX5d~k^@Wgj&uTug z#nxQM2jOx`{%bP%uU`g`O3|zC_`15T2RAX3UNJMFDQ-pK%iqL7MvU2GKLs~eZW_l6 z=%a%LhvRO?3EMb>8ufv1WXdiUL_lx0nhpKYg!C^E8TTXSlok|gaLYWh2qc3vb#4f?{zLxK{o7YA_tj#K^xW(=GGAGcX-DZ2rd6o z1bJtT3Q;frz#+h`NO$^E^b&#m^LBW(^$>N|wo%qKtw8`c)5H7eXC`EI6V|$T}=jyEf1}z725Ac z@&<3BW58R~z)R70$^{DZdxq#|fjiT4&8X%!CLnuwCtp$#M`Arxnk9QTq4HlzYr8(9 zi$+P2K7i#5b$hab_3EOx_(>dbBg$7p#JtVBrTi)WWfdP+~->Ka_EmLADJ8cv&TdJtoIZ1rl#}X zbbV}X?_8~z1d?vyvSGSB{a4FPzYuujOYy0QQUN~YZvc^$0X*o;`zyr(Q1m&BZguOA zIOr+X+{);o8XUg>U~aR(1s) zXOUN4hr)a6wPzl_%?$9@L7Q`Js_Nbx%H9|lQ5#7HAAl*_1vT%J&c(RjPVs$okmHxU zyw?^{P3?M=JBF2RTD@o*%_JdN;r;1V-5dnMaN0q8ph6XH5Q&YjgiXI*Wr5d>A&}kO z3VF&F$*Zq#u4w)b7XB&^VAHl(LB}wPwwc{^&uh5e+1wS++u?3wKf2!(>>zwf4 z_kN9>#sCk^5hHjpM4F`v=*^qF`^Wq#8Mk)TDLj9(cZ|WI#r4H@Bz#gKkG2njQ${iw z7g*l8$bjIXZ0GBk;$$SOZz483cG{{G^1esVSQ`$BSv@R$ZT~7}PkLEERLQJL+-s2b z;2c%>jYy!daSKi?#xAN?Y|eGi4rk12Te+t1HeBK{h$@F(da#j}GalwclN2e%g)+TpQCd$=5#X&mRJ+ue$p<`L^_yO$r_W+{FN!kA zK|@+;<>b=Kj}{o%C?jrkh|rC)Vid{5WE-vpfnyexT4O3SxveR{(tG&*7l(L7{3JvL-o9^yIhjXNdS^2XBS1yYJckKS8+kiCM;$!6ZIZG*#ysB2yFixQ$eGCWj+EKtmXS&0H!FG3HVU`SU9i={<#TI z^B{?Z~CoOC>8nr-PxYrWARyPdEsXMWL(Zm-_vl$=LWV zcO64%9_YM>S7Q}>SM$?ufo`)8l}vt@DwB`Y9bEvS6M5${{}OAAK=qDfKkng2wXNg2 zT6$MUo9?fb$EU+t(sChL0ubm!5SpOU9S4`A+R*9{r`u9xR%+ANsx(Zrc5s}grOUE@ z+0nm-%$Q@LC+Iu3O2Fpg5WdE64w~3J}(Dm#yCB?8q*N-;%o}> znxiuyq8O19sTDLA$Q8VMq<^mVh)GF}^{EA|%}7CJU(}o0hGB z0_xD52%rM%m;w(>fMwn8O-VgLTwsi!KzlaGs43M6&vI^aj;z%$bvs5uD+zejSOikl zDlp7M{Y*yQ$|VlY&*hiJ!h_GF2tZ;{9)`=LPFHmTsYON>(|KbxGE0!8)CX)_6`RsK zOzbrhRayXMCL7u6GAFSoyC3L3)SWJcg3i)h;gPl>D@PbuMuO5hzddnW<1>1fn~SY8 zXFTL>m1mlshFThMDJ8!A6q5VL_~>;s(6Xgbn9MBhop3&Na4fHY8aYcF5@&TxU;ENY zx*N&Y0E&-S6?+;Kz|L{x;fj>s> z&!KZ;duWZ5BIjwhdRkPKNQXJ``X_@;=|N#3kD5fDg$^|f?2B1x& z?3CJI;Ew&#q$!|z-_NLK>PDJHPDQ1cO)KieCzSQSb;56`880b0h>5mb6>wq!C22>x zkitzWpwW5`j)_6EXk=?LX_|Z7HnDqfdRD4yaL@&hY(4|5EyFW)<} zOFM#z-nT%cJoaM>-V=f%yaD2fex3fr`>LqW-ELu2W?}R!!x_<`r1}{K560Tq7@>SJIZln65Xm_ves9dig39VF)lW9bvR9rhum_KQnTnX^BBi!z+Z} zc53X3wC$UJo7<)9i!JWt4Rce@(3wrG8i9hBero55S9kZunVd5Nqs6xgzn%=gWRhMY z>kcwGvKFMIxor(OUb3m$Cc&wu@!7j zeCC2S79PDlIF+h`%Zqz0zkgs0LJ`s|{PdoEZny%JAvu9U*(hgdyqyp(cXf-#tEw4y`c0 zW>l!ro!>N%B%csHd6l!)A%Es&cz&i5f2nk<|8J9dngqz)R+k-XXyq1q`-5#~=Z)_N zhSx7GyI*-X{FMADreHv9F^A&(H%OnCcD7)(5HtbC->Ct-z)2Q30nMw;|A3=@Vb0|; zEDZ?63thE%FV*+_U@!&{BHQymrqO%~6ou(J{7d-<&h+F7Jn<@>`S%+>2r<93yl?Z; ze>W6(iJY@g!Ug<}d@R^33guB~`@o^qoPF?kBtuPkox5HpHf2-2awXr%|DK@2 zDc-|HVks2iaVc;09}vKnK!K`z;k>xNq+)6Ft)vB+pT>USkJ408k>+5w>IHh6q3+|Q zhC{QRl-?~GK#JaHDZ9aQ-woo9+q$&XMm6F_dzo}}Vs6A`{dN3$n)D!`ROYVnt0Q0| zfH2sB=wSHO{3_X@?Epb1>6m#3L>Be`*B|~s?z=ebnlEJlV;?Cf40Lbl)M`0J{TImw B*?9l} literal 33522 zcmY(q1AJUjw+A}0t;V({wr$&u?Z$4@rj2dewj0~F)3CALySmW-CCZt)NUI=ICNh z!pQ_=0+I>BlaP?`yO>$4=-Vnz~p!xmi0pkbKfL`ReHICO}5^$>_h=|FqN1 z+T#B>Ik^6>SRetJKi@F3FaeqWOB+;`|1+0Y$;H|n#QBrHAPfJ0O8)=y{+ACw^C$EF zPh(^A0@DPc_lO?ur$Hv8j{v>FdIHa_Hjik6PtV=TbJ#ZRLrE-bL=v6 zE{f?77wr%0u9JKZZ<7z1j&1Yv3C$6-#ct5Ly1E0Q1Kj;R8=uOy88ZEDJr6}c5ra;sB)CD&=tzG=m9)p@-qf6EleOm zE@`Bl+7`Cf8b)vM^B3mk%GlW0CZe~uwaFM82YUMW$k^LwZWpMYr~%F94gi^85ZnIV zKuE@qVf1#04tI?M)r@3H+?Q`MtGy6$sah1RSV%6wa$&(IV<<_DLh|;9&33cZhSIvn z^}$`}QF$A?I#aBeq}(@$s@IEaYPZ1bYC|TqVx{D^Flc9vm)$Nut74Ti=pMhv z8fiv2T@(}#T1LirznA;5wnkgC%jZONG;Few5DW_R9HgsTYbY)WO&u>O^QRzm9af*< z7ER3IY$Hzt{dD~O!KKZFz-d@(8#{LO7L@F@llcadT%R3lTHEn&fnA4(oV0b-)zz5T z*rT&3f(b_-cfkdIH>Km$HwhvR zlrAUk&BOKGt#TGhMD!@HJ31p1W69IQU#uaqIPKh+`CHg>;KYJ_o>5zi2RrFlH1AOG zZP1jI^|8V2`u|M0>@_>a&)cV)U5`7ndi8M^HW}s&Lo(`^ES8s+C-?2DdYxpNyWGV+ zxoqmpId7;Tn-RoTZ@fiB5woc_U9QqIcU@)Z2lTtEs;QY4%<_&M4k~XGy+TVn(~?5p z7l5Jf75#yB_VDP>4nLO_AQ{v0g?>}Yx6`@qTIcp?@tjbIjWzufk)2(=DK?!4SDu5^ zbhLLsnFYAZg246e>dG|?)gkT9N+UuWY}cD~l7Q}jzQDK`?%amAQ#mDJ>3|37|yDMwpnmmy6U88P5XqKAF@0?hZMM+ z6f!n|<{KmfeC4UEzJ%_=`R_R3$1SXmJDcq z9x290I}>0K()J1}lZO@$S2p_@ot{nzwzNlI$X8hc)-#Lcu2f+VPA+!@^eBbg)A95w z)?(@Kn=cb@kCc*UXd~O0DlNzl338q|=9& z8&jbcZ>rEEKQhY7F=b^oy1)ej1SfBc14oe5>nOP7ZiKyrwi2m6{2W7HAMv$hSZU1c z4MKvWX02c*314d)TMKm~kGwKpOoChL$|Prd>6i^#4Fw7xs+d!3@e9l-5k!N71Awt$fnO`6 zEj;>g#6dcB%cxfIzSwdE%DD66aZba5p#+&oC?2+n# zS4KEE_?VkAn?`G@P%2S4K~EM-BJNePYHWKkL*RQb-j@=CKEd7VV4Y#XEEy zLZ+_GP3}1|%7etZ%V`sygjD*Uhw@3N+$`(eM0PkPyAmCmPilZCPp(yf<4w#2bQL9mdIakWrL+8KdE$HOc+OjL-G$H7bkNgd*VIyliOG+w0ue9j6Mb4+j_I>+(u@Q%^T;71izN9tQ z!r(LoRxwRK3>qeo_2sOq9lUA5D;!0}X*_4~eY`i>5gHLn@DE#YBL-MTY!;QwNIxY! z35DFc1{`z?_GB7l?!2+gcLP@n0&HKuVY2?O2y`?_(OQmi8tLC;zc5r-hygi}(T{`! zgi6CXv`onf9!B8f@u9ypa&wyor}b4dj1#OxN%UF0u#G=v5ZNvX+H_L%dSJ1{aZZynxmG6Wm=) zK>)0nK~X%Da*xrMV~s-s|K^s;+PI}ipa*g~xNE;|1As!eHE`-rndaq#5I$QhGAu4T zT3wX6*CRHQ)_`%HXBVt~QQ|W%2;up&IB!Mi$atJAUvVZKm*3;rf-~TRm+s1PUw^5` z1y+XGfYxT@gRKZuaGH9WFu9ej4Q^z=DvM6y?>E_`)wMCP&ZMSuh4@`#M_Li(K-BXP zB+qC856jbqrfoUPQ!f70O9?kLcV#Ffd_Enf_8n}UdgpXqMHNp{HePzd;*$eRI7SqN=aYuuv$mffrWlb~q6T=H!t@OOwrrZRoT}pwn&rQ*3Z=e`ziA zo40N;Lw+a^cIiB2G}%D(jKb%jcdQD+TK|{pLTKFj8l`gj^cdj9OWna7ri#Zf82@ zZ<#$gggk#z>Oi85gHbax0xOZOrp}ajaG)G>U`YjZ zkynw%e7XHVK)nTK>IX?_b#?M_iF9h`BiTx`N4Dg}BRKxwC`uS@pJ{{Q<{F-|_%EgT zPz1%Wt3>jG|H`WiQ6 z3}y0-QsXYJ)ioqx-_jOyg4qc|;5F;8DM$b``~tp$kia+BRFsp~ThO^+-_8zCxu<#$ z8zn#h(|TYGiB3aPnqZ@CmWV?*D7ehOn5B4h@-5qImil_&OHL=Yf2*lvG-mdrN?iEA z>;!3BhVtKkGrrT47M$G;mxg1lQG^fL6 z1@DgH!RX}nU+^g2gx^c&Q<>|Iu3+!O-oq70Za3kA2;wVUCluWot$saIfnZlMf@FGR z0$#h2rT39Z=#NKjY*J2IO)~>YY+s@m0=S%pp$2e#wk1mvM(MYwd;Hs-w`$usmK3u; zm&=Hy1c0j#oDQ}&Yf8r@=zO_xY{z0*q94*xD$xDaZp)h?XOC!ATn&Aqqpw$bL^Vpe zo>AI;Rm1gL{o&hqDrkZkdM80%kK@kG*W`ztsGJ*roBZn$%3ztpOT6|#v?qAswXuVS zg^Nc46}k-5k5?{t>ey_#Ih6upei14qqk)XXmuI}p;@9g{=NLdY8|+=0E75+)2VvO` zPkq%plT;Sh10@~`C8tP4@PfAeo7Q9)H^t=;B(@W?ps9n<(L_2q-#wwahY-^2Cf40~ zq5p_v{m+OR66rjI!lE*8gm5hJuH-i01mgB5$HH(^wVi8s!O}9)CQ0&gaR2T7<&YBZX@UJopb8Sh zFEpG2InKAHUOw0&blura6m>OV7cI6_Fu{5VD7r%2lY|KK-wa+hoaNT=nYR56 ziMYN-sB3AII@V-Cc*#9tU(9MZ<)>RgR@S)YF-iRSrKj=X-QL0p(4lFHdjUy- z(aDBp0kwsHXuA0*JD_V|XsEO|63i()l5au?5AbjUp@@_e%%=SBH@ z*59%W66H0pHD~5XE?VG+8S;PVLMU^CQ#Wq3#(|D-X+;-w2PqWuGdIFURrqHB`z{@w7uH z-$O$~jdP{sBqTyr&FWDODY9?}0WHi~Fj8i`nRkwuVcdl3;4F*Es6G7b(^lvo}P{RG*IpFIx~9c{;M z%I@R&G(6sVYaReHSTJw&n%f>sBA-K_KP>XXQUtoP?^Fa)v~?B1C#<7?g#r>HG7Nm- z7~p zSPVcuuf!-%HuD5!oIStWq3GRzjeK8D|8xFwTAoH3b0lYU%LTqUw! zy|KVs;Bp;WjjhNUu7L9nv2}H!=x}0vt zz~Q%$8&hoe}M{i~q-brIOv6zk?5bOaiGpEU#Is#OX5JlyIwzotIy$X~xy0D4~E z`K)_N8C^ZS$3fjK#7`ZZ;@@XVtq@06AZ%?@*AdK%KBpM&!jQpZTK?O+J1k~i8CTD9*rY^1tBn4B0&KPPWQF(YxCVUcZixX-%?Nye2@94%5Z*R zUJI(78)46BQJmGG{a3&<-Lh=CN5XC8;bX%mD)slZOR`i>d6f7g2Zip^Tpv-_JM8h& zvXMI{bHw7otxzVLZtD@)NZ{Xd7bEGKYg}O^Tl}OIsckTif)9VrA6tA>3+h|}uEHKb zELR2+dN_H!iNADs z6Xv`>r|{Et>?x9zZ`m&VcYn%N?F{DuwaEb8-2R_?O~{swgz&ZO2Q@UtrR3AtRT%3$?I3lGQhMhuzJIoY6+D@Njk2fu{gPv4Mz$UE>k+;R=Cd2&Ms4(9wTAD@EL8SjlV%U4^0sco%n9R zExQp{RF)?XJX*=f5-{-atPE>Qm)5Hl{-)rNk>7{J=&K+5&Z0fS4bJSR8o`u5;T_;sGpSd z)LNM+c0vClk&D&%=_B;av{k|D#OxAf%^27Z#{V;k{Hq{=52ZmOy)Fj}TBC{YD#Iv z$`fIb8Zpk9?a;P_@Q|afBOXxqyN4fbo#*1fFkQ6X47QGyjja&(x>h}ALCx?Db3Fd! z<`Hx{`M&a;-r+%_zqtzR;Ie<5L)DosDI)pZO6+F|FL4e({TAw)dFNrGQvFRrW+70p zW%J<+u8>v+5%3AsXV~iQ`zBbw{kkw3(t^1J;{_?!xAVq+ z(cpp_5)}WQg+Fd}KTr5GmGA-CdBw$mFd0)%vxKM&ezjRNn;{IvcVVX^au>mkh1$8y z0oI4!_bV`mvg#yOvoNQSwoy(h=Q0~)rM*v)Ls66rUSkxTP8&|@{9ZW2V@9a*GZDve zTQc<>JY-kg+ECl%q;tCWagu4E1Y@aI8!ZJ9LFfupF?z5lj$HCr!uTtCX<&AhWW~9i ze1#p(%d&s-l!xb$x#}|@AYi5a5+K-%-6lqOd;RZIu~K__1yn)T%&0^pa=4uGk9@C* z#H^=hdKM42QCY)|jEG7I37=(OD1j?<&8z3GIRgpUca%SCb!^$`=WD)rzEWp?rkRM@ zj9g0Iy@vaAex8vJ#>>S{KA>o2RT5TT8A`GG2xy+X_&n>H?v z_e{aOqrnsjzexq&7TgMO7a6eY95;l(C;<5~8`#bULCz5&B~_EUnd@O9Znx*bnqQN1 zuQDVVe}BHEUf$QTX|F9UDs_w>6TJKT$94K(sB0wV^bEC@#(x_x4dMgM_TtAC)ShwU zV`5Yq1Z<{+%C#mw-|s=H_$36UQtLbc->QyY{ieUUs{I7HSL8^(cCc0cEWbwhmX$mA zz6|gb<`*SFHBRR@udDF2Or0kSh9-A!kh)@lK1Do4UZ|iU$zpXIb()YL_Lt{z1wlto z0KZ)NFGWSgxGU@WSdkiliHQmR29~+NW=bY-6v&6EPdPATO);Lu<=vq;ai_-e*}|`j zeE+O#XMUj*5HK7u>5%bx{9Rn0gv`dku59me$`doq^c#@v0rEjXNhQvDXbxuZ34qjc z&p>{zJ0j7q7r1l9BgL0p<-v>>T6~m!)R14LbQ1$fp0?I5<@^o1pgp*#5+U|`v-g3Z zS?vPubNekUfDnXwe!P7xge{7`fbE>a7tS9kiZ%+g({B{r^nb}Tv~A|16E;|QWJuY+xru^9qfie{`gVEU7XDM8cn-y6yQ7V3Q_7Be#DbPy) zQFc8?pAVtIQ_xM7xVgqN1rQ_&&lZ0CP@&R$I#zr-*^3HqHbvp5qg0`<(rHI-jip;F zcIQ#VIK1ikL*c}hu196@J;87~+O)h?YYryn0d2y)+nlSY&Y>B7rRj z7u<=TZk73C?tKt6W&)xb)FLqlC~F5gu16ziDH`9bJxw6~X_H)BZRiqcYD-8Aj#kB+ zH-C)#xAdE3QV}Bs!Yqf7#n2ezL2>dH*C0j?rv;keR|?=WWKtd%eIZ7xK*Gd{2lqJ< z-8nm>?uuCL6@;?@!Rt25&eZm2SLpSZdbYWxYs)}mbKYqYCx;R{r&!s6I`}Iw?To6v zzHb9fs%BllNL;uU`V0G{oIpV9^{m9rO4~$S^!h+Lr=xI#>?1KbvX-Z3NfZH(XmD^a zX3ydmUG{j=-toM?hQ-hVvEtX|)oM*H<~MeTFz|;tagS#F;9}$x%`ilnq|5hh#eL4v z+J8+}Iar+cL2nLR4m+A6W22CMVq%O0PqwHyZJNQa6?fj37nOD1E4HdmX7%%$IAiIK zUF0|!0k!Zg$VB`Ud>$8l*G#QvRX(*wOi-c7;zy6AG=V0>i|Zu;6P}I^Wm3bdyvl!} zeK5m%O9K>gJi>UBR7VLx_-PBPj3r7IZo65EWtq4yS7c^ur z0?$t27jZG0z$Ve8ZpI2#DuxWgL8y@_3uWy%KTb=Vnx%H;@n@{_9@PlPl0GF-*5=J= zxudLsedu_WfLeU*FX>1rQ5PoY#^VYZS`H`^CML#Hg@a(ztsc+oD`d?}YFpB>GrRdi zedfte4P4Q}kztw5Xq;bh#qN??k;b{z`TLm2P7R6d5+hLeOMau{VeyhaixNX%2s@X9x+-|u> zr8Odzt(czUqSA}yudg%cRO;rYE`CJ>8}BSedG&k~BQIzx(*_soBbgTc1_cw0HI(CB zFnIw``x8rGM)6%8_u*nClL;moQ`$;CLq1JV%b~?S_6(tXxwc%nL#h~cH+lsImuwY_v9ykk`6kWF4DaOPBa;< z8_FLaVWc(ulfHkKkS3R51jsW}f_IeW;^kZ?=iTT&J$FXS=-U?GFb$+F2{r8L+ z`RjL#@b`p5%;%{9FOeZP8giHu&9D1GM(;90TkcDlz%Qlo_G=y@HH{jZ-nSErwR4ru z51V4BE}_F08>MmHKn(q$W<)|(=_LP#vc^ph$B)qU=fCu3BN9u&&w4_o_>QmeG)-9H ztAG~wGVeE#_P_aPJV2tVxM!X` z9v0~V<&$x>t@-J`N}cZk^gfOt;1uLqyL!Vn_k@2<>=)gi@DPlpsM%GC-MJyb4*r$i zH1g|lt>c>EY3uBABwk67RIE0DYlY-r?Z1$G&1qJeFHJMT4c3zLM-J@k7-y*e# zpI%k_v*^>B(0jfDvo27sNP&>KF~+l*?!ZnI6w|LrH=K0cQbBUiwg zp$?E(2eUWtQb_?v$cXsqajuco&ML3tp%?zCKVPUf%c~@ckWF;aew{Hpw>ny|MM^_C z>?UjZ_EN?kVmoVGmwC$+Ol$rn0vhLTSYO&9)dr7CI*vR(Od7bn9G%1z@6LxJN^(G- zY|tR=kisM5@3sVSvwQ3Aq+AkjB=n3K3=T=>GeL?j?3L4_JH72l9H8reKaKJ1eEH6v z%5NP7U%$Ry!uD;U^Iyz5X#G*T-9sQ`Bt}{FHlf&iTyBbasJ_;9L&jR(t&H0N;!3VZEQ@;y^05zEgy&$ zPAz)MzJwi7t(QtL%or<>I#$@$Btqo*=%76R>*lrFFnKo4<;iS87v#~PknrAnrg**X2Q06HL7`#tZXdi<}bwFZtv8tW!S5Ggm zuhD1Zt~J2#VbCL+Z{cp;XTSLS8|HU+MN9AFT&Lm!x~|&lc7DYq#nXEpYekQYeY~N( zriROCV6n-+q!ppfo==CJe#9cr#mZxki?arDtmY@)L%(I+i#4ygI-A0UzMu zQRH1qRLaDd&Tn9AKJ{DSCVh*aD&KhYaV^{d>Hr~0z{g{BtlJ+^Q&EA{V%#dws$@Kc zQ>2tZg!8L*T>+7_7WTr>klv>6i)ktN7_a4_*}~YxdZ!U`k-4mu6KWmC^YQSOUqI*p znU)i3!7Kwl*X8Wnjjf|U%@Jc7bv*TN&H4$(wfo_Zpt!l1eJ6|G@KwX`@e^BJuGy;l zNa^2(m%3b9UEsoNr``|pr$)kwyP~Th8?j5;Ofubnyc~e+Z$?F}l^EbbK5EH_@Lq4f zwDwE8g_u!Z|49L+X=K6;@5=BU;?2jFMo=8vbsRo=mtq~vo9$M*V0hQa5=n}yS0m1B z4=$&=;5oS!Mq{-ei>md@FcWjtoo}7uf#;bz$OOEI2=pj5!(GbE60*qZ z;)Ui|=)teOFwXYR4c7p-)(V4W4Wj22dmCvN3VN+cA&)HZx`qY<^)6vDa#3?9(F_V| z>YkW<75|R`q5Vke_Xq)J25n1vW#P4E4k^D+=YpR=zg0G`UgB`@DJPevtbs<>>p}Gt z9N5kIRsf6`oRGp5ArUqMmtjEZc$%OJ8CjqD-5yF(V@ZiPy6WMXbb$Ai$HC~>q#8UP zE^e52?#+Gsm>KH4R6|7@Mox4jJPuCH06XOMeckewUiS-D%}`g(qD{<7J=I8gHFM(E zWgaOpEOj`|GzNAg4(*n$!d^)e6F7AV6YpQ9<`t*pI$kb3-?baiU$*dxM`O_H_s{E( zM9l~Ms?#?e4WB_i=D-(|s#M&dqF6=+Bvpefa-ol>Y6@0fL!$R5l*Bf)_4R6p^$ra0 zwS1Qq%AX5g%kZ9;@9>+)PN$k_G&&yhLRo19CC?NIgwXp6yl&2Kt4E?Q9>byr-XFEP z{bcVNei?V3IWcEG?(OB>;n$%sQLIm?LJjl@xPH;TUtiC+k;?=_4h(f4iwz4cRg}r4 zMdVA!q9srg7l-9f4hxo;N?O`7pjP_WV;*ff126PQPk#SY#RaqMFJK-nx0qvNRd&zz z=!C*nE&B$pZ!-0&R0tUe;RTJl6^H`8kJ630b-SP&5g!^6MWr(Tnj9MuKaMRA{#vcIQF??YesVmQ1rpMFGWt zadq0ai|DCQ|MPMkt1W#*j8Q9P7hRXcpoK~BgM$}yoJhsf?>hNR-a$~y+lwy-IiGmk$+^XRs0PW;WB~lHSIqmd zQbh4*)!k^plmV?Dy<1~K?@vEuR8XUYG#Ia6LA8njSu}3 z%5e2~#Ej!On7DPL#zVT=k~d*8?ZE+(qcUY%`^L#rVOUsl9N_!c{&j;-P!ctxZNi6> zsd;V2r~dKryXxqEiyftHALg08+7vCQDtMiyNB%rV=c#nZ-e)0G2SxbR{hjWMn}$9> z=HjoQu!)O)oulaN=VghX*rR?AZ}NtIPq=UhE+GZnBBHg;9go3K%1DV~De6U>gvj{jw>7} zWiaMxW1LOH_@X$)tHO0Ck$@!+zka~SldrV0GEk~KEMvvksh#q}o%8(7YyP{8a9L>5 zA}IcTeLi-xap?~;!xy|msX$2rm3ZPk; z!Qs)i?$&Saa;cQ9Y&;zkJfDW?vYAnO)4sJ%E)?)Mbv0LL>fd=#q9n~b%zVblNg9oQ z-x(flHnw`FXU_ev&n(x^uXEu`2&Qf+5Rm52EjN_y%q`U!XXVG?agVty60H`m03H)Y zU^WnLHf*qiI$j}fLXIx%%!*Q3Pyo7nSaJfoZatpu*B^?I(!y(O)z* z5s=N`vR?sdm?8@FCzax(1QFjJii?5@AL4qqVFe$Zkea}jj{O!}{!Mpe^nIf2y^-di zgczW-p#F0c|J6?^<34T5&-kD*G_#9ZA^v>MKNV6n7++8}J<9n%X4Bz$FPukC;~>es zf9XoA2#Av=+dG~^`B?BC7Y7E%DNx-N#0#yQxTAh`CVm%$R4T(06KC++r_aJda>}T_4N1>SbJ4@@T<_8ve6RArSVVds#H-GKH)|0| zDrNacg5EPc^=1_3N%{HxjZB3TQn{+5qa!di7!5?U{EzN7aRdad2!R*K8mPgGxylLy zZ`=r>W)1VBLBF{vhL!G#hIZx;9Z0W@G&TfJ0B3`=`WSR5>&+tr;}LzRN%&AUa@Dcw?E{lT3?u! z_M00O?Aw9NZb|Gz^H(+ek-YbM^6K9+{F1P`ZK%l{YdT&}Uv8M4z}yZ$_T!_?PotiI zyRce-dOtPjKc6PtIoEBa&A~x~!qH~(HmH?F%j}Qri-60HzqYa*#7`SriM+GAKjMtN z!3Exy!uQL!TJ&hi705>vZ3kq}wPYAA`@){yq6O7P6(ZSs2ZeY~QNm-PDcAVE>Ew)0 zPHGur1S|^T-qn;SlL+59^X`TdcZhX)jV)MtG`{{j3P9z$q*<0#QcFw%a};_r zZd>^U3W%XT-7nL@oSEYj)?fECA=RMv05rJe6+@{DjMF%Nbf=R*DJJ;%Kd0b%PeZp= zbch!9((Z_8f8B5!+jvghE<*hQP95w>Bm6v4hZKWqSynH~7Ti}KGeH?qEVlakNd9o# zD!cDy3j$_)S)1Xv^W~72<11qq_%m_j92}6F z#qW#qWeX{_idEbrG*aAZn1xQARnof4t;P+I04<5}Lm!(Nq!>dCzD-sNi48A`$s$?T zj|-goc?3vxd8~zu@~U0(*=eH(E?1Nl6V`0+8m=0MNYdH0GP06UK5R0?Q~d^8khIc; zNmoF%6ip@wJI0T48=2DJ_*K(HC+R)smKrVialMW|&GS+&0$-iZTJ!10-pURi-1UCx zRUu)3q8bCkv)(&;c+2+fGQoef%~rdA9JC~kA99v|W5_pE=2h^qhAtwfESdusa;@eE zyEKWw9+~FJf}NOK-$!H@e-FgL9P7X(kFkVH#UnWaeyklCP2V|733f6z8 zX!NT=kD*-pi)-)(c)$AVGj`=huPd zJK%7NQeOOGLr?ePi)}fWwWdq`?7`7P4|02;IIygBmB1ol z8w?K=qtbGw1Srd?;GbJ0UhrsKMS%yMZ!cUULLYZ&z$gWaQx^`Og4^DHp>8oEuk*{( zEg#q&R|_)Op0Vn#@bM6dD>!8EHT`_`dJ-WeLJI$z{Oa7Q=6SMzilzoU_j{Va_H;+> zJoGE9^5*h%69@m&j+=Qs)F?(!1mH`(e7YdSi_xLZ>Dd$T?}HiixarAA#oehu0&EB# z1ZfwTQ`f_f#P0(;H}yUrN>dvjw_D{43;Eq`a!CBJ-jdTPyk1eVb!sRUJsB?b(8cL& zw(#pPT%@~0DzwbwG0#5;APu&DaLm|v4NDPBlxG~ z*Coel%xCb+@5+72kUsy9V(&7|RUJdG_nmF}A8&IIi1snZQ)-IkY+6MqqeAKCrl3X$ za=ZYC3vul|!uJ5zUitl2tdY#XERdA-^5U2y$_wt8$6wfIZH=p{pHkdcLA9@{+iFwJ zpbLb`b?0}FmK%a1W~R86)SZ5V`8_Q3(W#!~-=^}~v3{_7TQqVI0gaB1PD1S0q=b%v z5nD5k?wxtg#s2Uxf%pZx&GE1?yi#}mi@4@%$Q}isX|ivV&94p!(xajk4aeU~_J^ET;&gry<|9euGj?1oLRdmPgFa;TJS6&%4*DBTIIl_-`y%G-h& z>scK3gH?Gj$|kKnlB*hV=%xp2u)ShxGSD@0Q`~v9YFPo-3WcMty}W9UFFg7P)i0+g z2c6N2{np*${3kzs@6BW)e#ZFaG*x%BiW+*m<7Rx(-9ME(967)lms~5j&qYULQy1;e zQ@=`N=Qa%Y-_vpobg|<#rd@Dx245rE;%_oJf6sR=_URrIw}Z9Q@? zELb5cH@Nx`TRg_?0YmAM1a>;dJ2=xFgQ4#@n}CQYN(9EZw4@{lR z3J|K^umF8GWLZ{J)%gwX=4CQrhkU39-L^Q2SO|F%5$#Xv&OVV%^_D$g{Y-6@4~dhD zYdC>6{@{KsfMl)NF}ZomUkcywcBPKlZ5mSM`Y8QgcslWCM3SJ>*NEi7TWaz$Ga5ub ztM_BNUlUn3y*HUIiyb_>#DLQuB}DN0=Y`e-y`liNBu!XIOAZZlSY0lSMX@r!F-D^$ z0C?1)2_jELD;`ZX$VG7=!~H9SjxuacMxKCSESVXk>I){iPNt&3{v?f-=ehanBQoDtFm2J1ku8H{N_VVB-t1kI_>F(Havf|dAwa$=&z zI9&q0GvRxVAPO!+5Ao#d1kxbz999_dcxQN~L6fQL@hit+jz9w~#Ag^J%w)Y47rH91 zY6lv5SpSa6cRan8R^`?;fA@DI(EZDNNbdLS|Isaxi)Db3+?Sj} zmBLTOosNepT@B~(Lo5zeky9>=VsP}n5)4+cjjld{s@PTo(hQyL;50?0{P7LihSSv3L`vQ8Dz&?kHtzB zjxTz=OhSS5TO66{PbXQR)KaaWyQYjmI^FMjETB%+?wtN{0ll#ge`kGQgpcu~u zKnA(adc=+|P+M$xEA6jivG-X?Di_8eq@^&R~W( zWV3K-0&#KS(MSUQhY(qnXd7`#yv#fS_Y;(9>=R4%XhDxZ=3!Fzfab=aP@tiTl@?}1o)QR$gB(I_@<5rywHXUQiVF9aEKA56 z1Y+)p9#5jIHWJ{0tesoRp}|-EO0yJai=+MEJ5F!o%qy^)uK<2wqJc=ny`CTlT>-G( zCHoxob)w}x)$TKS;=iU;wE0e>MZ@-QCQ67sZ2VJ`0;MFI!18%nM)Z&ZOU#7pTaXnx zF4e2xFQ+Rz$!AXs^M_p^^`Y}~42vjlC+ur4Q-y2$=mMgy^ZLR z7?S1YSZCL12Fpddexx`+wJzWqL@7V5H#f!1;Nak>1qu-+b2tjICKlEu%YS=fh%of_ zJ(_HZJsfLqxkL%nx3vu!9#|hw$?%2GT=1QdgI`S=lr)F!IX!m9xc!L zE7Cg4OE9EPv0NN-_xS~N>xQu}WXeGtOcFwo-E8p+|#Csxlx0E1MopqJ!CMc3j^cI565rgf^A8}TF`!Lyd)4X5` zl*m3tz{9`vloxN;PuSwh`BKA}o@YTgGHZxlYf1SGD;ymEM<02xmW*6@Zb0`?bcUlWnIO0+cO9^EKbrCrS2QI8=FDXgz;XjBP7@0-AFSjm(u zU-R5fKmG%stu{r?{`m<@KF!C&HON=Ot1=+0tuW=UyN}@Sy^lk zK*-;v!4je5N+ndI;;3f2PRDxDO&Mef+lbArLH0RmS%zIeI_lp_nc>N?ic|ewQwj64 z({505WRUxdeqd{yJWu0i(2vbgw_fMkJPXHN&ic)rBcS9Rp6F{dB1@>2*Hh?j==R@& zv~SM9G2Jmj{~kJlLuwc+y|W!i%8B&{7nK|)ul=ju2&>ep9At?ckEVdd^-`D1Xvf&@ zw>KUN4SJ1{1_91?#@o&APgK)=>(|$bMq*eaVX<8n6(#@0X5tDo28mip1P2U`>*{tRGX}P6OKw?J)DEZ<0@fveuBB1mne(yN7L1;tL~m5r zR-K;G0P-QkYqb9`QXr`!wC1;a-@$KtcwIFQA>%?}vMA!X^IZb9r(3 zkRyk0-&urs5pVY>C)C1aVNiL0-0$9BiWV%qpNFiItqAgguFIFS*=;eoX%6Uuv36r5 zb0sN6P}i8Fik|Pe2J@G03WEwPBll)Ul9P$6r-B~QbL=h_0U!phDfo2zfp|BU3SR$~ zCIopEqAOr=Mk`X)c1os~TQ3?R!r&aT>b~p1Mnl}8YlwmTfC8ypmT3t+s38O`28P3kl9^8yECr_hNklR{6=AkFQ@wHfX@gVDM z*~|VtIbdAC8f10X?+_1fk#^oBHS?l@#Bxvv{yzboKw`f$%4Jw+5GeIvdFI9U5k$TY z902UEL2*f`aaeu4egFVK07*naR45^VUI?pGpsJ&~x;mLKZj_ugd$c_J&wp8ZX(vD9 zKAINOY=;>z0PZj$1K}gtQA&cj|E2wNbWF4gk!TTRL9{)|B{gN?S?h|^bsQ3ij9yt$ znkVHYN2R8^5*Zk3rMB{@RF-B*T{T(bMyR2@qBk@cJRDix+j62tUxpBxK! z!i>XN05oGqw`l#lfBXY^?4e)C#*LdSH5N=UP3gZGFaYkqx$bsP1PFu6ZQHgTMiySW z7Y+(QusTpfQsy=~i~TErq*T@>z1j;tw1V1_G*i&T{i`c1vbg_cDiv2(cWJ7xRRE() z6E^OfyjWz!Am%kzN!cfh)Kp_&@*^Y(#TT2JrMs=OBY#m##1Uso| zRdtLH9js}g;xYJ<7X**ue<9Gj;Mf z2@7(Ux88bF7Z_`iX&X<+F`Li5Hvno)5-1IcgUM>zAbTau>dI8RisR5 z0>!hyVRc0_$_*QLSn;62a`RsPBiQU>!-y$Yn0mzx0w~%%|N8g;QL3s2A;dTSNM++< zBIIyZK7>_OO8ISZH$(L>_#LgY_UzsR%d8s2poUZ&66xW?k|beJqU2@nL_Xp5V5OO# z$?n-6iFxmf8886ui&;I1Hc3sn?|tvR_vMZ|ZUuf^BnW1WI1ON04O@F;>WC}k{L8+D z>g*qhcHFCD$DeGfW1rV_}_yxCmvx^#oqXC=w^<&9J<(W($^&~=ZH$aIZjjhb_NW9`*wa$ zsCDj9y#c-*J9erNYwFagQVVHsSXeN?Rj(jogBF0@CH-)=w(pOC?gStAxpXVsv-hCZ zA#g1SxhVTvQR%SaLQAy9Qh>1%3*NW@c)_tDX;6$D$vF!35q=)68*EE2O{0*B<5F~g zezdRzoPif4*0qpcCy6`yPlhV$f3Lg%Q_C7OYTvItn3q170R!MZnADy$NiZ?>CvyO= zUHiFAn>JO2Ry2bQ3iLzN$yx}YEGK%h(X791hm|qVn|fZAT35=gKYU2$ExbXF78YA+ zQUFR~ltv+ya7G{?xeumfTCv&5V22_naQfjq?W5ym3ew2VpEY}ueDKjK6=ty=_CI#? zFtqIs*w)L6W$%lZ2c*?p863+<$F|Jplb-a@x%%?+9O@g`I{)c8S#s_?x$NSFV8iQL_saxWXh;xP zXDk5tKo*)=9JpV0E?gKWS&j#LotsyL#iU;Aw$&r}(Ki-?anJ#CEObF6%gym5#K$NL z9s^tH4I9==X4-afb3xiu1+jBa=D4?JzyP?nX7VK4;og@Z{qVz&L49d0RScHY3)I&e zP6p)wBXa`d9{~tz$_xrC)@+s0h~*rFV0N3g?uN-_lbp9`E@C^UDX8g%WJ`ppI-*n= zrxcWAeU*|sK+Nbn7J!>zu;H()bYT&425Yi3emRTPw%UWh3yaHz=go&sxkisUCN3Jx z06~|0&X^}Z~$rlMOQ928aZO!X6i zMsn=#;nTXew!a9+GbAxa_rc9j2U%3N4aCY)V-;ZlJeqr2*DVT8RZ|Q?(K2qeudg3s zN^g|%GHXAsiPP*(%zLlQfB|r?OykKlLiV|?u2vQ=UMLF|%$Fmez6@&<9qtXseQO5_ zOlcwb$f{D8OZ({X@KDw7PM$Pc)^FUd*#wgk<3VBR;@1|PgZEj~)LINEFtY*W;T;5U z+W^Hr7*w38MT<)-;KUE%8OCS#Z;gVls1Fb;ciHnIFF}@@nVB3#_LQ&4Yp{;91`r8>&Hty-^>A9twEN zpd%2HZ+apfEn?DdOZrX3vPqg?@~;((+(0`O4w=HR$rDFQVq%iK{nqPpBy9)!Buj5V z>@-y;eP{rD(o@(w4OncnMWxcx(&WGYeMNTfIe;I1+at2;lp_W-_n?sxVQNg#&|v9+ zBS4KyV5b}v6@mK*d_sVW`VnCk~iOYP3kHS!=Jel?QlV85Bk*hK2PVZ%nSn;T`_`Ym$HS1*=JFFZ%;;pS%{#~LNgBpFTGY-wq8kzx#tZJ4+rSz1MF~$0QLyK#yXfyf(l#I5pOt2s+|M? zuUxZ3nr7HuP}a2;xFE8023@_tYgiySMt=ypesJqeGH&X{GJDn(88V~+;Eob+U*Ko76QhFi>v2^$zW0$A-6+4Q_;xh*X#$B>P+s3n~JY(K3<~ z6M${NhiOWJ)HLI8k)t|i*+3Z_tCY`1v+A~);5*rq7aD$ z;N1Sm?SSe`=}(~N6#NWL7)X7>Myr09yhqo}q(1 zt*dB1O#~Cbq?%=LZ16#1ZVS|UtK(ib?3dw^*z5|*j_^1NK(?fq1<2WsW%y{Ln0?Z$ zl8Mgjy|lF;G)W_M(;Od)V+qkC9gLoBdm%_^FMZzPx#~TYn}1Zd3{|B^q_(OEW|$uO zne7=Mx6NC3jtqdiGfRC~hd)@FP-bLgAau^va`wFGupvg`?p6e%a|dxFTu9BxzS0zu zP7DMval}7T%}|8Jp_h;a1YY3aE!LNUtLoYY@$lk(ZO##_VfW#epZ&X$LN^H+7IaKrw+wlZ4^3$kSAu08r) ze0`y>CRc$!Q;t6a2EfOkqdu#_A1PT(`qV!4)ZewA3FAkC8rcA}y5>)r^%?99b@g7yHg08ENafO>cZV82W8hprMLj*Hipu!Zq~fH^x<)u!Ay~=cTm83zkk((M!Xrlvl@ZVpKl#*)_)czEC|abZ z{IINBvr=As@jvS2M1N>*7YsFSeKcJj7yx%UHGO-5KXCrgNqs;1_!IffZywVQlapYC zK}Q2zv#6T|0s^=W0xfz25eN|xp_Ze8QYtJ2Kn{glVetE9t|PYX3@kQI0G7cx!^6`D zf5>F0_u_&BXBHTFmvtvEv)@7Sk&=y=&~8*7v!E}kpU6hrb@^_!=b{S>zXQi_pJN{c zcO&k*;?l)1@TitgK3${t`}_IGbyuA$*IsjlhP-|KwKqVa>(CB^#v4gBr@X6T0NmBg z^x=8_ut{M^X%D5P%b)-Fm@Iw!8M*%I3xrlw1dT-rISBmffh2km(c_2Iueyo=wggx@ zOdJ&he0KF!>oxA8Cc<R8^ zv@6jD0cHV}E{bH+4%OL7YdHO0qIMruReFt9OV{PuidPB;Ifh&X{tL4 zYqZ5OY4Rj_{q;8xh`vbo#sFbXKFD1@}g+==Q%ZDG8dw%>KNNLCG z9(FLC6LeqeG!POD1PLQ{vuD<)dnn3nM#pc z$AdQc{e~kjJjY5(z4Ej5$gUWKu(t(LRB%X=lau9=OD>iVKKM|wvvUlHt%um@s{wGQ z)6zF5`NQ=>d}fAVUA}xdG7c`2p@TzY){M!rW9L4lkWrwl+!IqL+pge;Uyh*a1Q2bN z16l=GgrCK3lS0!?kkp!>=N}6f4YJfh0Rd75+hi6Bi)aJgie9_2UbSCf@&Oi>Q92^R zgC!RUzwLc6(QUKQyp=#)58q&_wicf=TPDIIX+8vU1#rsPxobbR3dmgyYEABd&KRL# zA@F$)fI~)ze%H0@w%|JjK(&-7rNub_bf8>u#bvT`e>6$k{IRjhYHls{hDJd=9T%+V5b zIjASvW?>(;{WCxFKE9BW@)`w6HhaxQ!p$>4JiPs;sE~=k+GsDe>1CZ23S0grj^ zKfuF>Gv(D+UXfS-_qKfH+Kb>a=%zV`-u+;OjK>dJ*=PRpoeIqoDWKvX$*M1Ye1S2|)mKQ>1^lX4TdEDRQ43A8-KHz-zo0%Ks>7$RPN zVd576wpJU!-Wvy`dSuNR`J3X1F?1y!7%r&_&bY%PIsO zJ(K91!MwxNCv*IirVmXXtUBiW{6hK0*RGO(|MzY9IwK;cpv{Ur-S0<4M972*6J*)4 z<+=zua{zW9U)Fa6;C_1YHU-W_w!w)L$IIdcGo+@X2yAh^+T?C`g3~q;`d*7lrIIsWl6t(K-OG9~Ff35vE%q+1PNnB2rbwLVc{4Z!oBFwEh*9 zBMJx>5`vfGw!s`16Ao8LBt~=eVXYllR1or~zP4N{%8KNMYcD_~k9>LIKX0i)35UV9 zxL_nF4U%18leu5!qM!>Bz&(A+IQ3;_og1&eRGxnBe*iU9X7wf5UX-csd)TlPjSseE z%U0dL^E;S=XJ;m%?`MD@AP5;Q=Wl<1R<1%Ix+eTMX^FIX>nt$#w(o1D&bVTqV^m8Tg3ykd6wp>xv5yu4Lf;$Z z-UpwQ_dedBdrsNOQ?Nx4b6gZ?1w+a`cu*|NEO#Q7)*!jyym=d{^zSQ3YJOS z3)07zpk$OsN|H%J`I%TQDlP--?5}%DzEe7E74Cp7v@^s_Yq1Eiek27YSV{4ygC$_S zVHZs>*^36LDQhthz|=`2Wa-NNQe25~1Awg0Ju3|^D3LCKF$mdlt6TQXn_*+^<{@=8 zEt_wJo9F=%ebv19^TonRpY%iM=(AK}4F9yJU{M-p%vWENi?bRq7^JkBPnj{~F z6n;>z?34E(^!d}{_iG?Hf`qK$Qp8)PUoWXP!AG{asv0hR05&Djl+?CaYAMXEZ-Kf5 zDU0=LomQX$XQaBMq)NrHSGEj89QDx=*>w-F*$k97VN9~@Kaj1uVvd3AImZ(n87g^4 zOSB(SP;2SnE0zeY1N&wGxS_sI^ATrd=gGfcdAD`XO$##GacAd1poMofz;?)%PaHo= zwr<~}-*LfNGjy?df9WdmbgM_3g~~ZZMn=G=cnD%=uY+pIM;8{yxBODR836a;W9JW( zKYFr{|9$0kx%!Glx~F3}8iMEf7vE5dm^3&Z>~%e;YKuJj`={l)o9@Ifn)^@d{z^pP zpz4Kf5hQ8@&5JC$*;O1UKvlTK)3~fsYF2YXa|o=l6legm?qwa#uny0&3`&T_D=e)V zTZF^y|XJ%s)74smZOhrq8I^Muf~lP0KvM^;wW zm)^+302n{LzA9w%Xt?qI2Or6#aY+&r?g!vjt3-D<(x1HY+ETgY<}1L?dTadU&sJ}c zC;sw+{Nu@oVAC87i8MTi;A%%F{Q$(Lve-`OfxqCaV0{C3>Up`h1#k#X?yHrA15~7< zEL1-+FAZk`*7ByEi>6@haAkR zgIB91u-x@kDs|_WAH4rop=5g3?gQFCzZ(}Lx)rKG3*+Uuxi=^4OjAszZDIT0zU3Nu z`PC0#(Ul=CjWp-9{E!zcn6IofxfXlTY8}Lv=)eHDj~+HzXXQ0$GV>EvB zrTD=jmk_AP$II5p%;^)=@PT{F5+oCQ<+Tswj@xdQabt(KQYQkDI#fC-&_Kc;K(;Bd z4jqbKhtfy^&VIRnrlACLB=IvrWCM$?hEyL>PfGz338xZXR8U)GoMR%i;GiI7gP}lz zS)>)%&X$N%C){e4)e*t$iGnSdSyH!52{h;7;Ro*kckv8#-lf`i%Fsk?E7BZe<2@F~ zz{O!2q|)owZ_|4jlIIQx#eV;%7o_NDj%d)k`5j^Y)O0pG}dKeZ-PprRN}oYX}Hw{fj}xf zcg_@0%>CF8N6OyR!>aq`GC(#uhHNzS!Q8Ja8{XQxb-)FM;3dn;#fIC3__%2K{&#MG z6#n1ZKVwHzr+xHjG5nwDeT9Vwz~_EH68mJ8N^jbs4f5WbZn#AL_~eW5AI_8dsvK-f z5dV7COxd$%FWMj_rS`_4kkqmiQr{4;odjoiXxJA{es;U0VqxH7K%ntD_s?{SP{#(a=={-Jthv>!T3&$)la*b)Zkq%Lcp^S@ zr8+Y39*%+PES7S%14_?O$z)Peg1rCXN)^N(!moC+X0_)wE zt{4FK@*^h&qaQ21Xm)Q~C39y@ZI$+t`tIF-NPnquF;U7U5-3!yY}~R_sT4CUD9a0A z(PWXT9-0(-xi?CFUKZG12D!7q*xAr6%HIIt&q1*06O^J+_pAF=jE!R;1t*Z%52IeT zYY*p0p`)Y1VO15S{<%Yw6J+0kOazO!0tK+Ga76wf6}Hq}7>NVKtr$W(>aB$FlBH%J z6y{wC9XJEf?}reJY&28EF!(#wR~Cfv#&Ka0I{U2Yn)4|Sg0ynf;ljkl=ac0d#LKN( z3iA(1O3E;mGcc`&QQ?9bNme}_;B#nTW`p@=S)}XVnuMYgg|T8ZIy9j zhACTo6s++DOXlMTxmHrsawP_!CaY}iP2n>PYD5bx_ZEbatv)K%}tqy5dJ} z7ame-%isWHB?*-6py~`eOF$l3b?fWnf*)Bbl2t4jn zYmm&_-_K9o4oeZ}j?|pv^F;gfXi_SSx*VSsPS&|WfDOQ$0Abqan`rvzCXsL_JeZyX z0D9`)J~+r<+3!m9qYD662fN^qpZM1RD=n*_PxMP?h?Jp&HJ30Ku5sW%_NQh5=(Y{G zqc*5EIRSpBtFAatHX)iN7n5@6$A9qso8;l&KBXy8>#H#)_Xe3WXAW5D4>8vE;fNfa zpRsQSz`gWn2_S-p0+p>Bm&@GQ(-a&8ic$oCZ0+Y;WZdZCYNWxRH+^QA&^rhA#lb02R<{_5 z&?sSMdltLQ+AeBbLH3$sY}Y3GXFIVNPe^#2QK)k zX8^MTnj{4!8{HnnbYiFj=W(_yU%6iAC@LyU7c|vxW8tt17Y3@*==;0~KE^kH<#HHt z48|VZUmp6|ZSvqR|AYkrY&AmEjvbY#I_rZ6Qq@-a%fd<<0NcNolYCcjz$xIP58s#B z)5ieJUMf5yASwAhd^lSvqdz=}NLd(-f(fyUp*~u*W)qAX2En;K6hb145>e>HdO0~c zNHN+7!w66^P*4wdE5~muXcg?%B0+FcXH2Js2&j7M(N<`15KJE}qY7PQaE-tsJ4#@v z->&`L9qWPu4?yC$XH6d`d(%o}$gt6{9`ly;j2t!fMCMS5jt<4*P!379rK)mX1gtfN zFicXQqrw6%8T9T@=k!ZRhyOI_!-ZQH~{Nk-}BL0;{H~Tw(@6P=hQ6 z+}}dOs@I)|O~CO!0?gBsiO0yU;(qi+cD)q)Xq7|*A;c)_v(PP(l3ok9Jm)|#j!2Yw z&v-=1+`4Ti79STl=g*M!n|CVmG$hvVx8SJV#LPJm&@##Qykttpg#EF5_DvPx!0r-1^1=Y zi_(0Oz|P4n(2kShL)9^!;8Fks7&PGU_wxkMf{=)Wg%LMw7PAd()+OkkDeXm@q`aKy-Apz1AfI4BTL zj1ONAI^i$?uT&QeYhkd*WxrbsMoWtoFu-0s_+7Y{KX>6=S%Yvo6lU#DO;;h5^FqQg zTgCc*77e#za8WhI@I8|!j*`cpcn(exHL~dJsj~FF*RVfk7@jjfs-*$2I}iHnO;t0#ILaUrP&g(77pYu<$MQP)ZU zQ(Z%$mo6Oa0b{lcISU`$KYrXuI9_mX86dM}PLt2!_Q$qJp~FH0HQi|~^xHhArL74I zew+(XZ0BqctXl&YL7Hun%`b&;io!MusYqcl5PKMS=NEMPsE45BXqR!YFS&4`j2xaU zzxwUpuwePf6&KBuXP>^dN}>3B#r=%#7#;@a1A^B9Qf(VQ z%2vX}@#8Xo-vk>e6j{&&P_)9LVr6YfiK-wiW+V)@MK+bcX|3St;;Vx7h@YH_dW2qj2$~lyj@FlQKfF!0Jz;u znh%@-rFfvObWT{e=2O@@Pg3=YO@%1DB2cLQ7zK%NHds*l{N{pXrm+UWMx%tS+xEhc zBSnE?%`B~{5IPo=F*mP30o;UO=s=iKI7(`@C_wmPBL$QOpGcKhV$cUwQ2b2RozW=O z8VlC~5uLID1{@q87X-4}?33Tgy4z}%psphujm3a~%0*18z@QMQY-WM&-41pap=Fz0 z)U=YJcC3-$)ow&bVvmn{V6f|2%c{WkDX0sFk1{zEvij5sQ%c>=-do$@6!5;b_N>!b zvTΝ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 diff --git a/apps/fontclock/custom.html b/apps/fontclock/custom.html index 0d88d07df..862f83f81 100644 --- a/apps/fontclock/custom.html +++ b/apps/fontclock/custom.html @@ -44,12 +44,12 @@ { name: "black", background : [0.0,0.0,0.0], - second_hand: [1.0,1.0,0.0], + second_hand: [1.0,1.0,0.0] }, { name: "red", background : [1.0,0.0,0.0], - second_hand: [1.0,1.0,0.0], + second_hand: [1.0,1.0,0.0] }, { name: "grey", @@ -74,6 +74,7 @@ { name: "black", background : [0.0,0.0,0.0], + second_hand: [1.0,1.0,0.0] }, { name: "grey", diff --git a/apps/fontclock/fontclock-icon.js b/apps/fontclock/fontclock-icon.js index d9bdd8c65..49431587b 100644 --- a/apps/fontclock/fontclock-icon.js +++ b/apps/fontclock/fontclock-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("lEowkA/4AGmYIHABHzmVCCaE0kUin4TPmUimQTQ+UzmcvJ6EjCaP/kYABCaEymYTl+Q7SMgITTmQTQPAK0RMgITm+QTS+ciPCcikQpPY4MjmYTO+czmcyHh4TCmcvJ54nCPCBjBJx4oECc8zJ6ATTn48RE4YTTHh4SDH4ImRFBwTGFBgTGFBgSGFBYmHUgITRmcyFBASFAoUjE5PzkQLBHJxiDAQP/GxAA==")) +require("heatshrink").decompress(atob("lEowkA/4AvmUiAA0/CRHzkczAA0vExM/n/zn8zAIPzCZUi/8j+cvmUzAgI7JBQITHkY6JCwRNEIYITIDoQSEExXyDoQSDn4mKHQ4mKLoImRHQQmPMIYTDExY6HExY6HExQ6HYgISJHQ4TBAgbXOAAb3Ba5giBn8/H4zXHMYfzEww6I+cyPJAtEToizBNoQTFLo0yBAKMI+UikUjIwQSBJg61ICALGMPQgQBJhB6IbJjcGJhw6DCQJMMUIhMOHQavBCRo6CJh46DTJo6EJh5eCTJwADdwISQJiIAo")) diff --git a/apps/fontclock/fontclock.png b/apps/fontclock/fontclock.png index 70a1cd5327a61bc1b0d393b57e2093864e565b9c..97377413c55a3e2a4023dbafc411c77df6badd74 100644 GIT binary patch delta 5994 zcmV-w7nSJk6x%b9BYzBOX+uL$Nkc;*P;zf(X>4Tx07!|IR|iy6$r_$pl8}(l0uhiB zdK08qDIv4~0#XGVAqgau7!rbt9bHs#t%xXAbXCN*x&pEm#I7uYy)PD2lyy-TMNxSZ z63}&DIqyGb?tJ;?pTFIi+!+8g`?wNGE~*7Up1437A0EscpMRRhBy|ED7yt&a0cKpD zOu~wbiw01J`oGJ&8vs%CR~;3${yF|%MTakt@c=+3LY%>u@$w*U0s!B@lSm5yAS!r^ zX$2Amo(Hk66b1-!xdLY?@h%0CD;c@2tM zh)5>M<<9s&OY^@aFIPU~!x}cKP#O`h$RF15R?gHY1*SsWEzXFERn!{dJ`rD8cK}d| zP#%$_)JKhYGB&IqeCGgl=5s@$AU1+HOq?4Nt>QB>MSo!&h~a8Mr;7?Wi4f~UyjUO$ zO;G7F$H1@#FmAk6 z7@@2Wc7K}39gH95g0%_6tfV130@?WJp=;~v&yF< z$Q&Fk9GsB@o!XY{W4PYz;gRqCv%jf6ANEn-YhsJBL)ba& zBz6Hiiq!)qb^>d_TCigZJiNM|46d#rZ-4QF@#H`|qJQ|~s(dOcDRZuM?sER594in^ zFHmee_EgCXsVGZWz+}O%gMi5q^PEO8U7cNB08o5ulz(4u8H3*tgmLjJm)`_{Pbnm` zzH(d(0FFEbfd1|)XYmGZn-u^YYvakKg-Q-rJP7b#LKE&Z17HFyfGy0&6?g(a5Pt+h zK_rL;i69kBhE*2AbuI;ikiK~N8lf|KAZxCGk3b#NE1 zo=)%*^niDuA3+cjLPO|?0b+_+Ar6Qu;*A6#p-40mkE9~$NERYS!0aAvnLe?W& zks9P@cP7xD)Ah<{=z71c$JQEPNG>W#9{C^QkBgl3`nXc4*)U4~Yo z)#x6y4n2upLa(D8=u5O01DHC-z|1g5%o}54u~-_GiAk|JSSeP4Rb%_GM);nuVjWmF z_5mm2bexGh!WA5WC*eFiAD@FS#nsX4#Hu=8Mv1^3GawRB7RTF(W=#vCrO^s#%V;&UQ?v)PJ`K8tlLkkF zuQ6AnN~2EWipDEVvZj?LOLMYjk!FSFAxAm?br$Mu(>bN{n2ymc=xjQVzJR`+eumzuOVqW|<>+SX zmg(-*ZPo43)6sL+OV*pNSEYAMuY-XxtQj0eE@L_4Amaw(;|SvstPz3{OGfM)ab?7N z{gL`X`U3q@{r&pa^?yGaFbzTtatu}))EnG4#0~8Y#~DsD++=vhuzRHLNWYQ1k)!U@9^#H$7qc zf~m)3F>{%f%+t&sGb6JIGr8GTvsSZya~ty{^J4S;=Jzcq7JuFrnHJ?1%@#eDrj}zZ zXIa)--mxNEd0Pps)>@sjdT(uGonpPny59P^jlK=XrpTt&=AJFhHqbWTw%YcZ9nsF) zF2`=8U7I~>?_n>rud=`FfI4_Oh#WRLw2vZ;@);!_RXysaBh``RSm;>m_|S>r6zx>( zRPXd^wB_iu(SIvPpBw$f*~2;4dAsvn7af;KmtvPjmp88Vt~}Q&*K2Mxw=lQ4ZVhg) z-5uNo?wj0idC)z^dMxs2_W11St=h@|D>6Pxa!Rw~Cu6LaGQt$IV1fO7^xjsjI zKKOe27Wf|Y{nO9UFUN1U-}5mxV+3Qik9q8G?$7n#>VMx6zzj$a*b>kYXcou~tPXq> zWD&#<+7a}OWyi{9?P0wNb`F*X9}a%c_GQmzH-%s!;UT3Vt)V)hNuldQAB35QWrfv- z^@Mwb&kS#hAVfq(tc`r)>7@W8~@otiB zl02z7Su=TJa!vC4l#rBFDIMcSkDopMQmSF9D77Jtl$M;fBdvEr=!7*BIwyKeESY#? zlFg*)lP*j)oSZxP*c8nv+$o3B3F#^6yVE~$V}H5T+};dM#)ga@9-Ft8_mUsPFXwj& z`~|B7&occpS7koW^3PhG)g=rRRtURAY|(nr>+Fc^&DrmBVsm!p4CJQd?$1-pOV2wZ z))D83PfsB#rZUz6V>jgsz=A+kxbh5}u9sBe+m%72hQEDR{DD(st< zJb&%bbnWTl=`AztXDpfVtSGGLrZCJA5{YL)A zE1QBg?b~d;xoq>tEut;AwuW!5tG2GL*hbt|xb5loxpwrkJCJ#BkK_BQNu+_!ZVMklai?3)M4dT*Htg)FbF6bG&ikJ~dcpU?k&E6J z>o0j;s%!CRIsBW)Z--kwTk9@+U2bUeX=`jB(|-I);FXhCL$02^#<_Osdd&6q8%Z~A z-JE!{;}-wc^V_+%U*9Rb(|>o~J;J@x`&#!a9vD5S{@w2P{T-ei#~y|}Y=3!_@aXPi z-s6`~WKTYIE__ORTJg;ES05)hJO6V3tGPF>_rbfocm3~6`waSaeenKp?qkZwXZ_PYkv>&^w)@=p zCF;w)fxLkM30KM;JPKg2p?{f~0KC}=04)`s9pJrg8n zC;|*DWq4_3I#qLJazk%zZDnqBK2u|IWo2%2Xm4~pFJ*XXW;#`KWpYDrZEa<4lZ^r* z0W*`Z0yzRRGL!29Ba<`&Vv{%nE`N~aCZzxX3HM1vK~z`?#aIb&Rn-~(?tOb+HVA|S zNMwnug}?+7F_3^P3ejPx3KXiqsHJpJGfvxSXKHOrF*<6+VLH>+K&1^ZC@?8Y*pe0q zO9v1zgfIu-Qh~^YMkB%F1{_Y0=+h%`*gcR{fSTtyL34Sdz=Gw|F)?{O6x$MY zLf@)yBW_w*=NO`?N?A%QVZB`hQGYu zj`lV?JS2$&yE{>Gt&b$@#+Q{A{PCR@{NryeSo@2`(1+>!UHm`*B^D92qj{%kw;l`| z6%MzH{6=j^d?d6m5r3#Ygc)^+h~_0Ep|xQnDF}SzL=BOl(~}+AXipEbZNbW)EycJ= ziT&W%UdS3$TzmOU2~O-dhs|#ODf;D6oISp9k`qGOEE>D08S zid<)fUTz|mIC{Mit0$H?3>lOm%)1=hi6FgImRqqi$Aq=NUJ?{sNC3UM^QM%&A0EfT z7m|=PB@T9rL!=PE1COnaJ2IaXT_g>Q->w5Jcc<7X9^n(oEu-+++b}`fJ(k= ztTQ41{bH=nPD6Nv9!`gg$f64AvXJiT24#*H)oLX))Y-9Xn+eNaor{d6vjh&VLVR*z z_Jk)`p@X0d3ef9XnF_fBdp|gVCpS#QxCtYuu78qi$uQ>?p*s&nagap7Yw;GT zmW%|k%CKo4-CZs^JOGLH-S{l`G+cDbQE7OC6!^3^E_-2NK*FQ(BHaYj3*=B}XcERbAg)14HfsR`m zody?*I#Kh51HaAR2!qie?)w7`V2}+mxUPE8j@L@VH3WEH+j7! z@LzED6uc^xgvrUYsNF!d*Lw!!q%4Q2;D6|qaHg;sR+|n#_}zQ~j-T@fCw`OO#43DI zZtloAi0CNb*>$Pn@W~VTxa+ahP}H_kKX}xNdGwD@&zzV!06N;8IDDW7F|jJFc%F=s zoyu|x@^>|2==elr{V*MIqlYPv4!8y|$al}3xB^qT2`h6JkxracTPbQ~(w&Wf*?)W~ zg*L+)3)a{R8qyiF$6LQxY$kRjELj!-vspr6K{GBDS+Q(W2GZt#k4`1w`7MyT4e6D@x3q4x&~W5#NUS!PN2lWMbCB;C(1_2JOoUOJ&@5j}**Bpl6e z#rXm&p58ncbDo$^&v_%6WuVCFUSP`a{wP*hto^b9XAfT`*Ln{K!cRnvhkr_$mO$Jr zu1CUzFsy%Vh9H-{qV_bQwW%G)4)>v^+==JbMPTx@FjQ5T@!5_RL?^~!#mgB1tbHA@ z0RVYGag%cM-fKfmBX+)-kC%Rxj`-0rR8=Tn5W^*xDsgCMC8o_WB5Qf1$Zw|#+HwB4 z4Ou^)jr7Gch5tpC;2Iu63x9AiYlzc;SFDuX$q=86IU22ID?Zs$fJLh(Vq{_r9T?~} zjPB*{zJ{_(O<1#O7$#0Npt_2fBy#n^nZ*2vf&$-%TQWaiR=%Sh}+@~j#5vUwihYs22_=HV*e-Yh)NuZ*FKzs z5u;qyrA5}NnXp>yR73fIAfxQs4IJN7 zfrv-OBWukp#3hUnCipu|fASS05BD!9g9^anW0%p>)PXfWdP004GKA~V-C@Srf>K;B zZoz`JnUvS2QvK$9=Y4(qCc*L61^`rCTVLIXBik-u(|Z{(4u9c-?-mKX;O`}fP8g1t ze!qfJjWV8vsxV3jWTwYwIy&ZJL5H(?^rmI&tP`DN4>YW8sTwNX?uk z+{p7eEq&9h`6Cai!Tlefgr&U=FJ#Xr)@pGm_Zng!jl)xG=;Wc~HDCI;--_VBXej-D z2F1%W<*S>YSAU|GzD})vbqyY)6bj-@2lZP*52pRCv|2t>_rx|mv1s`SS z;gKoP=xpwVE;0(wY{*0`eedJOrHZS~x6PXWz6FEcqDG%;=`b)hIS%#ZEtvOg3TBhm zlnNkD!XegC|Aij3->*R>weaU#8|Az3NP3&0#^c<+ODEREg1&$K0R0D*z5-hL{r|ZB Y51A2cZY8m0sQ>@~07*qoM6N<$g8lGhNB{r; delta 2036 zcmV004R>004l5008;`004mK z004C`008P>0026e000+ooVrmw0001ZlbQ@sNJszx0096107w7;00963paK8{00001 z0000epaTE|000010000e00000#uS4c00009a7bBm000XU000XU0RWnu7ytkQXp>P5 z)00~cB$G%E6O$wkB$F%;Zj-#et{1%|-2lPk!3w`b9BtY}lCTIfWAu*7&cHLNtO;IEziWiY0XGqS4 zUHh;!5TmgBXh6d9z;rjv3s})pUo?vCQfPcG(hX{fI znx;j%+uKey-gd&P3SPY@>$#14VO?JcV#BfO6%Sa-vgOR(Ee=G#XBdf~fk}T_rVA+0(xX7xQiB2B;E@ zdA7d2ivR{e1}C zt=6cMeFXjp;R5A6v)y_*+-AK$rigm^qowkhay z=uYGiOX3T2j(_Xo>o326KWO3b?g5V8y91LNc&oUJX0wAAFG~b_AG>?Sxxq=)A_JVx zBsT5+(ftpUU`vX*g8}mS90o%Vx5%D=+@aeR!Cqv{6=DG?ReNyjH*BDiD4qPsek4WX z5W==RR4XMMzW-Zfvsq4ii?sle8Jw~qp%!PgSG)%!xqpeu*%>Y>C(N@D?;SlrGMU84 zlf0X_o#}N^Kj&gl9x_SzF-3ZS2M-@15jUX+4Pt;U^v-C>3;^|iInpD78%{yUPZO^L{+lRV?6NM zUEaLA5J0KW%X)=2KV*ng*xFcwVI~v^gXVR}e#N4hSV@ghI(`f(rl?gt7eEQGw3(-; zCHPJa31N)P#Msqa@g$c*R#aaiEkL7jNlYd@hP_&Tro{Wroc;3XTmU7s9uw}WQDQNS zFn<_~SRj_tL_;UYbOBvgx;qaTwNfnMJsSd%LbaTW`65vCZ&x$p=fA^RAduS-)8;6n_wmEtQ8x%wtNhp<*Ew_qWkJe@a79ew7+; zB6DVd0!~EP_e1L3DcegItF-%eDxn&7<*pNPK1;)J>Pyv3uQ9 z%pL60GoC-g)2II+i*JG#!4C=m#+J;TQjD8Y5)7q5|K~u{X%q}g&BKo4suz*AGk{=<2l-4K-+uKO3++r5+^_Y~GczcQ<`>K#r&CdayqeFTTB}31 z^4Kaq Date: Sun, 23 May 2021 15:04:32 +0100 Subject: [PATCH 0025/2129] font clock bug fix: not saving settings when background is changed --- apps/fontclock/fontclock.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/fontclock/fontclock.js b/apps/fontclock/fontclock.js index 25260c42c..d453f6b9a 100644 --- a/apps/fontclock/fontclock.js +++ b/apps/fontclock/fontclock.js @@ -268,9 +268,9 @@ function next_colorscheme(){ //console.log("color_scheme_index=" + color_scheme_index); force_redraw = true; if(prev_color_scheme_index == color_scheme_index){ - return true; - } else { return false; + } else { + return true; } } From 658b10fed3ee84884d4cde6fe8daa2721982d551 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sun, 23 May 2021 22:29:08 +0100 Subject: [PATCH 0026/2129] font clock. - Took out old code - Code now too complexed for emulator so took it off - Added ROman Numerals to vector fonts --- apps.json | 2 +- apps/fontclock/custom.html | 8 +++ apps/fontclock/fontclock.font.abril_ff50.js | 36 ------------- apps/fontclock/fontclock.font.mntn25.js | 16 ------ apps/fontclock/fontclock.font.mntn50.js | 10 ---- apps/fontclock/fontclock.font.vector25.js | 16 ------ apps/fontclock/fontclock.font.vector50.js | 56 +++++++++++++++++++-- apps/fontclock/fontclock.js | 33 ++++++------ 8 files changed, 80 insertions(+), 97 deletions(-) diff --git a/apps.json b/apps.json index 4f050b0ef..c3576d495 100644 --- a/apps.json +++ b/apps.json @@ -223,7 +223,7 @@ "description": "Choose the font and design of clock face from a library of available designs", "tags": "clock", "type":"clock", - "allow_emulator":true, + "allow_emulator":false, "readme": "README.md", "custom":"custom.html", "storage": [ diff --git a/apps/fontclock/custom.html b/apps/fontclock/custom.html index 862f83f81..6a013a003 100644 --- a/apps/fontclock/custom.html +++ b/apps/fontclock/custom.html @@ -151,6 +151,14 @@ name: "grey", background : [0.5,0.5,0.5], second_hand: [0.0,0.0,0.0] + }, + { + name: "purple", + background : [1.0,0.0,1.0] + }, + { + name: "blue", + background : [0.4,0.7,1.0] } ] } diff --git a/apps/fontclock/fontclock.font.abril_ff50.js b/apps/fontclock/fontclock.font.abril_ff50.js index d61a2ca49..3d5169c63 100644 --- a/apps/fontclock/fontclock.font.abril_ff50.js +++ b/apps/fontclock/fontclock.font.abril_ff50.js @@ -8,48 +8,12 @@ class DigitNumeralFont extends NumeralFont{ super(); // dimension map provides the dimensions of the character for // each number for plotting and collision detection - - /*this.dimension_map = { - 3 : [30,38], - 6 : [30,38], - 9 : [30,38], - 12: [49,38] - };*/ this.widths = atob("DRIhFRwdHhsfGh8fDQ=="); this.font = atob("AAAAAAAAAAAAAAAAAAAAAAAH4AAAAAAD/AAAAAAB/4AAAAAAf+AAAAAAH/gAAAAAB/4AAAAAAf+AAAAAAD/AAAAAAA/gAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAPwAAAAAAf8AAAAAA/+AAAAAB/8AAAAAD/wAAAAAH/gAAAAAP/AAAAAAf+AAAAAA/8AAAAAB/4AAAAAD/wAAAAAH/gAAAAAP/AAAAAAH+AAAAAAB8AAAAAAAIAAAAAAAAAAAAAAAAAAH/8AAAAAP//8AAAAP///wAAAH///+AAAD////4AAB/////AAA/////wAAf////+AAH/////wAD/////8AA//////AAP/gAA/wADwAAAAeAA4AAAADgAMAAAAA4ADAAAAAOAAwAAAADgAMAAAAA4ADgAAAAeAA/gAAA/AAP/////wAD/////8AAf/////AAH/////gAA/////4AAH////8AAB////+AAAP////AAAA////gAAAD///gAAAAH//AAAAAAAAAAAAGAAAAAwABgAAAAMAAYAAAADAAGAAAAAwADgAAAAMAA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAAAAAAAMAAAAAAADAAAAAAAAwAAAAAAAMAAAAAAAAAAAAAAAAAAAHwAAD8AAH/AAB/AAD/wAA/wAA/+AAf8AAf/gAP/AAH/4AH/wAD/+AD/8AA//gB//AAOPwA//wADD4Aff8AAwAAPn/AAMAAPx/wADAAH8f8AA4AH+H/AAPgP/B/wAD///gf8AA///4H/AAP//8B/wAD//+Af8AAf//AH/AAH//wB/wAA//4A/8AAH/4Af/AAA/8A//wAAD8Af/8AAAAAD+AAAAAAAAAAAAAAAAAAAAAAAAPwAAA/gAP+AAAf8AD/wAAP/gB/+AAH/4Af/wAB/+AH/8AAf/gB//AAP/4wP/wAD/8OD+OAAw/DgPDgAMDAwAA4ADAAcAAOAAwAHAADgAOAH4AA4AD///AAeAA///+A/AAP/////wAD/////8AA//9///AAP//f//gAB//n//4AAf/w//+AAD/8P//AAAf+B//gAAB+AP/wAAAAAB/4AAAAAADwAAAAAAAAAAAAAAAeAAAAAAAfgAAAAAAf4AAAAAAPmAAAAAAPhgAAAAAPwYAAAAAPwGAAAAAHwBgAAAAHwAYDAAAH4AGAwAAH4ABgMAAH4AAYDAAD4AAGAwAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AA//////AAP/////wAD/////8AAAAAAYDAAAAAAGAwAAAAABgMAAAAAAYBAAAAAB/4AAAAAAf+AAAAAAAAAAAAAAAD4AAAAAAB/gAAAAAA/8AAP//wf/gAD//8H/4AA//3B//AAP8Bgf/wAD/A4D/8AAfwOA/jgAH8DAH44AB/gwAAOAAf4MAADgAH+DAAA4AB/g4AAeAAf8PwA/AAH/D///wAB/w///8AAf8P///AAD/j///wAA/4f//4AAP+H//+AAH/A///AAD/wP//gAA/gB//wAAAAAH/4AAAAAAfwAAAAAAAAAAAAAAAAAAAAAD//wAAAAH///AAAAH///8AAAD////gAAD////8AAB/////gAAf////4AAP/////AAH/////wAB/////8AA//////gAP8B4AD4AD4A4AAOAA4AMAADgAOAHAAA4ADABwAAOAAwAcAAHgAMAH4AP4ADD5///8AA5/f///AAP/////wAD/////8AAf/v//+AAH/7///AAA/+f//wAAH/H//4AAA/gf/4AAABgD/8AAAAAAH4AAAAAAAAAAAAAAAAAAAAf/wAAAAAP/8AAAAAD/8AAAAAA/8AAAAAAP+AAA/AAD/gAA/4AA/4AA//AAP+AAf/wAD/gAf/+AA/4AP//gAP+AH//4AD/gD//+AA/4B///gAP+B/+BwAD/g/8AAAA/4f8AAAAP+P8AAAAD/n8AAAAA/78AAAAAP/+AAAAAD/+AAAAAA/+AAAAAAP+AAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAB/gH/4AAA/8D//AAAf/h//wAAP/8f/+AAH//v//gAB//7//8AAf/////AAP/////wAD/////+AA//////gAP//+AB4ADgAeAAOAAwADgADgAMAA4AA4ADAAOAAOAA4AHwADgAP//+AD4AD/////+AA//////AAP/////wAD//7//8AAf/+///AAH//P//gAA//x//4AAH/4f/8AAA/8D/+AAAD8Af/AAAAAAB/AAAAAAAAAAAAA/gAAAAAA//APwAAA//8H+AAAf//j/wAAP//4/+AAD///f/gAB/////8AAf//+//AAP///v/wAD///7+eAA////PjgAPgAPwA4ADgAA4AOAAwAAOADgAMAADgA4ADAAA4AeAAwAAcAfgAPAAeA/wAD/////8AA//////AAP/////gAB/////wAAf////8AAD////+AAAf////AAAH////gAAAf///gAAAD///gAAAAH//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AH4AAAB/gD/AAAAf8B/4AAAP/Af+AAAD/wH/gAAA/8B/4AAAH/Af+AAAB/wD/AAAAP4A/gAAAAwABgAAAAAAAA=="); var scale = 1; // size multiplier for this font this.size = 50+(scale<<8)+(1<<16); this.y_offset = -12; - /* scale - this.widths = atob("ExkuHicoKiYrJCsrEw=="); - this.font = atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/AAAAAAAAAAf+AAAAAAAAAB/8AAAAAAAAAP/4AAAAAAAAA//gAAAAAAAAD/+AAAAAAAAAP/4AAAAAAAAA//gAAAAAAAAD/+AAAAAAAAAP/wAAAAAAAAAf/AAAAAAAAAA/4AAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAA8AAAAAAAAAAfwAAAAAAAAAP/AAAAAAAAAH/8AAAAAAAAD/+AAAAAAAAB//AAAAAAAAA//gAAAAAAAAf/wAAAAAAAAP/4AAAAAAAAH/8AAAAAAAAD/+AAAAAAAAB//AAAAAAAAA//gAAAAAAAAf/wAAAAAAAAP/4AAAAAAAAH/8AAAAAAAAD/+AAAAAAAAB//AAAAAAAAA//gAAAAAAAAH/wAAAAAAAAAf4AAAAAAAAAB8AAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAB//wAAAAAAAB///8AAAAAAAf///+AAAAAAH////+AAAAAB/////+AAAAAP/////8AAAAB//////4AAAAP//////wAAAB///////gAAAP///////AAAA///////8AAAH///////4AAAf///////gAAB////////AAAP///////8AAA////////wAAD+AAAAAA/gAAPAAAAAAAeAAA4AAAAAAA4AAHgAAAAAADgAAcAAAAAAAOAABwAAAAAAA4AAHAAAAAAADgAAcAAAAAAAOAAB4AAAAAAA4AADgAAAAAAHgAAPgAAAAAB+AAA/8AAAAA/wAAD////////AAAP///////8AAAf///////wAAB///////+AAAD///////4AAAP///////AAAAf//////8AAAB///////gAAAD//////8AAAAH//////gAAAAP/////8AAAAAP/////AAAAAAf////4AAAAAAP///8AAAAAAAH//+AAAAAAAAADAAAAAAAAAAAAAAAAAAAIAAAAAAAAAABwAAAAAADAAAHAAAAAAAMAAAcAAAAAAAwAABwAAAAAADAAAHAAAAAAAMAAAcAAAAAAAwAABgAAAAAADAAAP///////8AAA////////wAAD////////AAAP///////8AAA////////wAAD////////AAAP///////8AAB////////wAAH////////AAAf///////8AAB////////wAAH////////AAAf///////8AAB////////wAAH////////AAAAAAAAAAAMAAAAAAAAAAAwAAAAAAAAAADAAAAAAAAAAAMAAAAAAAAAAAwAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAP+AAAAf8AAAD/8AAAD/wAAAf/4AAAf/AAAD//gAAD/8AAAP//AAAf/wAAB//8AAD//AAAH//wAAf/8AAA///AAD//wAAD//4AAf//AAAP//gAD//8AAA8P+AAfv/wAADg/wAD8//AAAcB8AAfj/8AABwAAAD+P/wAAHAAAAfw//AAAcAAAH+D/8AABwAAA/4P/wAAHgAAP/A//AAAfAAD/4D/8AAB/AD//AP/wAAD////8A//AAAP////gD/8AAA////8AP/wAAD////gA//AAAP///8AD/8AAAf///wAP/wAAB///+AA//AAAD///wAH/8AAAP//+AAf/wAAAf//wAD//AAAA//+AAf/8AAAB//wAP//wAAAD/8AD///AAAAA8AAP//8AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAABwAAAP8AAAAA/4AAD/8AAAAH/wAAP/4AAAA//gAB//wAAAH/+AAH//gAAA//8AAf/+AAAH//wAD//8AAAf//AAH//wAAB//8AAf//AAAP//gAB//8AAA//+BwD/D4AADw/4GAP8HgAAOD/A4APwOAABwHwDgAAA4AAHAAAOAAADgAAcAAA4AAAOAABwAAHgAAA4AAHgAA+AAADgAAfAAH8AAAeAAB/wD/4AAD4AAH////4AAfgAAf////+B/+AAA////////wAAD///3////AAAP///f///8AAA///9////wAAD///j///+AAAH//+P///4AAAf//w////gAAA///B///8AAAB//4H///gAAAD//AP//+AAAAH/4Af//wAAAAH+AA//+AAAAAAAAB//gAAAAAAAAD/4AAAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAfAAAAAAAAAAH8AAAAAAAAAA/wAAAAAAAAAP3AAAAAAAAAD+cAAAAAAAAA/hwAAAAAAAAH4HAAAAAAAAB+AcAAAAAAAAfwBwAAAAAAAH8AHAAAAAAAB/AAcAAAAAAAPwABwAAAAAAD+AAHADAAAAA/gAAcAMAAAAP4AABwAwAAAD+AAAHADAAAAfwAAAcAMAAAH8AAABwAwAAB////////AAAP///////8AAA////////wAAD////////AAAP///////8AAA////////wAAD////////AAAP///////8AAA////////wAAD////////AAAP///////8AAA////////wAAD////////AAAP///////8AAAAAAAABwAwAAAAAAAAHADAAAAAAAAAcAMAAAAAAAABwAwAAAAAAAAHADAAAAAAAAAcAAAAAAAAAB//gAAAAAAAAH/+AAAAAAAAAf/4AAAAAAAAAAAAAAAAAAAAAB+AAAAAAAAAAf+AAAAAAAAAD/+AAAAAAAAAf/8AAAH///4B//wAAA////gH//gAAD///+A//+AAAP/ABwB//8AAA/8AHAH//wAAD/wA4Af//AAAH/gDgB/9+AAAf+AOAD/h4AAB/4AwAH+DgAAH/gHAAHAOAAAf/AcAAAA4AAB/8BwAAADgAAH/wHAAAAOAAAf/AeAAAA4AAB/+B8AAAHgAAD/4H4AAB+AAAP/gf////4AAA/+B/////AAAD/8H////8AAAP/wP////wAAA//A/////AAAD/8D////4AAAP/4P////gAAA//gf///8AAAD/+B////wAAAP/wD///+AAAB/+AH///wAAAP/wAf///AAAB/gAA///wAAAAAAAA//+AAAAAAAAA//gAAAAAAAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAAAAAAAH///4AAAAAAB////8AAAAAA/////4AAAAAH/////4AAAAB//////wAAAAP//////gAAAB///////AAAAP//////8AAAB///////4AAAH///////gAAA////////AAAD///////8AAAf///////wAAB////////AAAP/4B+AAD+AAA/4AHgAAD4AAD8AA4AAAHgAAPgAHgAAAOAAA8AAcAAAA4AAHgABwAAADgAAcAAPAAAAOAABwAA8AAAA4AAHAADwAAAHgAAcAAPwAAD+AABwPw/////4AADg/z/////AAAPD/P////8AAA//+/////wAAD//7////+AAAP//n////4AAAf//f////gAAB//5////8AAAD//j////gAAAP/+H///+AAAAf/wf///wAAAA//A///+AAAAA/wB///gAAAAAYAB//8AAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAAD//+AAAAAAAAP//4AAAAAAAA//8AAAAAAAAD//AAAAAAAAAP/4AAAAAAAAA//gAAAH+AAAD/8AAAB/8AAAP/wAAAf/4AAA//AAAH//wAAD/8AAA///AAAP/wAAH//+AAA//AAA///4AAD/8AAP///gAAP/wAB///+AAA//AAP///4AAD/8AB////gAAP/wAP///+AAA//AD//wD4AAD/8Af/4ADAAAP/wD/8AAAAAA//Af/AAAAAAD/8D/wAAAAAAP/wf8AAAAAAA//H/gAAAAAAD/8/4AAAAAAAP/3+AAAAAAAA///gAAAAAAAD//8AAAAAAAAP//AAAAAAAAA//wAAAAAAAAD/8AAAAAAAAAP/gAAAAAAAAA/4AAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAH8AA//wAAAAB/8AH//wAAAAf/8A///AAAAD//4H//+AAAAf//g///8AAAD///D///wAAAP//8f///gAAB///5///+AAAH///n///8AAAf///////wAAD////////AAAP///////8AAA////////4AAD////////gAAP////gAB+AAB+AAP4AAB4AAHgAAfAAADgAAeAAA8AAAOAABwAADwAAA4AAHAAAPAAADgAAcAAA8AAAOAAB4AADwAAA4AAH4AAfgAAHgAAP////gAB+AAA////////4AAD////////gAAP///////8AAA////////wAAD////////AAAH///n///8AAAf//+f///gAAA///5///+AAAD///D///4AAAH//4P///AAAAP//gf//4AAAAf/4A///AAAAA//AB//4AAAAAfgAD//AAAAAAAAAD/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAAAAAAAf/8AA+AAAAAH//8AP+AAAAA///4B/8AAAAH///4P/4AAAA////h//wAAAH////H//gAAA////+f/+AAAD////5//4AAAf////3//wAAB/////f//AAAH////9//8AAA/////z/j4AAD/////H+HgAAP////8PgOAAA/gAAfwAA4AADwAAAPAADgAAeAAAA8AAOAAB4AAABwAA4AAHAAAAHAADgAAcAAAA4AAeAABwAAADgAD4AAHgAAAeAAfgAAeAAADwAH8AAA+AAA+AH/wAAD////////AAAP///////4AAA////////gAAD///////8AAAH///////wAAAf//////+AAAA///////4AAAD///////AAAAH//////4AAAAP//////AAAAAf/////wAAAAA/////8AAAAAA/////gAAAAAA////wAAAAAAAf//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAfgAAAAAB/wAD/gAAAAAP/gAf/AAAAAB/+AD/8AAAAAH/8AP/4AAAAAf/wA//gAAAAD//AD/+AAAAAP/8AP/4AAAAAf/wA//gAAAAB/+AD/+AAAAAH/4AP/wAAAAAP/AAf+AAAAAAf4AA/wAAAAAAIAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="); - var scale = 1; // size multiplier for this font - this.size = 70+(scale<<8)+(1<<16); - this.y_offset = -15 - */ - // font size 90 - /*this.dimension_map = { - 1 : [50,70], - 2 : [50,70], - 3 : [50,70], - 4 : [50,70], - 5 : [50,70], - 6 : [54,70], - 7 : [54,70], - 8 : [54,70], - 9 : [54,70], - 10: [87,70], - 11: [87,70], - 12: [87,70] - }; - - this.widths = atob("GCA8JjI0NjE3Ljc3GA=="); - this.font = atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAD/gAAAAAAAAAAAAH/4AAAAAAAAAAAAP/8AAAAAAAAAAAAf/8AAAAAAAAAAAAf/+AAAAAAAAAAAAf/+AAAAAAAAAAAA//+AAAAAAAAAAAA//+AAAAAAAAAAAA//+AAAAAAAAAAAA//+AAAAAAAAAAAAf/+AAAAAAAAAAAAf/+AAAAAAAAAAAAf/8AAAAAAAAAAAAP/4AAAAAAAAAAAAH/4AAAAAAAAAAAAD/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAA/AAAAAAAAAAAAAH/AAAAAAAAAAAAA//AAAAAAAAAAAAH//AAAAAAAAAAAA//8AAAAAAAAAAAH//gAAAAAAAAAAA//8AAAAAAAAAAAH//gAAAAAAAAAAA//8AAAAAAAAAAAH//gAAAAAAAAAAA//8AAAAAAAAAAAH//gAAAAAAAAAAA//8AAAAAAAAAAAH//AAAAAAAAAAAA//4AAAAAAAAAAAH//AAAAAAAAAAAA//4AAAAAAAAAAAH//AAAAAAAAAAAA//4AAAAAAAAAAAH//AAAAAAAAAAAA//4AAAAAAAAAAAH//AAAAAAAAAAAA//4AAAAAAAAAAAD//AAAAAAAAAAAAD/4AAAAAAAAAAAAD/AAAAAAAAAAAAAD4AAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH///AAAAAAAAAAB////8AAAAAAAAAP/////gAAAAAAAA//////4AAAAAAAD//////+AAAAAAAH///////gAAAAAAP///////wAAAAAAf///////4AAAAAA////////8AAAAAB////////+AAAAAD/////////AAAAAH/////////gAAAAH/////////wAAAAP/////////wAAAAP/////////4AAAAf/////////4AAAAf/////////4AAAAf/////////8AAAA//////////8AAAA///gAAAAf/8AAAA/wAAAAAAAH+AAAA+AAAAAAAAB+AAAB8AAAAAAAAAeAAAB4AAAAAAAAAeAAAB4AAAAAAAAAOAAAB4AAAAAAAAAOAAABwAAAAAAAAAOAAABwAAAAAAAAAOAAABwAAAAAAAAAOAAAB4AAAAAAAAAOAAAB4AAAAAAAAAeAAAB4AAAAAAAAAeAAAB8AAAAAAAAA+AAAA+AAAAAAAAB+AAAA/4AAAAAAAP8AAAA////AAB///8AAAA//////////8AAAAf/////////8AAAAf/////////4AAAAf/////////4AAAAP/////////wAAAAP/////////wAAAAH/////////gAAAAH/////////gAAAAD/////////AAAAAB////////+AAAAAA////////8AAAAAAf///////8AAAAAAP///////wAAAAAAH///////gAAAAAAB///////AAAAAAAAf/////8AAAAAAAAH/////gAAAAAAAAA////8AAAAAAAAAAB///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAOAAAAAAAAAcAAAAOAAAAAAAAAcAAAAeAAAAAAAAAcAAAAeAAAAAAAAAcAAAAcAAAAAAAAAcAAAAcAAAAAAAAAcAAAAcAAAAAAAAAcAAAAcAAAAAAAAAcAAAAcAAAAAAAAAcAAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAB//////////8AAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/AAAAAB/8AAAAAf/wAAAAD/8AAAAB//4AAAAH/8AAAAD//4AAAAP/8AAAAH//8AAAAf/8AAAAH//8AAAA//8AAAAP//8AAAB//8AAAAP//8AAAD//8AAAAf//8AAAH//8AAAAf//8AAAP//8AAAA///8AAAf//8AAAA///8AAA///8AAAA///4AAB/f/8AAAA+D/4AAD+f/8AAAA8D/wAAH8f/8AAAB4D/gAAP8f/8AAAB4AOAAAf4f/8AAABwAAAAA/wf/8AAABwAAAAB/wf/8AAABwAAAAD/gf/8AAABwAAAAP/Af/8AAAB4AAAAf+Af/8AAAB4AAAB/+Af/8AAAB8AAAH/8Af/8AAAB+AAAf/4Af/8AAAB/gAH//wAf/8AAAB//////wAf/8AAAA//////gAf/8AAAA//////AAf/8AAAA/////+AAf/8AAAA/////+AAf/8AAAA/////8AAf/8AAAAf////4AAf/8AAAAf////wAAf/8AAAAP////gAAf/8AAAAP////gAA//8AAAAH////AAA//8AAAAH///+AAB//8AAAAD///4AAD//8AAAAB///wAAH//8AAAAA///gAAf//8AAAAAf/+AAD///8AAAAAD/4AAP///8AAAAAAAAAAP///8AAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAD8AAAAD/4AAAAAAP/gAAAP/+AAAAAA//wAAAf//AAAAAB//4AAAf//gAAAAD//8AAA///gAAAAH//8AAA///wAAAAH//8AAA///4AAAAP//8AAA///4AAAAf//8AAA///4AAAAf//8AAA///8AAAAf//8AAA///8AAAA///8AAA///8AAAA///8BwAf/j+AAAA///4BwAf/A+AAAA+D/4BwAP/AeAAAA4D/wBwAD/AeAAAB4D/gBwAAAAOAAABwAAADwAAAAOAAABwAAADwAAAAOAAABwAAADwAAAAOAAABwAAAHgAAAAOAAAB4AAAHwAAAAOAAAB4AAAP4AAAAeAAAB+AAA/4AAAAeAAAB/wAD/+AAAA+AAAB//////AAAB+AAAB//////wAAP+AAAB///////gH/+AAAB//////////8AAAA////9/////8AAAA////9/////8AAAA////8/////8AAAA////4/////4AAAAf///4/////4AAAAf///4/////4AAAAf///wf////wAAAAP///gf////wAAAAP///gP////gAAAAH///AP////gAAAAD//+AH////AAAAAB//8AD///+AAAAAAf/4AD///8AAAAAAH/AAB///4AAAAAAAAAAA///wAAAAAAAAAAAP//AAAAAAAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAfAAAAAAAAAAAAAB/AAAAAAAAAAAAAH/AAAAAAAAAAAAAf/AAAAAAAAAAAAB/nAAAAAAAAAAAAD+HAAAAAAAAAAAAP8HAAAAAAAAAAAA/wHAAAAAAAAAAAD/AHAAAAAAAAAAAH8AHAAAAAAAAAAAf4AHAAAAAAAAAAB/gAHAAAAAAAAAAH+AAHAAAAAAAAAAf4AAHAAAAAAAAAA/gAAHAAAAAAAAAD/AAAHAAcAAAAAAP8AAAHAAcAAAAAA/wAAAHAAcAAAAAD/AAAAHAAcAAAAAH+AAAAHAAcAAAAAf4AAAAHAAcAAAAB/gAAAAHAAcAAAAH+AAAAAHAAcAAAAP/////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAA//////////8AAAAAAAAAAAHAAcAAAAAAAAAAAHAAcAAAAAAAAAAAHAAcAAAAAAAAAAAHAAcAAAAAAAAAAAHAAcAAAAAAAAAAAHAAcAAAAAAAAAAAHAAAAAAAAAAAAAAHAAAAAAAAAAAAAf//gAAAAAAAAAAAf//gAAAAAAAAAAAf//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/gAAAAAAAAAAAAH/8AAAAAAAAAAAAP/+AAAAAAAAAAAAf//AAAAAAAAAAAAf//gAAAAf////gA///wAAAA/////wA///wAAAA/////wA///4AAAA///4HgA///4AAAA//AAHgA///4AAAA//AAPAA///8AAAAf/gAPAA///8AAAAf/gAOAA///+AAAAf/gAeAAf/g+AAAAf/wAeAAP/geAAAAf/wAcAAH/geAAAAf/wAcAAD+AOAAAAf/wAcAAAAAOAAAAf/4AcAAAAAOAAAAf/4AcAAAAAOAAAAP/4A8AAAAAOAAAAP/4A8AAAAAOAAAAP/8A+AAAAAeAAAAP/8AfAAAAA+AAAAP/8AfgAAAB+AAAAP/8Af8AAAf+AAAAP/+Af/////+AAAAP/+Af/////8AAAAP/+Af/////8AAAAP/+Af/////8AAAAH//Af/////8AAAAH//AP/////4AAAAH//AP/////4AAAAH//AP/////4AAAAH//AH/////wAAAAH//AH/////wAAAAH//AH/////gAAAAH//AD/////AAAAAP/+AB/////AAAAA//8AA////+AAAAB//gAA////8AAAAB/wAAAP///4AAAAAAAAAAH///gAAAAAAAAAAB//+AAAAAAAAAAAAf/4AAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//wAAAAAAAAAAD////gAAAAAAAAAf////4AAAAAAAAD//////AAAAAAAAP//////gAAAAAAA///////4AAAAAAB///////8AAAAAAH///////+AAAAAAP////////AAAAAAf////////gAAAAA/////////gAAAAB/////////wAAAAD/////////wAAAAD/////////4AAAAH/////////4AAAAP/////////8AAAAP/////////8AAAAf/////////8AAAAf/////////8AAAAf//wD/gAA/+AAAA//gAH4AAAD+AAAA/8AAPgAAAA+AAAA/wAAPAAAAAeAAAA/AAAeAAAAAOAAAA+AAAcAAAAAOAAAB8AAA8AAAAAOAAAB4AAA4AAAAAOAAAB4AAB4AAAAAOAAAB4AAB8AAAAAeAAABwAAB8AAAAAeAAABwAAB+AAAAA+AAABwAAB/AAAAD+AAABwAMB/+AAD/+AAAB4D/h//////8AAAB4D/x//////8AAAB8D/5//////8AAAA///5//////8AAAA///8//////4AAAA///8//////4AAAA///8//////wAAAAf//8//////wAAAAf//8f/////gAAAAP//8f/////gAAAAP//8P/////AAAAAH//8P////+AAAAAD//4H////8AAAAAB//wD////4AAAAAA//gB////wAAAAAAP/AA////gAAAAAAAQAAP//+AAAAAAAAAAAB//wAAAAAAAAAAAAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf///AAAAAAAAAAA////AAAAAAAAAAA///+AAAAAAAAAAA///gAAAAAAAAAAA///AAAAAAAAAAAA//+AAAAAAAAAAAA//8AAAAAAAAAAAA//8AAAAAP/AAAAA//4AAAAA//gAAAA//4AAAAD//wAAAA//4AAAAP//4AAAA//4AAAAf//8AAAA//4AAAA///8AAAA//4AAAD///+AAAA//4AAAH///+AAAA//4AAAP///+AAAA//4AAA////+AAAA//4AAB////+AAAA//4AAD////+AAAA//4AAH////+AAAA//4AAP////+AAAA//4AA/////+AAAA//4AB///gD+AAAA//4AD//8AAeAAAA//4AH//gAAAAAAA//4AP/+AAAAAAAA//4Af/4AAAAAAAA//4A//gAAAAAAAA//4D/+AAAAAAAAA//4H/4AAAAAAAAA//4P/gAAAAAAAAA//4f+AAAAAAAAAA//4/8AAAAAAAAAA//5/wAAAAAAAAAA////AAAAAAAAAAA///8AAAAAAAAAAA///4AAAAAAAAAAA///gAAAAAAAAAAA//+AAAAAAAAAAAA//4AAAAAAAAAAAA//wAAAAAAAAAAAA//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+AAAAAAAAPAAAH//wAAAAAAD/8AAP//4AAAAAAP//AA///+AAAAAA///gB///+AAAAAB///wB////AAAAAD///4D////gAAAAD///8H////wAAAAH///8H////wAAAAP///+P////4AAAAP///+P////4AAAAf////P////4AAAAf////f////8AAAAf////f////8AAAA/////f////8AAAA//////////8AAAA//////////+AAAA//////////+AAAA///////8f/+AAAB//////gAAH+AAAB/4AB/+AAAA+AAAB+AAAH8AAAAeAAAB8AAAD4AAAAeAAAB4AAAD4AAAAOAAAB4AAAB4AAAAOAAABwAAABwAAAAOAAAB4AAAB4AAAAOAAAB4AAAB4AAAAOAAAB4AAAD4AAAAOAAAB8AAAH8AAAAeAAAB/gAAP8AAAA+AAAB//////AAAD+AAAA//////+AA/+AAAA//////////+AAAA//////////+AAAA//////////8AAAA/////f////8AAAAf////f////8AAAAf////f////8AAAAf////P////4AAAAP///+P////4AAAAP///+H////4AAAAH///8H////wAAAAH///4H////wAAAAD///4D////gAAAAB///wB////gAAAAA///gA////AAAAAAf//AAf//+AAAAAAH/8AAP//4AAAAAAA/AAAH//wAAAAAAAAAAAB/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAAAAP/+AAAAAAAAAAAB///gAAfgAAAAAAH///4AD/4AAAAAAP///8AH/+AAAAAA/////AP//AAAAAA/////gf//gAAAAB/////gf//gAAAAD/////w///wAAAAH/////4///wAAAAH/////4///4AAAAP/////8///4AAAAP/////8///8AAAAf/////8///8AAAAf/////+f//8AAAAf/////+f/z8AAAA//////+P/g+AAAA//////+H/geAAAA//////+D/AeAAAA//gAH/+AAAOAAAB/gAAAD+AAAOAAAB+AAAAA+AAAOAAAB8AAAAA+AAAOAAAB4AAAAAeAAAOAAAB4AAAAAeAAAOAAABwAAAAAcAAAeAAABwAAAAAcAAAeAAABwAAAAA8AAA+AAAB4AAAAA4AAB+AAAB4AAAAB4AAH+AAAB8AAAAHwAAf8AAAB+AAAAPgAD/8AAAA/4AAD/AD//8AAAA//////////4AAAA//////////4AAAA//////////4AAAAf/////////wAAAAf/////////wAAAAf/////////gAAAAP/////////AAAAAP/////////AAAAAH////////+AAAAAH////////8AAAAAD////////4AAAAAB////////wAAAAAA////////AAAAAAAf//////+AAAAAAAH//////4AAAAAAAD//////gAAAAAAAAf////8AAAAAAAAAH////gAAAAAAAAAAP//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAMAAAAAAAAB/gAAD/gAAAAAAAH/4AAH/4AAAAAAAP/8AAP/8AAAAAAAP/8AAf/8AAAAAAAf/+AAf/+AAAAAAAf/+AAf/+AAAAAAAf/+AA//+AAAAAAAf/+AA//+AAAAAAAf/+AA//+AAAAAAAf/+AA//+AAAAAAAf/+AAf/+AAAAAAAf/+AAf/+AAAAAAAP/8AAf/8AAAAAAAP/8AAP/4AAAAAAAH/4AAH/4AAAAAAAD/gAAD/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="); - var scale = 1; // size multiplier for this font - this.size=90+(scale<<8)+(1<<16); - this.y_offset = -20 - */ } getDimensions(hour){ diff --git a/apps/fontclock/fontclock.font.mntn25.js b/apps/fontclock/fontclock.font.mntn25.js index e7abac8bf..2aaeb4c9e 100644 --- a/apps/fontclock/fontclock.font.mntn25.js +++ b/apps/fontclock/fontclock.font.mntn25.js @@ -11,22 +11,6 @@ class DigitNumeralFont extends NumeralFont{ super(); // dimension map provides the dimensions of the character for // each number for plotting and collision detection - - /*this.dimension_map = { - 0 : [25,25], - 1 : [10,25], - 2 : [15,25], - 3 : [15,25], - 4 : [15,25], - 5 : [15,25], - 6 : [20,25], - 7 : [15,25], - 8 : [20,25], - 9 : [20,25], - 10 : [31,25], - 11 : [20,25], - 12: [25,25] - };*/ this.widths = atob("BgsVCw8PEBEUEBQUBw=="); this.font = atob("AAAAAAAAAAAAp9bgAAAAAAAAAAAADr+vAAAAAAAAAAAAAOv68AAAAAAAAAAAAA6/rwAAAAAAAAAAAADr+fAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAXwAAAAAAAAAAAAXz//wAAAAAAAAAXz//7q+AAAAAAAXz//8q+//wAAAAXz//8q+//yr3wAXz//8q+//yr3//ZAL/8q+//yr3//ZMAAAW+//2q3//ZQAAAAAC/2q3//pQAAAAAAAAF3//pQAAAAAAAAAAAnpQAAAAAAAAAAAAAAAAABL3//tgQAAAAAAAAj//su9//0gAAAAAC7/vv///73/gAAAAB/8/9u7u7/+34AAAA78/r/////c/+9QAAf9/P/LvLu/+///AADu/++//+7/7Pv79QAv37+/sQAAb/7978AF/f3vwAAAAD+/v+4Aj9779QAAAADs+/vwCP3vv1AAAAAOz7+/AF/P3fsAAAAC+/v94AL9+/v5AAAD/9/f/QAP3+/8/9ze/7+/v2AAj9+//Lztu+/P//AAAP/f3P////6//fcAAAL/z/y7u7vv7PoAAAAD/+z////9z/oAAAAAAK//3LvO/+QAAAAAAAAH3///6zAAAAAAAAAAAAAAAAAAAAAAC96fQAAAAAAAAAAAAL769AAAAAAAAAAAAAvvr5ZmZmZmZmZmAAC++v//////////8AAL76/bu7u7u7u7uwAAvvr/7u7u7u7u7uAAC++v/u7u7u7u7u4AAL76/KqqqqqqqqqgAAvvr///////////AAAjQlVVVVVVVVVVUAAAAAAAAAAAAAAAAAAAhTAAAAAAAAAyUlAAD7+udQAAAAHfv68AAPv777AAAAX/+/rwAC+/y/kAAAn+77+vAAb8/q9gAB79//v68ACf7frzAF/9/t+/rwAH/d+/QK/u/P/7+vAAX8/t/u/f/P7Pv68AAvv7+uzv3vz/+/rwAA/P3///z/v/Pr+vAACPv9u67939EOv68AAA/6///7/3AA6/rwAAAv/Ku+/iAADr+fAAAACu//5gAAAAAAAAAAAAAAAAAAAAAAAAAAhTAAAAAAAAAAIrIAD7+udgAAAAGo379gAPr7/rAAAAAfv935AB+vvvcjMkFQ/Pv+sAT6/d9K/r+vDs+/3QB/zvvzr+v68Nz7+/AJ/d+/Ov6/rx3Pv78Ab779+I/N/PX8+/zwAvv8/P/5/v7/z7/+AA+/z+m/r7/Kv9/PkACvv7///8+//7398gAB/9/bvvzvy8/89wAABv++/93+nf/b+gAAAALv/e/9//3v+wAAAAAASd21AVrcogAAAAAAAAAAAb753JAAAAAAAAAALP/frusAAAAAAAAE3/zO+u6wAAAAAABe/7z/367rAAAAAAf/+9/7vvrusAAAAG/+rv+s/9+u6wAAAAra//rf+5367rAAAABv/q7/q//vrusAAAAK2v/5z/w1+u6wAAAAb/6d/7IAX67rAAAACsr/+AL//vru//4AAG/+YAAaqr+u7aqgAAnUAAAD///67v//AAAAAAAABVWPruxVUAAAAAAAAAACtphgAAAAAAAAAAAAAAAAAAAAA0U3d3d3d1AADMAAAL76//////0ACr9AAAvvr9zMzMyABd/vAAC++v7u7u7qAPz79QAL76//////wPz975AAvvr8rN7Oyw+vv+wAC++vQN37/ODs+/vgAL769A6/v9wN37+/AAvvr0Dq+/3Q/Pv78AC++vQN38/vv8+/3QAL769Ar8397+7/36AAvvr0Bfv8/s/7/PMAC++vQA77+9/a+fwAAL769ABP3f///f8gAAVnSRAAb/mrzP8wAAAAAAAAAC3///wQAAAAAAAAAAAAJiAAAAAAAAAAA2ZmZiAAAAAAAAAK7//////+YAAAAAA//Lu7u7up77AAAABP+//+7u7v/5/QAAAP7fyN///+y/+/cAAH+/n/2qqqvv7vzwAA/f3+r/////v8+/cAD7+/v82rye38/e6wBPv9zrn9388fv7/NAI/O+va+/Pzw3Pv68Aj93689z7/dDc+vrwBPv+v06/z90Pz7++AA+/3vnO/Pz+/PvuwAD7+/o4/O/56/38+QAN/v5QP8/f//7PzxAAP89QAL+f3czfj6AAAK9wAAH/v///z/EAAADQAAAC79q879EAAAAAAAAAAJ3//YAAAAAAAAAAAAAAAAAAAAAL3p9AAAAAAAAAAAAAvvr0AAAAAAAAAAAAC++vQAAAAAAAAAAAAL769AAAAAAAAFrgAAvvr0AAAAAFrv/9AAC++vQAAFvv/9u98AAL769Wvv/8u9//6gAArN7//8u+//67z/AACv/8u+//27z//roAAFu+//273//rvP/wAAv/273//rvP//xxAABb3//rvP//xxAAAAAL/rvP//thAAAAAAAAXP/+thAAAAAAAAAACutgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGt/qYCvv2kAAAAAAb/69/+/+vP/AAAAAT+z//q/8//6/8QAAP8/7u9/P+7z/v7AADv36//+/v///778gAfv7/Lr/7++3/vz6AG+/7+/9+/v//Pz+0Aj8789d77+/Ds+/zwCf3Pryvuv68N36+vAJ/c+vK+6/rwzfr68An9z68r7r+vDN+vrwCPzvz1v+z78ez6+/AE+/7//fzv3+/Pv98AD7+/ne+/v57e/e/QAO7v3//9/u/v+vr2AAT9/7u9+v68uvz/AAAM/O////v///z/EAAACv+6vP/+u6z/IAAAAATP//1H3//7IAAAAAAAABAAAAEAAAAAAAAABJkwAAAAAAAAAAAAr///+gAAAAEQAAAB783dvP0QAADNAAAA37/93/n8AAC79QAAT5/c/9358wBt/vAADu/v+8/+79Afz79QAPn7+//Pv58Pv975AD+f7/zP3fjw+vv+wAf7789T+/6vTs+/vgCf3fvyP8/789z7+/AG+++/SP7Pvw+fr74AL5/e+837+/X3+v3AAPv7+//d3d797/35AA3+7/vMzMzK75+/MAA/r97//////r/fwAAAz5/7uqqqqt/d8gAAAe/N//////6v9gAAAACv/bqqqr3/4gAAAAAAOM/////aUAAAAAAAAAAAAAAAAAAAAAAAAAAQEQABARAAAAAAAABvvuoF+u6wAAAAAAAG++6gX67rAAAAAAAAb77qBfrusAAAAAAABvvuoF+u6wAAAAAAAE16pwPXunAAAAAAAAAAAAAAAAAAAA=="); var scale = 1; // size multiplier for this font diff --git a/apps/fontclock/fontclock.font.mntn50.js b/apps/fontclock/fontclock.font.mntn50.js index 43b8aeb9b..650c0b1af 100644 --- a/apps/fontclock/fontclock.font.mntn50.js +++ b/apps/fontclock/fontclock.font.mntn50.js @@ -6,15 +6,6 @@ const DIM_37x47 = [37,47]; class DigitNumeralFont extends NumeralFont{ constructor(){ super(); - // dimension map provides the dimensions of the character for - // each number for plotting and collision detection - - /*this.dimension_map = { - 3 : [30,47], - 6 : [37,47], - 9 : [37,47], - 12: [49,47] - };*/ this.widths = atob("DRYqFR0fHyMnICgnDQ=="); this.font = atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAChkoAAAAAAAAAAAAAvP7wAAAAAAAAAAAAC8/vAAAAAAAAAAAAALz+8AAAAAAAAAAAAAvP7wAAAAAAAAAAAAC8/vAAAAAAAAAAAAALz+8AAAAAAAAAAAAAvP7wAAAAAAAAAAAAC8/vAAAAAAAAAAAAALz+8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAH/AAAAAAAAAAAAAB//8AAAAAAAAAAAAf///gAAAAAAAAAAH///5LAAAAAAAAAB///+S/8AAAAAAAAf///kv//wAAAAAAH///5L///4AAAAAB///+S///+G8AAAAf///kv///hv/wAAH///5L///4b///AAP//+S///+G///5AAA//kv///hv//+QAAAD5L///4b///kAAAAAC///+G///5AAAAAAA///hv//+QAAAAAAAD/4b///kAAAAAAAAAKG///5AAAAAAAAAAAv//+QAAAAAAAAAAAD//kAAAAAAAAAAAAAP5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAAAAAAAAAAC////4AAAAAAAAAAL//////gAAAAAAAAP//6Vr//8AAAAAAAH/9Gv/pH/9AAAAAAD/4v////4v/AAAAAA/8///////P/AAAAAP9v/4BUC//n/AAAAD/f/m///+b/3/AAAAv3/n/////2/3+AAAH9/3//+r//9/39AAA/v9/+G/+S/9/78AAD9/f+f///9v9/fwAAvf3/f/////f9/fgAD9/vz/4AAv/P78/AAf/39/0AAAH/f3/9AC9/f78AAAAD+/f34ALz+9/QAAAAH9+/PgA/Pvz8AAAAAPz+8/AD99/PgAAAAAvP338AP739+AAAAAC9/ffwA/ff34AAAAAL399/AD8+/PwAAAAA/P7z8APz/9/AAAAAD9//PgAvf37/AAAAA//39+AB+/Pz/AAAAP8/P70AD9/v3/wAAP/f79/AAP39/3/////3/f38AAf79/2////5/3+/QAA/f9/9r//p/9/78AAB/f9//5Rb//f9/QAAD/f9v/////n/f8AAAD/f/b////n/3/AAAAD/f/4WqlL/9/wAAAAH/X//////9f9AAAAAH/1/////9f/QAAAAAC/+H///0v/gAAAAAAB//+QAb//0AAAAAAAAf//////0AAAAAAAAAB/////QAAAAAAAAAAAAa6QAAAAAAAAAAAAAAAAAAAAAAAAClopAAAAAAAAAAAAAPvz4AAAAAAAAAAAAA+/PgAAAAAAAAAAAAD78+AAAAAAAAAAAAAPvz4AAAAAAAAAAAAA+/PgAAAAAAAAAAAAD78///////////wAAPvz///////////AAA+/P6qqqqqqqqqoAAD78///////////gAAPvz///////////AAA+/P//////////8AAD78+AAAAAAAAAAAAAPvz///////////AAA+/P//////////8AAD78/qqqqqqqqqqgAAPvz//////////+AAA+/P//////////8AAD68///////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAAAAAAAAA/PQAAAAAAAG8+vAAD9+/ZAAAAAC/z+8AAP/3+9AAAAA//P7wAB+/PvwAAAAf/8/vAAL3+9/AAAAL/bz+8AA/P/z8AAAD/r/P7wAD9+/PgAAB/7/8/vAAP379+AAAv+//z+8AA/vf30AAP+/9vP7wAD+9/vQAH/v+v8/vAAP7399AD/7/f/z+8AA/fv30A/7/3//P7wAD9+/Pgv+/7/28/vAALz+9/v/v9/9/z+8AAvP3+//v/v+v/P7wAB+/f3/7/v/f/8/vAAD+/v4H/3/3/bz+8AAP39///7/2/0vP7wAAf79v/9/9/8C8/vAAA/f9G5/+v+ALz+8AAC/f/7//f/QAvP7wAAD/P///r/wAC8/vAAAH/n//n/0AALz+8AAAH/5Ab/8AAAvP7wAAAH////9AAAB8tfAAAAC///9AAAAAAAAAAAAAK/kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyQAAAAAAAAABj4AA/P7gAAAAAAAu/PwAD9+/fQAAAAH3+9/AAP73+8AAAAAfv378AB+/PvwAAAAA//P70AL3+9/AAAAAD+9/fgA/P7z8KWiloPz78+AD8+/Pg/vP7wvP/z8APz78+D+8/vC8/vPwA/fv34P7z+8L3+8/AD99/fQ/vP7wvf738AP3399D+8/vB9/ffwA/ff30P7z+8H3+9/AD9+/fg/vf30vP738APz/8/D9+/Pj8+/PwA/P77//z/9//778+AC+/f3//f3+/9/f74AD+/v3/+/v6/f7+/AAPz9/5b9/f+b/fz8AAv79////+v//3+/gAA/f9///3/f/9/38AAC/f+RR/3/Rlv9/gAAD/f////3////f8AAAD/b////3///3/AAAAH/2//X/5//n/0AAAAD/+lr///lb/8AAAAAC////9////+AAAAAAAv//9Af//+AAAAAAAABaQAAAaQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7z58AAAAAAAAAAAB//P7wAAAAAAAAAAC//8/vAAAAAAAAAAC//rz+8AAAAAAAAAD//X/P7wAAAAAAAAH//X/8/vAAAAAAAAH//b//z+8AAAAAAAH//L/+vP7wAAAAAAL/+P/9f8/vAAAAAAL/+f/9f/z+8AAAAAL/9f/8v//P7wAAAAD/9f/4v/68/vAAAAAP9v/4//4vz+8AAAAA8v/5//0v/P7wAAAAAv/1//1//8/vAAAAAP/1//x///z+8AAAAA/y//i//wvP7wAAAADi//i//gC8/vAAAAAD//X//gALz+8AAAAA//X//QAAvP7wAAAAD/L//Af//8/vv/gAAOL/+AC///z+///AAAP/+AAH///P7//8AAD/9AAAAAC8/vAAAAAP9AAAB///z+///AAA4AAAAL///P7//8AAAAAAAAKqr8/vaqgAAAAAAAAAALz+8AAAAAAAAAAAAAvPrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAAA8AAAD14//////0AAL8AAAPvz//////gACf8AAA+/P/////+AAvfwAAD78+AAAAAAAD/vwAAPvz//////gA39/AAA+/P/////+AP3++AAD78/qqqqqgA/fz8AAPvz//////Qt/vvwAA+/P/////+D78/vQAD78//////4P739+AAPvz4A9ufPQ/Pvz8AA+/PgH3+9+C8+vPwAD78+Avf/z0L3+9/AAPvz4C8//fAff338AA+/PgLz7+8B9/vfwAD78+AvPv7wL3+9/AAPvz4D8+/fg/P/z8AA+/PgLz+8/D9+/PwAD78+AvP77///39+AAPvz4B+/P3/9/v/wAA+/PgD9+/3/f39/AAD78+AP38/0L/f78AAPvz4Av79///39/QAA+/PgA/f8//9//8AAD78+AB/f9L5f9/QAAPvz4AD/f/6//f8AAA+/PgAD/P///3/AAAD289AAH/j//y/wAAAAAAAAAH/9AH/8AAAAAAAAAAD////+AAAAAAAAAAAB///+AAAAAAAAAAAAAGvpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa////6QAAAAAAAAB///////+AAAAAAAB/////////gAAAAAA//kAAAABv/0AAAAAP/X//////n/0AAAAD/b///////6/0AAAA/3//6qqqv/9/wAAAL9/9a////kv9/wAAB/P+v//////P9/QAAP6/f///////P+/AAA/P3/5AAAAf/fz8AAP3+/2/////3/v74AA/f79//////79/fwAD/+/f/6qqr/3++/AAvf39/Pz799//3+9AD8/vfw/vf/w/fv38APz/8/D/9+/D8+/PwA/fvz4ff734L3/9/AD99/fS8//fQff738AP3399Lz799B9/ffwA/ff30vPv7wH3+9/AD9+/Pj8+/vQvP7z8APz68+Lz79+D8+/PwA/P338vP7z8f779+AB+/f/x+/f//+/f70AD+9/fD+9/f/7/+/AAP3+/QP3+/b2/f38AA/fz8Av/3///7//gAB/v3QA/f3///v38AAD9/gAC/v2//b+/gAAH9+AAD+/+AL/r8AAAP+wAAH+v///6/QAAAP0AAAP/f//9/4AAAAfQAAAP/lvlv+AAAAAkAAAAL//r//QAAAAAAAAAAD////wAAAAAAAAAAAAv//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPrz4AAAAAAAAAAAAA+/PgAAAAAAAAAAAAD78+AAAAAAAAAAAAAPvz4AAAAAAAAAAAAA+/PgAAAAAAAAAAAAD78+AAAAAAAAAAAAAPvz4AAAAAAAAAGAAA+/PgAAAAAAAB/8AAD78+AAAAAAAv//wAAPvz4AAAAAL///4AAA+/PgAAAC///+G8AAD78+AAAv///hv/wAAPvz4AL///4b///AAA+/Pm///+G///9EAAD79////Rv//+R/wAAPr///0f///kv//AAA///9H///5L///4AAD//R///+S///+GwAAPkf///kv///hv/AAAL///5L///4b//8AAD//+W///+G///9AAAP/hv///Rv//+QAAAAob///0f///kAAAAAC///9H///5AAAAAAAP//R///+QAAAAAAAA/kf///kAAAAAAAAAAL///5AAAAAAAAAAAP//+QAAAAAAAAAAAA//kAAAAAAAAAAAAAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//0AL//9AAAAAAAf///+L////QAAAAAP/+r////r//wAAAAD/0v5f/4r6b/wAAAA/6///n////1/wAAAP9////3////9/gAAC/f/gG/3/kB/9/AAAP7/b/9/3//+f+/AAC/f3//9/v///f79AAP39/+/9/f///f38AA/v/9uf+/v/n+/vwAL79/f/v38//38/vQA/P77//f7z///78/AD8//Pz9/vfw/Prz8AP379+H79+/D8/vfwA/vf30Pvz68L399/AD+9/fQ+/Prwff378AP7399D78+vB9/fvwA/vf30Pvz68H39+/AD+9/fQ+/Prwff378AP7399D78+vB9/fvwA/vf30Pvz+8H39+/AD9+/fg/vP7wvf338APz/8/D+8/vT8/vfwA/P77/v339//378/AC9/f7//P77/+/f34AH++/r/9/f3/r9/vQAP39/0H++v4D/f38AA/v+///39///+/fwAA/f9///39//+v39AAD/v9b5/v+b+P+/wAAD/f/6//v/6//r8AAAH/f////7///2/gAAAL/X//3/3//5/4AAAAH/5FC//9BB/+AAAAAH//////////QAAAAAB////A////QAAAAAAAK/5AAG/5QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//QAAAAAAAAAAAAv///4AAAAAAAAAAAf////9AAAABQAAAAH/0aR/9AAAAPQAAAB/2//+v9AAAC/AAAAf9////f8AAA3/AAAD/f/Qf/f4AAL38AAAv3/P/n/fwAAv78AAD+/r//3/fwAd/fwAAv7+///7+/AD9/vgAD9/f8pv3+/Af39/AAP7//v//v38Lf778AB+/f3/9/f/w//P70AL3++/r+9/vT99/fgA/P7z8Pz79+Pz78/AD9+/Pgvf/z4vPrz8AP3799B9/vPi9/vfwA/vf30D7+8+H399/AD9+/fQff/z4ff338AP3799C8+/fS8/vfwA/P7z4P73+8Pz/8/AD8/vfw//fvw/fvz8AL39//n3+8/P79/fgAP/39/6VVVv/f7/8AA/f7+//////3+/fwAD+/f9/////9/79/AAH9/f+FVVVRv9/P0AAP3+f///////f9/AAAf3/f//////7/P0AAA/3/W////+j/3/AAAA/7/+lVVVr/9/wAAAB/3///////+f9AAAAB/9//////+L/QAAAAB//QVVVVQv/wAAAAAA/////////4AAAAAAAf///////4AAAAAAAABv////+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB89fAHz18AAAAAAAAPz78AvP7wAAAAAAAA/PvwC8/vAAAAAAAAD8+/ALz+8AAAAAAAAPz78AvP7wAAAAAAAA/PvwC8/vAAAAAAAAD8+/ALz+8AAAAAAAAPz78AvP7wAAAAAAAA/PvwC8/vAAAAAAAAC8+vALz68AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="); var scale = 1; // size multiplier for this font @@ -31,7 +22,6 @@ class DigitNumeralFont extends NumeralFont{ default: return DIM_37x47; } - //return this.dimension_map[hour]; } hour_txt(hour){ return hour.toString(); } draw(hour_txt,x,y){ diff --git a/apps/fontclock/fontclock.font.vector25.js b/apps/fontclock/fontclock.font.vector25.js index 0c66b1d07..95b23d040 100644 --- a/apps/fontclock/fontclock.font.vector25.js +++ b/apps/fontclock/fontclock.font.vector25.js @@ -5,22 +5,6 @@ const DIM_27x22 = [27,22]; class DigitNumeralFont extends NumeralFont{ constructor(){ super(); - // dimension map provides the dimesions of the character for - // each number for plotting and collision detection - /*this.dimension_map = { - 1 : [14,22], - 2 : [14,22], - 3 : [14,22], - 4 : [14,22], - 5 : [14,22], - 6 : [14,22], - 7 : [14,22], - 8 : [14,22], - 9 : [14,22], - 10: [27,22], - 11: [27,22], - 12: [27,22] - };*/ } getDimensions(hour){ if (hour < 10){ diff --git a/apps/fontclock/fontclock.font.vector50.js b/apps/fontclock/fontclock.font.vector50.js index 85466958f..2b83b0911 100644 --- a/apps/fontclock/fontclock.font.vector50.js +++ b/apps/fontclock/fontclock.font.vector50.js @@ -6,8 +6,6 @@ const DIM_54x44 = [54,44]; class DigitNumeralFont extends NumeralFont{ constructor(){ super(); - // dimension map provides the dimesions of the character for - // each number for plotting and collision detection } getDimensions(hour){ if (hour < 10){ @@ -39,4 +37,56 @@ class DigitNumeralFont extends NumeralFont{ getName(){return "Digit";} } -module.exports = [DigitNumeralFont]; \ No newline at end of file +const DIM_50x40 = [50,40]; +const DIM_70x40 = [70,40]; +class RomanNumeralFont extends NumeralFont{ + constructor(){ + super(); + } + getText(hour){ + switch (hour){ + case 1 : return 'I'; + case 2 : return 'II'; + case 3 : return 'III'; + case 4 : return 'IV'; + case 5 : return 'V'; + case 6 : return 'VI'; + case 7 : return 'VII'; + case 8 : return 'VIII'; + case 9 : return 'IX'; + case 10: return 'X'; + case 11: return 'XI'; + case 12: return 'XII'; + default: return ''; + } + } + getDimensions(hour){ + switch (hour){ + case 3: + case 6: + case 9: + return DIM_50x40; + case 12: + return DIM_70x40; + default: + return DIM_70x40; + } + } + hour_txt(hour){ return this.getText(hour); } + draw(hour_txt,x,y){ + /*var dim = DIM_70x40; + g.setColor(0.5,0,0); + g.fillPoly([x,y, + x+dim[0],y, + x+dim[0],y+dim[1], + x,y+dim[1] + ]);*/ + g.setColor(1.0,1.0,1.0); + g.setFontAlign(-1,-1,0); + g.setFont("Vector",50); + g.drawString(hour_txt,x,y); + } + getName(){return "Roman";} +} + +module.exports = [DigitNumeralFont,RomanNumeralFont]; \ No newline at end of file diff --git a/apps/fontclock/fontclock.js b/apps/fontclock/fontclock.js index d453f6b9a..840e42c5a 100644 --- a/apps/fontclock/fontclock.js +++ b/apps/fontclock/fontclock.js @@ -28,23 +28,26 @@ var color_schemes = [ var fonts = DEFAULT_NUMERALS; var numerals = DEFAULT_NUMERALS; var radius = DEFAULT_RADIUS; -try{ - var fonts_info = require("Storage").readJSON(FONTS_FILE); - if(fonts_info != null){ - console.log("loaded font:" + JSON.stringify(fonts_info)); - fonts = fonts_info.fonts; - numerals = fonts_info.numerals; - radius = fonts_info.radius; - color_schemes = fonts_info.color_schemes; - } else { - fonts = DEFAULT_FONTS; - numerals = DEFAULT_NUMERALS; - radius = DEFAULT_RADIUS; - console.log("no fonts loaded defaulting to:" + fonts); - } + +var fonts_info = null; +try { + fonts_info = require("Storage").readJSON(FONTS_FILE); } catch(e){ - console.log("failed to load fonts:" + e); + console.log("failed to load fonts file:" + FONTS_FILE + e); } +if(fonts_info != null){ + console.log("loaded font:" + JSON.stringify(fonts_info)); + fonts = fonts_info.fonts; + numerals = fonts_info.numerals; + radius = fonts_info.radius; + color_schemes = fonts_info.color_schemes; +} else { + fonts = DEFAULT_FONTS; + numerals = DEFAULT_NUMERALS; + radius = DEFAULT_RADIUS; + console.log("no fonts loaded defaulting to:" + fonts); +} + if(fonts == null || fonts.length == 0){ fonts = DEFAULT_FONTS; console.log("defaulting fonts to locale:" + fonts); From 1fc24b9fe76a843420c7db2a67624f38004f2297 Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Sun, 23 May 2021 23:03:38 +0100 Subject: [PATCH 0027/2129] font clock bug fix: Transition on vecotor 4 clock between roman numerals and digits not clearing --- apps/fontclock/fontclock.font.vector50.js | 1 - apps/fontclock/fontclock.hourscriber.js | 2 +- apps/fontclock/fontclock.js | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/fontclock/fontclock.font.vector50.js b/apps/fontclock/fontclock.font.vector50.js index 2b83b0911..ccc4599fd 100644 --- a/apps/fontclock/fontclock.font.vector50.js +++ b/apps/fontclock/fontclock.font.vector50.js @@ -81,7 +81,6 @@ class RomanNumeralFont extends NumeralFont{ x+dim[0],y+dim[1], x,y+dim[1] ]);*/ - g.setColor(1.0,1.0,1.0); g.setFontAlign(-1,-1,0); g.setFont("Vector",50); g.drawString(hour_txt,x,y); diff --git a/apps/fontclock/fontclock.hourscriber.js b/apps/fontclock/fontclock.hourscriber.js index 38f960da3..eaddbab4e 100644 --- a/apps/fontclock/fontclock.hourscriber.js +++ b/apps/fontclock/fontclock.hourscriber.js @@ -71,7 +71,7 @@ class HourScriber { this.curr_numeral_font.draw(this.curr_hour_str, this.curr_hour_x, this.curr_hour_y); - //console.log("erasing old hour"); + //console.log("erasing old hour display:" + this.curr_hour_str + " color:" + background); var hours_frac = this.hours / 12; var angle = TWO_PI*hours_frac; var dimensions = this.numeral_font.getDimensions(this.hours); diff --git a/apps/fontclock/fontclock.js b/apps/fontclock/fontclock.js index 840e42c5a..bd6ba16b7 100644 --- a/apps/fontclock/fontclock.js +++ b/apps/fontclock/fontclock.js @@ -219,6 +219,7 @@ function next_font() { } if (curr_font != numeral_fonts_index) { + console.log("numeral font changed") for (var i = 0; i < hour_scribers.length; i++) { hour_scribers[i].setNumeralFont( numeral_fonts[numeral_fonts_index]); From c146cfb6cb6a009cd4f8310c1c94874816e2852c Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Mon, 24 May 2021 16:30:49 +0200 Subject: [PATCH 0028/2129] multiclock - Added localisation to digi.js and timedat.js - using the locale module for language-specific time and date formats - in timdat.js, a special date format consisting of day of week, month and day of month is used that is not available as a date pattern. Hence, it's built in place. - in timedat.js, some unused variables have been removed and lastmin now uses the number returned by the Date object directly --- apps.json | 2 +- apps/multiclock/ChangeLog | 1 + apps/multiclock/digi.js | 4 +++- apps/multiclock/timdat.js | 23 ++++++++++++++++------- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/apps.json b/apps.json index d088885ef..408737e79 100644 --- a/apps.json +++ b/apps.json @@ -2260,7 +2260,7 @@ { "id": "multiclock", "name": "Multi Clock", "icon": "multiclock.png", - "version":"0.12", + "version":"0.13", "description": "Clock with multiple faces - Big, Analogue, Digital, Text, Time-Date.\n Switch between faces with BTN1 & BTN3", "readme": "README.md", "tags": "clock", diff --git a/apps/multiclock/ChangeLog b/apps/multiclock/ChangeLog index c02e390b2..2f27f7f28 100644 --- a/apps/multiclock/ChangeLog +++ b/apps/multiclock/ChangeLog @@ -10,3 +10,4 @@ 0.10: Added GPS and Grid Ref clock faces 0.11: Updated Pedometer clock to retrieve steps from either wpedom or activepedom 0.12: Removed GPS and Grid Ref clock faces, superceded by GPS setup and Walkers Clock +0.13: Localised digi.js and timdat.js \ No newline at end of file diff --git a/apps/multiclock/digi.js b/apps/multiclock/digi.js index 4422e6b62..0b2ca4aaa 100644 --- a/apps/multiclock/digi.js +++ b/apps/multiclock/digi.js @@ -1,5 +1,7 @@ (() => { +var locale = require("locale"); + function getFace(){ var buf = Graphics.createArrayBuffer(240,92,1,{msb:true}); @@ -19,7 +21,7 @@ function getFace(){ buf.drawString(time,buf.getWidth()/2,0); buf.setFont("6x8",2); buf.setFontAlign(0,-1); - var date = d.toString().substr(0,15); + var date = locale.dow(d, 1) + " " + locale.date(d, 1); buf.drawString(date, buf.getWidth()/2, 70); flip(); } diff --git a/apps/multiclock/timdat.js b/apps/multiclock/timdat.js index ff1bdf000..a4a93a691 100644 --- a/apps/multiclock/timdat.js +++ b/apps/multiclock/timdat.js @@ -1,16 +1,16 @@ (() => { + var locale = require("locale"); + var dayFirst = ["en_GB", "en_IN", "en_NAV", "de_DE", "nl_NL", "fr_FR", "en_NZ", "en_AU", "de_AT", "en_IL", "es_ES", "fr_BE", "de_CH", "fr_CH", "it_CH", "it_IT", "tr_TR", "pt_BR", "cs_CZ", "pt_PT"]; + var withDot = ["de_DE", "nl_NL", "de_AT", "de_CH", "hu_HU", "cs_CZ", "sl_SI"]; + function getFace(){ var lastmin=-1; function drawClock(){ var d=Date(); if (d.getMinutes()==lastmin) return; - d=d.toString().split(' '); - var min=d[4].substr(3,2); - var sec=d[4].substr(-2); - var tm=d[4].substring(0,5); - var hr=d[4].substr(0,2); - lastmin=min; + var tm=d.toString().split(' ')[4].substring(0,5); + lastmin=d.getMinutes(); g.reset(); g.clearRect(0,24,239,239); var w=g.getWidth(); @@ -19,7 +19,16 @@ g.drawString(tm,4+(w-g.stringWidth(tm))/2,64); g.setFontVector(36); g.setColor(0x07ff); - var dt=d[0]+" "+d[1]+" "+d[2];//+" "+d[3]; + var dt=locale.dow(d, 1) + " "; + if (dayFirst.includes(locale.name)) { + dt+=d.getDate(); + if (withDot.includes(locale.name)) { + dt+="."; + } + dt+=" " + locale.month(d, 1); + } else { + dt+=locale.month(d, 1) + " " + d.getDate(); + } g.drawString(dt,(w-g.stringWidth(dt))/2,160); g.flip(); } From d4c1c63e158f6874a6b6a733583ac25728646dba Mon Sep 17 00:00:00 2001 From: adrian w kirk Date: Mon, 24 May 2021 19:51:13 +0100 Subject: [PATCH 0029/2129] sliding text clock: turning emulator option off. Emulator will not work because the clock is split into languages classes. Turning off the emulator otherwise people will think it doesn't work --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index d088885ef..80dc1e2b1 100644 --- a/apps.json +++ b/apps.json @@ -249,7 +249,7 @@ "description": "Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Currently English, French, Japanese, Spanish and German are supported", "tags": "clock", "type":"clock", - "allow_emulator":true, + "allow_emulator":false, "readme": "README.md", "custom":"custom.html", "storage": [ @@ -3220,4 +3220,4 @@ {"name":"doztime.img","url":"app-icon.js","evaluate":true} ] } -] \ No newline at end of file +] From 35daeafe17fd774031d8f2cd096fb3b03671ccf7 Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Tue, 25 May 2021 21:15:20 +0200 Subject: [PATCH 0030/2129] cliock - using locale for internationalization --- apps/cliock/app.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/apps/cliock/app.js b/apps/cliock/app.js index ca48bb26f..d9541f545 100644 --- a/apps/cliock/app.js +++ b/apps/cliock/app.js @@ -2,7 +2,6 @@ var fontsize = 3; var locale = require("locale"); var marginTop = 40; var flag = false; -var WeekDays = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]; var hrtOn = false; var hrtStr = "Hrt: ??? bpm"; @@ -26,19 +25,14 @@ function drawAll(){ } function updateRest(now){ - let date = locale.date(now,false); - writeLine(WeekDays[now.getDay()],1); - writeLine(date,2); + writeLine(locale.dow(now),1); + writeLine(locale.date(now,1),2); drawInfo(5); } function updateTime(){ if (!Bangle.isLCDOn()) return; let now = new Date(); - let h = now.getHours(); - let m = now.getMinutes(); - h = h>=10?h:"0"+h; - m = m>=10?m:"0"+m; - writeLine(h+":"+m,0); + writeLine(locale.time(now,1),0); writeLine(flag?" ":"_",3); flag = !flag; if(now.getMinutes() == 0) From 03d580160d57c56a598ca09062ddd9b7bda04950 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 26 May 2021 08:28:34 +0100 Subject: [PATCH 0031/2129] bump version --- apps.json | 2 +- apps/cliock/ChangeLog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 99ae7b96d..dbfc51d49 100644 --- a/apps.json +++ b/apps.json @@ -1260,7 +1260,7 @@ "name": "Commandline-Clock", "shortName":"CLI-Clock", "icon": "app.png", - "version":"0.11", + "version":"0.12", "description": "Simple CLI-Styled Clock", "tags": "clock,cli,command,bash,shell", "type":"clock", diff --git a/apps/cliock/ChangeLog b/apps/cliock/ChangeLog index 07b38e189..53616638b 100644 --- a/apps/cliock/ChangeLog +++ b/apps/cliock/ChangeLog @@ -3,3 +3,4 @@ 0.09: Add BTN1 status line with ID,Fw ver, mem %, battery % 0.10: Icon fixed for transparency 0.11: added Heart Rate Monitor status and ability to turn on/off +0.12: added support for different locales From 1dca641ff0b4a94a888994fa137262df694c4ff5 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 26 May 2021 16:21:52 +0100 Subject: [PATCH 0032/2129] boot 0.23: Move to a precalculated .boot0 file which should speed up load time setting 0.25: Move boot.js code into 'boot' app itself launch 0.05: Use g.theme for colours widbat 0.06: Use 'g.theme' (requires bootloader 0.23) widlock: new widget --- apps.json | 25 ++++++++--- apps/boot/ChangeLog | 1 + apps/boot/boot0.js | 70 +---------------------------- apps/boot/bootupdate.js | 95 ++++++++++++++++++++++++++++++++++++++++ apps/launch/ChangeLog | 1 + apps/launch/app.js | 27 ++++++------ apps/setting/ChangeLog | 1 + apps/setting/boot.js | 15 ------- apps/widbat/ChangeLog | 1 + apps/widbat/widget.js | 4 +- apps/widlock/ChangeLog | 1 + apps/widlock/widget.js | 10 +++++ apps/widlock/widget.png | Bin 0 -> 728 bytes 13 files changed, 146 insertions(+), 105 deletions(-) create mode 100644 apps/boot/bootupdate.js delete mode 100644 apps/setting/boot.js create mode 100644 apps/widlock/ChangeLog create mode 100644 apps/widlock/widget.js create mode 100644 apps/widlock/widget.png diff --git a/apps.json b/apps.json index dbfc51d49..a0a819ca5 100644 --- a/apps.json +++ b/apps.json @@ -4,11 +4,12 @@ "tags": "tool,system", "type":"bootloader", "icon": "bootloader.png", - "version":"0.22", + "version":"0.23", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "storage": [ {"name":".boot0","url":"boot0.js"}, - {"name":".bootcde","url":"bootloader.js"} + {"name":".bootcde","url":"bootloader.js"}, + {"name":"bootupdate.js","url":"bootupdate.js"} ], "sortorder" : -10 }, @@ -41,7 +42,7 @@ "name": "Launcher (Default)", "shortName":"Launcher", "icon": "app.png", - "version":"0.04", + "version":"0.05", "description": "This is needed by Bangle.js to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", "tags": "tool,system,launcher", "type":"launch", @@ -171,13 +172,12 @@ { "id": "setting", "name": "Settings", "icon": "settings.png", - "version":"0.24", + "version":"0.25", "description": "A menu for setting up Bangle.js", "tags": "tool,system", "readme": "README.md", "storage": [ {"name":"setting.app.js","url":"settings.js"}, - {"name":"setting.boot.js","url":"boot.js"}, {"name":"setting.img","url":"settings-icon.js","evaluate":true} ], "data": [ @@ -571,7 +571,7 @@ { "id": "widbat", "name": "Battery Level Widget", "icon": "widget.png", - "version":"0.05", + "version":"0.06", "description": "Show the current battery level and charging status in the top right of the clock", "tags": "widget,battery", "type":"widget", @@ -579,6 +579,17 @@ {"name":"widbat.wid.js","url":"widget.js"} ] }, + { "id": "widlock", + "name": "Lock Widget", + "icon": "widget.png", + "version":"0.01", + "description": "On devices with always-on display (Bangle.js 2) this displays lock icon whenever the display is locked", + "tags": "widget,lock", + "type":"widget", + "storage": [ + {"name":"widlock.wid.js","url":"widget.js"} + ] + }, { "id": "widbatpc", "name": "Battery Level Widget (with percentage)", "shortName": "Battery Widget", @@ -3123,7 +3134,7 @@ {"name":"gps.kit.js","url":"gps.kit.js"}, {"name":"digi.kit.js","url":"digi.kit.js"}, {"name":"heart.kit.js","url":"heart.kit.js"}, - {"name":"swatch.kit.js","url":"swatch.kit.js"}, + {"name":"swatch.kit.js","url":"swatch.kit.js"}, {"name":"compass.kit.js","url":"compass.kit.js"}, {"name":"kitchen.img","url":"kitchen.icon.js","evaluate":true} ], diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 7e9fd4a81..adfdb2709 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -21,3 +21,4 @@ 0.20: Allow Gadgetbridge to work even with programmable:off 0.21: Handle echo off char from Gadgetbridge app when programmable:off (fix #558) 0.22: Stop LCD timeout being disabled on first run (when there is no settings.json) +0.23: Move to a precalculated .boot0 file which should speed up load time diff --git a/apps/boot/boot0.js b/apps/boot/boot0.js index 550513b11..3e567d9b8 100644 --- a/apps/boot/boot0.js +++ b/apps/boot/boot0.js @@ -1,68 +1,2 @@ -// This ALWAYS runs at boot -E.setFlags({pretokenise:1}); -// Load settings... -var s = require('Storage').readJSON('setting.json',1)||{}; -if (s.ble!==false) { - if (s.HID) { // Human interface device - if (s.HID=="joy") Bangle.HID = E.toUint8Array(atob("BQEJBKEBCQGhAAUJGQEpBRUAJQGVBXUBgQKVA3UBgQMFAQkwCTEVgSV/dQiVAoECwMA=")); - else if (s.HID=="kb") Bangle.HID = E.toUint8Array(atob("BQEJBqEBBQcZ4CnnFQAlAXUBlQiBApUBdQiBAZUFdQEFCBkBKQWRApUBdQORAZUGdQgVACVzBQcZAClzgQAJBRUAJv8AdQiVArECwA==")); - else /*kbmedia*/Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA==")); - NRF.setServices({}, {uart:true, hid:Bangle.HID}); - } -} -if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth - if (s.log) Terminal.setConsole(true); // if showing debug, force REPL onto terminal - else E.setConsole(null,{force:true}); // on new (2v05+) firmware we have E.setConsole which allows a 'null' console - /* If not programmable add our own handler for Bluetooth data - to allow Gadgetbridge commands to be received*/ - Bluetooth.line=""; - Bluetooth.on('data',function(d) { - var l = (Bluetooth.line + d).split("\n"); - Bluetooth.line = l.pop(); - l.forEach(n=>Bluetooth.emit("line",n)); - }); - Bluetooth.on('line',function(l) { - if (l.startsWith('\x10')) l=l.slice(1); - if (l.startsWith('GB({') && l.endsWith('})') && global.GB) - try { global.GB(JSON.parse(l.slice(3,-1))); } catch(e) {} - }); -} else { - if (s.log && !NRF.getSecurityStatus().connected) Terminal.setConsole(); // if showing debug, put REPL on terminal (until connection) - else Bluetooth.setConsole(true); // else if no debug, force REPL to Bluetooth -} -// we just reset, so BLE should be on. -// Don't disconnect if something is already connected to us -if (s.ble===false && !NRF.getSecurityStatus().connected) NRF.sleep(); -// Set time, vibrate, beep, etc -if (!Bangle.F_BEEPSET) { - if (!s.vibrate) Bangle.buzz=Promise.resolve; - if (s.beep===false) Bangle.beep=Promise.resolve; - else if (s.beep=="vib") Bangle.beep = function (time, freq) { - return new Promise(function(resolve) { - if ((0|freq)<=0) freq=4000; - if ((0|time)<=0) time=200; - if (time>5000) time=5000; - analogWrite(D13,0.1,{freq:freq}); - setTimeout(function() { - digitalWrite(D13,0); - resolve(); - }, time); - }); - }; -} -if (s.timeout!==undefined) Bangle.setLCDTimeout(s.timeout); -if (!s.timeout) Bangle.setLCDPower(1); -E.setTimeZone(s.timezone); -delete s; -// Draw out of memory errors onto the screen -E.on('errorFlag', function(errorFlags) { - g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip(); - print("Interpreter error:", errorFlags); - E.getErrorFlags(); // clear flags so we get called next time -}); -// stop users doing bad things! -global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); } -// Load *.boot.js files -require('Storage').list(/\.boot\.js/).forEach(bootFile=>{ - eval(require('Storage').read(bootFile)); -}); +// Initially this runs and rewrites itself +eval(require('Storage').read('bootupdate.js')); diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js new file mode 100644 index 000000000..4f380b948 --- /dev/null +++ b/apps/boot/bootupdate.js @@ -0,0 +1,95 @@ +/* This rewrites boot0.js based on current settings. If settings changed then it +recalculates, but this avoids us doing a whole bunch of reconfiguration most +of the time. */ +E.showMessage("Updating boot0..."); +var s = require('Storage').readJSON('setting.json',1)||{}; +var boot = ""; +var CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/)); +boot += `if (E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))!=${CRC}) { eval(require('Storage').read('bootupdate.js'));} else {\n`; +boot += `E.setFlags({pretokenise:1});\n`; +if (s.ble!==false) { + if (s.HID) { // Human interface device + if (s.HID=="joy") boot += `Bangle.HID = E.toUint8Array(atob("BQEJBKEBCQGhAAUJGQEpBRUAJQGVBXUBgQKVA3UBgQMFAQkwCTEVgSV/dQiVAoECwMA="));`; + else if (s.HID=="kb") boot += `Bangle.HID = E.toUint8Array(atob("BQEJBqEBBQcZ4CnnFQAlAXUBlQiBApUBdQiBAZUFdQEFCBkBKQWRApUBdQORAZUGdQgVACVzBQcZAClzgQAJBRUAJv8AdQiVArECwA=="));` + else /*kbmedia*/boot += `Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA=="));`; + boot += `NRF.setServices({}, {uart:true, hid:Bangle.HID});\n`; + } +} +if (s.blerepl===false) { // If not programmable, force terminal off Bluetooth + if (s.log) boot += `Terminal.setConsole(true);\n`; // if showing debug, force REPL onto terminal + else boot += `E.setConsole(null,{force:true});\n`; // on new (2v05+) firmware we have E.setConsole which allows a 'null' console + /* If not programmable add our own handler for Bluetooth data + to allow Gadgetbridge commands to be received*/ + boot += ` +Bluetooth.line=""; +Bluetooth.on('data',function(d) { + var l = (Bluetooth.line + d).split("\n"); + Bluetooth.line = l.pop(); + l.forEach(n=>Bluetooth.emit("line",n)); +}); +Bluetooth.on('line',function(l) { + if (l.startsWith('\x10')) l=l.slice(1); + if (l.startsWith('GB({') && l.endsWith('})') && global.GB) + try { global.GB(JSON.parse(l.slice(3,-1))); } catch(e) {} +});\n`; +} else { + if (s.log) boot += `if (!NRF.getSecurityStatus().connected) Terminal.setConsole();\n`; // if showing debug, put REPL on terminal (until connection) + else boot += `Bluetooth.setConsole(true);\n`; // else if no debug, force REPL to Bluetooth +} +// we just reset, so BLE should be on. +// Don't disconnect if something is already connected to us +if (s.ble===false) boot += `if (!NRF.getSecurityStatus().connected) NRF.sleep();\n`; +// Set time +if (s.timeout!==undefined) boot += `Bangle.setLCDTimeout(${s.timeout});\n`; +if (!s.timeout) boot += `Bangle.setLCDPower(1);\n`; +boot += `E.setTimeZone(${s.timezone});`; +// Set vibrate, beep, etc IF on older firmwares +if (!Bangle.F_BEEPSET) { + if (!s.vibrate) boot += `Bangle.buzz=Promise.resolve;\n` + if (s.beep===false) boot += `Bangle.beep=Promise.resolve;\n` + else if (s.beep=="vib") boot += `Bangle.beep = function (time, freq) { + return new Promise(function(resolve) { + if ((0|freq)<=0) freq=4000; + if ((0|time)<=0) time=200; + if (time>5000) time=5000; + analogWrite(D13,0.1,{freq:freq}); + setTimeout(function() { + digitalWrite(D13,0); + resolve(); + }, time); + }); + };\n`; +} +// Draw out of memory errors onto the screen +boot += `E.on('errorFlag', function(errorFlags) { + g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip(); + print("Interpreter error:", errorFlags); + E.getErrorFlags(); // clear flags so we get called next time +});\n`; +// stop users doing bad things! +if (global.save) boot += `global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); }\n`; +// Apply any settings-specific stuff +if (s.options) boot+=`Bangle.setOptions(${E.toJS(s.options)});\n`; +if (s.quiet && s.qmOptions) boot+=`Bangle.setOptions(${E.toJS(s.qmOptions)});\n`; +if (s.quiet && s.qmBrightness) { + if (s.qmBrightness!=1) boot+=`Bangle.setLCDBrightness(${s.qmBrightness});\n`; +} else { + if (s.brightness && s.brightness!=1) boot+=`Bangle.setLCDBrightness(${s.brightness});\n`; +} +if (s.quiet && s.qmTimeout) boot+=`Bangle.setLCDTimeout(${s.qmTimeout});\n`; +if (s.passkey!==undefined && s.passkey.length==6) boot+=`NRF.setSecurity({passkey:${s.passkey}, mitm:1, display:1});\n`; +if (s.whitelist) boot+=`NRF.on('connect', function(addr) { if (!(require('Storage').readJSON('setting.json',1)||{}).whitelist.includes(addr)) NRF.disconnect(); });\n`; +// Pre-2v10 firmwares without a theme +if (!g.theme) { + boot += `g.theme={fg:-1,bg:0,fg2:-1,bg2:7,fgH:-1,bgH:0x02F7};\n`; +} +// Append *.boot.js files +require('Storage').list(/\.boot\.js/).forEach(bootFile=>{ + boot += "//"+bootFile+"\n"+require('Storage').read(bootFile)+"\n"; +}); +boot += "}\n";// initial 'if' +var s = require('Storage').write('.boot0',boot); +delete boot; +E.showMessage("Reloading..."); +eval(require('Storage').read('.boot0')); +eval(require('Storage').read('.bootcde')); diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog index 7e7ea65ab..8be4ef463 100644 --- a/apps/launch/ChangeLog +++ b/apps/launch/ChangeLog @@ -2,3 +2,4 @@ 0.02: Only store relevant app data (saves RAM when many apps) 0.03: Allow scrolling to wrap around (fix #382) 0.04: Now displays widgets +0.05: Use g.theme for colours diff --git a/apps/launch/app.js b/apps/launch/app.js index 9795d8901..0d9d0b004 100644 --- a/apps/launch/app.js +++ b/apps/launch/app.js @@ -12,35 +12,36 @@ var menuScroll = 0; var menuShowing = false; function drawMenu() { - g.setFont("6x8",2); - g.setFontAlign(-1,0); - var n = 3; + g.reset().setFont("6x8",2).setFontAlign(-1,0); + var w = g.getWidth(); + var h = g.getHeight(); + var m = w/2; + var n = (h-48)/64; if (selected>=n+menuScroll) menuScroll = 1+selected-n; if (selectedn+menuScroll) ? -1 : 0); - g.fillPoly([120,233,106,219,134,219]); + g.setColor(menuScroll ? g.theme.fg : g.theme.bg); + g.fillPoly([m,6,m-14,20,m+14,20]); + g.setColor((apps.length>n+menuScroll) ? g.theme.fg : g.theme.bg); + g.fillPoly([m,h-7,m-14,h-21,m+14,h-21]); // draw - g.setColor(-1); + g.setColor(g.theme.fg); for (var i=0;i { - var settings = require('Storage').readJSON('setting.json', true); - if (!settings) return; - if (settings.options) Bangle.setOptions(settings.options); - if (settings.quiet && settings.qmOptions) Bangle.setOptions(settings.qmOptions); - if (settings.quiet && settings.qmBrightness) { - if (settings.qmBrightness!=1) Bangle.setLCDBrightness(settings.qmBrightness); - } else { - if (settings.brightness && settings.brightness!=1) Bangle.setLCDBrightness(settings.brightness); - } - if (settings.quiet && settings.qmTimeout) Bangle.setLCDTimeout(s.qmTimeout); - if (settings.passkey!==undefined && settings.passkey.length==6) NRF.setSecurity({passkey:settings.passkey, mitm:1, display:1}); - if (settings.whitelist) NRF.on('connect', function(addr) { if (!settings.whitelist.includes(addr)) NRF.disconnect(); }); - delete settings; -})() diff --git a/apps/widbat/ChangeLog b/apps/widbat/ChangeLog index b9d50ab8b..128cee034 100644 --- a/apps/widbat/ChangeLog +++ b/apps/widbat/ChangeLog @@ -2,3 +2,4 @@ 0.03: Tweaks for variable size widget system 0.04: Ensure redrawing works with variable size widget system 0.05: Fix regression stopping correct widget updates +0.06: Use 'g.theme' (requires bootloader 0.23) diff --git a/apps/widbat/widget.js b/apps/widbat/widget.js index bca3ae046..95fad1b20 100644 --- a/apps/widbat/widget.js +++ b/apps/widbat/widget.js @@ -7,16 +7,16 @@ function draw() { var s = 39; var x = this.x, y = this.y; + g.reset(); if (Bangle.isCharging()) { g.setColor(CHARGING).drawImage(atob("DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y); x+=16; } - g.setColor(-1); + g.setColor(g.theme.fg); g.fillRect(x,y+2,x+s-4,y+21); g.clearRect(x+2,y+4,x+s-6,y+19); g.fillRect(x+s-3,y+10,x+s,y+14); g.setColor(CHARGING).fillRect(x+4,y+6,x+4+E.getBattery()*(s-12)/100,y+17); - g.setColor(-1); } Bangle.on('charging',function(charging) { if(charging) Bangle.buzz(); diff --git a/apps/widlock/ChangeLog b/apps/widlock/ChangeLog new file mode 100644 index 000000000..b4d1ae593 --- /dev/null +++ b/apps/widlock/ChangeLog @@ -0,0 +1 @@ +0.01: First commit diff --git a/apps/widlock/widget.js b/apps/widlock/widget.js new file mode 100644 index 000000000..b710de8c6 --- /dev/null +++ b/apps/widlock/widget.js @@ -0,0 +1,10 @@ +(function(){ + Bangle.on('lcdPower', function(on) { + WIDGETS["lock"].width = Bangle.isLCDOn()?0:16; + Bangle.drawWidgets(); + }); + WIDGETS["lock"]={area:"tl",width:Bangle.isLCDOn()?0:16,draw:function(w) { + if (!Bangle.isLCDOn()) + g.reset().drawImage(atob("DhABH+D/wwMMDDAwwMf/v//4f+H/h/8//P/z///f/g=="), w.x, w.y); + }}; +})() diff --git a/apps/widlock/widget.png b/apps/widlock/widget.png new file mode 100644 index 0000000000000000000000000000000000000000..e0eaa4aa9e0aa3254375ef7002311617f8edb807 GIT binary patch literal 728 zcmV;}0w?{6P)6(HTO6)!8C-tm-i#F_&!ta<(zxI z-@J3)g$F4q|2Hbm!yLyMwQaj-jG0wRIlwtUfNvsF(OSQ$)oQDiO64%Fnz0#hUAL%| zdIU`Sgl>w+J&9_@StP+0C*}Q*DTA*T9%bH##{$hfM4x_BC_DR z?(HZVLeGHXIHS2-?i0s*zA7R&J`U%*!UF5j< zgI?kRN~O{V;1=e}UA%unBaL z$wMZ8kMIPT0nQ{Vi66jP!?2LK&!%6nuYsoc4Im$fx<1&oG#Au7)m}lqE!6zy2Q3~T ze`t8@7ZhX$W?~Q%3KgJs5Cci~d@pi-0Vn<~lo}W|sexf*C2^<#)f(*VAKjGsF_^Gp z{s`415d+m4eBb-KZvCFLO>ZPQdX#N0wleUq Date: Wed, 26 May 2021 20:21:28 +0100 Subject: [PATCH 0033/2129] Add 'Bangle.setUI' polyfill and use it from launcher --- apps.json | 4 ++-- apps/boot/ChangeLog | 1 + apps/boot/bootupdate.js | 40 +++++++++++++++++++++++++++++++++++++++- apps/launch/ChangeLog | 1 + apps/launch/app.js | 33 +++++++++++++++------------------ 5 files changed, 58 insertions(+), 21 deletions(-) diff --git a/apps.json b/apps.json index a0a819ca5..09477d72a 100644 --- a/apps.json +++ b/apps.json @@ -4,7 +4,7 @@ "tags": "tool,system", "type":"bootloader", "icon": "bootloader.png", - "version":"0.23", + "version":"0.24", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "storage": [ {"name":".boot0","url":"boot0.js"}, @@ -42,7 +42,7 @@ "name": "Launcher (Default)", "shortName":"Launcher", "icon": "app.png", - "version":"0.05", + "version":"0.06", "description": "This is needed by Bangle.js to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", "tags": "tool,system,launcher", "type":"launch", diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index adfdb2709..a176df670 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -22,3 +22,4 @@ 0.21: Handle echo off char from Gadgetbridge app when programmable:off (fix #558) 0.22: Stop LCD timeout being disabled on first run (when there is no settings.json) 0.23: Move to a precalculated .boot0 file which should speed up load time +0.24: Add Bangle.setUI polyfill diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index 4f380b948..9dc90cc9a 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -79,10 +79,48 @@ if (s.quiet && s.qmBrightness) { if (s.quiet && s.qmTimeout) boot+=`Bangle.setLCDTimeout(${s.qmTimeout});\n`; if (s.passkey!==undefined && s.passkey.length==6) boot+=`NRF.setSecurity({passkey:${s.passkey}, mitm:1, display:1});\n`; if (s.whitelist) boot+=`NRF.on('connect', function(addr) { if (!(require('Storage').readJSON('setting.json',1)||{}).whitelist.includes(addr)) NRF.disconnect(); });\n`; -// Pre-2v10 firmwares without a theme +// Pre-2v10 firmwares without a theme/setUI if (!g.theme) { boot += `g.theme={fg:-1,bg:0,fg2:-1,bg2:7,fgH:-1,bgH:0x02F7};\n`; } +if (!Bangle.setUI) { + boot += `Bangle.setUI=function(mode, cb) { +if (Bangle.btnWatches) { + Bangle.btnWatches.forEach(clearWatch); + delete Bangle.btnWatches; +} +if (Bangle.swipeHandler) { + Bangle.removeListener("swipe", Bangle.swipeHandler); + delete Bangle.swipeHandler; +} +if (Bangle.touchandler) { + Bangle.removeListener("touch", Bangle.touchHandler); + delete Bangle.touchHandler; +} +function b() { + try{Bangle.buzz(20);}catch(e){} +} +if (!mode) return; +else if (mode=="updown") { + Bangle.btnWatches = [ + setWatch(function() { b();cb(-1); }, BTN1, {repeat:1}), + setWatch(function() { b();cb(1); }, BTN3, {repeat:1}), + setWatch(function() { b();cb(); }, BTN2, {repeat:1}) + ]; +} else if (mode=="leftright") { + Bangle.btnWatches = [ + setWatch(function() { b();cb(-1); }, BTN1, {repeat:1}), + setWatch(function() { b();cb(1); }, BTN3, {repeat:1}), + setWatch(function() { b();cb(); }, BTN2, {repeat:1}) + ]; + Bangle.swipeHandler = d => {b();cb(d);}; + Bangle.on("swipe", Bangle.swipeHandler); + Bangle.touchHandler = d => {b();cb();}; + Bangle.on("touch", Bangle.touchHandler); +} else + throw new Error("Unknown UI mode"); +};\n`; +} // Append *.boot.js files require('Storage').list(/\.boot\.js/).forEach(bootFile=>{ boot += "//"+bootFile+"\n"+require('Storage').read(bootFile)+"\n"; diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog index 8be4ef463..b56c9f6bb 100644 --- a/apps/launch/ChangeLog +++ b/apps/launch/ChangeLog @@ -3,3 +3,4 @@ 0.03: Allow scrolling to wrap around (fix #382) 0.04: Now displays widgets 0.05: Use g.theme for colours +0.06: Use Bangle.setUI for buttons diff --git a/apps/launch/app.js b/apps/launch/app.js index 0d9d0b004..ab1a89fc0 100644 --- a/apps/launch/app.js +++ b/apps/launch/app.js @@ -43,25 +43,22 @@ function drawMenu() { } g.clear(); drawMenu(); -setWatch(function() { - selected--; - if (selected<0) selected = apps.length-1; - drawMenu(); -}, BTN1, {repeat:true}); -setWatch(function() { - selected++; - if (selected>=apps.length) selected = 0; - drawMenu(); -}, BTN3, {repeat:true}); -setWatch(function() { // run - if (!apps[selected].src) return; - if (require("Storage").read(apps[selected].src)===undefined) { - E.showMessage("App Source\nNot found"); - setTimeout(drawMenu, 2000); +Bangle.setUI("updown",dir=>{ + if (dir) { + selected += dir; + if (selected<0) selected = apps.length-1; + if (selected>=apps.length) selected = 0; + drawMenu(); } else { - E.showMessage("Loading..."); - load(apps[selected].src); + if (!apps[selected].src) return; + if (require("Storage").read(apps[selected].src)===undefined) { + E.showMessage("App Source\nNot found"); + setTimeout(drawMenu, 2000); + } else { + E.showMessage("Loading..."); + load(apps[selected].src); + } } -}, BTN2, {repeat:true,edge:"falling"}); +}); Bangle.loadWidgets(); Bangle.drawWidgets(); From 7f80cb1625cf28822999e89107371ec7e4b10240 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 26 May 2021 21:06:48 +0100 Subject: [PATCH 0034/2129] Added super simple clock Ensure pedometer uses system colour scheme --- apps.json | 15 ++++++++++++++- apps/s7clk/ChangeLog | 1 + apps/s7clk/app.js | 40 ++++++++++++++++++++++++++++++++++++++++ apps/s7clk/icon.js | 1 + apps/s7clk/icon.png | Bin 0 -> 279 bytes apps/widpedom/ChangeLog | 1 + apps/widpedom/widget.js | 14 ++++---------- 7 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 apps/s7clk/ChangeLog create mode 100644 apps/s7clk/app.js create mode 100644 apps/s7clk/icon.js create mode 100644 apps/s7clk/icon.png diff --git a/apps.json b/apps.json index 09477d72a..f1ef7849a 100644 --- a/apps.json +++ b/apps.json @@ -857,6 +857,19 @@ {"name":"sclock.img","url":"clock-simple-icon.js","evaluate":true} ] }, + { "id": "s7clk", + "name": "Simple 7 segment Clock", + "icon": "icon.png", + "version":"0.04", + "description": "A simple 7 segment Clock with date", + "tags": "clock", + "type":"clock", + "allow_emulator":true, + "storage": [ + {"name":"s7clk.app.js","url":"app.js"}, + {"name":"s7clk.img","url":"icon.js","evaluate":true} + ] + }, { "id": "vibrclock", "name": "Vibrate Clock", "icon": "app.png", @@ -1125,7 +1138,7 @@ { "id": "widpedom", "name": "Pedometer widget", "icon": "widget.png", - "version":"0.12", + "version":"0.13", "description": "Daily pedometer widget", "tags": "widget", "type":"widget", diff --git a/apps/s7clk/ChangeLog b/apps/s7clk/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/s7clk/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/s7clk/app.js b/apps/s7clk/app.js new file mode 100644 index 000000000..6973b8c16 --- /dev/null +++ b/apps/s7clk/app.js @@ -0,0 +1,40 @@ +require("Font7x11Numeric7Seg").add(Graphics); + +function draw() { + var d = new Date(); + var size = Math.floor(g.getWidth()/(7*6)); + var x = (g.getWidth()/2) - size*6, + y = (g.getHeight()/2) - size*7; + g.reset().clearRect(0,y,g.getWidth(),y+size*12+8); + g.setFont("7x11Numeric7Seg",size).setFontAlign(1,-1); + g.drawString(d.getHours(), x, y); + g.setFontAlign(-1,-1); + if (d.getSeconds()&1) g.drawString(":", x,y); + g.drawString(("0"+d.getMinutes()).substr(-2),x+size*4,y); + // draw seconds + g.setFont("7x11Numeric7Seg",size/2); + g.drawString(("0"+d.getSeconds()).substr(-2),x+size*18,y + size*7); + // date + var s = d.toString().split(" ").slice(0,4).join(" "); + g.reset().setFontAlign(0,-1); + g.drawString(s,g.getWidth()/2, y + size*12); +} + +// Only update when display turns on +Bangle.on('lcdPower', function(on) { + if (secondInterval) + clearInterval(secondInterval); + secondInterval = undefined; + if (on) + secondInterval = setInterval(draw, 1000); + draw(); +}); + +var secondInterval = setInterval(draw, 1000); +g.clear(); +draw(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// Show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); diff --git a/apps/s7clk/icon.js b/apps/s7clk/icon.js new file mode 100644 index 000000000..d5d9aaf68 --- /dev/null +++ b/apps/s7clk/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mUygP/AC5BlH4MAn/gAwN/4EP/AFBsEMhkBwEAjEDgYJBgEGgHA4EYDwOAmEwBIIYyj/wgf+AoMH/kA/4eBJXwYLVxgAjh//AC3w")) diff --git a/apps/s7clk/icon.png b/apps/s7clk/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cb08aec5e1b88cbd097bd451c072ec7c04d3bea9 GIT binary patch literal 279 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-wj^(N7l!{JxM1({$v}}ao-U3d z8I5nJU*u{w5OK~wzAvjZ-u~~px328fnZ=O@Zai~1*e;N-byXs<=jBG%BflSI>;69a zbmv@K25$Di 3){ stps = stps.slice(0,-3) + "," + stps.slice(-3); g.setFont("4x6", 1); // if big, shrink text to fix From 994ea1298b703985cff6aee223cfd47f00f922c1 Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 00:50:30 +0200 Subject: [PATCH 0035/2129] Create ChangeLog --- apps/gbtwist/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/gbtwist/ChangeLog diff --git a/apps/gbtwist/ChangeLog b/apps/gbtwist/ChangeLog new file mode 100644 index 000000000..e6a8d1263 --- /dev/null +++ b/apps/gbtwist/ChangeLog @@ -0,0 +1 @@ +Initial version From a10792af7fa5a8cc90a3548ae7dc41a16450e7ee Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 00:50:50 +0200 Subject: [PATCH 0036/2129] Add files via upload --- apps/gbtwist/app-icon.js | 1663 +++++++++++++++++++++++++++ apps/gbtwist/app.js | 2071 ++++++++++++++++++++++++++++++++++ apps/gbtwist/app.png | 1548 +++++++++++++++++++++++++ apps/gbtwist/screenshot1.jpg | 1611 ++++++++++++++++++++++++++ 4 files changed, 6893 insertions(+) create mode 100644 apps/gbtwist/app-icon.js create mode 100644 apps/gbtwist/app.js create mode 100644 apps/gbtwist/app.png create mode 100644 apps/gbtwist/screenshot1.jpg diff --git a/apps/gbtwist/app-icon.js b/apps/gbtwist/app-icon.js new file mode 100644 index 000000000..d460c76b4 --- /dev/null +++ b/apps/gbtwist/app-icon.js @@ -0,0 +1,1663 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BangleApps/app-icon.js at master · radsvvid/BangleApps + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +
+ + + + + +
+ + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + +
+ +
+ +
+

+ + + / + + BangleApps + + +

+ + + forked from espruino/BangleApps + + +
+ +
    + +
  • + +
    + + + + + + + + Watch + + + + + +
    +
    +

    Notifications

    + +
    + +
    +
    + + + + + + + + +
    + +
    +
    +
    + + +
    +
    + +
    + + + +
  • + +
  • +
    +
    + + +
    +
    + + +
    + +
  • + +
  • + + + Fork + + +
  • +
+ +
+ + + + +
+ + +
+
+ + + + +
+ + + + Permalink + + + +
+ +
+
+ + + master + + + + +
+
+
+ Switch branches/tags + +
+ + + +
+ +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+ +
+ + + + Go to file + + +
+ + + + + + + + + +
+
+
+ + + +
+ +
+
+
 
+
+ +
+
 
+ Cannot retrieve contributors at this time +
+
+ + + + + + + + + + + + + +
+ +
+ + +
+ + 1 lines (1 sloc) + + 283 Bytes +
+ +
+ + + +
+ + + + +
+ +
+
+ +
+
+ +
+ +
+
+ + + +
+ + + + + + +
require("heatshrink").decompress(atob("mEwwhC/AC3wCysP/4vW/4YWGAJJWGC4YBGCJ1EJKAQBAAZJFh4WPCgQwDGZIWHDAgXKCxAtDAgYuPGAgXIFJIGFC5w3EAwQXHIwoMDBIanJC56NNLARIHC543IC+jVGC454IC96P/C8D9HOxwXDEggXMh4QEC5JGHEAYlGC5wJBJArfFRhRZHFxYkBJIYqFFxYXCAQJJEUhoXCPQhcNAATQFEIwAOJIYAUIJgYjJOIvWAEw="))
+ + + +
+ +
+ + + + +
+ + +
+ + +
+
+ + + + +
+ + + +
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/gbtwist/app.js b/apps/gbtwist/app.js new file mode 100644 index 000000000..3e3e00c7e --- /dev/null +++ b/apps/gbtwist/app.js @@ -0,0 +1,2071 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BangleApps/app.js at master · radsvvid/BangleApps + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + +
+ +
+ +
+

+ + + / + + BangleApps + + +

+ + + forked from espruino/BangleApps + + +
+ +
    + +
  • + +
    + + + + + + + + Watch + + + + + +
    +
    +

    Notifications

    + +
    + +
    +
    + + + + + + + + +
    + +
    +
    +
    + + +
    +
    + +
    + + + +
  • + +
  • +
    +
    + + +
    +
    + + +
    + +
  • + +
  • + + + Fork + + +
  • +
+ +
+ + + + +
+ + +
+
+ + + + +
+ + + + Permalink + + + +
+ +
+
+ + + master + + + + +
+
+
+ Switch branches/tags + +
+ + + +
+ +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+ +
+ + + + Go to file + + +
+ + + + + + + + + +
+
+
+ + + +
+ +
+
+
 
+
+ +
+
 
+ Cannot retrieve contributors at this time +
+
+ + + + + + + + + + + + + +
+ +
+ + +
+ + 100 lines (88 sloc) + + 1.98 KB +
+ +
+ + + +
+ + + + +
+ +
+
+ +
+
+ +
+ +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
// just a watch, to fill an empty screen
+
function drwClock() {
var d = new Date();
var h = d.getHours(), m = d.getMinutes();
var time = ("0"+h).substr(-2) + ":" + ("0"+m).substr(-2);
g.reset();
g.setFont('6x8',7);
g.setFontAlign(-1,-1);
g.drawString(time,20,80);
}
+
g.clear();
drwClock();
Bangle.loadWidgets();
Bangle.drawWidgets();
+
/////////////////////////////////////////////////////////////
// control music by twist/buttons
+
var counter = 0; //stores your counted your twists
var tstate = false; //are you ready to count the twists?
+
function playx() {
Bluetooth.println(JSON.stringify({t:"music", n:"play"}));
}
+
function volup() {
Bluetooth.println(JSON.stringify({t:"music", n:"volumeup"}));
}
+
function voldn() {
Bluetooth.println(JSON.stringify({t:"music", n:"volumedown"}));
}
+
function sendCmd() {
print (counter);
Bangle.beep(200,3000);
if (tstate==false && counter>0){
do {playx(); counter--;}
while (counter >= 1);
}
}
+
function twistctrl() {
if (tstate==false){
tstate=true;
setTimeout('tstate=false',4000);
setTimeout(sendCmd,4100);
Bangle.beep(200,3000);
}
else{
g.clearRect(10,140,230,200);
if (tstate==true){
if (counter < 5){
counter++;
drwCmd();
Bangle.buzz(100,2);
}
else {
counter = 0;
Bangle.buzz(400);
}
}
}
}
+
/////////////////////////////////////////////////////////////
// draw the command to be executed
+
function drwCmd() {
g.setFont('6x8',6);
g.setColor(0.3,1,0.3);
g.clearRect(10,140,230,200);
switch (counter){
case 1:
g.drawString('play',50,150);
break;
case 2:
g.drawString('next',50,150);
break;
case 3:
g.drawString('prev',50,150);
break;
case 4:
g.drawString('nx f',50,150);
break;
case 5:
g.drawString('pr f',50,150);
break;
case 0:
g.clearRect(10,140,230,200);
break;
}
}
+
setWatch(volup,BTN1,{repeat:true});
setWatch(voldn,BTN3,{repeat:true});
Bangle.on('twist',twistctrl);
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});
+ + + +
+ +
+ + + + +
+ + +
+ + +
+
+ + + + +
+ + + +
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/gbtwist/app.png b/apps/gbtwist/app.png new file mode 100644 index 000000000..e12e3f4c3 --- /dev/null +++ b/apps/gbtwist/app.png @@ -0,0 +1,1548 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BangleApps/app.png at master · radsvvid/BangleApps + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + +
+ +
+ +
+

+ + + / + + BangleApps + + +

+ + + forked from espruino/BangleApps + + +
+ +
    + +
  • + +
    + + + + + + + + Watch + + + + + +
    +
    +

    Notifications

    + +
    + +
    +
    + + + + + + + + +
    + +
    +
    +
    + + +
    +
    + +
    + + + +
  • + +
  • +
    +
    + + +
    +
    + + +
    + +
  • + +
  • + + + Fork + + +
  • +
+ +
+ + + + +
+ + +
+
+ + + + +
+ + + + Permalink + + + +
+ +
+
+ + + master + + + + +
+
+
+ Switch branches/tags + +
+ + + +
+ +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+ +
+ + + + Go to file + + +
+ + + + + + + + + +
+
+
+ + + +
+ +
+
+
 
+
+ +
+
 
+ Cannot retrieve contributors at this time +
+
+ + + + + + + + + + + + + +
+ +
+ + +
+ + 906 Bytes +
+ +
+ + + +
+ + + + +
+ +
+
+ +
+ +
+
+ + + +
+
+ app.png +
+
+ +
+ + + + +
+ + +
+ + +
+
+ + +
+ + + +
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/gbtwist/screenshot1.jpg b/apps/gbtwist/screenshot1.jpg new file mode 100644 index 000000000..93c33c5b6 --- /dev/null +++ b/apps/gbtwist/screenshot1.jpg @@ -0,0 +1,1611 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BangleApps/screenshot1.jpg at master · radsvvid/BangleApps + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + +
+ + + + + + + + + +
+
+
+ + + + + + + + + + +
+ +
+ +
+

+ + + / + + BangleApps + + +

+ + + forked from espruino/BangleApps + + +
+ +
    + +
  • + +
    + + + + + + + + Watch + + + + + +
    +
    +

    Notifications

    + +
    + +
    +
    + + + + + + + + +
    + +
    +
    +
    + + +
    +
    + +
    + + + +
  • + +
  • +
    +
    + + +
    +
    + + +
    + +
  • + +
  • + + + Fork + + +
  • +
+ +
+ + + + +
+ + +
+
+ + + + +
+ + + + Permalink + + + +
+ +
+
+ + + master + + + + +
+
+
+ Switch branches/tags + +
+ + + +
+ +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+ +
+ + + + Go to file + + +
+ + + + + + + + + +
+
+
+ + + +
+ +
+
+ + + +
+ + + + + + +
+
+ + Latest commit + 7d5ae92 + May 27, 2021 + + + + + + History + + +
+
+ +
+ +
+
+ + + 1 + + contributor + + +
+ +

+ Users who have contributed to this file +

+
+ + + + + + +
+
+
+
+ + + + + + + + + + + + + +
+ +
+ + +
+ + 63.8 KB +
+ +
+ + + +
+ + + + +
+ +
+
+ +
+ +
+
+ + + +
+
+ screenshot1.jpg +
+
+ +
+ + + + +
+ + +
+ + +
+
+ + +
+ + + +
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + From 4c7707d0bd97b3eb2473497f9b52e5e171fc48eb Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 00:54:29 +0200 Subject: [PATCH 0037/2129] Update apps.json --- apps.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps.json b/apps.json index a0a819ca5..c2e9a4ca9 100644 --- a/apps.json +++ b/apps.json @@ -3230,5 +3230,20 @@ {"name":"doztime.app.js","url":"app.js"}, {"name":"doztime.img","url":"app-icon.js","evaluate":true} ] +}, +{ "id":"gbtwist", + "name":"Gadgetbridge Twist Control", + "shortName":"Twist Control", + "icon":"app.png", + "version":"0.01", + "description":"Shake your wrist to control your music app via Gadgetbridge", + "tags":"tools,bluetooth,gadgetbridge,music", + "type":"app", + "allow_emulator":false, + "readme": "README.md", + "storage": [ + {"name":"gbtwist.app.js","url":"app.js"}, + {"name":"gbtwist.img","url":"app-icon.js","evaluate":true} + ] } ] From f6973a6ab5a1ff812d556749d471d4efa41ad77c Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:00:11 +0200 Subject: [PATCH 0038/2129] Create README.md --- apps/gbtwist/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 apps/gbtwist/README.md diff --git a/apps/gbtwist/README.md b/apps/gbtwist/README.md new file mode 100644 index 000000000..c9bb28cd3 --- /dev/null +++ b/apps/gbtwist/README.md @@ -0,0 +1,10 @@ +# Gadgetbridge Twist Control + +Control your music app (e.g. MortPlayer Music [a folder based, not tag based player] ) that handles multiple play-commands (same as using a single-button-headset's button to change songs) on your Gadgetbridge-connected phone. + • Activate counting for 4 seconds with a twist (beeps at start and end of counting) + • twist multiple times for: + play/pause (1), next song (2), prev. song (3), next folder (4), prev. folder (5), reset counter (6) + • the command to be sent is shown in green + • Volume up/down is controlled by BTN1/BTN3 presses + + From 7161b62531a376cc72b520d3da575609e5ed046d Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:01:40 +0200 Subject: [PATCH 0039/2129] Update README.md --- apps/gbtwist/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/gbtwist/README.md b/apps/gbtwist/README.md index c9bb28cd3..a99b75300 100644 --- a/apps/gbtwist/README.md +++ b/apps/gbtwist/README.md @@ -7,4 +7,5 @@ Control your music app (e.g. MortPlayer Music [a folder based, not tag based pla • the command to be sent is shown in green • Volume up/down is controlled by BTN1/BTN3 presses - +![screenshot1](https://user-images.githubusercontent.com/84921310/119907281-3ad10d80-bf50-11eb-9818-c2247c99352c.jpg) + From 91377976653d64fc1bc3b69579629de6d1c4a5b6 Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:02:19 +0200 Subject: [PATCH 0040/2129] Delete screenshot1.jpg --- apps/gbtwist/screenshot1.jpg | 1611 ---------------------------------- 1 file changed, 1611 deletions(-) delete mode 100644 apps/gbtwist/screenshot1.jpg diff --git a/apps/gbtwist/screenshot1.jpg b/apps/gbtwist/screenshot1.jpg deleted file mode 100644 index 93c33c5b6..000000000 --- a/apps/gbtwist/screenshot1.jpg +++ /dev/null @@ -1,1611 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BangleApps/screenshot1.jpg at master · radsvvid/BangleApps - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
- - - -
- - - - - - - - - -
-
-
- - - - - - - - - - -
- -
- -
-

- - - / - - BangleApps - - -

- - - forked from espruino/BangleApps - - -
- -
    - -
  • - -
    - - - - - - - - Watch - - - - - -
    -
    -

    Notifications

    - -
    - -
    -
    - - - - - - - - -
    - -
    -
    -
    - - -
    -
    - -
    - - - -
  • - -
  • -
    -
    - - -
    -
    - - -
    - -
  • - -
  • - - - Fork - - -
  • -
- -
- - - - -
- - -
-
- - - - -
- - - - Permalink - - - -
- -
-
- - - master - - - - -
-
-
- Switch branches/tags - -
- - - -
- -
- -
- - -
- -
- - - - - - - - - - - - - - - - -
- - -
-
-
-
- -
- -
- - - - Go to file - - -
- - - - - - - - - -
-
-
- - - -
- -
-
- - - -
- - - - - - -
-
- - Latest commit - 7d5ae92 - May 27, 2021 - - - - - - History - - -
-
- -
- -
-
- - - 1 - - contributor - - -
- -

- Users who have contributed to this file -

-
- - - - - - -
-
-
-
- - - - - - - - - - - - - -
- -
- - -
- - 63.8 KB -
- -
- - - -
- - - - -
- -
-
- -
- -
-
- - - -
-
- screenshot1.jpg -
-
- -
- - - - -
- - -
- - -
-
- - -
- - - -
-
- -
-
- -
- - - - - - - - - - - - - - - - - - - - - - From a29614c88ac5c3822644357a5f4b4a8f0e43c4f1 Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:02:50 +0200 Subject: [PATCH 0041/2129] Update README.md --- apps/gbtwist/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/gbtwist/README.md b/apps/gbtwist/README.md index a99b75300..2323296a5 100644 --- a/apps/gbtwist/README.md +++ b/apps/gbtwist/README.md @@ -7,5 +7,4 @@ Control your music app (e.g. MortPlayer Music [a folder based, not tag based pla • the command to be sent is shown in green • Volume up/down is controlled by BTN1/BTN3 presses -![screenshot1](https://user-images.githubusercontent.com/84921310/119907281-3ad10d80-bf50-11eb-9818-c2247c99352c.jpg) - +![screenshot1](https://user-images.githubusercontent.com/84921310/119907374-65bb6180-bf50-11eb-9073-f29f7e333e00.jpg) From dcca6f043dc7b4786f2fb147d6997efa010929dc Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:05:03 +0200 Subject: [PATCH 0042/2129] Update README.md --- apps/gbtwist/README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/gbtwist/README.md b/apps/gbtwist/README.md index 2323296a5..7e9dbcbe5 100644 --- a/apps/gbtwist/README.md +++ b/apps/gbtwist/README.md @@ -1,10 +1,15 @@ # Gadgetbridge Twist Control Control your music app (e.g. MortPlayer Music [a folder based, not tag based player] ) that handles multiple play-commands (same as using a single-button-headset's button to change songs) on your Gadgetbridge-connected phone. - • Activate counting for 4 seconds with a twist (beeps at start and end of counting) - • twist multiple times for: - play/pause (1), next song (2), prev. song (3), next folder (4), prev. folder (5), reset counter (6) - • the command to be sent is shown in green - • Volume up/down is controlled by BTN1/BTN3 presses +- Activate counting for 4 seconds with a twist (beeps at start and end of counting) +- twist multiple times for: + play/pause (1), + next song (2), + prev. song (3), + next folder (4), + prev. folder (5), + reset counter (6) +- the command to be sent is shown in green +- Volume up/down is controlled by BTN1/BTN3 presses ![screenshot1](https://user-images.githubusercontent.com/84921310/119907374-65bb6180-bf50-11eb-9073-f29f7e333e00.jpg) From 5ab3a32a293927d669400173375b711d68698aa6 Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:07:04 +0200 Subject: [PATCH 0043/2129] Delete app-icon.js --- apps/gbtwist/app-icon.js | 1663 -------------------------------------- 1 file changed, 1663 deletions(-) delete mode 100644 apps/gbtwist/app-icon.js diff --git a/apps/gbtwist/app-icon.js b/apps/gbtwist/app-icon.js deleted file mode 100644 index d460c76b4..000000000 --- a/apps/gbtwist/app-icon.js +++ /dev/null @@ -1,1663 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BangleApps/app-icon.js at master · radsvvid/BangleApps - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
- - - -
- - - - - - - - - -
-
-
- - - - - - - - - - -
- -
- -
-

- - - / - - BangleApps - - -

- - - forked from espruino/BangleApps - - -
- -
    - -
  • - -
    - - - - - - - - Watch - - - - - -
    -
    -

    Notifications

    - -
    - -
    -
    - - - - - - - - -
    - -
    -
    -
    - - -
    -
    - -
    - - - -
  • - -
  • -
    -
    - - -
    -
    - - -
    - -
  • - -
  • - - - Fork - - -
  • -
- -
- - - - -
- - -
-
- - - - -
- - - - Permalink - - - -
- -
-
- - - master - - - - -
-
-
- Switch branches/tags - -
- - - -
- -
- -
- - -
- -
- - - - - - - - - - - - - - - - -
- - -
-
-
-
- -
- -
- - - - Go to file - - -
- - - - - - - - - -
-
-
- - - -
- -
-
-
 
-
- -
-
 
- Cannot retrieve contributors at this time -
-
- - - - - - - - - - - - - -
- -
- - -
- - 1 lines (1 sloc) - - 283 Bytes -
- -
- - - -
- - - - -
- -
-
- -
-
- -
- -
-
- - - -
- - - - - - -
require("heatshrink").decompress(atob("mEwwhC/AC3wCysP/4vW/4YWGAJJWGC4YBGCJ1EJKAQBAAZJFh4WPCgQwDGZIWHDAgXKCxAtDAgYuPGAgXIFJIGFC5w3EAwQXHIwoMDBIanJC56NNLARIHC543IC+jVGC454IC96P/C8D9HOxwXDEggXMh4QEC5JGHEAYlGC5wJBJArfFRhRZHFxYkBJIYqFFxYXCAQJJEUhoXCPQhcNAATQFEIwAOJIYAUIJgYjJOIvWAEw="))
- - - -
- -
- - - - -
- - -
- - -
-
- - - - -
- - - -
-
- -
-
- -
- - - - - - - - - - - - - - - - - - - - - - From b0e768c0f0aa8b0381aad504dd2638b89292f719 Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:07:11 +0200 Subject: [PATCH 0044/2129] Delete app.js --- apps/gbtwist/app.js | 2071 ------------------------------------------- 1 file changed, 2071 deletions(-) delete mode 100644 apps/gbtwist/app.js diff --git a/apps/gbtwist/app.js b/apps/gbtwist/app.js deleted file mode 100644 index 3e3e00c7e..000000000 --- a/apps/gbtwist/app.js +++ /dev/null @@ -1,2071 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BangleApps/app.js at master · radsvvid/BangleApps - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
- - - -
- - - - - - - - - -
-
-
- - - - - - - - - - -
- -
- -
-

- - - / - - BangleApps - - -

- - - forked from espruino/BangleApps - - -
- -
    - -
  • - -
    - - - - - - - - Watch - - - - - -
    -
    -

    Notifications

    - -
    - -
    -
    - - - - - - - - -
    - -
    -
    -
    - - -
    -
    - -
    - - - -
  • - -
  • -
    -
    - - -
    -
    - - -
    - -
  • - -
  • - - - Fork - - -
  • -
- -
- - - - -
- - -
-
- - - - -
- - - - Permalink - - - -
- -
-
- - - master - - - - -
-
-
- Switch branches/tags - -
- - - -
- -
- -
- - -
- -
- - - - - - - - - - - - - - - - -
- - -
-
-
-
- -
- -
- - - - Go to file - - -
- - - - - - - - - -
-
-
- - - -
- -
-
-
 
-
- -
-
 
- Cannot retrieve contributors at this time -
-
- - - - - - - - - - - - - -
- -
- - -
- - 100 lines (88 sloc) - - 1.98 KB -
- -
- - - -
- - - - -
- -
-
- -
-
- -
- -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// just a watch, to fill an empty screen
-
function drwClock() {
var d = new Date();
var h = d.getHours(), m = d.getMinutes();
var time = ("0"+h).substr(-2) + ":" + ("0"+m).substr(-2);
g.reset();
g.setFont('6x8',7);
g.setFontAlign(-1,-1);
g.drawString(time,20,80);
}
-
g.clear();
drwClock();
Bangle.loadWidgets();
Bangle.drawWidgets();
-
/////////////////////////////////////////////////////////////
// control music by twist/buttons
-
var counter = 0; //stores your counted your twists
var tstate = false; //are you ready to count the twists?
-
function playx() {
Bluetooth.println(JSON.stringify({t:"music", n:"play"}));
}
-
function volup() {
Bluetooth.println(JSON.stringify({t:"music", n:"volumeup"}));
}
-
function voldn() {
Bluetooth.println(JSON.stringify({t:"music", n:"volumedown"}));
}
-
function sendCmd() {
print (counter);
Bangle.beep(200,3000);
if (tstate==false && counter>0){
do {playx(); counter--;}
while (counter >= 1);
}
}
-
function twistctrl() {
if (tstate==false){
tstate=true;
setTimeout('tstate=false',4000);
setTimeout(sendCmd,4100);
Bangle.beep(200,3000);
}
else{
g.clearRect(10,140,230,200);
if (tstate==true){
if (counter < 5){
counter++;
drwCmd();
Bangle.buzz(100,2);
}
else {
counter = 0;
Bangle.buzz(400);
}
}
}
}
-
/////////////////////////////////////////////////////////////
// draw the command to be executed
-
function drwCmd() {
g.setFont('6x8',6);
g.setColor(0.3,1,0.3);
g.clearRect(10,140,230,200);
switch (counter){
case 1:
g.drawString('play',50,150);
break;
case 2:
g.drawString('next',50,150);
break;
case 3:
g.drawString('prev',50,150);
break;
case 4:
g.drawString('nx f',50,150);
break;
case 5:
g.drawString('pr f',50,150);
break;
case 0:
g.clearRect(10,140,230,200);
break;
}
}
-
setWatch(volup,BTN1,{repeat:true});
setWatch(voldn,BTN3,{repeat:true});
Bangle.on('twist',twistctrl);
setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});
- - - -
- -
- - - - -
- - -
- - -
-
- - - - -
- - - -
-
- -
-
- -
- - - - - - - - - - - - - - - - - - - - - - From 799738f85b2608f521333f02d24595c523b79e51 Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:07:22 +0200 Subject: [PATCH 0045/2129] Delete app.png --- apps/gbtwist/app.png | 1548 ------------------------------------------ 1 file changed, 1548 deletions(-) delete mode 100644 apps/gbtwist/app.png diff --git a/apps/gbtwist/app.png b/apps/gbtwist/app.png deleted file mode 100644 index e12e3f4c3..000000000 --- a/apps/gbtwist/app.png +++ /dev/null @@ -1,1548 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BangleApps/app.png at master · radsvvid/BangleApps - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
- - - -
- - - - - - - - - -
-
-
- - - - - - - - - - -
- -
- -
-

- - - / - - BangleApps - - -

- - - forked from espruino/BangleApps - - -
- -
    - -
  • - -
    - - - - - - - - Watch - - - - - -
    -
    -

    Notifications

    - -
    - -
    -
    - - - - - - - - -
    - -
    -
    -
    - - -
    -
    - -
    - - - -
  • - -
  • -
    -
    - - -
    -
    - - -
    - -
  • - -
  • - - - Fork - - -
  • -
- -
- - - - -
- - -
-
- - - - -
- - - - Permalink - - - -
- -
-
- - - master - - - - -
-
-
- Switch branches/tags - -
- - - -
- -
- -
- - -
- -
- - - - - - - - - - - - - - - - -
- - -
-
-
-
- -
- -
- - - - Go to file - - -
- - - - - - - - - -
-
-
- - - -
- -
-
-
 
-
- -
-
 
- Cannot retrieve contributors at this time -
-
- - - - - - - - - - - - - -
- -
- - -
- - 906 Bytes -
- -
- - - -
- - - - -
- -
-
- -
- -
-
- - - -
-
- app.png -
-
- -
- - - - -
- - -
- - -
-
- - -
- - - -
-
- -
-
- -
- - - - - - - - - - - - - - - - - - - - - - From c0e38a8185c09b6e1bf5ede9de7e14fd9bac7ea2 Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:08:43 +0200 Subject: [PATCH 0046/2129] Add files via upload --- apps/gbtwist/app.js | 97 +++++++++++++++++++++++++++++++++++++++++++ apps/gbtwist/app.png | Bin 0 -> 906 bytes 2 files changed, 97 insertions(+) create mode 100644 apps/gbtwist/app.js create mode 100644 apps/gbtwist/app.png diff --git a/apps/gbtwist/app.js b/apps/gbtwist/app.js new file mode 100644 index 000000000..4bd495277 --- /dev/null +++ b/apps/gbtwist/app.js @@ -0,0 +1,97 @@ +// just a watch, to fill an empty screen + +function drwClock() { + var d = new Date(); + var h = d.getHours(), m = d.getMinutes(); + var time = ("0"+h).substr(-2) + ":" + ("0"+m).substr(-2); + g.reset(); + g.setFont('6x8',7); + g.setFontAlign(-1,-1); + g.drawString(time,20,80); +} + +g.clear(); +drwClock(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +///////////////////////////////////////////////////////////// +// control music by twist/buttons + +var counter = 0; //stores your counted your twists +var tstate = false; //are you ready to count the twists? + +function playx() { + Bluetooth.println(JSON.stringify({t:"music", n:"play"})); +} + +function volup() { + Bluetooth.println(JSON.stringify({t:"music", n:"volumeup"})); +} + +function voldn() { + Bluetooth.println(JSON.stringify({t:"music", n:"volumedown"})); +} + +function sendCmd() { + print (counter); + Bangle.beep(200,3000); + if (tstate==false && counter>0){ + do {playx(); counter--;} + while (counter >= 1); + } +} + +function twistctrl() { + if (tstate==false){ + tstate=true; + setTimeout('tstate=false',4000); + setTimeout(sendCmd,4100); + Bangle.beep(200,3000); + } + else{ + g.clearRect(10,140,230,200); + if (tstate==true){ + if (counter < 5){ + counter++; + drwCmd(); + Bangle.buzz(100,2); + } + else { + counter = 0; + Bangle.buzz(400); + } + } + } +} + +function drwCmd() { + g.setFont('6x8',6); + g.setColor(0.3,1,0.3); + g.clearRect(10,140,230,200); +switch (counter){ + case 1: + g.drawString('play',50,150); + break; + case 2: + g.drawString('next',50,150); + break; + case 3: + g.drawString('prev',50,150); + break; + case 4: + g.drawString('nx f',50,150); + break; + case 5: + g.drawString('pr f',50,150); + break; + case 0: + g.clearRect(10,140,230,200); + break; +} +} + +setWatch(volup,BTN1,{repeat:true}); +setWatch(voldn,BTN3,{repeat:true}); +Bangle.on('twist',twistctrl); +setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); \ No newline at end of file diff --git a/apps/gbtwist/app.png b/apps/gbtwist/app.png new file mode 100644 index 0000000000000000000000000000000000000000..2379c76f075bc03c0874358774ee626f77c5d79b GIT binary patch literal 906 zcmV;519kj~P)EX>4Tx04R}tkv&MmKpe$izo>T{x)hUfUYhmWs!37+MB?#~fb3MK=50`V-<4U2e#czV;) zIqwt4SXokt&xywjx*+i**JYRAIF}su^URo$&CC<~5g@z^v>LYkeQevU6Cm&mTxlJDtqIJ0lHTZO z@gtyb8@RacX!0I#xdRM7>5?HiQh=tvSOnhB=$rDuz%9_b=JwX!$LRx*rLNL9z`-Ff zTB7WAk9YTU_xA6Zc7H$a+j4TCqcJ`J000JJOGiWi000000Qp0^e*gdg32;bRa{vG? zBLDy{BLR4&KXw2B00(qQO+^Rg1riMr5s4h2L;wH*h)G02RA}DqnZ0epKn#WXRM>UO z1fD`Gq{$XZm%>A2mJE>@QpHVnh{t$o&VXU)e#!e$A_4*o;Uw}iA9)fbve{k@;)L1rr>!wkHFYQQZRj8KNsWVV$d*}E$S5~2Hpr&*py?+*wubgYu zZPXGVr%*#SwJKbapCsR{{h=m+rx;J}nB5_oEc5^{lVIyERK=zi`med$|Bno;9>8jX zuodwJux5aW9?v53AtH}%-CjhFwe?@rmp%5XxOUN0Q;DU=*2w1a0N`9}Vv!}Gi=)hc z;w=*VuIct2OQ$F6KO~>7)*MLQk$fTfZ7m(IgnT!N4Wh1!`Q(1jB6455a1omdqz;=} z?7Bq&F$gV)>Gy%qTqbpP*}Bgor-i11Xa-ekfRY!DUQesV03$)Do%RN)@_nEsgqfp} g>Z1B2VY9zvza Date: Fri, 28 May 2021 01:11:18 +0200 Subject: [PATCH 0047/2129] Create app-icon.js --- apps/gbtwist/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/gbtwist/app-icon.js diff --git a/apps/gbtwist/app-icon.js b/apps/gbtwist/app-icon.js new file mode 100644 index 000000000..b28bbe664 --- /dev/null +++ b/apps/gbtwist/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwIYVhAFEjgFEh4FEg+AAocD4AME8ADCgPAvAFCj/8nkQAoN//8enAQB///44FBgYFB8f4FoIFB+IFBh/+n/4AocH/AXBj/+gP8FIIFDFwM//0x/wFDAIIFNv4FB/4FNEaIFFj/gn5HCj+AAoUEh4FBMgUP4AFDw/gv/wAoPDPoKhBjnxAoKtBjl4TYLICninBagUPWYLJPFoIADZIYABnj6KABIA=")) From b54431b8fe509cfb45f791c940781976af8944ba Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:17:38 +0200 Subject: [PATCH 0048/2129] Update ChangeLog --- apps/gbtwist/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gbtwist/ChangeLog b/apps/gbtwist/ChangeLog index e6a8d1263..8684b5743 100644 --- a/apps/gbtwist/ChangeLog +++ b/apps/gbtwist/ChangeLog @@ -1 +1 @@ -Initial version +v0.01: Initial version From 7c60b8fdddd20ccfdb012427aa806119743bbaed Mon Sep 17 00:00:00 2001 From: radsvvid <84921310+radsvvid@users.noreply.github.com> Date: Fri, 28 May 2021 01:18:03 +0200 Subject: [PATCH 0049/2129] Update ChangeLog --- apps/gbtwist/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gbtwist/ChangeLog b/apps/gbtwist/ChangeLog index 8684b5743..ec66c5568 100644 --- a/apps/gbtwist/ChangeLog +++ b/apps/gbtwist/ChangeLog @@ -1 +1 @@ -v0.01: Initial version +0.01: Initial version From 572a5120dc5eaf934907e37ed8164342decdfda3 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 May 2021 09:30:12 +0100 Subject: [PATCH 0050/2129] update core --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 7d04c4884..3f2ff467f 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 7d04c488496c873f392c5a068f72a6c75df40f70 +Subproject commit 3f2ff467f22b746da94160e59ff89b621601b261 From f382c8b68fe716cc3fb063b9716e201dbf269b80 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 May 2021 11:58:08 +0100 Subject: [PATCH 0051/2129] misc app tweaks --- apps.json | 6 +++--- apps/about/ChangeLog | 1 + apps/about/app.js | 8 ++++++-- apps/hrm/ChangeLog | 1 + apps/hrm/heartrate.js | 40 +++++++++++++++++++++++++++++++++------- apps/s7clk/ChangeLog | 1 + apps/s7clk/app.js | 3 ++- 7 files changed, 47 insertions(+), 13 deletions(-) diff --git a/apps.json b/apps.json index 5ce7682f9..e12c07d04 100644 --- a/apps.json +++ b/apps.json @@ -54,7 +54,7 @@ { "id": "about", "name": "About", "icon": "app.png", - "version":"0.07", + "version":"0.08", "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", "tags": "tool,system", "allow_emulator":true, @@ -665,7 +665,7 @@ { "id": "hrm", "name": "Heart Rate Monitor", "icon": "heartrate.png", - "version":"0.03", + "version":"0.04", "description": "Measure your heart rate and see live sensor data", "tags": "health", "storage": [ @@ -860,7 +860,7 @@ { "id": "s7clk", "name": "Simple 7 segment Clock", "icon": "icon.png", - "version":"0.04", + "version":"0.02", "description": "A simple 7 segment Clock with date", "tags": "clock", "type":"clock", diff --git a/apps/about/ChangeLog b/apps/about/ChangeLog index 22409a4ec..62e8d0126 100644 --- a/apps/about/ChangeLog +++ b/apps/about/ChangeLog @@ -5,3 +5,4 @@ 0.05: Actual pixels as of 27 Apr 2020 0.06: Actual pixels as of 12 Jun 2020 0.07: Pressing a button now exits immediately (fix #618) +0.08: Make about (mostly) work on non-240px screens diff --git a/apps/about/app.js b/apps/about/app.js index a9c6854d9..aa91b5e42 100644 --- a/apps/about/app.js +++ b/apps/about/app.js @@ -5,8 +5,12 @@ var s = require("Storage"); g.clear(1); g.setFont("6x8"); var y = 24, h=8; +if (g.getWidth()>=240) { g.drawImage(require("heatshrink").decompress(atob("vE4gQZWg//AAI3Zh4dCoAd6wAd64Ad2j4d6l4dcn4dC6Adc+AdYv4dUggHG//kgN//AGB1WkDpkOAwsH/gDBgJ4CTRwdGl6RDl/0gHQgJeMDo2/AgcDIAIkBnAdRgJyCAAQdDlgdRgZPDgbWBDoUcDqMPRYcJgEfoA7Uh9AAgQ1BEgIdBngdRKQIACmBbB6AdB2gdRnoEDyB+C8tbbQVpgNAqOkAwMGyEQDoMB1AIBvgdDPYMC+H//7zBg//+fAA4OAgH//twDoMv/4WB3iyEAAPwHINvTYMAv/A/sC6BmBh/wDoP4gIuBdwayBAAP/DoMH4F4ToQSB+EPJQUOgKmDBgIABhAdFB4L7BgfAAYNwjpKChwJBTIQdDiAdFgHgAYIdDmDaCO4MD9Wq14dM+CdCDoU0nDjChyhBAAIdFsgdTZgaVDmPYLJk0LIodDaIcxcILRDSo80jiVECgUAvgDCmG0YQTRHDoTRBgLRCMwJDBnodDeAMDKoUvAIU/DocD6ELDoKRCAIM/LIcGG4PQUIKCBU4PzDoaEB/p3BFQKKCh9ADoXsKIVVqonCtVBoFQcAUKyFwghdB3IPBCwJZCAQMfEgQAL2AGFgZJBDoZgDABEMWYQJFgLwCkACB/gdLWYMCfoQAE35BEDpkH8EfdgYADl4mDl68BABazBFBA2CgK8CABcBUZP/8kBv58CAC1//4ABUQwASn4dgOxoALl4dC4AdYj4d6h4d+wAd6oAd2g4dCAwQA=")),120,y); g.drawString("BANGLEJS.COM",120,y-4); +} else { + y=0; // small screen, start right at top +} g.drawString("Powered by Espruino",0,y+=4+h); g.drawString("Version "+ENV.VERSION,0,y+=h); g.drawString("Commit "+ENV.GIT_COMMIT,0,y+=h); @@ -27,9 +31,9 @@ if (ENV.SPIFLASH) g.drawString("SPI Flash: "+(ENV.SPIFLASH>>10)+"k",0,y+=h); g.setFontAlign(0,-1); g.drawString(NRF.getAddress(),120,232); g.flip(); - +print(y); // Pixel chooser image -g.drawImage(require("heatshrink").decompress(atob("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")),0,135); +g.drawImage(require("heatshrink").decompress(atob("+FQgl+xnu8AIBwGQgHuAoN3gF/hcLgEHu943G3hwUCDwIBCAAV3uEAhoBBhsO90OgHgoACBh0IhP5AAQXBg8H8Hw+GwEAXn4AECxGAh0MEAOeJAMP3+/huIG4cMg1mMog8BhnsAQIBC///J4MN6HcBIOIAAPs8Hl9nM5gcB0Hg852BAIMAI4YACIIIACh8AKAcAvA6D7vd7wTBTYJ3B9e+hEAhA4CyHuy8HXw29NgIABx+ASQKsBYgR3DgHQCIXMsEAAIOZyGZzx3Dh/A57IDPoXN4HNHwQoB9wAByDvBO4LhDOwR4Fd4cP/4oB0DWCd45VCgFFAYPuO4QACgEed4PweAILBN4NpwEMXILvBO4bvD/f/d4cPCYJ1BAAKSCzp3E/hNBJwPziEP+H8hrvD9DtC5MJd4RTBGoLvBhe7BQJSBAAeAI4IoCO4T2Ch8N6DvDeAPgqFQd48MiB3BE4cI/AvC5ns4AKCdgQAD//wUwMMhhgBO4Nmd4xED57vD+EwFgKTCYoON/+v////OZwGXgF55vQI4TaBEQRxB6Hw7DRCAAPgO44ACKYlFoB3CHIcAiEAi93I4JpCdARmBd4IAFd4QAE4HA5//hh1BAIIPByA5BEQUM/n8O4TzCAAQtBhvd/X8d4YYBvwOBO4LvBYIoKBh/YewfA6B3DLoP/d4JXGABMBiKkEAAwKH9LyFO4fwOoR3Dd4TDD5/AJQcwDgcO9zvC1vd7ocBxuAvh3CuEHh5jCEoOPgHf/53CGgMAoGgbgX/CgJZEAIYAB5HIbxRCBAYULhZfBAAMA/GA/47Bd44ABh4CBg1mg8A3YAB3vtO4cMWxvG5vdZYWIw8AvPQd4NwRwUwAYIlBhsNGoR3CqB3BIAR4BFAXHAIg/CRAIDBIgtHHIR3D3ZhCZYXwwBrCOAXP5n855kNO4OABIyxCHYcDmdutOZA4VAAYUNqB0DAAQfDKIVms3AAgJ3BhBMBJwgAHhi7DDIQABgl9CIrvCeAJ3JABPM4AoBhqbDIgI0CMQfdOgR3E5nG5MzIAIBBAQIABwA5BgUgkEiEAe7hwECtgCB2B3BbwMJ9OeyBLIh3gFATvCPITuDhoCEgFVqq0B//w///MQWIbYJkFAAIjBEoR3DCoOA8A3CYAOvh/wE4LvEKoLvCoEE/7xDAAy/C2G+gw2DNQ2e9I0DBgxIBxGAWgS1DAAfd7pYE6BrBWwUIh2OAwLcGNQOA5jbCd4gACO4OgAgMHu4aBDokKgGIZ4LtBogABBgXw4HwhnL5lwEQXgd4V3BAIdBb4jvBO4/uIAfQKAJ3Gh7sC6/X7ogBUIL0BCwJ3ChHoO4QeCO4YHBXAQCBO4xQBJoYVBNwIBBhWq0HDwEOCIPuoDtIH4LuCAAOwMIR3BUATnIfgZ9BFYKHBd5nQKwICBBYWAPoJ3B///d5HM5jvD4DxBd4PQGwIBCHIMAeAQAEhQIC4GIboQABB4ifBW4ZeCAAO+EwJyBNQV2sDvCAAw6DAAaLFDgPwB4kNGIUJ5I3CcooAHO4OZzILH+AABFgcKeAa+Dd4p3Jd4+Ld4juChnMuz0DNQQABBAMOM4RqDuFwY4IUEGpLwB8DjB+ACBC4kJyAEC93uyAABDoxLB8HwFYTlBAIMMFIJlEQQJ3BCoIYBDgULCIpZCQ4YGBu5pBhn/u4UExB2BNoMO9wBB9xqDO4JeEEQKTFxABBwHJh3ex2P9+JxncZAJcBhMJO4mZO4dgXYRPCWQQzF4AABRIhHB5gACBYPeSAcAxOAAYICCdwK0CQYfc/I6BNYeAOwIAKBgMMQIIHC8EP///AoLkBgH4+AMCd4uoxWI1B3EAAOQzIDBswCBcIwAGBosOh7dChuNAYXvL4IPChGYgEP+AnFFox3B9vtO4LvBG47/CcofOPoYABWIIzCd4bYCB4NwgwFBd4IBBhI0Bh64CdwIHBdwJIBdAq7BEgTwDAgaxBAQMJhvdBALuBBAIQDeAMPh/ADQOH2+IhpeDfgbvDZAMP54ACMoJcCsAYC5nOV4OXcgQADd4QADs8HsF2g1QSwQAE+AcGRILhD/5cDE4ySDAgcGwGdxqvDd4j3BCIMP5iSCvfQcA6SB9wLBxBmBAAX/H4LkDSAcOFoOXgG72AgEd4IADqEFAQkL93rhzHCLgRIBCwbwCBgSFBOoLvBwEMg6XBBgIXDO4WJhuNHQyOF+DvCu+w2/QHoQACBYPt7qsCAAPgOQLvJAAeXhYdCZYIBBKYOAAII/I3yMB6CoBd4UDgbvDO44gBPIQ+BW4YADD4TvBOoI2FKA0A0AABAwfu9oOFOwPgAQLgBDoqwBAQIJFO5QACJIP/JQIDC+AVCO4LrBdgjuE24uB/7uFd4nwQob0DxEN7uIVxJ3E1R3Bh0ONoZ+E93gAIIPCVQ7fDgENAwRhC8AWBE4LvNAAXdaQsAmAHEO4QABhOZyB6BxB3BIg3QH4PQ/GIEIIAGQIMPTQMAhTuB1DaE9xNCAQTvCLgQACyDcDAAWIFARbD3ew9ycEKILvCABkMAAMAgZKCAAYlBHog8BAArqDO4mPx5bBuCTDCYWfh/P6AeFNgVwg7FEaITvC4BIB4B3HMgXdEwP/VwyCBO4QpB8A4GABiUCACB2COoIBCxH4wEM28A5hYCgEGszvC6F3NojKBuF3O4g+DPQPAAAWQ/7GB5nMH48D+AsCAAZDBF4YFCP4OAwD4GJgQCBhkJBYg8BBQJeBCgoABBAQCBNgIABd4UL5dwBASZQxGAKQcNAgPuQgJuBhnAz8A/kM553GFwMwO4PPhYfFTYjvBhAwBfAQABuA/GVAKKCTgxdR/GI+EM3gXCSIZeBg8Au7vEO4vQJgIAB+BTB8DvI//8FQLzBFYPL5YDBKQvQd5Z3FYoUPO4ZUBCQOf/5YDVoIFDIwNw+CUHBgQADEAOIUQnHg9wg+8714zUQCYbvBO4pDFXwRPBd4UOfwIzB5e7U4gAMO4R4BA4S4HhgiBO452DRQcP54ECyEJzJ3DkYXDGIIABRQTvCVoI0EhvcZghFCu4QBaQhKEdYIIFO4m7hewGIIRFEJAAFMYRQCRQZ3FXYUOCYXgd4cJhJ5BBIMOgE9mAYCxGAd4kAdwJ3DzIYBhu9OwbvDPwqTCcI8LAYU83gEC2B4BCoP85ns4Z6BO5UP/5lCAAz+DF4kPOoIBBC4eggGpdoJeBh3ggEDkLvGHROeDAMI7rFETYLVB3ew6AMDJwxKEgcAQgZ3D5//53Onk8O4a+BAIO62DvIKQMJKIMIZofQh3uOQIABR4X/BgLtBd4h3B4+QiF2gzjCeggAB5vmwGrd4YADSYMGy2Wd4jODd4j5EAA52BMwLvB53uO4MNTIUBgIRB1TOBAAJlBABkHJAXgHYI9CXAK6Cbwvghx3BAoNgAQI1BiMAw53ExJ3BAAUMhWQhptCd4T3DNwzGBhh5BhnMPoQEDBAnM5jvB4YIBFQUQ+EQd4plBFYZLCGgvQuDvCO4/gdoWZzIWDO4TvDGYIBBxGLw+HO4OKO4nA1WQ4GwFYMGBIML3a6I/53CgEOZxoAFO4MPgPxSwIAE93gSIQACqsFqEMF4MLeAbjFW4UA0ABCAAmOSwp3Dxe7hAiGha3BhOQhANCd4W/l7EDyGQzILBG4L4GP4Z3ODgKVBLgYhBL4MM/kA/LcBoHwoCAF6HueALdBh3+eAQABuEHcgKdFbgQBB4JtD3YAGgGwUoIiDAYTdB2Xy2DiCOgJ4BO4vQPYfMGQJdB5nM55rELYg9CA4fvO4cIxEAzJoBh4uBO4sLH4QOBC4X/PAMHAAQSCg/ud4UMAAYMCzOIwB2GO4oABJQbvFAAg3BHAPgFIKpDO4TgB//5zML1cAjUAhUQeAYABxAeC7qWDAALvCAAfAK4bbB92QAAJCFg93d4gGBAgSVBO4sJxbvI2EIBwPYAQOqVoYOBXAICDbI5YDO4cJzOZznMhQiCKYXQO4PMCQLCBLYorIABGQhp3CewTvDKIbvB54TBd453Hd4sNPQWZGITnDbQMPX4jLFABEONQMK3QGBFAR3Cg8Gd4JwRDYRwDUQJHC8HgCg2wd4XA+B3DeYO/BgMJxDvHhYMBd4l3agRCI7sNAAJEEFgLtCJ4nM5gbGhqRBg9gMgUPdoYBDfwIaExAABwDvEAIUOhIBBQAMJAYJ3D93Ah7RDAAO7+ARBEQgADBAbvBAoPuO48OW4R2FAAZ2GCoPOEAMLX4gDCNYTvB+Hw/8AuAIBAQScBDQQBBG4SoBF4OQAALvDO4ZQCd4eZOwbDCd4WZwEPGwQAL7p3BhOQDALMBQQPgNY/bO4R4DCAXx/DOGAAZnBAAMPd4JCBg4ABTgo4BAIPuEwXteAhlDJgOQd4UL3YMC/PwAgW52EJ/grDh//O4IpDeQ0A5iLBGIOwc4ZBB5nAG4OZm71BIoR3DhyrC/8QEgYiBu50BRIdwUwLvBAAp3DdwYlBEwS3CACLvGO4fM5h3CBQIpDgEIxAFDqoeCD4PdhvQRYOA//w8CsBMIML7zaCMoYACiMfF4PwX4OQuFwdgZ3B6BgBeAMAd4oRB3cLVgLFFhoEBha7Ch8PhAABAgJ4G+ycCd4vHvjBBVIZ5Ed4gABSoQxChsIdYWQ8HphOnVw4iCT4hQBO4TvDMYR3DdQVwBIR3ChcLPALvDHwXAFQQSCABXwPoP/sBCHO4SMCwBxEhAFB5ncDYIsMEoKFCa4YDC8DCBAQOZ5nMBILvIAoPdH4UPdgIBDSAQACJgMIHYzvDdoQADBweZzMAsx3CKgZIBIofAMAoMBwBKB6AMELAQCBIIIAKXRGZ/6YDIQNwg7vBO4buBABewAAK+DGh4AEz3pegZtBGwLyC4C1DOwj/DO5BYBhOQ3JCBh7LBgHuAAMA5vgvI9HVAKpCABDkBO4ztDgEEdwYAJd4TqDgwFEO4sP95ABO4TiBbYp4EKoncgEKAIPdRoMJCoJCDbYQjBDQPA8Fw0BQLAYyYBAAuIwAABg75DCAISE+DVBAQTvHsFgZQ2Zd45TCGwgIC8HuAQINDd4Wg0HQ5j4ByAaEHoTvFO4OwMouYmcwh//AIIKDYgYADh4IBPIMHg7dBgxoFCAMAwACBEIgACdwMGAwYWDhvLD4sOeoMHAwWJwDvIO4JxBeALvB5jdKABf4RAOImCNBKoVQAQOOG4YAC/5UBd4Y7BBYQ4Sd4sPj6OCLQIAHO4cIH4R2BPAwAChcOXYMMgYNHhpODAA7XBO4rvBMwMI9HoeYZBC5kM4AGBd4TPC4D5Cu+Zh5iB3ew2HP5nAdAbwBAocP+J3ChItCOIYtCAoYOBgHgOwUMdYIADBIOw8Fw6GQLwIAG6GZzLvKFYJ6Bd4arC7qRCO4cM5gABAwIyB8DvDCARKC+C8BAgP//4GBABEBiJ3BqAcCuF3O4l3AwgAF4AABIQJ3Ch7wDyYIB1MK7gOCYwOQDgcMNYP/NwQMCyDtBBAQHBhv9/p3FOwTZBXQcJx3ugF3uEHvKnDO4LvDdQYADL4kP81wdA14KQmwcoq3CAQP8BYfweATvCyGQ6EMI4J3Bd5UAhQEDxEIdoOgO4MPDQJ3GMIPILQhEB8BXCJQR3EGpIAFh/g8AtCLwQlBHoIgCAQbwFPQcAggLEd4SUB6ARBuF96EAhML3YABDYMJCwQwCNYWAAQJVB7vw/oaBO4Y0B5iuD4+Qhx3Kh4DCWoIGBh7tCAgIUE+HuAYJ3D/8A7iTDhgeCegQAEBIdEoBoB9IIDO4PcDQNwuDvD2CaC4HACALuEd4iRB7vzO4JTBg5JCeAXohEMvLvGAgMD//yOALVBBgIDCAA8OBYLvDAAVQ+ABBcooBBeQ54CggABEgKZCQYgABO4QXDO4wAJdQMN7vddwOIg93XIXMh3gwDuBLgQ3CNoJdB+Hw/7iChnsFIkNhsMHoUOCAJ3BegQABgtVNQwnBAYMLWYIADNgVAOwNAd4UN5pfFKwR3GgEJgBkBLIX/VoKoCXQgAHB4QAFOAPwLYIBBO4QDBAIIjBSIPMDYxyDhaCBb4zvJ9wAE2C4BeAKlFO40AtvM5wdBO4O7fgg+BH4JJCM5ByEhjjEAA4KBBg4XCh//UoRsBNoXdPIWw2HQ2G9BAIYBhcJYYIFBD4TRCAAiWDO4sAyALCUgZ3DAA94vEO70AzOQK4JmH6BfEhvdFAUDmEzmDkCAAe72BTBKosHu93VYIAENwKOBd4R6CVYXA2GQgyLCfhTvHLYJ3Bd5IAD997SoNwhCJDEgPuCIn/MwItBAQR3BhoWCOgIBBAA2q0BaBKRLvCGggABCZTqEAwsIDojvGaYTvGAA0Ph33uELg94BYjKECIP/boMNAwPe6HMd4Q8BxGAAIKFBeAgIBh2OMoXgcYIAJ5jvCfQvdeIQANh7vLGRbvEvOQW4JeBwGA5jLG/+IMgXtOwImHmDvFyB5ExAkCIQIbCNYNwg93hGIgHA4CIBg4gETYdAA4SHBEAIXBAIIRCC4h3EgyOKhi6CBIsIaIICCO4cIQYP/d4S8B9x3HmZ4BIIcM/IMDd4sNDIsHg6uBO4QJCeAl3AoJiBRIUO9wLBYoJOBAAOwPAoAD8C2EAAY8BVIJEC7oPHwBBEbwQmEaYXnSgwAGHAojFHwbuBd4QHB5iBEGwzaCN4MMCQTvF34qFhyDCO4MJ/kAx2wBAP8hvQ5h2CPoLXD9ns8GIwEMKYcLeAR2EJooAHXAR3CDQMMAATvFh1w87vCLobuDAIJ3EXwaJBxBIBdwKSCh5CCu4ZBAAMIzOAO4h/CgxxBPAJ2BL4XQhoGBYxI/F9x4BDIPgEwUA3YABNwToDyB4B2CvCACihGg8GKwLvCxjvGVgVwTYIYDBgIYBd4Z3Cd4JxBOALwD7tOMYQ3EUAMJeAQKE9ylCqA4CNQIACIQcM/IaBAAIZCgjADJANgAIQAIuEDmEwmZPBDIsM5iPKO4tAgGQMIbvEAAMOAATuCBATvCg93uB3BNAQAEhzvDmDdEAgLuEAALuBd5JABwFng53JdwsIWINwCYuIMAQACQAV3AAJBCHoZ3EBQTvB7vQc4UOhqlDd4R1BO4X/O44FEfgLvEO4JuHQIQoBd4Z3Du5jBh8PdwwDCmDBB8BKEDwYfCA4bNBSQ+IhMJhSWBACp3CAoSfBIoXuCpLvH5n5eASQBSIuIaIMPvIGBh/wE5J3Bd4RlCLoeIBQOIO5sIO4WoFQ7xBdgICBhrdFuAhC/4ABA4IABDotm5nMgBXBhe7gG7dwSrH8AABaAgBBg6gBABGgAwruEdYQDCAoX8HgJ3CAAnwd4qLD1orGAAbDFAAUP/4rBP4J3E5/8s3uO4IAIwB7CFQgrFO4QoBGw6aB1QoJbIKiBNwR3C4HAhhABJYkP94UB6GQD4vbTgXuAATJC8BABYgwAHeoI1Bhh3DQwIABoBNDhbwINAZ3EGgpUBh8LmfuYhRxBhg7BhgIC/gDCg8HgGIFIRGBA4IAGd4hxCgF3uB3GhB3IhOZFALvC5h3DoFPgjkB7sA2AcCHYkPSYVwYokOKIbvF126AoNEgigB9RHCUAJ1BdARsCewVwwF4WAYvBMoI/Cu4zBxwGB3cL2BxBFAJNBO4v3+/wVAOQJYJNChP5c4sDgEwgGEwB3B93QJoUHNoICCXYb7BeAIADYYvA53u93qeAVAAAJWB1wRDd4wAEsEIHIMGs1mu4ABHQQCBhHIAoOwAALvDAoI3B9x3Cv9/CwPPyGN6ABBd4h3HppOBhzvCMoR2BAQKxBO4TvGIwQAD5nA8Hg92u1QuCAILwEd4Z3Hg0GgGIgB2BO4d2sw+Bd4mwAIJ3FEQqRCd48P/+QO4kAkQFCojGCRQLdDGwJwCDYJTBdxZlBgB2BA==")),0,y+19); g.flip(); setWatch(_=>load(), BTN1); diff --git a/apps/hrm/ChangeLog b/apps/hrm/ChangeLog index 1efe78c07..6cedf8f1b 100644 --- a/apps/hrm/ChangeLog +++ b/apps/hrm/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Use HRM data and calculations from Bangle.js (don't access hardware directly) 0.03: Fix timing issues, and use 1/2 scale to keep graph on screen +0.04: Update for new firmwares that have a 'HRM-raw' event diff --git a/apps/hrm/heartrate.js b/apps/hrm/heartrate.js index 1ec0a31d2..09e8a826e 100644 --- a/apps/hrm/heartrate.js +++ b/apps/hrm/heartrate.js @@ -4,18 +4,25 @@ Bangle.setHRMPower(1); var hrmInfo, hrmOffset = 0; var hrmInterval; function onHRM(h) { - // this is the first time we're called if (counter!==undefined) { + // the first time we're called remove + // the countdown counter = undefined; g.clear(); } hrmInfo = h; - hrmOffset = 0; + /* On 2v09 and earlier firmwares the only solution for realtime + HRM was to look at the 'raw' array that got reported. If you timed + it right you could grab the data pretty much as soon as it was written. + In new firmwares, '.raw' is not available. */ if (hrmInterval) clearInterval(hrmInterval); hrmInterval = undefined; - setTimeout(function() { - hrmInterval = setInterval(readHRM,41); - }, 40); + if (hrmInfo.raw) { + hrmOffset = 0; + setTimeout(function() { + hrmInterval = setInterval(readHRM,41); + }, 40); + } var px = g.getWidth()/2; g.setFontAlign(0,0); @@ -28,13 +35,32 @@ function onHRM(h) { g.drawString("BPM",px+15,45); } Bangle.on('HRM', onHRM); +/* On newer (2v10) firmwares we can subscribe to get +HRM events as they happen */ +Bangle.on('HRM-raw', function(v) { + var a = v.raw; + hrmOffset++; + if (hrmOffset>g.getWidth()) { + hrmOffset=0; + g.clearRect(0,90,239,239); + g.moveTo(-100,0); + } + + y = E.clip(170 - (v.raw*2),100,230); + g.setColor(1,1,1); + g.lineTo(hrmOffset, y); +}); // It takes 5 secs for us to get the first HRM event var counter = 5; function countDown() { - E.showMessage("Please wait...\n"+counter--); - if (counter) setTimeout(countDown, 1000); + if (counter) { + g.drawString(counter--,g.getWidth()/2,g.getHeight()/2, true); + setTimeout(countDown, 1000); + } } +g.clear().setFont("6x8",2).setFontAlign(0,0); +g.drawString("Please wait...",g.getWidth()/2,g.getHeight()/2 - 16); countDown(); diff --git a/apps/s7clk/ChangeLog b/apps/s7clk/ChangeLog index 5560f00bc..a08e25f2f 100644 --- a/apps/s7clk/ChangeLog +++ b/apps/s7clk/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Tweaks for Q3 watch diff --git a/apps/s7clk/app.js b/apps/s7clk/app.js index 6973b8c16..475ab38f5 100644 --- a/apps/s7clk/app.js +++ b/apps/s7clk/app.js @@ -16,11 +16,12 @@ function draw() { g.drawString(("0"+d.getSeconds()).substr(-2),x+size*18,y + size*7); // date var s = d.toString().split(" ").slice(0,4).join(" "); - g.reset().setFontAlign(0,-1); + g.setFont("6x8").setFontAlign(0,-1); g.drawString(s,g.getWidth()/2, y + size*12); } // Only update when display turns on +if (process.env.BOARD!="SMAQ3") // hack for Q3 which is always-on Bangle.on('lcdPower', function(on) { if (secondInterval) clearInterval(secondInterval); From 96afb54d0a96a2d45e0dba4a31e8d897bc61cf98 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 May 2021 12:02:59 +0100 Subject: [PATCH 0052/2129] setting 0.26: Use Bangle.softOff if available as this keeps the time --- apps.json | 2 +- apps/setting/ChangeLog | 1 + apps/setting/settings.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index e12c07d04..f75d54575 100644 --- a/apps.json +++ b/apps.json @@ -172,7 +172,7 @@ { "id": "setting", "name": "Settings", "icon": "settings.png", - "version":"0.25", + "version":"0.26", "description": "A menu for setting up Bangle.js", "tags": "tool,system", "readme": "README.md", diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 771ce1d4a..00d11d562 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -28,3 +28,4 @@ 0.23: Change max time offset to 13 for NZ summer daylight time (NZDT) 0.24: Add Quiet Mode settings 0.25: Move boot.js code into 'boot' app itself +0.26: Use Bangle.softOff if available as this keeps the time diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 159575619..12448d463 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -115,7 +115,7 @@ function showMainMenu() { 'Set Time': ()=>showSetTimeMenu(), 'LCD': ()=>showLCDMenu(), 'Reset Settings': ()=>showResetMenu(), - 'Turn Off': ()=>Bangle.off(), + 'Turn Off': ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() }, '< Back': ()=>load() }; return E.showMenu(mainmenu); From 3b82fefd54155877c76cd1031ad86c0c46dd24c9 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 May 2021 12:49:29 +0100 Subject: [PATCH 0053/2129] minor layout tweak --- apps/about/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/about/app.js b/apps/about/app.js index aa91b5e42..9edd0c94f 100644 --- a/apps/about/app.js +++ b/apps/about/app.js @@ -9,7 +9,7 @@ if (g.getWidth()>=240) { g.drawImage(require("heatshrink").decompress(atob("vE4gQZWg//AAI3Zh4dCoAd6wAd64Ad2j4d6l4dcn4dC6Adc+AdYv4dUggHG//kgN//AGB1WkDpkOAwsH/gDBgJ4CTRwdGl6RDl/0gHQgJeMDo2/AgcDIAIkBnAdRgJyCAAQdDlgdRgZPDgbWBDoUcDqMPRYcJgEfoA7Uh9AAgQ1BEgIdBngdRKQIACmBbB6AdB2gdRnoEDyB+C8tbbQVpgNAqOkAwMGyEQDoMB1AIBvgdDPYMC+H//7zBg//+fAA4OAgH//twDoMv/4WB3iyEAAPwHINvTYMAv/A/sC6BmBh/wDoP4gIuBdwayBAAP/DoMH4F4ToQSB+EPJQUOgKmDBgIABhAdFB4L7BgfAAYNwjpKChwJBTIQdDiAdFgHgAYIdDmDaCO4MD9Wq14dM+CdCDoU0nDjChyhBAAIdFsgdTZgaVDmPYLJk0LIodDaIcxcILRDSo80jiVECgUAvgDCmG0YQTRHDoTRBgLRCMwJDBnodDeAMDKoUvAIU/DocD6ELDoKRCAIM/LIcGG4PQUIKCBU4PzDoaEB/p3BFQKKCh9ADoXsKIVVqonCtVBoFQcAUKyFwghdB3IPBCwJZCAQMfEgQAL2AGFgZJBDoZgDABEMWYQJFgLwCkACB/gdLWYMCfoQAE35BEDpkH8EfdgYADl4mDl68BABazBFBA2CgK8CABcBUZP/8kBv58CAC1//4ABUQwASn4dgOxoALl4dC4AdYj4d6h4d+wAd6oAd2g4dCAwQA=")),120,y); g.drawString("BANGLEJS.COM",120,y-4); } else { - y=0; // small screen, start right at top + y=-(4+h); // small screen, start right at top } g.drawString("Powered by Espruino",0,y+=4+h); g.drawString("Version "+ENV.VERSION,0,y+=h); @@ -29,11 +29,11 @@ g.drawString("Storage: "+(require("Storage").getFree()>>10)+"k free",0,y+=h); if (ENV.STORAGE) g.drawString(" "+(ENV.STORAGE>>10)+"k total",0,y+=h); if (ENV.SPIFLASH) g.drawString("SPI Flash: "+(ENV.SPIFLASH>>10)+"k",0,y+=h); g.setFontAlign(0,-1); -g.drawString(NRF.getAddress(),120,232); g.flip(); -print(y); + // Pixel chooser image g.drawImage(require("heatshrink").decompress(atob("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")),0,y+19); +g.drawString(NRF.getAddress(),g.getWidth()/2,g.getHeight()-8,true); g.flip(); setWatch(_=>load(), BTN1); From 9f9ba8aac5594da1fdc2b2f4753b9b7d5bb88bb1 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 May 2021 12:50:34 +0100 Subject: [PATCH 0054/2129] tweak --- apps/s7clk/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/s7clk/app.js b/apps/s7clk/app.js index 475ab38f5..5bc2bff8f 100644 --- a/apps/s7clk/app.js +++ b/apps/s7clk/app.js @@ -31,8 +31,8 @@ Bangle.on('lcdPower', function(on) { draw(); }); -var secondInterval = setInterval(draw, 1000); g.clear(); +var secondInterval = setInterval(draw, 1000); draw(); Bangle.loadWidgets(); Bangle.drawWidgets(); From 901adb43281d2f39220fc6d8394297cee1d95815 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 May 2021 14:20:01 +0100 Subject: [PATCH 0055/2129] boot 0.25: Fix error in 'no clock app' message --- apps.json | 2 +- apps/boot/ChangeLog | 1 + apps/boot/bootloader.js | 6 +----- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps.json b/apps.json index f75d54575..361a71779 100644 --- a/apps.json +++ b/apps.json @@ -4,7 +4,7 @@ "tags": "tool,system", "type":"bootloader", "icon": "bootloader.png", - "version":"0.24", + "version":"0.25", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "storage": [ {"name":".boot0","url":"boot0.js"}, diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index a176df670..48e1baa48 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -23,3 +23,4 @@ 0.22: Stop LCD timeout being disabled on first run (when there is no settings.json) 0.23: Move to a precalculated .boot0 file which should speed up load time 0.24: Add Bangle.setUI polyfill +0.25: Fix error in 'no clock app' message diff --git a/apps/boot/bootloader.js b/apps/boot/bootloader.js index df3718dcc..138258c5a 100644 --- a/apps/boot/bootloader.js +++ b/apps/boot/bootloader.js @@ -14,11 +14,7 @@ if (!clockApp) { if (clockApp) clockApp = require("Storage").read(clockApp.src); } -if (!clockApp) clockApp=`E.showMessage("No Clock Found"); -setWatch(() => { - Bangle.showLauncher(); -}, BTN2, {repeat:false,edge:"falling"});) -`; +if (!clockApp) clockApp=`E.showMessage("No Clock Found");setWatch(()=>{Bangle.showLauncher();}, BTN2, {repeat:false,edge:"falling"});`; // check to see if our clock is wrong - if it is use GPS time if ((new Date()).getFullYear()<2000) { E.showMessage("Searching for\nGPS time"); From 2f2bd423ddc3a371ff0b067afa5d81537d03b965 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 May 2021 14:38:14 +0100 Subject: [PATCH 0056/2129] Misc tweaks to reduce RAM usage - not really enough to warrant version change --- apps/widbt/widget.js | 4 +--- apps/widgps/widget.js | 5 ++--- apps/widhrt/widget.js | 5 ++--- apps/widhwt/widget.js | 5 ++--- apps/widid/widget.js | 4 +--- apps/widtbat/widget.js | 3 +-- apps/widviz/widget.js | 17 ++++++++--------- 7 files changed, 17 insertions(+), 26 deletions(-) diff --git a/apps/widbt/widget.js b/apps/widbt/widget.js index 2236ee50d..0dac82e76 100644 --- a/apps/widbt/widget.js +++ b/apps/widbt/widget.js @@ -1,13 +1,11 @@ (function(){ - var img_bt = E.toArrayBuffer(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==")); - function draw() { g.reset(); if (NRF.getSecurityStatus().connected) g.setColor(0,0.5,1); else g.setColor(0.3,0.3,0.3); - g.drawImage(img_bt,10+this.x,2+this.y); + g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="),10+this.x,2+this.y); } function changed() { WIDGETS["bluetooth"].draw(); diff --git a/apps/widgps/widget.js b/apps/widgps/widget.js index e3d85afca..19be2abaf 100644 --- a/apps/widgps/widget.js +++ b/apps/widgps/widget.js @@ -1,7 +1,6 @@ (function(){ if (!Bangle.isGPSOn) return; // old firmware - var img = E.toArrayBuffer(atob("GBiBAAAAAAAAAAAAAA//8B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+A//8AAAAAAAAAAAAA==")); - + function draw() { g.reset(); if (Bangle.isGPSOn()) { @@ -9,7 +8,7 @@ } else { g.setColor(0.3,0.3,0.3); // off = grey } - g.drawImage(img, 10+this.x, 2+this.y); + g.drawImage(atob("GBiBAAAAAAAAAAAAAA//8B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+B//+BgYGBgYGBgYGBgYGBgYGBgYGB//+A//8AAAAAAAAAAAAA=="), 10+this.x, 2+this.y); } var timerInterval; diff --git a/apps/widhrt/widget.js b/apps/widhrt/widget.js index 16cec0b87..8ac76def8 100644 --- a/apps/widhrt/widget.js +++ b/apps/widhrt/widget.js @@ -1,7 +1,6 @@ (function(){ if (!Bangle.isHRMOn) return; // old firmware - var img = E.toArrayBuffer(atob("FhaBAAAAAAAAAAAAAcDgD8/AYeGDAwMMDAwwADDAAMOABwYAGAwAwBgGADAwAGGAAMwAAeAAAwAAAAAAAAAAAAA=")); - + function draw() { g.reset(); if (Bangle.isHRMOn()) { @@ -9,7 +8,7 @@ } else { g.setColor(0.3,0.3,0.3); // off = grey } - g.drawImage(img, 10+this.x, 2+this.y); + g.drawImage(atob("FhaBAAAAAAAAAAAAAcDgD8/AYeGDAwMMDAwwADDAAMOABwYAGAwAwBgGADAwAGGAAMwAAeAAAwAAAAAAAAAAAAA="), 10+this.x, 2+this.y); } var timerInterval; diff --git a/apps/widhwt/widget.js b/apps/widhwt/widget.js index 6affdea52..d178a5b5d 100644 --- a/apps/widhwt/widget.js +++ b/apps/widhwt/widget.js @@ -1,10 +1,9 @@ /* jshint esversion: 6 */ (() => { - var icon = require("heatshrink").decompress(atob("jEYwIKHgwCBhwCBh4CEggPCkACBmAXDBwVZ+EB+F4gEsjl8EgMP+EChk/gEMh+ehkA+YIBxwxBnF/4HggH/wEAj0AA==")); var color = 0x4A69; function draw() { - g.reset().setColor(color).drawImage(icon, this.x + 1, 0); + g.reset().setColor(color).drawImage(require("heatshrink").decompress(atob("jEYwIKHgwCBhwCBh4CEggPCkACBmAXDBwVZ+EB+F4gEsjl8EgMP+EChk/gEMh+ehkA+YIBxwxBnF/4HggH/wEAj0AA==")), this.x + 1, 0); } WIDGETS["widhwt"] = { area: "tr", width: 26, draw: draw }; @@ -20,4 +19,4 @@ }, 35E3); }); -})(); \ No newline at end of file +})(); diff --git a/apps/widid/widget.js b/apps/widid/widget.js index e97eecb65..68917c65a 100644 --- a/apps/widid/widget.js +++ b/apps/widid/widget.js @@ -1,9 +1,7 @@ /* jshint esversion: 6 */ (() => { - var id = NRF.getAddress().substr().substr(12).split(":"); - - // draw your widget at xpos function draw() { + var id = NRF.getAddress().substr().substr(12).split(":"); g.reset().setColor(0, 0.5, 1).setFont("6x8", 1); g.drawString(id[0], this.x+2, this.y+4, true); g.drawString(id[1], this.x+2, this.y+14, true); diff --git a/apps/widtbat/widget.js b/apps/widtbat/widget.js index 8cc4b0c83..6d5aded8b 100644 --- a/apps/widtbat/widget.js +++ b/apps/widtbat/widget.js @@ -1,11 +1,10 @@ /* jshint esversion: 6 */ (() => { const CBS = 0x41f, CBC = 0x07E0; - var batS = require("heatshrink").decompress(atob("j0TwIHEv///kD////EfAYPwuEAgPB4EAg/HCgMfzgDBvwOC/IOC84ONDoUcFgc/AYOAHYRDE")); var xo = 6, xl = 22, yo = 9, h = 17; function draw() { - g.reset().setColor(CBS).drawImage(batS, this.x + 1, this.y + 4); + g.reset().setColor(CBS).drawImage(require("heatshrink").decompress(atob("j0TwIHEv///kD////EfAYPwuEAgPB4EAg/HCgMfzgDBvwOC/IOC84ONDoUcFgc/AYOAHYRDE")), this.x + 1, this.y + 4); g.setColor(0).fillRect(this.x + xo, this.y + yo, this.x + xl, this.y + h); var cbc = (Bangle.isCharging()) ? CBC : CBS; g.setColor(cbc).fillRect(this.x + xo, this.y + yo, this.x + (xl - xo) / 100 * E.getBattery() + xo, this.y + h); diff --git a/apps/widviz/widget.js b/apps/widviz/widget.js index 4282d4c96..241dabf61 100644 --- a/apps/widviz/widget.js +++ b/apps/widviz/widget.js @@ -1,34 +1,33 @@ (() => { var saved = null; - + function hide(){ if (!Bangle.isLCDOn() || saved) return; saved = []; for (var wd of WIDGETS) { - saved.push(wd.draw); + saved.push(wd.draw); wd.draw=()=>{}; } g.setColor(0,0,0); g.fillRect(0,0,239,23); } - + function reveal(){ if (!Bangle.isLCDOn() || !saved) return; for (var wd of WIDGETS) wd.draw = saved.shift(); - Bangle.drawWidgets(); + Bangle.drawWidgets(); saved=null; } - + function draw(){ - var img = E.toArrayBuffer(atob("GBgBAAAAAAAAAAAAAAAAAH4AAf+AB4HgDgBwHDw4OH4cMOcMYMMGYMMGMOcMOH4cHDw4DgBwB4HgAf+AAH4AAAAAAAAAAAAAAAAA")); g.setColor(0x07ff); - g.drawImage(img,this.x,this.y); + g.drawImage(atob("GBgBAAAAAAAAAAAAAAAAAH4AAf+AB4HgDgBwHDw4OH4cMOcMYMMGYMMGMOcMOH4cHDw4DgBwB4HgAf+AAH4AAAAAAAAAAAAAAAAA"),this.x,this.y); } - + WIDGETS["viz"] ={area:"tl", width:24,draw:draw}; Bangle.on('swipe',(dir)=>{ if (dir<0) hide(); else reveal(); - }); + }); })(); From 48c4b790264a51bf9090d648648abbd5858a9c81 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 May 2021 14:47:17 +0100 Subject: [PATCH 0057/2129] welcome 0.10: Tweaks to reduce memory usage --- apps.json | 2 +- apps/welcome/ChangeLog | 1 + apps/welcome/app.js | 63 ++++++++++++++++++++++-------------------- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/apps.json b/apps.json index 361a71779..89be44fcf 100644 --- a/apps.json +++ b/apps.json @@ -105,7 +105,7 @@ { "id": "welcome", "name": "Welcome", "icon": "app.png", - "version":"0.09", + "version":"0.10", "description": "Appears at first boot and explains how to use Bangle.js", "tags": "start,welcome", "allow_emulator":true, diff --git a/apps/welcome/ChangeLog b/apps/welcome/ChangeLog index 9545dbbfa..ce9194c5d 100644 --- a/apps/welcome/ChangeLog +++ b/apps/welcome/ChangeLog @@ -11,3 +11,4 @@ 0.09: Allow welcome to run after a fresh install More useful app menu BTN2 now goes to menu on release +0.10: Tweaks to reduce memory usage diff --git a/apps/welcome/app.js b/apps/welcome/app.js index 8cbdc2efa..565e87d5d 100644 --- a/apps/welcome/app.js +++ b/apps/welcome/app.js @@ -11,7 +11,7 @@ function animate(seq,period) { // Fade in to FG color with angled lines function fade(callback) { var n = 0; - function f() { + function f() {"ram" for (var i=n;i<240;i+=10) { g.drawLine(i,0,0,i); g.drawLine(i,240,240,i); @@ -24,16 +24,17 @@ function fade(callback) { f(); } - -var scenes = [ - function() { +var SCENE_COUNT=11; +function getScene(n) { + if (n==0) return function() { g.clear(1); g.setFont("4x6",2); var n=0; + var l = Bangle.getLogo(); var i = setInterval(function() { n+=0.04; g.setColor(n,n,n); - g.drawImage(Bangle.getLogo(),(240-222)/2,(240-100)/2); + g.drawImage(l,(240-222)/2,(240-100)/2); if (n>=1) { clearInterval(i); setTimeout(()=>g.drawString("Open",34,144), 500); @@ -41,7 +42,8 @@ var scenes = [ setTimeout(()=>g.drawString("Smart Watch",34,168), 1500); } },50); - },function() { + }; + if (n==1) return function() { var img = require("heatshrink").decompress(atob("ptRxH+qYAfvl70mj5gAC0ekvd8FkAAdz3HJAYAH4+eJXWkJJYAF0hK2vfNJaIAB5t7S3fN5/V6wAD6vOTg9SumXy2W3QAB3eXul2JdnO63XAApPEVYvAJQIACJoRQDzBLoJQ3W5/NIwr4GJohMFAAROgJYvVJQiPGABZNN3bsdvYyESwnWJSIAC3RNM3V1JjZAES4nVJSYAB4xMNJrbkE56WD5xLVdB5NbFofNJbgABJh26qREPrFXrlbAAWjFgfWJgRLaTQhMLy5KNJINhsJLDrYrD5xLC6pLa5nGTR7oLq9bJQJMKTAXWJbbnR3RLJSoRMHv4pC5rkec6SaIrBLGw2r2XW1epcoqYeJiOXJYziEsOH2RBBw7lF56Yg5nGc6FScZOGJQPX2TmDFIfVTEBMSc4hLEw5KB6+rsJMH63X6pMf5hMQzBLCq5LD1ZLEJhTlfJiWXTA2GJYpMIcwPNc2O6TAuGRIPX1igDJg/PJmyYDcgXWwxMH1ApC53XcsHAJiVYcg2HJYZME0YpC5vWJkhLNJgLlDTAeFJhF/FQfVJkG6JiGXcomyJgOrJYhMErYqD53NJj7lRzBMDcoeGJhzoBJb3GJiN1qZBCJgWyJYpNF1LigAAXAJiNSJgzlGJgt/JkZLRy9TJgeHJhznFcuSZGw5MHJomjcuhLBqdcJiSaiTChMV1CYxy5LCqdXIAWy6+rJhCalTCN2JgdYH4WHJiGpTF7kDc43W2RMJTUZLQzBLFc4mr6+GJh2jTFmXJYyaEwuyc5Sag4xLZTQmG2WFJhxNaJYZMLJZSaEJoOHTR9/Ja+6JbdTqRNETRRNF1JLV4BLcAANYI5ToK1BLYJhWYJZwABq5NoJZ91JaAABdAZNS0ZLey9SJaRNYv5KM426JZmXuxKUJrKcL0lTzBLKzBKYJrVXvfGSol7EYWXJI27zF1JLQADq5NUrgYB4wAEEIV0comXI7wAFrCcPJgYWBTIIAETIN2JYmWuhMkdSdYCgOeJgueqRLFyzhfTi9bq4TC45MF49TuuXJlpONcogAC0hKB0gHDvZMEqRMpAANSq9crlbJAYADqwRDxGk0mIA4eCTQOeveXJdYAHqxNFdAeIAAQGCrOI0oHEAGVXTRJMGvgGCwRM7TAZMHwQGCvhM1rBMERIhMGAwdZJmtSqVTwNcwJEDJg19cvIADa4d9JhANDJnSLHJgrl6AAhFFAwpZDegjn7vhMGcvwABrJAFJgjl/TQpBBI4jl/AAN8TQhHDcv4ADcJBMDvpM+IYaeDAAhL+qd9SgycEJn7iEAA18Jf7nEcv4AIrJLIcv6aMcv4ADvhMHrJJ/AAbl/c6ZM/AAt9cv7nSIv7nLcv4AHrLl/TRpJBvgnjA==")); g.reset(); g.setColor("#6633ff"); @@ -73,7 +75,8 @@ var scenes = [ },20); },3500); - },function() { + }; + if (n==2) return function() { g.reset(); g.setBgColor("#ffa800");g.clear(); g.setFont("6x8",2); @@ -88,8 +91,8 @@ var scenes = [ ()=>g.drawString("2",200,120), ()=>g.drawString("3",200,200) ],200); - }, - function() { + }; + if (n==3) return function() { g.reset(); g.setBgColor("#00a8ff");g.clear(); g.setFontAlign(0,0); @@ -98,8 +101,8 @@ var scenes = [ g.setFontAlign(-1,-1); g.setFont("6x8",2); g.drawString("Move up\nin menus\n\nTurn Bangle.js on\nif it was off", 20,40); - }, - function() { + }; + if (n==4) return function() { g.reset(); g.setBgColor("#00a8ff");g.clear(); g.setFontAlign(0,0); @@ -108,8 +111,8 @@ var scenes = [ g.setFontAlign(-1,-1); g.setFont("6x8",2); g.drawString("Select menu\nitem\n\nLaunch app\nwhen watch\nis showing", 20,70); - }, - function() { + }; + if (n==5) return function() { g.reset(); g.setBgColor("#00a8ff");g.clear(); g.setFontAlign(0,0); @@ -118,8 +121,8 @@ var scenes = [ g.setFontAlign(-1,-1); g.setFont("6x8",2); g.drawString("Move down\nin menus\n\nLong press\nto exit app\nand go back\nto clock", 20,100); - }, - function() { + }; + if (n==6) return function() { g.reset(); g.setBgColor("#ff3300");g.clear(); g.setFontAlign(0,0); @@ -129,8 +132,8 @@ var scenes = [ g.setFontAlign(-1,-1); g.setFont("6x8",2); g.drawString("If Bangle.js\never stops,\nhold buttons\n1 and 2 for\naround six\nseconds.\n\n\n\nBangle.js will\nthen reboot.", 20,20); - }, - function() { + }; + if (n==7) return function() { g.reset(); g.setBgColor("#00a8ff");g.clear(); g.setFont("6x8",2); @@ -147,8 +150,8 @@ var scenes = [ g.drawString("work too. Try now",x,y+=h); g.drawString("to change page.",x,y+=h);} ],300); - }, - function() { + }; + if (n==8) return function() { g.reset(); g.setBgColor("#339900");g.clear(); g.setFont("6x8",2); @@ -165,8 +168,8 @@ var scenes = [ g.drawString("with a Bluetooth",x,y+=h); g.drawString("capable device",x,y+=h);}, ],400); - }, - function() { + }; + if (n==9) return function() { g.reset(); g.setBgColor("#990066");g.clear(); g.setFont("6x8",2); @@ -227,8 +230,8 @@ var scenes = [ } setInterval(draw,50); - }, - function() { + }; + if (n==10) return function() { g.reset(); g.setBgColor("#660099");g.clear(); g.setFontAlign(0,0); @@ -245,18 +248,18 @@ var scenes = [ g.drawString("Bangle.js",x,y+=h);} ],400); } -]; +} var sceneNumber = 0; function move(dir) { - if (dir>0 && sceneNumber+1 == scenes.length) return; // at the end - sceneNumber = (sceneNumber+dir)%scenes.length; + if (dir>0 && sceneNumber+1 == SCENE_COUNT) return; // at the end + sceneNumber = (sceneNumber+dir)%SCENE_COUNT; if (sceneNumber<0) sceneNumber=0; clearInterval(); - scenes[sceneNumber](); + getScene(sceneNumber)(); if (sceneNumber>1) { - var l = scenes.length; + var l = SCENE_COUNT; for (var i=0;imove(1), BTN3, {repeat:true}); setWatch(()=>{ // If we're on the last page - if (sceneNumber == scenes.length-1) { + if (sceneNumber == SCENE_COUNT-1) { load(); } }, BTN2, {repeat:true,edge:"falling"}); From d92855a4c644e1a6c0eadf7b65e1c5b6be5b4d75 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 May 2021 14:50:52 +0100 Subject: [PATCH 0058/2129] Revert softOff as it seems broken on Bangle.js --- apps.json | 2 +- apps/setting/ChangeLog | 1 - apps/setting/settings.js | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 89be44fcf..3dcd90802 100644 --- a/apps.json +++ b/apps.json @@ -172,7 +172,7 @@ { "id": "setting", "name": "Settings", "icon": "settings.png", - "version":"0.26", + "version":"0.25", "description": "A menu for setting up Bangle.js", "tags": "tool,system", "readme": "README.md", diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 00d11d562..771ce1d4a 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -28,4 +28,3 @@ 0.23: Change max time offset to 13 for NZ summer daylight time (NZDT) 0.24: Add Quiet Mode settings 0.25: Move boot.js code into 'boot' app itself -0.26: Use Bangle.softOff if available as this keeps the time diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 12448d463..a4c1aa009 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -115,7 +115,7 @@ function showMainMenu() { 'Set Time': ()=>showSetTimeMenu(), 'LCD': ()=>showLCDMenu(), 'Reset Settings': ()=>showResetMenu(), - 'Turn Off': ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() }, + 'Turn Off': ()=>{ Bangle.off(); }, '< Back': ()=>load() }; return E.showMenu(mainmenu); From d570261e475420da67f8cd03fb7f88e3ce780285 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 28 May 2021 19:41:33 +0100 Subject: [PATCH 0059/2129] Revert "Revert softOff as it seems broken on Bangle.js" - fixed! https://github.com/espruino/Espruino/issues/2011 This reverts commit d92855a4c644e1a6c0eadf7b65e1c5b6be5b4d75. --- apps.json | 2 +- apps/setting/ChangeLog | 1 + apps/setting/settings.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 3dcd90802..89be44fcf 100644 --- a/apps.json +++ b/apps.json @@ -172,7 +172,7 @@ { "id": "setting", "name": "Settings", "icon": "settings.png", - "version":"0.25", + "version":"0.26", "description": "A menu for setting up Bangle.js", "tags": "tool,system", "readme": "README.md", diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 771ce1d4a..00d11d562 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -28,3 +28,4 @@ 0.23: Change max time offset to 13 for NZ summer daylight time (NZDT) 0.24: Add Quiet Mode settings 0.25: Move boot.js code into 'boot' app itself +0.26: Use Bangle.softOff if available as this keeps the time diff --git a/apps/setting/settings.js b/apps/setting/settings.js index a4c1aa009..12448d463 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -115,7 +115,7 @@ function showMainMenu() { 'Set Time': ()=>showSetTimeMenu(), 'LCD': ()=>showLCDMenu(), 'Reset Settings': ()=>showResetMenu(), - 'Turn Off': ()=>{ Bangle.off(); }, + 'Turn Off': ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() }, '< Back': ()=>load() }; return E.showMenu(mainmenu); From d49a22a990a33c531e08dfd8603d9f85db3aa563 Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Sun, 30 May 2021 20:40:56 +0200 Subject: [PATCH 0060/2129] trex: enabling move left and right --- apps/trex/trex.js | 4 ++-- core | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/trex/trex.js b/apps/trex/trex.js index fe84cb31a..642c10054 100644 --- a/apps/trex/trex.js +++ b/apps/trex/trex.js @@ -9,8 +9,8 @@ g.flip = function() { },0,(240-128)/2,{scale:2}); }; var W = g.getWidth(); -var BTNL = BTN4; -var BTNR = BTN5; +var BTNL = BTN2; +var BTNR = BTN3; var BTNU = BTN1; // Images can be added like this in Espruino v2.00 diff --git a/core b/core index 3f2ff467f..0ba4c2bd5 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 3f2ff467f22b746da94160e59ff89b621601b261 +Subproject commit 0ba4c2bd5503264279222b04a41505471c6622ff From f7dd6badd325cc1dbdecf3a154d98c6ed276da0a Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 2 Jun 2021 23:30:42 +0100 Subject: [PATCH 0061/2129] kitchen detect missing waypoint.json file --- apps.json | 2 +- apps/arrow/README.md | 4 ++++ apps/kitchen/ChangeLog | 1 + apps/kitchen/README.md | 3 +++ apps/kitchen/annex.js | 29 +++++++++++++++++++++++++++++ apps/kitchen/compass.kit.js | 17 +++-------------- apps/kitchen/kitchen.app.js | 36 +++++++++++++++++------------------- 7 files changed, 58 insertions(+), 34 deletions(-) create mode 100644 apps/kitchen/annex.js diff --git a/apps.json b/apps.json index e4da83e7f..ade2f6502 100644 --- a/apps.json +++ b/apps.json @@ -3085,7 +3085,7 @@ { "id": "kitchen", "name": "Kitchen Combo", "icon": "kitchen.png", - "version":"0.10", + "version":"0.11", "description": "Combination of the Stepo, Walkersclock, Arrow and Waypointer apps into a multiclock format. 'Everything but the kitchen sink'. Requires firmware v2.08.167 or later", "tags": "tool,outdoors,gps", "type":"clock", diff --git a/apps/arrow/README.md b/apps/arrow/README.md index 3b439711c..4b77dbc42 100644 --- a/apps/arrow/README.md +++ b/apps/arrow/README.md @@ -36,6 +36,10 @@ charge. *BTN3* - invokes calibration ( can be cancelled if pressed accidentally) +## Issues +* detect when calibration data is missing + ## Acknowledgement This app is based in the work done by [jeffmer](https://github.com/jeffmer/JeffsBangleAppsDev) + diff --git a/apps/kitchen/ChangeLog b/apps/kitchen/ChangeLog index 71548ec30..ea42a3f11 100644 --- a/apps/kitchen/ChangeLog +++ b/apps/kitchen/ChangeLog @@ -8,3 +8,4 @@ 0.08: Improved error handling for missing firmware features, added template app.kit.js 0.09: Added heart rate monitor app 0.10: Converted Stepo to use direct screen writes, added a Trip Counter feature to stepo +0.11: Detect when waypoints.json is not present, error E-WPT diff --git a/apps/kitchen/README.md b/apps/kitchen/README.md index a829a39b0..d847adabc 100644 --- a/apps/kitchen/README.md +++ b/apps/kitchen/README.md @@ -244,6 +244,7 @@ The following error codes will be displayed if one of the dependancies is not me * E-STEPS - no pedomintor widget has been installed, please install the widpedom or the activepedom widgets * E-CALIB - no compass calibration data was found, see 'Compass Calibration' * E-FW - require firmware 2v08.187 or later to detect gps and compass power status +* E-WPT - missing waypoints.json file ### Issues / Future enhancements @@ -254,3 +255,5 @@ The following error codes will be displayed if one of the dependancies is not me seconds after the LCD goes off. At present I just rely on using the GPSSetup app and set the GPS power mode that I want. * Add a small graph to the heart rate monitor app +* Add a facility to call the Arrow calibration process +* Maybe create waypoints.json file if missing diff --git a/apps/kitchen/annex.js b/apps/kitchen/annex.js new file mode 100644 index 000000000..d789f5d0c --- /dev/null +++ b/apps/kitchen/annex.js @@ -0,0 +1,29 @@ +// annexed code that might be worth keeping + +/***************************************************************************** + +Screen Buffer Object that can be shared between faces + +Making into a Class like this means we allocate the memory once +and avoid fragmenting the memory when we switch in and out of faces + +******************************************************************************/ + +function BUF() { + this.pal4color = new Uint16Array([0x0000,0xFFFF,0x7BEF,0xAFE5],0,2); // b,w,grey,greenyellow + this.pal4red = new Uint16Array([0x0000,0xFFFF,0xF800,0xAFE5],0,2); // b,w,red,greenyellow + this.buf = Graphics.createArrayBuffer(120,120,2,{msb:true}); +} + +BUF.prototype.flip = function(x,y) { + g.drawImage({width:120,height:120,bpp:2, buffer:this.buf.buffer, palette:this.pal4color}, x, y); + this.buf.clear(); +} + +BUF.prototype.flip_red = function(x,y) { + g.drawImage({width:120,height:120,bpp:2, buffer:this.buf.buffer, palette:this.pal4red}, x, y); + this.buf.clear(); +} + +let bufObj = new BUF(); + diff --git a/apps/kitchen/compass.kit.js b/apps/kitchen/compass.kit.js index 530ba021c..b20cdce2c 100644 --- a/apps/kitchen/compass.kit.js +++ b/apps/kitchen/compass.kit.js @@ -17,13 +17,12 @@ } function init(gps,sw, hrm) { - showMem("compass init() START"); gpsObject = gps; intervalRefSec = undefined; bearing = 0; // always point north if GPS is off heading = 0; oldHeading = 0; - previous = {hding:"-", bs:"-", dst:"-", wp_name:"-", course:999}; + resetPrevious(); loc = require("locale"); CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; getWaypoint(); @@ -34,12 +33,9 @@ */ if (!Bangle.isCompassOn()) Bangle.setCompassPower(1); gps.determineGPSState(); - - showMem("compass init() END"); } function freeResources() { - showMem("compass freeResources() START"); gpsObject = undefined; intervalRefSec = undefined; previous = undefined; @@ -50,7 +46,6 @@ CALIBDATA = undefined; wp = undefined; if (Bangle.isCompassOn !== undefined && Bangle.isCompassOn()) Bangle.setCompassPower(0); - showMem("compass freeResources() END"); } function startTimer() { @@ -67,12 +62,6 @@ if (Bangle.isCompassOn !== undefined && Bangle.isCompassOn()) Bangle.setCompassPower(0); } - function showMem(msg) { - var val = process.memory(); - var str = msg + " " + Math.round(val.usage*100/val.total) + "%"; - log_debug(str); - } - function onButtonShort(btn) { log_debug("onButtonShort()"); if (gpsObject.getState() !== gpsObject.GPS_RUNNING) return; @@ -206,12 +195,12 @@ drawCompass(dir, 0xFFC0); // yellow oldHeading = dir; } - + if (gpsObject.getState() === gpsObject.GPS_RUNNING) { drawGPSData(); } else { drawCompassHeading(); - } + } } // only used when acting as compass with GPS off diff --git a/apps/kitchen/kitchen.app.js b/apps/kitchen/kitchen.app.js index c3f7bd74d..fcaa048bb 100644 --- a/apps/kitchen/kitchen.app.js +++ b/apps/kitchen/kitchen.app.js @@ -33,10 +33,10 @@ function nextFace(){ // when you feel the buzzer you know you have done a long press function longPressCheck() { Bangle.buzz(); - debug_log("long PressCheck() buzz"); + debug_log("BUZZ, long press"); if (pressTimer) { clearInterval(pressTimer); - debug_log("clear pressTimer 2"); + debug_log("CLEAR pressTimer 2"); pressTimer = undefined; } } @@ -48,10 +48,10 @@ function buttonPressed(btn) { } else { firstPress = getTime(); if (pressTimer) { - debug_log("clear pressTimer 1"); + debug_log("CLEAR pressTimer 1"); clearInterval(pressTimer); } - debug_log("set pressTimer 1"); + debug_log("SET pressTimer 1"); pressTimer = setInterval(longPressCheck, 1500); } } @@ -60,7 +60,7 @@ function buttonPressed(btn) { function buttonReleased(btn) { var dur = getTime() - firstPress; if (pressTimer) { - debug_log("clear pressTimer 3"); + debug_log("CLEAR pressTimer 3"); clearInterval(pressTimer); pressTimer = undefined; } @@ -256,7 +256,7 @@ GPS.prototype.processFix = function(fix) { this.gpsState = this.GPS_RUNNING; if (!this.last_fix.fix && !(require("Storage").readJSON("setting.json", 1) || {}).quiet) { Bangle.buzz(); // buzz on first position - debug_log("GPS fix buzz"); + debug_log("BUZZ - gps fix"); } this.last_fix = fix; } @@ -303,7 +303,7 @@ GPS.prototype.getWPdistance = function() { //log_debug(this.last_fix); //log_debug(this.wp_current); - if (this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) + if (this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) return 0; else return this.calcDistance(this.last_fix, this.wp_current); @@ -313,14 +313,14 @@ GPS.prototype.getWPbearing = function() { //log_debug(this.last_fix); //log_debug(this.wp_current); - if (this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) + if (this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) return 0; else return this.calcBearing(this.last_fix, this.wp_current); } GPS.prototype.loadFirstWaypoint = function() { - var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}]; + var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}]; this.wp_index = 0; this.wp_current = waypoints[this.wp_index]; log_debug(this.wp_current); @@ -332,7 +332,7 @@ GPS.prototype.getCurrentWaypoint = function() { } GPS.prototype.waypointHasLocation = function() { - if (this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) + if (this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE" || this.wp_current.lat === undefined || this.wp_current.lat === 0) return false; else return true; @@ -340,12 +340,12 @@ GPS.prototype.waypointHasLocation = function() { GPS.prototype.markWaypoint = function() { - if(this.wp_current.name === "NONE") + if(this.wp_current.name === "E-WPT" || this.wp_current.name === "NONE") return; log_debug("GPS::markWaypoint()"); - var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}]; + var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}]; this.wp_current = waypoints[this.wp_index]; if (this.waypointHasLocation()) { @@ -360,7 +360,7 @@ GPS.prototype.markWaypoint = function() { } GPS.prototype.nextWaypoint = function(inc) { - var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"NONE"}]; + var waypoints = require("Storage").readJSON("waypoints.json")||[{name:"E-WPT"}]; this.wp_index+=inc; if (this.wp_index>=waypoints.length) this.wp_index=0; if (this.wp_index<0) this.wp_index = waypoints.length-1; @@ -731,14 +731,14 @@ function TRIP() { TRIP.prototype.resetTrip = function(steps) { this.tripStart = (0 + steps); - console.log("resetTrip starting=" + this.tripStart); + log_debug("resetTrip starting=" + this.tripStart); } TRIP.prototype.getTrip = function(steps) { let tripSteps = (0 + steps) - this.tripStart; - console.log("getTrip steps=" + steps); - console.log("getTrip tripStart=" + this.tripStart); - console.log("getTrip=" + tripSteps); + log_debug("getTrip steps=" + steps); + log_debug("getTrip tripStart=" + this.tripStart); + log_debug("getTrip=" + tripSteps); return tripSteps; } @@ -758,7 +758,6 @@ Debug Object ******************************************************************************/ -/* function DEBUG() { this.logfile = require("Storage").open("debug.log","a"); } @@ -770,7 +769,6 @@ DEBUG.prototype.log = function(msg) { } debugObj = new DEBUG(); -*/ function debug_log(m) { //debugObj.log(m); From d68a7c66303451b8c6a24cef804ac6cd9d4464e0 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 2 Jun 2021 23:42:22 +0100 Subject: [PATCH 0062/2129] kitchen remove heart.kit.js from the install config in apps.json --- apps.json | 1 - apps/kitchen/README.md | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index c1e727abd..8e3446543 100644 --- a/apps.json +++ b/apps.json @@ -3146,7 +3146,6 @@ {"name":"stepo.kit.js","url":"stepo.kit.js"}, {"name":"gps.kit.js","url":"gps.kit.js"}, {"name":"digi.kit.js","url":"digi.kit.js"}, - {"name":"heart.kit.js","url":"heart.kit.js"}, {"name":"swatch.kit.js","url":"swatch.kit.js"}, {"name":"compass.kit.js","url":"compass.kit.js"}, {"name":"kitchen.img","url":"kitchen.icon.js","evaluate":true} diff --git a/apps/kitchen/README.md b/apps/kitchen/README.md index d847adabc..ef8ee826f 100644 --- a/apps/kitchen/README.md +++ b/apps/kitchen/README.md @@ -76,6 +76,9 @@ The following buttons depend on which face is currently in use ## Heart ![](screenshot_heart.jpg) - A simple heart rate monitor, at present the app is just showing the raw value from HRM.bpm +- This is an experimental app and not installed by default. The + heart.kit.js file can be uploaded via the Espruino IDE if you want + to try it out. Then reload the App. - BTN1, long press, turn heart rate monitor on / off ## Waypointer From 5055333b30c7e67b97b600adbb5c7230eb74d1e0 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Fri, 4 Jun 2021 22:47:32 +0100 Subject: [PATCH 0063/2129] kitchen - corrections to README file --- apps/kitchen/README.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/kitchen/README.md b/apps/kitchen/README.md index ef8ee826f..502ec1a7f 100644 --- a/apps/kitchen/README.md +++ b/apps/kitchen/README.md @@ -229,12 +229,12 @@ I have settled on directly writing to the screen using the Graphics object (g.) for the compass App. This creates a bit of flicker when the arrow moves but is more reliable than using the ArrayBuffer. -v0.09: Since adding the heart rate monitor I have noticed that I can -sometimes can a memory error when switch through the Apps back to the -Stepo App. I think this can be cured by statically allocating the -ArrayBuffer for stepo rather than using new everytime you switch back -into the stepo watch face. The problem is that the bangle memory -management / defragmentation is quite slow to run. +v0.09: Since adding the heart rate monitor I have sometimes observed +a low memory error when switching through the Apps back to the Stepo +App. I think this can be cured by statically allocating the +ArrayBuffer for stepo rather than using 'new' everytime you switch +back into the stepo watch face. The problem is that the bangle +memory management / defragmentation is quite slow to run. v0.10: Revisited having a display buffer for the stepo part of the App. Now use direct screen writing as it means less memory allocation and @@ -244,10 +244,13 @@ reduces chance of getting a memory error on switching watch faces. The following error codes will be displayed if one of the dependancies is not met. -* E-STEPS - no pedomintor widget has been installed, please install the widpedom or the activepedom widgets -* E-CALIB - no compass calibration data was found, see 'Compass Calibration' -* E-FW - require firmware 2v08.187 or later to detect gps and compass power status -* E-WPT - missing waypoints.json file +* E-STEPS - no pedomintor widget has been installed, please install + the widpedom or the activepedom widgets +* E-CALIB - no compass calibration data was found, see 'Compass + Calibration' +* E-FW - require firmware 2v08.187 or later to detect gps and compass + power status +* E-WPT - missing waypoints.json file ### Issues / Future enhancements From 5dad6caa1d4765d755f23f7731b5f86e45ae7a04 Mon Sep 17 00:00:00 2001 From: Eric Woodward Date: Sat, 5 Jun 2021 16:39:30 -0400 Subject: [PATCH 0064/2129] Add Mystic Dock v1.00 --- apps.json | 15 ++ apps/mysticdock/ChangeLog | 1 + apps/mysticdock/README.md | 43 +++++ apps/mysticdock/mystic-dock-app.js | 247 ++++++++++++++++++++++++ apps/mysticdock/mystic-dock-boot.js | 1 + apps/mysticdock/mystic-dock-icon.js | 1 + apps/mysticdock/mystic-dock-settings.js | 48 +++++ apps/mysticdock/mystic-dock.png | Bin 0 -> 1823 bytes 8 files changed, 356 insertions(+) create mode 100644 apps/mysticdock/ChangeLog create mode 100644 apps/mysticdock/README.md create mode 100644 apps/mysticdock/mystic-dock-app.js create mode 100644 apps/mysticdock/mystic-dock-boot.js create mode 100644 apps/mysticdock/mystic-dock-icon.js create mode 100644 apps/mysticdock/mystic-dock-settings.js create mode 100644 apps/mysticdock/mystic-dock.png diff --git a/apps.json b/apps.json index 89be44fcf..01fa1c5e2 100644 --- a/apps.json +++ b/apps.json @@ -3258,5 +3258,20 @@ {"name":"gbtwist.app.js","url":"app.js"}, {"name":"gbtwist.img","url":"app-icon.js","evaluate":true} ] +}, +{ "id": "mysticdock", + "name": "Mystic Dock", + "icon": "mystic-dock.png", + "version":"1.0", + "description": "A retro-inspired dockface that displays the current time and battery charge while plugged in, and which features an interactive mode that shows the time, date, and a rotating data display line.", + "tags": "dock", + "type":"dock", + "readme": "README.md", + "storage": [ + {"name":"mysticdock.app.js","url":"mystic-dock-app.js"}, + {"name":"mysticdock.boot.js","url":"mystic-dock-boot.js"}, + {"name":"mysticdock.settings.js","url":"mystic-dock-settings.js"}, + {"name":"mysticdock.img","url":"mystic-dock-icon.js","evaluate":true} + ] } ] diff --git a/apps/mysticdock/ChangeLog b/apps/mysticdock/ChangeLog new file mode 100644 index 000000000..34fe53627 --- /dev/null +++ b/apps/mysticdock/ChangeLog @@ -0,0 +1 @@ +1.00: First published version. diff --git a/apps/mysticdock/README.md b/apps/mysticdock/README.md new file mode 100644 index 000000000..09e81ba09 --- /dev/null +++ b/apps/mysticdock/README.md @@ -0,0 +1,43 @@ +# Mystic Dock for Bangle.js + +A retro-inspired dockface that displays the current time and battery charge while plugged in, and which features an interactive mode that shows the time, date, and a rotating data display line. + +## Features + +- Screensaver-like dock mode while charging (displays the current time for 8 seconds and a blank screen for 2, changing text placement with each draw) +- 24 or 12-hour time (adjustable via the Settings menu) +- Variable colors (also in the Settings) +- Interactive watchface display (use upper and lower watch-buttons to activate it and rotate between values at the bottom) +- International localization of watchface date (which can be disabled via the Settings if memory becomes an issue) +- Automatic watchface reload when unplugged (toggleable via the Settings menu) +- Rotates display 90 degrees if it detects it is sideways (for use in a charging dock) + +When in interactive display mode, the bottom line rotates between the following items: + +- Current time zone +- Battery charge level +- Device ID (derived from the last 4 of the MAC) +- Memory usage +- Firmware version + + +## Inspirations + +- [Bluetooth Dock](https://github.com/espruino/BangleApps/tree/master/apps/bluetoothdock) +- [CLI Clock](https://github.com/espruino/BangleApps/tree/master/apps/cliock) +- [Dev Clock](https://github.com/espruino/BangleApps/tree/master/apps/dclock) +- [Digital Clock](https://github.com/espruino/BangleApps/tree/master/apps/digiclock) +- [Simple Clock](https://github.com/espruino/BangleApps/tree/master/apps/sclock) +- [Simplest Clock](https://github.com/espruino/BangleApps/tree/master/apps/simplest) + +Icon adapted from [this one](https://publicdomainvectors.org/en/free-clipart/Digital-clock-display-vector-image/10845.html) and [this one](https://publicdomainvectors.org/en/free-clipart/Vector-image-of-power-manager-icon/20141.html) from [Public Domain Vectors](https://publicdomainvectors.org). + + +## Changelog + +- 1.00: First published version. (June 2021) + + +## Author + +Eric Wooodward https://itsericwoodward.com/ diff --git a/apps/mysticdock/mystic-dock-app.js b/apps/mysticdock/mystic-dock-app.js new file mode 100644 index 000000000..2e6fdafc5 --- /dev/null +++ b/apps/mysticdock/mystic-dock-app.js @@ -0,0 +1,247 @@ +/** + * Mystic Dock for Bangle.js + * + * + Original Author: Eric Wooodward https://itsericwoodward.com/ + * + see README.md for details + */ + +/* jshint esversion: 6 */ + +const timeFontSize = 6; +const dataFontSize = 2; +const font = "6x8"; + +const xyCenter = g.getWidth() / 2; + +const ypos = [ + 45, // Time + 105, // Date + 145, // Symbol + 210 // Info +]; + +const settings = require('Storage').readJSON('mysticdock.json', 1) || + require('Storage').readJSON('mysticclock.json', 1) || {}; +const colors = ['white', 'blue', 'green', 'purple', 'red', 'teal', 'other']; +const color = settings.color ? colors[settings.color] : 0; + +const yposMax = 190; +const yposMin = 60; +let y = yposMax; + +let lastButtonPressTime; +let wasInActiveMode = false; + + +const infoData = { + '*GMT_MODE': { + calc: () => (new Date()).toString().split(" ")[5], + }, + BATT_MODE: { + calc: () => `BATT: ${E.getBattery()}%`, + }, + ID_MODE: { + calc: () => { + const val = NRF.getAddress().split(":"); + return `ID: ${val[4]}${val[5]}`; + }, + }, + MEM_MODE: { + calc: () => { + const val = process.memory(); + return `MEM: ${Math.round(val.usage * 100 / val.total)}%`; + }, + }, + VER_MODE: { + calc: () => `FW: ${process.env.VERSION}`, + }, +}; +const infoList = Object.keys(infoData).sort(); +let infoMode = infoList[0]; + + +function setColor() { + const colorCommands = { + white: () => g.setColor(1, 1, 1), + blue: () => g.setColor(0, 0, 1), + green: () => g.setColor(0, 1, 0), + purple: () => g.setColor(1, 0, 1), + red: () => g.setColor(1, 0, 0), + teal: () => g.setColor(0, 1, 1), + other: () => g.setColor(1, 1, 0) + }; + + // default if value unknown + if (!color || !colorCommands[color]) return colorCommands.white(); + return colorCommands[color](); +} + + +function drawInfo() { + if (infoData[infoMode] && infoData[infoMode].calc) { + // clear info + g.setColor(0, 0, 0); + g.fillRect(0, ypos[3] - 8, 239, ypos[3] + 25); + + // draw info + g.setFont(font, dataFontSize); + setColor(); + g.drawString((infoData[infoMode].calc()), xyCenter, ypos[3], true); + } +} + +function drawImage() { + setColor(); + g.drawPoly([xyCenter - 100, ypos[2], xyCenter + 100, ypos[2], xyCenter, ypos[2] + 30], true); +} + +function drawClock() { + + // default draw styles + g.reset(); + + // get date + const d = new Date(); + const dLocal = d.toString().split(" "); + + const minutes = (`0${d.getMinutes()}`).substr(-2); + const seconds = (`0${d.getSeconds()}`).substr(-2); + + const useLocale = !settings.useLocale; + + let hours = (`0${d.getHours()}`).substr(-2); + let meridian = ""; + + if (d.getSeconds() % 10 === 0) { + y = Math.floor(Math.random() * (yposMax - yposMin)) + yposMin; + } + + // drawSting centered + g.setFontAlign(0, 0); + + // setup color + setColor(); + + if (settings.use12Hour) { + hours = parseInt(hours, 10); + meridian = 'AM'; + if (hours === 0) { + hours = 12; + } + else if (hours >= 12) { + meridian = 'PM'; + if (hours > 12) hours -= 12; + } + hours = (' ' + hours).substr(-2); + } + + g.setFont(font, timeFontSize); + + if (lastButtonPressTime && ((d.getTime() - lastButtonPressTime) / 1000) < 5) { + + // clear screen when switching modes + if (!wasInActiveMode) { + g.clear(); + wasInActiveMode = true; + } + + // draw clock in center w/ seconds + // show date (locale'd, based on settings) + // show info line below it + g.drawString(`${hours}${(d.getSeconds() % 2) ? ' ' : ':'}${minutes}`, xyCenter - 15, ypos[0], true); + g.setFont(font, dataFontSize); + + if (settings.use12Hour) { + g.drawString(seconds, xyCenter + 97, ypos[0] - 10, true); + g.drawString(meridian, xyCenter + 97, ypos[0] + 10, true); + } + else { + g.drawString(seconds, xyCenter + 97, ypos[0] + 10, true); + } + + // draw DoW, name of month, date, year + g.setFont(font, dataFontSize); + g.drawString([ + useLocale ? require('locale').dow(d, 1) : dLocal[0], + useLocale ? require('locale').month(d, 1) : dLocal[1], + d.getDate(), + d.getFullYear() + ].join(' '), xyCenter, ypos[1], true); + + drawInfo(); + drawImage(); + } + else if (d.getSeconds() % 10 === 8) { + g.clear(); + wasInActiveMode = false; + } + else if (d.getSeconds() % 10 !== 9) { + // clear screen when switching modes + if (wasInActiveMode) { + g.clear(); + wasInActiveMode = false; + } + g.drawString(`${hours}${(d.getSeconds() % 2) ? ' ' : ':'}${minutes}`, xyCenter - (settings.use12Hour ? 15 : 0), y, true); + g.setFont(font, dataFontSize); + if (settings.use12Hour) { + g.drawString(meridian, xyCenter + 97, y + 10, true); + } + g.drawString(`BATT: ${E.getBattery() === 100 ? '100' : ('0' + E.getBattery()).substr(-2)}%`, xyCenter, y + 35, true); + } + + g.flip(); +} + + +function nextInfo() { + lastButtonPressTime = Date.now(); + let idx = infoList.indexOf(infoMode); + + if (idx > -1) { + if (idx === infoList.length - 1) infoMode = infoList[0]; + else infoMode = infoList[idx + 1]; + } +} + + +function prevInfo() { + lastButtonPressTime = Date.now(); + let idx = infoList.indexOf(infoMode); + + if (idx > -1) { + if (idx === 0) infoMode = infoList[infoList.length - 1]; + else infoMode = infoList[idx - 1]; + } +} + + +if (Bangle.getAccel().x < -0.7) { + g.setRotation(3); // assume watch in charge cradle +} + +g.clear(); + +setInterval(drawClock, 1000); +drawClock(); + +if (Bangle.isCharging()) { + Bangle.on("charging", isCharging => { + const reloadOnUplug = !settings.reloadOnUplug; + + if (!isCharging && reloadOnUplug) load(); + }); +} + +// show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); + +// change to "active mode" and rotate through info when the buttons are pressed +setWatch(() => { + nextInfo(); + drawClock(); +}, BTN3, { repeat: true }); + +setWatch(() => { + prevInfo(); + drawClock(); +}, BTN1, { repeat: true }); diff --git a/apps/mysticdock/mystic-dock-boot.js b/apps/mysticdock/mystic-dock-boot.js new file mode 100644 index 000000000..7cb7fa8a4 --- /dev/null +++ b/apps/mysticdock/mystic-dock-boot.js @@ -0,0 +1 @@ +Bangle.on("charging", isCharging => { if (isCharging) load("mysticdock.app.js"); }); diff --git a/apps/mysticdock/mystic-dock-icon.js b/apps/mysticdock/mystic-dock-icon.js new file mode 100644 index 000000000..527825dd7 --- /dev/null +++ b/apps/mysticdock/mystic-dock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkBIf4A6g93u9gs4DCBBIAFu9ms9wAYYIJAAt2FAN2BYMHEwIIIAAkGBQV3AYNns1mBAwXGg4KCIgYTEBAZ2JCYQABBBIXJQoRcCBA0GDQpPCBAUGuwTBBAwfCUwgTDMoVmBA8GQIIXGWoJ9DBA4vHAAIOBcoYIHC4xqCCQR2BBBEGJAKSGAH4Adb4SIBDCYXCUwQwVDCjJCXYS/CDh4SCAAoxPDA72CPaQdCTB57CLgQYCGCIdFJJ4QFTIQXUGwpHQJAapQI4qQPCIqtDVCQECMCR5BJgN2bSArCuACCbSIRCIobZQOgZMCgx4OJIjvCCyAYCCYJMBYB4zHC6oA/AE4=")) diff --git a/apps/mysticdock/mystic-dock-settings.js b/apps/mysticdock/mystic-dock-settings.js new file mode 100644 index 000000000..7bfda1c0f --- /dev/null +++ b/apps/mysticdock/mystic-dock-settings.js @@ -0,0 +1,48 @@ +// make sure to enclose the function in parentheses +(function (back) { + + const settings = require('Storage').readJSON('mysticdock.json',1)||{}; + const colors = ['White', 'Blue', 'Green', 'Purple', 'Red', 'Teal', 'Yellow']; + const offon = ['Off','On']; + const onoff = ['On','Off']; + + function save(key, value) { + settings[key] = value; + require('Storage').writeJSON('mysticdock.json',settings); + } + + const appMenu = { + '': {'title': 'Dock Settings'}, + '< Back': back, + 'Color': { + value: 0|settings['color'], + min:0, + max:6, + format: m => colors[m], + onchange: m => {save('color', m)} + }, + '12 Hour Clock': { + value: 0|settings['use12Hour'], + min:0, + max:1, + format: m => offon[m], + onchange: m => {save('use12Hour', m)} + }, + 'Reload on Unplug': { + value: 0|settings['reloadOnUplug'], + min:0, + max:1, + format: m => onoff[m], + onchange: m => {save('reloadOnUplug', m)} + }, + 'Use Locale': { + value: 0|settings['useLocale'], + min:0, + max:1, + format: m => onoff[m], + onchange: m => {save('useLocale', m)} + }, + }; + E.showMenu(appMenu) + +}) diff --git a/apps/mysticdock/mystic-dock.png b/apps/mysticdock/mystic-dock.png new file mode 100644 index 0000000000000000000000000000000000000000..4c0dce770cbb8f4a948f5899d1683f3cd8d92aeb GIT binary patch literal 1823 zcmV+)2jKXLP)17B88s4*dWC02y>e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00xIiL_t(&-tC!xj9pa`$3HXY zzWw1AREp4oK-mJZKhy#?#qzUlO6yiykVt?KO-zx0s_=(IqXBIb6QiV2i#8T2H8Caz zL#a~R(q9w|*jmM`rnQ!~v{XuwE)Cm2*}Z4RKknOo_rAV%*WIwMO?Hx--22YG-*dim zX6DSy6KTddgGD*RWtc#{CFzsiIk{&8I&#m=Kuhkq3wY-P#Hl6HjMuzAiH9}88{RAR zUZu{G>jRRFe;!YECWY~2U*a;O3g^>!SX+hjPRaG_Ihj__8SsOS-4QD|&nNg1$2aG2CJTC{lFm#?wwH*Hr*I^P zb63FkJ9cLrpb0gDT&~!X6#r?3pKeh6HAm(N(hUA{hu3r8JSf<@+@viamkahxEaGfZ zY`-IO1scJBQHAqO!B)qCJF(m*NVDLpa+?!C#wzv?N3Ij>U~W=?nSz`x__L0DS>Ohc z+XZP7d}R)&0i;#&GLBc{d`^%Ng0J&I5V&6OHw<>>e!Lds9KqKca)sir6eo~rf**F+ z3gO!ca;2baG_&^CXf=(}MMsgayP~e!sOpsQ= z|LujZWxT*{gQm>fXgU>+LmSALli=*i9A3U8$W(<0bUK_X*!U30=~og-T|Gh_?uo?Jiuo_Ml1GQB-|gcJzm&inXULyhd)7F z65&$0Ghnaaa6M8Rw!L&dZL?H~263xuDauf-_36Wf5PT!%@e7;t)Ku{~cZo?SKpy zG{Xdj3z}2Z3JV08B((=S!4@05R$l_AcH)nLKB9zMk}O52&Y50!;?gvW9DX_y=#e=> zSQyapH7w4+wngH1BfN0B5-59%{6Go!1mq(pnw1}O?5T)-%d$*#o}hP^PtXzI?}G1j z?AHdXybc6vIVJukh4*T_a2(=qQ@U^IqI+Z)-E+H$Psc3b z1LRUAS(YFRr9L}Qkl7F(PS8o(TXm%mb>oko2rcs^D>+A1lDN1bV)w>Ehhu0DvbEsb zE19Bgi8U7w;Ey}$t=(BxS}tX+LgPEU!yObaFz7KJ*d z5)HZg!~J;Qz!q3WqDKkmN&N_TuGcA_>gPhP0sUe{>$ctMNZ`fFzsuJd;41)X4`rAwHH?3i2BQ$@&Cl z*Kqjzgm8QLn2r?Bh7}32u>Z?Cp(Y-byaaxhqgN^;bo_107StlpDCks0CWCKr!iofK)n4t}vxfiB zu?>b?CCCK=0yr}86JeC26UzSbVL@jFJQzITuwy8bx&Fu{*&ipq+hKKX0rv=DQ6;&vb|YSs z4skX*SeXFf#{v0-5}%0p!*+%d=v@u}cXQzM>I?aR;>2)gZkWJe Date: Sat, 5 Jun 2021 16:47:18 -0400 Subject: [PATCH 0065/2129] Add Mystic Clock v1.00 --- apps.json | 15 ++ apps/mysticclock/ChangeLog | 1 + apps/mysticclock/README.md | 40 ++++ apps/mysticclock/mystic-clock-app.js | 215 ++++++++++++++++++++++ apps/mysticclock/mystic-clock-icon.js | 1 + apps/mysticclock/mystic-clock-settings.js | 41 +++++ apps/mysticclock/mystic-clock.png | Bin 0 -> 981 bytes 7 files changed, 313 insertions(+) create mode 100644 apps/mysticclock/ChangeLog create mode 100644 apps/mysticclock/README.md create mode 100644 apps/mysticclock/mystic-clock-app.js create mode 100644 apps/mysticclock/mystic-clock-icon.js create mode 100644 apps/mysticclock/mystic-clock-settings.js create mode 100644 apps/mysticclock/mystic-clock.png diff --git a/apps.json b/apps.json index 89be44fcf..93d82c5b9 100644 --- a/apps.json +++ b/apps.json @@ -3258,5 +3258,20 @@ {"name":"gbtwist.app.js","url":"app.js"}, {"name":"gbtwist.img","url":"app-icon.js","evaluate":true} ] +}, +{ "id": "mysticclock", + "name": "Mystic Clock", + "icon": "mystic-clock.png", + "version":"1.00", + "description": "A retro-inspired watchface featuring time, date, and an interactive data display line.", + "tags": "clock", + "type":"clock", + "readme": "README.md", + "allow_emulator":true, + "storage": [ + {"name":"mysticclock.app.js","url":"mystic-clock-app.js"}, + {"name":"mysticclock.settings.js","url":"mystic-clock-settings.js"}, + {"name":"mysticclock.img","url":"mystic-clock-icon.js","evaluate":true} + ] } ] diff --git a/apps/mysticclock/ChangeLog b/apps/mysticclock/ChangeLog new file mode 100644 index 000000000..34fe53627 --- /dev/null +++ b/apps/mysticclock/ChangeLog @@ -0,0 +1 @@ +1.00: First published version. diff --git a/apps/mysticclock/README.md b/apps/mysticclock/README.md new file mode 100644 index 000000000..fd5bbb431 --- /dev/null +++ b/apps/mysticclock/README.md @@ -0,0 +1,40 @@ +# Mystic Clock for Bangle.js + +A retro-inspired watchface featuring time, date, and an interactive data display line. + +## Features + +- 24 or 12-hour time (adjustable via the Settings menu) +- Variable colors (also in the Settings) +- Interactive data display line (use upper and lower watch-buttons to rotate between values) +- Cover watch screen with your hand to put it to sleep (the watch, not your hand) +- International localization of date (which can be disabled via the Settings if memory becomes an issue) + +The interactive line rotates between the following items: + +- Current time zone +- Battery charge level +- Device ID (derived from the last 4 of the MAC) +- Memory usage +- Firmware version + + +## Inspirations + +- [CLI Clock](https://github.com/espruino/BangleApps/tree/master/apps/cliock) +- [Dev Clock](https://github.com/espruino/BangleApps/tree/master/apps/dclock) +- [Digital Clock](https://github.com/espruino/BangleApps/tree/master/apps/digiclock) +- [Simple Clock](https://github.com/espruino/BangleApps/tree/master/apps/sclock) +- [Simplest Clock](https://github.com/espruino/BangleApps/tree/master/apps/simplest) + +Icon adapted from [Public Domain Vectors](https://publicdomainvectors.org/en/free-clipart/Digital-clock-display-vector-image/10845.html). + + +## Changelog + +- 1.00: First published version. (June 2021) + + +## Author + +Eric Wooodward https://itsericwoodward.com/ diff --git a/apps/mysticclock/mystic-clock-app.js b/apps/mysticclock/mystic-clock-app.js new file mode 100644 index 000000000..22c2c8982 --- /dev/null +++ b/apps/mysticclock/mystic-clock-app.js @@ -0,0 +1,215 @@ +/** + * Mystic Clock for Bangle.js + * + * + Original Author: Eric Wooodward https://itsericwoodward.com/ + * + see README.md for details + */ + +/* jshint esversion: 6 */ + +const timeFontSize = 6; +const dataFontSize = 2; +const font = "6x8"; + +const xyCenter = g.getWidth() / 2; + +const yposTime = 75; +const yposDate = 125; +const yposSymbol = 160; +const yposInfo = 220; + +const settings = require('Storage').readJSON('mysticclock.json', 1) || {}; +const colors = ['white', 'blue', 'green', 'purple', 'red', 'teal', 'other']; +const color = settings.color ? colors[settings.color] : 0; + +const infoData = { + '*GMT_MODE': { + calc: () => (new Date()).toString().split(" ")[5], + }, + BATT_MODE: { + calc: () => `BATT: ${E.getBattery()}%`, + }, + ID_MODE: { + calc: () => { + const val = NRF.getAddress().split(":"); + return `ID: ${val[4]}${val[5]}`; + }, + }, + MEM_MODE: { + calc: () => { + const val = process.memory(); + return `MEM: ${Math.round(val.usage * 100 / val.total)}%`; + }, + }, + VER_MODE: { + calc: () => `FW: ${process.env.VERSION}`, + }, +}; +const infoList = Object.keys(infoData).sort(); +let infoMode = infoList[0]; + +function setColor() { + const colorCommands = { + white: () => g.setColor(1, 1, 1), + blue: () => g.setColor(0, 0, 1), + green: () => g.setColor(0, 1, 0), + purple: () => g.setColor(1, 0, 1), + red: () => g.setColor(1, 0, 0), + teal: () => g.setColor(0, 1, 1), + other: () => g.setColor(1, 1, 0) + }; + + // default if value unknown + if (!color || !colorCommands[color]) return colorCommands.white(); + return colorCommands[color](); +} + +function getLocale() { + return require('locale'); +} + +function drawClock() { + + // default draw styles + g.reset(); + + // drawSting centered + g.setFontAlign(0, 0); + + // setup color + setColor(); + + // get date + const d = new Date(); + const dLocal = d.toString().split(" "); + + const useLocale = !settings.useLocale; + + const minutes = (`0${d.getMinutes()}`).substr(-2); + const seconds = (`0${d.getSeconds()}`).substr(-2); + + let hours = (`0${d.getHours()}`).substr(-2); + let meridian = ""; + + if (settings.use12Hour) { + hours = parseInt(hours, 10); + meridian = 'AM'; + if (hours === 0) { + hours = 12; + } + else if (hours >= 12) { + meridian = 'PM'; + if (hours > 12) hours -= 12; + } + hours = (' ' + hours).substr(-2); + } + + g.setFont(font, timeFontSize); + g.drawString(`${hours}${(d.getSeconds() % 2) ? ' ' : ':'}${minutes}`, xyCenter - 15, yposTime, true); + g.setFont(font, dataFontSize); + + if (settings.use12Hour) { + g.drawString(seconds, xyCenter + 97, yposTime - 10, true); + g.drawString(meridian, xyCenter + 97, yposTime + 10, true); + } + else { + g.drawString(seconds, xyCenter + 97, yposTime + 10, true); + } + + // draw DoW, name of month, date, year + g.setFont(font, dataFontSize); + g.drawString([ + useLocale ? getLocale().dow(d, 1) : dLocal[0], + useLocale ? getLocale().month(d, 1) : dLocal[1], + d.getDate(), + d.getFullYear() + ].join(" "), xyCenter, yposDate, true); + +} + +function drawInfo() { + if (infoData[infoMode] && infoData[infoMode].calc) { + // clear info + g.setColor(0, 0, 0); + g.fillRect(0, yposInfo - 8, 239, yposInfo + 25); + + // draw info + g.setFont(font, dataFontSize); + setColor(); + g.drawString((infoData[infoMode].calc()), xyCenter, yposInfo, true); + } +} + +function drawImage() { + setColor(); + g.drawPoly([xyCenter - 100, yposSymbol, xyCenter + 100, yposSymbol, xyCenter, yposSymbol + 30], true); +} + +function drawAll() { + drawClock(); + drawInfo(); + drawImage(); +} + +function nextInfo() { + let idx = infoList.indexOf(infoMode); + if (idx > -1) { + if (idx === infoList.length - 1) infoMode = infoList[0]; + else infoMode = infoList[idx + 1]; + } +} + +function prevInfo() { + let idx = infoList.indexOf(infoMode); + if (idx > -1) { + if (idx === 0) infoMode = infoList[infoList.length - 1]; + else infoMode = infoList[idx - 1]; + } +} + + +let secondInterval; + +// handle LCD power state change +Bangle.on('lcdPower', on => { + + // stop running when screen turns off + if (secondInterval) clearInterval(secondInterval); + secondInterval = undefined; + + // start running + if (on) { + secondInterval = setInterval(drawAll, 1000); + drawAll(); // draw immediately + } +}); + +// cover screen to put it to sleep +Bangle.on('touch', (button) => { + if (button === 3 && Bangle.isLCDOn()) Bangle.setLCDPower(false); +}); + +// clean app screen +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// if screen already active, draw now and start interval +if (Bangle.isLCDOn()) { + secondInterval = setInterval(drawAll, 1000); + drawAll(); // draw immediately +} + +// show launcher when middle button pressed +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); + +// rotate through info when the buttons are pressed +setWatch(() => { + nextInfo(); + drawAll(); +}, BTN3, { repeat: true }); + +setWatch(() => { + prevInfo(); + drawAll(); +}, BTN1, { repeat: true }); diff --git a/apps/mysticclock/mystic-clock-icon.js b/apps/mysticclock/mystic-clock-icon.js new file mode 100644 index 000000000..7415fccd5 --- /dev/null +++ b/apps/mysticclock/mystic-clock-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkBIf4A/AH4A/AH4A/AH4ALs1msADCA4MGAgQDBBYIAGg93u92s4DBuEAAYN3swDCC5AhBuwMBg4XBuwEBs4dCC49nHgNwCQREBCYNnEYYXHHQQvBAAJZBAgRPEC5IOCu0GM4YLCuCGDAAREBHwtnJ41gDQIXEOAQvBDoZ7CuwjCWwimTJgLCFZojWEbwbWIAH4A/AH4A/AH4A/AH4AFA")) diff --git a/apps/mysticclock/mystic-clock-settings.js b/apps/mysticclock/mystic-clock-settings.js new file mode 100644 index 000000000..2fa0c49c5 --- /dev/null +++ b/apps/mysticclock/mystic-clock-settings.js @@ -0,0 +1,41 @@ +// make sure to enclose the function in parentheses +(function (back) { + + const settings = require('Storage').readJSON('mysticclock.json',1)||{}; + const colors = ['White', 'Blue', 'Green', 'Purple', 'Red', 'Teal', 'Yellow']; + const offon = ['Off','On']; + const onoff = ['On','Off']; + + function save(key, value) { + settings[key] = value; + require('Storage').writeJSON('mysticclock.json',settings); + } + + const appMenu = { + '': {'title': 'Clock Settings'}, + '< Back': back, + 'Color': { + value: 0|settings['color'], + min:0, + max:6, + format: m => colors[m], + onchange: m => {save('color', m)} + }, + '12 Hour Clock': { + value: 0|settings['use12Hour'], + min:0, + max:1, + format: m => offon[m], + onchange: m => {save('use12Hour', m)} + }, + 'Use Locale': { + value: 0|settings['useLocale'], + min:0, + max:1, + format: m => onoff[m], + onchange: m => {save('useLocale', m)} + } + }; + E.showMenu(appMenu) + +}) diff --git a/apps/mysticclock/mystic-clock.png b/apps/mysticclock/mystic-clock.png new file mode 100644 index 0000000000000000000000000000000000000000..915e2ee32e296ea26a1e96f93813e19730c0002a GIT binary patch literal 981 zcmV;`11kK9P)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00TWqL_t(&-tCx8h*nh`#(&TM zzB4)liT0(LA2<d!82Woq6va-?4G$z&UW?-t+O?^E>~KbMBP}FblW@3%q2243Ggb zKnBPF86X2>fDDiUG5}}+&3aMywl#A%*N5e>(7iRfapQNZ&g($Cq6r#vIlJm9!A0;#UEk8v zf+_H4Mt2B*lDY$yfbI-Dnus?8y)5*+padVPY3%G+!$*wPM{kXzY2E-W)Z72HR`^#F z2WoMClSrc_+$Wd-Z4}z5uJ4{UK4@45{>sF*z-LUnRa>VUMLL>b2>27UL1;rwjHnB;2+Q?p-lnj4gHSTig-|@v4nd}Rz3fXUJrVywz(MmL4xDepce%zYWZ@^`0y;5 zC7|5_eKn1P3BIW`UJ$ITX?*L3RT%{S?ZhJmPy&~@0zk|PQyj z(=`S#`F}2ykJA|-17v^ Date: Sun, 6 Jun 2021 17:33:02 +0200 Subject: [PATCH 0066/2129] chore: bump largeclock version in apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 89be44fcf..f50a5370c 100644 --- a/apps.json +++ b/apps.json @@ -1885,7 +1885,7 @@ "id": "largeclock", "name": "Large Clock", "icon": "largeclock.png", - "version": "0.07", + "version": "0.08", "description": "A readable and informational digital watch, with date, seconds and moon phase", "readme": "README.md", "tags": "clock", From 6de833db3bca32b0e3e1d9d609477c6d8fe5eae3 Mon Sep 17 00:00:00 2001 From: Johannes Schneider Date: Sat, 29 May 2021 13:04:11 +0200 Subject: [PATCH 0067/2129] trex: added highscore and setting (for highscore reset) --- apps.json | 8 ++++++-- apps/trex/ChangeLog | 1 + apps/trex/settings.js | 19 +++++++++++++++++++ apps/trex/trex.js | 26 ++++++++++++++++++++++++-- core | 2 +- 5 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 apps/trex/settings.js diff --git a/apps.json b/apps.json index 89be44fcf..cdfc14d24 100644 --- a/apps.json +++ b/apps.json @@ -362,13 +362,17 @@ { "id": "trex", "name": "T-Rex", "icon": "trex.png", - "version":"0.02", + "version":"0.03", "description": "T-Rex game in the style of Chrome's offline game", "tags": "game", "allow_emulator":true, "storage": [ {"name":"trex.app.js","url":"trex.js"}, - {"name":"trex.img","url":"trex-icon.js","evaluate":true} + {"name":"trex.img","url":"trex-icon.js","evaluate":true}, + {"name":"trex.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"trex.score", "storageFile": true} ] }, { "id": "astroid", diff --git a/apps/trex/ChangeLog b/apps/trex/ChangeLog index 42c1df403..587dec05b 100644 --- a/apps/trex/ChangeLog +++ b/apps/trex/ChangeLog @@ -1 +1,2 @@ 0.02: Add "ram" keyword to allow 2v06 Espruino builds to cache function that needs to be fast +0.03: Enabled BTN2 and BTN3, added highscore (score is saved to storage and can be reset in app settings menu) diff --git a/apps/trex/settings.js b/apps/trex/settings.js new file mode 100644 index 000000000..67aa9a518 --- /dev/null +++ b/apps/trex/settings.js @@ -0,0 +1,19 @@ +(function (back) { + const menu = { + '': { 'title': 'T-Rex' }, + '< Back': back, + 'Reset Highscore': () => { + E.showPrompt('Reset Highscore?').then((v) => { + let delay = 50; + if (v) { + delay = 500; + E.showMessage('Resetting'); + var f = require('Storage').open('trex.score', 'w'); + f.write('0\n'); + } + setTimeout(() => E.showMenu(menu), delay); + }); + } + }; + E.showMenu(menu); +}); diff --git a/apps/trex/trex.js b/apps/trex/trex.js index 642c10054..0e36ec59a 100644 --- a/apps/trex/trex.js +++ b/apps/trex/trex.js @@ -1,3 +1,13 @@ +function loadHighScore() { + var f = require("Storage").open("trex.score", "r"); + return f.readLine() || 0; +} + +function saveHighScore(score) { + var f = require("Storage").open("trex.score", "w"); + f.write(score + "\n"); +} + greal = g; g.clear(); g = Graphics.createArrayBuffer(120,64,1,{msb:true}); @@ -134,6 +144,8 @@ var IMG = { IMG.rex.forEach(i=>i.transparent=0); IMG.cacti.forEach(i=>i.transparent=0); var cacti, rex, frame; +// displayedHighScore is not updated before restart +var highScore = loadHighScore(), displayedHighScore; function gameStart() { rex = { @@ -152,6 +164,7 @@ function gameStart() { } IMG.ground = { width: 128, height: 3, bpp : 1, buffer : random.buffer }; frame = 0; + displayedHighScore = highScore; setInterval(onFrame, 50); } function gameStop() { @@ -159,8 +172,13 @@ function gameStop() { rex.img = 2; // dead clearInterval(); setTimeout(function() { + // putting saveHighScore here to not delay the frame drawing + if (rex.score > highScore) { + highScore = rex.score; + saveHighScore(highScore); + } setWatch(gameStart, BTNU, {repeat:0,debounce:50,edge:"rising"}); - }, 1000); + }, 800); setTimeout(onFrame, 10); } @@ -190,6 +208,9 @@ function onFrame() { while (cacti.length && cacti[0].x<0) cacti.shift(); } else { g.drawString("Game Over!",(W-g.stringWidth("Game Over!"))/2,20); + if (rex.score > highScore) { + g.drawString("New Record!",(W-g.stringWidth("New Record!"))/2,28); + } } g.drawLine(0,60,239,60); cacti.forEach(c=>g.drawImage(IMG.cacti[c.img],c.x,60-IMG.cacti[c.img].height)); @@ -213,7 +234,8 @@ function onFrame() { var groundOffset = frame&127; g.drawImage(IMG.ground, -groundOffset, 61); g.drawImage(IMG.ground, 128-groundOffset, 61); - g.drawString(rex.score,(W-1)-g.stringWidth(rex.score)); + g.drawString(displayedHighScore,(W-1)-g.stringWidth(displayedHighScore), 0); + g.drawString(rex.score,(W-1)-g.stringWidth(rex.score), 8); g.flip(); } diff --git a/core b/core index 0ba4c2bd5..3f2ff467f 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 0ba4c2bd5503264279222b04a41505471c6622ff +Subproject commit 3f2ff467f22b746da94160e59ff89b621601b261 From 09f13c242ad389851f0cc102a0608840cee256ef Mon Sep 17 00:00:00 2001 From: Smooklu <37220586+Smooklu@users.noreply.github.com> Date: Mon, 7 Jun 2021 13:02:11 -0500 Subject: [PATCH 0068/2129] Create FD6FDetect.app.js --- apps/fd6fdetect/FD6FDetect.app.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 apps/fd6fdetect/FD6FDetect.app.js diff --git a/apps/fd6fdetect/FD6FDetect.app.js b/apps/fd6fdetect/FD6FDetect.app.js new file mode 100644 index 000000000..67e4d2c02 --- /dev/null +++ b/apps/fd6fdetect/FD6FDetect.app.js @@ -0,0 +1,25 @@ +//Bangle.setLCDPower(1); //debugging purposes +//Bangle.setLCDTimeout(0); // debugging purposes +g.clear(); // clear screen +let amount = 'global value'; // make amount global +function FindCOVIDAwareBeacons() { // function for finding COVID beacons +NRF.findDevices(function(devices) { // function for searching for devices with the UUID of FD6F + g.setFont('Vector', 75); // set size of font to 75x + g.setFontAlign(0,0); // align font + var amount = devices.length; // get amount of devices matching FD6F + g.clear(); // clear screen + g.drawString(amount, 125, 100); // draw amount of devices matching FD6F + if (amount == 1) { // check to see if we need to use the word users or user + g.setFont('Vector', 25); // set size of font to 25x + g.drawString('COVIDAwareMN', 125, 150); // draw string + g.drawString('user', 125, 175); // draw string + g.drawString('nearby', 125, 200); // draw string + } else{ // if more than one change user to users + g.setFont('Vector', 25); // set size of font to 25x + g.drawString('COVIDAwareMN', 125, 150); // draw string + g.drawString('users', 125, 175); // draw string + g.drawString('nearby', 125, 200); // draw string + } +}, {timeout : 1000, filters : [{services: ['fd6f'] }] }); // set filters to target only FD6F beacons +} +setInterval(FindCOVIDAwareBeacons, 2000); // poll for new devices From 72299583d4ce53a831f9d9964e5cf95b9f58d2a8 Mon Sep 17 00:00:00 2001 From: Smooklu <37220586+Smooklu@users.noreply.github.com> Date: Mon, 7 Jun 2021 13:02:25 -0500 Subject: [PATCH 0069/2129] Add files via upload --- apps/fd6fdetect/FD6FDetect.info | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/fd6fdetect/FD6FDetect.info diff --git a/apps/fd6fdetect/FD6FDetect.info b/apps/fd6fdetect/FD6FDetect.info new file mode 100644 index 000000000..dec8374ce --- /dev/null +++ b/apps/fd6fdetect/FD6FDetect.info @@ -0,0 +1 @@ +{"id":"fd6fdetect","name":"FD6FDetect","src":"FD6FDetect.app.js","icon":"FD6FDetect.img","version":"0.01","files":"FD6FDetect.info,FD6FDetect.img,FD6FDetect.app.js"} \ No newline at end of file From e409ada3471a8a9cefe389c909a837be56284ede Mon Sep 17 00:00:00 2001 From: Weiming Date: Mon, 7 Jun 2021 16:40:23 -0400 Subject: [PATCH 0070/2129] Update ChangeLog --- apps/gpsrec/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog index 412dbe9d3..c71a29482 100644 --- a/apps/gpsrec/ChangeLog +++ b/apps/gpsrec/ChangeLog @@ -21,3 +21,4 @@ 0.17: Disable recording if storage is full (fix #574) 0.18: Period counter now uses GPS time rather than counting packets (allows use with GPS Setup) 0.19: Fix memory usage issues inside track viewer app +0.20: Add documentation to explain time needed for getting a time fix From 2dd8844a45f3de68745215e103873ec41bba4a77 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Jun 2021 09:38:08 +0100 Subject: [PATCH 0071/2129] 0.26: Remove buzz in setUI polyfill (#750) --- apps.json | 2 +- apps/boot/ChangeLog | 1 + apps/boot/bootupdate.js | 19 ++++++++----------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/apps.json b/apps.json index fdf0b5871..f5b4c47a6 100644 --- a/apps.json +++ b/apps.json @@ -4,7 +4,7 @@ "tags": "tool,system", "type":"bootloader", "icon": "bootloader.png", - "version":"0.25", + "version":"0.26", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "storage": [ {"name":".boot0","url":"boot0.js"}, diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 48e1baa48..37ce0d0ac 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -24,3 +24,4 @@ 0.23: Move to a precalculated .boot0 file which should speed up load time 0.24: Add Bangle.setUI polyfill 0.25: Fix error in 'no clock app' message +0.26: Remove buzz in setUI polyfill (#750) diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index 9dc90cc9a..9dd49453e 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -97,25 +97,22 @@ if (Bangle.touchandler) { Bangle.removeListener("touch", Bangle.touchHandler); delete Bangle.touchHandler; } -function b() { - try{Bangle.buzz(20);}catch(e){} -} if (!mode) return; else if (mode=="updown") { Bangle.btnWatches = [ - setWatch(function() { b();cb(-1); }, BTN1, {repeat:1}), - setWatch(function() { b();cb(1); }, BTN3, {repeat:1}), - setWatch(function() { b();cb(); }, BTN2, {repeat:1}) + setWatch(function() { cb(-1); }, BTN1, {repeat:1}), + setWatch(function() { cb(1); }, BTN3, {repeat:1}), + setWatch(function() { cb(); }, BTN2, {repeat:1}) ]; } else if (mode=="leftright") { Bangle.btnWatches = [ - setWatch(function() { b();cb(-1); }, BTN1, {repeat:1}), - setWatch(function() { b();cb(1); }, BTN3, {repeat:1}), - setWatch(function() { b();cb(); }, BTN2, {repeat:1}) + setWatch(function() { cb(-1); }, BTN1, {repeat:1}), + setWatch(function() { cb(1); }, BTN3, {repeat:1}), + setWatch(function() { cb(); }, BTN2, {repeat:1}) ]; - Bangle.swipeHandler = d => {b();cb(d);}; + Bangle.swipeHandler = d => {cb(d);}; Bangle.on("swipe", Bangle.swipeHandler); - Bangle.touchHandler = d => {b();cb();}; + Bangle.touchHandler = d => {cb();}; Bangle.on("touch", Bangle.touchHandler); } else throw new Error("Unknown UI mode"); From 3df0e9d64c6eb917b638e1c622585bcad3510c19 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Thu, 10 Jun 2021 20:18:21 +0200 Subject: [PATCH 0072/2129] remove duplicate omnitrix "readme" key from apps.json (no code change) --- apps.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps.json b/apps.json index f5b4c47a6..aee81676b 100644 --- a/apps.json +++ b/apps.json @@ -3212,7 +3212,6 @@ "readme": "README.md", "description": "An Omnitrix Showpiece", "tags": "game", - "readme": "README.md", "storage": [ {"name":"omnitrix.app.js","url":"omnitrix.app.js"}, {"name":"omnitrix.img","url":"omnitrix.icon.js","evaluate":true} From 002f861038674221327a50c256bcea881d3e0ab0 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Thu, 10 Jun 2021 20:17:03 +0200 Subject: [PATCH 0073/2129] barclock: use timeout to tick exactly on the second, instead of interval --- apps.json | 2 +- apps/barclock/ChangeLog | 3 ++- apps/barclock/clock-bar.js | 18 +++++++++--------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps.json b/apps.json index aee81676b..c10395020 100644 --- a/apps.json +++ b/apps.json @@ -1312,7 +1312,7 @@ { "id": "barclock", "name": "Bar Clock", "icon": "clock-bar.png", - "version":"0.05", + "version":"0.06", "description": "A simple digital clock showing seconds as a bar", "tags": "clock", "type":"clock", diff --git a/apps/barclock/ChangeLog b/apps/barclock/ChangeLog index 616ee66e9..551926191 100644 --- a/apps/barclock/ChangeLog +++ b/apps/barclock/ChangeLog @@ -2,4 +2,5 @@ 0.02: Apply locale, 12-hour setting 0.03: Fix dates drawing over each other at midnight 0.04: Small bugfix -0.05: Clock does not start if app Languages is not installed \ No newline at end of file +0.05: Clock does not start if app Languages is not installed +0.06: Improve accuracy \ No newline at end of file diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index 0f2609298..4bb6c048a 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -12,12 +12,12 @@ date.setMonth(1, 3) // februari: months are zero-indexed const localized = locale.date(date, true) locale.dayFirst = /3.*2/.test(localized) - + locale.hasMeridian = false if(typeof locale.meridian === 'function') { // function does not exists if languages app is not installed locale.hasMeridian = (locale.meridian(date) !== '') } - + } const screen = { width: g.getWidth(), @@ -124,7 +124,7 @@ g.fillRect(0, timeTop, screen.width, screen.height) } - let lastSeconds + let lastSeconds, tTick const tick = function () { g.reset() const date = new Date() @@ -136,20 +136,20 @@ } // the bar only gets larger, so drawing on top of the previous one is fine drawBar(date) - lastSeconds = seconds + // schedule next update + const millis = date.getMilliseconds() + tTick = setTimeout(tick, 1000-millis) } - let iTick const start = function () { lastSeconds = 99 // force redraw tick() - iTick = setInterval(tick, 1000) } const stop = function () { - if (iTick) { - clearInterval(iTick) - iTick = undefined + if (tTick) { + clearTimeout(tTick) + tTick = undefined } } From c6bafb6b0a1cd7f6efa71a800c41e5b67229c740 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Thu, 10 Jun 2021 20:46:02 +0200 Subject: [PATCH 0074/2129] barclock: add readme with screenshots --- apps.json | 1 + apps/barclock/README.md | 6 ++++++ apps/barclock/screenshot.png | Bin 0 -> 2764 bytes apps/barclock/screenshot_pm.png | Bin 0 -> 2595 bytes 4 files changed, 7 insertions(+) create mode 100644 apps/barclock/README.md create mode 100644 apps/barclock/screenshot.png create mode 100644 apps/barclock/screenshot_pm.png diff --git a/apps.json b/apps.json index c10395020..31c791c86 100644 --- a/apps.json +++ b/apps.json @@ -1316,6 +1316,7 @@ "description": "A simple digital clock showing seconds as a bar", "tags": "clock", "type":"clock", + "readme": "README.md", "allow_emulator":true, "storage": [ {"name":"barclock.app.js","url":"clock-bar.js"}, diff --git a/apps/barclock/README.md b/apps/barclock/README.md new file mode 100644 index 000000000..4b92313c5 --- /dev/null +++ b/apps/barclock/README.md @@ -0,0 +1,6 @@ +# Bar Clock +A simple digital clock showing seconds as a horizontal bar. + +| 24hr style | 12hr style | +| --- | --- | +| ![24-hour bar clock](screenshot.png) | ![12-hour bar clock with meridian](screenshot_pm.png) | diff --git a/apps/barclock/screenshot.png b/apps/barclock/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..d37ee9cae2680e73889600e8eb29f87ba2956f87 GIT binary patch literal 2764 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 literal 0 HcmV?d00001 From c1358b51bcde602c6039cf8aed996d61b4d77bba Mon Sep 17 00:00:00 2001 From: hughbarney Date: Thu, 10 Jun 2021 23:49:44 +0100 Subject: [PATCH 0075/2129] updated README for gpsservice app, to state its superceded by gpssetup --- apps/gpsservice/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/gpsservice/README.md b/apps/gpsservice/README.md index b1e3e60d4..061f3ba3b 100644 --- a/apps/gpsservice/README.md +++ b/apps/gpsservice/README.md @@ -2,6 +2,9 @@ A configurable, low power GPS widget that runs in the background. +NOTE: This app has been superceded by [gpssetup](https://github.com/espruino/BangleApps/blob/master/apps/gpssetup/README.md) + + ## Goals To develop a low power GPS widget that runs in the background and to From ca12134ffe2a4ee3b464b49d1f497ca842a9e7af Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 11 Jun 2021 11:14:52 +0100 Subject: [PATCH 0076/2129] lock alignment --- apps/widlock/widget.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/widlock/widget.js b/apps/widlock/widget.js index b710de8c6..ea664a083 100644 --- a/apps/widlock/widget.js +++ b/apps/widlock/widget.js @@ -5,6 +5,6 @@ }); WIDGETS["lock"]={area:"tl",width:Bangle.isLCDOn()?0:16,draw:function(w) { if (!Bangle.isLCDOn()) - g.reset().drawImage(atob("DhABH+D/wwMMDDAwwMf/v//4f+H/h/8//P/z///f/g=="), w.x, w.y); + g.reset().drawImage(atob("DhABH+D/wwMMDDAwwMf/v//4f+H/h/8//P/z///f/g=="), w.x+1, w.y+4); }}; })() From 45b5ab231a5875e131a8f494f1701d0e39f84c6a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 11 Jun 2021 11:15:18 +0100 Subject: [PATCH 0077/2129] minor colour change to help with rounding on 3bpp --- apps/widid/widget.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/widid/widget.js b/apps/widid/widget.js index 68917c65a..d4f4d6386 100644 --- a/apps/widid/widget.js +++ b/apps/widid/widget.js @@ -2,7 +2,7 @@ (() => { function draw() { var id = NRF.getAddress().substr().substr(12).split(":"); - g.reset().setColor(0, 0.5, 1).setFont("6x8", 1); + g.reset().setColor(0, 0.49, 1).setFont("6x8", 1); g.drawString(id[0], this.x+2, this.y+4, true); g.drawString(id[1], this.x+2, this.y+14, true); } From 7a287c497e17b8389ea683218de13edd22f6d822 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 11 Jun 2021 11:34:05 +0100 Subject: [PATCH 0078/2129] Add option for 3 bit maps, scrolling support --- apps.json | 2 +- apps/openstmap/ChangeLog | 1 + apps/openstmap/app.js | 16 +++++++++++++++- apps/openstmap/custom.html | 11 +++++++++++ apps/openstmap/openstmap.js | 15 ++++++++++----- 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/apps.json b/apps.json index f5b4c47a6..a02aec925 100644 --- a/apps.json +++ b/apps.json @@ -1462,7 +1462,7 @@ "name": "OpenStreetMap", "shortName":"OpenStMap", "icon": "app.png", - "version":"0.05", + "version":"0.06", "description": "[BETA] Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are", "tags": "outdoors,gps", "custom": "custom.html", diff --git a/apps/openstmap/ChangeLog b/apps/openstmap/ChangeLog index 64b39b509..4d9b61031 100644 --- a/apps/openstmap/ChangeLog +++ b/apps/openstmap/ChangeLog @@ -3,3 +3,4 @@ 0.03: Show widgets (mainly so we can use the GPS recorder widget) 0.04: Move map rendering to a module (fix #396) 0.05: Show currently active gpsrec GPS trace (fix #395) +0.06: Add support for scrolling, option for 3 bit maps diff --git a/apps/openstmap/app.js b/apps/openstmap/app.js index 940557361..5a01a9059 100644 --- a/apps/openstmap/app.js +++ b/apps/openstmap/app.js @@ -34,7 +34,7 @@ Bangle.on('GPS',function(f) { g.drawString(txt,120,y1 + 4); drawMarker(); }); -Bangle.setGPSPower(1); +Bangle.setGPSPower(1, "app"); if (HASWIDGETS) { Bangle.loadWidgets(); @@ -55,3 +55,17 @@ setWatch(function() { m.lon = fix.lon; redraw(); }, BTN2, {repeat:true}); + +var hasScrolled = false; +E.on('touch',e=>{ + if (e.b) { + g.setClipRect(0,y1,g.getWidth()-1,y2); + g.scroll(e.dx,e.dy); + m.scroll(e.dx,e.dy); + g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); + hasScrolled = true; + } else if (hasScrolled) { + hasScrolled = false; + redraw(); + } +}); diff --git a/apps/openstmap/custom.html b/apps/openstmap/custom.html index 81a55a4f8..95a4ff0a6 100644 --- a/apps/openstmap/custom.html +++ b/apps/openstmap/custom.html @@ -32,6 +32,7 @@
+

3 bit