ctrlpad restucture: controls class

pull/3383/head
Rob Pilling 2023-08-28 22:30:38 +01:00
parent 40a1b1a209
commit 639afaa20a
1 changed files with 117 additions and 97 deletions

View File

@ -25,11 +25,6 @@
}; };
} }
type Control = {
text: string,
cb: () => void,
};
class Overlay { class Overlay {
g2: Graphics; g2: Graphics;
width: number; width: number;
@ -63,43 +58,73 @@
} }
renderG2(): void { renderG2(): void {
const g = this.g2; this.g2
g
.reset() .reset()
.clearRect(0, 0, this.width, this.height) .clearRect(0, 0, this.width, this.height)
.drawRect(0, 0, this.width - 1, this.height - 1) .drawRect(0, 0, this.width - 1, this.height - 1)
.drawRect(1, 1, this.width - 2, this.height - 2); .drawRect(1, 1, this.width - 2, this.height - 2);
}
}
type Control = {
x: number,
y: number,
text: string,
cb: () => void,
};
class Controls {
controls: [Control, Control, Control, Control, Control];
constructor(g: Graphics) {
// const connected = NRF.getSecurityStatus().connected;
// if (0&&connected) {
// // TODO
// return [
// { text: "<", cb: hid.next },
// { text: "@", cb: hid.toggle },
// { text: ">", cb: hid.prev },
// { text: "-", cb: hid.down },
// { text: "+", cb: hid.up },
// ];
// }
const height = g.getHeight();
const centreY = height / 2;
const circleGapY = 30;
const width = g.getWidth();
this.controls = [
{ x: width / 4 - 10, y: centreY - circleGapY, text: "BLE", cb: function() { console.log(this.text); } },
{ x: width / 2, y: centreY - circleGapY, text: "DnD", cb: function() { console.log(this.text); } },
{ x: width * 3/4 + 10, y: centreY - circleGapY, text: "?", cb: function() { console.log(this.text); } },
{ x: width / 3, y: centreY + circleGapY, text: "B-", cb: function() { console.log(this.text); } },
{ x: width * 2/3, y: centreY + circleGapY, text: "B+", cb: function() { console.log(this.text); } },
];
}
draw(g: Graphics): void {
g g
.setFontAlign(0, 0) .setFontAlign(0, 0)
.setFont("Vector:20"); .setFont("Vector:20");
this.drawCtrls(); for(const ctrl of this.controls){
g
.setColor("#fff")
.fillCircle(ctrl.x, ctrl.y, 23)
.setColor("#000")
.drawString(ctrl.text, ctrl.x, ctrl.y);
}
} }
drawCtrls(): void { hitTest(x: number, y: number): Control | undefined {
const centreY = this.height / 2; const radius = 25;
const circleGapY = 30;
const controls = getControls(); for(const ctrl of this.controls)
if(Math.abs(y - ctrl.y) < radius && Math.abs(x - ctrl.x) < radius)
return ctrl;
this.drawCtrl(this.width / 4 - 10, centreY - circleGapY, controls[0].text); return undefined;
this.drawCtrl(this.width / 2, centreY - circleGapY, controls[1].text);
this.drawCtrl(this.width * 3/4 + 10, centreY - circleGapY, controls[2].text);
this.drawCtrl(this.width / 3, centreY + circleGapY, controls[3].text);
this.drawCtrl(this.width * 2/3, centreY + circleGapY, controls[4].text);
}
drawCtrl(x: number, y: number, label: string): void {
const g = this.g2;
g
.setColor("#fff")
.fillCircle(x, y, 23)
.setColor("#000")
.drawString(label, x, y);
} }
} }
@ -121,31 +146,9 @@
let startY = 0; let startY = 0;
let startedUpDrag = false; let startedUpDrag = false;
let upDragAnim: IntervalId | undefined; let upDragAnim: IntervalId | undefined;
let overlay: Overlay | undefined; let ui: undefined | { overlay: Overlay, ctrls: Controls };
let touchDown = false; let touchDown = false;
type Controls = [Control, Control, Control, Control, Control];
const getControls = (): Controls => {
const connected = NRF.getSecurityStatus().connected;
if (connected) {
return [
{ text: "<", cb: hid.next },
{ text: "@", cb: hid.toggle },
{ text: ">", cb: hid.prev },
{ text: "-", cb: hid.down },
{ text: "+", cb: hid.up },
];
}
return [
{ text: "a", cb: () => {} },
{ text: "b", cb: () => {} },
{ text: "c", cb: () => {} },
{ text: "d", cb: () => {} },
{ text: "e", cb: () => {} },
];
};
const onDrag = (e => { const onDrag = (e => {
const dragDistance = 30; const dragDistance = 30;
@ -155,7 +158,7 @@
case State.IgnoreCurrent: case State.IgnoreCurrent:
if(e.b === 0){ if(e.b === 0){
state = State.Idle; state = State.Idle;
overlay = undefined; ui = undefined;
} }
break; break;
@ -168,7 +171,7 @@
}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 ui = undefined
} }
} }
break; break;
@ -182,24 +185,31 @@
startY = 0; startY = 0;
Bangle.prependListener("touch", onTouch); Bangle.prependListener("touch", onTouch);
Bangle.buzz(20); Bangle.buzz(20);
overlay!.setBottom(g.getHeight()); ui!.overlay.setBottom(g.getHeight());
break; break;
} }
console.log("returning to idle"); console.log("returning to idle");
state = State.Idle; state = State.Idle;
overlay?.hide(); ui?.overlay.hide();
overlay = undefined; ui = undefined;
}else{ }else{
// partial drag, show UI feedback: // partial drag, show UI feedback:
const dragOffset = 32; const dragOffset = 32;
if (!overlay) overlay = new Overlay(); if (!ui) {
overlay.setBottom(e.y - dragOffset); const overlay = new Overlay();
ui = {
overlay,
ctrls: new Controls(overlay.g2),
};
ui.ctrls.draw(ui.overlay.g2);
}
ui.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");
E.stopEventPropagation?.(); E.stopEventPropagation?.();
if(e.b){ if(e.b){
if(!touchDown){ if(!touchDown){
@ -208,34 +218,44 @@
const dist = Math.max(0, startY - e.y); const dist = Math.max(0, startY - e.y);
if (startedUpDrag || (startedUpDrag = dist > 10)) // ignore small drags if (startedUpDrag || (startedUpDrag = dist > 10)) // ignore small drags
overlay!.setBottom(g.getHeight() - dist); ui!.overlay.setBottom(g.getHeight() - dist);
} }
}else if(e.b === 0 && startY > dragDistance){ }else if(e.b === 0){
let bottom = g.getHeight() - Math.max(0, startY - e.y); if((startY - e.y) > dragDistance){
let bottom = g.getHeight() - Math.max(0, startY - e.y);
if (upDragAnim) clearInterval(upDragAnim); if (upDragAnim) clearInterval(upDragAnim);
upDragAnim = setInterval(() => { upDragAnim = setInterval(() => {
if (!overlay || bottom <= 0) { if (!ui || bottom <= 0) {
clearInterval(upDragAnim!); clearInterval(upDragAnim!);
upDragAnim = undefined; upDragAnim = undefined;
overlay?.hide(); ui?.overlay.hide();
overlay = undefined; ui = undefined;
return; return;
} }
overlay?.setBottom(bottom); ui!.overlay.setBottom(bottom);
bottom -= 10; bottom -= 30;
}, 50) }, 50)
Bangle.removeListener("touch", onTouch); Bangle.removeListener("touch", onTouch);
state = State.Idle; state = State.Idle;
}else{
ui!.overlay.setBottom(g.getHeight());
}
} }
break; break;
} }
if(e.b) touchDown = true; if(e.b) touchDown = true;
}) satisfies DragCallback; }) satisfies DragCallback;
const onTouch = ((_btn, _xy) => { const onTouch = ((_btn, xy) => {
// TODO: button presses if(!ui || !xy) return;
const top = g.getHeight() - ui.overlay.height; // assumed anchored to bottom
const left = (g.getWidth() - ui.overlay.width) / 2; // more assumptions
const ctrl = ui.ctrls.hitTest(xy.x - left, xy.y - top);
ctrl?.cb();
}) satisfies TouchCallback; }) satisfies TouchCallback;
Bangle.prependListener("drag", onDrag); Bangle.prependListener("drag", onDrag);
@ -248,23 +268,23 @@
}; };
//const DEBUG = true; //const DEBUG = true;
const sendHid = (code: number) => { //const sendHid = (code: number) => {
//if(DEBUG) return; // //if(DEBUG) return;
try{ // try{
NRF.sendHIDReport( // NRF.sendHIDReport(
[1, code], // [1, code],
() => NRF.sendHIDReport([1, 0]), // () => NRF.sendHIDReport([1, 0]),
); // );
}catch(e){ // }catch(e){
console.log("sendHIDReport:", e); // console.log("sendHIDReport:", e);
} // }
}; //};
const hid = { // const hid = {
next: () => sendHid(0x01), // next: () => sendHid(0x01),
prev: () => sendHid(0x02), // prev: () => sendHid(0x02),
toggle: () => sendHid(0x10), // toggle: () => sendHid(0x10),
up: () => sendHid(0x40), // up: () => sendHid(0x40),
down: () => sendHid(0x80), // down: () => sendHid(0x80),
}; // };
})() })()