E.showScroller = (function(options) { /* options = { h = height c = # of items scroll = initial scroll position scrollMin = minimum scroll amount (can be negative) draw = function(idx, rect) select = function(idx) } returns { draw = draw all drawItem(idx) = draw specific item } */ if (!options) return Bangle.setUI(); // remove existing handlers var menuShowing = false; var R = Bangle.appRect; var Y = Bangle.appRect.y; var n = Math.ceil(R.h/options.h); var menuScrollMin = 0|options.scrollMin; var menuScrollMax = options.h*options.c - R.h; if (menuScrollMax { g.reset().clearRect(R.x,R.y,R.x2,R.y2); g.setClipRect(R.x,R.y,R.x2,R.y2); var a = YtoIdx(R.y); var b = Math.min(YtoIdx(R.y2),options.c-1); for (var i=a;i<=b;i++) options.draw(i, {x:R.x,y:idxToY(i),w:R.w,h:options.h}); g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); }, drawItem : i => { var y = idxToY(i); g.reset().setClipRect(R.x,y,R.x2,y+options.h); options.draw(i, {x:R.x,y:y,w:R.w,h:options.h}); g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); }}; var rScroll = s.scroll&~1; // rendered menu scroll (we only shift by 2 because of dither) s.draw(); // draw the full scroller g.flip(); // force an update now to make this snappier Bangle.setUI({ mode : "custom", back : options.back, swipe : (hor,ver)=>{ pixels = 120; var dy = ver*pixels; if (s.scroll - dy > menuScrollMax) dy = s.scroll - menuScrollMax-8; // Makes it so the last 'page' has the same position as previous pages. This should be done dynamically (change the static 8 to be a variable) so the offset is correct even when no widget field or title field is present. if (s.scroll - dy < menuScrollMin) dy = s.scroll - menuScrollMin; s.scroll -= dy; var oldScroll = rScroll; rScroll = s.scroll &~1; dy = oldScroll-rScroll; if (!dy || options.c<=3) return; //options.c<=3 should maybe be dynamic, so 3 would be replaced by a variable dependent on R=Bangle.appRect. It's here so we don't try to scroll if all entries fit in the app rectangle. g.reset().setClipRect(R.x,R.y,R.x2,R.y2); g.scroll(0,dy); var d = ver*pixels; if (d < 0) { g.setClipRect(R.x,R.y2-(1-d),R.x2,R.y2); let i = YtoIdx(R.y2-(1-d)); let y = idxToY(i); //print(i, options.c, options.c-i); //debugging info while (y < R.y2 - (options.h*((options.c-i)<=0)) ) { //- (options.h*((options.c-i)<=0)) makes sure we don't go beyond the menu entries in the menu object "options". This has to do with "dy = s.scroll - menuScrollMax-8" above. options.draw(i, {x:R.x,y:y,w:R.w,h:options.h}); i++; y += options.h; } } else { // d>0 g.setClipRect(R.x,R.y,R.x2,R.y+d); let i = YtoIdx(R.y+d); let y = idxToY(i); //print(i, options.c, options.c-i); //debugging info while (y > R.y-options.h) { options.draw(i, {x:R.x,y:y,w:R.w,h:options.h}); y -= options.h; i--; } } g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); }, touch : (_,e)=>{ if (e.y=0) && i