diff --git a/apps/accellog/app.js b/apps/accellog/app.js index fdb4d52be..c54c5002b 100644 --- a/apps/accellog/app.js +++ b/apps/accellog/app.js @@ -99,12 +99,12 @@ function startRecord(force) { {type:"txt", id:"time", font:"6x8:2", label:" - ", pad:5, bgCol:g.theme.bg}, {type:"txt", font:"6x8:2", label:"RECORDING", bgCol:"#f00", pad:5, fillx:1}, ] - },[ // Buttons... + },{btns:[ // Buttons... {label:"STOP", cb:()=>{ Bangle.removeListener('accel', accelHandler); showMenu(); }} - ]); + ]}); layout.render(); // now start writing diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index c2b4bde12..2c6d66e45 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -40,7 +40,7 @@ const layout = new Layout({ {height: 40}, {id: "date", type: "txt", font: "10%", valign: 1}, ], -}, false, {lazy: true}); +}, {lazy: true}); // adjustments based on screen size and whether we display am/pm let thickness; // bar thickness, same as time font "pixel block" size if (is12Hour) { diff --git a/apps/gpsinfo/gps-info.js b/apps/gpsinfo/gps-info.js index 047c1bc17..df888651a 100644 --- a/apps/gpsinfo/gps-info.js +++ b/apps/gpsinfo/gps-info.js @@ -68,7 +68,7 @@ function onGPS(fix) { {type:"txt", font:"6x8", label:"", fillx:true, id:"time" }, {type:"txt", font:"6x8", label:"", fillx:true, id:"sat" }, {type:"txt", font:"6x8", label:"", fillx:true, id:"maidenhead" }, - ]},[],{lazy:true}); + ]},{lazy:true}); } else { layout = new Layout( { type:"v", c: [ @@ -80,9 +80,9 @@ function onGPS(fix) { {type:"txt", font:"6x8", pad:3, label:"Satellites" } ]}, {type:"txt", font:"6x8", label:"", id:"progress" } - ]},[],{lazy:true}); + ]},{lazy:true}); } - g.clearRect(0,24,g.getWidth(),g.getHeight()); + g.clearRect(0,24,g.getWidth(),g.getHeight()); layout.render(); } lastFix = fix; @@ -103,7 +103,7 @@ function onGPS(fix) { nofix = (nofix+1) % 4; layout.progress.label = ".".repeat(nofix) + " ".repeat(4-nofix); } - layout.render(); + layout.render(); } Bangle.loadWidgets(); diff --git a/apps/speedo/speedo.js b/apps/speedo/speedo.js index 2e729c114..1d87859a8 100644 --- a/apps/speedo/speedo.js +++ b/apps/speedo/speedo.js @@ -23,7 +23,7 @@ function onGPS(fix) { {type:"txt", font:"10%", label:fix.satellites, pad:2, id:"sat" }, {type:"txt", font:"6x8", pad:3, label:"Satellites" } ]}, - ]},[],{lazy:true}); + ]},{lazy:true}); } else { layout = new Layout( { type:"v", c: [ @@ -34,7 +34,7 @@ function onGPS(fix) { {type:"txt", font:"10%", label:fix.satellites, pad:2, id:"sat" }, {type:"txt", font:"6x8", pad:3, label:"Satellites" } ]}, - ]},[],{lazy:true}); + ]},{lazy:true}); } g.clearRect(0,24,g.getWidth(),g.getHeight()); layout.render(); diff --git a/apps/weather/app.js b/apps/weather/app.js index 6dba14143..6a0852f81 100644 --- a/apps/weather/app.js +++ b/apps/weather/app.js @@ -35,7 +35,7 @@ var layout = new Layout({type:"v", bgCol: g.theme.bg, c: [ {type: "txt", font: "6x8", pad: 4, id: "updateTime", label: "15 minutes ago"}, ]}, {filly: 1}, -]}, null, {lazy: true}); +]}, {lazy: true}); function formatDuration(millis) { let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s"); diff --git a/modules/Layout.js b/modules/Layout.js index 09e2a3d8c..94abd42fd 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -4,7 +4,7 @@ Usage: ``` var Layout = require("Layout"); -var layout = new Layout( layoutObject, btns, options ) +var layout = new Layout( layoutObject, options ) layout.render(optionalObject); ``` @@ -47,15 +47,13 @@ layoutObject has: * A `filly` int to choose if the object should fill available space in y. 0=no, 1=yes, 2=2x more space * `width` and `height` fields to optionally specify minimum size -btns is an array of objects containing: - -* `label` - the text on the button -* `cb` - a callback function -* `cbl` - a callback function for long presses - options is an object containing: * `lazy` - a boolean specifying whether to enable automatic lazy rendering +* `btns` - array of objects containing: + * `label` - the text on the button + * `cb` - a callback function + * `cbl` - a callback function for long presses If automatic lazy rendering is enabled, calls to `layout.render()` will attempt to automatically determine what objects have changed or moved, clear their previous locations, and re-render just those objects. @@ -78,9 +76,8 @@ Other functions: */ -function Layout(layout, buttons, options) { +function Layout(layout, options) { this._l = this.l = layout; - this.b = buttons; // Do we have >1 physical buttons? this.physBtns = (process.env.HWVERSION==2) ? 1 : 3; this.yOffset = Object.keys(global.WIDGETS).length ? 24 : 0; @@ -88,7 +85,43 @@ function Layout(layout, buttons, options) { options = options || {}; this.lazy = options.lazy || false; - if (buttons) { + var btnList; + if (process.env.HWVERSION!=2) { + // no touchscreen, find any buttons in 'layout' + btnList = []; + function btnRecurser(l) { + 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; + Bangle.setUI("updown", 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 += dir; + if (s<0) s+=lh; + if (s>=l) s-=l; + if (this.buttons[s]) { + this.buttons[s].selected = 1; + this.render(this.buttons[s]); + } + this.selectedButton = s; + }); + } + } + + if (options.btns) { + var buttons = options.btns; + this.b = buttons; if (this.physBtns >= buttons.length) { // Handler for button watch events function pressHandler(btn,e) { @@ -114,12 +147,14 @@ function Layout(layout, buttons, options) { {type:"v", pad:1, filly:1, c: buttons.map(b=>(b.type="txt",b.font="6x8",b.height=btnHeight,b.r=1,b))} ]}; } else { - let btnHeight = Math.floor((g.getHeight()-this.yOffset) / buttons.length); - this._l.width = g.getWidth()-20; // button width + // 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.h=btnHeight,b.w=32,b.r=1,b))} + {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); } } if (process.env.HWVERSION==2) { @@ -233,7 +268,7 @@ Layout.prototype.render = function (l) { 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); + g.setColor(l.selected?g.theme.bgH:g.theme.bg2).fillPoly(poly).setColor(l.selected ? g.theme.fgH : g.theme.fg2).drawPoly(poly).setFont("6x8",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 + (0|l.pad), l.y + (0|l.pad)); }, "custom":function(l){ @@ -347,8 +382,8 @@ Layout.prototype.update = function() { l._w = g.stringWidth(l.label); } }, "btn": function(l) { - l._h = 24; - l._w = 14 + l.label.length*8; + l._h = 32; + l._w = 20 + l.label.length*12; }, "img": function(l) { var src = l.src(); // get width and height out of image if (src[0]) { @@ -407,5 +442,3 @@ Layout.prototype.clear = function(l) { 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; diff --git a/tests/Layout/bin/runtest.sh b/tests/Layout/bin/runtest.sh index 5ce2ab21f..c85b3fe6c 100755 --- a/tests/Layout/bin/runtest.sh +++ b/tests/Layout/bin/runtest.sh @@ -1,7 +1,7 @@ #!/bin/bash # Requires Linux x64 (for ./espruino) # Also imagemagick for display - + cd `dirname $0`/.. if [ "$#" -ne 1 ]; then echo "USAGE:" @@ -19,7 +19,7 @@ SRCBMP=$SRCDIR/`basename $SRCJS .js`.bmp echo "TEST $SRCJS ($SRCBMP)" cat ../../modules/Layout.js > $TESTJS -echo 'Bangle = {};BTN1=0;process.env = process.env;process.env.HWVERSION=2;' >> $TESTJS +echo 'Bangle = { setUI : function(){} };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 @@ -39,5 +39,3 @@ else echo Files are the same exit 0 fi - - diff --git a/tests/Layout/tests/accellog.js b/tests/Layout/tests/accellog.js index 4ae865f4f..63b2ab410 100644 --- a/tests/Layout/tests/accellog.js +++ b/tests/Layout/tests/accellog.js @@ -6,8 +6,8 @@ var layout = new Layout({ type: "v", c: [ {type:"txt", id:"time", font:"6x8:2", label:" - ", pad:5}, {type:"txt", font:"6x8:2", label:"RECORDING", bgCol:"#f00", pad:5, fillx:1}, ] -},[ // Buttons... +}{btns:[ // Buttons... {label:"STOP", cb:()=>{}} -]); +]}); layout.samples.label = "123"; layout.time.label = "123s"; diff --git a/tests/Layout/tests/buttons_1_bangle1.bmp b/tests/Layout/tests/buttons_1_bangle1.bmp new file mode 100644 index 000000000..8da6d1e8a Binary files /dev/null and b/tests/Layout/tests/buttons_1_bangle1.bmp differ diff --git a/tests/Layout/tests/buttons_1_bangle1.js b/tests/Layout/tests/buttons_1_bangle1.js new file mode 100644 index 000000000..fb6fb29fa --- /dev/null +++ b/tests/Layout/tests/buttons_1_bangle1.js @@ -0,0 +1,9 @@ +var BTN2 = 1, BTN3=2; +process.env = process.env;process.env.HWVERSION=1; +g = Graphics.createArrayBuffer(240,240,4); + +var layout = new Layout({ type: "v", c: [ + {type:"txt", font:"6x8", label:"A test"}, +]},{btns:[ // Buttons... + {label:"STOP", cb:()=>{}}, +]}); diff --git a/tests/Layout/tests/buttons_1_bangle2.bmp b/tests/Layout/tests/buttons_1_bangle2.bmp new file mode 100644 index 000000000..2e4d1a256 Binary files /dev/null and b/tests/Layout/tests/buttons_1_bangle2.bmp differ diff --git a/tests/Layout/tests/buttons_1_bangle2.js b/tests/Layout/tests/buttons_1_bangle2.js new file mode 100644 index 000000000..74b6c96af --- /dev/null +++ b/tests/Layout/tests/buttons_1_bangle2.js @@ -0,0 +1,6 @@ + +var layout = new Layout({ type: "v", c: [ + {type:"txt", font:"6x8", label:"A test"}, +]},{btns:[ // Buttons... + {label:"STOP", cb:()=>{}}, +]}); diff --git a/tests/Layout/tests/buttons_3_bangle1.bmp b/tests/Layout/tests/buttons_3_bangle1.bmp new file mode 100644 index 000000000..4edc88d08 Binary files /dev/null and b/tests/Layout/tests/buttons_3_bangle1.bmp differ diff --git a/tests/Layout/tests/buttons_3_bangle1.js b/tests/Layout/tests/buttons_3_bangle1.js new file mode 100644 index 000000000..c8346f449 --- /dev/null +++ b/tests/Layout/tests/buttons_3_bangle1.js @@ -0,0 +1,11 @@ +var BTN2 = 1, BTN3=2; +process.env = process.env;process.env.HWVERSION=1; +g = Graphics.createArrayBuffer(240,240,4); + +var layout = new Layout({ type: "v", c: [ + {type:"txt", font:"6x8", label:"A test"}, +]},{btns:[ // Buttons... + {label:"A", cb:()=>{}}, + {label:"STOP", cb:()=>{}}, + {label:"B", cb:()=>{}}, +]}); diff --git a/tests/Layout/tests/buttons_3_bangle2.bmp b/tests/Layout/tests/buttons_3_bangle2.bmp new file mode 100644 index 000000000..4b9fa5b42 Binary files /dev/null and b/tests/Layout/tests/buttons_3_bangle2.bmp differ diff --git a/tests/Layout/tests/buttons_3_bangle2.js b/tests/Layout/tests/buttons_3_bangle2.js new file mode 100644 index 000000000..bf70fcb38 --- /dev/null +++ b/tests/Layout/tests/buttons_3_bangle2.js @@ -0,0 +1,8 @@ + +var layout = new Layout({ type: "v", c: [ + {type:"txt", font:"6x8", label:"A test"}, +]},{btns:[ // Buttons... + {label:"A", cb:()=>{}}, + {label:"STOP", cb:()=>{}}, + {label:"B", cb:()=>{}}, +]}); diff --git a/tests/Layout/tests/buttons_osd_bangle1.bmp b/tests/Layout/tests/buttons_osd_bangle1.bmp new file mode 100644 index 000000000..723075385 Binary files /dev/null and b/tests/Layout/tests/buttons_osd_bangle1.bmp differ diff --git a/tests/Layout/tests/buttons_osd_bangle1.js b/tests/Layout/tests/buttons_osd_bangle1.js new file mode 100644 index 000000000..108cb62b0 --- /dev/null +++ b/tests/Layout/tests/buttons_osd_bangle1.js @@ -0,0 +1,17 @@ +var BTN2 = 1, BTN3=2; +process.env = process.env;process.env.HWVERSION=1; +g = Graphics.createArrayBuffer(240,240,4); + +/* When displaying OSD buttons on Bangle.js 1 we should turn +the side buttons into 'soft' buttons and then use the physical +buttons for up/down selection */ + +var layout = new Layout({ type: "v", c: [ + {type:"txt", font:"6x8", label:"A test"}, + {type:"btn", label:"Button 1"}, + {type:"btn", label:"Button 2"} +]},{btns:[ // Buttons... + {label:"A", cb:()=>{}}, + {label:"STOP", cb:()=>{}}, + {label:"B", cb:()=>{}}, +]}); diff --git a/tests/Layout/tests/buttons_osd_bangle2.bmp b/tests/Layout/tests/buttons_osd_bangle2.bmp new file mode 100644 index 000000000..397c9e871 Binary files /dev/null and b/tests/Layout/tests/buttons_osd_bangle2.bmp differ diff --git a/tests/Layout/tests/buttons_osd_bangle2.js b/tests/Layout/tests/buttons_osd_bangle2.js new file mode 100644 index 000000000..8733eb691 --- /dev/null +++ b/tests/Layout/tests/buttons_osd_bangle2.js @@ -0,0 +1,10 @@ + +var layout = new Layout({ type: "v", c: [ + {type:"txt", font:"6x8", label:"A test"}, + {type:"btn", label:"Button 1"}, + {type:"btn", label:"Button 2"} +]},{btns:[ // Buttons... + {label:"A", cb:()=>{}}, + {label:"STOP", cb:()=>{}}, + {label:"B", cb:()=>{}}, +]}); diff --git a/tests/Layout/tests/padding.bmp b/tests/Layout/tests/padding.bmp index b2d192750..84ae4dc1b 100644 Binary files a/tests/Layout/tests/padding.bmp and b/tests/Layout/tests/padding.bmp differ diff --git a/tests/Layout/tests/padding_with_fill.bmp b/tests/Layout/tests/padding_with_fill.bmp index 2c785bbc0..9f82ed09f 100644 Binary files a/tests/Layout/tests/padding_with_fill.bmp and b/tests/Layout/tests/padding_with_fill.bmp differ