Files
Foundry-VTT-Docker/resources/app/client/apps/hud/controls.js
2025-01-04 00:34:03 +01:00

1052 lines
34 KiB
JavaScript

/**
* @typedef {Object} SceneControlTool
* @property {string} name
* @property {string} title
* @property {string} icon
* @property {boolean} visible
* @property {boolean} toggle
* @property {boolean} active
* @property {boolean} button
* @property {Function} onClick
* @property {ToolclipConfiguration} toolclip Configuration for rendering the tool's toolclip.
*/
/**
* @typedef {Object} SceneControl
* @property {string} name
* @property {string} title
* @property {string} layer
* @property {string} icon
* @property {boolean} visible
* @property {SceneControlTool[]} tools
* @property {string} activeTool
*/
/**
* @typedef {object} ToolclipConfiguration
* @property {string} src The filename of the toolclip video.
* @property {string} heading The heading string.
* @property {ToolclipConfigurationItem[]} items The items in the toolclip body.
*/
/**
* @typedef {object} ToolclipConfigurationItem
* @property {string} [paragraph] A plain paragraph of content for this item.
* @property {string} [heading] A heading for the item.
* @property {string} [content] Content for the item.
* @property {string} [reference] If the item is a single key reference, use this instead of content.
*/
/**
* Scene controls navigation menu
* @extends {Application}
*/
class SceneControls extends Application {
/** @inheritdoc */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
width: 100,
id: "controls",
template: "templates/hud/controls.html",
popOut: false
});
}
/* -------------------------------------------- */
/**
* The Array of Scene Control buttons which are currently rendered
* @type {SceneControl[]}
*/
controls = this._getControlButtons();
/* -------------------------------------------- */
/**
* The currently active control set
* @type {string}
*/
get activeControl() {
return this.#control;
}
#control = "token";
/* -------------------------------------------- */
/**
* The currently active tool in the control palette
* @type {string}
*/
get activeTool() {
return this.#tools[this.#control];
}
/**
* Track which tool is active within each control set
* @type {Record<string, string>}
*/
#tools = {};
/* -------------------------------------------- */
/**
* Return the active control set
* @type {SceneControl|null}
*/
get control() {
if ( !this.controls ) return null;
return this.controls.find(c => c.name === this.#control) || null;
}
/* -------------------------------------------- */
/**
* Return the actively controlled tool
* @type {SceneControlTool|null}
*/
get tool() {
const control = this.control;
if ( !control ) return null;
return this.#tools[control.name] || null;
}
/* -------------------------------------------- */
/* Methods */
/* -------------------------------------------- */
/**
* Initialize the Scene Controls by obtaining the set of control buttons and rendering the HTML
* @param {object} options Options which modify how the controls UI is initialized
* @param {string} [options.control] An optional control set to set as active
* @param {string} [options.layer] An optional layer name to target as the active control
* @param {string} [options.tool] A specific named tool to set as active for the palette
*/
initialize({control, layer, tool} = {}) {
// Determine the control set to activate
let controlSet = control ? this.controls.find(c => c.name === control) : null;
if ( !controlSet && layer ) controlSet = this.controls.find(c => c.layer === layer);
if ( !controlSet ) controlSet = this.control;
// Determine the tool to activate
tool ||= this.#tools[controlSet.name] || controlSet.activeTool || null;
// Activate the new control scheme
this.#control = controlSet?.name || null;
if ( controlSet && (this.#tools[this.#control] !== tool) ) {
this.#tools[this.#control] = tool;
// Refresh placeable states if the active tool changed
if ( canvas.ready ) {
// TODO: Perhaps replace this with a CanvasLayer#_onToolChanged callback
const layer = canvas[controlSet.layer];
if ( layer instanceof PlaceablesLayer ) {
for ( const placeable of layer.placeables ) placeable.renderFlags.set({refreshState: true});
}
}
}
this.controls = this._getControlButtons();
// Render the UI
this.render(true);
}
/* -------------------------------------------- */
/** @inheritdoc */
async getData(options={}) {
const showToolclips = game.settings.get("core", "showToolclips");
const canvasActive = !!canvas.scene;
const controls = [];
const isMac = navigator.appVersion.includes("Mac");
const mod = isMac ? "⌘" : game.i18n.localize("CONTROLS.CtrlAbbr");
const alt = isMac ? "⌥" : game.i18n.localize("CONTROLS.Alt");
for ( const c of this.controls ) {
if ( c.visible === false ) continue;
const control = foundry.utils.deepClone(c);
control.isActive = canvasActive && (this.#control === control.name);
control.css = control.isActive ? "active" : "";
control.tools = [];
for ( const t of c.tools ) {
if ( t.visible === false ) continue;
const tool = foundry.utils.deepClone(t);
tool.isActive = canvasActive && ((this.#tools[control.name] === tool.name) || (tool.toggle && tool.active));
tool.css = [
tool.toggle ? "toggle" : null,
tool.isActive ? "active" : null
].filterJoin(" ");
tool.tooltip = showToolclips && tool.toolclip
? await renderTemplate("templates/hud/toolclip.html", { ...tool.toolclip, alt, mod })
: tool.title;
control.tools.push(tool);
}
if ( control.tools.length ) controls.push(control);
}
// Return data for rendering
return {
controls,
active: canvasActive,
cssClass: canvasActive ? "" : "disabled"
};
}
/* -------------------------------------------- */
/* Event Listeners and Handlers */
/* -------------------------------------------- */
/** @inheritdoc */
activateListeners(html) {
html.find(".scene-control").click(this._onClickLayer.bind(this));
html.find(".control-tool").click(this._onClickTool.bind(this));
canvas.notes?.hintMapNotes();
}
/* -------------------------------------------- */
/**
* Handle click events on a Control set
* @param {Event} event A click event on a tool control
* @private
*/
_onClickLayer(event) {
event.preventDefault();
if ( !canvas.ready ) return;
const li = event.currentTarget;
const controlName = li.dataset.control;
if ( this.#control === controlName ) return;
this.#control = controlName;
const control = this.controls.find(c => c.name === controlName);
if ( control ) canvas[control.layer].activate();
}
/* -------------------------------------------- */
/**
* Handle click events on Tool controls
* @param {Event} event A click event on a tool control
* @private
*/
_onClickTool(event) {
event.preventDefault();
if ( !canvas.ready ) return;
const li = event.currentTarget;
const control = this.control;
const toolName = li.dataset.tool;
const tool = control.tools.find(t => t.name === toolName);
// Handle Toggles
if ( tool.toggle ) {
tool.active = !tool.active;
if ( tool.onClick instanceof Function ) tool.onClick(tool.active);
}
// Handle Buttons
else if ( tool.button ) {
if ( tool.onClick instanceof Function ) tool.onClick();
}
// Handle Tools
else if ( this.#tools[control.name] !== toolName ) {
this.#tools[control.name] = toolName;
const layer = canvas[control.layer];
if ( layer instanceof PlaceablesLayer ) {
for ( const placeable of layer.placeables ) placeable.renderFlags.set({refreshState: true});
}
if ( tool.onClick instanceof Function ) tool.onClick();
}
// Render the controls
this.render();
}
/* -------------------------------------------- */
/**
* Get the set of Control sets and tools that are rendered as the Scene Controls.
* These controls may be extended using the "getSceneControlButtons" Hook.
* @returns {SceneControl[]}
* @private
*/
_getControlButtons() {
const controls = [];
const isGM = game.user.isGM;
const clip = game.settings.get("core", "showToolclips") ? "Clip" : "";
const commonControls = {
create: { heading: "CONTROLS.CommonCreate", reference: "CONTROLS.ClickDrag" },
move: { heading: "CONTROLS.CommonMove", reference: "CONTROLS.Drag" },
edit: { heading: "CONTROLS.CommonEdit", reference: "CONTROLS.DoubleClick" },
editAlt: { heading: "CONTROLS.CommonEdit", reference: "CONTROLS.DoubleRightClick" },
sheet: { heading: "CONTROLS.CommonOpenSheet", reference: "CONTROLS.DoubleClick" },
hide: { heading: "CONTROLS.CommonHide", reference: "CONTROLS.RightClick" },
delete: { heading: "CONTROLS.CommonDelete", reference: "CONTROLS.Delete" },
rotate: { heading: "CONTROLS.CommonRotate", content: "CONTROLS.ShiftOrCtrlScroll" },
select: { heading: "CONTROLS.CommonSelect", reference: "CONTROLS.Click" },
selectAlt: { heading: "CONTROLS.CommonSelect", content: "CONTROLS.ClickOrClickDrag" },
selectMultiple: { heading: "CONTROLS.CommonSelectMultiple", reference: "CONTROLS.ShiftClick" },
hud: { heading: "CONTROLS.CommonToggleHUD", reference: "CONTROLS.RightClick" },
draw: { heading: "CONTROLS.CommonDraw", reference: "CONTROLS.ClickDrag" },
drawProportionally: { heading: "CONTROLS.CommonDrawProportional", reference: "CONTROLS.AltClickDrag" },
place: { heading: "CONTROLS.CommonPlace", reference: "CONTROLS.ClickDrag" },
chain: { heading: "CONTROLS.CommonChain", content: "CONTROLS.ChainCtrlClick" },
movePoint: { heading: "CONTROLS.CommonMovePoint", reference: "CONTROLS.ClickDrag" },
openClose: { heading: "CONTROLS.CommonOpenClose", reference: "CONTROLS.Click" },
openCloseSilently: { heading: "CONTROLS.CommonOpenCloseSilently", reference: "CONTROLS.AltClick" },
lock: { heading: "CONTROLS.CommonLock", reference: "CONTROLS.RightClick" },
lockSilently: { heading: "CONTROLS.CommonLockSilently", reference: "CONTROLS.AltRightClick" },
onOff: { heading: "CONTROLS.CommonOnOff", reference: "CONTROLS.RightClick" }
};
const buildItems = (...items) => items.map(item => commonControls[item]);
// Token Controls
controls.push({
name: "token",
title: "CONTROLS.GroupToken",
layer: "tokens",
icon: "fa-solid fa-user-alt",
tools: [
{
name: "select",
title: "CONTROLS.BasicSelect",
icon: "fa-solid fa-expand",
toolclip: {
src: "toolclips/tools/token-select.webm",
heading: "CONTROLS.BasicSelect",
items: [
{ paragraph: "CONTROLS.BasicSelectP" },
...buildItems("selectAlt", "selectMultiple", "move", "rotate", "hud", "sheet"),
...(game.user.isGM ? buildItems("editAlt", "delete") : []),
{ heading: "CONTROLS.BasicMeasureStart", reference: "CONTROLS.CtrlClickDrag" },
{ heading: "CONTROLS.BasicMeasureWaypoints", reference: "CONTROLS.CtrlClick" },
{ heading: "CONTROLS.BasicMeasureFollow", reference: "CONTROLS.Spacebar" }
]
}
},
{
name: "target",
title: "CONTROLS.TargetSelect",
icon: "fa-solid fa-bullseye",
toolclip: {
src: "toolclips/tools/token-target.webm",
heading: "CONTROLS.TargetSelect",
items: [
{ paragraph: "CONTROLS.TargetSelectP" },
...buildItems("selectAlt", "selectMultiple")
]
}
},
{
name: "ruler",
title: "CONTROLS.BasicMeasure",
icon: "fa-solid fa-ruler",
toolclip: {
src: "toolclips/tools/token-measure.webm",
heading: "CONTROLS.BasicMeasure",
items: [
{ heading: "CONTROLS.BasicMeasureStart", reference: "CONTROLS.ClickDrag" },
{ heading: "CONTROLS.BasicMeasureWaypoints", reference: "CONTROLS.CtrlClick" },
{ heading: "CONTROLS.BasicMeasureFollow", reference: "CONTROLS.Spacebar" }
]
}
}
],
activeTool: "select"
});
// Measurement Layer Tools
controls.push({
name: "measure",
title: "CONTROLS.GroupMeasure",
layer: "templates",
icon: "fa-solid fa-ruler-combined",
visible: game.user.can("TEMPLATE_CREATE"),
tools: [
{
name: "circle",
title: "CONTROLS.MeasureCircle",
icon: "fa-regular fa-circle",
toolclip: {
src: "toolclips/tools/measure-circle.webm",
heading: "CONTROLS.MeasureCircle",
items: buildItems("create", "move", "edit", "hide", "delete")
}
},
{
name: "cone",
title: "CONTROLS.MeasureCone",
icon: "fa-solid fa-angle-left",
toolclip: {
src: "toolclips/tools/measure-cone.webm",
heading: "CONTROLS.MeasureCone",
items: buildItems("create", "move", "edit", "hide", "delete", "rotate")
}
},
{
name: "rect",
title: "CONTROLS.MeasureRect",
icon: "fa-regular fa-square",
toolclip: {
src: "toolclips/tools/measure-rect.webm",
heading: "CONTROLS.MeasureRect",
items: buildItems("create", "move", "edit", "hide", "delete", "rotate")
}
},
{
name: "ray",
title: "CONTROLS.MeasureRay",
icon: "fa-solid fa-arrows-alt-v",
toolclip: {
src: "toolclips/tools/measure-ray.webm",
heading: "CONTROLS.MeasureRay",
items: buildItems("create", "move", "edit", "hide", "delete", "rotate")
}
},
{
name: "clear",
title: "CONTROLS.MeasureClear",
icon: "fa-solid fa-trash",
visible: isGM,
onClick: () => canvas.templates.deleteAll(),
button: true
}
],
activeTool: "circle"
});
// Tiles Layer
controls.push({
name: "tiles",
title: "CONTROLS.GroupTile",
layer: "tiles",
icon: "fa-solid fa-cubes",
visible: isGM,
tools: [
{
name: "select",
title: "CONTROLS.TileSelect",
icon: "fa-solid fa-expand",
toolclip: {
src: "toolclips/tools/tile-select.webm",
heading: "CONTROLS.TileSelect",
items: buildItems("selectAlt", "selectMultiple", "move", "rotate", "hud", "edit", "delete")
}
},
{
name: "tile",
title: "CONTROLS.TilePlace",
icon: "fa-solid fa-cube",
toolclip: {
src: "toolclips/tools/tile-place.webm",
heading: "CONTROLS.TilePlace",
items: buildItems("create", "move", "rotate", "hud", "edit", "delete")
}
},
{
name: "browse",
title: "CONTROLS.TileBrowser",
icon: "fa-solid fa-folder",
button: true,
onClick: () => {
new FilePicker({
type: "imagevideo",
displayMode: "tiles",
tileSize: true
}).render(true);
},
toolclip: {
src: "toolclips/tools/tile-browser.webm",
heading: "CONTROLS.TileBrowser",
items: buildItems("place", "move", "rotate", "hud", "edit", "delete")
}
},
{
name: "foreground",
title: "CONTROLS.TileForeground",
icon: "fa-solid fa-home",
toggle: true,
active: false,
onClick: active => {
this.control.foreground = active;
for ( const tile of canvas.tiles.placeables ) {
tile.renderFlags.set({refreshState: true});
if ( tile.controlled ) tile.release();
}
}
},
{
name: "snap",
title: "CONTROLS.CommonForceSnap",
icon: "fa-solid fa-plus",
toggle: true,
active: canvas.forceSnapVertices,
onClick: toggled => canvas.forceSnapVertices = toggled
}
],
activeTool: "select"
});
// Drawing Tools
controls.push({
name: "drawings",
title: "CONTROLS.GroupDrawing",
layer: "drawings",
icon: "fa-solid fa-pencil-alt",
visible: game.user.can("DRAWING_CREATE"),
tools: [
{
name: "select",
title: "CONTROLS.DrawingSelect",
icon: "fa-solid fa-expand",
toolclip: {
src: "toolclips/tools/drawing-select.webm",
heading: "CONTROLS.DrawingSelect",
items: buildItems("selectAlt", "selectMultiple", "move", "hud", "edit", "delete", "rotate")
}
},
{
name: "rect",
title: "CONTROLS.DrawingRect",
icon: "fa-solid fa-square",
toolclip: {
src: "toolclips/tools/drawing-rect.webm",
heading: "CONTROLS.DrawingRect",
items: buildItems("draw", "move", "hud", "edit", "delete", "rotate")
}
},
{
name: "ellipse",
title: "CONTROLS.DrawingEllipse",
icon: "fa-solid fa-circle",
toolclip: {
src: "toolclips/tools/drawing-ellipse.webm",
heading: "CONTROLS.DrawingEllipse",
items: buildItems("draw", "move", "hud", "edit", "delete", "rotate")
}
},
{
name: "polygon",
title: "CONTROLS.DrawingPoly",
icon: "fa-solid fa-draw-polygon",
toolclip: {
src: "toolclips/tools/drawing-polygon.webm",
heading: "CONTROLS.DrawingPoly",
items: [
{ heading: "CONTROLS.CommonDraw", content: "CONTROLS.DrawingPolyP" },
...buildItems("move", "hud", "edit", "delete", "rotate")
]
}
},
{
name: "freehand",
title: "CONTROLS.DrawingFree",
icon: "fa-solid fa-signature",
toolclip: {
src: "toolclips/tools/drawing-free.webm",
heading: "CONTROLS.DrawingFree",
items: buildItems("draw", "move", "hud", "edit", "delete", "rotate")
}
},
{
name: "text",
title: "CONTROLS.DrawingText",
icon: "fa-solid fa-font",
onClick: () => {
const controlled = canvas.drawings.controlled;
if ( controlled.length === 1 ) controlled[0].enableTextEditing();
},
toolclip: {
src: "toolclips/tools/drawing-text.webm",
heading: "CONTROLS.DrawingText",
items: buildItems("draw", "move", "hud", "edit", "delete", "rotate")
}
},
{
name: "role",
title: "CONTROLS.DrawingRole",
icon: "fa-solid fa-circle-info",
toggle: true,
active: false
},
{
name: "snap",
title: "CONTROLS.CommonForceSnap",
icon: "fa-solid fa-plus",
toggle: true,
active: canvas.forceSnapVertices,
onClick: toggled => canvas.forceSnapVertices = toggled
},
{
name: "configure",
title: "CONTROLS.DrawingConfig",
icon: "fa-solid fa-cog",
onClick: () => canvas.drawings.configureDefault(),
button: true
},
{
name: "clear",
title: "CONTROLS.DrawingClear",
icon: "fa-solid fa-trash",
visible: isGM,
onClick: () => canvas.drawings.deleteAll(),
button: true
}
],
activeTool: "select"
});
// Walls Layer Tools
controls.push({
name: "walls",
title: "CONTROLS.GroupWall",
layer: "walls",
icon: "fa-solid fa-block-brick",
visible: isGM,
tools: [
{
name: "select",
title: "CONTROLS.WallSelect",
icon: "fa-solid fa-expand",
toolclip: {
src: "toolclips/tools/wall-select.webm",
heading: "CONTROLS.WallSelect",
items: [
...buildItems("selectAlt", "selectMultiple", "move"),
{ heading: "CONTROLS.CommonMoveWithoutSnapping", reference: "CONTROLS.ShiftDrag" },
{ heading: "CONTROLS.CommonEdit", content: "CONTROLS.WallSelectEdit" },
...buildItems("delete")
]
}
},
{
name: "walls",
title: "CONTROLS.WallDraw",
icon: "fa-solid fa-bars",
toolclip: {
src: "toolclips/tools/wall-basic.webm",
heading: "CONTROLS.WallBasic",
items: [
{ heading: "CONTROLS.CommonBlocks", content: "CONTROLS.WallBasicBlocks" },
...buildItems("place", "chain", "movePoint", "edit", "delete")
]
}
},
{
name: "terrain",
title: "CONTROLS.WallTerrain",
icon: "fa-solid fa-mountain",
toolclip: {
src: "toolclips/tools/wall-terrain.webm",
heading: "CONTROLS.WallTerrain",
items: [
{ heading: "CONTROLS.CommonBlocks", content: "CONTROLS.WallTerrainBlocks" },
...buildItems("place", "chain", "movePoint", "edit", "delete")
]
}
},
{
name: "invisible",
title: "CONTROLS.WallInvisible",
icon: "fa-solid fa-eye-slash",
toolclip: {
src: "toolclips/tools/wall-invisible.webm",
heading: "CONTROLS.WallInvisible",
items: [
{ heading: "CONTROLS.CommonBlocks", content: "CONTROLS.WallInvisibleBlocks" },
...buildItems("place", "chain", "movePoint", "edit", "delete")
]
}
},
{
name: "ethereal",
title: "CONTROLS.WallEthereal",
icon: "fa-solid fa-mask",
toolclip: {
src: "toolclips/tools/wall-ethereal.webm",
heading: "CONTROLS.WallEthereal",
items: [
{ heading: "CONTROLS.CommonBlocks", content: "CONTROLS.WallEtherealBlocks" },
...buildItems("place", "chain", "movePoint", "edit", "delete")
]
}
},
{
name: "doors",
title: "CONTROLS.WallDoors",
icon: "fa-solid fa-door-open",
toolclip: {
src: "toolclips/tools/wall-door.webm",
heading: "CONTROLS.WallDoors",
items: [
{ heading: "CONTROLS.CommonBlocks", content: "CONTROLS.DoorBlocks" },
...buildItems("openClose", "openCloseSilently", "lock", "lockSilently", "place", "chain", "movePoint", "edit")
]
}
},
{
name: "secret",
title: "CONTROLS.WallSecret",
icon: "fa-solid fa-user-secret",
toolclip: {
src: "toolclips/tools/wall-secret-door.webm",
heading: "CONTROLS.WallSecret",
items: [
{ heading: "CONTROLS.WallSecretHidden", content: "CONTROLS.WallSecretHiddenP" },
{ heading: "CONTROLS.CommonBlocks", content: "CONTROLS.DoorBlocks" },
...buildItems("openClose", "openCloseSilently", "lock", "lockSilently", "place", "chain", "movePoint", "edit")
]
}
},
{
name: "window",
title: "CONTROLS.WallWindow",
icon: "fa-solid fa-window-frame",
toolclip: {
src: "toolclips/tools/wall-window.webm",
heading: "CONTROLS.WallWindow",
items: [
{ heading: "CONTROLS.CommonBlocks", content: "CONTROLS.WallWindowBlocks" },
...buildItems("place", "chain", "movePoint", "edit", "delete")
]
}
},
{
name: "clone",
title: "CONTROLS.WallClone",
icon: "fa-regular fa-clone"
},
{
name: "snap",
title: "CONTROLS.CommonForceSnap",
icon: "fa-solid fa-plus",
toggle: true,
active: canvas.forceSnapVertices,
onClick: toggled => canvas.forceSnapVertices = toggled,
toolclip: {
src: "toolclips/tools/wall-snap.webm",
heading: "CONTROLS.CommonForceSnap",
items: [{ paragraph: "CONTROLS.WallSnapP" }]
}
},
{
name: "close-doors",
title: "CONTROLS.WallCloseDoors",
icon: "fa-regular fa-door-closed",
onClick: () => {
let updates = canvas.walls.placeables.reduce((arr, w) => {
if ( w.isDoor && (w.document.ds === CONST.WALL_DOOR_STATES.OPEN) ) {
arr.push({_id: w.id, ds: CONST.WALL_DOOR_STATES.CLOSED});
}
return arr;
}, []);
if ( !updates.length ) return;
canvas.scene.updateEmbeddedDocuments("Wall", updates, {sound: false});
ui.notifications.info(game.i18n.format("CONTROLS.WallDoorsClosed", {number: updates.length}));
}
},
{
name: "clear",
title: "CONTROLS.WallClear",
icon: "fa-solid fa-trash",
onClick: () => canvas.walls.deleteAll(),
button: true
}
],
activeTool: "walls"
});
// Lighting Layer Tools
controls.push({
name: "lighting",
title: "CONTROLS.GroupLighting",
layer: "lighting",
icon: "fa-regular fa-lightbulb",
visible: isGM,
tools: [
{
name: "light",
title: "CONTROLS.LightDraw",
icon: "fa-solid fa-lightbulb",
toolclip: {
src: "toolclips/tools/light-draw.webm",
heading: "CONTROLS.LightDraw",
items: buildItems("create", "edit", "rotate", "onOff")
}
},
{
name: "day",
title: "CONTROLS.LightDay",
icon: "fa-solid fa-sun",
visible: !canvas.scene?.environment.darknessLock,
onClick: () => canvas.scene.update(
{environment: {darknessLevel: 0.0}},
{animateDarkness: CONFIG.Canvas.darknessToDaylightAnimationMS}
),
button: true,
toolclip: {
src: "toolclips/tools/light-day.webm",
heading: "CONTROLS.LightDay",
items: [
{heading: "CONTROLS.MakeDayH", content: "CONTROLS.MakeDayP"},
{heading: "CONTROLS.AutoLightToggleH", content: "CONTROLS.AutoLightToggleP"}
]
}
},
{
name: "night",
title: "CONTROLS.LightNight",
icon: "fa-solid fa-moon",
visible: !canvas.scene?.environment.darknessLock,
onClick: () => canvas.scene.update(
{environment: {darknessLevel: 1.0}},
{animateDarkness: CONFIG.Canvas.daylightToDarknessAnimationMS}
),
button: true,
toolclip: {
src: "toolclips/tools/light-night.webm",
heading: "CONTROLS.LightNight",
items: [
{heading: "CONTROLS.MakeNightH", content: "CONTROLS.MakeNightP"},
{heading: "CONTROLS.AutoLightToggleH", content: "CONTROLS.AutoLightToggleP"}
]
}
},
{
name: "reset",
title: "CONTROLS.LightReset",
icon: "fa-solid fa-cloud",
onClick: () => {
new Dialog({
title: game.i18n.localize("CONTROLS.FOWResetTitle"),
content: `<p>${game.i18n.localize("CONTROLS.FOWResetDesc")}</p>`,
buttons: {
yes: {
icon: '<i class="fa-solid fa-check"></i>',
label: "Yes",
callback: () => canvas.fog.reset()
},
no: {
icon: '<i class="fa-solid fa-times"></i>',
label: "No"
}
}
}).render(true);
},
button: true,
toolclip: {
src: "toolclips/tools/light-reset.webm",
heading: "CONTROLS.LightReset",
items: [{ paragraph: "CONTROLS.LightResetP" }]
}
},
{
name: "clear",
title: "CONTROLS.LightClear",
icon: "fa-solid fa-trash",
onClick: () => canvas.lighting.deleteAll(),
button: true
}
],
activeTool: "light"
});
// Sounds Layer Tools
controls.push({
name: "sounds",
title: "CONTROLS.GroupSound",
layer: "sounds",
icon: "fa-solid fa-music",
visible: isGM,
tools: [
{
name: "sound",
title: "CONTROLS.SoundDraw",
icon: "fa-solid fa-volume-up",
toolclip: {
src: "toolclips/tools/sound-draw.webm",
heading: "CONTROLS.SoundDraw",
items: buildItems("create", "edit", "rotate", "onOff")
}
},
{
name: "preview",
title: `CONTROLS.SoundPreview${clip}`,
icon: "fa-solid fa-headphones",
toggle: true,
active: canvas.sounds?.livePreview ?? false,
onClick: toggled => {
canvas.sounds.livePreview = toggled;
canvas.sounds.refresh();
},
toolclip: {
src: "toolclips/tools/sound-preview.webm",
heading: "CONTROLS.SoundPreview",
items: [{ paragraph: "CONTROLS.SoundPreviewP" }]
}
},
{
name: "clear",
title: "CONTROLS.SoundClear",
icon: "fa-solid fa-trash",
onClick: () => canvas.sounds.deleteAll(),
button: true
}
],
activeTool: "sound"
});
// Regions Layer Tools
controls.push({
name: "regions",
title: "CONTROLS.GroupRegion",
layer: "regions",
icon: "fa-regular fa-game-board",
visible: game.user.isGM,
tools: [
{
name: "select",
title: "CONTROLS.RegionSelect",
icon: "fa-solid fa-expand",
toolclip: {
src: "toolclips/tools/region-select.webm",
heading: "CONTROLS.RegionSelect",
items: [
{ paragraph: "CONTROLS.RegionSelectP" },
...buildItems("selectAlt", "selectMultiple", "edit", "delete")
]
}
},
{
name: "rectangle",
title: "CONTROLS.RegionRectangle",
icon: "fa-solid fa-square",
toolclip: {
src: "toolclips/tools/region-rectangle.webm",
heading: "CONTROLS.RegionRectangle",
items: [
{ paragraph: "CONTROLS.RegionShape" },
...buildItems("draw", "drawProportionally"),
{ paragraph: "CONTROLS.RegionPerformance" },
]
}
},
{
name: "ellipse",
title: "CONTROLS.RegionEllipse",
icon: "fa-solid fa-circle",
toolclip: {
src: "toolclips/tools/region-ellipse.webm",
heading: "CONTROLS.RegionEllipse",
items: [
{ paragraph: "CONTROLS.RegionShape" },
...buildItems("draw", "drawProportionally"),
{ paragraph: "CONTROLS.RegionPerformance" },
]
}
},
{
name: "polygon",
title: "CONTROLS.RegionPolygon",
icon: "fa-solid fa-draw-polygon",
toolclip: {
src: "toolclips/tools/region-polygon.webm",
heading: "CONTROLS.RegionPolygon",
items: [
{ paragraph: "CONTROLS.RegionShape" },
...buildItems("draw", "drawProportionally"),
{ paragraph: "CONTROLS.RegionPerformance" },
]
}
},
{
name: "hole",
title: "CONTROLS.RegionHole",
icon: "fa-duotone fa-object-subtract",
toggle: true,
active: canvas.regions?._holeMode ?? false,
onClick: toggled => canvas.regions._holeMode = toggled,
toolclip: {
src: "toolclips/tools/region-hole.webm",
heading: "CONTROLS.RegionHole",
items: [
{ paragraph: "CONTROLS.RegionHoleP" },
...buildItems("draw", "drawProportionally")
]
}
},
{
name: "snap",
title: "CONTROLS.CommonForceSnap",
icon: "fa-solid fa-plus",
toggle: true,
active: canvas.forceSnapVertices,
onClick: toggled => canvas.forceSnapVertices = toggled,
toolclip: {
src: "toolclips/tools/region-snap.webm",
heading: "CONTROLS.CommonForceSnap",
items: [
{ paragraph: "CONTROLS.RegionSnap" },
...buildItems("draw", "drawProportionally")
]
}
},
{
name: "clear",
title: "CONTROLS.RegionClear",
icon: "fa-solid fa-trash",
onClick: () => canvas.regions.deleteAll(),
button: true
}
],
activeTool: "select"
});
// Notes Layer Tools
controls.push({
name: "notes",
title: "CONTROLS.GroupNotes",
layer: "notes",
icon: "fa-solid fa-bookmark",
tools: [
{
name: "select",
title: "CONTROLS.NoteSelect",
icon: "fa-solid fa-expand"
},
{
name: "journal",
title: "NOTE.Create",
visible: game.user.hasPermission("NOTE_CREATE"),
icon: CONFIG.JournalEntry.sidebarIcon
},
{
name: "toggle",
title: "CONTROLS.NoteToggle",
icon: "fa-solid fa-map-pin",
toggle: true,
active: game.settings.get("core", NotesLayer.TOGGLE_SETTING),
onClick: toggled => game.settings.set("core", NotesLayer.TOGGLE_SETTING, toggled)
},
{
name: "clear",
title: "CONTROLS.NoteClear",
icon: "fa-solid fa-trash",
visible: isGM,
onClick: () => canvas.notes.deleteAll(),
button: true
}
],
activeTool: "select"
});
// Pass the Scene Controls to a hook function to allow overrides or changes
Hooks.callAll("getSceneControlButtons", controls);
return controls;
}
}