Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 31 additions & 28 deletions src/actions/mover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import type {BlockSvg, IDragger, IDragStrategy} from 'blockly';
import {Navigation} from '../navigation';
import {KeyboardDragStrategy} from '../keyboard_drag_strategy';
import {Direction, getXYFromDirection} from '../drag_direction';

const KeyCodes = utils.KeyCodes;
const createSerializedKey = ShortcutRegistry.registry.createSerializedKey.bind(
Expand Down Expand Up @@ -87,28 +88,28 @@ export class Mover {
{
name: 'Move left, constrained',
preconditionFn: (workspace) => this.isMoving(workspace),
callback: (workspace) => this.moveConstrained(workspace /* , ...*/),
callback: (workspace) => this.moveConstrained(workspace, Direction.Left),
keyCodes: [KeyCodes.LEFT],
allowCollision: true,
},
{
name: 'Move right unconstrained',
preconditionFn: (workspace) => this.isMoving(workspace),
callback: (workspace) => this.moveConstrained(workspace /* , ... */),
callback: (workspace) => this.moveConstrained(workspace, Direction.Right),
keyCodes: [KeyCodes.RIGHT],
allowCollision: true,
},
{
name: 'Move up, constrained',
preconditionFn: (workspace) => this.isMoving(workspace),
callback: (workspace) => this.moveConstrained(workspace /* , ... */),
callback: (workspace) => this.moveConstrained(workspace, Direction.Up),
keyCodes: [KeyCodes.UP],
allowCollision: true,
},
{
name: 'Move down constrained',
preconditionFn: (workspace) => this.isMoving(workspace),
callback: (workspace) => this.moveConstrained(workspace /* , ... */),
callback: (workspace) => this.moveConstrained(workspace, Direction.Down),
keyCodes: [KeyCodes.DOWN],
allowCollision: true,
},
Expand All @@ -117,7 +118,8 @@ export class Mover {
{
name: 'Move left, unconstrained',
preconditionFn: (workspace) => this.isMoving(workspace),
callback: (workspace) => this.moveUnconstrained(workspace, -1, 0),
callback: (workspace) =>
this.moveUnconstrained(workspace, Direction.Left),
keyCodes: [
createSerializedKey(KeyCodes.LEFT, [KeyCodes.ALT]),
createSerializedKey(KeyCodes.LEFT, [KeyCodes.CTRL]),
Expand All @@ -126,7 +128,8 @@ export class Mover {
{
name: 'Move right, unconstrained',
preconditionFn: (workspace) => this.isMoving(workspace),
callback: (workspace) => this.moveUnconstrained(workspace, 1, 0),
callback: (workspace) =>
this.moveUnconstrained(workspace, Direction.Right),
keyCodes: [
createSerializedKey(KeyCodes.RIGHT, [KeyCodes.ALT]),
createSerializedKey(KeyCodes.RIGHT, [KeyCodes.CTRL]),
Expand All @@ -135,7 +138,7 @@ export class Mover {
{
name: 'Move up unconstrained',
preconditionFn: (workspace) => this.isMoving(workspace),
callback: (workspace) => this.moveUnconstrained(workspace, 0, -1),
callback: (workspace) => this.moveUnconstrained(workspace, Direction.Up),
keyCodes: [
createSerializedKey(KeyCodes.UP, [KeyCodes.ALT]),
createSerializedKey(KeyCodes.UP, [KeyCodes.CTRL]),
Expand All @@ -144,7 +147,8 @@ export class Mover {
{
name: 'Move down, unconstrained',
preconditionFn: (workspace) => this.isMoving(workspace),
callback: (workspace) => this.moveUnconstrained(workspace, 0, 1),
callback: (workspace) =>
this.moveUnconstrained(workspace, Direction.Down),
keyCodes: [
createSerializedKey(KeyCodes.DOWN, [KeyCodes.ALT]),
createSerializedKey(KeyCodes.DOWN, [KeyCodes.CTRL]),
Expand Down Expand Up @@ -320,17 +324,18 @@ export class Mover {
* constrained to valid attachment points (if any).
*
* @param workspace The workspace to move on.
* @param direction The direction to move the dragged item.
* @returns True iff this action applies and has been performed.
*/
moveConstrained(
workspace: WorkspaceSvg,
/* ... */
) {
// Not yet implemented. Absorb keystroke to avoid moving cursor.
alert(`Constrained movement not implemented.
moveConstrained(workspace: WorkspaceSvg, direction: Direction) {
if (!workspace) return false;
const info = this.moves.get(workspace);
if (!info) throw new Error('no move info for workspace');

Use ctrl+arrow or alt+arrow (option+arrow on macOS) for unconstrained move.
Use enter to complete the move, or escape to abort.`);
info.dragger.onDrag(
info.fakePointerEvent('pointermove', direction),
info.totalDelta,
);
return true;
}

Expand All @@ -339,23 +344,17 @@ Use enter to complete the move, or escape to abort.`);
* without constraint.
*
* @param workspace The workspace to move on.
* @param xDirection -1 to move left. 1 to move right.
* @param yDirection -1 to move up. 1 to move down.
* @param direction The direction to move the dragged item.
* @returns True iff this action applies and has been performed.
*/
moveUnconstrained(
workspace: WorkspaceSvg,
xDirection: number,
yDirection: number,
): boolean {
moveUnconstrained(workspace: WorkspaceSvg, direction: Direction): boolean {
if (!workspace) return false;
const info = this.moves.get(workspace);
if (!info) throw new Error('no move info for workspace');

info.totalDelta.x +=
xDirection * UNCONSTRAINED_MOVE_DISTANCE * workspace.scale;
info.totalDelta.y +=
yDirection * UNCONSTRAINED_MOVE_DISTANCE * workspace.scale;
const {x, y} = getXYFromDirection(direction);
info.totalDelta.x += x * UNCONSTRAINED_MOVE_DISTANCE * workspace.scale;
info.totalDelta.y += y * UNCONSTRAINED_MOVE_DISTANCE * workspace.scale;

info.dragger.onDrag(info.fakePointerEvent('pointermove'), info.totalDelta);
return true;
Expand Down Expand Up @@ -446,10 +445,11 @@ export class MoveInfo {
* Create a fake pointer event for dragging.
*
* @param type Which type of pointer event to create.
* @param direction The direction if this movement is a constrained drag.
* @returns A synthetic PointerEvent that can be consumed by Blockly's
* dragging code.
*/
fakePointerEvent(type: string): PointerEvent {
fakePointerEvent(type: string, direction?: Direction): PointerEvent {
const workspace = this.block.workspace;
if (!(workspace instanceof WorkspaceSvg)) throw new TypeError();

Expand All @@ -460,9 +460,12 @@ export class MoveInfo {
this.startLocation.y + this.totalDelta.y,
),
);
const tilts = getXYFromDirection(direction);
return new PointerEvent(type, {
clientX: blockCoords.x,
clientY: blockCoords.y,
tiltX: tilts.x,
tiltY: tilts.y,
});
}
}
21 changes: 20 additions & 1 deletion src/keyboard_drag_strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,33 @@
* SPDX-License-Identifier: Apache-2.0
*/

import {dragging} from 'blockly';
import {dragging, utils} from 'blockly';
import {Direction, getDirectionFromXY} from './drag_direction';

export class KeyboardDragStrategy extends dragging.BlockDragStrategy {
private currentDragDirection: Direction | null = null;

override startDrag(e?: PointerEvent) {
super.startDrag(e);
// Set position of the dragging block, so that it doesn't pop
// to the top left of the workspace.
// @ts-expect-error block and startLoc are private.
this.block.moveDuringDrag(this.startLoc);
}

override drag(newLoc: utils.Coordinate, e?: PointerEvent): void {
if (!e) return;
this.currentDragDirection = getDirectionFromXY({x: e.tiltX, y: e.tiltY});
super.drag(newLoc);
}

/**
* Get whether the most recent drag event represents a constrained
* keyboard drag.
*
* @returns true if the current movement is constrained, otherwise false.
*/
private isConstrainedMovement(): boolean {
return !!this.currentDragDirection;
}
}