[V14] 1605 - Template Migration (#1621)

* Fixed so that our templates make use of SceneRegions instead

* Fixed visibility
This commit is contained in:
WBHarry 2026-02-01 17:21:56 +01:00 committed by GitHub
parent 57e51ee841
commit 578b090f08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 70 additions and 115 deletions

View file

@ -1,5 +1,5 @@
export { default as DhMeasuredTemplate } from './measuredTemplate.mjs';
export { default as DhRuler } from './ruler.mjs';
export { default as DhTemplateLayer } from './templateLayer.mjs';
export { default as DhRegionLayer } from './regionLayer.mjs';
export { default as DhTokenPlaceable } from './token.mjs';
export { default as DhTokenRuler } from './tokenRuler.mjs';

View file

@ -0,0 +1,48 @@
export default class DhRegionLayer extends foundry.canvas.layers.RegionLayer {
static prepareSceneControls() {
const sc = foundry.applications.ui.SceneControls;
const { tools, ...rest } = super.prepareSceneControls();
return {
...rest,
tools: {
select: tools.select,
templateMode: tools.templateMode,
rectangle: tools.rectangle,
circle: tools.circle,
ellipse: tools.ellipse,
cone: tools.cone,
inFront: {
name: 'inFront',
order: 7,
title: 'CONTROLS.inFront',
icon: 'fa-solid fa-eye',
toolclip: {
src: 'toolclips/tools/measure-cone.webm',
heading: 'CONTROLS.inFront',
items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete', 'rotate'])
}
},
ring: { ...tools.ring, order: 8 },
line: { ...tools.line, order: 9 },
emanation: { ...tools.emanation, order: 10 },
polygon: { ...tools.polygon, order: 11 },
hole: { ...tools.hole, order: 12 },
snap: { ...tools.snap, order: 13 },
clear: { ...tools.clear, order: 14 }
}
};
}
/** @inheritDoc */
_isCreationToolActive() {
return this.active && (game.activeTool === 'inFront' || game.activeTool in foundry.data.BaseShapeData.TYPES);
}
_createDragShapeData(event) {
const hole = ui.controls.controls[this.options.name].tools.hole?.active ?? false;
if (game.activeTool === 'inFront') return { type: 'cone', x: 0, y: 0, radius: 0, angle: 180, hole };
return super._createDragShapeData(event);
}
}

View file

@ -8,5 +8,4 @@ export { default as DhRollTable } from './rollTable.mjs';
export { default as DhScene } from './scene.mjs';
export { default as DhToken } from './token.mjs';
export { default as DhTooltipManager } from './tooltipManager.mjs';
export { default as DhTemplateManager } from './templateManager.mjs';
export { default as DhTokenManager } from './tokenManager.mjs';

View file

@ -1,105 +0,0 @@
/**
* A singleton class that handles preview templates.
*/
export default class DhTemplateManager {
#activePreview;
/**
* Create a template preview, deactivating any existing ones.
* @param {object} data
*/
async createPreview(data) {
const template = await canvas.templates._createPreview(data, { renderSheet: false });
this.#activePreview = {
document: template.document,
object: template,
origin: { x: template.document.x, y: template.document.y }
};
this.#activePreview.events = {
contextmenu: this.#cancelTemplate.bind(this),
mousedown: this.#confirmTemplate.bind(this),
mousemove: this.#onDragMouseMove.bind(this),
wheel: this.#onMouseWheel.bind(this)
};
canvas.stage.on('mousemove', this.#activePreview.events.mousemove);
canvas.stage.on('mousedown', this.#activePreview.events.mousedown);
canvas.app.view.addEventListener('wheel', this.#activePreview.events.wheel, true);
canvas.app.view.addEventListener('contextmenu', this.#activePreview.events.contextmenu);
}
/**
* Handles the movement of the temlate preview on mousedrag.
* @param {mousemove Event} event
*/
#onDragMouseMove(event) {
event.stopPropagation();
const { moveTime, object } = this.#activePreview;
const update = {};
const now = Date.now();
if (now - (moveTime || 0) <= 16) return;
this.#activePreview.moveTime = now;
let cursor = event.getLocalPosition(canvas.templates);
Object.assign(update, canvas.grid.getCenterPoint(cursor));
object.document.updateSource(update);
object.renderFlags.set({ refresh: true });
}
/**
* Handles the rotation of the preview template on scrolling.
* @param {wheel Event} event
*/
#onMouseWheel(event) {
if (!this.#activePreview) {
return;
}
if (!event.shiftKey && !event.ctrlKey) return;
event.stopPropagation();
event.preventDefault();
const { moveTime, object } = this.#activePreview;
const now = Date.now();
if (now - (moveTime || 0) <= 16) return;
this.#activePreview.moveTime = now;
const multiplier = event.shiftKey ? 0.2 : 0.1;
object.document.updateSource({
direction: object.document.direction + event.deltaY * multiplier
});
object.renderFlags.set({ refresh: true });
}
/**
* Cancels the preview template on right-click.
* @param {contextmenu Event} event
*/
#cancelTemplate(event) {
const { mousemove, mousedown, contextmenu, wheel } = this.#activePreview.events;
canvas.templates._onDragLeftCancel(event);
canvas.stage.off('mousemove', mousemove);
canvas.stage.off('mousedown', mousedown);
canvas.app.view.removeEventListener('contextmenu', contextmenu);
canvas.app.view.removeEventListener('wheel', wheel);
}
/**
* Creates a real MeasuredTemplate at the preview location and cancels the preview.
* @param {click Event} event
*/
#confirmTemplate(event) {
event.stopPropagation();
this.#cancelTemplate(event);
canvas.scene.createEmbeddedDocuments('MeasuredTemplate', [this.#activePreview.document.toObject()]);
this.#activePreview = undefined;
}
}

View file

@ -58,7 +58,7 @@ export const renderMeasuredTemplate = async event => {
const usedType = type === 'inFront' ? 'cone' : type === 'emanation' ? 'circle' : type;
const usedAngle =
type === CONST.MEASURED_TEMPLATE_TYPES.CONE
type === CONFIG.DH.GENERAL.templateTypes.CONE
? (angle ?? CONFIG.MeasuredTemplate.defaults.angle)
: type === CONFIG.DH.GENERAL.templateTypes.INFRONT
? '180'
@ -71,17 +71,32 @@ export const renderMeasuredTemplate = async event => {
];
}
const distance = type === CONFIG.DH.GENERAL.templateTypes.EMANATION ? baseDistance + 2.5 : baseDistance;
const radius = (distance / game.scenes.active.grid.distance) * game.scenes.active.grid.size;
const { width, height } = game.canvas.scene.dimensions;
const data = {
const shapeData = {
x: width / 2,
y: height / 2,
t: usedType,
distance: distance,
width: type === CONST.MEASURED_TEMPLATE_TYPES.RAY ? 5 : undefined,
width: type === CONFIG.DH.GENERAL.templateTypes.RAY ? 5 : undefined,
angle: usedAngle,
direction: direction
radius: radius,
direction: direction,
type: usedType
};
CONFIG.ux.TemplateManager.createPreview(data);
await canvas.regions.placeRegion(
{
name: usedType.capitalize(),
shapes: [shapeData],
restriction: { enabled: false, type: 'move', priority: 0 },
behaviors: [],
displayMeasurements: true,
locked: false,
ownership: { default: CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE },
visibility: CONST.REGION_VISIBILITY.ALWAYS
},
{ create: true }
);
};