diff --git a/apps.json b/apps.json index a4f4a50ab..3a68bc8b5 100644 --- a/apps.json +++ b/apps.json @@ -4,7 +4,7 @@ "tags": "tool,system,b2", "type":"bootloader", "icon": "bootloader.png", - "version":"0.26", + "version":"0.27", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "storage": [ {"name":".boot0","url":"boot0.js"}, @@ -1030,7 +1030,7 @@ { "id": "bclock", "name": "Binary Clock", "icon": "clock-binary.png", - "version":"0.02", + "version":"0.03", "description": "A simple binary clock watch face", "tags": "clock", "type":"clock", @@ -1106,9 +1106,9 @@ "name": "Large Digit Blob Clock", "shortName" : "Blob Clock", "icon": "clock-blob.png", - "version":"0.05", + "version":"0.06", "description": "A clock with big digits", - "tags": "clock", + "tags": "clock,b2", "type":"clock", "allow_emulator":true, "storage": [ @@ -1155,7 +1155,7 @@ { "id": "berlinc", "name": "Berlin Clock", "icon": "berlin-clock.png", - "version":"0.03", + "version":"0.04", "description": "Berlin Clock (see https://en.wikipedia.org/wiki/Mengenlehreuhr)", "tags": "clock", "type":"clock", @@ -1313,7 +1313,7 @@ { "id": "barclock", "name": "Bar Clock", "icon": "clock-bar.png", - "version":"0.06", + "version":"0.07", "description": "A simple digital clock showing seconds as a bar", "tags": "clock", "type":"clock", @@ -1572,7 +1572,7 @@ "name": "Numerals Clock", "shortName": "Numerals Clock", "icon": "numerals.png", - "version":"0.08", + "version":"0.09", "description": "A simple big numerals clock", "tags": "numerals,clock", "type":"clock", @@ -1986,7 +1986,7 @@ "id": "beebclock", "name": "Beeb Clock", "icon": "beebclock.png", - "version":"0.03", + "version":"0.04", "description": "Clock face that may be coincidentally familiar to BBC viewers", "tags": "clock", "type": "clock", @@ -2114,7 +2114,7 @@ "name": "Binary Clock", "shortName":"Binary Clock", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "A binary clock with hours and minutes. BTN1 toggles a digital clock.", "tags": "clock,binary", "type": "clock", @@ -2755,7 +2755,7 @@ { "id": "astral", "name": "Astral Clock", "icon": "app-icon.png", - "version":"0.02", + "version":"0.03", "readme": "README.md", "description": "Clock that calculates and displays Alt Az positions of all planets, Sun as well as several other astronomy targets (customizable) and current Moon phase. Coordinates are calculated by GPS & time and onscreen compass assists orienting. See Readme before using.", "tags": "clock", @@ -3223,7 +3223,7 @@ "name": "Bat Clock", "shortName":"Bat Clock", "icon": "bat-clock.png", - "version":"0.01", + "version":"0.02", "description": "Morphing Clock, with an awesome \"The Dark Knight\" themed logo.", "tags": "clock", "type": "clock", @@ -3278,7 +3278,7 @@ { "id": "mysticdock", "name": "Mystic Dock", "icon": "mystic-dock.png", - "version":"1.0", + "version":"1.00", "description": "A retro-inspired dockface that displays the current time and battery charge while plugged in, and which features an interactive mode that shows the time, date, and a rotating data display line.", "tags": "dock", "type":"dock", diff --git a/apps/astral/ChangeLog b/apps/astral/ChangeLog index 7a9d48bf1..a51c96760 100644 --- a/apps/astral/ChangeLog +++ b/apps/astral/ChangeLog @@ -1,2 +1,3 @@ 0.01: Create astral clock app 0.02: Fixed Whirlpool galaxy RA/DA, larger compass display, fixed moonphase overlapping battery widget +0.03: Update to use Bangle.setUI instead of setWatch diff --git a/apps/astral/app.js b/apps/astral/app.js index 5d2d16e8f..c445463f2 100644 --- a/apps/astral/app.js +++ b/apps/astral/app.js @@ -503,8 +503,8 @@ function coord_to_horizon(utc, ra, dec, lat, lon, h) { } // -// "mean_sidereal_time" returns the Mean Sidereal Time in units of degrees. -// Use lon = 0 to get the Greenwich MST. +// "mean_sidereal_time" returns the Mean Sidereal Time in units of degrees. +// Use lon = 0 to get the Greenwich MST. // East longitudes are positive; West longitudes are negative // // returns: time in degrees @@ -523,7 +523,7 @@ function mean_sidereal_time(lon) { var c = Math.floor(365.25 * year); var da = Math.floor(30.6001 * (month + 1)); - // days since J2000.0 + // days since J2000.0 var jd = b + c + da - 730550.5 + day + (hour + mins / 60.0 + secs / 3600.0) / 24.0; @@ -796,10 +796,11 @@ Bangle.on('lcdPower', on => { Bangle.setCompassPower(1); Bangle.setGPSPower(1); -// Buttons -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +// Show launcher when button pressed +Bangle.setClockMode(); -setWatch(function () { +Bangle.setUI("clockupdown", btn => { + if (btn==0) { if (!processing) { if (!modeswitch) { modeswitch = true; @@ -809,12 +810,11 @@ setWatch(function () { else modeswitch = false; } -}, BTN3, { repeat: true }); - -setWatch(function () { + } else { if (!processing) ready_to_compute = true; -}, BTN1, { repeat: true }); + } +}); setWatch(function () { if (!astral_settings.astral_default) { diff --git a/apps/barclock/ChangeLog b/apps/barclock/ChangeLog index 551926191..9589a1902 100644 --- a/apps/barclock/ChangeLog +++ b/apps/barclock/ChangeLog @@ -3,4 +3,5 @@ 0.03: Fix dates drawing over each other at midnight 0.04: Small bugfix 0.05: Clock does not start if app Languages is not installed -0.06: Improve accuracy \ No newline at end of file +0.06: Improve accuracy +0.07: Update to use Bangle.setUI instead of setWatch diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index 4bb6c048a..5069faa39 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -2,170 +2,168 @@ /** * A simple digital clock showing seconds as a bar **/ -{ - // Check settings for what type our clock should be - const is12Hour = (require('Storage').readJSON('setting.json', 1) || {})['12hour'] - let locale = require('locale') - { // add some more info to locale - let date = new Date() - date.setFullYear(1111) - date.setMonth(1, 3) // februari: months are zero-indexed - const localized = locale.date(date, true) - locale.dayFirst = /3.*2/.test(localized) +// Check settings for what type our clock should be +const is12Hour = (require('Storage').readJSON('setting.json', 1) || {})['12hour'] +let locale = require('locale') +{ // add some more info to locale + let date = new Date() + date.setFullYear(1111) + date.setMonth(1, 3) // februari: months are zero-indexed + const localized = locale.date(date, true) + locale.dayFirst = /3.*2/.test(localized) - locale.hasMeridian = false - if(typeof locale.meridian === 'function') { // function does not exists if languages app is not installed - locale.hasMeridian = (locale.meridian(date) !== '') - } - - } - const screen = { - width: g.getWidth(), - height: g.getWidth(), - middle: g.getWidth() / 2, - center: g.getHeight() / 2, + locale.hasMeridian = false + if(typeof locale.meridian === 'function') { // function does not exists if languages app is not installed + locale.hasMeridian = (locale.meridian(date) !== '') } - // hardcoded "settings" - const settings = { - time: { +} +const screen = { + width: g.getWidth(), + height: g.getWidth(), + middle: g.getWidth() / 2, + center: g.getHeight() / 2, +} + +// hardcoded "settings" +const settings = { + time: { + color: -1, + font: '6x8', + size: (is12Hour && locale.hasMeridian) ? 6 : 8, + middle: screen.middle, + center: screen.center, + ampm: { color: -1, font: '6x8', - size: (is12Hour && locale.hasMeridian) ? 6 : 8, - middle: screen.middle, - center: screen.center, - ampm: { - color: -1, - font: '6x8', - size: 2, - }, + size: 2, }, - date: { - color: -1, - font: 'Vector', - size: 20, - middle: screen.height - 20, // at bottom of screen - center: screen.center, - }, - bar: { - color: -1, - top: 155, // just below time - thickness: 6, // matches 24h time "pixel" size - }, - } - - const SECONDS_PER_MINUTE = 60 - - const timeText = function (date) { - if (!is12Hour) { - return locale.time(date, true) - } - const date12 = new Date(date.getTime()) - const hours = date12.getHours() - if (hours === 0) { - date12.setHours(12) - } else if (hours > 12) { - date12.setHours(hours - 12) - } - return locale.time(date12, true) - } - const ampmText = function (date) { - return is12Hour ? locale.meridian(date) : '' - } - - const dateText = function (date) { - const dayName = locale.dow(date, true), - month = locale.month(date, true), - day = date.getDate() - const dayMonth = locale.dayFirst ? `${day} ${month}` : `${month} ${day}` - return `${dayName} ${dayMonth}` - } - - const drawDateTime = function (date) { - const t = settings.time - g.setColor(t.color) - g.setFont(t.font, t.size) - g.setFontAlign(0, 0) // centered - g.drawString(timeText(date), t.center, t.middle, true) - if (is12Hour && locale.hasMeridian) { - const a = settings.time.ampm - g.setColor(a.color) - g.setFont(a.font, a.size) - g.setFontAlign(1, -1) // right top - // at right edge of screen, aligned with time bottom - const left = screen.width - a.size * 2, - top = t.middle + t.size - a.size - g.drawString(ampmText(date), left, top, true) - } - - const d = settings.date - g.setColor(d.color) - g.setFont(d.font, d.size) - g.setFontAlign(0, 0) // centered - g.drawString(dateText(date), d.center, d.middle, true) - } - - const drawBar = function (date) { - const b = settings.bar - const seconds = date.getSeconds() - if (seconds === 0) { - // zero-size rect stills draws one line of pixels, we don't want that - return - } - const fraction = seconds / SECONDS_PER_MINUTE, - width = fraction * screen.width - g.setColor(b.color) - g.fillRect(0, b.top, width, b.top + b.thickness) - } - - const clearScreen = function () { - g.setColor(0) - const timeTop = settings.time.middle - (settings.time.size * 4) - g.fillRect(0, timeTop, screen.width, screen.height) - } - - let lastSeconds, tTick - const tick = function () { - g.reset() - const date = new Date() - const seconds = date.getSeconds() - if (lastSeconds > seconds) { - // new minute - clearScreen() - drawDateTime(date) - } - // the bar only gets larger, so drawing on top of the previous one is fine - drawBar(date) - lastSeconds = seconds - // schedule next update - const millis = date.getMilliseconds() - tTick = setTimeout(tick, 1000-millis) - } - - const start = function () { - lastSeconds = 99 // force redraw - tick() - } - const stop = function () { - if (tTick) { - clearTimeout(tTick) - tTick = undefined - } - } - - // clean app screen - g.clear() - Bangle.loadWidgets() - Bangle.drawWidgets() - // Show launcher when middle button pressed - setWatch(Bangle.showLauncher, BTN2, {repeat: false, edge: 'falling'}) - - Bangle.on('lcdPower', function (on) { - if (on) { - start() - } else { - stop() - } - }) - start() + }, + date: { + color: -1, + font: 'Vector', + size: 20, + middle: screen.height - 20, // at bottom of screen + center: screen.center, + }, + bar: { + color: -1, + top: 155, // just below time + thickness: 6, // matches 24h time "pixel" size + }, } + +const SECONDS_PER_MINUTE = 60 + +const timeText = function (date) { + if (!is12Hour) { + return locale.time(date, true) + } + const date12 = new Date(date.getTime()) + const hours = date12.getHours() + if (hours === 0) { + date12.setHours(12) + } else if (hours > 12) { + date12.setHours(hours - 12) + } + return locale.time(date12, true) +} +const ampmText = function (date) { + return is12Hour ? locale.meridian(date) : '' +} + +const dateText = function (date) { + const dayName = locale.dow(date, true), + month = locale.month(date, true), + day = date.getDate() + const dayMonth = locale.dayFirst ? `${day} ${month}` : `${month} ${day}` + return `${dayName} ${dayMonth}` +} + +const drawDateTime = function (date) { + const t = settings.time + g.setColor(t.color) + g.setFont(t.font, t.size) + g.setFontAlign(0, 0) // centered + g.drawString(timeText(date), t.center, t.middle, true) + if (is12Hour && locale.hasMeridian) { + const a = settings.time.ampm + g.setColor(a.color) + g.setFont(a.font, a.size) + g.setFontAlign(1, -1) // right top + // at right edge of screen, aligned with time bottom + const left = screen.width - a.size * 2, + top = t.middle + t.size - a.size + g.drawString(ampmText(date), left, top, true) + } + + const d = settings.date + g.setColor(d.color) + g.setFont(d.font, d.size) + g.setFontAlign(0, 0) // centered + g.drawString(dateText(date), d.center, d.middle, true) +} + +const drawBar = function (date) { + const b = settings.bar + const seconds = date.getSeconds() + if (seconds === 0) { + // zero-size rect stills draws one line of pixels, we don't want that + return + } + const fraction = seconds / SECONDS_PER_MINUTE, + width = fraction * screen.width + g.setColor(b.color) + g.fillRect(0, b.top, width, b.top + b.thickness) +} + +const clearScreen = function () { + g.setColor(0) + const timeTop = settings.time.middle - (settings.time.size * 4) + g.fillRect(0, timeTop, screen.width, screen.height) +} + +let lastSeconds, tTick +const tick = function () { + g.reset() + const date = new Date() + const seconds = date.getSeconds() + if (lastSeconds > seconds) { + // new minute + clearScreen() + drawDateTime(date) + } + // the bar only gets larger, so drawing on top of the previous one is fine + drawBar(date) + lastSeconds = seconds + // schedule next update + const millis = date.getMilliseconds() + tTick = setTimeout(tick, 1000-millis) +} + +const start = function () { + lastSeconds = 99 // force redraw + tick() +} +const stop = function () { + if (tTick) { + clearTimeout(tTick) + tTick = undefined + } +} + +// clean app screen +g.clear() +Bangle.loadWidgets() +Bangle.drawWidgets() +// Show launcher when button pressed +Bangle.setUI("clock"); + +Bangle.on('lcdPower', function (on) { + if (on) { + start() + } else { + stop() + } +}) +start() diff --git a/apps/batclock/ChangeLog b/apps/batclock/ChangeLog index 5d221b4c4..e6e21b146 100644 --- a/apps/batclock/ChangeLog +++ b/apps/batclock/ChangeLog @@ -1 +1,2 @@ 0.01: App Created! +0.02: Update to use Bangle.setUI instead of setWatch diff --git a/apps/batclock/bat-clock.app.js b/apps/batclock/bat-clock.app.js index abb5fbd3a..31b8f5b9b 100644 --- a/apps/batclock/bat-clock.app.js +++ b/apps/batclock/bat-clock.app.js @@ -256,8 +256,5 @@ Bangle.drawWidgets(); timeInterval = setInterval(showTime, 1000); showTime(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { - repeat: false, - edge: "falling" -}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/bclock/ChangeLog b/apps/bclock/ChangeLog index 7819dbe2a..5b2cf598c 100644 --- a/apps/bclock/ChangeLog +++ b/apps/bclock/ChangeLog @@ -1 +1,2 @@ 0.02: Modified for use with new bootloader and firmware +0.03: Update to use Bangle.setUI instead of setWatch diff --git a/apps/bclock/clock-binary.js b/apps/bclock/clock-binary.js index 833aa00f6..fdf945ee6 100644 --- a/apps/bclock/clock-binary.js +++ b/apps/bclock/clock-binary.js @@ -105,5 +105,5 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); setInterval(() => { drawClock(); }, 1000); drawClock(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/beebclock/ChangeLog b/apps/beebclock/ChangeLog index ac1c58c29..b9a4dacec 100644 --- a/apps/beebclock/ChangeLog +++ b/apps/beebclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: Initial commit. Not very efficient, and widgets not working for some reason. 0.02: Fixes; widget support 0.03: Remove hardcoded hour buzz (you can install widchime if you miss it) +0.04: Update to use Bangle.setUI instead of setWatch diff --git a/apps/beebclock/beebclock.js b/apps/beebclock/beebclock.js index bbf65697f..2f7c48c36 100644 --- a/apps/beebclock/beebclock.js +++ b/apps/beebclock/beebclock.js @@ -51,341 +51,332 @@ Graphics.prototype.drawRotLine = function (sina, cosa, cx, cy, r1, r2) { ); }; +// Display modes +// +// 0: full-screen +// 1: with widgets +// 2: centred on Bangle (v.1), no widgets or time/date +// 3: centred with time above +// 4: centred with date above +// 5: centred with time and date above +let mode; -(function(g) { - // Display modes - // - // 0: full-screen - // 1: with widgets - // 2: centred on Bangle (v.1), no widgets or time/date - // 3: centred with time above - // 4: centred with date above - // 5: centred with time and date above - let mode; +// R1, R2: Outer and inner radii of hour marks +// RC1, RC2: Outer and inner radii of hub +// CX, CY: Centre location, relative to buffer (not screen, necessarily) +// HW2, MW2: Half-width of hour and minute hand +// HR, MR: Length of hour and minute hand, relative to CX,CY +// M: Half-width of gap in hour marks +// HSCALE: Half-width of hour mark as function(0 { + const fw = R1 * 2; + const fh = R1 * 2; + const fw2 = R1; + const fh2 = R1; + let hs = []; + + // Wipe the image and start with white + G.clear(); + G.setColor(1,1,1); + + // Draw the hour marks. for (let h=1; h<=12; h++) { - const a = Math.PI * h / 6; - ss[h] = Math.sin(a); - cs[h] = Math.cos(a); + hs[h] = HSCALE(h); + G.fillRotRect(ss[h], cs[h], CX, CY, -hs[h], hs[h], R2, R1); + } - // Draw the face with hour and minute hand. Ideally, we'd separate - // the face from the hands and double-buffer, but memory is limited, - // so we buffer once and minute, and draw the second hand dynamically - // (with a bit of flicker) - const drawFace = (G) => { - const fw = R1 * 2; - const fh = R1 * 2; - const fw2 = R1; - const fh2 = R1; - let hs = []; + // Draw the hub + G.fillCircle(CX, CY, RC1); - // Wipe the image and start with white - G.clear(); - G.setColor(1,1,1); + // Black + G.setColor(0,0,0); - // Draw the hour marks. - for (let h=1; h<=12; h++) { - hs[h] = HSCALE(h); - G.fillRotRect(ss[h], cs[h], CX, CY, -hs[h], hs[h], R2, R1); + // Clear the centre of the hub + G.fillCircle(CX, CY, RC2); + // Draw the gap in the hour marks + for (let h=1; h<=12; h++) { + G.fillRotRect(ss[h], cs[h], CX, CY, -M, M, R2-1, R1+1); + } + + // Back to white for future draw operations + G.setColor(1,1,1); + + // While the buffer remains full-screen, we may trim out the + // bottom of the image so we can shift the whole thing down for + // widgets. + const img = {width:GW,height:GH-TM,buffer:G.buffer}; + return img; +}; + +let hours, minutes, seconds, date; + +// Schedule event for calling at the start of the next second +const inOneSecond = (cb) => { + let now = new Date(); + clearTimeout(); + setTimeout(cb, 1000 - now.getMilliseconds()); +}; + +// Schedule event for calling at the start of the next minute +const inOneMinute = (cb) => { + let now = new Date(); + clearTimeout(); + setTimeout(cb, 60000 - (now.getSeconds() * 1000 + now.getMilliseconds())); +}; + +// Draw a fat hour/minute hand +const drawHand = (G, a, w2, r1, r2) => + G.fillRotRect(Math.sin(a), Math.cos(a), CX, CY, -w2, w2, r1, r2); + +// Redraw function +const drawAll = (force) => { + let now = new Date(); + + if (!faceImg) force = true; + + let face_changed = force; + let date_changed = false; + + tmp = hours; + hours = now.getHours(); + if (tmp !== hours) + face_changed = true; + + tmp = minutes; + minutes = now.getMinutes(); + if (tmp !== minutes) + face_changed = true; + + // If the face has been updated and/or needs a redraw, + // face_changed is true. + + let time_changed = face_changed; + + // If the screen needs an update, regardless of whether the face + // needs a redraw, time_changed is true. + + if (with_seconds) { + // If we're going by second, we always need an update. + seconds = now.getSeconds(); + time_changed = true; + } + + if (with_digital_date) { + // See if the date has changed. If it has, then we need a + // full-blown redraw of the screen and the face, plus text. + tmp = date; + date = now.getDate(); + if (tmp !== date) { + date_changed = true; + face_changed = true; // Should have changed anyway with hour/minute rollover + } + } + + if (face_changed) { + // Redraw the face and hands onto the buffer G1. + faceImg = drawFace(G1); + drawHand(G1, Math.PI*hours/6, HW2, RC1, HR); + drawHand(G1, Math.PI*minutes/30, MW2, RC1, MR); + } + + // Has the time updated? If so, we'll need to draw something. + if (time_changed) { + + // Are we adding text? + if (with_digital_date || with_digital_time) { + + // Construct the date/time text to add above the face + let d = now.toString(); + let da = d.toString().split(" "); + let txt; + + if (with_digital_time) { + txt = da[4].substr(0, 5); + if (with_digital_date) + G1.drawStringDH(txt+',', 24, 0, 'L', GW); + else + G1.drawStringDH(txt, 0, 0, 'C', GW); + } + + if (with_digital_date) { + let txt = [da[0], da[1], da[2]].join(" "); + if (with_digital_time) + G1.drawStringDH(txt, -24, 0, 'R', GW); + else + G1.drawStringDH(txt, 0, 0, 'C', GW); + } } - // Draw the hub - G.fillCircle(CX, CY, RC1); - - // Black - G.setColor(0,0,0); - - // Clear the centre of the hub - G.fillCircle(CX, CY, RC2); - - // Draw the gap in the hour marks - for (let h=1; h<=12; h++) { - G.fillRotRect(ss[h], cs[h], CX, CY, -M, M, R2-1, R1+1); - } - - // Back to white for future draw operations - G.setColor(1,1,1); - - // While the buffer remains full-screen, we may trim out the - // bottom of the image so we can shift the whole thing down for - // widgets. - const img = {width:GW,height:GH-TM,buffer:G.buffer}; - return img; - }; - - let hours, minutes, seconds, date; - - // Schedule event for calling at the start of the next second - const inOneSecond = (cb) => { - let now = new Date(); - clearTimeout(); - setTimeout(cb, 1000 - now.getMilliseconds()); - }; - - // Schedule event for calling at the start of the next minute - const inOneMinute = (cb) => { - let now = new Date(); - clearTimeout(); - setTimeout(cb, 60000 - (now.getSeconds() * 1000 + now.getMilliseconds())); - }; - - // Draw a fat hour/minute hand - const drawHand = (G, a, w2, r1, r2) => - G.fillRotRect(Math.sin(a), Math.cos(a), CX, CY, -w2, w2, r1, r2); - - // Redraw function - const drawAll = (force) => { - let now = new Date(); - - if (!faceImg) force = true; - - let face_changed = force; - let date_changed = false; - - tmp = hours; - hours = now.getHours(); - if (tmp !== hours) - face_changed = true; - - tmp = minutes; - minutes = now.getMinutes(); - if (tmp !== minutes) - face_changed = true; - - // If the face has been updated and/or needs a redraw, - // face_changed is true. - - let time_changed = face_changed; - - // If the screen needs an update, regardless of whether the face - // needs a redraw, time_changed is true. + // If the time has updated, we need to _at least_ draw the + // image to the screen. + g.setColor(1,1,1); + g.drawImage({width:GW, + height:GH-TM, + buffer:G1.buffer}, 0, TM); + // and possibly add the second hand if (with_seconds) { - // If we're going by second, we always need an update. - seconds = now.getSeconds(); - time_changed = true; + let a = 2.0 * Math.PI * seconds / 60.0; + g.drawRotLine(Math.sin(a), Math.cos(a), CX, CY+TM, RC1, R1); } - if (with_digital_date) { - // See if the date has changed. If it has, then we need a - // full-blown redraw of the screen and the face, plus text. - tmp = date; - date = now.getDate(); - if (tmp !== date) { - date_changed = true; - face_changed = true; // Should have changed anyway with hour/minute rollover - } - } + // And draw widgets if we're in that mode + if (with_widgets) + Bangle.drawWidgets(); + } - if (face_changed) { - // Redraw the face and hands onto the buffer G1. - faceImg = drawFace(G1); - drawHand(G1, Math.PI*hours/6, HW2, RC1, HR); - drawHand(G1, Math.PI*minutes/30, MW2, RC1, MR); - } + // Schedule to repeat this. A `setTimeout(1000)` isn't good + // enough, as all the above might've taken some milliseconds and + // we don't want to drift. + if (with_seconds) + inOneSecond(drawAll); + else + inOneMinute(drawAll); +}; - // Has the time updated? If so, we'll need to draw something. - if (time_changed) { +const setButtons = () => { + // Show launcher when button pressed + Bangle.setUI("clockupdown", btn=> { + if (btn==0) changeSeconds(); + if (btn==1) { ++mode; setMode(); drawAll(true); } + }); +}; - // Are we adding text? - if (with_digital_date || with_digital_time) { +// Load display parameters based on `mode` +const setMode = () => { + // Normalize mode to 0 <= mode <= 5 + mode = (6+mode) % 6; - // Construct the date/time text to add above the face - let d = now.toString(); - let da = d.toString().split(" "); - let txt; + // [R1, R2, RC1, RC2, HW2, MW3, HR, MR, M, HSCALE] = + const scales = [ + [120, 84, 17, 12.4, 4.6, 2.2, 8, 2, 1, h => (3.0 + Math.ceil(h/1.5)) ], + [102, 70, 14.6, 10.7, 3.88, 1.8, 8, 2, 1, h => (2.4 + Math.ceil(h/1.6)) ], + ]; - if (with_digital_time) { - txt = da[4].substr(0, 5); - if (with_digital_date) - G1.drawStringDH(txt+',', 24, 0, 'L', GW); - else - G1.drawStringDH(txt, 0, 0, 'C', GW); - } + if (mode < 3) { + // Face without time/date text. Might have widgets though. + with_digital_time = with_digital_date = false; + with_widgets = (mode == 1); + } + else { + // Face with time/date text, but no widgets + with_digital_time = (mode-2)&1; + with_digital_date = (mode-2)&2; + with_widgets = false; + } - if (with_digital_date) { - let txt = [da[0], da[1], da[2]].join(" "); - if (with_digital_time) - G1.drawStringDH(txt, -24, 0, 'R', GW); - else - G1.drawStringDH(txt, 0, 0, 'C', GW); - } - } + // Destructure the array to the global display parameters + let arr = scales[mode > 0 ? 1 : 0]; + R1 = arr[0]; + R2 = arr[1]; + RC1 = arr[2]; + RC2 = arr[3]; + HW2 = arr[4]; + MW2 = arr[5]; + HR = R2 - arr[6]; + MR = R1 - arr[7]; + M = arr[8]; + HSCALE = arr[9]; + TM = with_widgets ? 36 : 0; - // If the time has updated, we need to _at least_ draw the - // image to the screen. - g.setColor(1,1,1); - g.drawImage({width:GW, - height:GH-TM, - buffer:G1.buffer}, 0, TM); + CX = GW/2; + CY = R1; - // and possibly add the second hand - if (with_seconds) { - let a = 2.0 * Math.PI * seconds / 60.0; - g.drawRotLine(Math.sin(a), Math.cos(a), CX, CY+TM, RC1, R1); - } + // If we're in the small-face + text regime, we're going to buffer + // the full screen but draw the clock face further down to give + // space for the text. + // + // Compare with modes 0 (full-screen) and 1 (with_widgets==true) + // where the face is drawn at the top of the buffer, but drawn + // lower down the screen (so CY doesn't move) + if (mode > 1) { + CY += 36; + } - // And draw widgets if we're in that mode - if (with_widgets) - Bangle.drawWidgets(); - } + // We only don't bother redrawing the face from modes 2 to 5, as + // they're the same. + if (!faceImg || mode<3) { + faceImg = undefined; + } - // Schedule to repeat this. A `setTimeout(1000)` isn't good - // enough, as all the above might've taken some milliseconds and - // we don't want to drift. - if (with_seconds) - inOneSecond(drawAll); - else - inOneMinute(drawAll); - }; - - const setButtons = () => { - const opts = { repeat: true, edge:'rising', debounce:30}; - - // BTN1: enable/disable second hand - setWatch(changeSeconds, BTN1, opts); - - // BTN2: return to launcher - setWatch(Bangle.showLauncher, BTN2, { repeat:false, edge:'falling' }); - - // BTN3: change display mode - setWatch(function () { ++mode; setMode(); drawAll(true); }, BTN3, opts); - }; - - // Load display parameters based on `mode` - const setMode = () => { - // Normalize mode to 0 <= mode <= 5 - mode = (6+mode) % 6; - - // [R1, R2, RC1, RC2, HW2, MW3, HR, MR, M, HSCALE] = - const scales = [ - [120, 84, 17, 12.4, 4.6, 2.2, 8, 2, 1, h => (3.0 + Math.ceil(h/1.5)) ], - [102, 70, 14.6, 10.7, 3.88, 1.8, 8, 2, 1, h => (2.4 + Math.ceil(h/1.6)) ], - ]; - - if (mode < 3) { - // Face without time/date text. Might have widgets though. - with_digital_time = with_digital_date = false; - with_widgets = (mode == 1); - } - else { - // Face with time/date text, but no widgets - with_digital_time = (mode-2)&1; - with_digital_date = (mode-2)&2; - with_widgets = false; - } - - // Destructure the array to the global display parameters - let arr = scales[mode > 0 ? 1 : 0]; - R1 = arr[0]; - R2 = arr[1]; - RC1 = arr[2]; - RC2 = arr[3]; - HW2 = arr[4]; - MW2 = arr[5]; - HR = R2 - arr[6]; - MR = R1 - arr[7]; - M = arr[8]; - HSCALE = arr[9]; - TM = with_widgets ? 36 : 0; - - CX = GW/2; - CY = R1; - - // If we're in the small-face + text regime, we're going to buffer - // the full screen but draw the clock face further down to give - // space for the text. - // - // Compare with modes 0 (full-screen) and 1 (with_widgets==true) - // where the face is drawn at the top of the buffer, but drawn - // lower down the screen (so CY doesn't move) - if (mode > 1) { - CY += 36; - } - - // We only don't bother redrawing the face from modes 2 to 5, as - // they're the same. - if (!faceImg || mode<3) { - faceImg = undefined; - } - - // Store the settings for next time - try { - storage.writeJSON(filename, [mode,with_seconds]); - } catch (e) { - console.log(e); - } - - // Clear the screen: we need to make sure all parts are cleaned off. - g.clear(); - }; - - const changeSeconds = () => { - with_seconds = !with_seconds; - drawAll(true); - }; - - Bangle.loadWidgets(); - - // Restore mode + // Store the settings for next time try { - conf = storage.readJSON(filename); - mode = conf[0]; - with_seconds = conf[1]; + storage.writeJSON(filename, [mode,with_seconds]); } catch (e) { console.log(e); - mode = 1; } - setButtons(); - setMode(); - drawAll(); + // Clear the screen: we need to make sure all parts are cleaned off. + g.clear(); +}; - Bangle.on('lcdPower', (on) => { - if (on) { - Bangle.loadWidgets(); - Bangle.drawWidgets(); - drawAll(); - } else { - clearTimeout(); - } - }); +const changeSeconds = () => { + with_seconds = !with_seconds; + drawAll(true); +}; -})(g); +Bangle.loadWidgets(); + +// Restore mode +try { + conf = storage.readJSON(filename); + mode = conf[0]; + with_seconds = conf[1]; +} catch (e) { + console.log(e); + mode = 1; +} + +setButtons(); +setMode(); +drawAll(); + +Bangle.on('lcdPower', (on) => { + if (on) { + Bangle.loadWidgets(); + Bangle.drawWidgets(); + drawAll(); + } else { + clearTimeout(); + } +}); diff --git a/apps/berlinc/ChangeLog b/apps/berlinc/ChangeLog index a33332bc4..65ed0505f 100644 --- a/apps/berlinc/ChangeLog +++ b/apps/berlinc/ChangeLog @@ -1,2 +1,3 @@ 0.02: Modified for use with new bootloader and firmware 0.03: Shrinked size to avoid cut-off edges on the physical device. BTN3: show date. BTN1: show time in decimal. +0.04: Update to use Bangle.setUI instead of setWatch diff --git a/apps/berlinc/berlin-clock.js b/apps/berlinc/berlin-clock.js index 3950147b8..144fa5ba7 100644 --- a/apps/berlinc/berlin-clock.js +++ b/apps/berlinc/berlin-clock.js @@ -16,7 +16,7 @@ time_digit = []; function drawBerlinClock() { g.clear(); var now = new Date(); - + // show date below the clock if (show_date) { var yr = now.getFullYear(); @@ -28,7 +28,7 @@ function drawBerlinClock() { g.setFontAlign(-1,-1); g.drawString(dateString, ( g.getWidth() - strWidth ) / 2, height + offset + 4); } - + rowlights[0] = Math.floor(now.getHours() / 5); rowlights[1] = now.getHours() % 5; rowlights[2] = Math.floor(now.getMinutes() / 5); @@ -62,7 +62,7 @@ function drawBerlinClock() { } else { g.setColor(1, 0, 0); } - g.fillRect(x1 + 2, y1 + 2, x2 - 2, y2 - 2); + g.fillRect(x1 + 2, y1 + 2, x2 - 2, y2 - 2); } if (row == 3 && show_time) { g.setColor(1,1,1); @@ -100,9 +100,11 @@ g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); drawBerlinClock(); -// Toggle date display, when BTN3 is pressed -setWatch(toggleTime,BTN1, { repeat : true, edge: "falling"}); -// Toggle date display, when BTN3 is pressed -setWatch(toggleDate,BTN3, { repeat : true, edge: "falling"}); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); +if (BTN3) { + // Toggle date display, when BTN3 is pressed + setWatch(toggleTime,BTN1, { repeat : true, edge: "falling"}); + // Toggle date display, when BTN3 is pressed + setWatch(toggleDate,BTN3, { repeat : true, edge: "falling"}); +} +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/binclock/ChangeLog b/apps/binclock/ChangeLog index 2378e52f8..dc4ed8308 100644 --- a/apps/binclock/ChangeLog +++ b/apps/binclock/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Fixed bug where screen didn't clear so incorrect time displayed. +0.03: Update to use Bangle.setUI instead of setWatch diff --git a/apps/binclock/app.js b/apps/binclock/app.js index 7808dfe45..f8cbe8dd5 100644 --- a/apps/binclock/app.js +++ b/apps/binclock/app.js @@ -23,17 +23,17 @@ function drawTime(d) { } function updateHourArray(hours){ - + var j; for(j=0;j 15){ hourLED[0] = 1; hours = hours - 16; @@ -53,9 +53,9 @@ function updateHourArray(hours){ if(hours > 0){ hourLED[4] = 1; } - + return hourLED; - + } function updateMinuteArray(minutes){ @@ -63,12 +63,12 @@ function updateMinuteArray(minutes){ for(j=0;j 31){ minuteLED[0] = 1; minutes = minutes - 32; @@ -92,20 +92,20 @@ function updateMinuteArray(minutes){ if(minutes > 0){ minuteLED[5] = 1; } - + return minuteLED; - + } function draw(){ - + // work out how to display the current time var d = new Date(); var h = d.getHours(), m = d.getMinutes(); - + updateHourArray(h); updateMinuteArray(m); - + var i; //Draw hour circles for(i=0; i{ // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: "falling" }); -setWatch(function() { +// Show launcher when button pressed +Bangle.setUI("clockupdown", btn=>{ + if (btn!=1) return; if(displayTime == 0){ displayTime = 1; } else{ - displayTime = 0; + displayTime = 0; } -}, BTN, {edge:"rising", debounce:50, repeat:true}); +}); diff --git a/apps/blobclk/ChangeLog b/apps/blobclk/ChangeLog index 10983d7e1..9c4ef5b7b 100644 --- a/apps/blobclk/ChangeLog +++ b/apps/blobclk/ChangeLog @@ -4,3 +4,4 @@ 0.03: Modified for use with new bootloader and firmware 0.04: Modified to account for changes in the behavior of Graphics.fillPoly 0.05: Slight increase to draw speed after LCD on +0.06: Update to use Bangle.setUI instead of setWatch, allow themes and different size screens diff --git a/apps/blobclk/clock-blob.js b/apps/blobclk/clock-blob.js index 9b68bd4bd..c84b8a1e6 100644 --- a/apps/blobclk/clock-blob.js +++ b/apps/blobclk/clock-blob.js @@ -1,4 +1,6 @@ -const buf = Graphics.createArrayBuffer(144,200,1,{msb:true}); +let big = g.getHeight() > 200; +const buf = Graphics.createArrayBuffer(big ? 144 : 120, big ? 180 : 150,1,{msb:true}); +// TODO: convert these to Polys -> much faster and cleaner! const NUMBERS = [ [1,1,1,1,3,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1],//0 [0,1,1,1,3,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1],//1 @@ -14,8 +16,10 @@ const NUMBERS = [ let intervalRef = null; let digits = [-1,-1,-1,-1,-1,-1]; function flip() { - g.setColor(1,1,1); - g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},55,26); + g.reset(); + g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer}, + (g.getWidth() - buf.getWidth())/2, + 26 + (g.getHeight() - (buf.getHeight()+24))/2); } function drawPixel(ox,oy,x,y,r,p) { let x1 = ox+x*(r*2); @@ -53,26 +57,31 @@ function redraw() { let newDigits = [Math.floor(hours/10),hours%10,Math.floor(mins/10),mins%10,Math.floor(secs/10),secs%10]; + let s = big?6:5; // size of main digits + let y2 = big?72:55; + let y3 = big?144:110; + + for (var p = 0;p<25;p++) { var px = p%5; var py = Math.floor(p/5); if (digits[0] === -1 || NUMBERS[newDigits[0]][p] !== NUMBERS[digits[0]][p] ) { - drawPixel(0,20,px,py,6,NUMBERS[newDigits[0]][p]); + drawPixel(0,0,px,py,s,NUMBERS[newDigits[0]][p]); } if (digits[1] === -1 || NUMBERS[newDigits[1]][p] !== NUMBERS[digits[1]][p] ) { - drawPixel(78,20,px,py,6,NUMBERS[newDigits[1]][p]); + drawPixel(13*s,0,px,py,s,NUMBERS[newDigits[1]][p]); } if (digits[2] === -1 || NUMBERS[newDigits[2]][p] !== NUMBERS[digits[2]][p] ) { - drawPixel(0,92,px,py,6,NUMBERS[newDigits[2]][p]); + drawPixel(0,y2,px,py,s,NUMBERS[newDigits[2]][p]); } if (digits[3] === -1 || NUMBERS[newDigits[3]][p] !== NUMBERS[digits[3]][p] ) { - drawPixel(78,92,px,py,6,NUMBERS[newDigits[3]][p]); + drawPixel(13*s,y2,px,py,s,NUMBERS[newDigits[3]][p]); } if (digits[4] === -1 || NUMBERS[newDigits[4]][p] !== NUMBERS[digits[4]][p] ) { - drawPixel(69,164,px,py,3,NUMBERS[newDigits[4]][p]); + drawPixel(17*s - 3*12,y3,px,py,3,NUMBERS[newDigits[4]][p]); } if (digits[5] === -1 || NUMBERS[newDigits[5]][p] !== NUMBERS[digits[5]][p] ) { - drawPixel(108,164,px,py,3,NUMBERS[newDigits[5]][p]); + drawPixel(17*s,y3,px,py,3,NUMBERS[newDigits[5]][p]); } } digits = newDigits; @@ -99,5 +108,5 @@ Bangle.on('lcdPower',function(on) { clearTimers(); } }); -// Show launcher when middle button pressed -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +// Show launcher when button pressed +Bangle.setUI("clock"); diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 37ce0d0ac..ccf97a9eb 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -25,3 +25,4 @@ 0.24: Add Bangle.setUI polyfill 0.25: Fix error in 'no clock app' message 0.26: Remove buzz in setUI polyfill (#750) +0.27: Update polyfill for most recent changes diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index 9dd49453e..014edd552 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -3,6 +3,7 @@ recalculates, but this avoids us doing a whole bunch of reconfiguration most of the time. */ E.showMessage("Updating boot0..."); var s = require('Storage').readJSON('setting.json',1)||{}; +var isB2 = process.env.HWVERSION; // Is Bangle.js 2 var boot = ""; var CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/)); boot += `if (E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))!=${CRC}) { eval(require('Storage').read('bootupdate.js'));} else {\n`; @@ -81,9 +82,9 @@ if (s.passkey!==undefined && s.passkey.length==6) boot+=`NRF.setSecurity({passke if (s.whitelist) boot+=`NRF.on('connect', function(addr) { if (!(require('Storage').readJSON('setting.json',1)||{}).whitelist.includes(addr)) NRF.disconnect(); });\n`; // Pre-2v10 firmwares without a theme/setUI if (!g.theme) { - boot += `g.theme={fg:-1,bg:0,fg2:-1,bg2:7,fgH:-1,bgH:0x02F7};\n`; + boot += `g.theme={fg:-1,bg:0,fg2:-1,bg2:7,fgH:-1,bgH:0x02F7,dark:true};\n`; } -if (!Bangle.setUI) { +if (!Bangle.setUI) { // assume this is just for F18 - Q3 should already have it boot += `Bangle.setUI=function(mode, cb) { if (Bangle.btnWatches) { Bangle.btnWatches.forEach(clearWatch); @@ -114,6 +115,18 @@ else if (mode=="updown") { Bangle.on("swipe", Bangle.swipeHandler); Bangle.touchHandler = d => {cb();}; Bangle.on("touch", Bangle.touchHandler); +} else if (mode=="clock") { + Bangle.CLOCK=1; + Bangle.btnWatches = [ + setWatch(Bangle.showLauncher, BTN2, {repeat:1,edge:"falling"}) + ]; +} else if (mode=="clockupdown") { + Bangle.CLOCK=1; + Bangle.btnWatches = [ + setWatch(function() { cb(-1); }, BTN1, {repeat:1}), + setWatch(function() { cb(1); }, BTN3, {repeat:1}), + setWatch(Bangle.showLauncher, BTN2, {repeat:1,edge:"falling"}) + ]; } else throw new Error("Unknown UI mode"); };\n`; diff --git a/apps/numerals/ChangeLog b/apps/numerals/ChangeLog index 2869074a6..f94d719f4 100644 --- a/apps/numerals/ChangeLog +++ b/apps/numerals/ChangeLog @@ -6,3 +6,4 @@ 0.06: Improve rendering of Numeral 1, fix issue with alarms not showing up 0.07: Add date on touch and some improvements (see settings and readme) 0.08: Add new draw styles, tidy up draw functionality +0.09: Tweak for faster rendering diff --git a/apps/numerals/numerals.app.js b/apps/numerals/numerals.app.js index 49a41732e..3c7607eb1 100644 --- a/apps/numerals/numerals.app.js +++ b/apps/numerals/numerals.app.js @@ -22,16 +22,17 @@ var _12hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]||fal var _hCol = ["#ff5555","#ffff00","#FF9901","#2F00FF"]; var _mCol = ["#55ff55","#ffffff","#00EFEF","#FFBF00"]; var _rCol = 0; +var scale = g.getWidth()/240; var interval = 0; const REFRESH_RATE = 10E3; var drawFuncs = { fill : function(poly,isHole){ - if (isHole) g.setColor(0); + if (isHole) g.setColor(g.theme.bg); g.fillPoly(poly,true); }, framefill : function(poly,isHole){ var c = g.getColor(); - g.setColor(isHole ? 0 : ((c&0b1111011111011110)>>1)); // 16 bit half bright + g.setColor(isHole ? g.theme.bg : ((c&0b1111011111011110)>>1)); // 16 bit half bright g.fillPoly(poly,true); g.setColor(c); g.drawPoly(poly,true); @@ -48,7 +49,8 @@ var drawFuncs = { }; function translate(tx, ty, p){ - return p.map((x, i)=> x+((i&1)?ty:tx)); + //return p.map((x, i)=> x+((i&1)?ty:tx)); + return g.transformVertices(p, {x:tx,y:ty,scale:scale}); } @@ -57,15 +59,14 @@ if (!settings) { settings = { color:0, drawMode:"fill", - menuButton:24, showDate:0 }; } function drawNum(num,col,x,y,func,funcName){ g.setColor(col); - let tx = x*100+25; - let ty = y*104+32; + let tx = (x*100+25) * scale; + let ty = (y*104+32) * scale; for (let i=0;i0); @@ -98,9 +99,9 @@ function setUpdateInt(set){ if (set) interval=setInterval(draw, REFRESH_RATE); } -Bangle.setLCDMode(); -g.reset().clear(); -setWatch(Bangle.showLauncher, settings.menuButton, {repeat:false,edge:"falling"}); +g.clear(1); +// Show launcher when button pressed +Bangle.setUI("clock"); if (settings.color>0) _rCol=settings.color-1; setUpdateInt(1); draw(); diff --git a/apps/numerals/numerals.settings.js b/apps/numerals/numerals.settings.js index 991abc888..70f6e0d98 100644 --- a/apps/numerals/numerals.settings.js +++ b/apps/numerals/numerals.settings.js @@ -6,14 +6,12 @@ numeralsSettings = { color:0, drawMode:"fill", - menuButton:22, showDate:0 }; updateSettings(); } let numeralsSettings = storage.readJSON('numerals.json',1); if (!numeralsSettings) resetSettings(); - if (numeralsSettings.menuButton===undefined) numeralsSettings.menuButton=22; let dm = ["fill","frame","framefill","thickframe"]; let col = ["rnd","r/g","y/w","o/c","b/y"]; let btn = [[24,"BTN1"],[22,"BTN2"],[23,"BTN3"],[11,"BTN4"],[16,"BTN5"]]; @@ -31,12 +29,6 @@ format: v=>dm[v], onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();} }, - "Menu button": { - value: btn.findIndex(e=>e[0]==numeralsSettings.menuButton), - min:0,max:btn.length-1, - format: v=>btn[v][1], - onchange: v=> { numeralsSettings.menuButton=btn[v][0]; updateSettings();} - }, "Date on touch": { value: 0|numeralsSettings.showDate, min:0,max:1,