Merge branch 'espruino:master' into master
26
apps.json
|
@ -4,7 +4,7 @@
|
|||
"tags": "tool,system,b2",
|
||||
"type":"bootloader",
|
||||
"icon": "bootloader.png",
|
||||
"version":"0.29",
|
||||
"version":"0.30",
|
||||
"description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings",
|
||||
"storage": [
|
||||
{"name":".boot0","url":"boot0.js"},
|
||||
|
@ -258,7 +258,7 @@
|
|||
{ "id": "slidingtext",
|
||||
"name": "Sliding Clock",
|
||||
"icon": "slidingtext.png",
|
||||
"version":"0.06",
|
||||
"version":"0.07",
|
||||
"description": "Inspired by the Pebble sliding clock, old times are scrolled off the screen and new times on. You are also able to change language on the fly so you can see the time written in other languages using button 1. Currently English, French, Japanese, Spanish and German are supported",
|
||||
"tags": "clock",
|
||||
"type":"clock",
|
||||
|
@ -1139,7 +1139,7 @@
|
|||
"version":"0.01",
|
||||
"description": "Downloads assisted GPS (AGPS) data to Bangle.js for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.",
|
||||
"custom": "custom.html",
|
||||
"tags": "tool,outdoors,agps",
|
||||
"tags": "tool,outdoors,agps,bno2",
|
||||
"type": "RAM",
|
||||
"storage": [ ]
|
||||
},
|
||||
|
@ -2893,24 +2893,6 @@
|
|||
{"name":"de-stress.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
},
|
||||
{ "id": "gpsservice",
|
||||
"name": "Low power GPS Service",
|
||||
"shortName":"GPS Service",
|
||||
"icon": "gpsservice.png",
|
||||
"version":"0.04",
|
||||
"description": "low power GPS widget",
|
||||
"tags": "gps outdoors navigation",
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"gpsservice.app.js","url":"app.js"},
|
||||
{"name":"gpsservice.settings.js","url":"settings.js"},
|
||||
{"name":"gpsservice.wid.js","url":"widget.js"},
|
||||
{"name":"gpsservice.img","url":"gpsservice-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [
|
||||
{"name":"gpsservice.settings.json","url":"settings.json"}
|
||||
]
|
||||
},
|
||||
{ "id": "mclockplus",
|
||||
"name": "Morph Clock+",
|
||||
"shortName":"Morph Clock+",
|
||||
|
@ -3000,7 +2982,7 @@
|
|||
"icon": "gpssetup.png",
|
||||
"version":"0.02",
|
||||
"description": "Configure the GPS power options and store them in the GPS nvram",
|
||||
"tags": "gps, tools, outdoors",
|
||||
"tags": "gps,tools,outdoors,bno2",
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"gpssetup","url":"gpssetup.js"},
|
||||
|
|
|
@ -46,7 +46,6 @@ function getData() {
|
|||
});
|
||||
return new Promise(resolve=>{
|
||||
Puck.eval(`require("Storage").read(${JSON.stringify(fn)})`,csv=>{
|
||||
fileData[fn] = csv.trim();
|
||||
var el = document.querySelector(`.card-body[fn='${fn}']`);
|
||||
el.innerHTML = '<canvas width="400" height="100"></canvas>';
|
||||
var c = el.firstChild;
|
||||
|
|
|
@ -29,3 +29,4 @@
|
|||
0.28: Fix double clock load after settings are changed
|
||||
0.29: Update boot0 to avoid code block (faster execution)
|
||||
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
|
||||
|
|
|
@ -15,25 +15,5 @@ if (!clockApp) {
|
|||
clockApp = require("Storage").read(clockApp.src);
|
||||
}
|
||||
if (!clockApp) clockApp=`E.showMessage("No Clock Found");setWatch(()=>{Bangle.showLauncher();}, BTN2, {repeat:false,edge:"falling"});`;
|
||||
// check to see if our clock is wrong - if it is use GPS time
|
||||
if ((new Date()).getFullYear()<2000) {
|
||||
E.showMessage("Searching for\nGPS time");
|
||||
Bangle.on("GPS",function cb(g) {
|
||||
Bangle.setGPSPower(0);
|
||||
Bangle.removeListener("GPS",cb);
|
||||
if (!g.time || (g.time.getFullYear()<2000) ||
|
||||
(g.time.getFullYear()>2200)) {
|
||||
// GPS receiver's time not set - just boot clock anyway
|
||||
eval(clockApp);
|
||||
delete clockApp;
|
||||
return;
|
||||
}
|
||||
// We have a GPS time. Set time and reboot (to load alarms properly)
|
||||
setTime(g.time.getTime()/1000);
|
||||
load();
|
||||
});
|
||||
Bangle.setGPSPower(1);
|
||||
} else {
|
||||
eval(clockApp);
|
||||
delete clockApp;
|
||||
}
|
||||
eval(clockApp);
|
||||
delete clockApp;
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
0.01: New App
|
||||
0.02: Restore to SuperE mode on power off.
|
||||
0.03: dont reset to SuperE mode on power, as it prevents its general use
|
||||
0.04: Only turn GPS off if it was previously on (stops other apps/widgets that use GPS getting broken)
|
|
@ -1,141 +0,0 @@
|
|||
# GPS Service
|
||||
|
||||
A configurable, low power GPS widget that runs in the background.
|
||||
|
||||
NOTE: This app has been superceded by [gpssetup](https://github.com/espruino/BangleApps/blob/master/apps/gpssetup/README.md)
|
||||
|
||||
|
||||
## Goals
|
||||
|
||||
To develop a low power GPS widget that runs in the background and to
|
||||
facilitate an OS grid reference display in a watch face.
|
||||
|
||||
|
||||
* An app that turns on the GPS and constantly displays the screen
|
||||
will use around 75mA, the battery will last between 3-4 hours.
|
||||
|
||||
* Using the GPS in a Widget in Super-E Power Saving Mode (PSM) with
|
||||
the screen off most of the time, will consume around 35mA and you
|
||||
might get 10hrs before a recharge.
|
||||
|
||||
* Using the GPS in Power Saving Mode On/Off (PSMOO) with suitable
|
||||
settings can reduce the average consumption to around 15mA. A
|
||||
simple test using a 120s update period, 6s search period was still
|
||||
running with 45% battery 20 hours after it started.
|
||||
|
||||
|
||||
## Settings
|
||||
|
||||
The Settings App enables you set the following options for the GPS
|
||||
Service. Go to Settings, select App/Widgets and then 'GPS Service'.
|
||||
|
||||
- GPS - On/Off. When this value is changed the GPS Service will be
|
||||
powered on or off and the GPS Widget will be displayed.
|
||||
|
||||
- Power Mode:
|
||||
|
||||
- SuperE - the factory default setup for the GPS. The recommended
|
||||
power saving mode.
|
||||
|
||||
- PSMOO - On/Off power saving mode. Configured by interval and
|
||||
search time. Choose this mode if you are happy to get a GPS
|
||||
position update less often (say every 1 or 2 minutes). The longer
|
||||
the interval the more time the GPS will spend sleeping in low
|
||||
power mode (7mA) between obtaining fixes (35mA). For walking in
|
||||
open country an update once every 60 seconds is adequate to put
|
||||
you within a 6 digit grid refernce sqaure.
|
||||
|
||||
- update - the time between two position fix attempts.
|
||||
|
||||
- search - the time between two acquisition attempts if the receiver
|
||||
is unable to get a position fix.
|
||||
|
||||
|
||||
|
||||
## Screenshots
|
||||
### GPS Watch face
|
||||
|
||||
* The Age value is the number of seconds since the last position fix was received.
|
||||
|
||||

|
||||
|
||||
### Grid Reference Watch face
|
||||
|
||||
* The time shown is the timestamp of the last position fix.
|
||||
* The age value is shown at the bottom of the screen.
|
||||
|
||||

|
||||
|
||||
## Interface for Apps
|
||||
|
||||
The code below demonstrates how you can setup and start the gpsservice from your own App.
|
||||
|
||||
```js
|
||||
function test_gps_on() {
|
||||
|
||||
var settings = WIDGETS.gpsservice.gps_get_settings();
|
||||
|
||||
// change the settings to what you require
|
||||
settings.gpsservice = true;
|
||||
settings.update = 65;
|
||||
settings.search = 5;
|
||||
settings.power_mode = "PSMOO";
|
||||
|
||||
WIDGETS.gpsservice.gps_set_settings(settings);
|
||||
WIDGETS.gpsservice.reload(); // will power on
|
||||
}
|
||||
```
|
||||
|
||||
In your app can retrieve the last fix as and when required.
|
||||
|
||||
```js
|
||||
var fix = {
|
||||
fix: 0,
|
||||
alt: 0,
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
speed: 0,
|
||||
time: 0,
|
||||
satellites: 0
|
||||
};
|
||||
|
||||
// only attempt to get gps fix if gpsservice is loaded
|
||||
if (WIDGETS.gpsservice !== undefined) {
|
||||
fix = WIDGETS.gpsservice.gps_get_fix();
|
||||
gps_on = WIDGETS.gpsservice.gps_get_status();
|
||||
}
|
||||
|
||||
if (fix.fix) {
|
||||
var time = formatTime(fix.time);
|
||||
var age = timeSince(time);
|
||||
```
|
||||
|
||||
When done you can turn the gpsservice off using the code below.
|
||||
|
||||
```js
|
||||
function test_gps_off() {
|
||||
|
||||
var settings = WIDGETS.gpsservice.gps_get_settings();
|
||||
|
||||
settings.gpsservice = false;
|
||||
settings.power_mode = "SuperE";
|
||||
|
||||
WIDGETS.gpsservice.gps_set_settings(settings);
|
||||
WIDGETS.gpsservice.reload(); // will power off
|
||||
}
|
||||
```
|
||||
|
||||
## To Do List
|
||||
* add a logging option with options for interval between log points
|
||||
* add graphics and icons to the watch faces to make them look nicer
|
||||
|
||||
|
||||
## References
|
||||
|
||||
* [UBLOX M8 Receiver Data Sheet](https://www.u-blox.com/sites/default/files/products/documents/u-blox8-M8_ReceiverDescrProtSpec_%28UBX-13003221%29.pdf)
|
||||
|
||||
* [UBLOX Power Management App Note](https://www.u-blox.com/sites/default/files/products/documents/PowerManagement_AppNote_%28UBX-13005162%29.pdf)
|
||||
|
||||
* Some useful code on Github and be found [here](https://portal.u-blox.com/s/question/0D52p0000925T00CAE/ublox-max-m8q-getting-stuck-when-sleeping-with-extint-pin-control)
|
||||
and [here](https://github.com/thasti/utrak/blob/master/gps.c)
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
const SETTINGS_FILE = "gpsservice.settings.json";
|
||||
let settings = require("Storage").readJSON(SETTINGS_FILE,1)||{};
|
||||
|
||||
|
||||
|
||||
function updateSettings() {
|
||||
require("Storage").write(SETTINGS_FILE, settings);
|
||||
}
|
||||
|
||||
function reloadWidget() {
|
||||
if (WIDGETS.gpsservice)
|
||||
WIDGETS.gpsservice.reload();
|
||||
}
|
||||
|
||||
function showMainMenu() {
|
||||
var power_options = ["SuperE","PSMOO"];
|
||||
|
||||
const mainmenu = {
|
||||
'': { 'title': 'GPS Service' },
|
||||
'< Exit': ()=>{load();},
|
||||
'GPS': {
|
||||
value: !!settings.gpsservice,
|
||||
format: v =>v?'On':'Off',
|
||||
onchange: v => {
|
||||
settings.gpsservice = v;
|
||||
updateSettings();
|
||||
reloadWidget(); // only when we change On/Off status
|
||||
},
|
||||
},
|
||||
|
||||
'Power Mode': {
|
||||
value: 0 | power_options.indexOf(settings.power_mode),
|
||||
min: 0, max: 1,
|
||||
format: v => power_options[v],
|
||||
onchange: v => {
|
||||
settings.power_mode = power_options[v];
|
||||
updateSettings();
|
||||
},
|
||||
},
|
||||
|
||||
'Update (s)': {
|
||||
value: settings.update,
|
||||
min: 10,
|
||||
max: 1800,
|
||||
step: 10,
|
||||
onchange: v => {
|
||||
settings.period =v;
|
||||
updateSettings();
|
||||
}
|
||||
},
|
||||
'Search (s)': {
|
||||
value: settings.search,
|
||||
min: 1,
|
||||
max: 65,
|
||||
step: 1,
|
||||
onchange: v => {
|
||||
settings.search = v;
|
||||
updateSettings();
|
||||
}
|
||||
},
|
||||
'< Back': ()=>{load();}
|
||||
};
|
||||
|
||||
return E.showMenu(mainmenu);
|
||||
}
|
||||
|
||||
showMainMenu();
|
Before Width: | Height: | Size: 129 KiB |
|
@ -1 +0,0 @@
|
|||
require("heatshrink").decompress(atob("mEwghC/AH4AKg9wC6t3u4uVC6wWBI6t3uJeVuMQCqcBLisAi4XLxAABFxAXKgc4DBAuBRhQXEDAq7MmYXEwBHEXZYXFGAOqAAKDMmczC4mIC62CC50PC4JIBkQABiIvRmURAAUSjQXSFwMoxGKC6CRFwUSVYgXLPIgXXwMYegoXLJAYXCGBnzGA0hPQIwMgYwGC6gwCC4ZIMC4gYBC604C4ZISmcRVgapQAAMhC6GIJIwXCMBcIxGDDBAuLC4IwGAARGMAAQWGmAXPJQoWMC4pwCCpoXJAB4XXAH4A/ABQA="))
|
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 122 KiB |
|
@ -1,4 +0,0 @@
|
|||
(function(back) {
|
||||
// just go right to our app
|
||||
load("gpsservice.app.js");
|
||||
})();
|
|
@ -1 +0,0 @@
|
|||
{"gpsservice":false, "power_mode":"SuperE", "update":120, "search":6}
|
|
@ -1,259 +0,0 @@
|
|||
|
||||
/*
|
||||
|
||||
test bed for working out lowest power consumption, with workable GPS
|
||||
Load into IDE and upload code to RAM when connected to watch
|
||||
|
||||
*/
|
||||
|
||||
|
||||
Bangle.on('GPS-raw',function (d) {
|
||||
if (d[0]=="$") return;
|
||||
if (d.startsWith("\xB5\x62\x05\x01")) print("GPS ACK");
|
||||
else if (d.startsWith("\xB5\x62\x05\x00")) print("GPS NACK");
|
||||
// 181,98 sync chars
|
||||
else print("GPS",E.toUint8Array(d).join(","));
|
||||
});
|
||||
|
||||
function writeGPScmd(cmd) {
|
||||
var d = [0xB5,0x62]; // sync chars
|
||||
d = d.concat(cmd);
|
||||
var a=0,b=0;
|
||||
for (var i=2;i<d.length;i++) {
|
||||
a += d[i];
|
||||
b += a;
|
||||
}
|
||||
d.push(a&255,b&255);
|
||||
console.log(d);
|
||||
Serial1.write(d);
|
||||
}
|
||||
|
||||
// quick hack
|
||||
function wait(ms){
|
||||
var start = new Date().getTime();
|
||||
var end = start;
|
||||
while(end < start + ms) {
|
||||
end = new Date().getTime();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* gps_disable_nmea_output
|
||||
*
|
||||
* disables all NMEA messages to be output from the GPS.
|
||||
* even though the parser can cope with NMEA messages and ignores them, it
|
||||
* may save power to disable them completely.
|
||||
*
|
||||
*
|
||||
* DO NOT USE
|
||||
* HB: This is a bad idea on a Bangle JS
|
||||
* You wont get any fixes if you call this function
|
||||
*
|
||||
*
|
||||
*/
|
||||
function UBX_CFG_DISABLE_NMEA() {
|
||||
writeGPScmd([0x06, 0x00, /* UBX-CFG-PRT */
|
||||
20, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, /* UART1, reserved, no TX ready */
|
||||
0xe0, 0x08, 0x00, 0x00, /* UART mode (8N1) */
|
||||
0x80, 0x25, 0x00, 0x00, /* UART baud rate (9600) */
|
||||
0x01, 0x00, /* input protocols (uBx only) */
|
||||
0x01, 0x00, /* output protocols (uBx only) */
|
||||
0x00, 0x00, /* flags */
|
||||
0x00, 0x00]); /* reserved */
|
||||
}
|
||||
|
||||
/*
|
||||
* gps_disable_nmea_output
|
||||
*
|
||||
* disables all NMEA messages to be output from the GPS.
|
||||
* even though the parser can cope with NMEA messages and ignores them, it
|
||||
* may save power to disable them completely.
|
||||
*
|
||||
* Can use this to switch NMEA back on if you call
|
||||
* UBX_CFG_DISABLE_NMEA()
|
||||
*
|
||||
*/
|
||||
function UBX_CFG_RESTORE_NMEA() {
|
||||
writeGPScmd([0x06, 0x00, /* UBX-CFG-PRT */
|
||||
20, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, /* UART1, reserved, no TX ready */
|
||||
0xe0, 0x08, 0x00, 0x00, /* UART mode (8N1) */
|
||||
0x80, 0x25, 0x00, 0x00, /* UART baud rate (9600) */
|
||||
0x03, 0x00, /* input protocols (uBx only) */
|
||||
0x03, 0x00, /* output protocols (uBx only) */
|
||||
0x00, 0x00, /* flags */
|
||||
0x00, 0x00]); /* reserved */
|
||||
}
|
||||
|
||||
function UBX_CFG_PMS() {
|
||||
// UBX-CFG-PMS - enable power management - Super-E
|
||||
writeGPScmd([0x06,0x86, // msg class + type
|
||||
8,0,//length
|
||||
0x00,0x03, 0,0, 0,0, 0,0]);
|
||||
}
|
||||
|
||||
function UBX_CFG_INTERVAL(period, ontime) {
|
||||
writeGPScmd([0x06,0x86, // msg class + type
|
||||
8,0, //length
|
||||
//v0, interval period ontime reserved
|
||||
0x00, 0x02, period, 0, ontime, 0, 0, 0 ]);
|
||||
// the values are little endian, least significant byte first
|
||||
}
|
||||
|
||||
/*
|
||||
* set update baud rate
|
||||
*
|
||||
* the setting is in milliseconds in 2 bytes, max 65 seconds
|
||||
* we are passing in a value in seconds
|
||||
* we set the most significant byte only
|
||||
* 8 seconds ~ 8192ms 0x2000, 0x20 = 32 = 4*8
|
||||
*
|
||||
*/
|
||||
function UBX_CFG_RATE(rate) {
|
||||
rate = (rate * 4) % 256;
|
||||
//console.log("rate=" + rate);
|
||||
|
||||
writeGPScmd([0x06,0x08, // class, id
|
||||
0x06, 0, // length
|
||||
0x00, rate, // b0: 8192ms 0x2000, 0x00FF (~65sec)
|
||||
0x01, 0x00, // b2:
|
||||
0x01, 0x00]); // b4: timeref GPS
|
||||
}
|
||||
|
||||
/*
|
||||
* Save configuration otherwise it will reset when the GPS wakes up
|
||||
*
|
||||
*/
|
||||
function UBX_CFG_SAVE() {
|
||||
writeGPScmd([0x06, 0x09, // class id
|
||||
0x0D, 0x00, // length
|
||||
0x00, 0x00, 0x00, 0x00, // clear mask
|
||||
0xFF, 0xFF, 0x00, 0x00, // save mask
|
||||
0x00, 0x00, 0x00, 0x00, // load mask
|
||||
0x07]); // b2=eeprom b1=flash b0=bat backed ram
|
||||
// code on github had 7 - all 3 set ?
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Reset to factory settings using clear mask in UBX_CFG_CFG
|
||||
* https://portal.u-blox.com/s/question/0D52p0000925T00CAE/ublox-max-m8q-getting-stuck-when-sleeping-with-extint-pin-control
|
||||
*/
|
||||
function UBX_CFG_RESET() {
|
||||
writeGPScmd([0x06, 0x09, // class id
|
||||
0x0D, 0x00,
|
||||
0xFF, 0xFB, 0x00, 0x00, // clear mask
|
||||
0x00, 0x00, 0x00, 0x00, // save mask
|
||||
0xFF, 0xFF, 0x00, 0x00, // load mask
|
||||
0x17]);
|
||||
}
|
||||
|
||||
|
||||
// convert an integer to an array of bytes
|
||||
function int_2_bytes( x ){
|
||||
var bytes = [];
|
||||
var i = 4;
|
||||
do {
|
||||
bytes[--i] = x & (255);
|
||||
x = x>>8;
|
||||
} while (i);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Extended Power Management
|
||||
* update and search are in seconds
|
||||
*
|
||||
* https://github.com/thasti/utrak/blob/master/gps.c
|
||||
*/
|
||||
function UBX_CFG_PM2(update,search) {
|
||||
|
||||
var u = int_2_bytes(update*1000);
|
||||
var s = int_2_bytes(search*1000);
|
||||
|
||||
writeGPScmd([0x06, 0x3B, /* class id */
|
||||
44, 0, /* length */
|
||||
0x01, 0x00, 0x00, 0x00, /* v1, reserved 1..3 */
|
||||
0x00, 0x10, 0x00, 0x00, /* on/off-mode, update ephemeris */
|
||||
// little endian, lsb first
|
||||
//0x30, 0x75, 0x00, 0x00, /* update period, ms, 120s=00 01 D4 C0, 30s= 00 00 75 30 */
|
||||
//0x88, 0x13, 0x00, 0x00, /* search period, ms, 120s, 20s = 00 00 4E 20, 5s = 13 88 */
|
||||
u[3], u[2], u[1], u[0], /* update period, ms, 120s=00 01 D4 C0, 30s= 00 00 75 30 */
|
||||
s[3], s[2], s[1], s[0], /* search period, ms, 120s, 20s = 00 00 4E 20, 5s = 13 88 */
|
||||
0x00, 0x00, 0x00, 0x00, /* grid offset */
|
||||
0x00, 0x00, /* on-time after first fix */
|
||||
0x01, 0x00, /* minimum acquisition time */
|
||||
0x00, 0x00, 0x00, 0x00, /* reserved 4,5 */
|
||||
0x00, 0x00, 0x00, 0x00, /* reserved 6 */
|
||||
0x00, 0x00, 0x00, 0x00, /* reserved 7 */
|
||||
0x00, 0x00, 0x00, 0x00, /* reserved 8,9,10 */
|
||||
0x00, 0x00, 0x00, 0x00]); /* reserved 11 */
|
||||
}
|
||||
|
||||
|
||||
// enable power saving mode, after configured with PM2
|
||||
function UBX_CFG_RXM() {
|
||||
writeGPScmd([0x06, 0x11, /* UBX-CFG-RXM */
|
||||
2, 0, /* length */
|
||||
0x08, 0x01]); /* reserved, enable power save mode */
|
||||
}
|
||||
|
||||
function onGPS(fix) {
|
||||
console.log(fix);
|
||||
}
|
||||
|
||||
|
||||
function setupGPS() {
|
||||
Bangle.setGPSPower(1);
|
||||
|
||||
UBX_CFG_RESET();
|
||||
wait(100);
|
||||
|
||||
//UBX_CFG_RESTORE_NMEA();
|
||||
//wait(20);
|
||||
|
||||
UBX_CFG_PM2(120,5);
|
||||
wait(20);
|
||||
|
||||
UBX_CFG_RXM();
|
||||
wait(20);
|
||||
|
||||
UBX_CFG_SAVE();
|
||||
wait(20);
|
||||
|
||||
Bangle.on('GPS',onGPS);
|
||||
}
|
||||
|
||||
function test_gps_on() {
|
||||
|
||||
var settings = WIDGETS.gpsservice.gps_get_settings();
|
||||
|
||||
settings.gpsservice = true;
|
||||
settings.update = 65;
|
||||
settings.search = 5;
|
||||
settings.power_mode = "PSMOO";
|
||||
|
||||
WIDGETS.gpsservice.gps_set_settings(settings);
|
||||
WIDGETS.gpsservice.reload(); // will power on
|
||||
}
|
||||
|
||||
|
||||
function test_gps_off() {
|
||||
|
||||
var settings = WIDGETS.gpsservice.gps_get_settings();
|
||||
|
||||
settings.gpsservice = false;
|
||||
settings.power_mode = "SuperE";
|
||||
|
||||
WIDGETS.gpsservice.gps_set_settings(settings);
|
||||
WIDGETS.gpsservice.reload(); // will power off
|
||||
}
|
||||
|
||||
// test_gps_on();
|
||||
// test_gps_off();
|
||||
|
|
@ -1,287 +0,0 @@
|
|||
(() => {
|
||||
var settings = {};
|
||||
var fixToggle = false; // toggles once for each reading
|
||||
var have_fix = false;
|
||||
var debug = false;
|
||||
var gpsPowerEnabled = false;
|
||||
|
||||
var last_fix = {
|
||||
fix: 0,
|
||||
alt: 0,
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
speed: 0,
|
||||
time: 0,
|
||||
satellites: 0
|
||||
};
|
||||
|
||||
function gps_get_fix() { return last_fix; }
|
||||
function gps_get_status() { return WIDGETS.gpsservice.width === 24 ? true : false;}
|
||||
function gps_get_version() { return "0.03"; }
|
||||
|
||||
function log_debug(o) {
|
||||
if (debug) console.log(o);
|
||||
}
|
||||
|
||||
function gps_set_debug(v) {
|
||||
debug = v;
|
||||
}
|
||||
|
||||
// Called by the GPS widget settings to reload settings and decide what to do
|
||||
function reload() {
|
||||
settings = gps_get_settings();
|
||||
log_debug(settings);
|
||||
Bangle.removeListener('GPS',onGPS);
|
||||
|
||||
if (settings.gpsservice) {
|
||||
gps_power_on();
|
||||
} else {
|
||||
gps_power_off();
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve the settings from Storage, can be called by external apps
|
||||
function gps_get_settings() {
|
||||
var sets = require("Storage").readJSON("gpsservice.settings.json",1)||{};
|
||||
sets.gpsservice = sets.gpsservice||false;
|
||||
sets.update = sets.update||120;
|
||||
sets.search = sets.search||5;
|
||||
sets.power_mode = sets.power_mode||"SuperE";
|
||||
return sets;
|
||||
}
|
||||
|
||||
// pass in the required settings, can be called by external apps
|
||||
function gps_set_settings(sets) {
|
||||
settings.gpsservice = sets.gpsservice||false;
|
||||
settings.update = sets.update||120;
|
||||
settings.search = sets.search||5;
|
||||
settings.power_mode = sets.power_mode||"SuperE";
|
||||
require("Storage").write("gpsservice.settings.json", settings);
|
||||
}
|
||||
|
||||
// issue: currently possible to call this without having set settings.gpsservice in settings file
|
||||
function gps_power_on() {
|
||||
have_fix = false;
|
||||
fixToggle = false;
|
||||
setupGPS();
|
||||
WIDGETS.gpsservice.width = 24;
|
||||
}
|
||||
|
||||
function gps_power_off() {
|
||||
//setupSuperE(); // return to expected setup for other apps
|
||||
if (gpsPowerEnabled) {
|
||||
gpsPowerEnabled = false;
|
||||
Bangle.setGPSPower(0);
|
||||
}
|
||||
have_fix = false;
|
||||
fixToggle = false;
|
||||
last_fix.fix = 0;
|
||||
WIDGETS.gpsservice.width = 0;
|
||||
}
|
||||
|
||||
// quick hack
|
||||
function wait(ms){
|
||||
var start = new Date().getTime();
|
||||
var end = start;
|
||||
while(end < start + ms) {
|
||||
end = new Date().getTime();
|
||||
}
|
||||
}
|
||||
|
||||
function setupGPS() {
|
||||
Bangle.setGPSPower(1);
|
||||
gpsPowerEnabled = true;
|
||||
|
||||
if (settings.power_mode === "PSMOO") {
|
||||
setupPSMOO();
|
||||
} else {
|
||||
setupSuperE();
|
||||
}
|
||||
Bangle.on('GPS',onGPS);
|
||||
}
|
||||
|
||||
function setupPSMOO() {
|
||||
log_debug("setupGPS() PSMOO");
|
||||
UBX_CFG_RESET();
|
||||
wait(100);
|
||||
|
||||
UBX_CFG_PM2(settings.update, settings.search);
|
||||
wait(20);
|
||||
|
||||
UBX_CFG_RXM();
|
||||
wait(20);
|
||||
|
||||
UBX_CFG_SAVE();
|
||||
wait(20);
|
||||
}
|
||||
|
||||
function setupSuperE() {
|
||||
log_debug("setupGPS() Super-E");
|
||||
UBX_CFG_RESET();
|
||||
wait(100);
|
||||
|
||||
UBX_CFG_PMS();
|
||||
wait(20);
|
||||
|
||||
UBX_CFG_SAVE();
|
||||
wait(20);
|
||||
}
|
||||
|
||||
function writeGPScmd(cmd) {
|
||||
var d = [0xB5,0x62]; // sync chars
|
||||
d = d.concat(cmd);
|
||||
var a=0,b=0;
|
||||
for (var i=2;i<d.length;i++) {
|
||||
a += d[i];
|
||||
b += a;
|
||||
}
|
||||
d.push(a&255,b&255);
|
||||
Serial1.write(d);
|
||||
}
|
||||
|
||||
// UBX-CFG-PMS - enable power management - Super-E
|
||||
function UBX_CFG_PMS() {
|
||||
writeGPScmd([0x06,0x86, // msg class + type
|
||||
8,0,//length
|
||||
0x00,0x03, 0,0, 0,0, 0,0]);
|
||||
}
|
||||
|
||||
// convert an integer to an array of bytes
|
||||
function int_2_bytes( x ){
|
||||
var bytes = [];
|
||||
var i = 4;
|
||||
do {
|
||||
bytes[--i] = x & (255);
|
||||
x = x>>8;
|
||||
} while (i);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Extended Power Management
|
||||
* update and search are in milli seconds
|
||||
* settings are loaded little endian, lsb first
|
||||
*
|
||||
* https://github.com/thasti/utrak/blob/master/gps.c
|
||||
*/
|
||||
function UBX_CFG_PM2(update,search) {
|
||||
|
||||
var u = int_2_bytes(update*1000);
|
||||
var s = int_2_bytes(search*1000);
|
||||
|
||||
writeGPScmd([0x06, 0x3B, /* class id */
|
||||
44, 0, /* length */
|
||||
0x01, 0x00, 0x00, 0x00, /* v1, reserved 1..3 */
|
||||
0x00, 0x10, 0x00, 0x00, /* on/off-mode, update ephemeris */
|
||||
u[3], u[2], u[1], u[0], /* update period, ms, 120s=00 01 D4 C0, 30s= 00 00 75 30 */
|
||||
s[3], s[2], s[1], s[0], /* search period, ms, 120s, 20s = 00 00 4E 20, 5s = 13 88 */
|
||||
0x00, 0x00, 0x00, 0x00, /* grid offset */
|
||||
0x00, 0x00, /* on-time after first fix */
|
||||
0x01, 0x00, /* minimum acquisition time */
|
||||
0x00, 0x00, 0x00, 0x00, /* reserved 4,5 */
|
||||
0x00, 0x00, 0x00, 0x00, /* reserved 6 */
|
||||
0x00, 0x00, 0x00, 0x00, /* reserved 7 */
|
||||
0x00, 0x00, 0x00, 0x00, /* reserved 8,9,10 */
|
||||
0x00, 0x00, 0x00, 0x00]); /* reserved 11 */
|
||||
}
|
||||
|
||||
// enable power saving mode, after configured with PM2
|
||||
function UBX_CFG_RXM() {
|
||||
writeGPScmd([0x06, 0x11, /* UBX-CFG-RXM */
|
||||
2, 0, /* length */
|
||||
0x08, 0x01]); /* reserved, enable power save mode */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Save configuration otherwise it will reset when the GPS wakes up
|
||||
*
|
||||
*/
|
||||
function UBX_CFG_SAVE() {
|
||||
writeGPScmd([0x06, 0x09, // class id
|
||||
0x0D, 0x00, // length
|
||||
0x00, 0x00, 0x00, 0x00, // clear mask
|
||||
0xFF, 0xFF, 0x00, 0x00, // save mask
|
||||
0x00, 0x00, 0x00, 0x00, // load mask
|
||||
0x07]); // b2=eeprom b1=flash b0=bat backed ram
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset to factory settings using clear mask in UBX_CFG_CFG
|
||||
* https://portal.u-blox.com/s/question/0D52p0000925T00CAE/ublox-max-m8q-getting-stuck-when-sleeping-with-extint-pin-control
|
||||
*/
|
||||
function UBX_CFG_RESET() {
|
||||
writeGPScmd([0x06, 0x09, // class id
|
||||
0x0D, 0x00,
|
||||
0xFF, 0xFB, 0x00, 0x00, // clear mask
|
||||
0x00, 0x00, 0x00, 0x00, // save mask
|
||||
0xFF, 0xFF, 0x00, 0x00, // load mask
|
||||
0x17]);
|
||||
}
|
||||
|
||||
// draw the widget
|
||||
function draw() {
|
||||
if (!settings.gpsservice) return;
|
||||
g.reset();
|
||||
g.drawImage(atob("GBgCAAAAAAAAAAQAAAAAAD8AAAAAAP/AAAAAAP/wAAAAAH/8C9AAAB/8L/QAAAfwv/wAAAHS//wAAAAL//gAAAAf/+AAAAAf/4AAAAL//gAAAAD/+DwAAAB/Uf8AAAAfA//AAAACAf/wAAAAAH/0AAAAAB/wAAAAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),this.x,this.y);
|
||||
if (gps_get_status() === true && have_fix) {
|
||||
g.setColor("#00FF00");
|
||||
g.drawImage(fixToggle ? atob("CgoCAAAAA0AAOAAD5AAPwAAAAAAAAAAAAAAAAA==") : atob("CgoCAAABw0AcOAHj5A8PwHwAAvgAB/wABUAAAA=="),this.x,this.y+14);
|
||||
} else {
|
||||
g.setColor("#0000FF");
|
||||
if (fixToggle) g.setFont("6x8").drawString("?",this.x,this.y+14);
|
||||
}
|
||||
}
|
||||
|
||||
function onGPS(fix) {
|
||||
fixToggle = !fixToggle;
|
||||
WIDGETS.gpsservice.draw();
|
||||
log_debug(fix);
|
||||
last_fix.satellites = fix.satellites;
|
||||
|
||||
/*
|
||||
* If we have a fix record it, we will get another soon. Apps
|
||||
* will see the timestamp of the last fix and be able to work out
|
||||
* if it is stale. This means an App will always have the last
|
||||
* known fix, and we avoid saying no fix all the time.
|
||||
*
|
||||
*/
|
||||
if (fix.fix) {
|
||||
last_fix.fix = fix.fix;
|
||||
last_fix.alt = fix.alt;
|
||||
last_fix.lat = fix.lat;
|
||||
last_fix.lon = fix.lon;
|
||||
last_fix.speed = fix.speed;
|
||||
last_fix.time = fix.time;
|
||||
}
|
||||
}
|
||||
|
||||
// redraw when the LCD turns on
|
||||
Bangle.on('lcdPower', function(on) {
|
||||
if (on) WIDGETS.gpsservice.draw();
|
||||
});
|
||||
|
||||
// add the widget
|
||||
WIDGETS.gpsservice = {
|
||||
area:"tl",
|
||||
width:24,
|
||||
draw:draw,
|
||||
gps_power_on:gps_power_on,
|
||||
gps_power_off:gps_power_off,
|
||||
gps_get_status:gps_get_status,
|
||||
gps_get_fix:gps_get_fix,
|
||||
gps_get_version:gps_get_version,
|
||||
gps_get_settings:gps_get_settings,
|
||||
gps_set_settings:gps_set_settings,
|
||||
gps_set_debug:gps_set_debug,
|
||||
reload:function() {
|
||||
reload();
|
||||
Bangle.drawWidgets(); // relayout all widgets
|
||||
}};
|
||||
|
||||
// load settings, set correct widget width
|
||||
reload();
|
||||
|
||||
})();
|
|
@ -496,6 +496,24 @@ var locales = {
|
|||
day: "Vasárnap,Hétfő,Kedd,Szerda,Csütörtök,Péntek,Szombat",
|
||||
trans: { yes: "igen", Yes: "Igen", no: "nem", No: "Nem", ok: "ok", on: "be", off: "ki" }
|
||||
},
|
||||
"oc_FR": {
|
||||
lang: "oc_FR",
|
||||
decimal_point: ",",
|
||||
thousands_sep: " ",
|
||||
currency_symbol: "€",
|
||||
int_curr_symbol: "EUR",
|
||||
speed: "km/h",
|
||||
distance: { 0: "m", 1: "km" },
|
||||
temperature: "°C",
|
||||
ampm: { 0: "", 1: "" },
|
||||
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "%A %d %B de %Y", "1": "%d/%m/%Y" }, // dimenge 1 de març de 2020 // 01/03/2020
|
||||
abmonth: "gen.,febr.,març,abril,mai,junh,julh,ago.,set.,oct.,nov.,dec.",
|
||||
month: "genièr,febrièr,març,abril,mai,junh,julhet,agost,setembre,octòbre,novembre,decembre",
|
||||
abday: "dg,dl,dm,dc,dj,dv,ds",
|
||||
day: "dimenge,diluns,dimars,dimècres,dijòus,divendres,dissabte",
|
||||
trans: { yes: "òc", Yes: "Òc", no: "non", No: "Non", ok: "ok", on: "on", off: "off" }
|
||||
},
|
||||
"pt_BR": {
|
||||
lang: "pt_BR",
|
||||
decimal_point: ",",
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
0.04: Added German Language
|
||||
0.05: BUGFIX: pedometer widget interfered with the clock Font Alignment
|
||||
0.06: Use Bangle.setUI for button/launcher handling
|
||||
0.07: Support for Bangle.js 2 and themes
|
||||
|
|
|
@ -146,12 +146,6 @@ class ShiftText {
|
|||
//console.log("bgcolor:" + this.bg_color);
|
||||
g.setColor(this.bg_color[0],this.bg_color[1],this.bg_color[2]);
|
||||
g.drawString(this.txt, this.x, this.y);
|
||||
/*g.fillPoly([this.x - 1, this.y,
|
||||
240, this.y,
|
||||
240, this.y + this.font_size,
|
||||
this.x -1 , this.y + this.font_size,
|
||||
]);
|
||||
*/
|
||||
}
|
||||
setText(txt){
|
||||
this.txt = txt;
|
||||
|
@ -239,13 +233,21 @@ class ShiftText {
|
|||
|
||||
const CLOCK_TEXT_SPEED_X = 10;
|
||||
// a list of display rows
|
||||
let row_displays = [
|
||||
new ShiftText(240,50,'',"Vector",40,CLOCK_TEXT_SPEED_X,1,10,main_color(),bg_color()),
|
||||
new ShiftText(240,90,'',"Vector",30,CLOCK_TEXT_SPEED_X,1,10,other_color(),bg_color()),
|
||||
new ShiftText(240,120,'',"Vector",30,CLOCK_TEXT_SPEED_X,1,10,other_color(),bg_color()),
|
||||
new ShiftText(240,150,'',"Vector",30,CLOCK_TEXT_SPEED_X,1,10,other_color(),bg_color()),
|
||||
new ShiftText(240,180,'',"Vector",40,CLOCK_TEXT_SPEED_X,1,10,main_color(),bg_color())
|
||||
];
|
||||
let row_displays;
|
||||
function setRowDisplays(y, heights) {
|
||||
var cols = [
|
||||
main_color(), other_color(), other_color(), other_color(), main_color()
|
||||
];
|
||||
row_displays = [];
|
||||
for (var i=0;i<heights.length;i++) {
|
||||
row_displays.push(new ShiftText(g.getWidth(),y,'',"Vector",heights[i],CLOCK_TEXT_SPEED_X,1,10,cols[i],bg_color()));
|
||||
y += heights[i];
|
||||
}
|
||||
}
|
||||
if (g.getHeight()>200)
|
||||
setRowDisplays(50, [40,30,30,30,40]);
|
||||
else
|
||||
setRowDisplays(34, [35,25,25,25,35]);
|
||||
|
||||
function nextColorTheme(){
|
||||
//console.log("next color theme");
|
||||
|
@ -274,11 +276,7 @@ function setColor(main_color,other_color,bg_color){
|
|||
row_displays[row_displays.length - 1].setColor(main_color);
|
||||
row_displays[row_displays.length - 1].setBgColor(bg_color);
|
||||
g.setColor(bg_color[0],bg_color[1],bg_color[2]);
|
||||
g.fillPoly([0,25,
|
||||
0,240,
|
||||
240,240,
|
||||
240,25
|
||||
]);
|
||||
g.fillRect(0,24, g.getWidth(), g.getHeight());
|
||||
}
|
||||
|
||||
// load the date formats and laguages required
|
||||
|
@ -510,12 +508,14 @@ const PREFERENCE_FILE = "slidingtext.settings.json";
|
|||
* Called on startup to set the watch to the last preference settings
|
||||
*/
|
||||
function load_settings(){
|
||||
var setScheme = false;
|
||||
try{
|
||||
settings = require("Storage").readJSON(PREFERENCE_FILE);
|
||||
if(settings != null){
|
||||
console.log("loaded:" + JSON.stringify(settings));
|
||||
if(settings.color_scheme != null){
|
||||
set_colorscheme(settings.color_scheme);
|
||||
setScheme = true;
|
||||
}
|
||||
if(settings.date_format != null){
|
||||
set_dateformat(settings.date_format);
|
||||
|
@ -526,6 +526,9 @@ function load_settings(){
|
|||
} catch(e){
|
||||
console.log("failed to load settings:" + e);
|
||||
}
|
||||
// just set up as default
|
||||
if (!setScheme)
|
||||
setColorScheme(color_schemes[color_scheme_index]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -636,11 +639,7 @@ Bangle.drawWidgets();
|
|||
|
||||
startTimers();
|
||||
// Show launcher when button pressed
|
||||
Bangle.setUI("clock");
|
||||
|
||||
|
||||
// Handle button 1 being pressed
|
||||
setWatch(button1pressed, BTN1,{repeat:true,edge:"falling"});
|
||||
|
||||
// Handle button 3 being pressed
|
||||
setWatch(button3pressed, BTN3,{repeat:true,edge:"falling"});
|
||||
Bangle.setUI("clockupdown", d=>{
|
||||
if (d<0) button1pressed();
|
||||
if (d>0) button3pressed();
|
||||
});
|
||||
|
|
|
@ -87,6 +87,13 @@ function Layout(layout, buttons, options) {
|
|||
|
||||
if (buttons) {
|
||||
if (this.physBtns >= buttons.length) {
|
||||
// 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);
|
||||
}
|
||||
// enough physical buttons
|
||||
let btnHeight = Math.floor((g.getHeight()-this.yOffset) / this.physBtns);
|
||||
if (Bangle.btnWatch) Bangle.btnWatch.forEach(clearWatch);
|
||||
|
@ -113,10 +120,16 @@ function Layout(layout, buttons, options) {
|
|||
}
|
||||
}
|
||||
if (process.env.HWVERSION==2) {
|
||||
// Handler for touch events
|
||||
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)
|
||||
l.cb(e);
|
||||
if (l.c) l.c.forEach(n => touchHandler(n,e));
|
||||
}
|
||||
Bangle.touchHandler = function(_,e){touchHandler(layout,e)};
|
||||
Bangle.on('touch',Bangle.touchHandler);
|
||||
Bangle.on('touch',Bangle.touchHandler);
|
||||
}
|
||||
|
||||
|
||||
// add IDs
|
||||
var ll = this;
|
||||
function idRecurser(l) {
|
||||
|
@ -139,21 +152,6 @@ Layout.prototype.remove = function (l) {
|
|||
}
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Handler for touch events
|
||||
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)
|
||||
l.cb(e);
|
||||
if (l.c) l.c.forEach(n => touchHandler(n,e));
|
||||
}
|
||||
|
||||
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") {
|
||||
|
@ -164,10 +162,8 @@ function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) {
|
|||
if (c) l.c = c;
|
||||
|
||||
if (!delete rectsToClear[hash]) {
|
||||
rects[hash] = {
|
||||
bg: parentBg == null ? g.theme.bg : parentBg,
|
||||
r: [l.x,l.y,l.x+l.w-1,l.y+l.h-1]
|
||||
};
|
||||
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
|
||||
|
@ -180,14 +176,14 @@ function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) {
|
|||
|
||||
Layout.prototype.render = function (l) {
|
||||
if (!l) l = this._l;
|
||||
|
||||
|
||||
function render(l) {"ram"
|
||||
g.reset();
|
||||
if (l.col) g.setColor(l.col);
|
||||
if (l.bgCol!==undefined) g.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){
|
||||
|
@ -227,7 +223,7 @@ Layout.prototype.render = function (l) {
|
|||
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);
|
||||
for (var r of clearList) g.setBgColor(r.bg).clearRect.apply(g, r);
|
||||
drawList.forEach(render);
|
||||
} else { // non-lazy
|
||||
render(l);
|
||||
|
@ -239,29 +235,37 @@ Layout.prototype.layout = function (l) {
|
|||
// exw,exh = extra width/height available
|
||||
switch (l.type) {
|
||||
case "h": {
|
||||
var x = l.x + (0|l.pad);
|
||||
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) { x += (l.w-l._w)/2; }
|
||||
if (!fillx) { acc_w += (l.w-l._w)>>1; fillx=1; }
|
||||
var x = acc_w;
|
||||
l.c.forEach(c => {
|
||||
c.w = c._w + ((0|c.fillx)*(l.w-l._w)/(fillx||1));
|
||||
c.h = c.filly ? l.h - (l.pad<<1) : c._h;
|
||||
c.x = x;
|
||||
c.y = l.y + (0|l.pad) + (1+(0|c.valign))*(l.h-(l.pad<<1)-c.h)/2;
|
||||
x += c.w;
|
||||
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) this.layout(c);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "v": {
|
||||
var y = l.y + (0|l.pad);;
|
||||
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) { y += (l.h-l._h)/2 }
|
||||
if (!filly) { acc_h += (l.h-l._h)>>1; filly=1; }
|
||||
var y = acc_h;
|
||||
l.c.forEach(c => {
|
||||
c.w = c.fillx ? l.w - (l.pad<<1) : c._w;
|
||||
c.h = c._h + ((0|c.filly)*(l.h-l._h)/(filly||1));
|
||||
c.y = y;
|
||||
c.x = l.x + (0|l.pad) + (1+(0|c.halign))*(l.w-(l.pad<<1)-c.w)/2;
|
||||
y += c.h;
|
||||
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) this.layout(c);
|
||||
});
|
||||
break;
|
||||
|
@ -288,8 +292,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 + (l.pad<<1), 0|l.width);
|
||||
l._h = Math.max(l._h + (l.pad<<1), 0|l.height);
|
||||
l._w = 0|Math.max(l._w + (l.pad<<1), 0|l.width);
|
||||
l._h = 0|Math.max(l._h + (l.pad<<1), 0|l.height);
|
||||
}
|
||||
var cb = {
|
||||
"txt" : function(l) {
|
||||
|
@ -349,8 +353,8 @@ Layout.prototype.update = function() {
|
|||
} else {
|
||||
l.w = l._w;
|
||||
l.h = l._h;
|
||||
l.x = (w-l.w)/2;
|
||||
l.y = y+(h-l.h)/2;
|
||||
l.x = (w-l.w)>>1;
|
||||
l.y = y+((h-l.h)>>1);
|
||||
}
|
||||
// layout children
|
||||
this.layout(l);
|
||||
|
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |