2022-02-19 01:34:37 +00:00
|
|
|
var face = require("Storage").readJSON("imageclock.face.json");
|
|
|
|
var resources = require("Storage").readJSON("imageclock.resources.json");
|
|
|
|
|
2022-02-21 16:58:33 +00:00
|
|
|
function prepareImg(resource){
|
|
|
|
//print("prepareImg: ", resource);
|
|
|
|
|
2022-02-27 13:12:54 +00:00
|
|
|
var result = cacheBuffers ? resource : {
|
|
|
|
width: resource.width,
|
|
|
|
height: resource.height,
|
|
|
|
bpp: resource.bpp
|
|
|
|
};
|
|
|
|
if (!cacheBuffers && resource.transparent) result.transparent = resource.transparent;
|
|
|
|
|
2022-02-19 01:34:37 +00:00
|
|
|
if (resource.img){
|
|
|
|
//print("buffer from img");
|
2022-02-27 13:12:54 +00:00
|
|
|
result.buffer = E.toArrayBuffer(atob(resource.img));
|
|
|
|
result.img = undefined;
|
2022-02-19 01:34:37 +00:00
|
|
|
} else if (resource.file){
|
|
|
|
//print("buffer from file");
|
2022-02-27 13:12:54 +00:00
|
|
|
result.buffer = E.toArrayBuffer(atob(require("Storage").read(resource.file)));
|
|
|
|
result.file = undefined;
|
|
|
|
} else if (resource.compressed && (resource.dataOffset == undefined)){
|
2022-02-21 16:58:33 +00:00
|
|
|
//print("buffer from compressed");
|
2022-02-27 13:12:54 +00:00
|
|
|
result.buffer = require("heatshrink").decompress(atob(resource.compressed));
|
|
|
|
result.compressed = undefined;
|
2022-02-21 16:58:33 +00:00
|
|
|
} else if (resource.buffer){
|
|
|
|
//print("buffer cached");
|
2022-02-27 13:12:54 +00:00
|
|
|
} else if (resource.dataOffset !== undefined){
|
|
|
|
//print("buffer from data file");
|
|
|
|
if (resource.compressed){
|
|
|
|
result.buffer = require("heatshrink").decompress(atob(require("Storage").read("imageclock.resources.data", resource.dataOffset, resource.dataLength)));
|
|
|
|
} else {
|
|
|
|
result.buffer = E.toArrayBuffer(atob(require("Storage").read("imageclock.resources.data", resource.dataOffset, resource.dataLength)));
|
|
|
|
}
|
|
|
|
result.compressed = undefined;
|
|
|
|
result.dataOffset = undefined;
|
|
|
|
result.dataLength = undefined;
|
|
|
|
} else {
|
|
|
|
print("Could not get image data for resource", resource);
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
2022-02-27 13:12:54 +00:00
|
|
|
|
|
|
|
if (result.paletteData){
|
2022-02-21 22:30:59 +00:00
|
|
|
result.palette = new Uint16Array(resource.paletteData);
|
|
|
|
result.paletteData = undefined;
|
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
|
2022-02-27 13:12:54 +00:00
|
|
|
return result;
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function getByPath(object, path, lastElem){
|
2022-02-24 22:15:58 +00:00
|
|
|
//print("getByPath", path,lastElem);
|
2022-02-19 01:34:37 +00:00
|
|
|
var current = object;
|
2022-02-24 22:15:58 +00:00
|
|
|
if (path.length) {
|
|
|
|
for (var c of path){
|
|
|
|
if (!current[c]) return undefined;
|
|
|
|
current = current[c];
|
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
if (lastElem!==undefined){
|
|
|
|
if (!current["" + lastElem]) return undefined;
|
2022-02-24 22:15:58 +00:00
|
|
|
//print("Found by lastElem", lastElem);
|
2022-02-19 01:34:37 +00:00
|
|
|
current = current["" + lastElem];
|
|
|
|
}
|
2022-02-24 22:15:58 +00:00
|
|
|
if (typeof current == "function"){
|
|
|
|
//print("current was function");
|
|
|
|
return undefined;
|
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
function splitNumberToDigits(num){
|
|
|
|
return String(num).split('').map(item => Number(item));
|
|
|
|
}
|
|
|
|
|
2022-02-19 18:22:44 +00:00
|
|
|
function drawNumber(element, offset){
|
|
|
|
var number = numbers[element.Value]();
|
2022-02-24 22:15:58 +00:00
|
|
|
var spacing = element.Spacing ? element.Spacing : 0;
|
|
|
|
var unit = element.Unit;
|
|
|
|
|
|
|
|
var imageIndexMinus = element.ImageIndexMinus;
|
|
|
|
var imageIndexUnit = element.ImageIndexUnit;
|
|
|
|
var numberOfDigits = element.Digits;
|
|
|
|
|
|
|
|
|
2022-02-19 18:22:44 +00:00
|
|
|
//print("drawNumber: ", number, element, offset);
|
|
|
|
if (number) number = number.toFixed(0);
|
|
|
|
|
2022-02-19 23:01:16 +00:00
|
|
|
if (!element.Refresh || element.Refresh == "Always" || (element.Refresh == "Change" && element.lastDrawnValue && element.lastDrawnValue != number)){
|
|
|
|
//var numberOffset = updateOffset(element, offset);
|
|
|
|
var numberOffset = offset;
|
|
|
|
|
|
|
|
var isNegative;
|
|
|
|
var digits;
|
|
|
|
if (number == undefined){
|
2022-02-24 22:15:58 +00:00
|
|
|
isNegative = true;
|
|
|
|
digits = [];
|
|
|
|
numberOfDigits = 0;
|
2022-02-19 23:01:16 +00:00
|
|
|
} else {
|
|
|
|
isNegative = number < 0;
|
|
|
|
if (isNegative) number *= -1;
|
|
|
|
digits = splitNumberToDigits(number);
|
|
|
|
}
|
2022-02-19 18:22:44 +00:00
|
|
|
|
2022-02-19 23:01:16 +00:00
|
|
|
//print("digits: ", digits);
|
|
|
|
if (!numberOfDigits) numberOfDigits = digits.length;
|
|
|
|
var firstDigitX = element.X;
|
|
|
|
var firstDigitY = element.Y;
|
2022-02-24 22:15:58 +00:00
|
|
|
var imageIndex = element.ImageIndex ? element.ImageIndex : 0;
|
2022-02-19 23:01:16 +00:00
|
|
|
|
2022-02-24 22:15:58 +00:00
|
|
|
var firstImage;
|
|
|
|
if (imageIndex){
|
|
|
|
firstImage = getByPath(resources, [], "" + (0 + imageIndex));
|
|
|
|
} else {
|
|
|
|
firstImage = getByPath(resources, element.ImagePath, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
var minusImage;
|
|
|
|
if (imageIndexMinus){
|
|
|
|
minusImage = getByPath(resources, [], "" + (0 + imageIndexMinus));
|
|
|
|
} else {
|
|
|
|
minusImage = getByPath(resources, element.ImagePath, "minus");
|
|
|
|
}
|
|
|
|
|
|
|
|
var unitImage;
|
|
|
|
//print("Get image for unit", imageIndexUnit);
|
|
|
|
if (imageIndexUnit !== undefined){
|
|
|
|
unitImage = getByPath(resources, [], "" + (0 + imageIndexUnit));
|
|
|
|
//print("Unit image is", unitImage);
|
|
|
|
} else if (element.Unit){
|
|
|
|
unitImage = getByPath(resources, element.ImagePath, getMultistate(element.Unit, "unknown"));
|
|
|
|
}
|
|
|
|
|
|
|
|
var numberWidth = (numberOfDigits * firstImage.width) + (Math.max((numberOfDigits - 1),0) * spacing);
|
|
|
|
if (isNegative && minusImage){
|
|
|
|
//print("Adding to width", minusImage);
|
|
|
|
numberWidth += minusImage.width + spacing;
|
|
|
|
}
|
|
|
|
if (unitImage){
|
|
|
|
//print("Adding to width", unitImage);
|
|
|
|
numberWidth += unitImage.width + spacing;
|
|
|
|
}
|
|
|
|
//print("numberWidth:", numberWidth);
|
|
|
|
|
|
|
|
if (element.Alignment == "Center") {
|
|
|
|
firstDigitX = Math.round(element.X - (numberWidth/2)) + 1;
|
|
|
|
firstDigitY = Math.round(element.Y - (firstImage.height/2)) + 1;
|
|
|
|
} else if (element.Alignment == "BottomRight"){
|
2022-02-19 23:01:16 +00:00
|
|
|
firstDigitX = element.X - numberWidth + 1;
|
|
|
|
firstDigitY = element.Y - firstImage.height + 1;
|
2022-02-24 22:15:58 +00:00
|
|
|
} else if (element.Alignment == "TopRight") {
|
|
|
|
firstDigitX = element.X - numberWidth + 1;
|
|
|
|
firstDigitY = element.Y;
|
|
|
|
} else if (element.Alignment == "BottomLeft") {
|
|
|
|
firstDigitX = element.X;
|
|
|
|
firstDigitY = element.Y - firstImage.height + 1;
|
2022-02-19 23:01:16 +00:00
|
|
|
}
|
2022-02-24 22:15:58 +00:00
|
|
|
|
2022-02-19 23:01:16 +00:00
|
|
|
var currentX = firstDigitX;
|
2022-02-24 22:15:58 +00:00
|
|
|
if (isNegative && minusImage){
|
|
|
|
//print("Draw minus at", currentX);
|
|
|
|
if (imageIndexMinus){
|
|
|
|
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, "" + (0 + imageIndexMinus));
|
|
|
|
} else {
|
|
|
|
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, "minus");
|
|
|
|
}
|
2022-02-19 23:01:16 +00:00
|
|
|
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, "minus");
|
2022-02-24 22:15:58 +00:00
|
|
|
currentX += minusImage.width + spacing;
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
2022-02-19 23:01:16 +00:00
|
|
|
for (var d = 0; d < numberOfDigits; d++){
|
|
|
|
var currentDigit;
|
|
|
|
var difference = numberOfDigits - digits.length;
|
|
|
|
if (d >= difference){
|
|
|
|
currentDigit = digits[d-difference];
|
|
|
|
} else {
|
|
|
|
currentDigit = 0;
|
|
|
|
}
|
|
|
|
//print("Digit " + currentDigit + " " + currentX);
|
2022-02-24 22:15:58 +00:00
|
|
|
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, currentDigit + imageIndex);
|
|
|
|
currentX += firstImage.width + spacing;
|
|
|
|
}
|
|
|
|
if (imageIndexUnit){
|
|
|
|
//print("Draw unit at", currentX);
|
|
|
|
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, "" + (0 + imageIndexUnit));
|
|
|
|
} else if (element.Unit){
|
|
|
|
drawElement({X:currentX,Y:firstDigitY}, numberOffset, element.ImagePath, getMultistate(element.Unit,"unknown"));
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
2022-02-19 23:01:16 +00:00
|
|
|
element.lastDrawnValue = number;
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function setColors(properties){
|
|
|
|
if (properties.fg) g.setColor(properties.fg);
|
|
|
|
if (properties.bg) g.setBgColor(properties.bg);
|
|
|
|
}
|
|
|
|
|
|
|
|
function drawElement(pos, offset, path, lastElem){
|
|
|
|
//print("drawElement ",pos, offset, path, lastElem);
|
2022-02-24 22:15:58 +00:00
|
|
|
//print("drawElement offset", offset, pos.X, pos.Y);
|
2022-02-19 18:22:44 +00:00
|
|
|
var resource = getByPath(resources, path, lastElem);
|
2022-02-24 22:15:58 +00:00
|
|
|
//print("Got resource", resource);
|
2022-02-19 18:22:44 +00:00
|
|
|
if (resource){
|
2022-02-24 22:15:58 +00:00
|
|
|
//print("resource ", resource,pos, offset, path, lastElem);
|
2022-02-21 16:58:33 +00:00
|
|
|
var image = prepareImg(resource);
|
2022-02-19 18:22:44 +00:00
|
|
|
if (image){
|
2022-02-24 22:15:58 +00:00
|
|
|
var imageOffset = updateColors(pos, offset);
|
|
|
|
setColors(imageOffset);
|
2022-02-19 18:22:44 +00:00
|
|
|
//print("drawImage from drawElement", image, pos, offset);
|
2022-02-20 13:59:49 +00:00
|
|
|
var options={};
|
|
|
|
if (pos.RotationValue){
|
2022-02-27 14:04:40 +00:00
|
|
|
options.rotate = scaledown(pos.RotationValue, pos.MinRotationValue, pos.MaxRotationValue);
|
2022-02-20 13:59:49 +00:00
|
|
|
options.rotate = options.rotate * Math.PI* 2;
|
|
|
|
}
|
|
|
|
if (pos.Scale){
|
|
|
|
options.scale = pos.ScaleValue;
|
|
|
|
}
|
|
|
|
//print("options", options);
|
2022-02-21 16:58:33 +00:00
|
|
|
//print("Memory before drawing", process.memory(false));
|
2022-02-24 22:15:58 +00:00
|
|
|
g.drawImage(image ,(imageOffset.X ? imageOffset.X : 0) + (pos.X ? pos.X : 0),(imageOffset.Y ? imageOffset.Y :0) + (pos.Y ? pos.Y : 0), options);
|
2022-02-19 18:22:44 +00:00
|
|
|
} else {
|
|
|
|
//print("Could not create image from", resource);
|
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
} else {
|
2022-02-19 18:22:44 +00:00
|
|
|
//print("Could not get resource from", path, lastElem);
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-19 23:01:16 +00:00
|
|
|
function checkRedraw(element, newValue){
|
|
|
|
var redrawConfig = element.Redraw ? element.Redraw : defaultRedraw;
|
|
|
|
switch(redrawConfig){
|
|
|
|
case "Change":
|
|
|
|
return !element.lastDrawnValue || element.lastDrawnValue != newValue;
|
|
|
|
case "Never":
|
|
|
|
return false;
|
|
|
|
case "Always":
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-24 22:15:58 +00:00
|
|
|
function getValue(value, defaultValue){
|
|
|
|
if (typeof value == "string"){
|
|
|
|
return numbers[value]();
|
|
|
|
}
|
|
|
|
if (value == undefined) return defaultValue;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getMultistate(name, defaultValue){
|
|
|
|
if (typeof name == "string"){
|
|
|
|
return multistates[name]();
|
|
|
|
} else {
|
|
|
|
if (name == undefined) return defaultValue;
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2022-02-19 18:22:44 +00:00
|
|
|
function drawScale(scale, offset){
|
|
|
|
//print("drawScale", scale, offset);
|
2022-02-19 01:34:37 +00:00
|
|
|
var segments = scale.Segments;
|
2022-02-19 18:22:44 +00:00
|
|
|
var value = numbers[scale.Value]();
|
2022-02-24 22:15:58 +00:00
|
|
|
var maxValue = getValue(scale.MaxValue, 1);
|
|
|
|
var minValue = getValue(scale.MinValue, 0);
|
|
|
|
var imageIndex = scale.ImageIndex !== undefined ? scale.ImageIndex : 0;
|
2022-02-19 18:22:44 +00:00
|
|
|
|
|
|
|
value = value/maxValue;
|
|
|
|
value -= minValue;
|
|
|
|
|
|
|
|
//print("Value is ", value, "(", maxValue, ",", minValue, ")");
|
|
|
|
|
|
|
|
var scaleOffset = updateOffset(scale, offset);
|
2022-02-19 23:01:16 +00:00
|
|
|
|
|
|
|
var segmentsToDraw = Math.ceil(value * segments.length);
|
2022-02-19 18:22:44 +00:00
|
|
|
|
2022-02-19 23:01:16 +00:00
|
|
|
if (checkRedraw(scale, segmentsToDraw)){
|
|
|
|
for (var i = 0; i < segmentsToDraw; i++){
|
2022-02-24 22:15:58 +00:00
|
|
|
drawElement(segments[i], scaleOffset, scale.ImagePath, imageIndex + i);
|
2022-02-19 23:01:16 +00:00
|
|
|
}
|
|
|
|
scale.lastDrawnValue = segmentsToDraw;
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function drawDigit(element, offset, digit){
|
|
|
|
drawElement(element, offset, element.ImagePath, digit);
|
|
|
|
}
|
|
|
|
|
|
|
|
function drawImage(image, offset, name){
|
2022-02-24 22:15:58 +00:00
|
|
|
var imageOffset = updateColors(image, offset);
|
2022-02-19 01:34:37 +00:00
|
|
|
if (image.ImagePath) {
|
|
|
|
//print("drawImage", image, offset, name);
|
2022-02-23 21:55:15 +00:00
|
|
|
if (image.Value && image.Steps){
|
2022-02-24 22:15:58 +00:00
|
|
|
var steps = Math.floor(scaledown(getValue(image.Value), getValue(image.MinValue, 0), getValue(image.MaxValue, 1)) * (image.Steps - 1));
|
2022-02-23 21:55:15 +00:00
|
|
|
//print("Step", steps, "of", image.Steps);
|
2022-02-24 22:15:58 +00:00
|
|
|
drawElement(image, imageOffset, image.ImagePath, "" + steps);
|
|
|
|
} else if (image.ImageIndex !== undefined) {
|
|
|
|
drawElement(image, imageOffset, image.ImagePath, image.ImageIndex);
|
2022-02-23 21:55:15 +00:00
|
|
|
} else {
|
2022-02-24 22:15:58 +00:00
|
|
|
drawElement(image, imageOffset, image.ImagePath, name ? "" + name: undefined);
|
2022-02-23 21:55:15 +00:00
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
} else if (image.ImageFile) {
|
|
|
|
var file = require("Storage").readJSON(image.ImageFile);
|
2022-02-24 22:15:58 +00:00
|
|
|
setColors(imageOffset);
|
|
|
|
g.drawImage(prepareImg(file),image.X + imageOffset.X, image.Y + imageOffset.Y);
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-19 18:22:44 +00:00
|
|
|
function drawCodedImage(image, offset){
|
2022-02-27 21:12:10 +00:00
|
|
|
var code = getValue(image.Value);
|
2022-02-19 18:22:44 +00:00
|
|
|
//print("drawCodedImage", image, offset, code);
|
2022-02-19 23:01:16 +00:00
|
|
|
|
|
|
|
if (checkRedraw(image, code)){
|
|
|
|
if (image.ImagePath) {
|
|
|
|
var factor = 1;
|
|
|
|
var currentCode = code;
|
|
|
|
while (code / factor > 1){
|
|
|
|
currentCode = Math.floor(currentCode/factor)*factor;
|
|
|
|
//print("currentCode", currentCode);
|
|
|
|
if (getByPath(resources, image.ImagePath, currentCode)){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
factor *= 10;
|
|
|
|
}
|
|
|
|
if (code / factor > 1){
|
|
|
|
//print("found match");
|
|
|
|
drawImage(image, offset, currentCode);
|
|
|
|
} else {
|
|
|
|
//print("fallback");
|
|
|
|
drawImage(image, offset, "fallback");
|
2022-02-19 18:22:44 +00:00
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
2022-02-19 23:01:16 +00:00
|
|
|
image.lastDrawnValue = code;
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
2022-02-19 18:22:44 +00:00
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
|
2022-02-19 18:22:44 +00:00
|
|
|
function getWeatherCode(){
|
|
|
|
var jsonWeather = require("Storage").readJSON('weather.json');
|
|
|
|
var weather = (jsonWeather && jsonWeather.weather) ? jsonWeather.weather : undefined;
|
|
|
|
|
|
|
|
if (weather && weather.code){
|
|
|
|
return weather.code;
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
2022-02-19 18:22:44 +00:00
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getWeatherTemperature(){
|
|
|
|
var jsonWeather = require("Storage").readJSON('weather.json');
|
|
|
|
var weather = (jsonWeather && jsonWeather.weather) ? jsonWeather.weather : undefined;
|
2022-02-19 01:34:37 +00:00
|
|
|
|
2022-02-22 17:37:01 +00:00
|
|
|
var result = { unit: "unknown"};
|
2022-02-19 18:22:44 +00:00
|
|
|
if (weather && weather.temp){
|
2022-02-22 17:37:01 +00:00
|
|
|
//print("Weather is", weather);
|
2022-02-21 18:14:46 +00:00
|
|
|
var temp = require('locale').temp(weather.temp-273.15);
|
2022-02-22 17:37:01 +00:00
|
|
|
result.value = Number(temp.match(/[\d\-]*/)[0]);
|
2022-02-21 18:14:46 +00:00
|
|
|
var unit;
|
|
|
|
if (temp.includes("C")){
|
2022-02-22 17:37:01 +00:00
|
|
|
result.unit = "celsius";
|
2022-02-21 18:14:46 +00:00
|
|
|
} else if (temp.includes("F")){
|
2022-02-22 17:37:01 +00:00
|
|
|
result.unit = "fahrenheit";
|
2022-02-21 18:14:46 +00:00
|
|
|
}
|
2022-02-19 18:22:44 +00:00
|
|
|
}
|
2022-02-22 17:37:01 +00:00
|
|
|
return result;
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function updateOffset(element, offset){
|
2022-02-24 22:15:58 +00:00
|
|
|
var newOffset = { X: offset.X ? offset.X : 0, Y: offset.Y ? offset.Y : 0 };
|
|
|
|
if (element && element.X) newOffset.X += element.X;
|
|
|
|
if (element && element.Y) newOffset.Y += element.Y;
|
2022-02-20 16:09:45 +00:00
|
|
|
newOffset = updateColors(element, newOffset);
|
|
|
|
//print("Updated offset from ", offset, "to", newOffset);
|
|
|
|
return newOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateColors(element, offset){
|
2022-02-24 22:15:58 +00:00
|
|
|
var newOffset = { X: offset.X ? offset.X : 0, Y: offset.Y ? offset.Y : 0 };
|
|
|
|
if (element){
|
|
|
|
newOffset.fg = element.ForegroundColor ? element.ForegroundColor: offset.fg;
|
|
|
|
newOffset.bg = element.BackgroundColor ? element.BackgroundColor: offset.bg;
|
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
//print("Updated offset from ", offset, "to", newOffset);
|
|
|
|
return newOffset;
|
|
|
|
}
|
|
|
|
|
2022-02-23 20:53:44 +00:00
|
|
|
function scaledown(value, min, max){
|
2022-02-24 22:15:58 +00:00
|
|
|
//print("scaledown", value, min, max);
|
2022-02-27 14:04:40 +00:00
|
|
|
var scaled = E.clip(getValue(value),getValue(min,0),getValue(max,1));
|
2022-02-24 22:15:58 +00:00
|
|
|
scaled -= getValue(min,0);
|
|
|
|
scaled /= getValue(max,1);
|
2022-02-23 20:53:44 +00:00
|
|
|
return scaled;
|
|
|
|
}
|
|
|
|
|
2022-02-23 22:09:53 +00:00
|
|
|
function rotate(center, coords, rotation) {
|
2022-02-27 14:04:40 +00:00
|
|
|
var value = scaledown(rotation.RotationValue, rotation.MinRotationValue, rotation.MaxRotationValue);
|
2022-02-24 22:15:58 +00:00
|
|
|
value -= rotation.RotationOffset ? rotation.RotationOffset : 0;
|
2022-02-23 22:09:53 +00:00
|
|
|
value *= 360;
|
|
|
|
value -= 180;
|
|
|
|
|
|
|
|
//print("Angle", value);
|
|
|
|
|
|
|
|
var radians = (Math.PI / 180) * value,
|
|
|
|
cos = -Math.cos(radians),
|
|
|
|
sin = Math.sin(radians),
|
|
|
|
x = (cos * (coords.X - center.X)) + (sin * (coords.Y - center.Y)) + center.X,
|
|
|
|
y = (cos * (coords.Y - center.Y)) - (sin * (coords.X - center.X)) + center.Y;
|
|
|
|
return {X:x,Y:y};
|
|
|
|
}
|
|
|
|
|
|
|
|
function drawPoly(element, offset){
|
|
|
|
var vertices = [];
|
2022-02-24 22:15:58 +00:00
|
|
|
var primitiveOffset = offset.clone();
|
|
|
|
if (element.X) primitiveOffset.X += element.X;
|
|
|
|
if (element.Y) primitiveOffset.Y += element.Y;
|
2022-02-23 22:09:53 +00:00
|
|
|
|
|
|
|
for (var c of element.Vertices){
|
|
|
|
if (element.RotationValue){
|
|
|
|
var rotated = rotate({X:0,Y:0}, c, element);
|
|
|
|
vertices.push(rotated.X + primitiveOffset.X);
|
|
|
|
vertices.push(rotated.Y + primitiveOffset.Y);
|
|
|
|
} else {
|
|
|
|
vertices.push(c.X + primitiveOffset.X);
|
|
|
|
vertices.push(c.Y + primitiveOffset.Y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (element.ForegroundColor) g.setColor(element.ForegroundColor);
|
|
|
|
|
2022-02-24 22:15:58 +00:00
|
|
|
if (element.Filled){
|
2022-02-23 22:09:53 +00:00
|
|
|
g.fillPoly(vertices,true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (element.BackgroundColor) g.setColor(element.BackgroundColor);
|
|
|
|
g.drawPoly(vertices,true);
|
|
|
|
}
|
|
|
|
|
2022-02-19 18:22:44 +00:00
|
|
|
var numbers = {};
|
|
|
|
numbers.Hour = () => { return new Date().getHours(); };
|
|
|
|
numbers.HourTens = () => { return Math.floor(new Date().getHours()/10); };
|
|
|
|
numbers.HourOnes = () => { return Math.floor(new Date().getHours()%10); };
|
|
|
|
numbers.Hour12 = () => { return new Date().getHours()%12; };
|
2022-02-22 17:45:31 +00:00
|
|
|
numbers.Hour12Analog = () => { var date = new Date(); return date.getHours()%12 + (date.getMinutes()/59); };
|
2022-02-19 18:22:44 +00:00
|
|
|
numbers.Hour12Tens = () => { return Math.floor((new Date().getHours()%12)/10); };
|
|
|
|
numbers.Hour12Ones = () => { return Math.floor((new Date().getHours()%12)%10); };
|
|
|
|
numbers.Minute = () => { return new Date().getMinutes(); };
|
2022-02-22 17:45:31 +00:00
|
|
|
numbers.MinuteAnalog = () => { var date = new Date(); return date.getMinutes() + (date.getSeconds()/59); };
|
2022-02-19 18:22:44 +00:00
|
|
|
numbers.MinuteTens = () => { return Math.floor(new Date().getMinutes()/10); };
|
|
|
|
numbers.MinuteOnes = () => { return Math.floor(new Date().getMinutes()%10); };
|
|
|
|
numbers.Second = () => { return new Date().getSeconds(); };
|
2022-02-22 17:45:31 +00:00
|
|
|
numbers.SecondAnalog = () => { var date = new Date(); return date.getSeconds() + (date.getMilliseconds()/999); };
|
2022-02-19 18:22:44 +00:00
|
|
|
numbers.SecondTens = () => { return Math.floor(new Date().getSeconds()/10); };
|
|
|
|
numbers.SecondOnes = () => { return Math.floor(new Date().getSeconds()%10); };
|
2022-02-24 22:15:58 +00:00
|
|
|
numbers.WeekDay = () => { return new Date().getDay(); };
|
|
|
|
numbers.WeekDayMondayFirst = () => { var day = (new Date().getDay() - 1); if (day < 0) day = 7 + day; return day; };
|
2022-02-19 18:22:44 +00:00
|
|
|
numbers.Day = () => { return new Date().getDate(); };
|
|
|
|
numbers.DayTens = () => { return Math.floor(new Date().getDate()/10); };
|
|
|
|
numbers.DayOnes = () => { return Math.floor(new Date().getDate()%10); };
|
|
|
|
numbers.Month = () => { return new Date().getMonth() + 1; };
|
|
|
|
numbers.MonthTens = () => { return Math.floor((new Date().getMonth() + 1)/10); };
|
|
|
|
numbers.MonthOnes = () => { return Math.floor((new Date().getMonth() + 1)%10); };
|
|
|
|
numbers.Pulse = () => { return pulse; };
|
|
|
|
numbers.Steps = () => { return Bangle.getHealthStatus ? Bangle.getHealthStatus("day").steps : undefined; };
|
2022-02-24 22:15:58 +00:00
|
|
|
numbers.StepsGoal = () => { return stepsgoal; };
|
2022-02-19 18:22:44 +00:00
|
|
|
numbers.Temperature = () => { return temp; };
|
|
|
|
numbers.Pressure = () => { return press; };
|
|
|
|
numbers.Altitude = () => { return alt; };
|
2022-02-21 18:14:46 +00:00
|
|
|
numbers.BatteryPercentage = E.getBattery;
|
|
|
|
numbers.BatteryVoltage = NRF.getBattery;
|
|
|
|
numbers.WeatherCode = getWeatherCode;
|
2022-02-24 22:15:58 +00:00
|
|
|
numbers.WeatherTemperature = () => { return getWeatherTemperature().value; };
|
2022-02-19 18:22:44 +00:00
|
|
|
|
|
|
|
var multistates = {};
|
|
|
|
multistates.Lock = () => { return Bangle.isLocked() ? "on" : "off"; };
|
|
|
|
multistates.Charge = () => { return Bangle.isCharging() ? "on" : "off"; };
|
|
|
|
multistates.Notifications = () => { return ((require("Storage").readJSON("setting.json", 1) || {}).quiet|0) ? "off" : "vibrate"; };
|
|
|
|
multistates.Alarm = () => { return (require('Storage').readJSON('alarm.json',1)||[]).some(alarm=>alarm.on) ? "on" : "off"; };
|
|
|
|
multistates.Bluetooth = () => { return NRF.getSecurityStatus().connected ? "on" : "off"; };
|
|
|
|
//TODO: Implement peripheral connection status
|
|
|
|
multistates.BluetoothPeripheral = () => { return NRF.getSecurityStatus().connected ? "on" : "off"; };
|
|
|
|
multistates.HRM = () => { return Bangle.isHRMOn ? "on" : "off"; };
|
|
|
|
multistates.Barometer = () => { return Bangle.isBarometerOn() ? "on" : "off"; };
|
|
|
|
multistates.Compass = () => { return Bangle.isCompassOn() ? "on" : "off"; };
|
|
|
|
multistates.GPS = () => { return Bangle.isGPSOn() ? "on" : "off"; };
|
2022-02-24 22:15:58 +00:00
|
|
|
multistates.WeatherTemperatureNegative = () => { return getWeatherTemperature().value ? getWeatherTemperature().value : 0 < 0; };
|
2022-02-21 18:14:46 +00:00
|
|
|
multistates.WeatherTemperatureUnit = () => { return getWeatherTemperature().unit; };
|
2022-02-24 22:15:58 +00:00
|
|
|
multistates.StepsGoal = () => { return (numbers.Steps() >= stepsgoal) ? "on": "off"; };
|
2022-02-19 18:22:44 +00:00
|
|
|
|
|
|
|
function drawMultiState(element, offset){
|
|
|
|
//print("drawMultiState", element, offset);
|
2022-02-19 23:01:16 +00:00
|
|
|
var value = multistates[element.Value]();
|
|
|
|
if (checkRedraw(element, value)){
|
2022-02-20 20:00:28 +00:00
|
|
|
//print("drawImage from drawMultiState", element, offset, value);
|
2022-02-19 23:01:16 +00:00
|
|
|
drawImage(element, offset, value);
|
|
|
|
element.lastDrawnValue = value;
|
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function draw(element, offset){
|
2022-02-19 18:22:44 +00:00
|
|
|
var initial = !element;
|
|
|
|
if (initial){
|
2022-02-19 01:34:37 +00:00
|
|
|
element = face;
|
2022-02-24 22:15:58 +00:00
|
|
|
if (!offset) offset ={};
|
|
|
|
if (!offset.X) offset.X = 0;
|
|
|
|
if (!offset.Y) offset.Y = 0;
|
2022-02-19 01:34:37 +00:00
|
|
|
g.clear();
|
|
|
|
}
|
2022-02-27 14:04:40 +00:00
|
|
|
|
2022-02-19 01:34:37 +00:00
|
|
|
|
|
|
|
var elementOffset = updateOffset(element, offset);
|
|
|
|
setColors(elementOffset);
|
|
|
|
//print("Using offset", elementOffset);
|
|
|
|
|
|
|
|
for (var current in element){
|
|
|
|
//print("Handling ", current, " with offset ", elementOffset);
|
2022-02-27 14:04:40 +00:00
|
|
|
//print("Handling ", current);
|
2022-02-19 01:34:37 +00:00
|
|
|
var currentElement = element[current];
|
2022-02-27 17:59:06 +00:00
|
|
|
|
|
|
|
//var start = Date.now();
|
2022-02-19 18:22:44 +00:00
|
|
|
try {
|
|
|
|
switch(current){
|
|
|
|
case "X":
|
|
|
|
case "Y":
|
|
|
|
case "Properties":
|
|
|
|
case "ForegroundColor":
|
|
|
|
case "BackgroundColor":
|
2022-02-27 17:59:06 +00:00
|
|
|
case "HideOn":
|
2022-02-19 18:22:44 +00:00
|
|
|
//Nothing to draw for these
|
|
|
|
break;
|
|
|
|
case "MultiState":
|
|
|
|
drawMultiState(currentElement, elementOffset);
|
|
|
|
break;
|
|
|
|
case "Image":
|
|
|
|
drawImage(currentElement, elementOffset);
|
|
|
|
break;
|
|
|
|
case "CodedImage":
|
|
|
|
drawCodedImage(currentElement, elementOffset);
|
|
|
|
break;
|
|
|
|
case "Number":
|
|
|
|
drawNumber(currentElement, elementOffset);
|
|
|
|
break;
|
2022-02-23 22:09:53 +00:00
|
|
|
case "Poly":
|
|
|
|
drawPoly(currentElement, elementOffset);
|
|
|
|
break;
|
2022-02-19 18:22:44 +00:00
|
|
|
case "Scale":
|
|
|
|
drawScale(currentElement, elementOffset);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//print("Enter next level", elementOffset);
|
2022-02-27 17:59:06 +00:00
|
|
|
if (currentElement.HideOn && currentElement.HideOn == "Lock" && Bangle.isLocked()){
|
|
|
|
//print("Hiding", current);
|
|
|
|
continue;
|
|
|
|
}
|
2022-02-19 18:22:44 +00:00
|
|
|
draw(currentElement, elementOffset);
|
|
|
|
//print("Done next level");
|
|
|
|
}
|
2022-02-27 14:04:40 +00:00
|
|
|
//print("Drawing of", current, "in", (Date.now() - start).toFixed(0), "ms");
|
2022-02-19 18:22:44 +00:00
|
|
|
} catch (e){
|
|
|
|
print("Error during drawing of", current, "in", element, e);
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-27 14:04:40 +00:00
|
|
|
//print("Finished drawing loop in", Date.now() - start);
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var pulse,alt,temp,press;
|
|
|
|
|
|
|
|
|
|
|
|
var zeroOffset={X:0,Y:0};
|
|
|
|
|
|
|
|
|
2022-02-20 20:00:09 +00:00
|
|
|
var requestedDraws = 0;
|
|
|
|
var isDrawing = false;
|
|
|
|
|
|
|
|
function initialDraw(){
|
2022-02-21 17:02:41 +00:00
|
|
|
//print("Free memory", process.memory(false).free);
|
2022-02-20 20:00:09 +00:00
|
|
|
requestedDraws++;
|
|
|
|
if (!isDrawing){
|
|
|
|
//print(new Date().toISOString(), "Can draw,", requestedDraws, "draws requested so far");
|
|
|
|
isDrawing = true;
|
|
|
|
requestedDraws = 0;
|
|
|
|
//print(new Date().toISOString(), "Drawing start");
|
2022-02-27 14:04:40 +00:00
|
|
|
var start = Date.now();
|
2022-02-20 20:00:09 +00:00
|
|
|
draw(undefined, zeroOffset);
|
2022-02-27 17:59:06 +00:00
|
|
|
//print(new Date().toISOString(), "Drawing done", (Date.now() - start).toFixed(0));
|
2022-02-20 20:00:09 +00:00
|
|
|
isDrawing = false;
|
|
|
|
if (requestedDraws > 0){
|
|
|
|
//print(new Date().toISOString(), "Had deferred drawing left, drawing again");
|
|
|
|
requestedDraws = 0;
|
|
|
|
draw(undefined, zeroOffset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-19 18:22:44 +00:00
|
|
|
|
2022-02-19 01:34:37 +00:00
|
|
|
function handleHrm(e){
|
|
|
|
if (e.confidence > 70){
|
|
|
|
pulse = e.bpm;
|
2022-02-24 22:15:58 +00:00
|
|
|
if (!redrawEvents || redrawEvents.includes("HRM") && !Bangle.isLocked()){
|
2022-02-21 17:02:41 +00:00
|
|
|
//print("Redrawing on HRM");
|
2022-02-20 20:54:42 +00:00
|
|
|
initialDraw();
|
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handlePressure(e){
|
|
|
|
alt = e.altitude;
|
|
|
|
temp = e.temperature;
|
|
|
|
press = e.pressure;
|
2022-02-24 22:15:58 +00:00
|
|
|
if (!redrawEvents || redrawEvents.includes("pressure") && !Bangle.isLocked()){
|
2022-02-21 17:02:41 +00:00
|
|
|
//print("Redrawing on pressure");
|
2022-02-20 20:54:42 +00:00
|
|
|
initialDraw();
|
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
|
2022-02-22 17:47:55 +00:00
|
|
|
function handleCharging(e){
|
2022-02-24 22:15:58 +00:00
|
|
|
if (!redrawEvents || redrawEvents.includes("charging") && !Bangle.isLocked()){
|
2022-02-22 17:47:55 +00:00
|
|
|
//print("Redrawing on charging");
|
|
|
|
initialDraw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-21 17:02:41 +00:00
|
|
|
|
|
|
|
function getMatchedWaitingTime(time){
|
|
|
|
var result = time - (Date.now() % time);
|
|
|
|
//print("Matched timeout", time, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function setMatchedInterval(callable, time, intervalHandler){
|
|
|
|
//print("Setting matched timeout for", time);
|
|
|
|
setTimeout(()=>{
|
|
|
|
var interval = setInterval(callable, time);
|
|
|
|
if (intervalHandler) intervalHandler(interval);
|
|
|
|
}, getMatchedWaitingTime(time));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-19 01:34:37 +00:00
|
|
|
var unlockedDrawInterval;
|
2022-02-21 17:02:41 +00:00
|
|
|
var lockedDrawInterval;
|
2022-02-19 01:34:37 +00:00
|
|
|
|
2022-02-21 17:02:41 +00:00
|
|
|
var lockedRedraw = getByPath(face, ["Properties","Redraw","Locked"]) || 60000;
|
|
|
|
var unlockedRedraw = getByPath(face, ["Properties","Redraw","Unlocked"]) || 1000;
|
2022-02-19 23:01:16 +00:00
|
|
|
var defaultRedraw = getByPath(face, ["Properties","Redraw","Default"]) || "Always";
|
2022-02-20 20:54:42 +00:00
|
|
|
var redrawEvents = getByPath(face, ["Properties","Redraw","Events"]);
|
2022-02-27 13:12:54 +00:00
|
|
|
var cacheBuffers = getByPath(face, ["Properties","CacheBuffers"]) || false;
|
2022-02-20 20:54:42 +00:00
|
|
|
var events = getByPath(face, ["Properties","Events"]);
|
|
|
|
|
2022-02-24 22:15:58 +00:00
|
|
|
var stepsgoal = 2000;
|
|
|
|
|
2022-02-20 20:54:42 +00:00
|
|
|
//print("events", events);
|
|
|
|
//print("redrawEvents", redrawEvents);
|
2022-02-19 01:34:37 +00:00
|
|
|
|
2022-02-21 17:02:41 +00:00
|
|
|
function handleLock(isLocked, forceRedraw){
|
|
|
|
//print("isLocked", Bangle.isLocked());
|
|
|
|
if (unlockedDrawInterval) clearInterval(unlockedDrawInterval);
|
|
|
|
if (lockedDrawInterval) clearInterval(lockedDrawInterval);
|
2022-02-19 01:34:37 +00:00
|
|
|
if (!isLocked){
|
|
|
|
Bangle.setHRMPower(1, "imageclock");
|
|
|
|
Bangle.setBarometerPower(1, 'imageclock');
|
2022-02-21 17:02:41 +00:00
|
|
|
setMatchedInterval(()=>{
|
|
|
|
//print("Redrawing on unlocked interval");
|
2022-02-19 18:22:44 +00:00
|
|
|
initialDraw();
|
2022-02-21 17:02:41 +00:00
|
|
|
},unlockedRedraw, (v)=>{
|
|
|
|
unlockedDrawInterval = v;
|
|
|
|
});
|
2022-02-19 01:34:37 +00:00
|
|
|
} else {
|
|
|
|
Bangle.setHRMPower(0, "imageclock");
|
|
|
|
Bangle.setBarometerPower(0, 'imageclock');
|
2022-02-21 17:02:41 +00:00
|
|
|
setMatchedInterval(()=>{
|
|
|
|
//print("Redrawing on locked interval");
|
|
|
|
initialDraw();
|
|
|
|
},lockedRedraw, (v)=>{
|
|
|
|
lockedDrawInterval = v;
|
|
|
|
});
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
2022-02-21 17:02:41 +00:00
|
|
|
if (forceRedraw || !redrawEvents || redrawEvents.includes("lock")){
|
|
|
|
//print("Redrawing on lock", isLocked);
|
2022-02-20 20:54:42 +00:00
|
|
|
initialDraw();
|
|
|
|
}
|
2022-02-19 01:34:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Bangle.setUI("clock");
|
|
|
|
|
2022-02-20 20:54:42 +00:00
|
|
|
if (!events || events.includes("pressure")){
|
|
|
|
Bangle.on('pressure', handlePressure);
|
|
|
|
Bangle.setBarometerPower(1, 'imageclock');
|
|
|
|
}
|
|
|
|
if (!events || events.includes("HRM")) {
|
|
|
|
Bangle.on('HRM', handleHrm);
|
|
|
|
Bangle.setHRMPower(1, "imageclock");
|
|
|
|
}
|
|
|
|
if (!events || events.includes("lock")) {
|
|
|
|
Bangle.on('lock', handleLock);
|
|
|
|
}
|
2022-02-22 17:47:55 +00:00
|
|
|
if (!events || events.includes("charging")) {
|
|
|
|
Bangle.on('charging', handleCharging);
|
|
|
|
}
|
2022-02-20 20:54:42 +00:00
|
|
|
|
2022-02-22 21:40:34 +00:00
|
|
|
function clearWidgetsDraw(){
|
|
|
|
if (WIDGETS && typeof WIDGETS === "object") {
|
|
|
|
for (let wd of WIDGETS) {
|
|
|
|
wd.draw = () => {};
|
|
|
|
wd.area = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Bangle.loadWidgets();
|
|
|
|
clearWidgetsDraw();
|
|
|
|
|
2022-02-21 17:02:41 +00:00
|
|
|
handleLock(Bangle.isLocked(), true);
|