diff --git a/apps/analogquadclk/ChangeLog b/apps/analogquadclk/ChangeLog new file mode 100644 index 000000000..09953593e --- /dev/null +++ b/apps/analogquadclk/ChangeLog @@ -0,0 +1 @@ +0.01: New Clock! diff --git a/apps/analogquadclk/app-icon.js b/apps/analogquadclk/app-icon.js new file mode 100644 index 000000000..8eedcb6cb --- /dev/null +++ b/apps/analogquadclk/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4X//8HA4IEBgH4C5cFqgJHitQjWpBY9q0gLvI5ar/AAkgBRMC1ALJlX6CxOrBZMq34LJ1f/9QKHhW//2gCxP6wAWHy/+KREqq4WIgGtr+qLhG1vw5IgX1KBALBywWIIwNaHJEAlNqUZOltAuJyouKqwuKrQuhywuJNIIuJlIuJHQLGIBYQ6IgtU1Q6GitQjWplQVGtWkBYIhHBcpHBBY5HBM5IABA")) \ No newline at end of file diff --git a/apps/analogquadclk/app.js b/apps/analogquadclk/app.js new file mode 100644 index 000000000..20da83280 --- /dev/null +++ b/apps/analogquadclk/app.js @@ -0,0 +1,242 @@ +const W = g.getWidth(); +const H = g.getHeight(); +const background = require("clockbg"); // image backgrounds +let drawTimeout; // timeout used to update every minute +let date = new Date(); // date at last draw +let lastModified = {x1:0,y1:0,x2:W-1,y2:H-1,first:true}; // rect that was covered by hands + +const HOUR_LEN = 55; // how far forwards does hand go? +const MIN_LEN = 72; +const HOUR_BACK = 10; // how far backwards dows hand go? +const MIN_BACK = 10; +const HOUR_W = 10; // width of cleared area +const MIN_W = 8; + +function get_hand(len, w, cornerw, overhang) { + return new Int8Array([ + 0, overhang+w, + -cornerw, overhang+cornerw, + -w, overhang, + -w, -len, + -cornerw, -len - cornerw, + 0, -len - w, + cornerw, -len - cornerw, + w, -len, + w, overhang, + cornerw, overhang+cornerw + ]); +} +const hand_hour = get_hand(HOUR_LEN, 6, 4, HOUR_BACK); +const hand_hour_bg = get_hand(HOUR_LEN, HOUR_W, 8, HOUR_BACK); +const hand_minute = get_hand(MIN_LEN, 4, 3, MIN_BACK); +const hand_minute_bg = get_hand(MIN_LEN, MIN_W, 6, MIN_BACK); + + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + +// draw the clock hands +function drawHands() { + let h = date.getHours()*Math.PI/6, m = date.getMinutes()*Math.PI/30; + g.setColor(g.theme.bg).fillPolyAA(g.transformVertices(hand_hour_bg,{x:W/2,y:H/2,rotate:h})); + g.fillPolyAA(g.transformVertices(hand_minute_bg,{x:W/2,y:H/2,rotate:m})); + g.setColor("#f00").fillPolyAA(g.transformVertices(hand_hour,{x:W/2,y:H/2,rotate:h})); + g.setColor(g.theme.fg).fillPolyAA(g.transformVertices(hand_minute,{x:W/2,y:H/2,rotate:m})); +} + +// return the screen area covered by clock hands (used for filling in background) +function getHandBounds() { + let h = date.getHours()*Math.PI/6, m = date.getMinutes()*Math.PI/30; + let sh = Math.sin(h), ch = Math.cos(h), sm = Math.sin(m), cm = Math.cos(m); + return { + x1 : Math.round((W/2)+Math.min(sh*HOUR_LEN, sm*MIN_LEN, -sh*HOUR_BACK, -sm*MIN_BACK)-HOUR_W), + y1 : Math.round((H/2)-Math.max(ch*HOUR_LEN, cm*MIN_LEN, -ch*HOUR_BACK, -cm*MIN_BACK)-HOUR_W), + x2 : Math.round((W/2)+Math.max(sh*HOUR_LEN, sm*MIN_LEN, -sh*HOUR_BACK, -sm*MIN_BACK)+HOUR_W), + y2 : Math.round((H/2)-Math.min(ch*HOUR_LEN, cm*MIN_LEN, -ch*HOUR_BACK, -cm*MIN_BACK)+HOUR_W), + }; +} + +function draw() { + // queue next draw in one minute + queueDraw(); + // work out locale-friendly date/time + date = new Date(); + //var timeStr = require("locale").time(date,1); + //var dateStr = require("locale").date(date); + // fill in area that we changed last time + background.fillRect(lastModified.x1, lastModified.y1, lastModified.x2, lastModified.y2); + if (!lastModified.first) { // first draw we don't have clockInfoMenuA/etc defined + if (lastModified.y1<30) { + if (lastModified.x1 < 30) clockInfoMenuA.redraw(); + if (lastModified.x2 > W-30) clockInfoMenuB.redraw(); + } + if (lastModified.y2>W-20) { + if (lastModified.x1 < 30) clockInfoMenuD.redraw(); + if (lastModified.x2 > W-30) clockInfoMenuC.redraw(); + } + } + // draw hands + drawHands(); + lastModified = getHandBounds(); + //g.drawRect(lastModified); // debug +} + +// Clear the screen once, at startup +background.fillRect(0, 0, W - 1, H - 1); +// draw immediately at first, queue update +draw(); + +// used for clockinfo image rendering +let clockInfoG = Graphics.createArrayBuffer(28, 28, 2, {msb:true}); +clockInfoG.transparent = 3; +// render clockinfos +let clockInfoDraw = function(itm, info, options) { + // itm: the item containing name/hasRange/etc + // info: data returned from itm.get() containing text/img/etc + // options: options passed into addInteractive + const left = options.x < 88, + top = options.y < 88, + imgx = left ? 1 : W - 28, imgy = top ? 19 : H - 42, + textx = left ? 2 : W - 1, texty = top ? 2 : H - 16; + let bg = g.theme.bg, fg = g.theme.fg; + // Clear the background + g.reset(); + background.fillRect(imgx, imgy, imgx+25, imgy+25); // erase image + background.fillRect(left?0:W/2, texty-1, left?W/2:W-1, texty+15); // erase text + // indicate focus - change colours + if (options.focus) { + bg = g.theme.fg; + fg = g.toColor("#f00"); + } + + if (info.img) { + //g.drawImage(info.img, left ? 2 : W - 27, top ? 18 : H - 41); // draw the image + // fiddle around colouring the border and inside of the image + clockInfoG.clear(1); + // do a border - images need to be transparent for this + clockInfoG.setColor(2).drawImage(info.img, 1,1).drawImage(info.img, 3,1). + drawImage(info.img, 1,3).drawImage(info.img, 3,3); + clockInfoG.setColor(1).drawImage(info.img, 2,2); // main image + clockInfoG.floodFill(27,27,3); // flood fill edge to transparent + clockInfoG.palette = new Uint16Array([bg,fg,bg/*border*/, g.toColor("#888")]); + g.drawImage(clockInfoG, imgx-1, imgy-1); + } + + g.setFont("6x8:2").setFontAlign(left ? -1 : 1, -1); + g.setColor(bg).drawString(info.text, textx-2, texty). // draw the text background + drawString(info.text, textx+2, texty). + drawString(info.text, textx, texty-2). + drawString(info.text, textx, texty+2); + g.setColor(fg).drawString(info.text, textx, texty); // draw the text + // redraw hands if needed + if ((top && lastModified.x1=texty)) { + g.reset(); + drawHands(); + } +}; + +// Load the clock infos +let clockInfoItems = require("clock_info").load(); +let clockInfoItemsBangle = clockInfoItems.find(i=>i.name=="Bangle"); +// Add extra Calendar and digital clock ClockInfos +if (clockInfoItemsBangle) { + if (!clockInfoItemsBangle.items.find(i=>i.name=="Date")) { + clockInfoItemsBangle.items.push({ name : "Date", + get : () => { + let d = new Date(); + let g = Graphics.createArrayBuffer(24,24,1,{msb:true}); + g.drawImage(atob("FhgBDADAMAMP/////////////////////8AADwAAPAAA8AADwAAPAAA8AADwAAPAAA8AADwAAPAAA8AADwAAP///////"),1,0); + g.setFont("6x15").setFontAlign(0,0).drawString(d.getDate(),11,17); + return { + text : require("locale").dow(d,1).toUpperCase(), + img : g.asImage("string") + }; + }, + show : function() { + this.interval = setTimeout(()=>{ + this.emit("redraw"); + this.interval = setInterval(()=>{ + this.emit("redraw"); + }, 86400000); + }, 86400000 - (Date.now() % 86400000)); + }, + hide : function() { + clearInterval(this.interval); + this.interval = undefined; + } + }); + } + if (!clockInfoItemsBangle.items.find(i=>i.name=="Clock")) { + clockInfoItemsBangle.items.push({ name : "Clock", + get : () => { + return { + text : require("locale").time(new Date(),1), + img : atob("GBiBAAAAAAB+AAD/AAD/AAH/gAP/wAP/wAYAYAYAYAYAYAYAYAYAcAYAcAYAYAYAYAYAYAYAYAP/wAP/wAH/gAD/AAD/AAB+AAAAAA==") + }; + }, + show : function() { + this.interval = setTimeout(()=>{ + this.emit("redraw"); + this.interval = setInterval(()=>{ + this.emit("redraw"); + }, 60000); + }, 60000 - (Date.now() % 60000)); + }, + hide : function() { + clearInterval(this.interval); + this.interval = undefined; + } + }); + } +} + + +// Add the 4 clockinfos +const CLOCKINFOSIZE = 50; +let clockInfoMenuA = require("clock_info").addInteractive(clockInfoItems, { + x: 0, + y: 0, + w: CLOCKINFOSIZE, + h: CLOCKINFOSIZE, + draw: clockInfoDraw +}); +let clockInfoMenuB = require("clock_info").addInteractive(clockInfoItems, { + x: W - CLOCKINFOSIZE, + y: 0, + w: CLOCKINFOSIZE, + h: CLOCKINFOSIZE, + draw: clockInfoDraw +}); +let clockInfoMenuC = require("clock_info").addInteractive(clockInfoItems, { + x: W - CLOCKINFOSIZE, + y: H - CLOCKINFOSIZE, + w: CLOCKINFOSIZE, + h: CLOCKINFOSIZE, + draw: clockInfoDraw +}); +let clockInfoMenuD = require("clock_info").addInteractive(clockInfoItems, { + x: 0, + y: H - CLOCKINFOSIZE, + w: CLOCKINFOSIZE, + h: CLOCKINFOSIZE, + draw: clockInfoDraw +}); + +// Show launcher when middle button pressed +Bangle.setUI({ + mode: "clock", + remove: function() { + if (drawTimeout) clearTimeout(drawTimeout); + clockInfoMenuA.remove(); + } +}); +// Load widgets +Bangle.loadWidgets(); +require("widget_utils").hide(); \ No newline at end of file diff --git a/apps/analogquadclk/icon.png b/apps/analogquadclk/icon.png new file mode 100644 index 000000000..79ded13c1 Binary files /dev/null and b/apps/analogquadclk/icon.png differ diff --git a/apps/analogquadclk/metadata.json b/apps/analogquadclk/metadata.json new file mode 100644 index 000000000..0a077bc78 --- /dev/null +++ b/apps/analogquadclk/metadata.json @@ -0,0 +1,16 @@ +{ "id": "analogquadclk", + "name": "Analog Quad Clock", + "shortName":"Quad Clock", + "version":"0.01", + "description": "An analog clock with clockinfos in each of the 4 corners, allowing 4 different data types to be rendered at once", + "icon": "icon.png", + "screenshots" : [ { "url":"screenshot.png" }, { "url":"screenshot2.png" } ], + "type": "clock", + "tags": "clock,clkinfo,analog", + "supports" : ["BANGLEJS2"], + "dependencies" : { "clock_info":"module", "clockbg":"module" }, + "storage": [ + {"name":"analogquadclk.app.js","url":"app.js"}, + {"name":"analogquadclk.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/analogquadclk/screenshot.png b/apps/analogquadclk/screenshot.png new file mode 100644 index 000000000..f1a1dd6b5 Binary files /dev/null and b/apps/analogquadclk/screenshot.png differ diff --git a/apps/analogquadclk/screenshot2.png b/apps/analogquadclk/screenshot2.png new file mode 100644 index 000000000..a62a94f58 Binary files /dev/null and b/apps/analogquadclk/screenshot2.png differ diff --git a/apps/clockbg/ChangeLog b/apps/clockbg/ChangeLog new file mode 100644 index 000000000..f7c47d4da --- /dev/null +++ b/apps/clockbg/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Moved settings into 'Settings->Apps' \ No newline at end of file diff --git a/apps/clockbg/README.md b/apps/clockbg/README.md new file mode 100644 index 000000000..8f2fe3e9d --- /dev/null +++ b/apps/clockbg/README.md @@ -0,0 +1,40 @@ +# Clock Backgrounds + +This app provides a library (`clockbg`) that can be used by clocks to +provide different backgrounds for them. + +## Usage + +By default the app provides just a red/green/blue background but it can easily be configured. + +You can either: + +* Go to [the Clock Backgrounds app](https://banglejs.com/apps/?id=clockbg) in the App Loader and upload backgrounds +* Go to the `Backgrounds` app on the Bangle itself, and choose between solid color, random colors, or any uploaded images. + + +## Usage in code + +Just use the following to use this library within your code: + +```JS +// once at the start +let background = require("clockbg"); + +// to fill the whole area +background.fillRect(Bangle.appRect); + +// to fill just one part of the screen +background.fillRect(x1, y1, x2, y2); +``` + +You should also add `"dependencies" : { "clockbg":"module" },` to your app's metadata to +ensure that the clock background library is automatically loaded. + +## Features to be added + +This library/app is still pretty basic right now, but a few features could be added that would really improve functionality: + +* Support for >1 image, and choosing randomly between them +* Support for gradients (random colors) +* Storing 'clear' areas of uploaded images so clocks can easily position themselves \ No newline at end of file diff --git a/apps/clockbg/app.png b/apps/clockbg/app.png new file mode 100644 index 000000000..21e39a4e5 Binary files /dev/null and b/apps/clockbg/app.png differ diff --git a/apps/clockbg/img/README.md b/apps/clockbg/img/README.md new file mode 100644 index 000000000..17846e6b8 --- /dev/null +++ b/apps/clockbg/img/README.md @@ -0,0 +1,19 @@ +Clock Images +============= + +If you want to add your own images ensure they're in the same style and then also list the image file in custom.html in the root directory. + +## Flags + +The flags come from https://icons8.com/icon/set/flags/color and are 480x480px + +If your flag is listed in https://icons8.com/icon/set/flags/color and you can't download it in the right size, please file an issue and we'll download it with our account. + + +## Other backgrounds + +Backgrounds prefixed `ai_` are generated by the AI [Bing Image Creator](https://www.bing.com/images/create) + + + + diff --git a/apps/clockbg/img/ai_eye.jpeg b/apps/clockbg/img/ai_eye.jpeg new file mode 100644 index 000000000..e41d40457 Binary files /dev/null and b/apps/clockbg/img/ai_eye.jpeg differ diff --git a/apps/clockbg/img/ai_hero.jpeg b/apps/clockbg/img/ai_hero.jpeg new file mode 100644 index 000000000..e0bad0895 Binary files /dev/null and b/apps/clockbg/img/ai_hero.jpeg differ diff --git a/apps/clockbg/img/ai_robot.jpeg b/apps/clockbg/img/ai_robot.jpeg new file mode 100644 index 000000000..a493a5c6a Binary files /dev/null and b/apps/clockbg/img/ai_robot.jpeg differ diff --git a/apps/clockbg/img/ai_rock.jpeg b/apps/clockbg/img/ai_rock.jpeg new file mode 100644 index 000000000..18cbe63b2 Binary files /dev/null and b/apps/clockbg/img/ai_rock.jpeg differ diff --git a/apps/clockbg/img/icons8-australia-480.png b/apps/clockbg/img/icons8-australia-480.png new file mode 100644 index 000000000..edf34cdee Binary files /dev/null and b/apps/clockbg/img/icons8-australia-480.png differ diff --git a/apps/clockbg/img/icons8-austria-480.png b/apps/clockbg/img/icons8-austria-480.png new file mode 100644 index 000000000..8450a8840 Binary files /dev/null and b/apps/clockbg/img/icons8-austria-480.png differ diff --git a/apps/clockbg/img/icons8-belgium-480.png b/apps/clockbg/img/icons8-belgium-480.png new file mode 100644 index 000000000..395fef8d1 Binary files /dev/null and b/apps/clockbg/img/icons8-belgium-480.png differ diff --git a/apps/clockbg/img/icons8-brazil-480.png b/apps/clockbg/img/icons8-brazil-480.png new file mode 100644 index 000000000..570ee39f9 Binary files /dev/null and b/apps/clockbg/img/icons8-brazil-480.png differ diff --git a/apps/clockbg/img/icons8-canada-480.png b/apps/clockbg/img/icons8-canada-480.png new file mode 100644 index 000000000..3d3080768 Binary files /dev/null and b/apps/clockbg/img/icons8-canada-480.png differ diff --git a/apps/clockbg/img/icons8-china-480.png b/apps/clockbg/img/icons8-china-480.png new file mode 100644 index 000000000..c3c3faba7 Binary files /dev/null and b/apps/clockbg/img/icons8-china-480.png differ diff --git a/apps/clockbg/img/icons8-denmark-480.png b/apps/clockbg/img/icons8-denmark-480.png new file mode 100644 index 000000000..2add9dbce Binary files /dev/null and b/apps/clockbg/img/icons8-denmark-480.png differ diff --git a/apps/clockbg/img/icons8-england-480.png b/apps/clockbg/img/icons8-england-480.png new file mode 100644 index 000000000..5c9a836a6 Binary files /dev/null and b/apps/clockbg/img/icons8-england-480.png differ diff --git a/apps/clockbg/img/icons8-flag-of-europe-480.png b/apps/clockbg/img/icons8-flag-of-europe-480.png new file mode 100644 index 000000000..654da87ba Binary files /dev/null and b/apps/clockbg/img/icons8-flag-of-europe-480.png differ diff --git a/apps/clockbg/img/icons8-france-480.png b/apps/clockbg/img/icons8-france-480.png new file mode 100644 index 000000000..e3cb56348 Binary files /dev/null and b/apps/clockbg/img/icons8-france-480.png differ diff --git a/apps/clockbg/img/icons8-germany-480.png b/apps/clockbg/img/icons8-germany-480.png new file mode 100644 index 000000000..0f86aa568 Binary files /dev/null and b/apps/clockbg/img/icons8-germany-480.png differ diff --git a/apps/clockbg/img/icons8-great-britain-480.png b/apps/clockbg/img/icons8-great-britain-480.png new file mode 100644 index 000000000..0acdcc191 Binary files /dev/null and b/apps/clockbg/img/icons8-great-britain-480.png differ diff --git a/apps/clockbg/img/icons8-greece-480.png b/apps/clockbg/img/icons8-greece-480.png new file mode 100644 index 000000000..319cf93cb Binary files /dev/null and b/apps/clockbg/img/icons8-greece-480.png differ diff --git a/apps/clockbg/img/icons8-hungary-480.png b/apps/clockbg/img/icons8-hungary-480.png new file mode 100644 index 000000000..ab838afea Binary files /dev/null and b/apps/clockbg/img/icons8-hungary-480.png differ diff --git a/apps/clockbg/img/icons8-italy-480.png b/apps/clockbg/img/icons8-italy-480.png new file mode 100644 index 000000000..f917cd85a Binary files /dev/null and b/apps/clockbg/img/icons8-italy-480.png differ diff --git a/apps/clockbg/img/icons8-lgbt-flag-480.png b/apps/clockbg/img/icons8-lgbt-flag-480.png new file mode 100644 index 000000000..10f869a0a Binary files /dev/null and b/apps/clockbg/img/icons8-lgbt-flag-480.png differ diff --git a/apps/clockbg/img/icons8-netherlands-480.png b/apps/clockbg/img/icons8-netherlands-480.png new file mode 100644 index 000000000..b271c5448 Binary files /dev/null and b/apps/clockbg/img/icons8-netherlands-480.png differ diff --git a/apps/clockbg/img/icons8-new-zealand-480.png b/apps/clockbg/img/icons8-new-zealand-480.png new file mode 100644 index 000000000..fc1ca7ec1 Binary files /dev/null and b/apps/clockbg/img/icons8-new-zealand-480.png differ diff --git a/apps/clockbg/img/icons8-norway-480.png b/apps/clockbg/img/icons8-norway-480.png new file mode 100644 index 000000000..270f5af8b Binary files /dev/null and b/apps/clockbg/img/icons8-norway-480.png differ diff --git a/apps/clockbg/img/icons8-scotland-480.png b/apps/clockbg/img/icons8-scotland-480.png new file mode 100644 index 000000000..991652211 Binary files /dev/null and b/apps/clockbg/img/icons8-scotland-480.png differ diff --git a/apps/clockbg/img/icons8-spain-480.png b/apps/clockbg/img/icons8-spain-480.png new file mode 100644 index 000000000..19c8dac04 Binary files /dev/null and b/apps/clockbg/img/icons8-spain-480.png differ diff --git a/apps/clockbg/img/icons8-sweden-480.png b/apps/clockbg/img/icons8-sweden-480.png new file mode 100644 index 000000000..60f412840 Binary files /dev/null and b/apps/clockbg/img/icons8-sweden-480.png differ diff --git a/apps/clockbg/img/icons8-switzerland-480.png b/apps/clockbg/img/icons8-switzerland-480.png new file mode 100644 index 000000000..801ba4776 Binary files /dev/null and b/apps/clockbg/img/icons8-switzerland-480.png differ diff --git a/apps/clockbg/img/icons8-ukraine-480.png b/apps/clockbg/img/icons8-ukraine-480.png new file mode 100644 index 000000000..3762c1112 Binary files /dev/null and b/apps/clockbg/img/icons8-ukraine-480.png differ diff --git a/apps/clockbg/img/icons8-usa-480.png b/apps/clockbg/img/icons8-usa-480.png new file mode 100644 index 000000000..d6288404e Binary files /dev/null and b/apps/clockbg/img/icons8-usa-480.png differ diff --git a/apps/clockbg/img/icons8-wales-480.png b/apps/clockbg/img/icons8-wales-480.png new file mode 100644 index 000000000..6c2941342 Binary files /dev/null and b/apps/clockbg/img/icons8-wales-480.png differ diff --git a/apps/clockbg/interface.html b/apps/clockbg/interface.html new file mode 100644 index 000000000..7fba8ea7b --- /dev/null +++ b/apps/clockbg/interface.html @@ -0,0 +1,179 @@ + + + + + + +

Upload an image:

+
+

If you'd like to contribute images you can add them on GitHub!

+
Preview:
+
+ + +
+ +
+ + +

Click

+ + + + + + + + \ No newline at end of file diff --git a/apps/clockbg/lib.js b/apps/clockbg/lib.js new file mode 100644 index 000000000..0da62453c --- /dev/null +++ b/apps/clockbg/lib.js @@ -0,0 +1,27 @@ +let settings = Object.assign({ + style : "randomcolor", + colors : ["#F00","#0F0","#00F"] +},require("Storage").readJSON("clockbg.json")||{}); +if (settings.style=="image") + settings.img = require("Storage").read(settings.fn); +if (settings.style=="randomcolor") { + settings.style = "color"; + var n = (0|(Math.random()*settings.colors.length)) % settings.colors.length; + settings.color = settings.colors[n]; +} + +// Fill a rectangle with the current background style, rect = {x,y,w,h} +// eg require("clockbg").fillRect({x:10,y:10,w:50,h:50}) +// require("clockbg").fillRect(Bangle.appRect) +exports.fillRect = function(rect,y,x2,y2) { + if ("object"!=typeof rect) rect = {x:rect,y:y,w:1+x2-rect,h:1+y2-y}; + if (settings.img) { + g.setClipRect(rect.x, rect.y, rect.x+rect.w-1, rect.y+rect.h-1).drawImage(settings.img).setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); + } else if (settings.style == "color") { + g.setBgColor(settings.color).clearRect(rect); + } else { + console.log("clockbg: No background set!"); + g.setBgColor(g.theme.bg).clearRect(rect); + } +}; + diff --git a/apps/clockbg/metadata.json b/apps/clockbg/metadata.json new file mode 100644 index 000000000..456590907 --- /dev/null +++ b/apps/clockbg/metadata.json @@ -0,0 +1,21 @@ +{ "id": "clockbg", + "name": "Clock Backgrounds", + "shortName":"Backgrounds", + "version": "0.02", + "description": "Library that allows clocks to include a custom background, from a library or uploaded.", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "module", + "readme": "README.md", + "provides_modules" : ["clockbg"], + "tags": "module,background", + "supports" : ["BANGLEJS2"], + "interface": "interface.html", + "storage": [ + {"name":"clockbg","url":"lib.js"}, + {"name":"clockbg.settings.js","url":"settings.js"} + ], "data": [ + {"wildcard":"clockbg.bg*.img"}, + {"name":"clockbg.json"} + ] +} diff --git a/apps/clockbg/screenshot.png b/apps/clockbg/screenshot.png new file mode 100644 index 000000000..f9d395e74 Binary files /dev/null and b/apps/clockbg/screenshot.png differ diff --git a/apps/clockbg/settings.js b/apps/clockbg/settings.js new file mode 100644 index 000000000..05135a1b4 --- /dev/null +++ b/apps/clockbg/settings.js @@ -0,0 +1,95 @@ +(function(back) { +let settings = Object.assign({ + style : "randomcolor", + colors : ["#F00","#0F0","#00F"] +},require("Storage").readJSON("clockbg.json")||{}); + +function saveSettings() { + if (settings.style!="image") + delete settings.fn; + if (settings.style!="color") + delete settings.color; + if (settings.style!="randomcolor") + delete settings.colors; + require("Storage").writeJSON("clockbg.json", settings); +} + +function getColorsImage(cols) { + var bpp = 1; + if (cols.length>4) bpp=4; + else if (cols.length>2) bpp=2; + var b = Graphics.createArrayBuffer(16*cols.length,16,bpp); + b.palette = new Uint16Array(1<{ + b.setColor(i).fillRect(i*16,0,i*16+15,15); + b.palette[i] = g.toColor(c); + }); + return "\0"+b.asImage("string"); +} + +function showModeMenu() { + 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])] = () => { + 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"], + ]; + 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/); + if (images.length) { + var menu = {"":{title:/*LANG*/"Images", back:showModeMenu}}; + images.forEach(im => { + menu[im.slice(8,-4)] = () => { + settings.style = "image"; + settings.fn = im; + saveSettings(); + showMainMenu(); + }; + }); + E.showMenu(menu); + } else { + E.showAlert("Please use App Loader to upload images").then(showModeMenu); + } + }, + }); +} + +function showMainMenu() { + E.showMenu({ + "" : {title:/*LANG*/"Clock Background", back:back}, + /*LANG*/"Mode" : { + value : settings.style, + onchange : showModeMenu + } + }); +} + +showMainMenu(); +}) \ No newline at end of file diff --git a/apps/pebblepp/ChangeLog b/apps/pebblepp/ChangeLog index a250646d5..1b64fefe3 100644 --- a/apps/pebblepp/ChangeLog +++ b/apps/pebblepp/ChangeLog @@ -4,3 +4,4 @@ 0.03: Use smaller font if clock_info test doesn't fit in area 0.04: Ensure we only scale down clockinfo text if it really won't fit 0.05: Minor code improvements +0.06: Use the clockbg library to allow custom image backgrounds \ No newline at end of file diff --git a/apps/pebblepp/app.js b/apps/pebblepp/app.js index 0330b9832..09691bab8 100644 --- a/apps/pebblepp/app.js +++ b/apps/pebblepp/app.js @@ -20,7 +20,8 @@ Graphics.prototype.setFontLECO1976Regular14 = function() { { const SETTINGS_FILE = "pebblepp.json"; -let settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'bg': '#0f0', 'color': 'Green', 'theme':'System', 'showlock':false}; +let settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'theme':'System', 'showlock':false}; +let background = require("clockbg"); let theme; let drawTimeout; @@ -50,7 +51,7 @@ let draw = function() { }; let loadThemeColors = function() { - theme = {fg: g.theme.fg, bg: g.theme.bg, day: g.toColor(0,0,0)}; + theme = {fg: g.theme.fg, bg: g.theme.bg }; if (settings.theme === "Dark") { theme.fg = g.toColor(1,1,1); theme.bg = g.toColor(0,0,0); @@ -58,13 +59,15 @@ let loadThemeColors = function() { theme.fg = g.toColor(0,0,0); theme.bg = g.toColor(1,1,1); } - // day and steps - if (settings.color == 'Blue' || settings.color == 'Red') - theme.day = g.toColor(1,1,1); // white on blue or red best contrast }; loadThemeColors(); // Load the clock infos +let clockInfoW = 0|(w/2); +let clockInfoH = 0|(h/2); +let clockInfoG = Graphics.createArrayBuffer(25, 25, 2, {msb:true}); +clockInfoG.transparent = 3; +clockInfoG.palette = new Uint16Array([g.theme.bg, g.theme.fg, g.toColor("#888"), g.toColor("#888")]); let clockInfoItems = require("clock_info").load(); let clockInfoDraw = (itm, info, options) => { // itm: the item containing name/hasRange/etc @@ -72,25 +75,26 @@ let clockInfoDraw = (itm, info, options) => { // options: options passed into addInteractive // Clear the background - if focussed, add a border g.reset().setBgColor(theme.bg).setColor(theme.fg); - var b = 0; // border + var y,b = 0; // border if (options.focus) { // white border b = 4; g.clearRect(options.x, options.y, options.x+options.w-1, options.y+options.h-1); } - g.setBgColor(settings.bg).clearRect(options.x+b, options.y+b, options.x+options.w-1-b, options.y+options.h-1-b); + background.fillRect(options.x+b, options.y+b, options.x+options.w-1-b, options.y+options.h-1-b); // we're drawing center-aligned here var midx = options.x+options.w/2; if (info.img) { // draw the image // TODO: we could replace certain images with our own ones here... - var y = options.y+8; + y = options.y+8; if (g.floodFill) { /* img is (usually) a black and white transparent image. But we really would like the bits in the middle of it to be white. So what we do is we draw a slightly bigger rectangle in white, draw the image, and then flood-fill the rectangle back to the background color. floodFill was only added in 2v18 so we have to check for it and fallback if not. */ - g.setBgColor(theme.bg).clearRect(midx-25,y-1,midx+24,y+48); - g.drawImage(info.img, midx-24,y,{scale:2}); - g.floodFill(midx-25,y,settings.bg); + clockInfoG.setBgColor(0).clearRect(0,0,24,24); + clockInfoG.setColor(1).drawImage(info.img, 0,0); + clockInfoG.floodFill(24,24,3); + g.drawImage(clockInfoG, midx-24,y,{scale:2}); } else { // fallback g.drawImage(info.img, midx-24,y,{scale:2}); } @@ -103,17 +107,18 @@ let clockInfoDraw = (itm, info, options) => { var l = g.wrapString(txt, options.w); txt = l.slice(0,2).join("\n") + (l.length>2)?"...":""; } - g.drawString(txt, midx,options.y+options.h-12); // draw the text + y = options.y+options.h-12; + g.drawString(txt, midx, y); // draw the text }; let clockInfoMenuA = require("clock_info").addInteractive(clockInfoItems, { app:"pebblepp", - x : 0, y: 0, w: w/2, h:h/2, + x : 0, y: 0, w: clockInfoW, h:clockInfoH, draw : clockInfoDraw }); let clockInfoMenuB = require("clock_info").addInteractive(clockInfoItems, { app:"pebblepp", - x : w/2, y: 0, w: w/2, h:h/2, + x : w/2, y: 0, w: clockInfoW, h:clockInfoH, draw : clockInfoDraw }); @@ -134,7 +139,7 @@ Bangle.setUI({ Bangle.loadWidgets(); require("widget_utils").swipeOn(); // hide widgets, make them visible with a swipe -g.setBgColor(settings.bg).clear(); // start off with completely clear background +background.fillRect(Bangle.appRect); // start off with completely clear background // contrast bar (top) g.setColor(theme.fg).fillRect(0, h2 - 6, w, h2); // contrast bar (bottom) diff --git a/apps/pebblepp/metadata.json b/apps/pebblepp/metadata.json index d6598b709..148682e73 100644 --- a/apps/pebblepp/metadata.json +++ b/apps/pebblepp/metadata.json @@ -2,15 +2,14 @@ "id": "pebblepp", "name": "Pebble++ Clock", "shortName": "Pebble++", - "version": "0.05", + "version": "0.06", "description": "A pebble style clock (based on the 'Pebble Clock' app) but with two configurable ClockInfo items at the top", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], "type": "clock", "tags": "clock,clkinfo", "supports": ["BANGLEJS2"], - "dependencies" : { "clock_info":"module" }, - "allow_emulator": true, + "dependencies" : { "clock_info":"module", "clockbg":"module" }, "storage": [ {"name":"pebblepp.app.js","url":"app.js"}, {"name":"pebblepp.settings.js","url":"settings.js"}, diff --git a/apps/pebblepp/settings.js b/apps/pebblepp/settings.js index b84a477e1..f477b9ab8 100644 --- a/apps/pebblepp/settings.js +++ b/apps/pebblepp/settings.js @@ -1,10 +1,8 @@ (function(back) { const SETTINGS_FILE = "pebblepp.json"; - // TODO Only the color/theme indices should be written in the settings file so the labels can be translated - // Initialize with default settings... - let s = {'bg': '#0f0', 'color': 'Green', 'theme':'System', 'showlock':false} + let s = {'theme':'System', 'showlock':false} // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings @@ -20,23 +18,11 @@ storage.write(SETTINGS_FILE, settings); } - var color_options = ['Green','Orange','Cyan','Purple','Red','Blue']; - var bg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f']; var theme_options = ['System', 'Light', 'Dark']; E.showMenu({ '': { 'title': 'Pebble++ Clock' }, /*LANG*/'< Back': back, - /*LANG*/'Colour': { - value: 0 | color_options.indexOf(s.color), - min: 0, max: 5, - format: v => color_options[v], - onchange: v => { - s.color = color_options[v]; - s.bg = bg_code[v]; - save(); - } - }, /*LANG*/'Theme': { value: 0 | theme_options.indexOf(s.theme), min: 0, max: theme_options.length - 1,