From d07580cc907d3bd7d3de221231ccf32936394d2d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 9 Jun 2022 10:41:03 +0100 Subject: [PATCH] Add minified layout library, which should improve layout speed a lot. --- modules/Layout.js | 8 ++++++ modules/Layout.min.js | 14 ++++++++++ tests/Layout/bin/runtest.sh | 51 ++++++++++++++++++++++--------------- 3 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 modules/Layout.min.js diff --git a/modules/Layout.js b/modules/Layout.js index 19cfabe11..436b04592 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -2,6 +2,14 @@ // See Layout.md for documentation +/* Minify to 'Layout.min.js' by: + + * checking out: https://github.com/espruino/EspruinoDocs + * run: ../EspruinoDocs/bin/minify.js modules/Layout.js modules/Layout.min.js + +*/ + + function Layout(layout, options) { this._l = this.l = layout; // Do we have >1 physical buttons? diff --git a/modules/Layout.min.js b/modules/Layout.min.js new file mode 100644 index 000000000..7dd169eb9 --- /dev/null +++ b/modules/Layout.min.js @@ -0,0 +1,14 @@ +function p(b,k){function d(h){h.id&&(f[h.id]=h);h.type||(h.type="");h.c&&h.c.forEach(d)}this._l=this.l=b;this.physBtns=2==process.env.HWVERSION?1:3;this.options=k||{};this.lazy=this.options.lazy||!1;if(2!=process.env.HWVERSION){var a=[];function h(m){"btn"==m.type&&a.push(m);m.c&&m.c.forEach(h)}h(b);a.length&&(this.physBtns=0,this.buttons=a,this.selectedButton=-1)}if(this.options.btns)if(this.b=b=this.options.btns,this.physBtns>=b.length){let h=Math.floor(Bangle.appRect.h/ +this.physBtns);for(2b.length;)b.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:b.map(m=>(m.type="txt",m.font="6x8",m.height=h,m.r=1,m))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:b.map(h=>(h.type="btn",h.filly=1,h.width=32,h.r=1,h))}]},a&&a.push.apply(a,this._l.c[1].c);this.setUI();var f=this;d(this._l);this.updateNeeded=!0}function r(b, +k,d,a,f){var h=null==b.bgCol?f:g.toColor(b.bgCol);if(h!=f||"txt"==b.type||"btn"==b.type||"img"==b.type||"custom"==b.type){var m=b.c;delete b.c;var c="H"+E.CRC32(E.toJS(b));m&&(b.c=m);delete k[c]||((a[c]=[b.x,b.y,b.x+b.w-1,b.y+b.h-1]).bg=null==f?g.theme.bg:f,d&&(d.push(b),d=null))}if(b.c)for(var l of b.c)r(l,k,d,a,h)}p.prototype.setUI=function(){Bangle.setUI();if(this.buttons){Bangle.setUI({mode:"updown",back:this.options.back},k=>{var d=this.selectedButton,a=this.buttons.length;if(void 0===k&&this.buttons[d])return this.buttons[d].cb(); +this.buttons[d]&&(delete this.buttons[d].selected,this.render(this.buttons[d]));d=(d+a+k)%a;this.buttons[d]&&(this.buttons[d].selected=1,this.render(this.buttons[d]));this.selectedButton=d});var b=!0}this.options.back&&!b&&Bangle.setUI({mode:"custom",back:this.options.back});if(this.b){function k(d,a){.75=d.x&&a.y>=d.y&&a.x<=d.x+d.w&&a.y<=d.y+d.h&&(2==a.type&&d.cbl?d.cbl(a):d.cb&&d.cb(a));d.c&&d.c.forEach(f=>k(f,a))}Bangle.touchHandler=(d,a)=>k(this._l,a);Bangle.on("touch",Bangle.touchHandler)}};p.prototype.render=function(b){function k(c){"ram"; +g.reset();void 0!==c.col&&g.setColor(c.col);void 0!==c.bgCol&&g.setBgColor(c.bgCol).clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1);d[c.type](c)}b||(b=this._l);this.updateNeeded&&this.update();var d={"":function(){},txt:function(c){if(c.wrap){g.setFont(c.font).setFontAlign(0,-1);var l=g.wrapString(c.label,c.w),e=c.y+(c.h-g.getFontHeight()*l.length>>1);l.forEach((n,q)=>g.drawString(n,c.x+(c.w>>1),e+g.getFontHeight()*q))}else g.setFont(c.font).setFontAlign(0,0,c.r).drawString(c.label,c.x+(c.w>>1),c.y+(c.h>> +1))},btn:function(c){var l=c.x+(0|c.pad),e=c.y+(0|c.pad),n=c.w-(c.pad<<1),q=c.h-(c.pad<<1);l=[l,e+4,l+4,e,l+n-5,e,l+n-1,e+4,l+n-1,e+q-5,l+n-5,e+q-1,l+4,e+q-1,l,e+q-5,l,e+4];e=c.selected?g.theme.bgH:g.theme.bg2;g.setColor(e).fillPoly(l).setColor(c.selected?g.theme.fgH:g.theme.fg2).drawPoly(l);void 0!==c.col&&g.setColor(c.col);c.src?g.setBgColor(e).drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)}):g.setFont(c.font||"6x8:2").setFontAlign(0, +0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:function(c){g.drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)})},custom:function(c){c.render(c)},h:function(c){c.c.forEach(k)},v:function(c){c.c.forEach(k)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(),f=[];r(b,a,f,this.rects,null);for(var h in a)delete this.rects[h];b=Object.keys(a).map(c=>a[c]).reverse();for(var m of b)g.setBgColor(m.bg).clearRect.apply(g, +m);f.forEach(k)}else k(b)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(b){switch(b.type){case "h":var k=b.x+(0|b.pad),d=0,a=b.c&&b.c.reduce((e,n)=>e+(0|n.fillx),0);a||(k+=b.w-b._w>>1,a=1);var f=k;b.c.forEach(e=>{e.x=0|f;k+=e._w;d+=0|e.fillx;f=k+Math.floor(d*(b.w-b._w)/a);e.w=0|f-e.x;e.h=0|(e.filly?b.h-(b.pad<<1):e._h);e.y=0|b.y+(0|b.pad)+((1+(0|e.valign))*(b.h-(b.pad<<1)-e.h)>>1);e.c&&this.layout(e)});break;case "v":var h=b.y+(0|b.pad),m=0,c=b.c&&b.c.reduce((e, +n)=>e+(0|n.filly),0);c||(h+=b.h-b._h>>1,c=1);var l=h;b.c.forEach(e=>{e.y=0|l;h+=e._h;m+=0|e.filly;l=h+Math.floor(m*(b.h-b._h)/c);e.h=0|l-e.y;e.w=0|(e.fillx?b.w-(b.pad<<1):e._w);e.x=0|b.x+(0|b.pad)+((1+(0|e.halign))*(b.w-(b.pad<<1)-e.w)>>1);e.c&&this.layout(e)})}};p.prototype.debug=function(b,k){b||(b=this._l);k=k||1;g.setColor(k&1,k&2,k&4).drawRect(b.x+k-1,b.y+k-1,b.x+b.w-k,b.y+b.h-k);b.pad&&g.drawRect(b.x+b.pad-1,b.y+b.pad-1,b.x+b.w-b.pad,b.y+b.h-b.pad);k++;b.c&&b.c.forEach(d=>this.debug(d,k))}; +p.prototype.update=function(){function b(a){"ram";k[a.type](a);if(a.r&1){var f=a._w;a._w=a._h;a._h=f}a._w=0|Math.max(a._w+(a.pad<<1),0|a.width);a._h=0|Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var k={txt:function(a){a.font.endsWith("%")&&(a.font="Vector"+Math.round(g.getHeight()*a.font.slice(0,-1)/100));if(a.wrap)a._h=a._w=0;else{var f=g.setFont(a.font).stringMetrics(a.label);a._w=f.width;a._h=f.height}},btn:function(a){a.font&&a.font.endsWith("%")&&(a.font="Vector"+Math.round(g.getHeight()* +a.font.slice(0,-1)/100));var f=a.src?g.imageMetrics("function"==typeof a.src?a.src():a.src):g.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+f.height;a._w=20+f.width},img:function(a){var f=g.imageMetrics("function"==typeof a.src?a.src():a.src),h=a.scale||1;a._w=f.width*h;a._h=f.height*h},"":function(a){a._w=0;a._h=0},custom:function(a){a._w=0;a._h=0},h:function(a){a.c.forEach(b);a._h=a.c.reduce((f,h)=>Math.max(f,h._h),0);a._w=a.c.reduce((f,h)=>f+h._w,0);null==a.fillx&&a.c.some(f=>f.fillx)&& +(a.fillx=1);null==a.filly&&a.c.some(f=>f.filly)&&(a.filly=1)},v:function(a){a.c.forEach(b);a._h=a.c.reduce((f,h)=>f+h._h,0);a._w=a.c.reduce((f,h)=>Math.max(f,h._w),0);null==a.fillx&&a.c.some(f=>f.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(f=>f.filly)&&(a.filly=1)}},d=this._l;b(d);d.fillx||d.filly?(d.w=Bangle.appRect.w,d.h=Bangle.appRect.h,d.x=Bangle.appRect.x,d.y=Bangle.appRect.y):(d.w=d._w,d.h=d._h,d.x=Bangle.appRect.w-d.w>>1,d.y=Bangle.appRect.y+(Bangle.appRect.h-d.h>>1));this.layout(d)};p.prototype.clear= +function(b){b||(b=this._l);g.reset();void 0!==b.bgCol&&g.setBgColor(b.bgCol);g.clearRect(b.x,b.y,b.x+b.w-1,b.y+b.h-1)};exports=p \ No newline at end of file diff --git a/tests/Layout/bin/runtest.sh b/tests/Layout/bin/runtest.sh index e06dec86b..9bac72283 100755 --- a/tests/Layout/bin/runtest.sh +++ b/tests/Layout/bin/runtest.sh @@ -18,24 +18,35 @@ SRCJS=$1 SRCBMP=$SRCDIR/`basename $SRCJS .js`.bmp echo "TEST $SRCJS ($SRCBMP)" -cat ../../modules/Layout.js > $TESTJS -echo 'Bangle = { setUI : function(){}, appRect:{x:0,y:0,w:176,h:176,x2:175,y2:175} };BTN1=0;process.env = process.env;process.env.HWVERSION=2;' >> $TESTJS -echo 'g = Graphics.createArrayBuffer(176,176,4);' >> $TESTJS -cat $SRCJS >> $TESTJS || exit 1 -echo 'layout.render()' >> $TESTJS -#echo 'layout.debug()' >> $TESTJS -echo 'require("fs").writeFileSync("'$TESTBMP'",g.asBMP())' >> $TESTJS +run_test () { + LAYOUTFILE=$1 + echo 'exports = {};' > $TESTJS + cat $LAYOUTFILE >> $TESTJS + echo ';' >> $TESTJS + echo 'Layout = exports;' >> $TESTJS + echo 'Bangle = { setUI : function(){}, appRect:{x:0,y:0,w:176,h:176,x2:175,y2:175} };BTN1=0;process.env = process.env;process.env.HWVERSION=2;' >> $TESTJS + echo 'g = Graphics.createArrayBuffer(176,176,4);' >> $TESTJS + cat $SRCJS >> $TESTJS || exit 1 + echo 'layout.render()' >> $TESTJS + #echo 'layout.debug()' >> $TESTJS + echo 'require("fs").writeFileSync("'$TESTBMP'",g.asBMP())' >> $TESTJS + echo ============================================= + echo TESTING $LAYOUTFILE $SRCJS + bin/espruino $TESTJS || exit 1 + if ! cmp $TESTBMP $SRCBMP >/dev/null 2>&1 + then + echo ============================================= + echo $LAYOUTFILE + echo $TESTBMP $SRCBMP differ + echo ============================================== + convert "+append" $TESTBMP $SRCBMP testresult.bmp + display testresult.bmp + exit 1 + else + echo Files are the same + exit 0 + fi +} -bin/espruino $TESTJS || exit 1 -if ! cmp $TESTBMP $SRCBMP >/dev/null 2>&1 -then - echo ============================================= - echo $TESTBMP $SRCBMP differ - echo ============================================== - convert "+append" $TESTBMP $SRCBMP testresult.bmp - display testresult.bmp - exit 1 -else - echo Files are the same - exit 0 -fi +run_test ../../modules/Layout.js +run_test ../../modules/Layout.min.js