2021-02-03 00:30:34 +00:00
|
|
|
/**
|
2021-04-07 21:45:50 +00:00
|
|
|
* Adrian Kirk 2021-02
|
|
|
|
* Sliding text clock inspired by the Pebble
|
|
|
|
* clock with the same name
|
|
|
|
*/
|
|
|
|
|
|
|
|
const color_schemes = [
|
|
|
|
{
|
|
|
|
name: "black",
|
|
|
|
background : [0.0,0.0,0.0],
|
2022-09-30 13:07:43 +00:00
|
|
|
main_bar: [1.0,0.0,0.0],
|
2022-06-28 10:08:43 +00:00
|
|
|
other_bars: [0.9,0.9,0.9],
|
2021-04-07 21:45:50 +00:00
|
|
|
},
|
2022-10-09 09:32:09 +00:00
|
|
|
{
|
|
|
|
name: "white",
|
|
|
|
background : [1.0,1.0,1.0],
|
|
|
|
main_bar: [0.0,0.0,0.0],
|
|
|
|
other_bars: [0.1,0.1,0.1],
|
|
|
|
},
|
2021-04-07 21:45:50 +00:00
|
|
|
{
|
|
|
|
name: "red",
|
|
|
|
background : [1.0,0.0,0.0],
|
|
|
|
main_bar: [1.0,1.0,0.0],
|
|
|
|
other_bars: [0.85,0.85,0.85]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "grey",
|
|
|
|
background : [0.5,0.5,0.5],
|
|
|
|
main_bar: [1.0,1.0,1.0],
|
|
|
|
other_bars: [0.0,0.0,0.0],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "purple",
|
2022-10-08 00:45:14 +00:00
|
|
|
background : [0.3,0.0,0.6],
|
2021-04-07 21:45:50 +00:00
|
|
|
main_bar: [1.0,1.0,0.0],
|
|
|
|
other_bars: [0.85,0.85,0.85]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "blue",
|
2022-09-30 13:07:43 +00:00
|
|
|
background : [0.1,0.2,1.0],
|
|
|
|
main_bar: [1.0,1.0,0.0],
|
2021-04-07 21:45:50 +00:00
|
|
|
other_bars: [0.9,0.9,0.9]
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
let color_scheme_index = 0;
|
|
|
|
|
2021-02-17 01:43:21 +00:00
|
|
|
|
2021-04-07 21:45:50 +00:00
|
|
|
/**
|
|
|
|
* The Watch Display
|
|
|
|
*/
|
|
|
|
|
|
|
|
function bg_color(){
|
|
|
|
return color_schemes[color_scheme_index].background;
|
|
|
|
}
|
|
|
|
|
|
|
|
function main_color(){
|
|
|
|
return color_schemes[color_scheme_index].main_bar;
|
|
|
|
}
|
|
|
|
|
|
|
|
function other_color(){
|
|
|
|
return color_schemes[color_scheme_index].other_bars;
|
|
|
|
}
|
|
|
|
|
|
|
|
let command_stack_high_priority = [];
|
|
|
|
let command_stack_low_priority = [];
|
|
|
|
|
|
|
|
function next_command(){
|
2022-09-30 13:07:43 +00:00
|
|
|
var command = command_stack_high_priority.pop();
|
2021-04-07 21:45:50 +00:00
|
|
|
if(command == null){
|
|
|
|
command = command_stack_low_priority.pop();
|
|
|
|
}
|
|
|
|
if(command != null){
|
|
|
|
command.call();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function reset_commands(){
|
|
|
|
command_stack_high_priority = [];
|
|
|
|
command_stack_low_priority = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
function has_commands(){
|
|
|
|
return command_stack_high_priority.length > 0 ||
|
2022-06-27 17:04:45 +00:00
|
|
|
command_stack_low_priority.length > 0;
|
2021-04-07 21:45:50 +00:00
|
|
|
}
|
2021-02-17 01:43:21 +00:00
|
|
|
|
2021-02-03 00:30:34 +00:00
|
|
|
class ShiftText {
|
2021-02-17 01:43:21 +00:00
|
|
|
/**
|
2021-04-07 21:45:50 +00:00
|
|
|
* Class Responsible for shifting text around the screen
|
|
|
|
*
|
|
|
|
* This is a object that initializes itself with a position and
|
|
|
|
* text after which you can tell it where you want to move to
|
|
|
|
* using the moveTo method and it will smoothly move the text across
|
|
|
|
* at the selected frame rate and speed
|
|
|
|
*/
|
2021-02-03 00:30:34 +00:00
|
|
|
constructor(x,y,txt,font_name,
|
2021-04-07 21:45:50 +00:00
|
|
|
font_size,speed_x,speed_y,freq_millis,
|
|
|
|
color,
|
2022-07-30 09:53:21 +00:00
|
|
|
bg_color,
|
2022-07-30 18:24:44 +00:00
|
|
|
row_context,
|
|
|
|
rotation){
|
2021-02-03 00:30:34 +00:00
|
|
|
this.x = x;
|
|
|
|
this.tgt_x = x;
|
2021-02-04 00:29:35 +00:00
|
|
|
this.init_x = x;
|
2021-02-03 00:30:34 +00:00
|
|
|
this.y = y;
|
|
|
|
this.tgt_y = y;
|
2021-02-04 00:29:35 +00:00
|
|
|
this.init_y = y;
|
2021-02-03 00:30:34 +00:00
|
|
|
this.txt = txt;
|
2021-02-04 00:29:35 +00:00
|
|
|
this.init_txt = txt;
|
2021-02-03 00:30:34 +00:00
|
|
|
this.font_name = font_name;
|
|
|
|
this.font_size = font_size;
|
|
|
|
this.speed_x = Math.abs(speed_x);
|
|
|
|
this.speed_y = Math.abs(speed_y);
|
|
|
|
this.freq_millis = freq_millis;
|
2021-04-07 21:45:50 +00:00
|
|
|
this.color = color;
|
|
|
|
this.bg_color = bg_color;
|
2022-07-30 09:53:21 +00:00
|
|
|
this.row_context = row_context;
|
2022-07-30 18:24:44 +00:00
|
|
|
this.rotation = rotation;
|
2021-02-03 00:30:34 +00:00
|
|
|
this.finished_callback=null;
|
2021-02-04 00:29:35 +00:00
|
|
|
this.timeoutId = null;
|
|
|
|
}
|
2022-07-30 09:53:21 +00:00
|
|
|
getRowContext(){ return this.row_context;}
|
2022-09-29 18:05:44 +00:00
|
|
|
setColor(color){ this.color = color; }
|
|
|
|
setBgColor(bg_color){ this.bg_color = bg_color; }
|
2021-04-18 08:31:25 +00:00
|
|
|
reset(hard_reset) {
|
2021-02-04 00:29:35 +00:00
|
|
|
this.hide();
|
|
|
|
this.x = this.init_x;
|
|
|
|
this.y = this.init_y;
|
2021-04-18 08:31:25 +00:00
|
|
|
if (hard_reset) {
|
|
|
|
this.txt = this.init_txt;
|
|
|
|
}
|
2021-02-04 00:29:35 +00:00
|
|
|
this.show();
|
|
|
|
if(this.timeoutId != null){
|
2021-04-07 21:45:50 +00:00
|
|
|
clearTimeout(this.timeoutId);
|
2021-02-04 00:29:35 +00:00
|
|
|
}
|
2021-02-03 00:30:34 +00:00
|
|
|
}
|
|
|
|
show() {
|
2022-07-30 18:24:44 +00:00
|
|
|
g.setFontAlign(-1,-1,this.rotation);
|
2021-02-03 00:30:34 +00:00
|
|
|
g.setFont(this.font_name,this.font_size);
|
2021-04-07 21:45:50 +00:00
|
|
|
g.setColor(this.color[0],this.color[1],this.color[2]);
|
2021-02-03 00:30:34 +00:00
|
|
|
g.drawString(this.txt, this.x, this.y);
|
|
|
|
}
|
|
|
|
hide(){
|
2022-07-30 18:24:44 +00:00
|
|
|
g.setFontAlign(-1,-1,this.rotation);
|
2021-02-03 00:30:34 +00:00
|
|
|
g.setFont(this.font_name,this.font_size);
|
2021-04-07 21:45:50 +00:00
|
|
|
//console.log("bgcolor:" + this.bg_color);
|
|
|
|
g.setColor(this.bg_color[0],this.bg_color[1],this.bg_color[2]);
|
2021-02-03 00:30:34 +00:00
|
|
|
g.drawString(this.txt, this.x, this.y);
|
|
|
|
}
|
|
|
|
setText(txt){
|
|
|
|
this.txt = txt;
|
|
|
|
}
|
|
|
|
setTextPosition(txt,x,y){
|
|
|
|
this.hide();
|
|
|
|
this.x = x;
|
|
|
|
this.y = y;
|
|
|
|
this.txt = txt;
|
|
|
|
this.show();
|
|
|
|
}
|
2021-02-04 00:29:35 +00:00
|
|
|
setTextXPosition(txt,x){
|
|
|
|
this.hide();
|
|
|
|
this.x = x;
|
|
|
|
this.txt = txt;
|
|
|
|
this.show();
|
|
|
|
}
|
2021-02-06 00:36:22 +00:00
|
|
|
setTextYPosition(txt,y){
|
|
|
|
this.hide();
|
|
|
|
this.y = y;
|
|
|
|
this.txt = txt;
|
|
|
|
this.show();
|
|
|
|
}
|
2021-02-03 00:30:34 +00:00
|
|
|
moveTo(new_x,new_y){
|
|
|
|
this.tgt_x = new_x;
|
|
|
|
this.tgt_y = new_y;
|
|
|
|
this._doMove();
|
|
|
|
}
|
2021-02-04 00:29:35 +00:00
|
|
|
moveToX(new_x){
|
|
|
|
this.tgt_x = new_x;
|
|
|
|
this._doMove();
|
|
|
|
}
|
|
|
|
moveToY(new_y){
|
|
|
|
this.tgt_y = new_y;
|
|
|
|
this._doMove();
|
|
|
|
}
|
2022-07-30 15:08:43 +00:00
|
|
|
scrollInFromBottom(txt,to_y){
|
|
|
|
if(to_y == null)
|
|
|
|
to_y = this.init_y;
|
|
|
|
|
2022-10-04 00:11:49 +00:00
|
|
|
this.setTextPosition(txt, this.init_x, g.getHeight()*2);
|
2022-07-30 15:08:43 +00:00
|
|
|
this.moveTo(this.init_x,to_y);
|
|
|
|
}
|
2022-07-29 21:49:48 +00:00
|
|
|
scrollInFromLeft(txt,to_x){
|
2022-07-30 15:08:43 +00:00
|
|
|
if(to_x == null)
|
|
|
|
to_x = this.init_x;
|
|
|
|
|
|
|
|
this.setTextPosition(txt, -txt.length * this.font_size - this.font_size, this.init_y);
|
|
|
|
this.moveTo(to_x,this.init_y);
|
2022-07-29 21:49:48 +00:00
|
|
|
}
|
|
|
|
scrollInFromRight(txt,to_x){
|
2022-07-30 15:08:43 +00:00
|
|
|
if(to_x == null)
|
|
|
|
to_x = this.init_x;
|
|
|
|
|
|
|
|
this.setTextPosition(txt, g.getWidth() + this.font_size, this.init_y);
|
|
|
|
this.moveTo(to_x,this.init_y);
|
2022-07-29 21:49:48 +00:00
|
|
|
}
|
|
|
|
scrollOffToLeft(){
|
2022-07-30 15:08:43 +00:00
|
|
|
this.moveTo(-this.txt.length * this.font_size, this.init_y);
|
2022-07-29 21:49:48 +00:00
|
|
|
}
|
|
|
|
scrollOffToRight(){
|
2022-07-30 15:08:43 +00:00
|
|
|
this.moveTo(g.getWidth() + this.font_size, this.init_y);
|
|
|
|
}
|
|
|
|
scrollOffToBottom(){
|
2022-10-04 00:11:49 +00:00
|
|
|
this.moveTo(this.init_x,g.getHeight()*2);
|
2022-07-29 21:49:48 +00:00
|
|
|
}
|
2021-02-03 00:30:34 +00:00
|
|
|
onFinished(finished_callback){
|
|
|
|
this.finished_callback = finished_callback;
|
|
|
|
}
|
|
|
|
/**
|
2021-04-07 21:45:50 +00:00
|
|
|
* private internal method for directing the text move.
|
|
|
|
* It will see how far away we are from the target coords
|
|
|
|
* and move towards the target at the defined speed.
|
|
|
|
*/
|
2021-02-03 00:30:34 +00:00
|
|
|
_doMove(){
|
|
|
|
this.hide();
|
|
|
|
// move closer to the target in the x direction
|
2021-04-07 21:45:50 +00:00
|
|
|
var diff_x = this.tgt_x - this.x;
|
|
|
|
var finished_x = false;
|
2021-02-03 00:30:34 +00:00
|
|
|
if(Math.abs(diff_x) <= this.speed_x){
|
|
|
|
this.x = this.tgt_x;
|
|
|
|
finished_x = true;
|
|
|
|
} else {
|
|
|
|
if(diff_x > 0){
|
|
|
|
this.x += this.speed_x;
|
|
|
|
} else {
|
|
|
|
this.x -= this.speed_x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// move closer to the target in the y direction
|
2021-04-07 21:45:50 +00:00
|
|
|
var diff_y = this.tgt_y - this.y;
|
|
|
|
var finished_y = false;
|
2021-02-03 00:30:34 +00:00
|
|
|
if(Math.abs(diff_y) <= this.speed_y){
|
|
|
|
this.y = this.tgt_y;
|
|
|
|
finished_y = true;
|
|
|
|
} else {
|
|
|
|
if(diff_y > 0){
|
|
|
|
this.y += this.speed_y;
|
|
|
|
} else {
|
|
|
|
this.y -= this.speed_y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.show();
|
2021-02-04 00:29:35 +00:00
|
|
|
this.timeoutId = null;
|
2021-04-07 21:45:50 +00:00
|
|
|
var finished = finished_x & finished_y;
|
2021-02-03 00:30:34 +00:00
|
|
|
if(!finished){
|
2021-02-04 00:29:35 +00:00
|
|
|
this.timeoutId = setTimeout(this._doMove.bind(this), this.freq_millis);
|
2021-02-03 00:30:34 +00:00
|
|
|
} else if(this.finished_callback != null){
|
|
|
|
this.finished_callback.call();
|
|
|
|
this.finished_callback = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-29 21:49:48 +00:00
|
|
|
function bangleVersion(){
|
|
|
|
return (g.getHeight()>200)? 1 : 2;
|
|
|
|
}
|
|
|
|
|
2022-09-29 18:10:26 +00:00
|
|
|
let row_displays;
|
2022-09-29 22:37:42 +00:00
|
|
|
function initDisplay(settings) {
|
2022-09-29 18:10:26 +00:00
|
|
|
if(row_displays != null){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(settings == null){
|
|
|
|
settings = {};
|
|
|
|
}
|
2022-10-09 09:32:09 +00:00
|
|
|
var row_types = {
|
|
|
|
large: {
|
|
|
|
color: 'major',
|
|
|
|
speed: 'medium',
|
|
|
|
angle_to_horizontal: 0,
|
|
|
|
scroll_off: ['left'],
|
|
|
|
scroll_in: ['right'],
|
|
|
|
size: 'large'
|
|
|
|
},
|
|
|
|
medium: {
|
|
|
|
color: 'minor',
|
|
|
|
speed: 'slow',
|
|
|
|
angle_to_horizontal: 0,
|
|
|
|
scroll_off: ['left'],
|
|
|
|
scroll_in: ['right'],
|
|
|
|
size: 'medium'
|
|
|
|
},
|
|
|
|
small: {
|
|
|
|
color: 'minor',
|
|
|
|
speed: 'superslow',
|
|
|
|
angle_to_horizontal: 0,
|
|
|
|
scroll_off: ['left'],
|
|
|
|
scroll_in: ['right'],
|
|
|
|
size: 'small'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
function mergeMaps(map1,map2){
|
|
|
|
if(map2 == null){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Object.keys(map2).forEach(key => {
|
|
|
|
if(map1.hasOwnProperty(key)){
|
|
|
|
map1[key] = mergeObjects(map1[key], map2[key]);
|
|
|
|
} else {
|
|
|
|
map1[key] = map2[key];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function mergeObjects(obj1, obj2){
|
|
|
|
const result = {};
|
|
|
|
Object.keys(obj1).forEach(key => result[key] = (obj2.hasOwnProperty(key))? obj2[key] : obj1[key]);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-10-06 20:20:42 +00:00
|
|
|
const row_type_overide = date_formatter.defaultRowTypes();
|
2022-09-29 18:05:44 +00:00
|
|
|
mergeMaps(row_types,row_type_overide);
|
2022-09-29 18:10:26 +00:00
|
|
|
mergeMaps(row_types,settings.row_types);
|
2022-10-11 20:09:55 +00:00
|
|
|
var row_defs = (settings.row_defs != null && settings.row_defs.length > 0)?
|
2022-09-30 09:37:29 +00:00
|
|
|
settings.row_defs : date_formatter.defaultRowDefs();
|
2022-09-29 18:10:26 +00:00
|
|
|
|
2022-10-09 09:32:09 +00:00
|
|
|
var heights = {
|
|
|
|
vvsmall: [15,13],
|
|
|
|
vsmall: [20,15],
|
|
|
|
ssmall: [22,17],
|
|
|
|
small: [25,20],
|
2022-10-15 12:07:33 +00:00
|
|
|
msmall: [29,22],
|
2022-10-09 09:32:09 +00:00
|
|
|
medium: [40,25],
|
|
|
|
mlarge: [45,35],
|
|
|
|
large: [50,40],
|
2022-10-11 20:09:55 +00:00
|
|
|
vlarge: [60,50],
|
2022-10-11 20:58:18 +00:00
|
|
|
slarge: [110,90]
|
2022-10-09 09:32:09 +00:00
|
|
|
};
|
2022-07-30 15:08:43 +00:00
|
|
|
|
2022-10-09 09:32:09 +00:00
|
|
|
var rotations = {
|
|
|
|
0: 0,
|
|
|
|
90: 3,
|
|
|
|
180: 2,
|
|
|
|
270: 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
var speeds = {
|
|
|
|
fast: 20,
|
|
|
|
medium: 10,
|
|
|
|
slow: 5,
|
|
|
|
vslow: 2,
|
|
|
|
superslow: 1
|
|
|
|
};
|
|
|
|
|
|
|
|
function create_row_type(row_type, row_def){
|
|
|
|
const speed = speeds[row_type.speed];
|
|
|
|
const rotation = rotations[row_type.angle_to_horizontal];
|
|
|
|
const height = heights[row_type.size];
|
|
|
|
const scroll_ins = [];
|
|
|
|
if(row_type.scroll_in.includes('left')){
|
|
|
|
scroll_ins.push((row_display,txt)=> row_display.scrollInFromLeft(txt));
|
|
|
|
}
|
|
|
|
if(row_type.scroll_in.includes('right')){
|
|
|
|
scroll_ins.push((row_display,txt)=> row_display.scrollInFromRight(txt));
|
|
|
|
}
|
|
|
|
if(row_type.scroll_in.includes('up')){
|
|
|
|
scroll_ins.push((row_display,txt)=> row_display.scrollInFromBottom(txt));
|
|
|
|
}
|
|
|
|
var scroll_in;
|
|
|
|
if(scroll_ins.length === 0){
|
|
|
|
scroll_in = (row_display,txt)=> row_display.scrollInFromLeft(txt);
|
|
|
|
} else if(scroll_ins.length === 1){
|
|
|
|
scroll_in = scroll_ins[0];
|
2022-09-29 18:05:44 +00:00
|
|
|
} else {
|
2022-10-09 09:32:09 +00:00
|
|
|
scroll_in = (row_display,txt) =>{
|
|
|
|
const idx = (Math.random() * scroll_ins.length) | 0;
|
|
|
|
return scroll_ins[idx](row_display,txt);
|
|
|
|
};
|
2022-08-10 23:53:05 +00:00
|
|
|
}
|
|
|
|
|
2022-10-09 09:32:09 +00:00
|
|
|
const scroll_offs = [];
|
|
|
|
if(row_type.scroll_off.includes('left')){
|
|
|
|
scroll_offs.push((row_display)=> row_display.scrollOffToLeft());
|
|
|
|
}
|
|
|
|
if(row_type.scroll_off.includes('right')){
|
|
|
|
scroll_offs.push((row_display)=> row_display.scrollOffToRight());
|
|
|
|
}
|
|
|
|
if(row_type.scroll_off.includes('down')){
|
|
|
|
scroll_offs.push((row_display)=> row_display.scrollOffToBottom());
|
|
|
|
}
|
|
|
|
var scroll_off;
|
|
|
|
if(scroll_offs.length === 0){
|
|
|
|
scroll_off = (row_display)=> row_display.scrollOffToLeft();
|
|
|
|
} else if(scroll_offs.length === 1){
|
|
|
|
scroll_off = scroll_offs[0];
|
|
|
|
} else {
|
|
|
|
scroll_off = (row_display) =>{
|
|
|
|
var idx = (Math.random() * scroll_off.length) | 0;
|
|
|
|
return scroll_offs[idx](row_display);
|
|
|
|
};
|
|
|
|
}
|
2022-07-30 21:47:21 +00:00
|
|
|
|
2022-10-09 09:32:09 +00:00
|
|
|
var text_formatter = (txt)=>txt;
|
|
|
|
const SPACES = ' ';
|
|
|
|
if(row_def.hasOwnProperty("alignment")){
|
|
|
|
const alignment = row_def.alignment;
|
|
|
|
if(alignment.startsWith("centre")){
|
|
|
|
const padding = parseInt(alignment.split("-")[1]);
|
|
|
|
if(padding > 0){
|
|
|
|
text_formatter = (txt) => {
|
|
|
|
const front_spaces = (padding - txt.length)/2 | 0;
|
|
|
|
return front_spaces > 0? SPACES.substring(0,front_spaces + 1) + txt : txt;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-09-29 18:05:44 +00:00
|
|
|
|
2022-10-09 09:32:09 +00:00
|
|
|
const version = bangleVersion() - 1;
|
|
|
|
const Y_RESERVED = 20;
|
|
|
|
return {
|
|
|
|
row_speed: speed,
|
|
|
|
row_height: height[version],
|
|
|
|
row_rotation: rotation,
|
|
|
|
x: (row_no) => row_def.init_coords[0] * g.getWidth() + row_def.row_direction[0] * height[version] * row_no,
|
|
|
|
y: (row_no) => Y_RESERVED + row_def.init_coords[1] * (g.getHeight() - Y_RESERVED) + row_def.row_direction[1] * height[version] * row_no,
|
|
|
|
scroll_in: scroll_in,
|
|
|
|
scroll_off: scroll_off,
|
|
|
|
fg_color: () => (row_type.color === 'major')? main_color(): other_color(),
|
|
|
|
row_text_formatter : text_formatter
|
2022-09-29 18:05:44 +00:00
|
|
|
};
|
|
|
|
}
|
2022-10-09 09:32:09 +00:00
|
|
|
row_displays = [];
|
|
|
|
row_defs.forEach(row_def =>{
|
|
|
|
const row_type = create_row_type(row_types[row_def.type],row_def);
|
|
|
|
// we now create the number of rows specified of that type
|
|
|
|
for(var row_no=0; row_no<row_def.rows; row_no++){
|
|
|
|
row_displays.push(new ShiftText(row_type.x(row_no),
|
|
|
|
row_type.y(row_no),
|
|
|
|
'',
|
|
|
|
"Vector",
|
|
|
|
row_type.row_height,
|
|
|
|
row_type.row_speed,
|
|
|
|
row_type.row_speed,
|
|
|
|
10,
|
|
|
|
row_type.fg_color(),
|
|
|
|
bg_color(),
|
|
|
|
row_type,
|
|
|
|
row_type.row_rotation
|
|
|
|
)
|
|
|
|
);
|
2022-10-02 19:45:30 +00:00
|
|
|
}
|
2022-10-09 09:32:09 +00:00
|
|
|
});
|
|
|
|
// dereference the setup variables to release the memory
|
2022-10-11 20:09:55 +00:00
|
|
|
row_defs = null;
|
2022-10-08 18:57:32 +00:00
|
|
|
row_types = null;
|
|
|
|
heights = null;
|
2022-10-09 09:32:09 +00:00
|
|
|
rotations = null;
|
|
|
|
speeds = null;
|
2021-09-29 08:19:43 +00:00
|
|
|
}
|
2022-06-27 17:04:45 +00:00
|
|
|
|
2021-04-07 21:45:50 +00:00
|
|
|
function nextColorTheme(){
|
|
|
|
color_scheme_index += 1;
|
2022-07-29 21:49:48 +00:00
|
|
|
if(color_scheme_index >= color_schemes.length){
|
2021-04-07 21:45:50 +00:00
|
|
|
color_scheme_index = 0;
|
2021-02-04 00:29:35 +00:00
|
|
|
}
|
2022-07-29 21:49:48 +00:00
|
|
|
updateColorScheme();
|
2022-09-29 22:37:42 +00:00
|
|
|
resetClock(true);
|
|
|
|
drawClock();
|
2021-04-19 11:05:50 +00:00
|
|
|
}
|
|
|
|
|
2022-07-29 21:49:48 +00:00
|
|
|
function updateColorScheme(){
|
2022-10-06 20:20:42 +00:00
|
|
|
const bgcolor = bg_color();
|
2022-07-29 21:49:48 +00:00
|
|
|
for(var i=0; i<row_displays.length; i++){
|
2022-09-29 18:05:44 +00:00
|
|
|
row_displays[i].setColor(row_displays[i].getRowContext().fg_color());
|
2022-07-29 21:49:48 +00:00
|
|
|
row_displays[i].setBgColor(bgcolor);
|
|
|
|
}
|
|
|
|
g.setColor(bgcolor[0],bgcolor[1],bgcolor[2]);
|
|
|
|
g.fillRect(0, 24, g.getWidth(), g.getHeight());
|
2021-02-09 07:22:12 +00:00
|
|
|
}
|
|
|
|
|
2022-09-29 22:37:42 +00:00
|
|
|
function resetClock(hard_reset){
|
2021-04-18 08:31:25 +00:00
|
|
|
console.log("reset_clock hard_reset:" + hard_reset);
|
|
|
|
|
2022-07-29 21:49:48 +00:00
|
|
|
updateColorScheme();
|
2021-04-18 08:31:25 +00:00
|
|
|
if(!hard_reset && last_draw_time != null){
|
|
|
|
// If its not a hard reset then we want to reset the
|
|
|
|
// rows set to the last time. If the last time is too long
|
|
|
|
// ago then we fast forward to 1 min ago.
|
|
|
|
// In this way the watch wakes by scrolling
|
|
|
|
// off the last time and scroll on the new time
|
|
|
|
var reset_time = last_draw_time;
|
2022-10-06 20:20:42 +00:00
|
|
|
const last_minute_millis = Date.now() - 60000;
|
2021-04-18 08:31:25 +00:00
|
|
|
if(reset_time.getTime() < last_minute_millis){
|
2021-04-19 11:05:50 +00:00
|
|
|
reset_time = display_time(new Date(last_minute_millis));
|
2021-04-18 08:31:25 +00:00
|
|
|
}
|
2022-10-06 20:20:42 +00:00
|
|
|
const rows = date_formatter.formatDate(reset_time);
|
2021-04-18 08:31:25 +00:00
|
|
|
for (var i = 0; i < rows.length; i++) {
|
|
|
|
row_displays[i].hide();
|
2022-07-30 15:08:43 +00:00
|
|
|
row_displays[i].x = row_displays[i].init_x;
|
2021-04-18 08:31:25 +00:00
|
|
|
row_displays[i].y = row_displays[i].init_y;
|
|
|
|
if(row_displays[i].timeoutId != null){
|
|
|
|
clearTimeout(row_displays[i].timeoutId);
|
|
|
|
}
|
|
|
|
row_displays[i].setText(rows[i]);
|
|
|
|
row_displays[i].show();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// do a hard reset and clear everything out
|
2022-09-29 18:10:26 +00:00
|
|
|
row_displays.forEach(row_display => row_display.reset(hard_reset));
|
2021-02-04 01:39:43 +00:00
|
|
|
}
|
2021-04-07 21:45:50 +00:00
|
|
|
reset_commands();
|
2021-02-04 00:29:35 +00:00
|
|
|
}
|
2021-02-01 02:16:56 +00:00
|
|
|
|
2021-04-07 21:45:50 +00:00
|
|
|
let last_draw_time = null;
|
2021-04-19 11:05:50 +00:00
|
|
|
const next_minute_boundary_secs = 10;
|
|
|
|
|
|
|
|
function display_time(date){
|
|
|
|
if(date.getSeconds() > 60 - next_minute_boundary_secs){
|
|
|
|
console.log("forwarding to next minute");
|
|
|
|
return new Date(date.getTime() + next_minute_boundary_secs * 1000);
|
|
|
|
} else {
|
|
|
|
return date;
|
|
|
|
}
|
|
|
|
}
|
2021-04-07 21:45:50 +00:00
|
|
|
|
2022-09-29 22:37:42 +00:00
|
|
|
function drawClock(){
|
2021-04-07 21:45:50 +00:00
|
|
|
var date = new Date();
|
2021-04-19 11:05:50 +00:00
|
|
|
|
|
|
|
// we don't want the time to be displayed
|
|
|
|
// and then immediately be trigger another time
|
2021-04-07 21:45:50 +00:00
|
|
|
if(last_draw_time != null &&
|
2022-10-05 15:28:33 +00:00
|
|
|
date.getTime() - last_draw_time.getTime() < next_minute_boundary_secs * 1000 &&
|
2021-04-07 21:45:50 +00:00
|
|
|
has_commands() ){
|
|
|
|
console.log("skipping draw clock");
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
last_draw_time = date;
|
|
|
|
}
|
|
|
|
reset_commands();
|
2021-04-19 11:05:50 +00:00
|
|
|
date = display_time(date);
|
2022-10-08 20:46:00 +00:00
|
|
|
const mem = process.memory(false);
|
|
|
|
console.log("draw_clock:" + last_draw_time.toISOString() + " display:" + date.toISOString() +
|
|
|
|
" memory:" + mem.usage / mem.total);
|
2022-06-27 17:04:45 +00:00
|
|
|
|
2022-10-05 15:28:33 +00:00
|
|
|
const rows = date_formatter.formatDate(date);
|
2021-04-07 21:45:50 +00:00
|
|
|
for (var i = 0; i < rows.length; i++) {
|
2022-10-05 15:28:33 +00:00
|
|
|
const display = row_displays[i];
|
|
|
|
if(display != null){
|
|
|
|
const txt = display.getRowContext().row_text_formatter(rows[i]);
|
|
|
|
display_row(display,txt);
|
|
|
|
}
|
2021-02-04 00:29:35 +00:00
|
|
|
}
|
2021-04-07 21:45:50 +00:00
|
|
|
// If the dateformatter has not returned enough
|
2022-07-26 23:01:56 +00:00
|
|
|
// rows then treat the remaining rows as empty
|
2021-04-11 14:18:30 +00:00
|
|
|
for (var j = i; j < row_displays.length; j++) {
|
2022-10-05 15:28:33 +00:00
|
|
|
const display = row_displays[j];
|
2021-02-11 22:54:53 +00:00
|
|
|
display_row(display,'');
|
|
|
|
}
|
2021-04-07 21:45:50 +00:00
|
|
|
next_command();
|
2021-02-04 00:29:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function display_row(display,txt){
|
2021-04-11 14:18:30 +00:00
|
|
|
if(display == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-07-26 23:01:56 +00:00
|
|
|
if(display.txt == null || display.txt === ''){
|
|
|
|
if(txt !== '') {
|
2022-09-30 13:07:43 +00:00
|
|
|
command_stack_high_priority.unshift(()=>{
|
2021-04-09 22:33:21 +00:00
|
|
|
display.onFinished(next_command);
|
2022-09-29 18:05:44 +00:00
|
|
|
display.getRowContext().scroll_in(display,txt);
|
2021-04-09 22:33:21 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
2022-07-26 23:01:56 +00:00
|
|
|
} else if(txt !== display.txt && display.txt != null){
|
2022-09-30 13:07:43 +00:00
|
|
|
command_stack_high_priority.push(()=>{
|
2021-04-07 21:45:50 +00:00
|
|
|
display.onFinished(next_command);
|
2022-09-29 18:05:44 +00:00
|
|
|
display.getRowContext().scroll_off(display);
|
2021-04-07 21:45:50 +00:00
|
|
|
}
|
|
|
|
);
|
2022-09-30 13:07:43 +00:00
|
|
|
command_stack_low_priority.push(() => {
|
2021-04-07 21:45:50 +00:00
|
|
|
display.onFinished(next_command);
|
2022-09-29 18:05:44 +00:00
|
|
|
display.getRowContext().scroll_in(display,txt);
|
2021-04-07 21:45:50 +00:00
|
|
|
}
|
2021-02-03 00:30:34 +00:00
|
|
|
);
|
|
|
|
} else {
|
2022-09-30 13:07:43 +00:00
|
|
|
command_stack_high_priority.push(() => {
|
2022-07-30 15:08:43 +00:00
|
|
|
display.setTextPosition(txt,display.init_x, display.init_y);
|
2021-04-07 21:45:50 +00:00
|
|
|
next_command();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* called from load_settings on startup to
|
|
|
|
* set the color scheme to named value
|
|
|
|
*/
|
2022-09-29 22:37:42 +00:00
|
|
|
function setColorScheme(colorscheme_name){
|
2021-04-07 21:45:50 +00:00
|
|
|
console.log("setting color scheme:" + colorscheme_name);
|
|
|
|
for (var i=0; i < color_schemes.length; i++) {
|
2022-07-26 23:01:56 +00:00
|
|
|
if(color_schemes[i].name === colorscheme_name){
|
2021-04-07 21:45:50 +00:00
|
|
|
color_scheme_index = i;
|
2022-07-29 21:49:48 +00:00
|
|
|
updateColorScheme();
|
2021-04-07 21:45:50 +00:00
|
|
|
break;
|
|
|
|
}
|
2021-02-01 02:16:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-09 09:32:09 +00:00
|
|
|
var date_formatter;
|
|
|
|
function setDateformat(shortname){
|
|
|
|
/**
|
|
|
|
* Demonstration Date formatter so that we can see the
|
|
|
|
* clock working in the emulator
|
|
|
|
*/
|
|
|
|
class DigitDateTimeFormatter {
|
|
|
|
constructor() {}
|
|
|
|
|
|
|
|
format00(num){
|
|
|
|
const value = (num | 0);
|
|
|
|
if(value > 99 || value < 0)
|
|
|
|
throw "must be between in range 0-99";
|
|
|
|
if(value < 10)
|
|
|
|
return "0" + value.toString();
|
|
|
|
else
|
|
|
|
return value.toString();
|
|
|
|
}
|
2022-10-08 20:46:00 +00:00
|
|
|
|
2022-10-09 09:32:09 +00:00
|
|
|
formatDate(now){
|
|
|
|
const hours = now.getHours() ;
|
|
|
|
const time_txt = this.format00(hours) + ":" + this.format00(now.getMinutes());
|
|
|
|
const date_txt = require('locale').dow(now,1) + " " + this.format00(now.getDate());
|
|
|
|
const month_txt = require('locale').month(now);
|
|
|
|
return [time_txt, date_txt, month_txt];
|
|
|
|
}
|
2022-10-08 20:46:00 +00:00
|
|
|
|
2022-10-09 09:32:09 +00:00
|
|
|
defaultRowTypes(){
|
|
|
|
return {
|
|
|
|
large: {
|
|
|
|
scroll_off: ['left', 'right', 'down'],
|
|
|
|
scroll_in: ['left', 'right', 'up'],
|
|
|
|
size: 'vlarge'
|
|
|
|
},
|
|
|
|
small: {
|
|
|
|
angle_to_horizontal: 90,
|
|
|
|
scroll_off: ['down'],
|
|
|
|
scroll_in: ['up'],
|
|
|
|
size: 'vvsmall'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2022-09-29 18:05:44 +00:00
|
|
|
|
2022-10-09 09:32:09 +00:00
|
|
|
defaultRowDefs() {
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
type: 'large',
|
|
|
|
row_direction: [0.0,1.0],
|
|
|
|
init_coords: [0.1,0.35],
|
|
|
|
rows: 1
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'small',
|
|
|
|
row_direction: [1.0,0],
|
|
|
|
init_coords: [0.85,0.99],
|
|
|
|
rows: 2
|
|
|
|
}
|
|
|
|
];
|
|
|
|
}
|
2022-07-30 09:53:21 +00:00
|
|
|
}
|
2022-07-26 23:01:56 +00:00
|
|
|
console.log("setting date format:" + shortname);
|
|
|
|
try {
|
2022-10-08 00:45:14 +00:00
|
|
|
if (date_formatter == null) {
|
2022-10-02 00:05:17 +00:00
|
|
|
if(shortname === "default"){
|
|
|
|
date_formatter = new DigitDateTimeFormatter();
|
|
|
|
} else {
|
2022-10-06 20:20:42 +00:00
|
|
|
const date_formatter_class = require("slidingtext.locale." + shortname + ".js");
|
2022-10-02 00:05:17 +00:00
|
|
|
date_formatter = new date_formatter_class();
|
|
|
|
}
|
2021-04-07 21:45:50 +00:00
|
|
|
}
|
2022-07-26 23:01:56 +00:00
|
|
|
} catch(e){
|
2022-10-09 09:32:09 +00:00
|
|
|
console.log("not loaded:" + shortname);
|
2021-04-07 21:45:50 +00:00
|
|
|
}
|
2022-07-31 22:42:09 +00:00
|
|
|
if(date_formatter == null){
|
|
|
|
date_formatter = new DigitDateTimeFormatter();
|
|
|
|
}
|
2021-04-07 21:45:50 +00:00
|
|
|
}
|
|
|
|
|
2022-06-27 17:04:45 +00:00
|
|
|
var enable_live_controls = false;
|
2021-04-07 21:45:50 +00:00
|
|
|
const PREFERENCE_FILE = "slidingtext.settings.json";
|
|
|
|
/**
|
|
|
|
* Called on startup to set the watch to the last preference settings
|
|
|
|
*/
|
2022-09-29 22:37:42 +00:00
|
|
|
function loadSettings() {
|
2022-07-26 23:01:56 +00:00
|
|
|
try {
|
2022-10-06 20:20:42 +00:00
|
|
|
const settings = Object.assign({},
|
2022-09-30 08:13:58 +00:00
|
|
|
require('Storage').readJSON(PREFERENCE_FILE, true) || {});
|
|
|
|
if (settings.date_formatter == null) {
|
|
|
|
settings.date_formatter = "en";
|
2022-09-30 00:34:40 +00:00
|
|
|
}
|
|
|
|
console.log("loaded settings:" + JSON.stringify(settings));
|
|
|
|
setDateformat(settings.date_formatter);
|
|
|
|
initDisplay(settings);
|
|
|
|
if (settings.color_scheme != null) {
|
2022-09-30 10:55:02 +00:00
|
|
|
setColorScheme(settings.color_scheme);
|
2022-10-09 10:28:38 +00:00
|
|
|
} else {
|
|
|
|
setColorScheme("black");
|
2022-09-30 00:34:40 +00:00
|
|
|
}
|
|
|
|
if (settings.enable_live_controls == null) {
|
2022-09-30 10:55:02 +00:00
|
|
|
settings.enable_live_controls = (bangleVersion() <= 1);
|
2021-04-07 21:45:50 +00:00
|
|
|
}
|
2022-09-30 00:34:40 +00:00
|
|
|
enable_live_controls = settings.enable_live_controls;
|
2022-07-01 18:51:00 +00:00
|
|
|
console.log("enable_live_controls=" + enable_live_controls);
|
2022-07-26 23:01:56 +00:00
|
|
|
} catch (e) {
|
2021-04-07 21:45:50 +00:00
|
|
|
console.log("failed to load settings:" + e);
|
|
|
|
}
|
2021-09-29 08:19:43 +00:00
|
|
|
// just set up as default
|
2022-09-29 22:37:42 +00:00
|
|
|
if (row_displays === undefined) {
|
|
|
|
setDateformat("default");
|
|
|
|
initDisplay();
|
2022-07-29 21:49:48 +00:00
|
|
|
updateColorScheme();
|
2022-07-26 23:01:56 +00:00
|
|
|
}
|
2022-10-09 09:32:09 +00:00
|
|
|
const mem = process.memory(true);
|
|
|
|
console.log("init complete memory:" + mem.usage / mem.total);
|
2021-04-07 21:45:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function button3pressed() {
|
2022-06-27 17:04:45 +00:00
|
|
|
if (enable_live_controls) {
|
|
|
|
nextColorTheme();
|
2022-09-29 22:37:42 +00:00
|
|
|
resetClock(true);
|
|
|
|
drawClock();
|
2022-06-27 17:04:45 +00:00
|
|
|
}
|
2021-04-07 21:45:50 +00:00
|
|
|
}
|
|
|
|
|
2021-02-06 00:36:22 +00:00
|
|
|
// The interval reference for updating the clock
|
|
|
|
let intervalRef = null;
|
|
|
|
|
2021-02-01 02:16:56 +00:00
|
|
|
function clearTimers(){
|
2021-04-18 08:31:25 +00:00
|
|
|
if(intervalRef != null) {
|
2021-02-01 02:16:56 +00:00
|
|
|
clearInterval(intervalRef);
|
|
|
|
intervalRef = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function startTimers(){
|
2022-10-06 20:20:42 +00:00
|
|
|
const date = new Date();
|
|
|
|
const secs = date.getSeconds();
|
|
|
|
const nextMinuteStart = 60 - secs;
|
2021-02-01 02:16:56 +00:00
|
|
|
setTimeout(scheduleDrawClock,nextMinuteStart * 1000);
|
2022-09-29 22:37:42 +00:00
|
|
|
drawClock();
|
2021-02-01 02:16:56 +00:00
|
|
|
}
|
|
|
|
|
2021-04-19 11:05:50 +00:00
|
|
|
/**
|
|
|
|
* confirms that a redraw is needed by checking the last redraw time and
|
|
|
|
* the lcd state of the UI
|
|
|
|
* @returns {boolean|*}
|
|
|
|
*/
|
|
|
|
function shouldRedraw(){
|
|
|
|
return last_draw_time != null &&
|
|
|
|
Date.now() - last_draw_time.getTime() > next_minute_boundary_secs * 1000
|
|
|
|
&& Bangle.isLCDOn();
|
|
|
|
}
|
|
|
|
|
2021-02-03 00:30:34 +00:00
|
|
|
function scheduleDrawClock(){
|
2021-04-18 08:31:25 +00:00
|
|
|
clearTimers();
|
|
|
|
if (Bangle.isLCDOn()) {
|
2021-04-19 11:05:50 +00:00
|
|
|
console.log("schedule draw of clock");
|
2021-04-18 08:31:25 +00:00
|
|
|
intervalRef = setInterval(() => {
|
2022-07-29 21:49:48 +00:00
|
|
|
if (!shouldRedraw()) {
|
|
|
|
console.log("draw clock callback - skipped redraw");
|
|
|
|
} else {
|
|
|
|
console.log("draw clock callback");
|
2022-09-29 22:37:42 +00:00
|
|
|
drawClock();
|
2022-07-29 21:49:48 +00:00
|
|
|
}
|
|
|
|
}, 60 * 1000
|
2021-04-19 11:05:50 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
if (shouldRedraw()) {
|
2022-09-29 22:37:42 +00:00
|
|
|
drawClock();
|
2021-04-19 11:05:50 +00:00
|
|
|
} else {
|
|
|
|
console.log("scheduleDrawClock - skipped redraw");
|
|
|
|
}
|
2021-04-18 08:31:25 +00:00
|
|
|
} else {
|
|
|
|
console.log("scheduleDrawClock - skipped not visible");
|
|
|
|
}
|
2021-02-01 02:16:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Bangle.on('lcdPower', (on) => {
|
|
|
|
if (on) {
|
|
|
|
console.log("lcdPower: on");
|
|
|
|
Bangle.drawWidgets();
|
2022-09-29 22:37:42 +00:00
|
|
|
resetClock(false);
|
2021-02-01 02:16:56 +00:00
|
|
|
startTimers();
|
|
|
|
} else {
|
|
|
|
console.log("lcdPower: off");
|
2022-09-29 22:37:42 +00:00
|
|
|
resetClock(false);
|
2021-02-01 02:16:56 +00:00
|
|
|
clearTimers();
|
|
|
|
}
|
|
|
|
});
|
2021-04-07 21:45:50 +00:00
|
|
|
|
2021-02-01 02:16:56 +00:00
|
|
|
g.clear();
|
2022-09-29 22:37:42 +00:00
|
|
|
loadSettings();
|
2021-07-28 08:55:22 +00:00
|
|
|
// Show launcher when button pressed
|
2021-09-29 08:19:43 +00:00
|
|
|
Bangle.setUI("clockupdown", d=>{
|
|
|
|
if (d>0) button3pressed();
|
|
|
|
});
|
2022-09-06 22:57:47 +00:00
|
|
|
Bangle.loadWidgets();
|
|
|
|
Bangle.drawWidgets();
|
|
|
|
|
|
|
|
startTimers();
|
|
|
|
|