Merge branch 'espruino:master' into gpsnav

pull/2164/head
storm64 2022-10-07 20:48:07 +02:00 committed by GitHub
commit 06c1156196
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 80 deletions

View File

@ -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

View File

@ -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();
}

View File

@ -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));

View File

@ -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",