Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps/clockbg/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@
Default (solid colour) now uses a variety of shades
Added .load/.unload to allow changes when fast loading clocks
0.09: Add more plasma and ring bg colours, random plasma color uses all the available colours
0.10: Added blobs background
0.10: Added blobs background
0.11: Added gradient background
Bangle.js 2 can use colorpicker module for custom plasma and gradient colors
19 changes: 10 additions & 9 deletions apps/clockbg/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ You can either:

* Go to [the Clock Backgrounds app](https://banglejs.com/apps/?id=clockbg) in the App Loader and use pre-made image backgrounds (or upload your own)
* Go to the `Backgrounds` app on the Bangle itself, and choose between:
* `Solid Color` - one color that never changes
* `Random Color` - a new color every time the clock starts
* `Image` - choose from a previously uploaded image
* `Squares` - a randomly generated pattern of squares in the selected color palette
* `Plasma` - a randomly generated 'plasma' pattern of squares in the selected color palette (random noise with a gaussian filter applied)
* `Rings` - randomly generated rings in the selected color palette
* `Tris` - randomly generated overlapping triangles in the selected color palette

* `Solid Color` - One color that never changes
* `Random Color` - A new color every time the clock starts
* `Image` - Choose from a previously uploaded image
* `Squares` - A randomly generated pattern of squares in the selected color palette
* `Plasma` - A randomly generated 'plasma' pattern of squares in the selected color palette (random noise with a gaussian filter applied)
* `Rings` - Randomly generated rings in the selected color palette
* `Tris` - Randomly generated overlapping triangles in the selected color palette
* `Blobs` - Randomly generated blobs of color in the selected color palette
* `Gradient` - A gradient from top to bottom with the selected colors

## Usage in code

Expand Down Expand Up @@ -54,7 +55,7 @@ A few features could be added that would really improve functionality:

* When 'fast loading', 'random' backgrounds don't update at the moment (calling `.reload` can fix this now, but it slows things down)
* Support for >1 image to be uploaded (requires some image management in `interface.html`), and choose randomly between them
* Support for gradients (random colors)
* Support for random colored gradients
* More types of auto-generated pattern (as long as they can be generated quickly or in the background)
* Storing 'clear' areas of uploaded images so clocks can easily position themselves
* Some backgrounds could update themselves in the background (eg a mandelbrot could calculate the one it should display next time while the watch is running)
36 changes: 34 additions & 2 deletions apps/clockbg/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,39 @@ exports.reload = function() {
bg.palette.set(settings.colors.map(c=>g.toColor(c)));
settings.img = bg;
settings.imgOpt = {scale:g.getWidth()/16};
} else if (settings.style=="blobs") { // ~25ms

} else if (settings.style=="gradient") { // ~60ms
settings.style = "image";
let c = settings.colors;
function pc(s) {
if (typeof s==="number") return s;
s=s.replace('#','');
if (s.length==3) s=s[0]+s[0]+s[1]+s[1]+s[2]+s[2];
return parseInt(s,16);
}
let a=pc(c[0]), b=pc(c[1]);
let bg=Graphics.createArrayBuffer(16,16,4,{msb:true});
bg.palette=new Uint16Array(16);
let ar=(a>>16)&255,ag=(a>>8)&255,ab=a&255;
let br=(b>>16)&255,bgv=(b>>8)&255,bb=b&255;
for (let i=0;i<5;i++) {
let t=i/4;
bg.palette[i]=g.toColor((ar+(br-ar)*t)/255,(ag+(bgv-ag)*t)/255,(ab+(bb-ab)*t)/255);
}
// 4bpp, 8 bytes/row. boundaries always at rows 3,6,9,12 for 16 rows/5 colors
let buf=new Uint8Array(bg.buffer), r;
buf.fill(0x00, 0, 24); // rows 0-2: color 0
r=Math.random()*65536|0; for(let x=24;x<32;x++,r>>=2) buf[x]=((r&1?1:0)<<4)|(r&2?1:0);
buf.fill(0x11, 32, 48); // rows 4-5: color 1
r=Math.random()*65536|0; for(let x=48;x<56;x++,r>>=2) buf[x]=((r&1?2:1)<<4)|(r&2?2:1);
buf.fill(0x22, 56, 72); // rows 7-8: color 2
r=Math.random()*65536|0; for(let x=72;x<80;x++,r>>=2) buf[x]=((r&1?3:2)<<4)|(r&2?3:2);
buf.fill(0x33, 80, 96); // rows 10-11: color 3
r=Math.random()*65536|0; for(let x=96;x<104;x++,r>>=2) buf[x]=((r&1?4:3)<<4)|(r&2?4:3);
buf.fill(0x44,104,128); // rows 13-15: color 4
settings.img=bg;
settings.imgOpt={scale:g.getWidth()/16};
}else if (settings.style=="blobs") { // ~25ms
settings.style = "image";
const S=11; // image size
const Z=88,W=Z/S,H=Z/S;
Expand Down Expand Up @@ -223,4 +255,4 @@ exports.fillRect = function(rect,y,x2,y2) {
// load background
exports.reload();

//exports.fillRect(Bangle.appRect); // testing
//exports.fillRect(Bangle.appRect); // testing
4 changes: 2 additions & 2 deletions apps/clockbg/metadata.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{ "id": "clockbg",
"name": "Clock Backgrounds",
"shortName":"Backgrounds",
"version": "0.10",
"version": "0.11",
"description": "Library that allows clocks to include a custom background (generated on demand or uploaded).",
"icon": "app.png",
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"},{"url":"screenshot4.png"},{"url":"screenshot5.png"},{"url":"screenshot6.png"}],
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"},{"url":"screenshot3.png"},{"url":"screenshot4.png"},{"url":"screenshot5.png"},{"url":"screenshot6.png"},{"url":"screenshot7.png"}],
"type": "module",
"readme": "README.md",
"provides_modules" : ["clockbg"],
Expand Down
Binary file added apps/clockbg/screenshot7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
235 changes: 176 additions & 59 deletions apps/clockbg/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,70 @@
delete settings.fn;
if (settings.style!="color")
delete settings.color;
if (!["randomcolor","squares","plasma","rings","tris","blobs"].includes(settings.style))
if (!["randomcolor","squares","plasma","rings","tris","blobs","gradient"].includes(settings.style))
delete settings.colors;
require("Storage").writeJSON("clockbg.json", settings);
}

function colorRange(from, to, steps) {
function parse(hex) {
hex = hex.replace("#", "");
if (hex.length === 3)
hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
return [
parseInt(hex.slice(0,2), 16),
parseInt(hex.slice(2,4), 16),
parseInt(hex.slice(4,6), 16)
];
}
function toHex(r, g, b) {
return "#" +
Math.round(r).toString(16).padStart(2,"0") +
Math.round(g).toString(16).padStart(2,"0") +
Math.round(b).toString(16).padStart(2,"0");
}
var a = parse(from);
var b = parse(to);
var result = [];
for (var i = 0; i < steps; i++) {
var t = i / (steps - 1);
result.push(toHex(
Comment thread
RKBoss6 marked this conversation as resolved.
a[0] + (b[0] - a[0]) * t,
a[1] + (b[1] - a[1]) * t,
a[2] + (b[2] - a[2]) * t
));
}
return result;
}
let customMenu=function(style, col1name, col2name, bck) {
var col1 = "", col2 = "";
function buildMenu() {
var menu = {"":{title:/*LANG*/"Custom", back:bck}};
menu[col1name] = function() {
require("colorpicker").show({
back: buildMenu,
onSelect: function(c) { col1 = c }
});
};
menu[col2name] = function() {
require("colorpicker").show({
back: function() { buildMenu(); },
onSelect: function(c) { col2 = c}
});
};
if (col1 !== "" && col2 !== "") {
menu[/*LANG*/"Save"] = function() {
settings.style = style;
settings.colors=[col1,col2]
if(style=="plasma")settings.colors = colorRange(col1, col2, 16);
saveSettings();
showMainMenu();
};
}
E.showMenu(menu);
}
buildMenu();
}

function getColorsImage(cols) {
var bpp = 1;
Expand All @@ -32,40 +92,53 @@
E.showMenu({
"" : {title:/*LANG*/"Background", back:showMainMenu},
/*LANG*/"Solid Color" : function() {
var cols = ["#F00","#0F0","#FF0",
"#00F","#F0F","#0FF",
"#000","#888","#fff",];
var menu = {"":{title:/*LANG*/"Colors", back:showModeMenu}};
cols.forEach(col => {
menu["-"+getColorsImage([col])] = () => {

require("colorpicker").show({
back:showMainMenu,
onSelect:function(col){
Comment thread
RKBoss6 marked this conversation as resolved.
settings.style = "color";
settings.color = col;
saveSettings();
showMainMenu();
};
});
E.showMenu(menu);
}
})
},
/*LANG*/"Random Color" : function() {
var cols = [
["#F00","#0F0","#FF0","#00F","#F0F","#0FF"],
["#F00","#0F0","#00F"],
["#FF0","#F0F","#0FF"],
["#00f","#0bf","#0f7","#3f0","#ff0","#f30","#f07","#b0f"],
["#66f","#6df","#6fb","#8f6","#ff6","#f86","#f6b","#d6f"],
["#007","#057","#073","#170","#770","#710","#703","#507"]
// Please add some more!
];
var menu = {"":{title:/*LANG*/"Colors", back:showModeMenu}};
cols.forEach(col => {
menu[getColorsImage(col)] = () => {
settings.style = "randomcolor";
settings.colors = col;
saveSettings();
showMainMenu();
if(process.env.BOARD=="BANGLEJS2"){
let opts={
onSelect:function(colors){
settings.style = "randomcolor";
settings.colors = colors;
saveSettings();
},
back:showMainMenu,
multiSelect:true,
};
Comment thread
RKBoss6 marked this conversation as resolved.
});
E.showMenu(menu);
if(settings.style=="randomcolor"){
opts.startingSelection=settings.colors;
}
require("colorpicker").show(opts);
}else{
var cols = [
["#F00","#0F0","#FF0","#00F","#F0F","#0FF"],
["#F00","#0F0","#00F"],
["#FF0","#F0F","#0FF"],
["#00f","#0bf","#0f7","#3f0","#ff0","#f30","#f07","#b0f"],
["#66f","#6df","#6fb","#8f6","#ff6","#f86","#f6b","#d6f"],
["#007","#057","#073","#170","#770","#710","#703","#507"]
// Please add some more!
];
var menu = {"":{title:/*LANG*/"Colors", back:showModeMenu}};
cols.forEach(col => {
menu[getColorsImage(col)] = () => {
settings.style = "randomcolor";
settings.colors = col;
saveSettings();
showMainMenu();
}
})
E.showMenu(menu);
}

},
/*LANG*/"Image" : function() {
let images = require("Storage").list(/clockbg\..*\.img/);
Expand Down Expand Up @@ -120,36 +193,43 @@
E.showMenu(menu);
},
/*LANG*/"Plasma" : function() {
var cols = [ // list of color palettes used as possible square colours - 16 entries
["#00f","#05f","#0bf","#0fd","#0f7","#0f1","#3f0","#9f0","#ff0","#f90","#f30","#f01","#f07","#f0d","#b0f","#50f"],
["#44f","#48f","#4df","#4fe","#4fa","#4f6","#7f4","#bf4","#ff4","#fb4","#f74","#f46","#f4a","#f4e","#d4f","#84f"],
["#009","#039","#079","#098","#094","#091","#290","#590","#990","#950","#920","#901","#904","#908","#709","#309"],
["#fff","#fef","#fdf","#fcf","#fbf","#fae","#f9e","#f8e","#f7e","#f6e","#f5d","#f4d","#f3d","#f2d","#f1d","#f0c"],
["#fff","#eff","#dff","#cef","#bef","#adf","#9df","#8df","#7cf","#6cf","#5bf","#4bf","#3bf","#2af","#1af","#09f"],
["#000","#110","#220","#330","#440","#550","#660","#770","#880","#990","#aa0","#bb0","#cc0","#dd0","#ee0","#ff0"],
["#000","#010","#020","#130","#140","#250","#260","#270","#380","#390","#4a0","#4b0","#5c0","#5d0","#5e0","#6f0"],
["#fff","#efe","#dfd","#cfc","#bfb","#afa","#9f9","#8f8","#7f7","#6f6","#5f5","#4f4","#3f3","#2f2","#1f1","#0f0"],
["#fff","#fee","#fdd","#fcc","#fbb","#faa","#f99","#f88","#f77","#f66","#f55","#f44","#f33","#f22","#f11","#f00"],
let showMenu = () => {
var cols = [ // list of color palettes used as possible square colours - 16 entries
["#00f","#05f","#0bf","#0fd","#0f7","#0f1","#3f0","#9f0","#ff0","#f90","#f30","#f01","#f07","#f0d","#b0f","#50f"],
["#44f","#48f","#4df","#4fe","#4fa","#4f6","#7f4","#bf4","#ff4","#fb4","#f74","#f46","#f4a","#f4e","#d4f","#84f"],
["#009","#039","#079","#098","#094","#091","#290","#590","#990","#950","#920","#901","#904","#908","#709","#309"],
["#fff","#fef","#fdf","#fcf","#fbf","#fae","#f9e","#f8e","#f7e","#f6e","#f5d","#f4d","#f3d","#f2d","#f1d","#f0c"],
["#fff","#eff","#dff","#cef","#bef","#adf","#9df","#8df","#7cf","#6cf","#5bf","#4bf","#3bf","#2af","#1af","#09f"],
["#000","#110","#220","#330","#440","#550","#660","#770","#880","#990","#aa0","#bb0","#cc0","#dd0","#ee0","#ff0"],
["#000","#010","#020","#130","#140","#250","#260","#270","#380","#390","#4a0","#4b0","#5c0","#5d0","#5e0","#6f0"],
["#fff","#efe","#dfd","#cfc","#bfb","#afa","#9f9","#8f8","#7f7","#6f6","#5f5","#4f4","#3f3","#2f2","#1f1","#0f0"],
["#fff","#fee","#fdd","#fcc","#fbb","#faa","#f99","#f88","#f77","#f66","#f55","#f44","#f33","#f22","#f11","#f00"],

// Please add some more!
];
var menu = {"":{title:/*LANG*/"Plasma", back:showModeMenu},
/*LANG*/"Random" : () => {
settings.style = "plasma";
settings.colors = cols;
saveSettings();
showMainMenu();
}};
cols.forEach(col => {
menu[getColorsImage(col)] = () => {
settings.style = "plasma";
settings.colors = col;
saveSettings();
showMainMenu();
// Please add some more!
];

var plasmaMenu = {"":{title:/*LANG*/"Plasma", back:showModeMenu},
/*LANG*/"Random" : () => {
settings.style = "plasma";
settings.colors = cols;
saveSettings();
showMainMenu();
},
};
});
E.showMenu(menu);
if(process.env.BOARD === "BANGLEJS2")plasmaMenu[/*LANG*/"Custom"]= () => customMenu("plasma", /*LANG*/"Background",/*LANG*/"Foreground", showMenu );
cols.forEach(col => {
plasmaMenu[getColorsImage(col)] = () => {
settings.style = "plasma";
settings.colors = col;
saveSettings();
showMainMenu();
};
});
E.showMenu(plasmaMenu);
}
showMenu()
},

/*LANG*/"Rings" : function() {
var cols = [ // list of color palettes used as possible square colours - 2 entries
["#ff0","#f00"], // yellow/red
Expand Down Expand Up @@ -232,6 +312,41 @@
});
E.showMenu(menu);
},
/*LANG*/"Gradient" : function() {
let showMenu=()=>{
var cols = [ // list of color palettes used as gradient colors
["#0ff","#00f"],
["#ff0","#0f0"],
["#0f0","#f00"],
["#0ff","#f0f"],
["#fff","#0ff"]


// Please add some more!
];

var menu = {"":{title:/*LANG*/"Gradient", back:showModeMenu},
/*LANG*/"Random" : () => {
settings.style = "gradient";
settings.colors = cols;
saveSettings();
showMainMenu();
},
};
if(process.env.BOARD === "BANGLEJS2")menu[/*LANG*/"Custom"]= () => customMenu("gradient", /*LANG*/"Top",/*LANG*/"Bottom",showMenu);
cols.forEach(col => {
menu[getColorsImage(col)] = () => {
settings.style = "gradient";
settings.colors = col;
saveSettings();
showMainMenu();
};
});
E.showMenu(menu);
}
showMenu()
}

});
}

Expand All @@ -250,6 +365,8 @@
});
}

showMainMenu();

/* Scripts for generating colors. Change the values in HSBtoRGB to generate different effects


Expand All @@ -270,6 +387,6 @@
}).join(","))

*/

showMainMenu();
})

})
Loading