Big addInteractive changes - allow >1 clock_info on screen at once. Each can have focus, and fix redraw queue issue

master
Gordon Williams 2022-11-21 19:53:08 +00:00
parent 7eda9dee49
commit 11f63df3b1
1 changed files with 79 additions and 30 deletions

View File

@ -1,4 +1,3 @@
var exports = {};
/* Module that allows for loading of clock 'info' displays /* Module that allows for loading of clock 'info' displays
that can be scrolled through on the clock face. that can be scrolled through on the clock face.
@ -129,13 +128,15 @@ Simply supply the menu data (from .load) and a function to draw the clock info.
For example: For example:
let clockInfoMenu = require("clock_info").addInteractive(require("clock_info").load(), (itm, info) => { let clockInfoMenu = require("clock_info").addInteractive(require("clock_info").load(), {
var x = 20, y = 20, w=80, h=48; x : 20, y: 20, w: 80, h:80, // dimensions of area used for clock_info
g.reset().clearRect(x,y,x+w-1,y+h-1); draw : (itm, info, options) => {
g.drawRect(x,y,x+w-1,y+h-1); // debug - just to show where we are g.reset().clearRect(options.x, options.y, options.x+options.w-2, options.y+options.h-1);
g.drawImage(info.img, x+w/2-12,y+4); if (options.focus) g.drawRect(options.x, options.y, options.x+options.w-2, options.y+options.h-1); // show if focused
g.setFont("6x8:2").setFontAlign(0,0).drawString(info.text, x+w/2,y+36); var midx = options.x+options.w/2;
}); g.drawImage(info.img, midx-12,options.y+4);
g.setFont("6x8:2").setFontAlign(0,0).drawString(info.text, midx,options.y+36);
}});
// then when clock 'unloads': // then when clock 'unloads':
clockInfoMenu.remove(); clockInfoMenu.remove();
delete clockInfoMenu; delete clockInfoMenu;
@ -143,48 +144,96 @@ delete clockInfoMenu;
Then if you need to unload the clock info so it no longer Then if you need to unload the clock info so it no longer
uses memory or responds to swipes, you can call clockInfoMenu.remove() uses memory or responds to swipes, you can call clockInfoMenu.remove()
and delete clockInfoMenu and delete clockInfoMenu
clockInfoMenu is the 'options' parameter, with the following added:
* 'remove' - remove this clockInfo item
* 'redraw' - force a redraw
* 'focus' - bool to show if menu is focused or not
*/ */
exports.addInteractive = function(menu, drawFn) { exports.addInteractive = function(menu, options) {
if ("function" == typeof options) options = {draw:options}; // backwards compatibility
exports.loadCount = (0|exports.loadCount)+1;
options.focus = exports.loadCount==1; // focus if we're the first one loaded
if (!menu.length || !menu[0].items.length) return; // no info if (!menu.length || !menu[0].items.length) return; // no info
var menuA = 0, menuB = 0; if (options.menuA===undefined) options.menuA = 0;
if (options.menuB===undefined) options.menuB = Math.min(exports.loadCount, menu[0].items.length)-1;
function drawItem(itm) {
options.draw(itm, itm.get(), options);
}
function menuShowItem(itm) { function menuShowItem(itm) {
itm.on('redraw', ()=>drawFn(itm, itm.get())); options.redrawHandler = ()=>drawItem(itm);
itm.show(); itm.on('redraw', options.redrawHandler);
itm.uses = (0|itm.uses)+1;
if (itm.uses==1) itm.show();
itm.emit("redraw"); itm.emit("redraw");
} }
function menuHideItem(itm) {
itm.removeListener('redraw',options.redrawHandler);
delete options.redrawHandler;
itm.uses--;
if (!itm.uses)
itm.hide();
}
// handling for swipe between menu items // handling for swipe between menu items
function swipeHandler(lr,ud){ function swipeHandler(lr,ud){
if (!options.focus) return; // ignore if we're not focussed
var oldMenuItem; var oldMenuItem;
if (ud) { if (ud) {
if (menu[menuA].items.length==1) return; // 1 item - can't move if (menu[options.menuA].items.length==1) return; // 1 item - can't move
oldMenuItem = menu[menuA].items[menuB]; oldMenuItem = menu[options.menuA].items[options.menuB];
menuB += ud; options.menuB += ud;
if (menuB<0) menuB = menu[menuA].items.length-1; if (options.menuB<0) options.menuB = menu[options.menuA].items.length-1;
if (menuB>=menu[menuA].items.length) menuB = 0; if (options.menuB>=menu[options.menuA].items.length) options.menuB = 0;
} else if (lr) { } else if (lr) {
if (menu.length==1) return; // 1 item - can't move if (menu.length==1) return; // 1 item - can't move
oldMenuItem = menu[menuA].items[menuB]; oldMenuItem = menu[options.menuA].items[options.menuB];
menuA += ud; options.menuA += ud;
if (menuA<0) menuA = menu.length-1; if (options.menuA<0) options.menuA = menu.length-1;
if (menuA>=menu.length) menuA = 0; if (options.menuA>=menu.length) options.menuA = 0;
menuB = 0; options.menuB = 0;
} }
if (oldMenuItem) { if (oldMenuItem) {
oldMenuItem.hide(); menuHideItem(oldMenuItem);
oldMenuItem.removeAllListeners("draw"); oldMenuItem.removeAllListeners("draw");
menuShowItem(menu[menuA].items[menuB]); menuShowItem(menu[options.menuA].items[options.menuB]);
} }
} }
Bangle.on("swipe",swipeHandler); Bangle.on("swipe",swipeHandler);
// draw the first item var touchHandler;
menuShowItem(menu[menuA].items[menuB]); if (options.x!==undefined && options.y!==undefined && options.w && options.h) {
// return an object with info that can be used to remove the info touchHandler = function(_,e) {
return { if (e.x<options.x || e.y<options.y ||
remove : function() { e.x>(options.x+options.w) || e.y>(options.y+options.h)) {
Bangle.removeListener("swipe",swipeHandler); if (options.focus) {
menu[menuA].items[menuB].hide(); options.focus=false;
options.redraw();
} }
return; // outside area
}
if (!options.focus) {
options.focus=true; // if not focussed, set focus
options.redraw();
} else if (menu[options.menuA].items[options.menuB].run)
menu[options.menuA].items[options.menuB].run(); // allow tap on an item to run it (eg home assistant)
else options.focus=true;
}; };
Bangle.on("touch",touchHandler);
}
// draw the first item
menuShowItem(menu[options.menuA].items[options.menuB]);
// return an object with info that can be used to remove the info
options.remove = function() {
Bangle.removeListener("swipe",swipeHandler);
if (touchHandler) Bangle.removeListener("touch",touchHandler);
menuHideItem(menu[options.menuA].items[options.menuB]);
exports.loadCount--;
};
options.redraw = function() {
drawItem(menu[options.menuA].items[options.menuB]);
};
return options;
}; };
// Code for testing (plots all elements from first list) // Code for testing (plots all elements from first list)