mirror of https://github.com/espruino/BangleApps
Merge branch 'espruino:master' into gpsnav
commit
06c1156196
|
@ -10,3 +10,5 @@
|
|||
0.08: Use default Bangle formatter for booleans
|
||||
0.09: Support new fast app switching
|
||||
0.10: Fix clock not correctly refreshing when drawing in timeouts option is not on
|
||||
0.11: Additional option in customizer to force drawing directly
|
||||
Fix some problems in handling timeouts
|
||||
|
|
|
@ -25,49 +25,49 @@ let firstDraw = true;
|
|||
|
||||
let startPerfLog = () => {};
|
||||
let endPerfLog = () => {};
|
||||
let printPerfLog = () => print("Deactivated");
|
||||
let resetPerfLog = () => {performanceLog = {};};
|
||||
Bangle.printPerfLog = () => {print("Deactivated");};
|
||||
Bangle.resetPerfLog = () => {performanceLog = {};};
|
||||
|
||||
let colormap={
|
||||
"#000":0,
|
||||
"#00f":1,
|
||||
"#0f0":2,
|
||||
"#0ff":3,
|
||||
"#f00":4,
|
||||
"#f0f":5,
|
||||
"#ff0":6,
|
||||
"#fff":7
|
||||
"#000":0,
|
||||
"#00f":1,
|
||||
"#0f0":2,
|
||||
"#0ff":3,
|
||||
"#f00":4,
|
||||
"#f0f":5,
|
||||
"#ff0":6,
|
||||
"#fff":7
|
||||
};
|
||||
|
||||
let palette = new Uint16Array([
|
||||
0x0000, //black #000
|
||||
0x001f, //blue #00f
|
||||
0x07e0, //green #0f0
|
||||
0x07ff, //cyan #0ff
|
||||
0xf800, //red #f00
|
||||
0xf81f, //magenta #f0f
|
||||
0xffe0, //yellow #ff0
|
||||
0xffff, //white #fff
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0x0000, //black #000
|
||||
0x001f, //blue #00f
|
||||
0x07e0, //green #0f0
|
||||
0x07ff, //cyan #0ff
|
||||
0xf800, //red #f00
|
||||
0xf81f, //magenta #f0f
|
||||
0xffe0, //yellow #ff0
|
||||
0xffff, //white #fff
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
0xffff, //white
|
||||
]);
|
||||
|
||||
let p0 = g;
|
||||
let p1;
|
||||
|
||||
if (settings.perflog){
|
||||
Bangle.startPerfLog = function(name){
|
||||
startPerfLog = function(name){
|
||||
let time = getTime();
|
||||
if (!performanceLog.start) performanceLog.start={};
|
||||
performanceLog.start[name] = time;
|
||||
};
|
||||
Bangle.endPerfLog = function (name){
|
||||
endPerfLog = function (name){
|
||||
let time = getTime();
|
||||
if (!performanceLog.last) performanceLog.last={};
|
||||
let duration = time - performanceLog.start[name];
|
||||
|
@ -92,20 +92,30 @@ let firstDraw = true;
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
let delayTimeouts = [];
|
||||
|
||||
startPerfLog("loadFunctions");
|
||||
|
||||
let delayTimeouts = {};
|
||||
let timeoutCount = 0;
|
||||
|
||||
let delay = function(t) {
|
||||
return new Promise(function (resolve) {
|
||||
delayTimeouts.push(setTimeout(resolve, t));
|
||||
const i = timeoutCount++;
|
||||
let timeout = setTimeout(()=>{
|
||||
resolve();
|
||||
delete delayTimeouts[i];
|
||||
}, t);
|
||||
delayTimeouts[i] = timeout;
|
||||
//print("Add delay timeout", delayTimeouts);
|
||||
});
|
||||
};
|
||||
|
||||
let cleanupDelays = function(){
|
||||
//print("Cleanup delays", delayTimeouts);
|
||||
for (let t of delayTimeouts){
|
||||
clearTimeout(t);
|
||||
}
|
||||
delayTimeouts = [];
|
||||
delayTimeouts = {};
|
||||
};
|
||||
|
||||
let prepareImg = function(resource){
|
||||
|
@ -117,7 +127,7 @@ let firstDraw = true;
|
|||
delete resource.dataOffset;
|
||||
delete resource.dataLength;
|
||||
if (resource.paletteData){
|
||||
result.palette = new Uint16Array(resource.paletteData);
|
||||
resource.palette = new Uint16Array(resource.paletteData);
|
||||
delete resource.paletteData;
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +173,7 @@ let firstDraw = true;
|
|||
let drawNumber = function(graphics, resources, element){
|
||||
startPerfLog("drawNumber");
|
||||
let number = getValue(element.Value);
|
||||
//print("drawNumber: ", number, element);
|
||||
let spacing = element.Spacing ? element.Spacing : 0;
|
||||
let unit = element.Unit;
|
||||
|
||||
|
@ -171,7 +182,6 @@ let firstDraw = true;
|
|||
let numberOfDigits = element.Digits;
|
||||
|
||||
|
||||
//print("drawNumber: ", number, element);
|
||||
if (number) number = number.toFixed(0);
|
||||
|
||||
let isNegative;
|
||||
|
@ -258,7 +268,7 @@ let firstDraw = true;
|
|||
} else {
|
||||
currentDigit = 0;
|
||||
}
|
||||
//print("Digit " + currentDigit + " " + currentX);
|
||||
//print("Digit", currentDigit, currentX);
|
||||
drawElement(graphics, resources, {X:currentX,Y:firstDigitY}, element, currentDigit + imageIndex);
|
||||
currentX += firstImage.width + spacing;
|
||||
}
|
||||
|
@ -295,11 +305,9 @@ let firstDraw = true;
|
|||
}
|
||||
}
|
||||
|
||||
//print("cache ",typeof element.cachedImage[cacheKey], element.ImagePath, lastElem);
|
||||
//print("cache ", typeof element.cachedImage[cacheKey], element.ImagePath, lastElem);
|
||||
if(element.cachedImage[cacheKey]){
|
||||
//print("drawElement ",pos, path, lastElem);
|
||||
//print("resource ", resource,pos, path, lastElem);
|
||||
//print("drawImage from drawElement", image, pos);
|
||||
//print("drawElement ", pos, element, lastElem);
|
||||
let options={};
|
||||
if (element.RotationValue){
|
||||
options.rotate = radians(element);
|
||||
|
@ -320,19 +328,23 @@ let firstDraw = true;
|
|||
};
|
||||
|
||||
let getValue = function(value, defaultValue){
|
||||
startPerfLog("getValue");
|
||||
if (typeof value == "string"){
|
||||
return numbers[value]();
|
||||
}
|
||||
if (value == undefined) return defaultValue;
|
||||
endPerfLog("getValue");
|
||||
return value;
|
||||
};
|
||||
|
||||
let getMultistate = function(name, defaultValue){
|
||||
startPerfLog("getMultistate");
|
||||
if (typeof name == "string"){
|
||||
return multistates[name]();
|
||||
} else {
|
||||
if (name == undefined) return defaultValue;
|
||||
}
|
||||
endPerfLog("getMultistate");
|
||||
return undefined;
|
||||
};
|
||||
|
||||
|
@ -343,9 +355,6 @@ let firstDraw = true;
|
|||
let imageIndex = scale.ImageIndex !== undefined ? scale.ImageIndex : 0;
|
||||
|
||||
let value = scaledown(scale.Value, scale.MinValue, scale.MaxValue);
|
||||
|
||||
//print("Value is ", value, "(", maxValue, ",", minValue, ")");
|
||||
|
||||
let segmentsToDraw = Math.ceil(value * segments.length);
|
||||
|
||||
for (let i = 0; i < segmentsToDraw; i++){
|
||||
|
@ -576,8 +585,6 @@ let firstDraw = true;
|
|||
let requestedDraws = 0;
|
||||
let isDrawing = false;
|
||||
|
||||
let drawingTime;
|
||||
|
||||
let start;
|
||||
|
||||
let deferredTimout;
|
||||
|
@ -589,12 +596,9 @@ let firstDraw = true;
|
|||
cleanupDelays();
|
||||
//print(new Date().toISOString(), "Can draw,", requestedDraws, "draws requested so far");
|
||||
isDrawing = true;
|
||||
resetPerfLog();
|
||||
requestedDraws = 0;
|
||||
//print(new Date().toISOString(), "Drawing start");
|
||||
startPerfLog("initialDraw");
|
||||
//start = Date.now();
|
||||
drawingTime = 0;
|
||||
//print("Precompiled");
|
||||
let promise = precompiledJs(watchfaceResources, watchface);
|
||||
|
||||
|
@ -608,8 +612,6 @@ let firstDraw = true;
|
|||
g.drawLine(0,24,g.getWidth(),24);
|
||||
}
|
||||
lastDrawTime = Date.now() - start;
|
||||
drawingTime += Date.now() - currentDrawingTime;
|
||||
//print(new Date().toISOString(), "Drawing done in", lastDrawTime.toFixed(0), "active:", drawingTime.toFixed(0));
|
||||
isDrawing=false;
|
||||
firstDraw=false;
|
||||
requestRefresh = false;
|
||||
|
@ -621,6 +623,8 @@ let firstDraw = true;
|
|||
if (requestedDraws > 0){
|
||||
//print(new Date().toISOString(), "Had deferred drawing left, drawing again");
|
||||
requestedDraws = 0;
|
||||
//print("Clear deferred timeout", deferredTimout);
|
||||
clearTimeout(deferredTimeout);
|
||||
deferredTimout = setTimeout(()=>{initialDraw(resources, face);}, 10);
|
||||
}
|
||||
} //else {
|
||||
|
@ -658,29 +662,34 @@ let firstDraw = true;
|
|||
|
||||
let getMatchedWaitingTime = function(time){
|
||||
let result = time - (Date.now() % time);
|
||||
//print("Matched timeout", time, result);
|
||||
//print("Matched wating time", time, result);
|
||||
return result;
|
||||
};
|
||||
|
||||
let setMatchedInterval = function(callable, time, intervalHandler, delay){
|
||||
//print("Setting matched interval for", time, intervalHandler);
|
||||
if (!delay) delay = 0;
|
||||
let matchedTime = getMatchedWaitingTime(time + delay);
|
||||
return setTimeout(()=>{
|
||||
let interval = setInterval(callable, time);
|
||||
//print("setMatchedInterval", interval);
|
||||
if (intervalHandler) intervalHandler(interval);
|
||||
callable();
|
||||
}, matchedTime);
|
||||
};
|
||||
|
||||
endPerfLog("loadFunctions");
|
||||
|
||||
let lastDrawTime = 0;
|
||||
|
||||
startPerfLog("loadProperties");
|
||||
let lockedRedraw = getByPath(watchface, ["Properties","Redraw","Locked"]) || 60000;
|
||||
let unlockedRedraw = getByPath(watchface, ["Properties","Redraw","Unlocked"]) || 1000;
|
||||
let defaultRedraw = getByPath(watchface, ["Properties","Redraw","Default"]) || "Always";
|
||||
let redrawEvents = getByPath(watchface, ["Properties","Redraw","Events"]);
|
||||
let clearOnRedraw = getByPath(watchface, ["Properties","Redraw","Clear"]);
|
||||
let events = getByPath(watchface, ["Properties","Events"]);
|
||||
endPerfLog("loadProperties");
|
||||
|
||||
//print("events", events);
|
||||
//print("redrawEvents", redrawEvents);
|
||||
|
@ -706,7 +715,10 @@ let firstDraw = true;
|
|||
//print("Redrawing on unlock", isLocked);
|
||||
initialDraw(watchfaceResources, watchface);
|
||||
}
|
||||
if (initialDrawTimeoutUnlocked) clearTimeout(initialDrawTimeoutUnlocked);
|
||||
if (initialDrawTimeoutUnlocked){
|
||||
//print("clear initialDrawTimeUnlocked timet", initialDrawTimeoutUnlocked);
|
||||
clearTimeout(initialDrawTimeoutUnlocked);
|
||||
}
|
||||
initialDrawTimeoutUnlocked = setMatchedInterval(()=>{
|
||||
//print("Redrawing on unlocked interval");
|
||||
initialDraw(watchfaceResources, watchface);
|
||||
|
@ -721,7 +733,10 @@ let firstDraw = true;
|
|||
//print("Redrawing on lock", isLocked);
|
||||
initialDraw(watchfaceResources, watchface);
|
||||
}
|
||||
if (initialDrawTimeoutLocked) clearTimeout(initialDrawTimeoutLocked);
|
||||
if (initialDrawTimeoutLocked){
|
||||
clearTimeout(initialDrawTimeoutLocked);
|
||||
//print("clear initialDrawTimeLocked timet", initialDrawTimeoutLocked);
|
||||
}
|
||||
initialDrawTimeoutLocked = setMatchedInterval(()=>{
|
||||
//print("Redrawing on locked interval");
|
||||
initialDraw(watchfaceResources, watchface);
|
||||
|
@ -780,7 +795,7 @@ let firstDraw = true;
|
|||
try{
|
||||
Bangle.setBarometerPower(1, 'imageclock');
|
||||
} catch (e){
|
||||
print("Error during barometer power up", e);
|
||||
//print("Error during barometer power up", e);
|
||||
}
|
||||
}
|
||||
if (!events || events.includes("HRM")) {
|
||||
|
@ -845,11 +860,17 @@ let firstDraw = true;
|
|||
delete showWidgets;
|
||||
delete firstDraw;
|
||||
|
||||
delete Bangle.printPerfLog;
|
||||
if (settings.perflog){
|
||||
delete Bangle.resetPerfLog;
|
||||
delete performanceLog;
|
||||
}
|
||||
|
||||
cleanupDelays();
|
||||
restoreWidgetDraw();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Bangle.loadWidgets();
|
||||
clearWidgetsDraw();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
Options:</br>
|
||||
<input type="checkbox" id="timeoutwrap" name="mode"/>
|
||||
<label for="timeoutwrap">Wrap draw calls in timeouts (Slower, more RAM use, better interactivity)</label></br>
|
||||
<input type="checkbox" id="forceOrigPlane" name="mode" disabled="true"/>
|
||||
<label for="forceOrigPlane">Force use of direct drawing (Even faster, but will produce visible artifacts on not optimized watch faces)</label></br>
|
||||
<input type="checkbox" id="debugprints" name="mode"/>
|
||||
<label for="debugprints">Add debug prints to generated code</label></br>
|
||||
</p>
|
||||
|
@ -579,11 +581,8 @@
|
|||
return result;
|
||||
}
|
||||
|
||||
function convertToCode(elements, properties, wrapInTimeouts){
|
||||
function convertToCode(elements, properties, wrapInTimeouts, forceUseOrigPlane){
|
||||
var code = "(function (wr, wf) {\n";
|
||||
if (!wrapInTimeouts){
|
||||
code += "var ct=Date.now();\n";
|
||||
}
|
||||
code += "var lc;\n";
|
||||
code += "var p = Promise.resolve();\n";
|
||||
|
||||
|
@ -595,7 +594,7 @@
|
|||
var c = elements[i].value;
|
||||
console.log("Check element", c);
|
||||
var name = c.Layer;
|
||||
var plane = wrapInTimeouts ? 1 : 0;
|
||||
var plane = (wrapInTimeouts && !forceUseOrigPlane) ? 1 : 0;
|
||||
if (typeof c.Plane == "number"){
|
||||
plane = c.Plane;
|
||||
}
|
||||
|
@ -610,8 +609,6 @@
|
|||
|
||||
console.log("Found planes", planes, "with numbers", planeNumbers)
|
||||
|
||||
if (wrapInTimeouts && planes == 0) planes = 1;
|
||||
|
||||
code += "p0 = g;\n";
|
||||
|
||||
for (var planeIndex = 0; planeIndex < planeNumbers.length; planeIndex++){
|
||||
|
@ -624,32 +621,25 @@
|
|||
if (plane != 0) code += "if (!p" + plane + ") p" + plane + " = Graphics.createArrayBuffer(g.getWidth(),g.getHeight(),4,{msb:true});\n";
|
||||
|
||||
if (properties.Redraw && properties.Redraw.Clear){
|
||||
if (wrapInTimeouts && plane != 0){
|
||||
if (wrapInTimeouts && (plane != 0 || forceUseOrigPlane)){
|
||||
code += "p = p.then(()=>delay(0)).then(()=>{\n";
|
||||
} else {
|
||||
code += "p = p.then(()=>{\n";
|
||||
}
|
||||
code += "var ct=Date.now();\n"
|
||||
if (addDebug()) code += 'print("Clear for redraw of plane ' + p + '");'+"\n";
|
||||
code += 'startPerfLog("initialDraw_g.clear");'+"\n";
|
||||
code += "p" + plane + ".clear(true);\n";
|
||||
code += 'endPerfLog("initialDraw_g.clear");'+ "\n";
|
||||
|
||||
code += "drawingTime += Date.now() - ct;\n";
|
||||
code += "});\n";
|
||||
}
|
||||
|
||||
var previousPlane = plane + 1;
|
||||
if (previousPlane < planeNumbers.length){
|
||||
code += "p = p.then(()=>{\n";
|
||||
code += "var ct=Date.now();\n";
|
||||
|
||||
if (addDebug()) code += 'print("Copying of plane ' + previousPlane + ' to display");'+"\n";
|
||||
//code += "g.drawImage(p" + i + ".asImage());";
|
||||
code += "p0.drawImage({width: p" + previousPlane + ".getWidth(), height: p" + previousPlane + ".getHeight(), bpp: p" + previousPlane + ".getBPP(), buffer: p" + previousPlane + ".buffer, palette: palette});\n";
|
||||
|
||||
|
||||
code += "drawingTime += Date.now() - ct;\n";
|
||||
code += "});\n";
|
||||
}
|
||||
|
||||
|
@ -660,12 +650,6 @@
|
|||
console.log("Layer elements", layername, layerElements);
|
||||
//code for whole layer
|
||||
|
||||
if (wrapInTimeouts && plane != 0){
|
||||
code += "p = p.then(()=>delay(0)).then(()=>{\n";
|
||||
} else {
|
||||
code += "p = p.then(()=>{\n";
|
||||
}
|
||||
code += "var ct=Date.now();\n";
|
||||
if (addDebug()) code += 'print("Starting layer ' + layername + '");' + "\n";
|
||||
|
||||
var checkForLayerChange = false;
|
||||
|
@ -732,14 +716,17 @@
|
|||
if (addDebug()) code += 'print("Element condition is ' + condition + '");' + "\n";
|
||||
code += "" + colorsetting;
|
||||
code += (condition.length > 0 ? "if (" + condition + "){\n" : "");
|
||||
if (wrapInTimeouts && (plane != 0 || forceUseOrigPlane)){
|
||||
code += "p = p.then(()=>delay(0)).then(()=>{\n";
|
||||
} else {
|
||||
code += "p = p.then(()=>{\n";
|
||||
}
|
||||
if (addDebug()) code += 'print("Drawing element ' + elementIndex + ' with type ' + c.type + ' on plane ' + planeName + '");' + "\n";
|
||||
code += "draw" + c.type + "(" + planeName + ", wr, wf.Collapsed[" + elementIndex + "].value);\n";
|
||||
|
||||
code += "});\n";
|
||||
code += (condition.length > 0 ? "}\n" : "");
|
||||
}
|
||||
|
||||
code += "drawingTime += Date.now() - ct;\n";
|
||||
code += "});\n";
|
||||
}
|
||||
console.log("Current plane is", plane);
|
||||
|
||||
|
@ -759,7 +746,7 @@
|
|||
var properties = faceJson.Properties;
|
||||
faceJson = { Properties: properties, Collapsed: collapseTree(faceJson,{X:0,Y:0})};
|
||||
console.log("After collapsing", faceJson);
|
||||
precompiledJs = convertToCode(faceJson.Collapsed, properties, document.getElementById('timeoutwrap').checked);
|
||||
precompiledJs = convertToCode(faceJson.Collapsed, properties, document.getElementById('timeoutwrap').checked, document.getElementById('forceOrigPlane').checked);
|
||||
console.log("After precompiling", precompiledJs);
|
||||
}
|
||||
|
||||
|
@ -1011,6 +998,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
document.getElementById("timeoutwrap").addEventListener("click", function() {
|
||||
document.getElementById("forceOrigPlane").disabled = !document.getElementById("timeoutwrap").checked;
|
||||
});
|
||||
|
||||
document.getElementById("btnSave").addEventListener("click", function() {
|
||||
var h = document.createElement('a');
|
||||
h.href = 'data:text/json;charset=utf-8,' + encodeURI(JSON.stringify(resultJson));
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "imageclock",
|
||||
"name": "Imageclock",
|
||||
"shortName": "Imageclock",
|
||||
"version": "0.10",
|
||||
"version": "0.11",
|
||||
"type": "clock",
|
||||
"description": "BETA!!! File formats still subject to change --- This app is a highly customizable watchface. To use it, you need to select a watchface. You can build the watchfaces yourself without programming anything. All you need to do is write some json and create image files.",
|
||||
"icon": "app.png",
|
||||
|
|
Loading…
Reference in New Issue