mirror of
https://github.com/DaanVandenBosch/phantasmal-world.git
synced 2025-04-06 08:08:28 +08:00
Entity drag and drop code doesn't use custom events anymore for increased performance and simplicity. Made code more typesafe and decoupled. Fixed some bugs.
This commit is contained in:
parent
4293a3862b
commit
6e666b0ea5
@ -72,10 +72,10 @@ export abstract class Renderer implements Disposable {
|
|||||||
this.schedule_render();
|
this.schedule_render();
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer_pos_to_device_coords(v: Vector2): Vector2 {
|
pointer_pos_to_device_coords(e: MouseEvent): Vector2 {
|
||||||
const coords = this.renderer.getSize(new Vector2());
|
const coords = this.renderer.getSize(new Vector2());
|
||||||
coords.width = (v.x / coords.width) * 2 - 1;
|
coords.width = (e.offsetX / coords.width) * 2 - 1;
|
||||||
coords.height = (v.y / coords.height) * -2 + 1;
|
coords.height = (e.offsetY / coords.height) * -2 + 1;
|
||||||
return coords;
|
return coords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ import { bind_children_to, el } from "../../core/gui/dom";
|
|||||||
import "./EntityListView.css";
|
import "./EntityListView.css";
|
||||||
import { entity_data, EntityType } from "../../core/data_formats/parsing/quest/entities";
|
import { entity_data, EntityType } from "../../core/data_formats/parsing/quest/entities";
|
||||||
import { ListProperty } from "../../core/observable/property/list/ListProperty";
|
import { ListProperty } from "../../core/observable/property/list/ListProperty";
|
||||||
import { Vec2 } from "../../core/data_formats/vector";
|
import { entity_dnd_source } from "./entity_dnd";
|
||||||
import { Disposable } from "../../core/observable/Disposable";
|
|
||||||
|
|
||||||
export abstract class EntityListView<T extends EntityType> extends ResizableWidget {
|
export abstract class EntityListView<T extends EntityType> extends ResizableWidget {
|
||||||
readonly element: HTMLElement;
|
readonly element: HTMLElement;
|
||||||
@ -19,7 +18,7 @@ export abstract class EntityListView<T extends EntityType> extends ResizableWidg
|
|||||||
this.disposables(
|
this.disposables(
|
||||||
bind_children_to(list_element, entities, this.create_entity_element),
|
bind_children_to(list_element, entities, this.create_entity_element),
|
||||||
|
|
||||||
make_draggable(list_element, target => {
|
entity_dnd_source(list_element, target => {
|
||||||
if (target !== list_element) {
|
if (target !== list_element) {
|
||||||
const drag_element = target.cloneNode(true) as HTMLElement;
|
const drag_element = target.cloneNode(true) as HTMLElement;
|
||||||
drag_element.style.width = "100px";
|
drag_element.style.width = "100px";
|
||||||
@ -43,119 +42,3 @@ export abstract class EntityListView<T extends EntityType> extends ResizableWidg
|
|||||||
return div;
|
return div;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EntityDrag = {
|
|
||||||
readonly offset_x: number;
|
|
||||||
readonly offset_y: number;
|
|
||||||
readonly data_transfer: DataTransfer;
|
|
||||||
readonly drag_element: HTMLElement;
|
|
||||||
readonly entity_type: EntityType;
|
|
||||||
};
|
|
||||||
|
|
||||||
function make_draggable(
|
|
||||||
element: HTMLElement,
|
|
||||||
start: (target: HTMLElement) => [HTMLElement, any] | undefined,
|
|
||||||
): Disposable {
|
|
||||||
let detail: { drag_element: HTMLElement; entity_type: EntityType } | undefined;
|
|
||||||
const grab_point = new Vec2(0, 0);
|
|
||||||
|
|
||||||
function clear(): void {
|
|
||||||
if (detail) {
|
|
||||||
detail.drag_element.remove();
|
|
||||||
detail = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function redispatch(e: DragEvent): void {
|
|
||||||
if (e.target instanceof HTMLElement && detail && e.dataTransfer) {
|
|
||||||
e.target.dispatchEvent(
|
|
||||||
new CustomEvent<EntityDrag>(`phantasmal-${e.type}`, {
|
|
||||||
detail: {
|
|
||||||
...detail,
|
|
||||||
data_transfer: e.dataTransfer,
|
|
||||||
offset_x: e.offsetX,
|
|
||||||
offset_y: e.offsetY,
|
|
||||||
},
|
|
||||||
bubbles: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dragstart(e: DragEvent): void {
|
|
||||||
if (e.target instanceof HTMLElement) {
|
|
||||||
clear();
|
|
||||||
|
|
||||||
const result = start(e.target);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
grab_point.set(e.offsetX + 2, e.offsetY + 2);
|
|
||||||
|
|
||||||
detail = {
|
|
||||||
drag_element: result[0],
|
|
||||||
entity_type: result[1],
|
|
||||||
};
|
|
||||||
|
|
||||||
detail.drag_element.style.position = "fixed";
|
|
||||||
detail.drag_element.style.pointerEvents = "none";
|
|
||||||
detail.drag_element.style.zIndex = "500";
|
|
||||||
detail.drag_element.style.top = "0";
|
|
||||||
detail.drag_element.style.left = "0";
|
|
||||||
detail.drag_element.style.transform = `translate(${e.clientX -
|
|
||||||
grab_point.x}px, ${e.clientY - grab_point.y}px)`;
|
|
||||||
document.body.append(detail.drag_element);
|
|
||||||
|
|
||||||
e.dataTransfer!.setDragImage(el.div(), 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dragenter(e: DragEvent): void {
|
|
||||||
redispatch(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
function dragover(e: DragEvent): void {
|
|
||||||
if (e.target instanceof HTMLElement && detail) {
|
|
||||||
detail.drag_element.style.transform = `translate(${e.clientX -
|
|
||||||
grab_point.x}px, ${e.clientY - grab_point.y}px)`;
|
|
||||||
|
|
||||||
redispatch(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dragleave(e: DragEvent): void {
|
|
||||||
redispatch(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
function dragend(): void {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
function drop(e: DragEvent): void {
|
|
||||||
try {
|
|
||||||
redispatch(e);
|
|
||||||
} finally {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
element.addEventListener("dragstart", dragstart);
|
|
||||||
document.addEventListener("dragenter", dragenter);
|
|
||||||
document.addEventListener("dragover", dragover);
|
|
||||||
document.addEventListener("dragleave", dragleave);
|
|
||||||
document.addEventListener("dragend", dragend);
|
|
||||||
document.addEventListener("drop", drop);
|
|
||||||
|
|
||||||
return {
|
|
||||||
dispose(): void {
|
|
||||||
element.removeEventListener("dragstart", dragstart);
|
|
||||||
document.removeEventListener("dragenter", dragenter);
|
|
||||||
document.removeEventListener("dragover", dragover);
|
|
||||||
document.removeEventListener("dragleave", dragleave);
|
|
||||||
document.removeEventListener("dragend", dragend);
|
|
||||||
document.removeEventListener("drop", drop);
|
|
||||||
|
|
||||||
clear();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
120
src/quest_editor/gui/entity_dnd.ts
Normal file
120
src/quest_editor/gui/entity_dnd.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import { entity_data, EntityType } from "../../core/data_formats/parsing/quest/entities";
|
||||||
|
import { Disposable } from "../../core/observable/Disposable";
|
||||||
|
import { Vec2 } from "../../core/data_formats/vector";
|
||||||
|
import { el } from "../../core/gui/dom";
|
||||||
|
|
||||||
|
export type EntityDragEvent = {
|
||||||
|
readonly entity_type: EntityType;
|
||||||
|
readonly drag_element: HTMLElement;
|
||||||
|
readonly event: DragEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
let dragging_details: Omit<EntityDragEvent, "event"> | undefined = undefined;
|
||||||
|
const listeners: Map<(e: EntityDragEvent) => void, (e: DragEvent) => void> = new Map();
|
||||||
|
const grab_point = new Vec2(0, 0);
|
||||||
|
let drag_sources = 0;
|
||||||
|
|
||||||
|
export function add_entity_dnd_listener(
|
||||||
|
element: HTMLElement,
|
||||||
|
type: "dragenter" | "dragover" | "dragleave" | "drop",
|
||||||
|
listener: (event: EntityDragEvent) => void,
|
||||||
|
): void {
|
||||||
|
function event_listener(event: DragEvent): void {
|
||||||
|
if (dragging_details) {
|
||||||
|
listener({ ...dragging_details, event });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners.set(listener, event_listener);
|
||||||
|
element.addEventListener(type, event_listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function remove_entity_dnd_listener(
|
||||||
|
element: HTMLElement,
|
||||||
|
type: "dragenter" | "dragover" | "dragleave" | "drop",
|
||||||
|
listener: (event: EntityDragEvent) => void,
|
||||||
|
): void {
|
||||||
|
const event_listener = listeners.get(listener);
|
||||||
|
|
||||||
|
if (event_listener) {
|
||||||
|
listeners.delete(listener);
|
||||||
|
element.removeEventListener(type, event_listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function entity_dnd_source(
|
||||||
|
element: HTMLElement,
|
||||||
|
start: (target: HTMLElement) => [HTMLElement, EntityType] | undefined,
|
||||||
|
): Disposable {
|
||||||
|
function dragstart(e: DragEvent): void {
|
||||||
|
if (e.target instanceof HTMLElement) {
|
||||||
|
const result = start(e.target);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
grab_point.set(e.offsetX + 2, e.offsetY + 2);
|
||||||
|
|
||||||
|
dragging_details = {
|
||||||
|
drag_element: result[0],
|
||||||
|
entity_type: result[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
dragging_details.drag_element.style.position = "fixed";
|
||||||
|
dragging_details.drag_element.style.pointerEvents = "none";
|
||||||
|
dragging_details.drag_element.style.zIndex = "500";
|
||||||
|
dragging_details.drag_element.style.top = "0";
|
||||||
|
dragging_details.drag_element.style.left = "0";
|
||||||
|
dragging_details.drag_element.style.transform = `translate(${e.clientX -
|
||||||
|
grab_point.x}px, ${e.clientY - grab_point.y}px)`;
|
||||||
|
document.body.append(dragging_details.drag_element);
|
||||||
|
|
||||||
|
if (e.dataTransfer) {
|
||||||
|
e.dataTransfer.effectAllowed = "copy";
|
||||||
|
e.dataTransfer.setDragImage(el.div(), 0, 0);
|
||||||
|
// setData is necessary for FireFox.
|
||||||
|
e.dataTransfer.setData(
|
||||||
|
"phantasmal-entity",
|
||||||
|
entity_data(dragging_details.entity_type).name,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
element.addEventListener("dragstart", dragstart);
|
||||||
|
|
||||||
|
if (++drag_sources === 1) {
|
||||||
|
document.addEventListener("dragover", dragover);
|
||||||
|
document.addEventListener("dragend", dragend);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
dispose(): void {
|
||||||
|
element.removeEventListener("dragstart", dragstart);
|
||||||
|
|
||||||
|
if (--drag_sources === 0) {
|
||||||
|
document.removeEventListener("dragover", dragover);
|
||||||
|
document.removeEventListener("dragend", dragend);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function dragover(e: DragEvent): void {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (e.dataTransfer) {
|
||||||
|
e.dataTransfer.dropEffect = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dragging_details) {
|
||||||
|
dragging_details.drag_element.style.transform = `translate(${e.clientX -
|
||||||
|
grab_point.x}px, ${e.clientY - grab_point.y}px)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dragend(): void {
|
||||||
|
if (dragging_details) {
|
||||||
|
dragging_details.drag_element.remove();
|
||||||
|
dragging_details = undefined;
|
||||||
|
}
|
||||||
|
}
|
@ -9,9 +9,13 @@ import { AreaUserData } from "./conversion/areas";
|
|||||||
import { SectionModel } from "../model/SectionModel";
|
import { SectionModel } from "../model/SectionModel";
|
||||||
import { Disposable } from "../../core/observable/Disposable";
|
import { Disposable } from "../../core/observable/Disposable";
|
||||||
import { Disposer } from "../../core/observable/Disposer";
|
import { Disposer } from "../../core/observable/Disposer";
|
||||||
import { EntityDrag } from "../gui/EntityListView";
|
|
||||||
import { is_npc_type } from "../../core/data_formats/parsing/quest/entities";
|
import { is_npc_type } from "../../core/data_formats/parsing/quest/entities";
|
||||||
import { npc_data } from "../../core/data_formats/parsing/quest/npc_types";
|
import { npc_data } from "../../core/data_formats/parsing/quest/npc_types";
|
||||||
|
import {
|
||||||
|
add_entity_dnd_listener,
|
||||||
|
EntityDragEvent,
|
||||||
|
remove_entity_dnd_listener,
|
||||||
|
} from "../gui/entity_dnd";
|
||||||
|
|
||||||
const DOWN_VECTOR = new Vector3(0, -1, 0);
|
const DOWN_VECTOR = new Vector3(0, -1, 0);
|
||||||
|
|
||||||
@ -20,11 +24,13 @@ type Highlighted = {
|
|||||||
mesh: Mesh;
|
mesh: Mesh;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PickMode {
|
||||||
|
Creating,
|
||||||
|
Transforming,
|
||||||
|
}
|
||||||
|
|
||||||
type Pick = {
|
type Pick = {
|
||||||
/**
|
mode: PickMode;
|
||||||
* Whether we picked an entity that is being created or one that has existed before.
|
|
||||||
*/
|
|
||||||
creating: boolean;
|
|
||||||
|
|
||||||
initial_section?: SectionModel;
|
initial_section?: SectionModel;
|
||||||
|
|
||||||
@ -82,12 +88,20 @@ export class QuestEntityControls implements Disposable {
|
|||||||
renderer.dom_element.addEventListener("mousedown", this.mousedown);
|
renderer.dom_element.addEventListener("mousedown", this.mousedown);
|
||||||
renderer.dom_element.addEventListener("mousemove", this.mousemove);
|
renderer.dom_element.addEventListener("mousemove", this.mousemove);
|
||||||
renderer.dom_element.addEventListener("mouseup", this.mouseup);
|
renderer.dom_element.addEventListener("mouseup", this.mouseup);
|
||||||
renderer.dom_element.addEventListener("phantasmal-dragenter", this.dragenter);
|
add_entity_dnd_listener(renderer.dom_element, "dragenter", this.dragenter);
|
||||||
renderer.dom_element.addEventListener("phantasmal-dragover", this.dragover);
|
add_entity_dnd_listener(renderer.dom_element, "dragover", this.dragover);
|
||||||
renderer.dom_element.addEventListener("phantasmal-dragleave", this.dragleave);
|
add_entity_dnd_listener(renderer.dom_element, "dragleave", this.dragleave);
|
||||||
|
add_entity_dnd_listener(renderer.dom_element, "drop", this.drop);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
|
this.renderer.dom_element.removeEventListener("mousedown", this.mousedown);
|
||||||
|
this.renderer.dom_element.removeEventListener("mousemove", this.mousemove);
|
||||||
|
this.renderer.dom_element.removeEventListener("mouseup", this.mouseup);
|
||||||
|
remove_entity_dnd_listener(this.renderer.dom_element, "dragenter", this.dragenter);
|
||||||
|
remove_entity_dnd_listener(this.renderer.dom_element, "dragover", this.dragover);
|
||||||
|
remove_entity_dnd_listener(this.renderer.dom_element, "dragleave", this.dragleave);
|
||||||
|
remove_entity_dnd_listener(this.renderer.dom_element, "drop", this.drop);
|
||||||
this.disposer.dispose();
|
this.disposer.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,9 +126,7 @@ export class QuestEntityControls implements Disposable {
|
|||||||
this.process_event(e);
|
this.process_event(e);
|
||||||
this.stop_transforming();
|
this.stop_transforming();
|
||||||
|
|
||||||
const new_pick = this.pick_entity(
|
const new_pick = this.pick_entity(this.renderer.pointer_pos_to_device_coords(e));
|
||||||
this.renderer.pointer_pos_to_device_coords(new Vector2(e.offsetX, e.offsetY)),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (new_pick) {
|
if (new_pick) {
|
||||||
// Disable camera controls while the user is transforming an entity.
|
// Disable camera controls while the user is transforming an entity.
|
||||||
@ -132,9 +144,7 @@ export class QuestEntityControls implements Disposable {
|
|||||||
private mousemove = (e: MouseEvent) => {
|
private mousemove = (e: MouseEvent) => {
|
||||||
this.process_event(e);
|
this.process_event(e);
|
||||||
|
|
||||||
const pointer_device_pos = this.renderer.pointer_pos_to_device_coords(
|
const pointer_device_pos = this.renderer.pointer_pos_to_device_coords(e);
|
||||||
new Vector2(e.offsetX, e.offsetY),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.selected && this.pick) {
|
if (this.selected && this.pick) {
|
||||||
if (this.moved_since_last_mouse_down) {
|
if (this.moved_since_last_mouse_down) {
|
||||||
@ -177,16 +187,11 @@ export class QuestEntityControls implements Disposable {
|
|||||||
this.renderer.schedule_render();
|
this.renderer.schedule_render();
|
||||||
};
|
};
|
||||||
|
|
||||||
private dragenter = (e: Event) => {
|
private dragenter = (e: EntityDragEvent) => {
|
||||||
const area = quest_editor_store.current_area.val;
|
const area = quest_editor_store.current_area.val;
|
||||||
if (!area) return;
|
if (!area) return;
|
||||||
|
|
||||||
const detail = (e as CustomEvent<EntityDrag>).detail;
|
const pointer_position = this.renderer.pointer_pos_to_device_coords(e.event);
|
||||||
|
|
||||||
const pointer_position = this.renderer.pointer_pos_to_device_coords(
|
|
||||||
new Vector2(detail.offset_x, detail.offset_y),
|
|
||||||
);
|
|
||||||
|
|
||||||
const { intersection, section } = this.pick_terrain(pointer_position, new Vector3());
|
const { intersection, section } = this.pick_terrain(pointer_position, new Vector3());
|
||||||
|
|
||||||
let position: Vec3 | undefined;
|
let position: Vec3 | undefined;
|
||||||
@ -208,15 +213,18 @@ export class QuestEntityControls implements Disposable {
|
|||||||
const quest = quest_editor_store.current_quest.val;
|
const quest = quest_editor_store.current_quest.val;
|
||||||
|
|
||||||
if (quest && position) {
|
if (quest && position) {
|
||||||
if (is_npc_type(detail.entity_type)) {
|
if (is_npc_type(e.entity_type)) {
|
||||||
const data = npc_data(detail.entity_type);
|
const data = npc_data(e.entity_type);
|
||||||
|
|
||||||
if (data.pso_type_id !== undefined && data.pso_roaming != undefined) {
|
if (data.pso_type_id != undefined && data.pso_roaming != undefined) {
|
||||||
detail.drag_element.style.display = "none";
|
e.drag_element.style.display = "none";
|
||||||
detail.data_transfer.dropEffect = "copy";
|
|
||||||
|
if (e.event.dataTransfer) {
|
||||||
|
e.event.dataTransfer.dropEffect = "copy";
|
||||||
|
}
|
||||||
|
|
||||||
const npc = new QuestNpcModel(
|
const npc = new QuestNpcModel(
|
||||||
detail.entity_type,
|
e.entity_type,
|
||||||
data.pso_type_id,
|
data.pso_type_id,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -235,7 +243,7 @@ export class QuestEntityControls implements Disposable {
|
|||||||
quest_editor_store.set_selected_entity(npc);
|
quest_editor_store.set_selected_entity(npc);
|
||||||
|
|
||||||
this.pick = {
|
this.pick = {
|
||||||
creating: true,
|
mode: PickMode.Creating,
|
||||||
initial_section: section,
|
initial_section: section,
|
||||||
initial_position: position,
|
initial_position: position,
|
||||||
grab_offset: new Vector3(0, 0, 0),
|
grab_offset: new Vector3(0, 0, 0),
|
||||||
@ -247,83 +255,63 @@ export class QuestEntityControls implements Disposable {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private dragover = (e: Event) => {
|
private dragover = (e: EntityDragEvent) => {
|
||||||
if (!quest_editor_store.current_area.val) return;
|
if (!quest_editor_store.current_area.val) return;
|
||||||
|
|
||||||
const detail = (e as CustomEvent<EntityDrag>).detail;
|
if (this.pick && this.pick.mode === PickMode.Creating) {
|
||||||
detail.data_transfer.dropEffect = "copy";
|
e.event.stopPropagation();
|
||||||
|
e.event.preventDefault();
|
||||||
|
|
||||||
if (this.selected && this.pick) {
|
if (e.event.dataTransfer) {
|
||||||
const pointer_device_pos = this.renderer.pointer_pos_to_device_coords(
|
e.event.dataTransfer.dropEffect = "copy";
|
||||||
new Vector2(detail.offset_x, detail.offset_y),
|
}
|
||||||
);
|
|
||||||
|
|
||||||
// TODO:
|
if (this.selected) {
|
||||||
// if (e.buttons === 1) {
|
const pointer_device_pos = this.renderer.pointer_pos_to_device_coords(e.event);
|
||||||
// User is transforming selected entity.
|
|
||||||
// User is dragging selected entity.
|
|
||||||
// if (e.shiftKey) {
|
|
||||||
// Vertical movement.
|
|
||||||
// this.translate_vertically(this.selected, this.pick, pointer_device_pos);
|
|
||||||
// } else {
|
|
||||||
// Horizontal movement across terrain.
|
|
||||||
this.translate_horizontally(this.selected, this.pick, pointer_device_pos);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
this.renderer.schedule_render();
|
if (e.event.shiftKey) {
|
||||||
|
// Vertical movement.
|
||||||
|
this.translate_vertically(this.selected, this.pick, pointer_device_pos);
|
||||||
|
} else {
|
||||||
|
// Horizontal movement across terrain.
|
||||||
|
this.translate_horizontally(this.selected, this.pick, pointer_device_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderer.schedule_render();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private dragleave = (e: Event) => {
|
private dragleave = (e: EntityDragEvent) => {
|
||||||
if (!quest_editor_store.current_area.val) return;
|
if (!quest_editor_store.current_area.val) return;
|
||||||
|
|
||||||
const detail = (e as CustomEvent<EntityDrag>).detail;
|
e.drag_element.style.display = "flex";
|
||||||
if (detail.drag_element) detail.drag_element.style.display = "flex";
|
|
||||||
|
|
||||||
const quest = quest_editor_store.current_quest.val;
|
const quest = quest_editor_store.current_quest.val;
|
||||||
|
|
||||||
if (quest && this.selected && this.selected.entity.type == detail.entity_type) {
|
if (quest && this.selected && this.pick && this.pick.mode === PickMode.Creating) {
|
||||||
quest.remove_entity(this.selected.entity);
|
quest.remove_entity(this.selected.entity);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private drop = () => {
|
private drop = () => {
|
||||||
// TODO: push onto undo stack.
|
// TODO: push onto undo stack.
|
||||||
|
this.pick = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
private process_event(e: Event): void {
|
private process_event(e: MouseEvent): void {
|
||||||
let offset_x: number;
|
if (e.type === "mousedown") {
|
||||||
let offset_y: number;
|
|
||||||
|
|
||||||
if (e instanceof MouseEvent) {
|
|
||||||
offset_x = e.offsetX;
|
|
||||||
offset_y = e.offsetY;
|
|
||||||
} else if (e instanceof CustomEvent) {
|
|
||||||
const detail = (e as CustomEvent<EntityDrag>).detail;
|
|
||||||
|
|
||||||
if (!("offset_x" in detail && "offset_y" in detail)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset_x = detail.offset_x;
|
|
||||||
offset_y = detail.offset_y;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.type === "mousedown" || e.type === "phantasmal-dragenter") {
|
|
||||||
this.moved_since_last_mouse_down = false;
|
this.moved_since_last_mouse_down = false;
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
offset_x !== this.last_pointer_position.x ||
|
e.offsetX !== this.last_pointer_position.x ||
|
||||||
offset_y !== this.last_pointer_position.y
|
e.offsetY !== this.last_pointer_position.y
|
||||||
) {
|
) {
|
||||||
this.moved_since_last_mouse_down = true;
|
this.moved_since_last_mouse_down = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.last_pointer_position.set(offset_x, offset_y);
|
this.last_pointer_position.set(e.offsetX, e.offsetY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -456,7 +444,12 @@ export class QuestEntityControls implements Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private stop_transforming = () => {
|
private stop_transforming = () => {
|
||||||
if (this.moved_since_last_mouse_down && this.selected && this.pick && !this.pick.creating) {
|
if (
|
||||||
|
this.moved_since_last_mouse_down &&
|
||||||
|
this.selected &&
|
||||||
|
this.pick &&
|
||||||
|
this.pick.mode === PickMode.Transforming
|
||||||
|
) {
|
||||||
const entity = this.selected.entity;
|
const entity = this.selected.entity;
|
||||||
quest_editor_store.push_translate_entity_action(
|
quest_editor_store.push_translate_entity_action(
|
||||||
entity,
|
entity,
|
||||||
@ -503,7 +496,7 @@ export class QuestEntityControls implements Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
creating: false,
|
mode: PickMode.Transforming,
|
||||||
mesh: intersection.object as Mesh,
|
mesh: intersection.object as Mesh,
|
||||||
entity,
|
entity,
|
||||||
initial_section: entity.section.val,
|
initial_section: entity.section.val,
|
||||||
|
Loading…
Reference in New Issue
Block a user