Merge remote-tracking branch 'upstream/master'
15
apps.json
|
@ -4,7 +4,7 @@
|
||||||
"tags": "tool,system,b2",
|
"tags": "tool,system,b2",
|
||||||
"type":"bootloader",
|
"type":"bootloader",
|
||||||
"icon": "bootloader.png",
|
"icon": "bootloader.png",
|
||||||
"version":"0.30",
|
"version":"0.31",
|
||||||
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":".boot0","url":"boot0.js"},
|
{"name":".boot0","url":"boot0.js"},
|
||||||
|
@ -3599,5 +3599,18 @@
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"menusmall.boot.js","url":"boot.js"}
|
{"name":"menusmall.boot.js","url":"boot.js"}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{ "id": "ffcniftya",
|
||||||
|
"name": "Nifty-A Clock",
|
||||||
|
"icon": "app.png",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "A nifty clock with time and date",
|
||||||
|
"tags":"clock,b2",
|
||||||
|
"type":"clock",
|
||||||
|
"allow_emulator":true,
|
||||||
|
"storage": [
|
||||||
|
{"name":"ffcniftya.app.js","url":"app.js"},
|
||||||
|
{"name":"ffcniftya.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -99,12 +99,12 @@ function startRecord(force) {
|
||||||
{type:"txt", id:"time", font:"6x8:2", label:" - ", pad:5, bgCol:g.theme.bg},
|
{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},
|
{type:"txt", font:"6x8:2", label:"RECORDING", bgCol:"#f00", pad:5, fillx:1},
|
||||||
]
|
]
|
||||||
},[ // Buttons...
|
},{btns:[ // Buttons...
|
||||||
{label:"STOP", cb:()=>{
|
{label:"STOP", cb:()=>{
|
||||||
Bangle.removeListener('accel', accelHandler);
|
Bangle.removeListener('accel', accelHandler);
|
||||||
showMenu();
|
showMenu();
|
||||||
}}
|
}}
|
||||||
]);
|
]});
|
||||||
layout.render();
|
layout.render();
|
||||||
|
|
||||||
// now start writing
|
// now start writing
|
||||||
|
|
|
@ -40,7 +40,7 @@ const layout = new Layout({
|
||||||
{height: 40},
|
{height: 40},
|
||||||
{id: "date", type: "txt", font: "10%", valign: 1},
|
{id: "date", type: "txt", font: "10%", valign: 1},
|
||||||
],
|
],
|
||||||
}, false, {lazy: true});
|
}, {lazy: true});
|
||||||
// adjustments based on screen size and whether we display am/pm
|
// adjustments based on screen size and whether we display am/pm
|
||||||
let thickness; // bar thickness, same as time font "pixel block" size
|
let thickness; // bar thickness, same as time font "pixel block" size
|
||||||
if (is12Hour) {
|
if (is12Hour) {
|
||||||
|
|
|
@ -30,3 +30,4 @@
|
||||||
0.29: Update boot0 to avoid code block (faster execution)
|
0.29: Update boot0 to avoid code block (faster execution)
|
||||||
Fix issues where 'Uncaught Error: Function not found' could happen with multiple .boot.js
|
Fix issues where 'Uncaught Error: Function not found' could happen with multiple .boot.js
|
||||||
0.30: Remove 'Get GPS time' at boot. Latest firmwares keep time through reboots, so this is not needed now
|
0.30: Remove 'Get GPS time' at boot. Latest firmwares keep time through reboots, so this is not needed now
|
||||||
|
0.31: Add polyfills for g.wrapString, g.imageMetrics, g.stringMetrics
|
||||||
|
|
|
@ -131,6 +131,41 @@ else if (mode=="updown") {
|
||||||
throw new Error("Unknown UI mode");
|
throw new Error("Unknown UI mode");
|
||||||
};\n`;
|
};\n`;
|
||||||
}
|
}
|
||||||
|
if (!g.imageMetrics) { // added in 2v11 - this is a limited functionality polyfill
|
||||||
|
boot += `Graphics.prototype.imageMetrics=function(src) {
|
||||||
|
if (src[0]) return {width:src[0],height:src[1]};
|
||||||
|
else if ('object'==typeof src) return {
|
||||||
|
width:("width" in src) ? src.width : src.getWidth(),
|
||||||
|
height:("height" in src) ? src.height : src.getHeight()};
|
||||||
|
var im = E.toString(src);
|
||||||
|
return {width:im.charCodeAt(0), height:im.charCodeAt(1)};
|
||||||
|
};\n`;
|
||||||
|
}
|
||||||
|
if (!g.stringMetrics) { // added in 2v11 - this is a limited functionality polyfill
|
||||||
|
boot += `Graphics.prototype.stringMetrics=function(txt) {
|
||||||
|
return {width:this.stringWidth(txt), height:this.getFontHeight()};
|
||||||
|
};\n`;
|
||||||
|
}
|
||||||
|
if (!g.wrapString) { // added in 2v11 - this is a limited functionality polyfill
|
||||||
|
boot += `Graphics.prototype.wrapString=function(str, maxWidth) {
|
||||||
|
var lines = [];
|
||||||
|
for (var unwrappedLine of str.split("\n")) {
|
||||||
|
var words = unwrappedLine.split(" ");
|
||||||
|
var line = words.shift();
|
||||||
|
for (var word of words) {
|
||||||
|
if (g.stringWidth(line + " " + word) > maxWidth) {
|
||||||
|
lines.push(line);
|
||||||
|
line = word;
|
||||||
|
} else {
|
||||||
|
line += " " + word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
};\n`;
|
||||||
|
}
|
||||||
|
|
||||||
// Append *.boot.js files
|
// Append *.boot.js files
|
||||||
require('Storage').list(/\.boot\.js/).forEach(bootFile=>{
|
require('Storage').list(/\.boot\.js/).forEach(bootFile=>{
|
||||||
// we add a semicolon so if the file is wrapped in (function(){ ... }()
|
// we add a semicolon so if the file is wrapped in (function(){ ... }()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New Clock Nifty A
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwkEIf4A5gX/+AGEn//mIWLgP/C4gGCAAMgC5UvC4sDC4YICkIhBgMQiEBE4Uxn4XDj//iEAn/yA4ICBgUikEikYXBBAIXEn/xJYURAYMygERkQHBiYLBKYIXF+AVDC4czgUSmIXBCQgED+ZeBR4YXBLYICDC5CPGC4IAIC40zmaPDC4MSLQQXK+ayCR4QXCiRoEC44ECh4bCC4MTiTDBC6ZHOC5B3NLYcvC4kBgL5BAAUikT+BfIIrB/8ykf/eYQXBkUTI4cBW4YQCgQGDmAXDkJfEC46GBAoJKCR4geCAAMRAAZRDAoIODO4UBPRIAJR5QXWgKNCTApNDC5Mv/6/DAwR3GAAyHCC4anJIo3/+bvEa4Uia4oXHkEvC4cvIgUf+YXKHYIvEAgcPC5QSGC5UBSwYXJLYQXFkUhgABBC5Ef/4mBl4XEmETmIXKgaXBmYCBC4cTkMxiQXJS4IACL4p3MgESCwJHFR5oxCiB3FkERC5cSToQXFmUyiAZFR48Bn7zCAQMjkfykQkBN4n/XgKPBAAQgCUQIfBUwYXHFgIGCdI4XDmYADmIIEkAWJAH4A4A=="))
|
|
@ -0,0 +1,95 @@
|
||||||
|
const locale = require("locale");
|
||||||
|
const is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"];
|
||||||
|
|
||||||
|
/* Clock *********************************************/
|
||||||
|
const scale = g.getWidth() / 176;
|
||||||
|
|
||||||
|
const widget = 24;
|
||||||
|
|
||||||
|
const viewport = {
|
||||||
|
width: g.getWidth(),
|
||||||
|
height: g.getHeight(),
|
||||||
|
}
|
||||||
|
|
||||||
|
const center = {
|
||||||
|
x: viewport.width / 2,
|
||||||
|
y: Math.round(((viewport.height - widget) / 2) + widget),
|
||||||
|
}
|
||||||
|
|
||||||
|
function d02(value) {
|
||||||
|
return ('0' + value).substr(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
g.reset();
|
||||||
|
g.clearRect(0, widget, viewport.width, viewport.height);
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
const hour = d02(now.getHours() - (is12Hour && now.getHours() > 12 ? 12 : 0));
|
||||||
|
const minutes = d02(now.getMinutes());
|
||||||
|
const day = d02(now.getDay());
|
||||||
|
const month = d02(now.getMonth() + 1);
|
||||||
|
const year = now.getFullYear();
|
||||||
|
|
||||||
|
const month2 = locale.month(now, 3);
|
||||||
|
const day2 = locale.dow(now, 3);
|
||||||
|
|
||||||
|
g.setFontAlign(1, 0).setFont("Vector", 90 * scale);
|
||||||
|
g.drawString(hour, center.x + 32 * scale, center.y - 31 * scale);
|
||||||
|
g.drawString(minutes, center.x + 32 * scale, center.y + 46 * scale);
|
||||||
|
|
||||||
|
g.fillRect(center.x + 30 * scale, center.y - 72 * scale, center.x + 32 * scale, center.y + 74 * scale);
|
||||||
|
|
||||||
|
g.setFontAlign(-1, 0).setFont("Vector", 16 * scale);
|
||||||
|
g.drawString(year, center.x + 40 * scale, center.y - 62 * scale);
|
||||||
|
g.drawString(month, center.x + 40 * scale, center.y - 44 * scale);
|
||||||
|
g.drawString(day, center.x + 40 * scale, center.y - 26 * scale);
|
||||||
|
g.drawString(month2, center.x + 40 * scale, center.y + 48 * scale);
|
||||||
|
g.drawString(day2, center.x + 40 * scale, center.y + 66 * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Minute Ticker *************************************/
|
||||||
|
|
||||||
|
let tickTimer;
|
||||||
|
|
||||||
|
function clearTickTimer() {
|
||||||
|
if (tickTimer) {
|
||||||
|
clearTimeout(tickTimer);
|
||||||
|
tickTimer = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function queueNextTick() {
|
||||||
|
clearTickTimer();
|
||||||
|
tickTimer = setTimeout(tick, 60000 - (Date.now() % 60000));
|
||||||
|
// tickTimer = setTimeout(tick, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tick() {
|
||||||
|
draw();
|
||||||
|
queueNextTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init **********************************************/
|
||||||
|
|
||||||
|
// Clear the screen once, at startup
|
||||||
|
g.clear();
|
||||||
|
// Start ticking
|
||||||
|
tick();
|
||||||
|
|
||||||
|
// Stop updates when LCD is off, restart when on
|
||||||
|
Bangle.on('lcdPower', (on) => {
|
||||||
|
if (on) {
|
||||||
|
tick(); // Start ticking
|
||||||
|
} else {
|
||||||
|
clearTickTimer(); // stop ticking
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load widgets
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
|
||||||
|
// Show launcher when middle button pressed
|
||||||
|
Bangle.setUI("clock");
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -68,7 +68,7 @@ function onGPS(fix) {
|
||||||
{type:"txt", font:"6x8", label:"", fillx:true, id:"time" },
|
{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:"sat" },
|
||||||
{type:"txt", font:"6x8", label:"", fillx:true, id:"maidenhead" },
|
{type:"txt", font:"6x8", label:"", fillx:true, id:"maidenhead" },
|
||||||
]},[],{lazy:true});
|
]},{lazy:true});
|
||||||
} else {
|
} else {
|
||||||
layout = new Layout( {
|
layout = new Layout( {
|
||||||
type:"v", c: [
|
type:"v", c: [
|
||||||
|
@ -80,7 +80,7 @@ function onGPS(fix) {
|
||||||
{type:"txt", font:"6x8", pad:3, label:"Satellites" }
|
{type:"txt", font:"6x8", pad:3, label:"Satellites" }
|
||||||
]},
|
]},
|
||||||
{type:"txt", font:"6x8", label:"", id:"progress" }
|
{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();
|
layout.render();
|
||||||
|
|
|
@ -10,6 +10,7 @@ function menuMain() {
|
||||||
function menuStepCount() {
|
function menuStepCount() {
|
||||||
E.showMenu({
|
E.showMenu({
|
||||||
"":{title:"Step Counting"},
|
"":{title:"Step Counting"},
|
||||||
|
"< Back":()=>menuMain(),
|
||||||
"per hour":()=>stepsPerHour()
|
"per hour":()=>stepsPerHour()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -17,6 +18,7 @@ function menuStepCount() {
|
||||||
function menuMovement() {
|
function menuMovement() {
|
||||||
E.showMenu({
|
E.showMenu({
|
||||||
"":{title:"Movement"},
|
"":{title:"Movement"},
|
||||||
|
"< Back":()=>menuMain(),
|
||||||
"per hour":()=>movementPerHour()
|
"per hour":()=>movementPerHour()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ function onGPS(fix) {
|
||||||
{type:"txt", font:"10%", label:fix.satellites, pad:2, id:"sat" },
|
{type:"txt", font:"10%", label:fix.satellites, pad:2, id:"sat" },
|
||||||
{type:"txt", font:"6x8", pad:3, label:"Satellites" }
|
{type:"txt", font:"6x8", pad:3, label:"Satellites" }
|
||||||
]},
|
]},
|
||||||
]},[],{lazy:true});
|
]},{lazy:true});
|
||||||
} else {
|
} else {
|
||||||
layout = new Layout( {
|
layout = new Layout( {
|
||||||
type:"v", c: [
|
type:"v", c: [
|
||||||
|
@ -34,7 +34,7 @@ function onGPS(fix) {
|
||||||
{type:"txt", font:"10%", label:fix.satellites, pad:2, id:"sat" },
|
{type:"txt", font:"10%", label:fix.satellites, pad:2, id:"sat" },
|
||||||
{type:"txt", font:"6x8", pad:3, label:"Satellites" }
|
{type:"txt", font:"6x8", pad:3, label:"Satellites" }
|
||||||
]},
|
]},
|
||||||
]},[],{lazy:true});
|
]},{lazy:true});
|
||||||
}
|
}
|
||||||
g.clearRect(0,24,g.getWidth(),g.getHeight());
|
g.clearRect(0,24,g.getWidth(),g.getHeight());
|
||||||
layout.render();
|
layout.render();
|
||||||
|
|
|
@ -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"},
|
{type: "txt", font: "6x8", pad: 4, id: "updateTime", label: "15 minutes ago"},
|
||||||
]},
|
]},
|
||||||
{filly: 1},
|
{filly: 1},
|
||||||
]}, null, {lazy: true});
|
]}, {lazy: true});
|
||||||
|
|
||||||
function formatDuration(millis) {
|
function formatDuration(millis) {
|
||||||
let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s");
|
let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s");
|
||||||
|
|
|
@ -4,7 +4,7 @@ Usage:
|
||||||
|
|
||||||
```
|
```
|
||||||
var Layout = require("Layout");
|
var Layout = require("Layout");
|
||||||
var layout = new Layout( layoutObject, btns, options )
|
var layout = new Layout( layoutObject, options )
|
||||||
layout.render(optionalObject);
|
layout.render(optionalObject);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ layoutObject has:
|
||||||
* `undefined` - blank, can be used for padding
|
* `undefined` - blank, can be used for padding
|
||||||
* `"txt"` - a text label, with value `label` and `r` for text rotation. 'font' is required
|
* `"txt"` - a text label, with value `label` and `r` for text rotation. 'font' is required
|
||||||
* `"btn"` - a button, with value `label` and callback `cb`
|
* `"btn"` - a button, with value `label` and callback `cb`
|
||||||
* `"img"` - an image where the function `src` is called to return an image to draw
|
* `"img"` - an image where `src` is an image, or a function which is called to return an image to draw
|
||||||
* `"custom"` - a custom block where `render(layoutObj)` is called to render
|
* `"custom"` - a custom block where `render(layoutObj)` is called to render
|
||||||
* `"h"` - Horizontal layout, `c` is an array of more `layoutObject`
|
* `"h"` - Horizontal layout, `c` is an array of more `layoutObject`
|
||||||
* `"v"` - Veritical layout, `c` is an array of more `layoutObject`
|
* `"v"` - Veritical layout, `c` is an array of more `layoutObject`
|
||||||
|
@ -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
|
* 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
|
* `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:
|
options is an object containing:
|
||||||
|
|
||||||
* `lazy` - a boolean specifying whether to enable automatic lazy rendering
|
* `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
|
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.
|
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._l = this.l = layout;
|
||||||
this.b = buttons;
|
|
||||||
// Do we have >1 physical buttons?
|
// Do we have >1 physical buttons?
|
||||||
this.physBtns = (process.env.HWVERSION==2) ? 1 : 3;
|
this.physBtns = (process.env.HWVERSION==2) ? 1 : 3;
|
||||||
this.yOffset = Object.keys(global.WIDGETS).length ? 24 : 0;
|
this.yOffset = Object.keys(global.WIDGETS).length ? 24 : 0;
|
||||||
|
@ -88,7 +85,43 @@ function Layout(layout, buttons, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
this.lazy = options.lazy || false;
|
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) {
|
if (this.physBtns >= buttons.length) {
|
||||||
// Handler for button watch events
|
// Handler for button watch events
|
||||||
function pressHandler(btn,e) {
|
function pressHandler(btn,e) {
|
||||||
|
@ -114,22 +147,25 @@ 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))}
|
{type:"v", pad:1, filly:1, c: buttons.map(b=>(b.type="txt",b.font="6x8",b.height=btnHeight,b.r=1,b))}
|
||||||
]};
|
]};
|
||||||
} else {
|
} else {
|
||||||
let btnHeight = Math.floor((g.getHeight()-this.yOffset) / buttons.length);
|
// add 'soft' buttons
|
||||||
this._l.width = g.getWidth()-20; // button width
|
this._l.width = g.getWidth()-32; // button width
|
||||||
this._l = {type:"h", c: [
|
this._l = {type:"h", c: [
|
||||||
this._l,
|
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) {
|
if (process.env.HWVERSION==2) {
|
||||||
// Handler for touch events
|
// Handler for touch events
|
||||||
function touchHandler(l,e) {
|
function touchHandler(l,e) {
|
||||||
if (l.type=="btn" && l.cb && e.x>=l.x && e.y>=l.y && e.x<=l.x+l.w && e.y<=l.y+l.h)
|
if (l.type=="btn" && l.cb && e.x>=l.x && e.y>=l.y && e.x<=l.x+l.w && e.y<=l.y+l.h) {
|
||||||
l.cb(e);
|
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));
|
if (l.c) l.c.forEach(n => touchHandler(n,e));
|
||||||
}
|
}
|
||||||
Bangle.touchHandler = function(_,e){touchHandler(layout,e)};
|
Bangle.touchHandler = (_,e)=>touchHandler(this._l,e);
|
||||||
Bangle.on('touch',Bangle.touchHandler);
|
Bangle.on('touch',Bangle.touchHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,24 +191,6 @@ Layout.prototype.remove = function (l) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function wrappedLines(str, maxWidth) {
|
|
||||||
var lines = [];
|
|
||||||
for (var unwrappedLine of str.split("\n")) {
|
|
||||||
var words = unwrappedLine.split(" ");
|
|
||||||
var line = words.shift();
|
|
||||||
for (var word of words) {
|
|
||||||
if (g.stringWidth(line + " " + word) > maxWidth) {
|
|
||||||
lines.push(line);
|
|
||||||
line = word;
|
|
||||||
} else {
|
|
||||||
line += " " + word;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lines.push(line);
|
|
||||||
}
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) {
|
function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) {
|
||||||
var bgCol = l.bgCol == null ? parentBg : g.toColor(l.bgCol);
|
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") {
|
if (bgCol != parentBg || l.type == "txt" || l.type == "btn" || l.type == "img" || l.type == "custom") {
|
||||||
|
@ -211,8 +229,9 @@ Layout.prototype.render = function (l) {
|
||||||
"txt":function(l){
|
"txt":function(l){
|
||||||
if (l.wrap) {
|
if (l.wrap) {
|
||||||
g.setFont(l.font,l.fsz).setFontAlign(0,-1);
|
g.setFont(l.font,l.fsz).setFontAlign(0,-1);
|
||||||
var lines = wrappedLines(l.label, l.w);
|
var lines = g.wrapString(l.label, l.w);
|
||||||
var y = l.y+((l.h-g.getFontHeight()*lines.length)>>1);
|
var y = l.y+((l.h-g.getFontHeight()*lines.length)>>1);
|
||||||
|
// TODO: on 2v11 we can just render in a single drawString call
|
||||||
lines.forEach((line, i) => g.drawString(line, l.x+(l.w>>1), y+g.getFontHeight()*i));
|
lines.forEach((line, i) => g.drawString(line, l.x+(l.w>>1), y+g.getFontHeight()*i));
|
||||||
} else {
|
} else {
|
||||||
g.setFont(l.font,l.fsz).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1));
|
g.setFont(l.font,l.fsz).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1));
|
||||||
|
@ -233,9 +252,9 @@ Layout.prototype.render = function (l) {
|
||||||
x,y+h-5,
|
x,y+h-5,
|
||||||
x,y+4
|
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){
|
}, "img":function(l){
|
||||||
g.drawImage(l.src(), l.x + (0|l.pad), l.y + (0|l.pad));
|
g.drawImage("function"==typeof l.src?l.src():l.src, l.x + (0|l.pad), l.y + (0|l.pad));
|
||||||
}, "custom":function(l){
|
}, "custom":function(l){
|
||||||
l.render(l);
|
l.render(l);
|
||||||
},"h":function(l) { l.c.forEach(render); },
|
},"h":function(l) { l.c.forEach(render); },
|
||||||
|
@ -342,26 +361,16 @@ Layout.prototype.update = function() {
|
||||||
if (l.wrap) {
|
if (l.wrap) {
|
||||||
l._h = l._w = 0;
|
l._h = l._w = 0;
|
||||||
} else {
|
} else {
|
||||||
g.setFont(l.font,l.fsz);
|
var m = g.setFont(l.font,l.fsz).stringMetrics(l.label);
|
||||||
l._h = g.getFontHeight();
|
l._w = m.width; l._h = m.height;
|
||||||
l._w = g.stringWidth(l.label);
|
|
||||||
}
|
}
|
||||||
}, "btn": function(l) {
|
}, "btn": function(l) {
|
||||||
l._h = 24;
|
l._h = 32;
|
||||||
l._w = 14 + l.label.length*8;
|
l._w = 20 + l.label.length*12;
|
||||||
}, "img": function(l) {
|
}, "img": function(l) {
|
||||||
var src = l.src(); // get width and height out of image
|
var m = g.imageMetrics("function"==typeof l.src?l.src():l.src); // get width and height out of image
|
||||||
if (src[0]) {
|
l._w = m.width;
|
||||||
l._w = src[0];
|
l._h = m.height;
|
||||||
l._h = src[1];
|
|
||||||
} else if ('object'==typeof src) {
|
|
||||||
l._w = ("width" in src) ? src.width : src.getWidth();
|
|
||||||
l._h = ("height" in src) ? src.height : src.getHeight();
|
|
||||||
} else {
|
|
||||||
var im = E.toString(src);
|
|
||||||
l._w = im.charCodeAt(0);
|
|
||||||
l._h = im.charCodeAt(1);
|
|
||||||
}
|
|
||||||
}, "": function(l) {
|
}, "": function(l) {
|
||||||
// size should already be set up in width/height
|
// size should already be set up in width/height
|
||||||
l._w = 0;
|
l._w = 0;
|
||||||
|
|
|
@ -19,7 +19,7 @@ SRCBMP=$SRCDIR/`basename $SRCJS .js`.bmp
|
||||||
echo "TEST $SRCJS ($SRCBMP)"
|
echo "TEST $SRCJS ($SRCBMP)"
|
||||||
|
|
||||||
cat ../../modules/Layout.js > $TESTJS
|
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
|
echo 'g = Graphics.createArrayBuffer(176,176,4);' >> $TESTJS
|
||||||
cat $SRCJS >> $TESTJS || exit 1
|
cat $SRCJS >> $TESTJS || exit 1
|
||||||
echo 'layout.render()' >> $TESTJS
|
echo 'layout.render()' >> $TESTJS
|
||||||
|
@ -39,5 +39,3 @@ else
|
||||||
echo Files are the same
|
echo Files are the same
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ var layout = new Layout({ type: "v", c: [
|
||||||
{type:"txt", id:"time", font:"6x8:2", label:" - ", pad:5},
|
{type:"txt", id:"time", font:"6x8:2", label:" - ", pad:5},
|
||||||
{type:"txt", font:"6x8:2", label:"RECORDING", bgCol:"#f00", pad:5, fillx:1},
|
{type:"txt", font:"6x8:2", label:"RECORDING", bgCol:"#f00", pad:5, fillx:1},
|
||||||
]
|
]
|
||||||
},[ // Buttons...
|
}{btns:[ // Buttons...
|
||||||
{label:"STOP", cb:()=>{}}
|
{label:"STOP", cb:()=>{}}
|
||||||
]);
|
]});
|
||||||
layout.samples.label = "123";
|
layout.samples.label = "123";
|
||||||
layout.time.label = "123s";
|
layout.time.label = "123s";
|
||||||
|
|
After Width: | Height: | Size: 28 KiB |
|
@ -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:()=>{}},
|
||||||
|
]});
|
After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
var layout = new Layout({ type: "v", c: [
|
||||||
|
{type:"txt", font:"6x8", label:"A test"},
|
||||||
|
]},{btns:[ // Buttons...
|
||||||
|
{label:"STOP", cb:()=>{}},
|
||||||
|
]});
|
After Width: | Height: | Size: 28 KiB |
|
@ -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:()=>{}},
|
||||||
|
]});
|
After Width: | Height: | Size: 15 KiB |
|
@ -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:()=>{}},
|
||||||
|
]});
|
After Width: | Height: | Size: 28 KiB |
|
@ -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:()=>{}},
|
||||||
|
]});
|
After Width: | Height: | Size: 15 KiB |
|
@ -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:()=>{}},
|
||||||
|
]});
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |