diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index f1f8fb40e..7d4d23f57 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -45,3 +45,4 @@ 0.40: Use substring of message when it's longer than fits the designated menu entry. 0.41: Fix a menu bug affecting alarms with empty messages. 0.42: Fix date not getting saved in event edit menu when tapping Confirm +0.43: New settings: Show confirm, Show Overflow, Show Type. diff --git a/apps/alarm/README.md b/apps/alarm/README.md index 9da142dab..43f72665e 100644 --- a/apps/alarm/README.md +++ b/apps/alarm/README.md @@ -13,7 +13,7 @@ It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master - `Repeat` → Select when the alarm will fire. You can select a predefined option (_Once_, _Every Day_, _Workdays_ or _Weekends_ or you can configure the days freely) - `New Timer` → Configure a new timer (triggered based on amount of time elapsed in hours/minutes/seconds) - `New Event` → Configure a new event (triggered based on time and date) - - `Repeat` → Alarm can be be fired only once or repeated (every X number of _days_, _weeks_, _months_ or _years_) + - `Repeat` → Alarm can be fired only once or repeated (every X number of _days_, _weeks_, _months_ or _years_) - `Advanced` - `Scheduler settings` → Open the [Scheduler](https://github.com/espruino/BangleApps/tree/master/apps/sched) settings page, see its [README](https://github.com/espruino/BangleApps/blob/master/apps/sched/README.md) for details - `Enable All` → Enable _all_ disabled alarms & timers diff --git a/apps/alarm/app.js b/apps/alarm/app.js index d135f184e..f8dcdbfed 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -1,6 +1,11 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); +const settings = Object.assign({ + showConfirm : true, + showAutoSnooze : true, + showHidden : true +}, require('Storage').readJSON('alarm.json',1)||{}); // 0 = Sunday (default), 1 = Monday const firstDayOfWeek = (require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0; const WORKDAYS = 62; @@ -51,12 +56,14 @@ function getLabel(e) { } function trimLabel(label, maxLength) { + if(settings.showOverflow) return label; return (label.length > maxLength ? label.substring(0,maxLength-3) + "..." : label.substring(0,maxLength)); } -function formatAlarmMessage(msg) { +function formatAlarmProperty(msg) { + if(settings.showOverflow) return msg; if (msg == null) { return msg; } else if (msg.length > 7) { @@ -155,7 +162,7 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate) { }, /*LANG*/"Message": { value: alarm.msg, - format: formatAlarmMessage, + format: formatAlarmProperty, onchange: () => { setTimeout(() => { keyboard.input({text:alarm.msg}).then(result => { @@ -166,6 +173,19 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate) { }, 100); } }, + /*LANG*/"Group": { + value: alarm.group, + format: formatAlarmProperty, + onchange: () => { + setTimeout(() => { + keyboard.input({text:alarm.group}).then(result => { + alarm.group = result; + prepareAlarmForSave(alarm, alarmIndex, time, date, true); + setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex, withDate); + }); + }, 100); + } + }, /*LANG*/"Enabled": { value: alarm.on, onchange: v => alarm.on = v @@ -197,6 +217,10 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex, withDate) { }; if (!keyboard) delete menu[/*LANG*/"Message"]; + if (!keyboard || !settings.showGroup) delete menu[/*LANG*/"Group"]; + if (!settings.showConfirm) delete menu[/*LANG*/"Confirm"]; + if (!settings.showAutoSnooze) delete menu[/*LANG*/"Auto Snooze"]; + if (!settings.showHidden) delete menu[/*LANG*/"Hidden"]; if (!alarm.date) { delete menu[/*LANG*/"Day"]; delete menu[/*LANG*/"Month"]; @@ -387,7 +411,7 @@ function showEditTimerMenu(selectedTimer, timerIndex) { }, /*LANG*/"Message": { value: timer.msg, - format: formatAlarmMessage, + format: formatAlarmProperty, onchange: () => { setTimeout(() => { keyboard.input({text:timer.msg}).then(result => { @@ -420,6 +444,8 @@ function showEditTimerMenu(selectedTimer, timerIndex) { }; if (!keyboard) delete menu[/*LANG*/"Message"]; + if (!settings.showConfirm) delete menu[/*LANG*/"Confirm"]; + if (!settings.showHidden) delete menu[/*LANG*/"Hidden"]; if (!isNew) { menu[/*LANG*/"Delete"] = () => { E.showPrompt(getLabel(timer) + "\n" + /*LANG*/"Are you sure?", { title: /*LANG*/"Delete Timer" }).then((confirm) => { diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index 3c676c217..bcd60a376 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -2,7 +2,7 @@ "id": "alarm", "name": "Alarms & Timers", "shortName": "Alarms", - "version": "0.42", + "version": "0.43", "description": "Set alarms and timers on your Bangle", "icon": "app.png", "tags": "tool,alarm", @@ -11,7 +11,8 @@ "dependencies": { "scheduler":"type", "alarm":"widget" }, "storage": [ { "name": "alarm.app.js", "url": "app.js" }, - { "name": "alarm.img", "url": "app-icon.js", "evaluate": true } + { "name": "alarm.img", "url": "app-icon.js", "evaluate": true }, + { "name": "alarm.settings.js", "url":"settings.js" } ], "screenshots": [ { "url": "screenshot-1.png" }, @@ -25,5 +26,6 @@ { "url": "screenshot-9.png" }, { "url": "screenshot-10.png" }, { "url": "screenshot-11.png" } - ] + ], + "data":[ {"name":"alarm.settings.json"} ] } diff --git a/apps/alarm/settings.js b/apps/alarm/settings.js new file mode 100644 index 000000000..765e5a5fa --- /dev/null +++ b/apps/alarm/settings.js @@ -0,0 +1,51 @@ +(function(back) { + let settings = Object.assign({ + showConfirm : true, + showAutoSnooze : true, + showHidden : true + }, require('Storage').readJSON('alarm.json',1)||{}); + + const save = () => require('Storage').write('alarm.json', settings); + const DATE_FORMATS = ['default', 'mmdd']; + const DATE_FORMATS_LABELS = [/*LANG*/'Default', /*LANG*/'MMDD']; + + const appMenu = { + '': {title: 'alarm'}, '< Back': back, + /*LANG*/'Menu Date Format': { + value: DATE_FORMATS.indexOf(settings.menuDateFormat || 'default'), + format: v => DATE_FORMATS_LABELS[v], + min: 0, + max: DATE_FORMATS.length - 1, + onchange : v => { + if(v > 0) { + settings.menuDateFormat=DATE_FORMATS[v]; + } else { + delete settings.menuDateFormat; + } + save(); + } + }, + /*LANG*/'Show Menu Auto Snooze': { + value : !!settings.showAutoSnooze, + onchange : v => { settings.showAutoSnooze=v; save();} + }, + /*LANG*/'Show Menu Confirm': { + value : !!settings.showConfirm, + onchange : v => { settings.showConfirm=v; save();} + }, + /*LANG*/'Show Menu Hidden': { + value : !!settings.showHidden, + onchange : v => { settings.showHidden=v; save();} + }, + /*LANG*/'Show Menu Group': { + value : !!settings.showGroup, + onchange : v => { settings.showGroup=v; save();} + }, + /*LANG*/'Show Text Overflow': { + value : !!settings.showOverflow, + onchange : v => { settings.showOverflow=v; save();} + }, + }; + + E.showMenu(appMenu); +}); diff --git a/apps/contourclock/ChangeLog b/apps/contourclock/ChangeLog index d13b16702..2fa26b89a 100644 --- a/apps/contourclock/ChangeLog +++ b/apps/contourclock/ChangeLog @@ -10,3 +10,4 @@ 0.28: More config options for cleaner look, enabled fast loading 0.29: Fixed a bug that would leave old font files in storage. 0.30: Added options to show widgets and date on twist and tap. New fonts. +0.31: Bugfix, no more freeze. diff --git a/apps/contourclock/app.js b/apps/contourclock/app.js index 407203e6c..1a510f014 100644 --- a/apps/contourclock/app.js +++ b/apps/contourclock/app.js @@ -34,9 +34,12 @@ extrasTimeout = undefined; hideExtras(); }, 5000); + extrasShown = false; }; let drawExtras = function() { //draw date, day of the week and widgets let date = new Date(); + g.reset(); + g.clearRect(0, 138, g.getWidth() - 1, 176); g.setFont("Teletext10x18Ascii").setFontAlign(0, 1); if (settings.weekday) g.drawString(require("locale").dow(date).toUpperCase(), g.getWidth() / 2, g.getHeight() - 18); if (settings.date) g.drawString(require('locale').date(date, 1), g.getWidth() / 2, g.getHeight()); @@ -45,21 +48,23 @@ }; let hideExtras = function() { if (extrasTimeout) clearTimeout(extrasTimeout); + extrasTimeout = undefined; //NEW + g.reset(); g.clearRect(0, 138, g.getWidth() - 1, 176); require("widget_utils").hide(); - extrasShown = false; + extrasShown = false; ///NEW }; let draw = function() { + if (drawTimeout) clearTimeout(drawTimeout); //NEW + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); let date = new Date(); g.reset(); if (extrasShown) drawExtras(); else hideExtras(); require('contourclock').drawClock(settings.fontIndex); - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = setTimeout(function() { - drawTimeout = undefined; - draw(); - }, 60000 - (Date.now() % 60000)); }; if (settings.hideWhenLocked) { onLock = locked => { @@ -83,6 +88,8 @@ Bangle.removeListener('twist', showExtras); if (drawTimeout) clearTimeout(drawTimeout); if (extrasTimeout) clearTimeout(extrasTimeout); + drawTimeout = undefined; + extrasTimeout = undefined; if (settings.hideWhenLocked) require("widget_utils").show(); g.reset(); g.clear(); @@ -91,7 +98,7 @@ g.clear(); if (settings.widgets) { Bangle.loadWidgets(); - Bangle.drawWidgets(); + setTimeout(Bangle.drawWidgets,0); //NEW } draw(); } diff --git a/apps/contourclock/metadata.json b/apps/contourclock/metadata.json index ca5ee114f..5c97ce933 100644 --- a/apps/contourclock/metadata.json +++ b/apps/contourclock/metadata.json @@ -1,7 +1,7 @@ { "id": "contourclock", "name": "Contour Clock", "shortName" : "Contour Clock", - "version":"0.30", + "version":"0.31", "icon": "app.png", "readme": "README.md", "description": "A Minimalist clockface with large Digits.", diff --git a/apps/dragboard/ChangeLog b/apps/dragboard/ChangeLog index d147a623b..68cd82cfa 100644 --- a/apps/dragboard/ChangeLog +++ b/apps/dragboard/ChangeLog @@ -7,3 +7,4 @@ 0.07: Settings for display colors 0.08: Catch and discard swipe events on fw2v19 and up (as well as some cutting edge 2v18 ones), allowing compatability with the Back Swipe app. +0.09: Fix colors settings, where color was stored as string instead of the expected int. diff --git a/apps/dragboard/metadata.json b/apps/dragboard/metadata.json index 5c52d9389..090c37a01 100644 --- a/apps/dragboard/metadata.json +++ b/apps/dragboard/metadata.json @@ -1,6 +1,6 @@ { "id": "dragboard", "name": "Dragboard", - "version":"0.08", + "version":"0.09", "description": "A library for text input via swiping keyboard", "icon": "app.png", "type":"textinput", diff --git a/apps/dragboard/settings.js b/apps/dragboard/settings.js index a53914869..59a13c443 100644 --- a/apps/dragboard/settings.js +++ b/apps/dragboard/settings.js @@ -21,7 +21,7 @@ value: settings[key] == color, onchange: () => { if (color >= 0) { - settings[key] = color; + settings[key] = parseInt(color); } else { delete settings[key]; } diff --git a/apps/draguboard/ChangeLog b/apps/draguboard/ChangeLog index bca1ca7c4..3f36dc4a6 100644 --- a/apps/draguboard/ChangeLog +++ b/apps/draguboard/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App based on dragboard, but with a U shaped drag area 0.02: Catch and discard swipe events on fw2v19 and up (as well as some cutting edge 2v18 ones), allowing compatability with the Back Swipe app. +0.03: Fix "Uncaught Error: Unhandled promise rejection: ReferenceError: "dragHandlerDB" is not defined" diff --git a/apps/draguboard/lib.js b/apps/draguboard/lib.js index 6c63668a9..57093de3f 100644 --- a/apps/draguboard/lib.js +++ b/apps/draguboard/lib.js @@ -148,7 +148,7 @@ exports.input = function(options) { g.clearRect(Bangle.appRect); resolve(text); }, - drag: dragHandlerDB + drag: dragHandlerUB }); Bangle.prependListener&&Bangle.prependListener('swipe', catchSwipe); // Intercept swipes on fw2v19 and later. Should not break on older firmwares. diff --git a/apps/draguboard/metadata.json b/apps/draguboard/metadata.json index 620f39f71..2f395f8a8 100644 --- a/apps/draguboard/metadata.json +++ b/apps/draguboard/metadata.json @@ -1,6 +1,6 @@ { "id": "draguboard", "name": "DragUboard", - "version":"0.02", + "version":"0.03", "description": "A library for text input via swiping U-shaped keyboard.", "icon": "app.png", "type":"textinput", diff --git a/apps/draguboard/settings.js b/apps/draguboard/settings.js index c94ebee70..ff4ede637 100644 --- a/apps/draguboard/settings.js +++ b/apps/draguboard/settings.js @@ -21,7 +21,7 @@ value: settings[key] == color, onchange: () => { if (color >= 0) { - settings[key] = color; + settings[key] = parseInt(color); } else { delete settings[key]; } diff --git a/apps/pomoplus/ChangeLog b/apps/pomoplus/ChangeLog index 1a137aad0..96104469b 100644 --- a/apps/pomoplus/ChangeLog +++ b/apps/pomoplus/ChangeLog @@ -1,3 +1,4 @@ 0.01: New app! 0.02-0.04: Bug fixes -0.05: Submitted to the app loader \ No newline at end of file +0.05: Submitted to the app loader +0.06: Added setting to show clock after start/resume diff --git a/apps/pomoplus/app.js b/apps/pomoplus/app.js index 73af5c935..a9e21b98a 100644 --- a/apps/pomoplus/app.js +++ b/apps/pomoplus/app.js @@ -1,3 +1,5 @@ +g.clear(); + Bangle.POMOPLUS_ACTIVE = true; //Prevent the boot code from running. To avoid having to reload on every interaction, we'll control the vibrations from here when the user is in the app. const storage = require("Storage"); @@ -13,32 +15,36 @@ if ( } function drawButtons() { + let w = g.getWidth(); + let h = g.getHeight(); //Draw the backdrop - const BAR_TOP = g.getHeight() - 24; + const BAR_TOP = h - 24; g.setColor(0, 0, 1).setFontAlign(0, -1) - .clearRect(0, BAR_TOP, g.getWidth(), g.getHeight()) - .fillRect(0, BAR_TOP, g.getWidth(), g.getHeight()) + .clearRect(0, BAR_TOP, w, h) + .fillRect(0, BAR_TOP, w, h) .setColor(1, 1, 1); if (!common.state.wasRunning) { //If the timer was never started, only show a play button - g.drawImage(common.BUTTON_ICONS.play, g.getWidth() / 2, BAR_TOP); + g.drawImage(common.BUTTON_ICONS.play, w / 2, BAR_TOP); } else { - g.drawLine(g.getWidth() / 2, BAR_TOP, g.getWidth() / 2, g.getHeight()); + g.drawLine(w / 2, BAR_TOP, w / 2, h); if (common.state.running) { - g.drawImage(common.BUTTON_ICONS.pause, g.getWidth() / 4, BAR_TOP) - .drawImage(common.BUTTON_ICONS.skip, g.getWidth() * 3 / 4, BAR_TOP); + g.drawImage(common.BUTTON_ICONS.pause, w / 4, BAR_TOP) + .drawImage(common.BUTTON_ICONS.skip, w * 3 / 4, BAR_TOP); } else { - g.drawImage(common.BUTTON_ICONS.reset, g.getWidth() / 4, BAR_TOP) - .drawImage(common.BUTTON_ICONS.play, g.getWidth() * 3 / 4, BAR_TOP); + g.drawImage(common.BUTTON_ICONS.reset, w / 4, BAR_TOP) + .drawImage(common.BUTTON_ICONS.play, w * 3 / 4, BAR_TOP); } } } function drawTimerAndMessage() { + let w = g.getWidth(); + let h = g.getHeight(); g.reset() .setFontAlign(0, 0) .setFont("Vector", 36) - .clearRect(0, 24, 176, 152) + .clearRect(w / 2 - 60, h / 2 - 34, w / 2 + 60, h / 2 + 34) //Draw the timer .drawString((() => { @@ -53,7 +59,7 @@ function drawTimerAndMessage() { if (hours >= 1) return `${parseInt(hours)}:${pad(minutes)}:${pad(seconds)}`; else return `${parseInt(minutes)}:${pad(seconds)}`; - })(), g.getWidth() / 2, g.getHeight() / 2) + })(), w / 2, h / 2) //Draw the phase label .setFont("Vector", 12) @@ -63,7 +69,7 @@ function drawTimerAndMessage() { else if (currentPhase == common.PHASE_SHORT_BREAK) return `Short break ${numShortBreaks + 1}/${common.settings.numShortBreaks}`; else return "Long break!"; })(common.state.phase, common.state.numShortBreaks), - g.getWidth() / 2, g.getHeight() / 2 + 18); + w / 2, h / 2 + 18); //Update phase with vibation if needed if (common.getTimeLeft() <= 0) { @@ -91,6 +97,7 @@ Bangle.on("touch", (button, xy) => { }; setupTimerInterval(); drawButtons(); + if (common.settings.showClock) Bangle.showClock(); } else if (common.state.running) { //If we are running, there are two buttons: pause and skip @@ -127,6 +134,7 @@ Bangle.on("touch", (button, xy) => { drawTimerAndMessage(); setupTimerInterval(); drawButtons(); + if (common.settings.showClock) Bangle.showClock(); } } }); @@ -154,4 +162,4 @@ E.on('kill', () => { }); Bangle.loadWidgets(); -Bangle.drawWidgets(); \ No newline at end of file +Bangle.drawWidgets(); diff --git a/apps/pomoplus/common.js b/apps/pomoplus/common.js index b1cd42de8..bf3e80751 100644 --- a/apps/pomoplus/common.js +++ b/apps/pomoplus/common.js @@ -105,14 +105,13 @@ exports.nextPhase = function (vibrate) { if (vibrate) { if (exports.state.phase == exports.PHASE_WORKING) { - Bangle.buzz(750, 1); + Bangle.buzz(800, 1); } else if (exports.state.phase == exports.PHASE_SHORT_BREAK) { Bangle.buzz(); setTimeout(Bangle.buzz, 400); } else { Bangle.buzz(); - setTimeout(Bangle.buzz, 400); - setTimeout(Bangle.buzz, 600); + setTimeout(Bangle.buzz, 400, 400); } } -} \ No newline at end of file +} diff --git a/apps/pomoplus/metadata.json b/apps/pomoplus/metadata.json index 0db15ab4d..4f2fd6cbb 100644 --- a/apps/pomoplus/metadata.json +++ b/apps/pomoplus/metadata.json @@ -1,7 +1,7 @@ { "id": "pomoplus", "name": "Pomodoro Plus", - "version": "0.05", + "version": "0.06", "description": "A configurable pomodoro timer that runs in the background.", "icon": "icon.png", "type": "app", diff --git a/apps/pomoplus/settings.js b/apps/pomoplus/settings.js index 1ff52340a..e5c516457 100644 --- a/apps/pomoplus/settings.js +++ b/apps/pomoplus/settings.js @@ -10,7 +10,8 @@ const storage = require("Storage"); longBreak: 900000, //15 minute long break numShortBreaks: 3, //3 short breaks for every long break pausedTimerExpireTime: 21600000, //If the timer was left paused for >6 hours, reset it on next launch - widget: false //If a widget is added in the future, whether the user wants it + showClock: false, //Show clock after start/resume + widget: false, //If a widget is added in the future, whether the user wants it }; } @@ -89,6 +90,13 @@ const storage = require("Storage"); else return `${Math.floor(value / 3600000)}h ${(value % 3600000) / 60000}m` } }, + 'Show clock': { + value: settings.showClock, + onchange: function(value) { + settings.showClock = value; + save(); + }, + }, }; E.showMenu(menu) -}) \ No newline at end of file +}) diff --git a/apps/setting/settings.js b/apps/setting/settings.js index f3b963d6e..3c4115a2f 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -823,7 +823,7 @@ function showAppSettings(app) { try { appSettings = eval(appSettings); } catch (e) { - console.log(`${app.name} settings error:`, e) + console.log(`${app.name} settings error:`, e); return showError(/*LANG*/'Error in settings'); } if (typeof appSettings !== "function") { @@ -833,7 +833,7 @@ function showAppSettings(app) { // pass showAppSettingsMenu as "back" argument appSettings(()=>showAppSettingsMenu()); } catch (e) { - console.log(`${app.name} settings error:`, e) + console.log(`${app.name} settings error:`, e); return showError(/*LANG*/'Error in settings'); } } diff --git a/apps/widhrt/ChangeLog b/apps/widhrt/ChangeLog index 39520ad6a..57e4c6b9c 100644 --- a/apps/widhrt/ChangeLog +++ b/apps/widhrt/ChangeLog @@ -1,5 +1,7 @@ 0.01: First version 0.02: Don't break if running on 2v08 firmware (just don't display anything) 0.03: Works with light theme - Doesn't drain battery by updating every 2 secs - fix alignment +0.04: Doesn't drain battery by updating every 2 secs +0.05: fix alignment +0.06: changed to solid red heart image when HRM is on + diff --git a/apps/widhrt/icons8-heart-20.png b/apps/widhrt/icons8-heart-20.png new file mode 100644 index 000000000..d0e801502 Binary files /dev/null and b/apps/widhrt/icons8-heart-20.png differ diff --git a/apps/widhrt/metadata.json b/apps/widhrt/metadata.json index a8f030157..21934f280 100644 --- a/apps/widhrt/metadata.json +++ b/apps/widhrt/metadata.json @@ -1,7 +1,7 @@ { "id": "widhrt", "name": "HRM Widget", - "version": "0.03", + "version": "0.06", "description": "Tiny widget to show the power on/off status of the Heart Rate Monitor", "icon": "widget.png", "type": "widget", diff --git a/apps/widhrt/widget.js b/apps/widhrt/widget.js index d9716fa24..b24830abf 100644 --- a/apps/widhrt/widget.js +++ b/apps/widhrt/widget.js @@ -9,10 +9,13 @@ WIDGETS.widhrt={area:"tr",width:24,draw:function() { g.reset(); if (Bangle.isHRMOn()) { - g.setColor("#f00"); // on = red + g.setColor('#f00'); // on = red } else { - g.setColor(g.theme.dark ? "#333" : "#CCC"); // off = grey + g.setColor(g.theme.dark ? '#fff' : '#000'); // off } - g.drawImage(atob("FhaBAAAAAAAAAAAAAcDgD8/AYeGDAwMMDAwwADDAAMOABwYAGAwAwBgGADAwAGGAAMwAAeAAAwAAAAAAAAAAAAA="), 1+this.x, 1+this.y); + + // image converter https://www.espruino.com/Image+Converter ; settings to get a fillable image + // 1 bit bw, transparency? Y, transparent bg, white heart (must be white for color fill) + g.drawImage(atob("FBSBAAAAAAAAAAAB+fg//8f//n//5//+f//n//5//+P//D//wf/4D/8Af+AB+AAPAABgAAAA"), 1+this.x, 1+this.y); }}; })(); diff --git a/apps/widhrt/widget.png b/apps/widhrt/widget.png index 4d8f5b730..8060d93ec 100644 Binary files a/apps/widhrt/widget.png and b/apps/widhrt/widget.png differ diff --git a/core b/core index 71813fe2e..11f8e16d2 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 71813fe2eaf19987cec07db850ab9d1959694f96 +Subproject commit 11f8e16d2ebb726bb92f29d812dc3ccba4f362a9 diff --git a/modules/Layout.js b/modules/Layout.js index 5afcce410..35b396c0e 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -186,14 +186,15 @@ Layout.prototype.render = function (l) { x+4,y+h-1, x,y+h-5, x,y+4 - ], bg = l.bgCol!==undefined?l.bgCol:gfx.theme.bg2, - btnborder = l.btnBorder!==undefined?l.btnBorder:gfx.theme.fg2; + ], bg = l.bgCol!==undefined?l.bgCol:gfx.theme.bg, + btnborder = l.btnBorderCol!==undefined?l.btnBorderCol:gfx.theme.fg2, + btnface = l.btnFaceCol!==undefined?l.btnFaceCol:gfx.theme.bg2; if(l.selected){ - bg = gfx.theme.bgH, btnborder = gfx.theme.fgH; + btnface = gfx.theme.bgH, btnborder = gfx.theme.fgH; } - gfx.setColor(bg).fillPoly(poly).setColor(btnborder).drawPoly(poly); + gfx.setColor(btnface).fillPoly(poly).setColor(btnborder).drawPoly(poly); if (l.col!==undefined) gfx.setColor(l.col); - if (l.src) gfx.setBgColor(bg).drawImage( + if (l.src) gfx.setBgColor(btnface).drawImage( "function"==typeof l.src?l.src():l.src, l.x + l.w/2, l.y + l.h/2, diff --git a/modules/Layout.md b/modules/Layout.md index 96790a41a..f9a858633 100644 --- a/modules/Layout.md +++ b/modules/Layout.md @@ -45,9 +45,10 @@ layout.render(); - A `scale` field, eg `2` to set scale of an image - A `r` field to set rotation of text or images (0: 0°, 1: 90°, 2: 180°, 3: 270°). - A `wrap` field to enable line wrapping. Requires some combination of `width`/`height` and `fillx`/`filly` to be set. Not compatible with text rotation. -- A `col` field, eg `#f00` for red -- A `bgCol` field for background color (will automatically fill on render). When `type:"btn"`, this sets the background color of the button, and will not change color on press -- A `btnBorder` field for button border color (will default to theme if not set) +- A `col` field, eg `#f00` for red. When `type:"btn"`, this sets the color of the button's text label (defaults to `Graphics.theme.fg2` if not set) +- A `bgCol` field for background color (will automatically fill on render). When `type:"btn"`, this sets the color of the space outside the button border (defaults to parent layoutObject's `bgCol` if not set) +- A `btnBorderCol` field for button border color (defaults to `Graphics.theme.fg2` if not set) +- A `btnFaceCol` field for the background color of the area inside the button border (defaults to `Graphics.theme.bg2` if not set) - A `halign` field to set horizontal alignment WITHIN a `v` container. `-1`=left, `1`=right, `0`=center - A `valign` field to set vertical alignment WITHIN a `h` container. `-1`=top, `1`=bottom, `0`=center - A `pad` integer field to set pixels padding diff --git a/modules/Layout.min.js b/modules/Layout.min.js index 914f02637..043477fd5 100644 --- a/modules/Layout.min.js +++ b/modules/Layout.min.js @@ -4,11 +4,11 @@ h,b,f,a){var e=null==d.bgCol?a:g.toColor(d.bgCol);if(e!=a||"txt"==d.type||"btn"= if(void 0===h&&this.buttons[b])return this.buttons[b].cb();this.buttons[b]&&(delete this.buttons[b].selected,this.render(this.buttons[b]));b=(b+f+h)%f;this.buttons[b]&&(this.buttons[b].selected=1,this.render(this.buttons[b]));this.selectedButton=b}),d=!0);!this.options.back&&!this.options.remove||d||Bangle.setUI({mode:"custom",back:this.options.back,remove:this.options.remove});if(this.b){function h(b,f){.75=b.x&&f.y>=b.y&&f.x<=b.x+b.w&&f.y<=b.y+b.h&&(2==f.type&&b.cbl?b.cbl(f):b.cb&&b.cb(f));b.c&&b.c.forEach(a=>h(a,f))}Bangle.touchHandler= (b,f)=>h(this._l,f);Bangle.on("touch",Bangle.touchHandler)}};p.prototype.render=function(d){function h(c){"ram";b.reset();void 0!==c.col&&b.setColor(c.col);void 0!==c.bgCol&&b.setBgColor(c.bgCol).clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1);f[c.type](c)}d||(d=this._l);this.updateNeeded&&this.update();var b=g,f={"":function(){},txt:function(c){"ram";if(c.wrap){var m=b.setFont(c.font).setFontAlign(0,-1).wrapString(c.label,c.w),n=c.y+(c.h-b.getFontHeight()*m.length>>1);b.drawString(m.join("\n"),c.x+(c.w>> -1),n)}else b.setFont(c.font).setFontAlign(0,0,c.r).drawString(c.label,c.x+(c.w>>1),c.y+(c.h>>1))},btn:function(c){"ram";var m=c.x+(0|c.pad),n=c.y+(0|c.pad),q=c.w-(c.pad<<1),r=c.h-(c.pad<<1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=void 0!==c.bgCol?c.bgCol:b.theme.bg2;q=void 0!==c.btnBorder?c.btnBorder:b.theme.fg2;c.selected&&(n=b.theme.bgH,q=b.theme.fgH);b.setColor(n).fillPoly(m).setColor(q).drawPoly(m);void 0!==c.col&&b.setColor(c.col);c.src?b.setBgColor(n).drawImage("function"== -typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)}):b.setFont(c.font||"6x8:2").setFontAlign(0,0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:function(c){"ram";b.drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)})},custom:function(c){"ram";c.render(c)},h:function(c){"ram";c.c.forEach(h)},v:function(c){"ram";c.c.forEach(h)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(), -e=[];t(d,a,e,this.rects,null);for(var l in a)delete this.rects[l];d=Object.keys(a).map(c=>a[c]).reverse();for(var k of d)b.setBgColor(k.bg).clearRect.apply(g,k);e.forEach(h)}else h(d)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(d){var h={h:function(b){"ram";var f=b.x+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.fillx),0);e||(f+=b.w-b._w>>1,e=1);var l=f;b.c.forEach(k=>{k.x=0|l;f+=k._w;a+=0|k.fillx;l=f+Math.floor(a*(b.w-b._w)/e);k.w=0|l-k.x;k.h=0|(k.filly?b.h- -(b.pad<<1):k._h);k.y=0|b.y+(0|b.pad)+((1+(0|k.valign))*(b.h-(b.pad<<1)-k.h)>>1);if(k.c)h[k.type](k)})},v:function(b){"ram";var f=b.y+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.filly),0);e||(f+=b.h-b._h>>1,e=1);var l=f;b.c.forEach(k=>{k.y=0|l;f+=k._h;a+=0|k.filly;l=f+Math.floor(a*(b.h-b._h)/e);k.h=0|l-k.y;k.w=0|(k.fillx?b.w-(b.pad<<1):k._w);k.x=0|b.x+(0|b.pad)+((1+(0|k.halign))*(b.w-(b.pad<<1)-k.w)>>1);if(k.c)h[k.type](k)})}};if(h[d.type])h[d.type](d)};p.prototype.debug=function(d,h){d||(d=this._l); -h=h||1;g.setColor(h&1,h&2,h&4).drawRect(d.x+h-1,d.y+h-1,d.x+d.w-h,d.y+d.h-h);d.pad&&g.drawRect(d.x+d.pad-1,d.y+d.pad-1,d.x+d.w-d.pad,d.y+d.h-d.pad);h++;d.c&&d.c.forEach(b=>this.debug(b,h))};p.prototype.update=function(){function d(a){"ram";b[a.type](a);if(a.r&1){var e=a._w;a._w=a._h;a._h=e}a._w=Math.max(a._w+(a.pad<<1),0|a.width);a._h=Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var h=g,b={txt:function(a){"ram";a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0, --1)/100));if(a.wrap)a._h=a._w=0;else{var e=g.setFont(a.font).stringMetrics(a.label);a._w=e.width;a._h=e.height}},btn:function(a){"ram";a.font&&a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0,-1)/100));var e=a.src?h.imageMetrics("function"==typeof a.src?a.src():a.src):h.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+e.height;a._w=20+e.width},img:function(a){"ram";var e=h.imageMetrics("function"==typeof a.src?a.src():a.src),l=a.scale||1;a._w=e.width*l;a._h=e.height* -l},"":function(a){"ram";a._w=0;a._h=0},custom:function(a){"ram";a._w=0;a._h=0},h:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>Math.max(e,l._h),0);a._w=a.c.reduce((e,l)=>e+l._w,0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)},v:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>e+l._h,0);a._w=a.c.reduce((e,l)=>Math.max(e,l._w),0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)}},f= -this._l;d(f);delete b;f.fillx||f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h,f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w>>1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h>>1));this.layout(f)};p.prototype.clear=function(d){d||(d=this._l);g.reset();void 0!==d.bgCol&&g.setBgColor(d.bgCol);g.clearRect(d.x,d.y,d.x+d.w-1,d.y+d.h-1)};exports=p \ No newline at end of file +1),n)}else b.setFont(c.font).setFontAlign(0,0,c.r).drawString(c.label,c.x+(c.w>>1),c.y+(c.h>>1))},btn:function(c){"ram";var m=c.x+(0|c.pad),n=c.y+(0|c.pad),q=c.w-(c.pad<<1),r=c.h-(c.pad<<1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=void 0!==c.btnBorderCol?c.btnBorderCol:b.theme.fg2;q=void 0!==c.btnFaceCol?c.btnFaceCol:b.theme.bg2;c.selected&&(q=b.theme.bgH,n=b.theme.fgH);b.setColor(q).fillPoly(m).setColor(n).drawPoly(m);void 0!==c.col&&b.setColor(c.col);c.src? +b.setBgColor(q).drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)}):b.setFont(c.font||"6x8:2").setFontAlign(0,0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:function(c){"ram";b.drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)})},custom:function(c){"ram";c.render(c)},h:function(c){"ram";c.c.forEach(h)},v:function(c){"ram";c.c.forEach(h)}};if(this.lazy){this.rects|| +(this.rects={});var a=this.rects.clone(),e=[];t(d,a,e,this.rects,null);for(var l in a)delete this.rects[l];d=Object.keys(a).map(c=>a[c]).reverse();for(var k of d)b.setBgColor(k.bg).clearRect.apply(g,k);e.forEach(h)}else h(d)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(d){var h={h:function(b){"ram";var f=b.x+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.fillx),0);e||(f+=b.w-b._w>>1,e=1);var l=f;b.c.forEach(k=>{k.x=0|l;f+=k._w;a+=0|k.fillx;l=f+Math.floor(a*(b.w- +b._w)/e);k.w=0|l-k.x;k.h=0|(k.filly?b.h-(b.pad<<1):k._h);k.y=0|b.y+(0|b.pad)+((1+(0|k.valign))*(b.h-(b.pad<<1)-k.h)>>1);if(k.c)h[k.type](k)})},v:function(b){"ram";var f=b.y+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.filly),0);e||(f+=b.h-b._h>>1,e=1);var l=f;b.c.forEach(k=>{k.y=0|l;f+=k._h;a+=0|k.filly;l=f+Math.floor(a*(b.h-b._h)/e);k.h=0|l-k.y;k.w=0|(k.fillx?b.w-(b.pad<<1):k._w);k.x=0|b.x+(0|b.pad)+((1+(0|k.halign))*(b.w-(b.pad<<1)-k.w)>>1);if(k.c)h[k.type](k)})}};if(h[d.type])h[d.type](d)};p.prototype.debug= +function(d,h){d||(d=this._l);h=h||1;g.setColor(h&1,h&2,h&4).drawRect(d.x+h-1,d.y+h-1,d.x+d.w-h,d.y+d.h-h);d.pad&&g.drawRect(d.x+d.pad-1,d.y+d.pad-1,d.x+d.w-d.pad,d.y+d.h-d.pad);h++;d.c&&d.c.forEach(b=>this.debug(b,h))};p.prototype.update=function(){function d(a){"ram";b[a.type](a);if(a.r&1){var e=a._w;a._w=a._h;a._h=e}a._w=Math.max(a._w+(a.pad<<1),0|a.width);a._h=Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var h=g,b={txt:function(a){"ram";a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()* +a.font.slice(0,-1)/100));if(a.wrap)a._h=a._w=0;else{var e=g.setFont(a.font).stringMetrics(a.label);a._w=e.width;a._h=e.height}},btn:function(a){"ram";a.font&&a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0,-1)/100));var e=a.src?h.imageMetrics("function"==typeof a.src?a.src():a.src):h.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+e.height;a._w=20+e.width},img:function(a){"ram";var e=h.imageMetrics("function"==typeof a.src?a.src():a.src),l=a.scale||1;a._w=e.width* +l;a._h=e.height*l},"":function(a){"ram";a._w=0;a._h=0},custom:function(a){"ram";a._w=0;a._h=0},h:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>Math.max(e,l._h),0);a._w=a.c.reduce((e,l)=>e+l._w,0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)},v:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>e+l._h,0);a._w=a.c.reduce((e,l)=>Math.max(e,l._w),0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&& +(a.filly=1)}},f=this._l;d(f);delete b;f.fillx||f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h,f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w>>1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h>>1));this.layout(f)};p.prototype.clear=function(d){d||(d=this._l);g.reset();void 0!==d.bgCol&&g.setBgColor(d.bgCol);g.clearRect(d.x,d.y,d.x+d.w-1,d.y+d.h-1)};exports=p \ No newline at end of file