ctrlpad: changing code from swipes to interact

pull/3383/head
Rob Pilling 2023-08-04 23:18:37 +01:00
parent 6c19423c24
commit d9c2bc94dd
1 changed files with 76 additions and 112 deletions

View File

@ -1,4 +1,22 @@
(() => { (() => {
if(!Bangle.prependListener){
type Event<T> = T extends `#on${infer Evt}` ? Evt : never;
Bangle.prependListener = function(
evt: Event<keyof BangleEvents>,
listener: () => void
){
// move our drag to the start of the event listener array
const handlers = (Bangle as BangleEvents)[`#on${evt}`]
if(handlers && typeof handlers !== "function"){
(Bangle as BangleEvents)[`#on${evt}`] = [listener as any].concat(
(handlers as Array<any>).filter((f: unknown) => f !== listener)
);
}
};
}
class Overlay { class Overlay {
g2: Graphics; g2: Graphics;
@ -28,6 +46,10 @@
Bangle.setLCDOverlay(g2, 10, y - 10); Bangle.setLCDOverlay(g2, 10, y - 10);
} }
hide(): void {
Bangle.setLCDOverlay();
}
renderG2(): void { renderG2(): void {
const g = this.g2; const g = this.g2;
@ -80,160 +102,100 @@
} }
let state = State.NoConn; let state = State.NoConn;
let startY = 0; let startY = 0;
const initDistance = 30;
let anchor = {x:0,y:0};
let start = {x:0,y:0};
let dragging = false;
let activeTimeout: TimeoutId | undefined;
let waitForRelease = true;
let overlay: Overlay | undefined; let overlay: Overlay | undefined;
let touchDown = false;
const onDrag = (e => { const onDrag = (e => {
const dragDistance = 30;
if (e.b === 0) touchDown = false;
switch (state) { switch (state) {
case State.NoConn: case State.NoConn:
break; break;
case State.IgnoreCurrent: case State.IgnoreCurrent:
if(e.b === 0) state = State.Idle; if(e.b === 0){
state = State.Idle;
overlay = undefined;
}
break; break;
case State.Idle: case State.Idle:
if(e.b && !activeTimeout){ // no need to check Bangle.CLKINFO_FOCUS if(e.b && !touchDown){ // no need to check Bangle.CLKINFO_FOCUS
// first touch if(e.y <= 40){
if (e.y <= 40){
state = State.TopDrag state = State.TopDrag
startY = e.y; startY = e.y;
console.log(" topdrag detected, starting @ " + startY); console.log(" topdrag detected, starting @ " + startY);
}else{ }else{
console.log(" ignoring this drag (too low @ " + e.y + ")"); console.log(" ignoring this drag (too low @ " + e.y + ")");
state = State.IgnoreCurrent; state = State.IgnoreCurrent;
overlay = undefined
} }
} }
break; break;
case State.TopDrag: case State.TopDrag:
if(e.b === 0){ if(e.b === 0){
console.log("topdrag stopped, distance: " + (e.y - startY)); console.log("topdrag stopped, distance: " + (e.y - startY));
if(e.y > startY + initDistance){ if(e.y > startY + dragDistance){
console.log("activating"); console.log("activating");
state = State.Active;
overlay!.setBottom(g.getHeight());
activate(); activate();
break; break;
} }
console.log("returning to idle"); console.log("returning to idle");
state = State.Idle; state = State.Idle;
Bangle.setLCDOverlay(); overlay?.hide();
overlay = undefined;
}else{ }else{
// partial drag, show UI feedback: // partial drag, show UI feedback:
const dragOffset = 38; const dragOffset = 32;
// @ts-ignore if (!overlay) overlay = new Overlay();
if (!overlay) global.overlay = overlay = new Overlay();
overlay.setBottom(e.y - dragOffset); overlay.setBottom(e.y - dragOffset);
} }
break; break;
case State.Active: case State.Active:
console.log("stolen drag handling, do whatever here"); console.log("stolen drag handling, do whatever here");
if(1)return; E.stopEventPropagation?.();
// Espruino/35c8cb9be11 if(e.b){
E.stopEventPropagation && E.stopEventPropagation(); if(!touchDown){
startY = e.y;
}else if(startY){
const dist = Math.max(0, startY - e.y);
if(e.b === 0){ overlay!.setBottom(g.getHeight() - dist);
// released }
const wasDragging = dragging; }else if(e.b === 0 && startY > dragDistance){
dragging = false; deactivate();
}
if(waitForRelease){ break;
waitForRelease = false;
return;
}
if(!wasDragging // i.e. tap
|| (Math.abs(e.x - anchor.x) < 2 && Math.abs(e.y - anchor.y) < 2))
{
toggle();
onEvent();
return;
}
}
if(waitForRelease) return;
if(e.b && !dragging){
dragging = true;
setStart(e);
Object.assign(anchor, start);
return;
}
const dx = e.x - start.x;
const dy = e.y - start.y;
if(Math.abs(dy) > 25 && Math.abs(dx) > 25){
// diagonal, ignore
setStart(e);
waitForRelease = true;
return;
}
// had a drag in a single axis
if(dx > 40){ next(); onEvent(); waitForRelease = true; }
else if(dx < -40){ prev(); onEvent(); waitForRelease = true; }
else if(dy > 30){ down(); onEvent(); setStart(e); }
else if(dy < -30){ up(); onEvent(); setStart(e); }
break;
} }
if(e.b) touchDown = true;
}) satisfies DragCallback; }) satisfies DragCallback;
const onTouch = ((_btn, _xy) => {
// TODO: button presses
}) satisfies TouchCallback;
const activate = () => { const activate = () => {
listen(); state = State.Active;
startY = 0;
Bangle.prependListener("touch", onTouch);
Bangle.buzz(20); Bangle.buzz(20);
overlay!.setBottom(g.getHeight());
}; };
const setStart = ({ x, y }: { x: number, y: number }) => { const deactivate = () => {
start.x = x; Bangle.removeListener("touch", onTouch);
start.y = y; state = State.Idle;
}; overlay?.hide();
};
const onEvent = () => { Bangle.prependListener("drag", onDrag);
Bangle.buzz(20); // feedback event sent
listen(); // had an event, keep listening for more
};
const listen = () => { const redraw = () => setTimeout(Bangle.drawWidgets, 10);
const wasActive = !!activeTimeout;
if(!wasActive){
waitForRelease = true; // wait for first touch up before accepting gestures
//Bangle.on("drag", onDrag);
// move our drag to the start of the event listener array
const dragHandlers = (Bangle as BangleEvents)["#ondrag"]
if(dragHandlers && typeof dragHandlers !== "function"){
(Bangle as BangleEvents)["#ondrag"] = [onDrag as undefined | typeof onDrag].concat(
dragHandlers.filter((f: unknown) => f !== onDrag)
);
}
redraw();
}
if(activeTimeout) clearTimeout(activeTimeout);
activeTimeout = setTimeout(() => {
activeTimeout = undefined;
//Bangle.removeListener("drag", onDrag);
redraw();
}, 3000);
};
Bangle.on("drag", onDrag);
const redraw = () => setTimeout(Bangle.drawWidgets, 50);
const connected = NRF.getSecurityStatus().connected; const connected = NRF.getSecurityStatus().connected;
WIDGETS["hid"] = { WIDGETS["hid"] = {
@ -242,7 +204,7 @@
draw: function() { draw: function() {
if(this.width === 0) return; if(this.width === 0) return;
g.drawImage( g.drawImage(
activeTimeout state === State.Active
? require("heatshrink").decompress(atob("jEYxH+AEfH44XXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")) ? require("heatshrink").decompress(atob("jEYxH+AEfH44XXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA=="))
: require("heatshrink").decompress(atob("jEYxH+AEcdjoXXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")), : require("heatshrink").decompress(atob("jEYxH+AEcdjoXXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")),
this.x! + 2, this.x! + 2,
@ -281,9 +243,11 @@
} }
}; };
const next = () => /*DEBUG ? console.log("next") : */ sendHid(0x01); const hid = {
const prev = () => /*DEBUG ? console.log("prev") : */ sendHid(0x02); next: () => /*DEBUG ? console.log("next") : */ sendHid(0x01),
const toggle = () => /*DEBUG ? console.log("toggle") : */ sendHid(0x10); prev: () => /*DEBUG ? console.log("prev") : */ sendHid(0x02),
const up = () => /*DEBUG ? console.log("up") : */ sendHid(0x40); toggle: () => /*DEBUG ? console.log("toggle") : */ sendHid(0x10),
const down = () => /*DEBUG ? console.log("down") : */ sendHid(0x80); up: () => /*DEBUG ? console.log("up") : */ sendHid(0x40),
down: () => /*DEBUG ? console.log("down") : */ sendHid(0x80),
};
})() })()