2023-06-27 21:52:45 +00:00
E . showScroller = ( function ( options ) {
2022-09-21 21:03:21 +00:00
/ * o p t i o n s = {
h = height
c = # of items
scroll = initial scroll position
scrollMin = minimum scroll amount ( can be negative )
draw = function ( idx , rect )
2022-12-05 21:26:35 +00:00
remove = function ( )
select = function ( idx , touch )
2022-09-21 21:03:21 +00:00
}
2022-12-05 21:26:35 +00:00
2022-09-21 21:03:21 +00:00
returns {
2023-06-18 21:06:56 +00:00
scroll : int // current scroll amount
draw : function ( ) // draw all
drawItem : function ( idx ) // draw specific item
isActive : function ( ) // is this scroller still active?
2022-09-21 21:03:21 +00:00
}
2023-06-18 21:06:56 +00:00
2022-09-21 21:03:21 +00:00
* /
if ( ! options ) return Bangle . setUI ( ) ; // remove existing handlers
2023-06-27 21:52:45 +00:00
var draw = ( ) => {
g . reset ( ) . clearRect ( R ) . 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 ) ;
2023-06-18 21:06:56 +00:00
} ;
2022-09-21 21:03:21 +00:00
Bangle . setUI ( {
mode : "custom" ,
back : options . back ,
2022-12-05 21:26:35 +00:00
remove : options . remove ,
2023-06-27 21:52:45 +00:00
redraw : draw ,
2022-12-05 21:26:35 +00:00
swipe : ( _ , UD ) => {
2024-03-13 10:51:40 +00:00
const pixels = 120 ;
2022-12-05 21:26:35 +00:00
var dy = UD * pixels ;
2022-09-21 21:03:21 +00:00
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.
2023-06-27 21:52:45 +00:00
g . reset ( ) . setClipRect ( R . x , R . y , R . x2 , R . y2 ) . scroll ( 0 , dy ) ;
2022-12-05 21:26:35 +00:00
var d = UD * pixels ;
2022-09-21 21:03:21 +00:00
if ( d < 0 ) {
2023-06-27 21:52:45 +00:00
let y = Math . max ( R . y2 - ( 1 - d ) , R . y ) ;
g . setClipRect ( R . x , y , R . x2 , R . y2 ) ;
let i = YtoIdx ( y ) ;
y = idxToY ( i ) ;
2022-09-21 21:03:21 +00:00
//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
2023-06-27 21:52:45 +00:00
let y = Math . min ( R . y + d , R . y2 ) ;
g . setClipRect ( R . x , R . y , R . x2 , y ) ;
let i = YtoIdx ( y ) ;
y = idxToY ( i ) ;
2022-09-21 21:03:21 +00:00
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 ) ;
2023-06-27 21:52:45 +00:00
} , touch : ( _ , e ) => {
if ( e . y < R . y - 4 ) return ;
var i = YtoIdx ( e . y ) ;
if ( ( menuScrollMin < 0 || i >= 0 ) && i < options . c ) {
let yAbs = ( e . y + rScroll - R . y ) ;
let yInElement = yAbs - i * options . h ;
2024-10-11 22:20:23 +00:00
options . select ( i , { x : e . x , y : yInElement , type : e . type } ) ;
2023-06-27 21:52:45 +00:00
}
}
2023-06-18 21:06:56 +00:00
} ) ;
2022-12-05 21:26:35 +00:00
var R = Bangle . appRect ;
2024-03-04 20:34:50 +00:00
//var Y = R.y;
//var n = Math.ceil(R.h/options.h);
2022-12-05 21:26:35 +00:00
var menuScrollMin = 0 | options . scrollMin ;
var menuScrollMax = options . h * options . c - R . h ;
if ( menuScrollMax < menuScrollMin ) menuScrollMax = menuScrollMin ;
function idxToY ( i ) {
return i * options . h + R . y - rScroll ;
}
function YtoIdx ( y ) {
return Math . floor ( ( y + rScroll - R . y ) / options . h ) ;
}
2023-06-27 21:52:45 +00:00
2023-06-18 21:06:56 +00:00
var s = {
2022-12-05 21:26:35 +00:00
scroll : E . clip ( 0 | options . scroll , menuScrollMin , menuScrollMax ) ,
2023-06-27 21:52:45 +00:00
draw : draw , drawItem : i => {
var y = idxToY ( i ) ;
g . reset ( ) . setClipRect ( R . x , Math . max ( y , R . y ) , R . x2 , Math . min ( y + options . h , R . y2 ) ) ;
options . draw ( i , { x : R . x , y : y , w : R . w , h : options . h } ) ;
g . setClipRect ( 0 , 0 , g . getWidth ( ) - 1 , g . getHeight ( ) - 1 ) ;
} , isActive : ( ) => Bangle . uiRedraw == draw
} ;
2022-12-05 21:26:35 +00:00
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
2022-09-21 21:03:21 +00:00
return s ;
2022-12-05 21:26:35 +00:00
} )