Matrix Clock Update: Matrix clock currently only works with the black theme, we extend to other themes
- setting panel is added so the colour scheme can be selectedmaster
parent
970c344c11
commit
c8059ce006
|
|
@ -1,4 +1,5 @@
|
||||||
0.01: Initial Release
|
0.01: Initial Release
|
||||||
0.02: Support for Bangle 2
|
0.02: Support for Bangle 2
|
||||||
0.03: Keep the date from being overwritten, use correct colour from theme for clearing
|
0.03: Keep the date from being overwritten, use correct colour from theme for clearing
|
||||||
0.04: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up".
|
0.04: Removed "wake LCD on face-up"-feature: A watch-face should not set things like "wake LCD on face-up".
|
||||||
|
0.05: Added support to other color themes (other then black)
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,82 @@
|
||||||
*
|
*
|
||||||
* Matrix Clock
|
* Matrix Clock
|
||||||
*
|
*
|
||||||
* A simple clock inspired by the movie.
|
* A simple clock inspired by the movie.
|
||||||
* Text shards move down the screen as a background to the
|
* Text shards move down the screen as a background to the
|
||||||
* time and date
|
* time and date
|
||||||
**/
|
**/
|
||||||
const Locale = require('locale');
|
const Locale = require('locale');
|
||||||
|
|
||||||
const SHARD_COLOR =[0,1.0,0];
|
const PREFERENCE_FILE = "matrixclock.settings.json";
|
||||||
|
const settings = Object.assign({'color': 'theme'},
|
||||||
|
require('Storage').readJSON(PREFERENCE_FILE, true) || {});
|
||||||
|
|
||||||
|
const colors = {
|
||||||
|
'green': [0,1.0,0],
|
||||||
|
'red' : [1.0,0.0,0.0],
|
||||||
|
'blue' : [0.0,0.0,1.0],
|
||||||
|
'black': [0.0,0.0,0.0],
|
||||||
|
'white': [1.0,1.0,1.0],
|
||||||
|
'yellow': [1.0,1.0,0.0],
|
||||||
|
'purple': [1.0,0.0,1.0]
|
||||||
|
};
|
||||||
|
|
||||||
|
const bg2fg_color = {
|
||||||
|
'green' : 'white',
|
||||||
|
'red' : 'white',
|
||||||
|
'blue': 'white',
|
||||||
|
'black' : 'green',
|
||||||
|
'white': 'black',
|
||||||
|
'yellow': 'black',
|
||||||
|
'purple': 'yellow'
|
||||||
|
};
|
||||||
|
|
||||||
|
function int2Color(color_int){
|
||||||
|
var blue_int = color_int & 31;
|
||||||
|
var blue = (blue_int)/31.0;
|
||||||
|
|
||||||
|
var green_int = (color_int >> 5) & 31;
|
||||||
|
var green = (green_int)/31.0;
|
||||||
|
|
||||||
|
var red_int = (color_int >> 11) & 31;
|
||||||
|
var red = red_int/ 31.0;
|
||||||
|
return [red,green,blue];
|
||||||
|
}
|
||||||
|
|
||||||
|
var fg_color = colors.black;
|
||||||
|
var bg_color = colors.white;
|
||||||
|
|
||||||
|
// now lets deal with the settings
|
||||||
|
if(settings.color == "theme"){
|
||||||
|
bg_color = int2Color(g.theme.bg);
|
||||||
|
if(g.theme.bg == 0) {
|
||||||
|
fg_color = colors.green;
|
||||||
|
} else {
|
||||||
|
fg_color = int2Color(g.theme.fg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bg_color = colors[settings.color];
|
||||||
|
fg_color = colors[bg2fg_color[settings.color]];
|
||||||
|
g.setBgColor(bg_color[0],bg_color[1],bg_color[2]);
|
||||||
|
}
|
||||||
|
if(fg_color == undefined)
|
||||||
|
fg_color = colors.black;
|
||||||
|
|
||||||
|
if(bg_color == undefined)
|
||||||
|
bg_color = colors.white;
|
||||||
|
|
||||||
const SHARD_FONT_SIZE = 12;
|
const SHARD_FONT_SIZE = 12;
|
||||||
const SHARD_Y_START = 30;
|
const SHARD_Y_START = 30;
|
||||||
|
|
||||||
const w = g.getWidth();
|
const w = g.getWidth();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The text shard object is responsible for creating the
|
* The text shard object is responsible for creating the
|
||||||
* shards of text that move down the screen. As the
|
* shards of text that move down the screen. As the
|
||||||
* shard moves down the screen the latest character added
|
* shard moves down the screen the latest character added
|
||||||
* is brightest with characters being coloured darker and darker
|
* is brightest with characters being coloured darker and darker
|
||||||
* going back to the eldest
|
* going back to the eldest
|
||||||
*/
|
*/
|
||||||
class TextShard {
|
class TextShard {
|
||||||
|
|
||||||
constructor(x,y,length){
|
constructor(x,y,length){
|
||||||
|
|
@ -34,44 +92,46 @@ class TextShard {
|
||||||
this.txt = [];
|
this.txt = [];
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* The add method call adds another random character to
|
* The add method call adds another random character to
|
||||||
* the chain
|
* the chain
|
||||||
*/
|
*/
|
||||||
add(){
|
add(){
|
||||||
this.txt.push(randomChar());
|
this.txt.push(randomChar());
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* The show method displays the latest shard image to the
|
* The show method displays the latest shard image to the
|
||||||
* screen with the following rules:
|
* screen with the following rules:
|
||||||
* - latest addition is brightest, oldest is darker
|
* - latest addition is brightest, oldest is darker
|
||||||
* - display up to defined length of characters only
|
* - display up to defined length of characters only
|
||||||
* of the shard to save cpu
|
* of the shard to save cpu
|
||||||
*/
|
*/
|
||||||
show(){
|
show(){
|
||||||
g.setFontAlign(-1,-1,0);
|
g.setFontAlign(-1,-1,0);
|
||||||
for(var i=0; i<Math.min(this.txt.length, this.length + 1) ; i++){
|
for(var i=0; i<Math.min(this.txt.length, this.length + 1) ; i++){
|
||||||
idx = this.txt.length - i - 1;
|
var idx = this.txt.length - i - 1;
|
||||||
var color_strength=1 - i/this.length;
|
var color_strength=1 - i/this.length;
|
||||||
if(i > this.length - 2){
|
if(i > this.length - 2){
|
||||||
color_strength = 0;
|
color_strength = 0;
|
||||||
}
|
}
|
||||||
g.setColor(color_strength*SHARD_COLOR[0],
|
var bg_color_strength = 1 - color_strength;
|
||||||
color_strength*SHARD_COLOR[1],
|
g.setColor(Math.abs(color_strength*fg_color[0] - bg_color_strength*bg_color[0]),
|
||||||
color_strength*SHARD_COLOR[2]);
|
Math.abs(color_strength*fg_color[1] - bg_color_strength*bg_color[1]),
|
||||||
|
Math.abs(color_strength*fg_color[2] - bg_color_strength*bg_color[2])
|
||||||
|
);
|
||||||
g.setFont("Vector",SHARD_FONT_SIZE);
|
g.setFont("Vector",SHARD_FONT_SIZE);
|
||||||
g.drawString(this.txt[idx], this.x, this.y + idx*SHARD_FONT_SIZE);
|
g.drawString(this.txt[idx], this.x, this.y + idx*SHARD_FONT_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Method tests to see if any part of the shard chain is still
|
* Method tests to see if any part of the shard chain is still
|
||||||
* visible on the screen
|
* visible on the screen
|
||||||
*/
|
*/
|
||||||
isVisible(){
|
isVisible(){
|
||||||
return (this.y + (this.txt.length - this.length - 2)*SHARD_FONT_SIZE < g.getHeight());
|
return (this.y + (this.txt.length - this.length - 2)*SHARD_FONT_SIZE < g.getHeight());
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* resets the shard back to the top of the screen
|
* resets the shard back to the top of the screen
|
||||||
*/
|
*/
|
||||||
reset(){
|
reset(){
|
||||||
this.y = SHARD_Y_START;
|
this.y = SHARD_Y_START;
|
||||||
this.txt = [];
|
this.txt = [];
|
||||||
|
|
@ -79,8 +139,8 @@ class TextShard {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* random character chooser to be called by the shard when adding characters
|
* random character chooser to be called by the shard when adding characters
|
||||||
*/
|
*/
|
||||||
const CHAR_CODE_START = 33;
|
const CHAR_CODE_START = 33;
|
||||||
const CHAR_CODE_LAST = 126;
|
const CHAR_CODE_LAST = 126;
|
||||||
const CHAR_CODE_LENGTH = CHAR_CODE_LAST - CHAR_CODE_START;
|
const CHAR_CODE_LENGTH = CHAR_CODE_LAST - CHAR_CODE_START;
|
||||||
|
|
@ -90,7 +150,7 @@ function randomChar(){
|
||||||
|
|
||||||
// Now set up the shards
|
// Now set up the shards
|
||||||
// we are going to have a limited no of shards (to save cpu)
|
// we are going to have a limited no of shards (to save cpu)
|
||||||
// but randomize the x value and length every reset to make it look as if there
|
// but randomize the x value and length every reset to make it look as if there
|
||||||
// are more
|
// are more
|
||||||
var shards = [];
|
var shards = [];
|
||||||
const NO_SHARDS = 3;
|
const NO_SHARDS = 3;
|
||||||
|
|
@ -112,14 +172,13 @@ var timeStr = "";
|
||||||
var dateStr = "";
|
var dateStr = "";
|
||||||
var last_draw_time = null;
|
var last_draw_time = null;
|
||||||
|
|
||||||
const TIME_X_COORD = 20;
|
|
||||||
const TIME_Y_COORD = g.getHeight() / 2;
|
const TIME_Y_COORD = g.getHeight() / 2;
|
||||||
const DATE_X_COORD = 170;
|
const DATE_X_COORD = 170;
|
||||||
const DATE_Y_COORD = 30;
|
const DATE_Y_COORD = 30;
|
||||||
const RESET_PROBABILITY = 0.5;
|
const RESET_PROBABILITY = 0.5;
|
||||||
/**
|
/**
|
||||||
* main loop to draw the clock face
|
* main loop to draw the clock face
|
||||||
*/
|
*/
|
||||||
function draw_clock(){
|
function draw_clock(){
|
||||||
// first move all the shards down the screen
|
// first move all the shards down the screen
|
||||||
for(var i=0; i<this.shards.length; i++){
|
for(var i=0; i<this.shards.length; i++){
|
||||||
|
|
@ -147,22 +206,22 @@ function draw_clock(){
|
||||||
g.setFont("Vector", g.getWidth() / 5);
|
g.setFont("Vector", g.getWidth() / 5);
|
||||||
g.setFontAlign(0,-1);
|
g.setFontAlign(0,-1);
|
||||||
if(last_draw_time == null || now.getMinutes() != last_draw_time.getMinutes()){
|
if(last_draw_time == null || now.getMinutes() != last_draw_time.getMinutes()){
|
||||||
g.setColor(g.theme.bg);
|
g.setColor(bg_color[0],bg_color[1],bg_color[2]);
|
||||||
g.drawString(timeStr, w/2, TIME_Y_COORD);
|
g.drawString(timeStr, w/2, TIME_Y_COORD);
|
||||||
timeStr = format_time(now);
|
timeStr = format_time(now);
|
||||||
}
|
}
|
||||||
g.setColor(SHARD_COLOR[0], SHARD_COLOR[1], SHARD_COLOR[2]);
|
g.setColor(fg_color[0], fg_color[1], fg_color[2]);
|
||||||
g.drawString(timeStr, w/2, TIME_Y_COORD);
|
g.drawString(timeStr, w/2, TIME_Y_COORD);
|
||||||
//
|
//
|
||||||
// draw date when it changes
|
// draw date when it changes
|
||||||
g.setFont("Vector",15);
|
g.setFont("Vector",15);
|
||||||
g.setFontAlign(0,-1,0);
|
g.setFontAlign(0,-1,0);
|
||||||
if(last_draw_time == null || now.getDate() != last_draw_time.getDate()){
|
if(last_draw_time == null || now.getDate() != last_draw_time.getDate()){
|
||||||
g.setColor(g.theme.bg);
|
g.setColor(bg_color[0],bg_color[1],bg_color[2]);
|
||||||
g.drawString(dateStr, w/2, DATE_Y_COORD);
|
g.drawString(dateStr, w/2, DATE_Y_COORD);
|
||||||
dateStr = format_date(now);
|
dateStr = format_date(now);
|
||||||
}
|
}
|
||||||
g.setColor(SHARD_COLOR[0], SHARD_COLOR[1], SHARD_COLOR[2]);
|
g.setColor(fg_color[0], fg_color[1], fg_color[2]);
|
||||||
g.drawString(dateStr, w/2, DATE_Y_COORD);
|
g.drawString(dateStr, w/2, DATE_Y_COORD);
|
||||||
last_draw_time = now;
|
last_draw_time = now;
|
||||||
}
|
}
|
||||||
|
|
@ -180,7 +239,7 @@ function format_time(now){
|
||||||
}
|
}
|
||||||
var am_pm;
|
var am_pm;
|
||||||
if(time.getHours() < 12){
|
if(time.getHours() < 12){
|
||||||
am_pm = "AM";
|
am_pm = "AM";
|
||||||
} else {
|
} else {
|
||||||
am_pm = "PM";
|
am_pm = "PM";
|
||||||
}
|
}
|
||||||
|
|
@ -188,13 +247,13 @@ function format_time(now){
|
||||||
}
|
}
|
||||||
|
|
||||||
function format00(num){
|
function format00(num){
|
||||||
var value = (num | 0);
|
var value = (num | 0);
|
||||||
if(value > 99 || value < 0)
|
if(value > 99 || value < 0)
|
||||||
throw "must be between in range 0-99";
|
throw "must be between in range 0-99";
|
||||||
if(value < 10)
|
if(value < 10)
|
||||||
return "0" + value.toString();
|
return "0" + value.toString();
|
||||||
else
|
else
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The interval reference for updating the clock
|
// The interval reference for updating the clock
|
||||||
|
|
@ -215,12 +274,12 @@ function startTimers(){
|
||||||
clearTimers();
|
clearTimers();
|
||||||
if (Bangle.isLCDOn()) {
|
if (Bangle.isLCDOn()) {
|
||||||
intervalRef = setInterval(() => {
|
intervalRef = setInterval(() => {
|
||||||
if (!shouldRedraw()) {
|
if (!shouldRedraw()) {
|
||||||
//console.log("draw clock callback - skipped redraw");
|
//console.log("draw clock callback - skipped redraw");
|
||||||
} else {
|
} else {
|
||||||
draw_clock();
|
draw_clock();
|
||||||
}
|
}
|
||||||
}, 100
|
}, 100
|
||||||
);
|
);
|
||||||
draw_clock();
|
draw_clock();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
(function(back) {
|
||||||
|
const PREFERENCE_FILE = "matrixclock.settings.json";
|
||||||
|
var settings = Object.assign({color_scheme : "theme"},
|
||||||
|
require('Storage').readJSON(PREFERENCE_FILE, true) || {});
|
||||||
|
|
||||||
|
console.log("loaded:" + JSON.stringify(settings));
|
||||||
|
|
||||||
|
function writeSettings() {
|
||||||
|
console.log("saving:" + JSON.stringify(settings));
|
||||||
|
require('Storage').writeJSON(PREFERENCE_FILE, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method which uses int-based menu item for set of string values
|
||||||
|
function stringItems(startvalue, writer, values) {
|
||||||
|
return {
|
||||||
|
value: (startvalue === undefined ? 0 : values.indexOf(startvalue)),
|
||||||
|
format: v => values[v],
|
||||||
|
min: 0,
|
||||||
|
max: values.length - 1,
|
||||||
|
wrap: true,
|
||||||
|
step: 1,
|
||||||
|
onchange: v => {
|
||||||
|
writer(values[v]);
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method which breaks string set settings down to local settings object
|
||||||
|
function stringInSettings(name, values) {
|
||||||
|
return stringItems(settings[name], v => settings[name] = v, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the menu
|
||||||
|
E.showMenu({
|
||||||
|
"" : { "title" : "Matrix Clock" },
|
||||||
|
"< Back" : () => back(),
|
||||||
|
"Colour": stringInSettings("color_scheme", ["theme", "black", "purple", "red", "white"])
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "matrixclock",
|
"id": "matrixclock",
|
||||||
"name": "Matrix Clock",
|
"name": "Matrix Clock",
|
||||||
"version": "0.04",
|
"version": "0.05",
|
||||||
"description": "inspired by The Matrix, a clock of the same style",
|
"description": "inspired by The Matrix, a clock of the same style",
|
||||||
"icon": "matrixclock.png",
|
"icon": "matrixclock.png",
|
||||||
"screenshots": [{"url":"screenshot_matrix.png"}],
|
"screenshots": [{"url":"screenshot_matrix.png"}],
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
"allow_emulator": true,
|
"allow_emulator": true,
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"matrixclock.app.js","url":"matrixclock.js"},
|
{"name":"matrixclock.app.js","url":"matrixclock.js"},
|
||||||
|
{ "name":"matrixclock.settings.js","url":"matrixclock.settings.js"},
|
||||||
{"name":"matrixclock.img","url":"matrixclock-icon.js","evaluate":true}
|
{"name":"matrixclock.img","url":"matrixclock-icon.js","evaluate":true}
|
||||||
]
|
],
|
||||||
|
"data": [{"name": "matrixclock.settings.json"}]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue