Skip to content
125 changes: 93 additions & 32 deletions js/activity.js
Original file line number Diff line number Diff line change
Expand Up @@ -505,22 +505,75 @@ class Activity {

/*
* Sets up right click functionality opening the context menus
* (if block is right clicked)
* (if block is right clicked or long-pressed)
*/
this.doContextMenus = () => {
document.addEventListener(
"contextmenu",
(event) => {
event.preventDefault();
event.stopPropagation();
if (this.beginnerMode) return;
if (!this.blocks.isCoordinateOnBlock(event.clientX, event.clientY) &&
event.target.id === "myCanvas") {
this._displayHelpfulWheel(event);
}
},
false
);
let longPressTimer = null;
const LONG_PRESS_DURATION = 500;

// Handle right-click (contextmenu event)
document.addEventListener("contextmenu", (event) => {
event.preventDefault();
event.stopPropagation();
if (!this.beginnerMode && !this.blocks.isCoordinateOnBlock(event.clientX, event.clientY) &&
event.target.id === "myCanvas") {
this._displayHelpfulWheel(event);
}
}, false);

// Handle touch start (long-press)
document.addEventListener("touchstart", (event) => {
if (event.touches.length !== 1) return;
event.preventDefault();

const touch = event.touches[0];
const isOnBlock = this.blocks.isCoordinateOnBlock(touch.clientX, touch.clientY);

if (touch.target.id === "myCanvas") {
if (!isOnBlock && !this.beginnerMode) {
// Handle canvas long press for helpful wheel
longPressTimer = setTimeout(() => {
this._displayHelpfulWheel({
clientX: touch.clientX,
clientY: touch.clientY,
preventDefault: () => {},
stopPropagation: () => {},
target: touch.target
});
}, LONG_PRESS_DURATION);
} else {
// Handle block long press for block menu
longPressTimer = setTimeout(() => {
const block = this.blocks.blockList.find(b => {
// Manual coordinate transformation
const containerX = b.container.x;
const containerY = b.container.y;
const scaleX = b.container.scaleX || 1;
const scaleY = b.container.scaleY || 1;

const localX = (touch.clientX - containerX) / scaleX;
const localY = (touch.clientY - containerY) / scaleY;

const isHit = b.container.hitTest(localX, localY);
return isHit;
});
piemenuBlockContext(block);
}, LONG_PRESS_DURATION);
}
}
}, false);

// Clear timer if touch ends or moves
const clearTimer = () => {
if (longPressTimer) {
clearTimeout(longPressTimer);
longPressTimer = null;
}
};

document.addEventListener("touchmove", clearTimer, false);
document.addEventListener("touchend", clearTimer, false);
document.addEventListener("touchcancel", clearTimer, false);
};

/*
Expand Down Expand Up @@ -554,6 +607,18 @@ class Activity {

docById("helpfulWheelDiv").style.display = "";

docById("helpfulWheelDiv").addEventListener('touchstart', (e) => {
e.stopPropagation();
}, true);

docById("helpfulWheelDiv").addEventListener('touchend', (e) => {
e.stopPropagation();
}, true);

docById("helpfulWheelDiv").addEventListener('touchmove', (e) => {
e.stopPropagation();
}, true);

const wheel = new wheelnav("helpfulWheelDiv", null, 300, 300);
wheel.colors = platformColor.wheelcolors;
wheel.slicePathFunction = slicePath().DonutSlice;
Expand Down Expand Up @@ -1916,62 +1981,58 @@ class Activity {
// Assuming you have defined 'that' and 'closeAnyOpenMenusAndLabels' elsewhere in your code

const myCanvas = document.getElementById("myCanvas");
const initialTouches = [[null, null], [null, null]]; // Array to track two fingers (Y and X coordinates)
const initialTouches = [[null, null], [null, null]];

/**
* Handles touch start event on the canvas.
* @param {TouchEvent} event - The touch event object.
*/
myCanvas.addEventListener("touchstart", (event) => {
if (event.touches.length === 2) {
event.preventDefault();
for (let i = 0; i < 2; i++) {
initialTouches[i][0] = event.touches[i].clientY;
initialTouches[i][1] = event.touches[i].clientX;
}
that.inTwoFingerScroll = true;
}
});
}, { passive: false });

/**
* Handles touch move event on the canvas.
* @param {TouchEvent} event - The touch event object.
*/
myCanvas.addEventListener("touchmove", (event) => {
if (event.touches.length === 2) {
if (event.touches.length === 2 && that.inTwoFingerScroll) {
for (let i = 0; i < 2; i++) {
const touchY = event.touches[i].clientY;
const touchX = event.touches[i].clientX;

if (initialTouches[i][0] !== null && initialTouches[i][1] !== null) {
const deltaY = touchY - initialTouches[i][0];
const deltaX = touchX - initialTouches[i][1];

if (deltaY !== 0) {
closeAnyOpenMenusAndLabels();
that.blocksContainer.y -= deltaY;
that.blocksContainer.y += deltaY;
}

if (deltaX !== 0) {
closeAnyOpenMenusAndLabels();
that.blocksContainer.x -= deltaX;
that.blocksContainer.x += deltaX;
}

initialTouches[i][0] = touchY;
initialTouches[i][1] = touchX;
}
that.refreshCanvas();
}

that.refreshCanvas();
}
});
}, { passive: false });

/**
* Handles touch end event on the canvas.
*/
myCanvas.addEventListener("touchend", () => {
that.inTwoFingerScroll = false;
for (let i = 0; i < 2; i++) {
initialTouches[i][0] = null;
initialTouches[i][1] = null;
}
that.refreshCanvas();
});

/**
Expand Down
15 changes: 12 additions & 3 deletions js/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const STRINGLEN = 9;
* Length of a long touch in milliseconds.
* @type {number}
*/
const LONGPRESSTIME = 1500;
const LONGPRESSTIME = 500;
const INLINECOLLAPSIBLES = ["newnote", "interval", "osctime", "definemode"];

/**
Expand Down Expand Up @@ -2882,7 +2882,12 @@ class Block {
* Handles the mousedown event on the block container.
* @param {Event} event - The mousedown event.
*/
this.container.on("mousedown", (event) =>{
this.container.on("mousedown", (event) => {
if (event.nativeEvent) {
event.nativeEvent.preventDefault();
}
event.stopPropagation();

docById("contextWheelDiv").style.display = "none";

// Track time for detecting long pause...
Expand Down Expand Up @@ -2926,7 +2931,11 @@ class Block {
*/
this.container.on("pressmove", (event) =>{
// FIXME: More voodoo
event.nativeEvent.preventDefault();
if (event.nativeEvent) {
event.nativeEvent.preventDefault();
} else {
event.preventDefault();
}

// Don't allow silence block to be dragged out of a note.
if (that.name === "rest2") {
Expand Down
11 changes: 11 additions & 0 deletions js/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2379,6 +2379,11 @@ class Blocks {
* @returns {void}
*/
this._moveBlock = (blk, x, y) => {
// If doing two-finger scroll, don't process any block movements
if (this.activity.inTwoFingerScroll) {
return;
}

const myBlock = this.blockList[blk];
if (myBlock.container != null) {
/** Round position so font renders clearly. */
Expand All @@ -2401,6 +2406,11 @@ class Blocks {
* @returns {void}
*/
this.moveBlockRelative = (blk, dx, dy) => {
// If doing two-finger scroll, don't allow block disconnection
if (this.activity.inTwoFingerScroll) {
return;
}

this.inLongPress = false;
this.isBlockMoving = true;
const myBlock = this.blockList[blk];
Expand Down Expand Up @@ -5013,6 +5023,7 @@ class Blocks {
}

this.inLongPress = true;

piemenuBlockContext(this.blockList[this.activeBlock]);
};

Expand Down
12 changes: 12 additions & 0 deletions js/piemenus.js
Original file line number Diff line number Diff line change
Expand Up @@ -3341,6 +3341,18 @@ const piemenuBlockContext = (block) => {

docById("contextWheelDiv").style.display = "";

docById("contextWheelDiv").addEventListener('touchstart', (e) => {
e.stopPropagation();
}, true);

docById("contextWheelDiv").addEventListener('touchend', (e) => {
e.stopPropagation();
}, true);

docById("contextWheelDiv").addEventListener('touchmove', (e) => {
e.stopPropagation();
}, true);

const labels = [
"imgsrc:header-icons/copy-button.svg",
"imgsrc:header-icons/extract-button.svg",
Expand Down