Bangle.js2: Including Layout module in internal flash

This commit is contained in:
Gordon Williams 2024-10-24 12:27:43 +01:00
parent b8634fd8e0
commit ef5c7c8a38
9 changed files with 378 additions and 0 deletions

View File

@ -65,6 +65,8 @@
ESP32: jshPinWatch now returns correct value (event ID vs pin number)
JS in the binary now uses jspExecuteJSFunctionCode which helps to skip a parsing step
JS modules that are included are now pretokenised
Bangle.js2: Now using pre-minified showRecoveryMenu and showTestScreen
Bangle.js2: Including Layout module in internal flash
2v23 : Fix XON/OFF thresholds to be based off the correct buffer size

View File

@ -83,6 +83,7 @@ info = {
'DEFINES += -DESPR_STORAGE_INITIAL_CONTENTS=1', # use banglejs2_storage_default
'DEFINES += -DESPR_USE_STORAGE_CACHE=32', # Add a 32 entry cache to speed up finding files
'JSMODULESOURCES += libs/js/banglejs/locale.min.js',
'JSMODULESOURCES += libs/js/banglejs/Layout.min.js',
'DFU_SETTINGS=--application-version 0xff --hw-version 52 --sd-req 0xa9,0xae,0xb6',
'DFU_PRIVATE_KEY=targets/nrf5x_dfu/dfu_private_key.pem',

View File

@ -88,6 +88,7 @@ info = {
'DEFINES += -DESPR_STORAGE_INITIAL_CONTENTS=1', # use banglejs2_storage_default
'DEFINES += -DESPR_USE_STORAGE_CACHE=32', # Add a 32 entry cache to speed up finding files
'JSMODULESOURCES += libs/js/banglejs/locale.min.js',
'JSMODULESOURCES += libs/js/banglejs/Layout.min.js',
'DFU_SETTINGS=--application-version 0xff --hw-version 52 --sd-req 0xa9,0xae,0xb6',
'DFU_PRIVATE_KEY=targets/nrf5x_dfu/dfu_private_key.pem',

View File

@ -55,6 +55,7 @@ info = {
'SOURCES += libs/banglejs/banglejs2_storage_default.c',
'DEFINES += -DESPR_STORAGE_INTITIAL_CONTENTS=1', #
'JSMODULESOURCES += libs/js/banglejs/locale.min.js',
'JSMODULESOURCES += libs/js/banglejs/Layout.min.js',
]
}
};

View File

@ -85,6 +85,7 @@ info = {
#'DEFINES += -DESPR_STORAGE_INITIAL_CONTENTS=1', # use banglejs2_storage_default
#'DEFINES += -DESPR_USE_STORAGE_CACHE=32', # Add a 32 entry cache to speed up finding files - NOT NEEDED ON INTERNAL FLASH
'JSMODULESOURCES += libs/js/banglejs/locale.min.js',
'JSMODULESOURCES += libs/js/banglejs/Layout.min.js',
'DFU_SETTINGS=--application-version 0xff --hw-version 52 --sd-req 0xa9,0xae,0xb6',
'DFU_PRIVATE_KEY=targets/nrf5x_dfu/dfu_private_key.pem',

View File

@ -52,6 +52,7 @@ info = {
'SOURCES += libs/misc/stepcount.c',
'SOURCES += libs/misc/heartrate.c',
'JSMODULESOURCES += libs/js/banglejs/locale.min.js',
'JSMODULESOURCES += libs/js/banglejs/Layout.min.js',
'SOURCES += libs/banglejs/banglejs2_storage_default.c',
'DEFINES += -DESPR_STORAGE_INITIAL_CONTENTS=1',
]

366
libs/js/banglejs/Layout.js Normal file
View File

@ -0,0 +1,366 @@
/* Copyright (c) 2022 Bangle.js contributors. See the file LICENSE for copying permission. */
// 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?
this.options = options || {};
this.lazy = this.options.lazy || false;
this.physBtns = 1;
let btnList;
if (process.env.HWVERSION!=2) {
this.physBtns = 3;
// no touchscreen, find any buttons in 'layout'
btnList = [];
function btnRecurser(l) {"ram";
if (l.type=="btn") btnList.push(l);
if (l.c) l.c.forEach(btnRecurser);
}
btnRecurser(layout);
if (btnList.length) { // there are buttons in 'layout'
// disable physical buttons - use them for back/next/select
this.physBtns = 0;
this.buttons = btnList;
this.selectedButton = -1;
}
}
if (this.options.btns) {
var buttons = this.options.btns;
if (this.physBtns >= buttons.length) {
// enough physical buttons
this.b = buttons;
let btnHeight = Math.floor(Bangle.appRect.h / this.physBtns);
if (this.physBtns > 2 && buttons.length==1)
buttons.unshift({label:""}); // pad so if we have a button in the middle
while (this.physBtns > buttons.length)
buttons.push({label:""});
this._l.width = g.getWidth()-8; // text width
this._l = {type:"h", filly:1, c: [
this._l,
{type:"v", pad:1, filly:1, c: buttons.map(b=>(b.type="txt",b.font="6x8",b.height=btnHeight,b.r=1,b))}
]};
} else {
// add 'soft' buttons
this._l.width = g.getWidth()-32; // button width
this._l = {type:"h", c: [
this._l,
{type:"v", c: buttons.map(b=>(b.type="btn",b.filly=1,b.width=32,b.r=1,b))}
]};
// if we're selecting with physical buttons, add these to the list
if (btnList) btnList.push.apply(btnList, this._l.c[1].c);
}
}
// Link in all buttons/touchscreen/etc
this.setUI();
// recurse over layout doing some fixing up if needed
var ll = this;
function recurser(l) {"ram";
// add IDs
if (l.id) ll[l.id] = l;
// fix type up
if (!l.type) l.type="";
if (l.c) l.c.forEach(recurser);
}
recurser(this._l);
this.updateNeeded = true;
}
Layout.prototype.setUI = function() {
Bangle.setUI(); // remove all existing input handlers
let uiSet;
if (this.buttons) {
// multiple buttons so we'll jus use back/next/select
Bangle.setUI({mode:"updown", back:this.options.back, remove:this.options.remove}, dir=>{
var s = this.selectedButton, l=this.buttons.length;
if (dir===undefined && this.buttons[s])
return this.buttons[s].cb();
if (this.buttons[s]) {
delete this.buttons[s].selected;
this.render(this.buttons[s]);
}
s = (s+l+dir) % l;
if (this.buttons[s]) {
this.buttons[s].selected = 1;
this.render(this.buttons[s]);
}
this.selectedButton = s;
});
uiSet = true;
}
if ((this.options.back || this.options.remove) && !uiSet) Bangle.setUI({mode: "custom", back: this.options.back, remove: this.options.remove});
// physical buttons -> actual applications
if (this.b) {
// Handler for button watch events
function pressHandler(btn,e) {
if (e.time-e.lastTime > 0.75 && this.b[btn].cbl)
this.b[btn].cbl(e);
else
if (this.b[btn].cb) this.b[btn].cb(e);
}
if (Bangle.btnWatches) Bangle.btnWatches.forEach(clearWatch);
Bangle.btnWatches = [];
if (this.b[0]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,0), BTN1, {repeat:true,edge:-1}));
if (this.b[1]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,1), BTN2, {repeat:true,edge:-1}));
if (this.b[2]) Bangle.btnWatches.push(setWatch(pressHandler.bind(this,2), BTN3, {repeat:true,edge:-1}));
}
// Handle touch events on new Bangle.js
if (process.env.HWVERSION==2) {
function touchHandler(l,e) {
if (l.cb && e.x>=l.x && e.y>=l.y && e.x<=l.x+l.w && e.y<=l.y+l.h) {
if (e.type==2 && l.cbl) l.cbl(e); else if (l.cb) l.cb(e);
}
if (l.c) l.c.forEach(n => touchHandler(n,e));
}
Bangle.touchHandler = (_,e)=>touchHandler(this._l,e);
Bangle.on('touch',Bangle.touchHandler);
}
}
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
var c = l.c;
delete l.c;
var hash = "H"+E.CRC32(E.toJS(l)); // String keys maintain insertion order
if (c) l.c = c;
if (!delete rectsToClear[hash]) {
var r = rects[hash] = [l.x,l.y,l.x+l.w-1,l.y+l.h-1];
r.bg = parentBg == null ? g.theme.bg : parentBg;
if (drawList) {
drawList.push(l);
drawList = null; // Prevent children from being redundantly added to the drawList
}
}
}
if (l.c) for (var ch of l.c) prepareLazyRender(ch, rectsToClear, drawList, rects, bgCol);
}
Layout.prototype.render = function (l) {
if (!l) l = this._l;
if (this.updateNeeded) this.update();
var gfx=g; // define locally, because this is faster
function render(l) {"ram";
gfx.reset();
if (l.col!==undefined) gfx.setColor(l.col);
if (l.bgCol!==undefined) gfx.setBgColor(l.bgCol).clearRect(l.x,l.y,l.x+l.w-1,l.y+l.h-1);
cb[l.type](l);
}
var cb = {
"":function(){},
"txt":function(l){"ram";
if (l.wrap) {
var lines = gfx.setFont(l.font).setFontAlign(0,-1).wrapString(l.label, l.w);
var y = l.y+((l.h-gfx.getFontHeight()*lines.length)>>1);
gfx.drawString(lines.join("\n"), l.x+(l.w>>1), y);
} else {
gfx.setFont(l.font).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1));
}
}, "btn":function(l){"ram";
var x = l.x+(0|l.pad), y = l.y+(0|l.pad),
w = l.w-(l.pad<<1), h = l.h-(l.pad<<1);
var poly = [
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
],
btnborder = l.btnBorderCol!==undefined?l.btnBorderCol:gfx.theme.fg2,
btnface = l.btnFaceCol!==undefined?l.btnFaceCol:gfx.theme.bg2;
if(l.selected){
btnface = gfx.theme.bgH, btnborder = gfx.theme.fgH;
}
gfx.setColor(btnface).fillPoly(poly).setColor(btnborder).drawPoly(poly);
if (l.col!==undefined) gfx.setColor(l.col);
if (l.src) gfx.setBgColor(btnface).drawImage(
"function"==typeof l.src?l.src():l.src,
l.x + l.w/2,
l.y + l.h/2,
{scale: l.scale||undefined, rotate: Math.PI*0.5*(l.r||0)}
);
else gfx.setFont(l.font||"6x8:2").setFontAlign(0,0,l.r).drawString(l.label,l.x+l.w/2,l.y+l.h/2);
}, "img":function(l){"ram";
gfx.drawImage(
"function"==typeof l.src?l.src():l.src,
l.x + l.w/2,
l.y + l.h/2,
{scale: l.scale||undefined, rotate: Math.PI*0.5*(l.r||0)}
);
}, "custom":function(l){"ram"; l.render(l);
}, "h":function(l) { "ram"; l.c.forEach(render);
}, "v":function(l) { "ram"; l.c.forEach(render); }
};
if (this.lazy) {
// we have to use 'var' here not 'let', otherwise the minifier
// renames vars to the same name, which causes problems as Espruino
// doesn't yet honour the scoping of 'let'
if (!this.rects) this.rects = {};
var rectsToClear = this.rects.clone();
var drawList = [];
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) gfx.setBgColor(r.bg).clearRect.apply(g, r);
drawList.forEach(render);
} else { // non-lazy
render(l);
}
};
Layout.prototype.forgetLazyState = function () {
this.rects = {};
}
Layout.prototype.layout = function (l) {
// l = current layout element
var cb = {
"h" : function(l) {"ram";
var acc_w = l.x + (0|l.pad);
var accfillx = 0;
var fillx = l.c && l.c.reduce((a,l)=>a+(0|l.fillx),0);
if (!fillx) { acc_w += (l.w-l._w)>>1; fillx=1; }
var x = acc_w;
l.c.forEach(c => {
c.x = 0|x;
acc_w += c._w;
accfillx += 0|c.fillx;
x = acc_w + Math.floor(accfillx*(l.w-l._w)/fillx);
c.w = 0|(x - c.x);
c.h = 0|(c.filly ? l.h - (l.pad<<1) : c._h);
c.y = 0|(l.y + (0|l.pad) + ((1+(0|c.valign))*(l.h-(l.pad<<1)-c.h)>>1));
if (c.c) cb[c.type](c);
});
},
"v" : function(l) {"ram";
var acc_h = l.y + (0|l.pad);
var accfilly = 0;
var filly = l.c && l.c.reduce((a,l)=>a+(0|l.filly),0);
if (!filly) { acc_h += (l.h-l._h)>>1; filly=1; }
var y = acc_h;
l.c.forEach(c => {
c.y = 0|y;
acc_h += c._h;
accfilly += 0|c.filly;
y = acc_h + Math.floor(accfilly*(l.h-l._h)/filly);
c.h = 0|(y - c.y);
c.w = 0|(c.fillx ? l.w - (l.pad<<1) : c._w);
c.x = 0|(l.x + (0|l.pad) + ((1+(0|c.halign))*(l.w-(l.pad<<1)-c.w)>>1));
if (c.c) cb[c.type](c);
});
}
};
if (cb[l.type]) cb[l.type](l);
};
Layout.prototype.debug = function(l,c) {
if (!l) l = this._l;
c=c||1;
g.setColor(c&1,c&2,c&4).drawRect(l.x+c-1, l.y+c-1, l.x+l.w-c, l.y+l.h-c);
if (l.pad)
g.drawRect(l.x+l.pad-1, l.y+l.pad-1, l.x+l.w-l.pad, l.y+l.h-l.pad);
c++;
if (l.c) l.c.forEach(n => this.debug(n,c));
};
Layout.prototype.update = function() {
delete this.updateNeeded;
var gfx=g; // define locally, because this is faster
// update sizes
function updateMin(l) {"ram";
cb[l.type](l);
if (l.r&1) { // rotation
var t = l._w;l._w=l._h;l._h=t;
}
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) {"ram";
if (l.font.endsWith("%"))
l.font = "Vector"+Math.round(gfx.getHeight()*l.font.slice(0,-1)/100);
if (l.wrap) {
l._h = l._w = 0;
} else {
var m = g.setFont(l.font).stringMetrics(l.label);
l._w = m.width; l._h = m.height;
}
}, "btn": function(l) {"ram";
if (l.font && l.font.endsWith("%"))
l.font = "Vector"+Math.round(gfx.getHeight()*l.font.slice(0,-1)/100);
var m = l.src?gfx.imageMetrics("function"==typeof l.src?l.src():l.src):gfx.setFont(l.font||"6x8:2").stringMetrics(l.label);
l._h = 16 + m.height;
l._w = 20 + m.width;
}, "img": function(l) {"ram";
var m = gfx.imageMetrics("function"==typeof l.src?l.src():l.src), s=l.scale||1; // get width and height out of image
l._w = m.width*s;
l._h = m.height*s;
}, "": function(l) {"ram";
// size should already be set up in width/height
l._w = 0;
l._h = 0;
}, "custom": function(l) {"ram";
// size should already be set up in width/height
l._w = 0;
l._h = 0;
}, "h": function(l) {"ram";
l.c.forEach(updateMin);
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) {"ram";
l.c.forEach(updateMin);
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;
}
};
var l = this._l;
updateMin(l);
delete cb;
if (l.fillx || l.filly) { // fill all
l.w = Bangle.appRect.w;
l.h = Bangle.appRect.h;
l.x = Bangle.appRect.x;
l.y = Bangle.appRect.y;
} else { // or center
l.w = l._w;
l.h = l._h;
l.x = (Bangle.appRect.w-l.w)>>1;
l.y = Bangle.appRect.y+((Bangle.appRect.h-l.h)>>1);
}
// layout children
this.layout(l);
};
Layout.prototype.clear = function(l) {
if (!l) l = this._l;
g.reset();
if (l.bgCol!==undefined) g.setBgColor(l.bgCol);
g.clearRect(l.x,l.y,l.x+l.w-1,l.y+l.h-1);
};
exports = Layout;

3
libs/js/banglejs/Layout.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
ªp(d,h){ªb(e){Ñram;e.idž(a[e.id]=e);e.type (e.type="");e.cže.c.forEach(b)}¯._l=¯.l=d;¯.options=h {};¯.lazy=¯.options.lazy !1;¯.physBtns=1;­f;£(2Œprocess.env.HWVERSION){¯.physBtns=3;f=[];ªe(l){Ñram;ÑbtnŠl.typežf.push(l);l.cžl.c.forEach(e)}e(d);f.lengthž(¯.physBtns=0,¯.buttons=f,¯.selectedButton=-1)}£(¯.options.btns)£(d=¯.options.btns,¯.physBtnsd.length){¯.b=d;­e=Math.floor(Bangle.appRect.h/¯.physBtns);§(2<¯.physBtnsž1Šd.lengthžd.unshift({label:""});¯.physBtns>d.length;)d.push({label:""});¯._l.width=g.getWidth()-8;¯._l={type:Ñh,filly:1,c:[¯._l,{type:Ñv,pad:1,filly:1,c:d.map(l¢(l.type=Ñtxt,l.font=Ñ6x8,l.height=e,l.r=1,l))}]}}¤¯._l.width=g.getWidth()-32,¯._l={type:Ñh,c:[¯._l,{type:Ñv,c:d.map(e¢(e.type=Ñbtn,e.filly=1,e.width=32,e.r=1,e))}]},fžf.push.apply(f,¯._l.c[1].c);¯.setUI();¬a=¯;b(¯._l);¯.updateNeeded=!0}ªt(d,h,b,f,a){¬e=Šd.bgCol?a:g.toColor(d.bgCol);£(eŒa ÑtxtŠd.type ÑbtnŠd.type ÑimgŠd.type ÑcustomŠd.type){¬l=d.c;¾d.c;¬k=ÑH+E.CRC32(E.toJS(d));(d.c=l);¾h[k] ((f[k]=[d.x,d.y,d.x+d.w-1,d.y+d.h-1]).bg=Ša?g.theme.bg:a,(b.push(d),b=))}£(d.c)§(¬cÆd.c)t(c,h,b,f,e)}p.prototype.setUI=ª(){Bangle.setUI();­d;¯.buttonsž(Bangle.setUI({mode:Ñupdown,back:¯.options.back,remove:¯.options.remove},h¢{¬b=¯.selectedButton,f=¯.buttons.length;£(À0¯.buttons[b])«¯.buttons[b].cb();¯.buttons[b]ž(¾¯.buttons[b].selected,¯.render(¯.buttons[b]));b=(b+f+h)%f;¯.buttons[b]ž(¯.buttons[b].selected=1,¯.render(¯.buttons[b]));¯.selectedButton=b}),d=!0);!¯.options.backž!¯.options.remove d Bangle.setUI({mode:Ñcustom,back:¯.options.back,remove:¯.options.remove});£(¯.b){ªh(b,f){.75<f.time-f.lastTimež¯.b[b].cbl?¯.b[b].cbl(f):¯.b[b].cbž¯.b[b].cb(f)}Bangle.btnWatchesžBangle.btnWatches.forEach(clearWatch);Bangle.btnWatches=[];¯.b[0]žBangle.btnWatches.push(setWatch(h.bind(¯,0),BTN1,{repeat:!0,edge:-1}));¯.b[1]žBangle.btnWatches.push(setWatch(h.bind(¯,1),BTN2,{repeat:!0,edge:-1}));¯.b[2]žBangle.btnWatches.push(setWatch(h.bind(¯,2),BTN3,{repeat:!0,edge:-1}))}£(2Šprocess.env.HWVERSION){ªh(b,f){b.cbžf.xb.xžf.yb.yžf.xŽb.x+b.wžf.yŽb.y+b.(2Šf.typežb.cbl?b.cbl(f):b.cbžb.cb(f));b.cžb.c.forEach(a¢h(a,f))}Bangle.touchHandler=(b,f)¢h(¯._l,f);Bangle.on(Ñtouch,Bangle.touchHandler)}};p.prototype.render=ª(d){ªh(c){Ñram;b.reset();À0<EFBFBD>c.colžb.setColor(c.col);À0<EFBFBD>c.bgColžb.setBgColor(c.bgCol).clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1);f[c.type](c)}d (d=¯._l);¯.updateNeededž¯.update();¬b=g,f={"":ª(){},txt:ª(c){Ñram;£(c.wrap){¬m=b.setFont(c.font).setFontAlign(0,-1).wrapString(c.label,c.w),n=c.y+(c.h-b.getFontHeight()*m.length1);b.drawString(m.join(Ñ
),c.x+(c.w1),n)}¤b.setFont(c.font).setFontAlign(0,0,c.r).drawString(c.label,c.x+(c.w1),c.y+(c.h1))},btn:ª(c){Ñram;¬m=c.x+(0|c.pad),n=c.y+(0|c.pad),q=c.w-(c.pad<EFBFBD>1),r=c.h-(c.pad<EFBFBD>1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=À0<EFBFBD>c.btnBorderCol?c.btnBorderCol:b.theme.fg2;q=À0<EFBFBD>c.btnFaceCol?c.btnFaceCol:b.theme.bg2;c.selectedž(q=b.theme.bgH,n=b.theme.fgH);b.setColor(q).fillPoly(m).setColor(n).drawPoly(m);À0<EFBFBD>c.colžb.setColor(c.col);c.src?b.setBgColor(q).drawImage(ÑfunctionŠ¿c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale À0,rotate:.5*Math.PI*(c.r 0)}):b.setFont(c.font Ñ6x8:2).setFontAlign(0,0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:ª(c){Ñram;b.drawImage(ÑfunctionŠ¿c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale À0,rotate:.5*Math.PI*(c.r 0)})},custom:ª(c){Ñram;c.render(c)},h:ª(c){Ñram;c.c.forEach(h)},v:ª(c){Ñram;c.c.forEach(h)}};£(¯.lazy){¯.rects (¯.rects={});¬a=¯.rects.clone(),e=[];t(d,a,e,¯.rects,);§(¬l¹a)¾¯.rects[l];d=Object.keys(a).map(c¢a[c]).reverse();§(¬kÆd)b.setBgColor(k.bg).clearRect.apply(g,k);e.forEach(h)}¤h(d)};p.prototype.forgetLazyState=ª(){¯.rects={}};p.prototype.layout=ª(d){¬h={h:ª(b){Ñram;¬f=b.x+(0|b.pad),a=0,e=b.cžb.c.reduce((k,c)¢k+(0|c.fillx),0);e (fb.w-b._w1,e=1);¬l=f;b.c.forEach(k¢{k.x=0|l;fk._w;a0|k.fillx;l=f+Math.floor(a*(b.w-b._w)/e);k.w=0|l-k.x;k.h=0|(k.filly?b.h-(b.pad<EFBFBD>1):k._h);k.y=0|b.y+(0|b.pad)+((1+(0|k.valign))*(b.h-(b.pad<EFBFBD>1)-k.h)1);£(k.c)h[k.type](k)})},v:ª(b){Ñram;¬f=b.y+(0|b.pad),a=0,e=b.cžb.c.reduce((k,c)¢k+(0|c.filly),0);e (fb.h-b._h1,e=1);¬l=f;b.c.forEach(k¢{k.y=0|l;fk._h;a0|k.filly;l=f+Math.floor(a*(b.h-b._h)/e);k.h=0|l-k.y;k.w=0|(k.fillx?b.w-(b.pad<EFBFBD>1):k._w);k.x=0|b.x+(0|b.pad)+((1+(0|k.halign))*(b.w-(b.pad<EFBFBD>1)-k.w)1);£(k.c)h[k.type](k)})}};£(h[d.type])h[d.type](d)};p.prototype.debug=
ª(d,h){d (d=¯._l);h=h 1;g.setColor(h&1,h&2,h&4).drawRect(d.x+h-1,d.y+h-1,d.x+d.w-h,d.y+d.h-h);d.padžg.drawRect(d.x+d.pad-1,d.y+d.pad-1,d.x+d.w-d.pad,d.y+d.h-d.pad);h˜;d.cžd.c.forEach(b¢¯.debug(b,h))};p.prototype.update=ª(){ªd(a){Ñram;b[a.type](a);£(a.r&1){¬e=a._w;a._w=a._h;a._h=e}a._w=Math.max(a._w+(a.pad<EFBFBD>1),0|a.width);a._h=Math.max(a._h+(a.pad<EFBFBD>1),0|a.height)}¾¯.updateNeeded;¬h=g,b={txt:ª(a){Ñram;a.font.endsWith(Ñ%)ž(a.font=ÑVector+Math.round(h.getHeight()*a.font.slice(0,-1)/100));£(a.wrap)a._h=a._w=0;¤{¬e=g.setFont(a.font).stringMetrics(a.label);a._w=e.width;a._h=e.height}},btn:ª(a){Ñram;a.fontža.font.endsWith(Ñ%)ž(a.font=ÑVector+Math.round(h.getHeight()*a.font.slice(0,-1)/100));¬e=a.src?h.imageMetrics(ÑfunctionŠ¿a.src?a.src():a.src):h.setFont(a.font Ñ6x8:2).stringMetrics(a.label);a._h=16+e.height;a._w=20+e.width},img:ª(a){Ñram;¬e=h.imageMetrics(ÑfunctionŠ¿a.src?a.src():a.src),l=a.scale 1;a._w=e.width*l;a._h=e.height*l},"":ª(a){Ñram;a._w=0;a._h=0},custom:ª(a){Ñram;a._w=0;a._h=0},h:ª(a){Ñram;a.c.forEach(d);a._h=a.c.reduce((e,l)¢Math.max(e,l._h),0);a._w=a.c.reduce((e,l)¢e+l._w,0);Ša.fillxža.c.some(e¢e.fillx)ž(a.fillx=1);Ša.fillyža.c.some(e¢e.filly)ž(a.filly=1)},v:ª(a){Ñram;a.c.forEach(d);a._h=a.c.reduce((e,l)¢e+l._h,0);a._w=a.c.reduce((e,l)¢Math.max(e,l._w),0);Ša.fillxža.c.some(e¢e.fillx)ž(a.fillx=1);Ša.fillyža.c.some(e¢e.filly)ž(a.filly=1)}},f=¯._l;d(f);¾b;f.fillx f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h,f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h1));¯.layout(f)};p.prototype.clear=ª(d){d (d=¯._l);g.reset();À0<EFBFBD>d.bgColžg.setBgColor(d.bgCol);g.clearRect(d.x,d.y,d.x+d.w-1,d.y+d.h-1)};exports=p

View File

@ -23,6 +23,7 @@ wget https://www.espruino.com/modules/SHT3C.min.js -O SHT3C.min.js
#wget https://www.espruino.com/modules/PCA9685.min.js -O PCA9685.min.js
#wget https://www.espruino.com/modules/Smartibot.min.js -O Smartibot.min.js
wget https://www.espruino.com/modules/EspruinoWiFi.min.js -O espruino_wifi/Wifi.min.js
wget https://banglejs.com/apps/modules/Layout.js -O banglejs/Layout.js
# Other libs
node ../../../EspruinoDocs/bin/minify.js --pretokenise nordic/Thingy.js nordic/Thingy.min.js
@ -54,6 +55,7 @@ node ../../../EspruinoDocs/bin/minify.js --pretokenise banglejs/Bangle_showRecov
node ../../../EspruinoDocs/bin/minify.js --pretokenise banglejs/Bangle_showRecoveryMenu.js banglejs/Bangle_showRecoveryMenu.min.js
node ../../../EspruinoDocs/bin/minify.js --pretokenise banglejs/Bangle_showTestScreen.js banglejs/Bangle_showTestScreen.min.js
node ../../../EspruinoDocs/bin/minify.js --pretokenise banglejs/locale.js banglejs/locale.min.js
node ../../../EspruinoDocs/bin/minify.js --pretokenise banglejs/Layout.js banglejs/Layout.min.js
node ../../../EspruinoDocs/bin/minify.js --pretokenise dickens/Bangle_setUI_DICKENS.js dickens/Bangle_setUI_DICKENS.min.js
node ../../../EspruinoDocs/bin/minify.js --pretokenise dickens/Bangle_drawWidgets_DICKENS.js dickens/Bangle_drawWidgets_DICKENS.min.js