feat: implements node drag and drop

This commit is contained in:
Mark Mankarious 2023-04-03 01:05:20 +01:00
parent 3848a648f0
commit b350320387
7 changed files with 107 additions and 18 deletions

View file

@ -5,7 +5,11 @@ import { Mouse } from "./types";
export class ModeManager {
renderer?: Renderer = undefined;
currentMode?: ModeBase = undefined;
currentMode?: {
instance: ModeBase;
class: typeof ModeBase;
};
lastMode?: typeof ModeBase;
mouse: Mouse = {
position: { x: 0, y: 0 },
delta: null,
@ -19,19 +23,34 @@ export class ModeManager {
this.renderer = renderer;
}
activateMode(Mode: typeof ModeBase) {
activateMode<T extends typeof ModeBase>(
Mode: T,
init?: (instance: InstanceType<T>) => void
) {
if (!this.renderer) return;
const lastMode = this.currentMode;
this.currentMode?.exit();
if (this.currentMode) {
this.currentMode.instance.exit();
this.lastMode = this.currentMode.class;
}
this.currentMode = new Mode({
renderer: this.renderer,
activateMode: this.activateMode.bind(this),
deactivate: lastMode?.exit ?? (() => {}),
});
this.currentMode = {
instance: new Mode({
renderer: this.renderer,
activateMode: this.activateMode.bind(this),
deactivate: this.deactivate.bind(this),
}),
class: Mode,
};
this.currentMode.entry(this.mouse);
init?.(this.currentMode.instance as InstanceType<T>);
this.currentMode.instance.entry(this.mouse);
}
deactivate() {
if (!this.lastMode) return;
this.activateMode(this.lastMode);
}
onMouseEvent(eventName: string, mouse: Mouse) {
@ -43,6 +62,6 @@ export class ModeManager {
send(eventName: string, params?: any) {
// TODO: Improve typings below
// @ts-ignore
this.currentMode?.[eventName]?.(params);
this.currentMode.instance?.[eventName]?.(params);
}
}

View file

@ -1,5 +1,8 @@
import { ModeBase } from "./ModeBase";
import { Mouse } from "./types";
import { getTargetFromSelection } from "./utils";
import { SelectNode } from "./SelectNode";
import { Node } from "../renderer/elements/Node";
export class Select extends ModeBase {
entry(mouse: Mouse) {
@ -24,6 +27,20 @@ export class Select extends ModeBase {
this.ctx.renderer.sceneElements.cursor.disable();
}
MOUSE_DOWN(mouse: Mouse) {
const { renderer } = this.ctx;
const { x, y } = renderer.getTileFromMouse(
mouse.position.x,
mouse.position.y
);
const items = renderer.getItemsByTile(x, y);
const target = getTargetFromSelection(items);
if (target instanceof Node) {
this.ctx.activateMode(SelectNode, (instance) => (instance.node = target));
}
}
MOUSE_MOVE(mouse: Mouse) {
const tile = this.ctx.renderer.getTileFromMouse(
mouse.position.x,

26
src/modes/SelectNode.ts Normal file
View file

@ -0,0 +1,26 @@
import { ModeBase } from "./ModeBase";
import { Mouse, ModeContext } from "./types";
import { Node } from "../renderer/elements/Node";
export class SelectNode extends ModeBase {
node?: Node;
constructor(ctx: ModeContext) {
super(ctx);
}
MOUSE_MOVE(mouse: Mouse) {
if (!this.node) return;
const tile = this.ctx.renderer.getTileFromMouse(
mouse.position.x,
mouse.position.y
);
this.node.moveTo(tile.x, tile.y);
}
MOUSE_UP() {
this.ctx.deactivate();
}
}

View file

@ -1,5 +1,5 @@
import { Renderer } from "../renderer/Renderer";
import type { ModeBase } from "./ModeBase";
import type { ModeManager } from "./ModeManager";
export interface Mode {
initial: string;
@ -19,6 +19,6 @@ export interface Mouse {
export interface ModeContext {
renderer: Renderer;
activateMode: (mode: typeof ModeBase) => void;
deactivate: () => void;
activateMode: ModeManager["activateMode"];
deactivate: ModeManager["deactivate"];
}

11
src/modes/utils.ts Normal file
View file

@ -0,0 +1,11 @@
import { Node } from "../renderer/elements/Node";
export const getTargetFromSelection = (items: (Node | undefined)[]) => {
const node = items.find((item) => item instanceof Node);
if (node) {
return node;
}
return null;
};

View file

@ -258,6 +258,12 @@ export class Renderer {
this.callbacks.onSceneChange(sceneEvent.event, this.exportScene());
}
getItemsByTile(x: number, y: number) {
const node = this.nodes.getNodeByTile(x, y);
return [node].filter((i) => Boolean(i));
}
get nodes() {
return this.sceneElements.nodes;
}

View file

@ -19,10 +19,6 @@ export class Nodes {
this.ctx = ctx;
}
getNodeById(id: string) {
return this.nodes.find((node) => node.id === id);
}
addNode(options: NodeOptions, sceneEvent?: SceneEvent) {
const node = new Node(
this.ctx,
@ -51,9 +47,23 @@ export class Nodes {
onMove(x: number, y: number, node: Node) {
const tile = this.ctx.getTileBounds(x, y);
node.position = {
x,
y,
};
node.container.position.set(tile.bottom);
}
getNodeById(id: string) {
return this.nodes.find((node) => node.id === id);
}
getNodeByTile(x: number, y: number) {
return this.nodes.find(
(node) => node.position.x === x && node.position.y === y
);
}
clear() {
this.nodes.forEach((node) => node.destroy());
this.nodes = [];