From 891a32bf4428215496ccc158534b4ecc68141c10 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Thu, 23 Sep 2021 08:27:19 +0200 Subject: [PATCH 1/7] New CSC sensor app add support for cadence sensor --- apps.json | 2 +- apps/cscsensor/ChangeLog | 2 +- apps/cscsensor/README.md | 4 +- apps/cscsensor/cscsensor.app.js | 121 +++++++++++++++++++++++--------- 4 files changed, 91 insertions(+), 38 deletions(-) diff --git a/apps.json b/apps.json index cd5bf3489..5ec2f83ae 100644 --- a/apps.json +++ b/apps.json @@ -2508,7 +2508,7 @@ "name": "Cycling speed sensor", "shortName":"CSCSensor", "icon": "icons8-cycling-48.png", - "version":"0.04", + "version":"0.05", "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", "tags": "outdoors,exercise,ble,bluetooth", "readme": "README.md", diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog index 7be2ed3e2..9af9f9926 100644 --- a/apps/cscsensor/ChangeLog +++ b/apps/cscsensor/ChangeLog @@ -2,4 +2,4 @@ 0.02: Add wheel circumference settings dialog 0.03: Save total distance traveled 0.04: Add sensor battery level indicator - +0.05: Add cadence sensor support diff --git a/apps/cscsensor/README.md b/apps/cscsensor/README.md index a31a4dc28..e19ebe60e 100644 --- a/apps/cscsensor/README.md +++ b/apps/cscsensor/README.md @@ -13,6 +13,6 @@ Currently the app displays the following data: Button 1 resets all measurements except total distance traveled. The latter gets preserved by being written to storage every 0.1 miles and upon exiting the app. If the watch app has not received an update from the sensor for at least 10 seconds, pushing button 3 will attempt to reconnect to the sensor. +Button 2 switches between the display for cycling speed and cadence. -I do not have access to a cadence sensor at the moment, so only the speed part is currently implemented. Values displayed are imperial or metric (depending on locale), -the wheel circumference can be adjusted in the global settings app. +Values displayed are imperial or metric (depending on locale), cadence is in RPM, the wheel circumference can be adjusted in the global settings app. diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index c402c06da..805a17296 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -28,6 +28,10 @@ class CSCSensor { this.distFactor = this.qMetric ? 1.609344 : 1; this.screenInit = true; this.batteryLevel = -1; + this.lastCrankTime = 0; + this.lastCrankRevs = 0; + this.showCadence = false; + this.cadence = 0; } reset() { @@ -40,6 +44,11 @@ class CSCSensor { this.screenInit = true; } + toggleDisplayCadence() { + this.showCadence = !this.showCadence; + this.screenInit = true; + } + setBatteryLevel(level) { if (level!=this.batteryLevel) { this.batteryLevel = level; @@ -62,7 +71,7 @@ class CSCSensor { else g.setFontVector(14).setFontAlign(0, 0, 0).setColor(0xffff).drawString("?", 16, 66); } - updateScreen() { + updateScreenRevs() { var dist = this.distFactor*(this.lastRevs-this.lastRevsStart)*this.wheelCirc/63360.0; var ddist = Math.round(100*dist)/100; var tdist = Math.round(this.distFactor*this.totaldist*10)/10; @@ -108,45 +117,88 @@ class CSCSensor { g.setColor(0).fillRect(88, 209, 238, 238); g.setColor(0xffff).drawString(tdist + " " + this.distUnit, 92, 226); } - + + updateScreenCadence() { + if (this.screenInit) { + for (var i=0; i<2; ++i) { + if ((i&1)==0) g.setColor(0, 0, 0); + else g.setColor(0x30cd); + g.fillRect(0, 48+i*32, 86, 48+(i+1)*32); + if ((i&1)==1) g.setColor(0); + else g.setColor(0x30cd); + g.fillRect(87, 48+i*32, 239, 48+(i+1)*32); + g.setColor(0.5, 0.5, 0.5).drawRect(87, 48+i*32, 239, 48+(i+1)*32).drawLine(0, 239, 239, 239);//.drawRect(0, 48, 87, 239); + g.moveTo(0, 80).lineTo(30, 80).lineTo(30, 48).lineTo(87, 48).lineTo(87, 239).lineTo(0, 239).lineTo(0, 80); + } + g.setFontAlign(1, 0, 0).setFontVector(19).setColor(1, 1, 0); + g.drawString("Cadence:", 87, 98); + this.drawBatteryIcon(); + this.screenInit = false; + } + g.setFontAlign(-1, 0, 0).setFontVector(26); + g.setColor(0).fillRect(88, 81, 238, 111); + g.setColor(0xffff).drawString(Math.round(this.cadence), 92, 98); + } + + updateScreen() { + if (!this.showCadence) { + this.updateScreenRevs(); + } else { + this.updateScreenCadence(); + } + } + updateSensor(event) { var qChanged = false; if (event.target.uuid == "0x2a5b") { - var wheelRevs = event.target.value.getUint32(1, true); - var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0); - if (dRevs>0) { - qChanged = true; - this.totaldist += dRevs*this.wheelCirc/63360.0; - if ((this.totaldist-this.settings.totaldist)>0.1) { - this.settings.totaldist = this.totaldist; - storage.writeJSON(SETTINGS_FILE, this.settings); + if (event.target.value.getUint8(0, true) & 0x2) { + // crank revolution + const crankRevs = event.target.value.getUint16(1, true); + const crankTime = event.target.value.getUint16(3, true); + if (crankTime > this.lastCrankTime) { + this.cadence = (crankRevs-this.lastCrankRevs)/(crankTime-this.lastCrankTime)*60000; + qChanged = true; } - } - this.lastRevs = wheelRevs; - if (this.lastRevsStart<0) this.lastRevsStart = wheelRevs; - var wheelTime = event.target.value.getUint16(5, true); - var dT = (wheelTime-this.lastTime)/1024; - var dBT = (Date.now()-this.lastBangleTime)/1000; - this.lastBangleTime = Date.now(); - if (dT<0) dT+=64; - if (Math.abs(dT-dBT)>3) dT = dBT; - this.lastTime = wheelTime; - this.speed = this.lastSpeed; - if (dRevs>0 && dT>0) { - this.speed = (dRevs*this.wheelCirc/63360.0)*3600/dT; - this.speedFailed = 0; - this.movingTime += dT; - } - else { - this.speedFailed++; - qChanged = false; - if (this.speedFailed>3) { - this.speed = 0; - qChanged = (this.lastSpeed>0); + this.lastCrankRevs = crankRevs; + this.lastCrankTime = crankTime; + } else { + // wheel revolution + var wheelRevs = event.target.value.getUint32(1, true); + var dRevs = (this.lastRevs>0 ? wheelRevs-this.lastRevs : 0); + if (dRevs>0) { + qChanged = true; + this.totaldist += dRevs*this.wheelCirc/63360.0; + if ((this.totaldist-this.settings.totaldist)>0.1) { + this.settings.totaldist = this.totaldist; + storage.writeJSON(SETTINGS_FILE, this.settings); + } } + this.lastRevs = wheelRevs; + if (this.lastRevsStart<0) this.lastRevsStart = wheelRevs; + var wheelTime = event.target.value.getUint16(5, true); + var dT = (wheelTime-this.lastTime)/1024; + var dBT = (Date.now()-this.lastBangleTime)/1000; + this.lastBangleTime = Date.now(); + if (dT<0) dT+=64; + if (Math.abs(dT-dBT)>3) dT = dBT; + this.lastTime = wheelTime; + this.speed = this.lastSpeed; + if (dRevs>0 && dT>0) { + this.speed = (dRevs*this.wheelCirc/63360.0)*3600/dT; + this.speedFailed = 0; + this.movingTime += dT; + } + else { + this.speedFailed++; + qChanged = false; + if (this.speedFailed>3) { + this.speed = 0; + qChanged = (this.lastSpeed>0); + } + } + this.lastSpeed = this.speed; + if (this.speed>this.maxSpeed && (this.movingTime>3 || this.speed<20) && this.speed<50) this.maxSpeed = this.speed; } - this.lastSpeed = this.speed; - if (this.speed>this.maxSpeed && (this.movingTime>3 || this.speed<20) && this.speed<50) this.maxSpeed = this.speed; } if (qChanged && this.qUpdateScreen) this.updateScreen(); } @@ -199,6 +251,7 @@ connection_setup(); setWatch(function() { mySensor.reset(); g.clearRect(0, 48, 239, 239); mySensor.updateScreen(); }, BTN1, {repeat:true, debounce:20}); E.on('kill',()=>{ if (gatt!=undefined) gatt.disconnect(); mySensor.settings.totaldist = mySensor.totaldist; storage.writeJSON(SETTINGS_FILE, mySensor.settings); }); setWatch(function() { if (Date.now()-mySensor.lastBangleTime>10000) connection_setup(); }, BTN3, {repeat:true, debounce:20}); +setWatch(function() { mySensor.toggleDisplayCadence(); g.clearRect(0, 48, 239, 239); mySensor.updateScreen(); }, BTN2, {repeat:true, debounce:20}); NRF.on('disconnect', connection_setup); Bangle.loadWidgets(); From 807ac743fc2d253fc82dd0b5b1e13aee95fee689 Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Thu, 23 Sep 2021 22:21:32 -0400 Subject: [PATCH 2/7] Layout: only set fillxy/y if null Fixes #820 --- modules/Layout.js | 8 ++++---- tests/Layout/tests/filly_issue820.bmp | Bin 0 -> 15562 bytes tests/Layout/tests/filly_issue820.js | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 tests/Layout/tests/filly_issue820.bmp create mode 100644 tests/Layout/tests/filly_issue820.js diff --git a/modules/Layout.js b/modules/Layout.js index 521b191b6..bfb13a561 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -329,14 +329,14 @@ Layout.prototype.update = function() { l.c.forEach(updateMin); l._h = l.c.reduce((a,b)=>Math.max(a,b._h+(b.pad<<1)),0); l._w = l.c.reduce((a,b)=>a+b._w+(b.pad<<1),0); - if (l.c.some(c=>c.fillx)) l.fillx = 1; - if (l.c.some(c=>c.filly)) l.filly = 1; + if (l.fillx == null && l.c.some(c=>c.fillx)) l.fillx = 1; + if (l.filly == null && l.c.some(c=>c.filly)) l.filly = 1; }, "v": function(l) { l.c.forEach(updateMin); l._h = l.c.reduce((a,b)=>a+b._h+(b.pad<<1),0); l._w = l.c.reduce((a,b)=>Math.max(a,b._w+(b.pad<<1)),0); - if (l.c.some(c=>c.fillx)) l.fillx = 1; - if (l.c.some(c=>c.filly)) l.filly = 1; + if (l.fillx == null && l.c.some(c=>c.fillx)) l.fillx = 1; + if (l.filly == null && l.c.some(c=>c.filly)) l.filly = 1; } }; updateMin(l); diff --git a/tests/Layout/tests/filly_issue820.bmp b/tests/Layout/tests/filly_issue820.bmp new file mode 100644 index 0000000000000000000000000000000000000000..886ba97d8967b1211ae7eb43c8f5bc5cf7cc55a7 GIT binary patch literal 15562 zcmeI1O-{ow5QPVcB~q@!0a#Rs6%uz~(ZlozJpxOXJp$qc9HYxDDh1n(W6SeWYy2Y- zGzQYi%gkrzP0|KYsr z_qLMWQ&5ypZCmU}YM_|pWOg9}iWyLP7+Hz5v@W-g7)Z-;(&LDMw6rd_54;3Yj>3-v z2#|PPP5}@g2$%HHdCNK;WU|CjV7$#&9IKkPO zZW?^@q{udHv!63yG+6J|&xDOF6RBI{B7+;)3mf;Rxu9{P#;+y!<<7HSCs|v9On3Lh z+^RU1QFwODiesKBQ({&e%P2fM@-zy0o>YloQ7EPG{0J6>JWs3yQ$r+%fPz2^5l9nD zffgb$1QaZ;E&)g?kQUq$6hJ`9f?EQRR3dp>{c8yW)p(wNML8v!=lRzX2CA8TZEdgr zwR1Dv>odf;wY~E*#D=)njyWID^-`>DjT;^+n>_Lb-<-8}vk~snxNr(hqBXA7YbLnG ztpd-DOWWq=t6A_G*GyFPx7uFZ+2Hh)?OLm@={2rBk90E0{ta&0O9|G$wWl@42m7y_ zis2f^mgfAepstm6+XLJD{1vDUr~~SNI-m}y1L}Y}pbn@5>VP_+4*Ww0 FegR&LXGs76 literal 0 HcmV?d00001 diff --git a/tests/Layout/tests/filly_issue820.js b/tests/Layout/tests/filly_issue820.js new file mode 100644 index 000000000..4b813fadf --- /dev/null +++ b/tests/Layout/tests/filly_issue820.js @@ -0,0 +1,9 @@ +g.clear(); +var layout = new Layout({type:"h", filly: 0, c: [ + {type: "txt", font: "50%", label: "A"}, + {type:"v", c: [ + {type: "txt", font: "10%", label: "B"}, + {filly: 1}, + {type: "txt", font: "10%", label: "C"}, + ]}, +]}); From 221c3acc94f9ad6969b4b27df4b58290162f0b3e Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Fri, 24 Sep 2021 17:42:47 -0400 Subject: [PATCH 3/7] Layout: make `pad` behave more consistently Fixes the second test case in #819 --- modules/Layout.js | 60 ++++++++++------------ tests/Layout/tests/accellog.bmp | Bin 15562 -> 15562 bytes tests/Layout/tests/padding.bmp | Bin 0 -> 15562 bytes tests/Layout/tests/padding.js | 26 ++++++++++ tests/Layout/tests/padding_issue819_2.bmp | Bin 0 -> 15562 bytes tests/Layout/tests/padding_issue819_2.js | 7 +++ tests/Layout/tests/padding_with_fill.bmp | Bin 0 -> 15562 bytes tests/Layout/tests/padding_with_fill.js | 26 ++++++++++ 8 files changed, 87 insertions(+), 32 deletions(-) create mode 100644 tests/Layout/tests/padding.bmp create mode 100644 tests/Layout/tests/padding.js create mode 100644 tests/Layout/tests/padding_issue819_2.bmp create mode 100644 tests/Layout/tests/padding_issue819_2.js create mode 100644 tests/Layout/tests/padding_with_fill.bmp create mode 100644 tests/Layout/tests/padding_with_fill.js diff --git a/modules/Layout.js b/modules/Layout.js index bfb13a561..2caa11c97 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -189,20 +189,24 @@ Layout.prototype.render = function (l) { "txt":function(l){ g.setFont(l.font,l.fsz).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); }, "btn":function(l){ + var x = l.x+(0|l.pad); + var y = l.y+(0|l.pad); + var w = l.w-(l.pad<<1); + var h = l.h-(l.pad<<1); var poly = [ - l.x,l.y+4, - l.x+4,l.y, - l.x+l.w-5,l.y, - l.x+l.w-1,l.y+4, - l.x+l.w-1,l.y+l.h-5, - l.x+l.w-5,l.y+l.h-1, - l.x+4,l.y+l.h-1, - l.x,l.y+l.h-5, - l.x,l.y+4 + x,y+4, + x+4,y, + x+w-5,y, + x+w-1,y+4, + x+w-1,y+h-5, + x+w-5,y+h-1, + x+4,y+h-1, + x,y+h-5, + x,y+4 ]; g.setColor(g.theme.bgH).fillPoly(poly).setColor(l.selected ? g.theme.fgH : g.theme.fg).drawPoly(poly).setFont("4x6",2).setFontAlign(0,0,l.r).drawString(l.label,l.x+l.w/2,l.y+l.h/2); }, "img":function(l){ - g.drawImage(l.src(), l.x, l.y); + g.drawImage(l.src(), l.x + (0|l.pad), l.y + (0|l.pad)); }, "custom":function(l){ l.render(l); },"h":function(l) { l.c.forEach(render); }, @@ -231,36 +235,28 @@ Layout.prototype.layout = function (l) { // exw,exh = extra width/height available switch (l.type) { case "h": { - let x = l.x + (l.w-l._w)/2; + var x = l.x + (0|l.pad); var fillx = l.c && l.c.reduce((a,l)=>a+(0|l.fillx),0); - if (fillx) { x = l.x; } + if (!fillx) { x += (l.w-l._w)/2; } l.c.forEach(c => { c.w = c._w + ((0|c.fillx)*(l.w-l._w)/(fillx||1)); - c.h = c.filly ? l.h : c._h; - if (c.pad) { - c.w += c.pad*2; - c.h += c.pad*2; - } + c.h = c.filly ? l.h - (l.pad<<1) : c._h; c.x = x; - c.y = l.y + (1+(0|c.valign))*(l.h-c.h)/2; + c.y = l.y + (0|l.pad) + (1+(0|c.valign))*(l.h-(l.pad<<1)-c.h)/2; x += c.w; if (c.c) this.layout(c); }); break; } case "v": { - let y = l.y + (l.h-l._h)/2; + var y = l.y + (0|l.pad);; var filly = l.c && l.c.reduce((a,l)=>a+(0|l.filly),0); - if (filly) { y = l.y; } + if (!filly) { y += (l.h-l._h)/2 } l.c.forEach(c => { - c.w = c.fillx ? l.w : c._w; + c.w = c.fillx ? l.w - (l.pad<<1) : c._w; c.h = c._h + ((0|c.filly)*(l.h-l._h)/(filly||1)); - if (c.pad) { - c.w += c.pad*2; - c.h += c.pad*2; - } c.y = y; - c.x = l.x + (1+(0|c.halign))*(l.w-c.w)/2; + c.x = l.x + (0|l.pad) + (1+(0|c.halign))*(l.w-(l.pad<<1)-c.w)/2; y += c.h; if (c.c) this.layout(c); }); @@ -288,8 +284,8 @@ Layout.prototype.update = function() { if (l.r&1) { // rotation var t = l._w;l._w=l._h;l._h=t; } - l._w = Math.max(l._w, 0|l.width); - l._h = Math.max(l._h, 0|l.height); + l._w = Math.max(l._w + (l.pad<<1), 0|l.width); + l._h = Math.max(l._h + (l.pad<<1), 0|l.height); } var cb = { "txt" : function(l) { @@ -327,14 +323,14 @@ Layout.prototype.update = function() { l._h = 0; }, "h": function(l) { l.c.forEach(updateMin); - l._h = l.c.reduce((a,b)=>Math.max(a,b._h+(b.pad<<1)),0); - l._w = l.c.reduce((a,b)=>a+b._w+(b.pad<<1),0); + l._h = l.c.reduce((a,b)=>Math.max(a,b._h),0); + l._w = l.c.reduce((a,b)=>a+b._w,0); if (l.fillx == null && l.c.some(c=>c.fillx)) l.fillx = 1; if (l.filly == null && l.c.some(c=>c.filly)) l.filly = 1; }, "v": function(l) { l.c.forEach(updateMin); - l._h = l.c.reduce((a,b)=>a+b._h+(b.pad<<1),0); - l._w = l.c.reduce((a,b)=>Math.max(a,b._w+(b.pad<<1)),0); + l._h = l.c.reduce((a,b)=>a+b._h,0); + l._w = l.c.reduce((a,b)=>Math.max(a,b._w),0); if (l.fillx == null && l.c.some(c=>c.fillx)) l.fillx = 1; if (l.filly == null && l.c.some(c=>c.filly)) l.filly = 1; } diff --git a/tests/Layout/tests/accellog.bmp b/tests/Layout/tests/accellog.bmp index 7ebe01b2100f193da43872cbb697f9bb9fbc0931..c0bbaf4fcead470781e8150343439fc7c6329e10 100644 GIT binary patch delta 169 zcmX?Ad8%?lDDULIJQ3J1GXn#|<+L2S)PABPhXM+s8`g60(-A|vs8_k|pdimz(3&ZU-o}b}yf!ibVn8uD@ z9iN?@U0z-uoea&>`2g-p3)EY4A-09~Ja1juxqW%+W!21x!+|0bLEjoz69#Mp~`F9Gn)dJrwFc)sOYXx<|75}+L=v*3ymn} zEZgbD%ofbWxmq`~1#?|KEKfhsuEcH4Y(2Q&WEpFUBoBUQe-wAm-y77ij`=N=OLGs3 zB<`r|wBa_$Lb+Y@TQGO77h)T|h{CuyR~_?P7g2P;ZD41_}OZ^C3eg{3cH>8TS zVcVs*qPNpe?}AG!I=o^=ZgPNSG`tv;lFKyGL+?^Pklwo00d1PG!i$T;SGX8~WIygz zueN*s_QGE6%#~MK@*+pZavz^qvSjSTlE+AvjO9K)v1G~Ehb51ZEE&svd}3l@IYhP@ zjrp+TF~s;Q2aI{H#Lbtn#>@a-9qZd~%XNbLa#r_;yQ@PixINf!BypWz&IfDJ!^6^( zqQB9&POQPlPFHU%?%ZE(y|K8le2B$`50ncr@;3&Tl2$YnVA1mmRGe-5j;&WAaR|K z577r&`R0H2(eL4k`9Oa{#GN ({ + width : 8, height : 8, bpp : 4, + transparent : 1, + buffer : E.toArrayBuffer(atob("Ee7uER7u7uHuDuDu7u7u7u7u7u7g7u4OHgAA4RHu7hE=")) +}); + +var layout = new Layout({type: "v", c: [ + {type: "txt", font: "6x8", bgCol: "#F00", pad: 5, label: "TEXT"}, + {type: "img", font: "6x8", bgCol: "#0F0", pad: 5, src: img}, + {type: "btn", font: "6x8", bgCol: "#00F", pad: 5, label: "BTN"}, + {type: "v", bgCol: "#F0F", pad: 2, c: [ + {type: "txt", font: "6x8", bgCol: "#F00", label: "v with children"}, + {type: "txt", font: "6x8", bgCol: "#0F0", halign: -1, label: "halign -1"}, + {type: "txt", font: "6x8", bgCol: "#00F", halign: 1, label: "halign 1"}, + ]}, + {type: "h", bgCol: "#0FF", pad: 2, c: [ + {type: "txt", font: "6x8:2", bgCol: "#F00", label: "h"}, + {type: "txt", font: "6x8", bgCol: "#0F0", valign: -1, label: "valign -1"}, + {type: "txt", font: "6x8", bgCol: "#00F", valign: 1, label: "valign 1"}, + ]}, + {type: "h", bgCol: "#FF0", pad: 2, c: [ + {type: "v", bgCol: "#0F0", pad: 2, c: [ + {type: "txt", font: "6x8", bgCol: "#F00", pad: 2, label: "nested"}, + ]}, + ]}, +]}); diff --git a/tests/Layout/tests/padding_issue819_2.bmp b/tests/Layout/tests/padding_issue819_2.bmp new file mode 100644 index 0000000000000000000000000000000000000000..549736065bfb02321eeb280e6b5479dc12ce49bc GIT binary patch literal 15562 zcmeIxy=}uV5QgCkkTL*Q@c=1|AXR|ukV3$2!T@u3{0T@&h65O> zUfHHa`S^)^C_lY^J&GSM+CJ##Ltl4tZ`Y2`$J6OFP19i*-KM)@3bM(ROm} z8S{_U*ev|fEVEmGr}>tx(}#23%eAob%7 literal 0 HcmV?d00001 diff --git a/tests/Layout/tests/padding_issue819_2.js b/tests/Layout/tests/padding_issue819_2.js new file mode 100644 index 000000000..874d28867 --- /dev/null +++ b/tests/Layout/tests/padding_issue819_2.js @@ -0,0 +1,7 @@ +var layout = new Layout({type: "v", c: [ + {type: "h", pad: 20, c: [ + {type: "txt", font: "10%", label: "abcd"}, + {fillx: 1}, + {type: "txt", font: "10%", label: "1234"}, + ]}, +]}); diff --git a/tests/Layout/tests/padding_with_fill.bmp b/tests/Layout/tests/padding_with_fill.bmp new file mode 100644 index 0000000000000000000000000000000000000000..15e05b0d980d41eb76f4bc70456126994e45bf63 GIT binary patch literal 15562 zcmeI3v96mi6oy@?W0k(jeSi*ERi{dQhYooMwq(sCBok}Lj*;>LRfWXbFfx(eEA>s4d-X#p)c2}X>X%xVsxHgAyeut}AaS__!6x8l0U~n6)ab(t_My(|T-RD> znWhAPlb@tn=L5J*s`D&Ef~q&JCYc$yNPKcdGVArng|j49L#!m8eCXVSUXG=3JK>Yb ztn+M=GTb0?#gmXe1R3bV%^wyvKf}y(Suy+&4q9$>=+KK)|EuhF1In=B7PmU2x;ki- zfL7I^!b0oHm7As@F^zX1Tr_y#l3u8!qT-BlS1yCPqTyoUflJQ91olDmp+oM<#ZjWD zxa^7{H^-PrFC%W956ptVEA+MAd%5GgG?cN{d-O)`xC63g;r?pOaLq1c*;JRU>rF@= ziaQXC{q|=9TivfER;k>0rPsJLtG*bLEm=sHCFc zEP+^5=5kF}ni_+;qTz}ou3T~!Ca@2>J#?r#apfq1dmUc5P&Y)6>s{EI)9Z?EXh+hY z_qn=&sg8Bt=Yb0}O&-j7p9ijW-sgc!Qdut+oYBISi;13f-sj4NP>PDnu5i~Yz~Q{_ zbn1UcT@7ANox%6@*x=>LrJ;bo1hE6oxDQ3*${icLT)9cB7h*fT$eg$st;Pl~CoYVo zD7fqwj(P=X9lV_MT4xN-ji-|{!U~97vE_yMAXlbwDINcb$#qUw?CF|4CDej;ny{0Bq+Pn~~lonuHczTf5F&PI2+}D=u0f*_CUmm|vUHJD+53xje4ZVDtaq z+|2=F63l@V7mGZG%(bER4?RWWFWxr>r2ddXY6N?htCR@#E>|fQ9J$Z$gVs2M@X}OF z$L!-4j4NUlKJC+L?>Nu6|Kx*jF3DUHcY*%WF$;12hTzUQX?xqq7ki-Z^+Vd*lb5s^ zheC~;xMJruTDgZ9(Sg>1{uQ&BM+c$<(Se0Ku(|vW(u1>Fh2U;hmvacg8$3a|DDL^P z3ZWOz)Q0(yOQ`cK#7P#JfgLa}GsjwVV3q@P$Blp4Vtbx$7Qwy|{|JYQ5M109^UtNn eD&^1Kqo=j90si&kpviHwJPrCZq48a>%YnZE;Q5#U literal 0 HcmV?d00001 diff --git a/tests/Layout/tests/padding_with_fill.js b/tests/Layout/tests/padding_with_fill.js new file mode 100644 index 000000000..dede39722 --- /dev/null +++ b/tests/Layout/tests/padding_with_fill.js @@ -0,0 +1,26 @@ +var img = () => ({ + width : 8, height : 8, bpp : 4, + transparent : 1, + buffer : E.toArrayBuffer(atob("Ee7uER7u7uHuDuDu7u7u7u7u7u7g7u4OHgAA4RHu7hE=")) +}); + +var layout = new Layout({type: "v", c: [ + {type: "txt", font: "6x8", bgCol: "#F00", fillx: 1, pad: 5, label: "TEXT"}, + {type: "img", font: "6x8", bgCol: "#0F0", filly: 1, fillx: 1,pad: 5, src: img}, + {type: "btn", font: "6x8", bgCol: "#00F", fillx: 1, pad: 5, label: "BTN"}, + {type: "v", bgCol: "#F0F", pad: 2, c: [ + {type: "txt", font: "6x8", bgCol: "#F00", fillx: 1, filly: 1, label: "v with children"}, + {type: "txt", font: "6x8", bgCol: "#0F0", halign: -1, label: "halign -1"}, + {type: "txt", font: "6x8", bgCol: "#00F", halign: 1, label: "halign 1"}, + ]}, + {type: "h", bgCol: "#0FF", pad: 2, c: [ + {type: "txt", font: "6x8:2", bgCol: "#F00", fillx: 1, filly: 1, label: "h"}, + {type: "txt", font: "6x8", bgCol: "#0F0", valign: -1, label: "valign -1"}, + {type: "txt", font: "6x8", bgCol: "#00F", valign: 1, label: "valign 1"}, + ]}, + {type: "h", bgCol: "#FF0", pad: 2, c: [ + {type: "v", bgCol: "#0F0", pad: 2, c: [ + {type: "txt", font: "6x8", bgCol: "#F00", fillx: 1, filly: 1, pad: 2, label: "nested"}, + ]}, + ]}, +]}); From feb9ce8ee543997f5f25fd27b4e90b43d4ec29ec Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Sat, 25 Sep 2021 12:45:42 +0200 Subject: [PATCH 4/7] CSC sensor app cadence time ist 1/1024s --- apps/cscsensor/cscsensor.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js index 805a17296..3d4120269 100644 --- a/apps/cscsensor/cscsensor.app.js +++ b/apps/cscsensor/cscsensor.app.js @@ -156,7 +156,7 @@ class CSCSensor { const crankRevs = event.target.value.getUint16(1, true); const crankTime = event.target.value.getUint16(3, true); if (crankTime > this.lastCrankTime) { - this.cadence = (crankRevs-this.lastCrankRevs)/(crankTime-this.lastCrankTime)*60000; + this.cadence = (crankRevs-this.lastCrankRevs)/(crankTime-this.lastCrankTime)*(60*1024); qChanged = true; } this.lastCrankRevs = crankRevs; From 107ddab9f220df4655c704b562d3825d2383a42d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 27 Sep 2021 15:28:52 +0100 Subject: [PATCH 5/7] oops - tag as clocks --- apps.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 3b8fe574c..5b7d3b440 100644 --- a/apps.json +++ b/apps.json @@ -3526,7 +3526,8 @@ "icon": "app.png", "version":"0.01", "description": "A simple clock using the bold Anton font.", - "tags": "clock,b2", + "tags":"clock,b2", + "type":"clock", "storage": [ {"name":"antonclk.app.js","url":"app.js"}, {"name":"antonclk.img","url":"app-icon.js","evaluate":true} @@ -3537,7 +3538,8 @@ "icon": "app.png", "version":"0.01", "description": "A clock using a wave image by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: This requires a bugfix for #2049 on Bangle.js 1**", - "tags": "clock,b2", + "tags":"clock,b2", + "type":"clock", "storage": [ {"name":"waveclk.app.js","url":"app.js"}, {"name":"waveclk.img","url":"app-icon.js","evaluate":true} From be5539d9483cafb678b61365af833db5fe00842e Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Mon, 27 Sep 2021 11:00:22 -0400 Subject: [PATCH 6/7] Lazy Layout: don't assume bg is already cleared --- modules/Layout.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index 2caa11c97..9f3a805be 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -154,16 +154,20 @@ function touchHandler(l,e) { if (l.c) l.c.forEach(n => touchHandler(n,e)); } -function prepareLazyRender(l, rectsToClear, drawList, rects, bgCol) { - if ((l.bgCol != null && l.bgCol != bgCol) || l.type == "txt" || l.type == "btn" || l.type == "img" || l.type == "custom") { +function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) { + var bgCol = l.bgCol == null ? parentBg : g.toColor(l.bgCol); + if (bgCol != parentBg || l.type == "txt" || l.type == "btn" || l.type == "img" || l.type == "custom") { // Hash the layoutObject without including its children - let c = l.c; + var c = l.c; delete l.c; - let hash = "H"+E.CRC32(E.toJS(l)); // String keys maintain insertion order + var hash = "H"+E.CRC32(E.toJS(l)); // String keys maintain insertion order if (c) l.c = c; if (!delete rectsToClear[hash]) { - rects[hash] = {bg: bgCol, r: [l.x,l.y,l.x+l.w-1,l.y+l.h-1]}; + rects[hash] = { + bg: parentBg == null ? g.theme.bg : parentBg, + r: [l.x,l.y,l.x+l.w-1,l.y+l.h-1] + }; if (drawList) { drawList.push(l); drawList = null; // Prevent children from being redundantly added to the drawList @@ -171,7 +175,7 @@ function prepareLazyRender(l, rectsToClear, drawList, rects, bgCol) { } } - if (l.c) for (let ch of l.c) prepareLazyRender(ch, rectsToClear, drawList, rects, l.bgCol == null ? bgCol : l.bgCol); + if (l.c) for (var ch of l.c) prepareLazyRender(ch, rectsToClear, drawList, rects, bgCol); } Layout.prototype.render = function (l) { @@ -220,7 +224,7 @@ Layout.prototype.render = function (l) { if (!this.rects) this.rects = {}; var rectsToClear = this.rects.clone(); var drawList = []; - prepareLazyRender(l, rectsToClear, drawList, this.rects, g.getBgColor()); + prepareLazyRender(l, rectsToClear, drawList, this.rects, null); for (var h in rectsToClear) delete this.rects[h]; var clearList = Object.keys(rectsToClear).map(k=>rectsToClear[k]).reverse(); // Rects are cleared in reverse order so that the original bg color is restored for (var r of clearList) g.setBgColor(r.bg).clearRect.apply(g, r.r); From 28bd9e8354a87d5ae7297742e5750a3b56acda0b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 27 Sep 2021 18:13:53 +0100 Subject: [PATCH 7/7] Swap icons! --- apps/antonclk/app-icon.js | 2 +- apps/waveclk/app-icon.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/antonclk/app-icon.js b/apps/antonclk/app-icon.js index 00892e9c3..fad03d50f 100644 --- a/apps/antonclk/app-icon.js +++ b/apps/antonclk/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwge27dtAX4C+/dt+wFB/wCECIu3/dvBYNv34RC7/tCIu//99EYN9C4IpB74jG3379ovDFIIRBEYxHD/47D2wjHCIX+AQJHBCIIXBNZt/+5QBEZIgBAQX///9EZRWBBARHDEwhlC/9/EAJoBDQIOBNwyPCEYYCDJQ4CJSQ4CB0O2lojL2lwBIXFiwsK0f/KgUbuwRJo6cBPAO34cUmJHH7U/97tBgEGBIODEY/RXoOw7cAgHbtlxoojGx7hCjAjD20ANA1378MEIIAB4d0u5HGNAPYCAYAB2n2SQSPDjv3CIsF2lxEYto//+CoOGCIUt0O3EYtHvqMBvlw4UAgJQBqIjERgQDBsO+7FAhaMH64DB+4qB+3AgARG9uhIgQJD4dghd+7dLBQZoBaISwC4cArf27dpCIf/23f9uHCIQABhoNClsl20ttuwgYKBEAIAChOmCIOH/vx9ttwB2BDgMBAoIRBmnbpkbtk2ltsgAMCJQOwAgMBk+eq3AhiSBsE2GAX//4WCAAOBAoVbtt8mCJBgHHfYMHdgoRBott+zmDsEAn/tEwkC7UAVoYACgPbv4REAASTBEYY0BPIPwCJAjEu3Dvq8BCAnbsEwGgm2jbAC8EAjFvEAQREjuwDQXbvvx7cd2K/EgEb9oRCAoLOBjEAgk/A=")) +require("heatshrink").decompress(atob("mEwgX/AH4A/AAf+14BBAoPq/Wq1QFB+EP+kLAoNA+CdB3//yEP6ALB/sABYf8gEMgALB6ALJqoLB+tVgH//kQhkQhUABYImCIwPwh3whcA94UCgJHD+AXB/4LCcQQLCKYQLB+EDBZQFCBY/Qh4LJ4ALLl4LFioLCgE/KZMAv4XFBYimBC4/+BYw7DRwQLIV4ILWTQQLDOIUA/ALDAC+t1uv/263/6/Pq/YLC3vv//vM4Oq33rBYP6/u//2/C4Pr1YXC12vBwO+BYO69XmJDQA/ACIA==")) diff --git a/apps/waveclk/app-icon.js b/apps/waveclk/app-icon.js index fad03d50f..00892e9c3 100644 --- a/apps/waveclk/app-icon.js +++ b/apps/waveclk/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwgX/AH4A/AAf+14BBAoPq/Wq1QFB+EP+kLAoNA+CdB3//yEP6ALB/sABYf8gEMgALB6ALJqoLB+tVgH//kQhkQhUABYImCIwPwh3whcA94UCgJHD+AXB/4LCcQQLCKYQLB+EDBZQFCBY/Qh4LJ4ALLl4LFioLCgE/KZMAv4XFBYimBC4/+BYw7DRwQLIV4ILWTQQLDOIUA/ALDAC+t1uv/263/6/Pq/YLC3vv//vM4Oq33rBYP6/u//2/C4Pr1YXC12vBwO+BYO69XmJDQA/ACIA==")) +require("heatshrink").decompress(atob("mEwge27dtAX4C+/dt+wFB/wCECIu3/dvBYNv34RC7/tCIu//99EYN9C4IpB74jG3379ovDFIIRBEYxHD/47D2wjHCIX+AQJHBCIIXBNZt/+5QBEZIgBAQX///9EZRWBBARHDEwhlC/9/EAJoBDQIOBNwyPCEYYCDJQ4CJSQ4CB0O2lojL2lwBIXFiwsK0f/KgUbuwRJo6cBPAO34cUmJHH7U/97tBgEGBIODEY/RXoOw7cAgHbtlxoojGx7hCjAjD20ANA1378MEIIAB4d0u5HGNAPYCAYAB2n2SQSPDjv3CIsF2lxEYto//+CoOGCIUt0O3EYtHvqMBvlw4UAgJQBqIjERgQDBsO+7FAhaMH64DB+4qB+3AgARG9uhIgQJD4dghd+7dLBQZoBaISwC4cArf27dpCIf/23f9uHCIQABhoNClsl20ttuwgYKBEAIAChOmCIOH/vx9ttwB2BDgMBAoIRBmnbpkbtk2ltsgAMCJQOwAgMBk+eq3AhiSBsE2GAX//4WCAAOBAoVbtt8mCJBgHHfYMHdgoRBott+zmDsEAn/tEwkC7UAVoYACgPbv4REAASTBEYY0BPIPwCJAjEu3Dvq8BCAnbsEwGgm2jbAC8EAjFvEAQREjuwDQXbvvx7cd2K/EgEb9oRCAoLOBjEAgk/A="))