/*
|
|
* This file is part of the warpgate module (https://github.com/trioderegion/warpgate)
|
|
* Copyright (c) 2021 Matthew Haentschke.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
import { logger } from './logger.js'
|
|
import { Gateway } from './gateway.js'
|
|
import { MODULE } from './module.js'
|
|
import {queueUpdate} from './update-queue.js'
|
|
import { Mutator } from './mutator.js'
|
|
|
|
export class UserInterface {
|
|
|
|
static register() {
|
|
this.hooks();
|
|
this.settings();
|
|
}
|
|
|
|
static hooks() {
|
|
Hooks.on("renderActorSheet", UserInterface._renderActorSheet);
|
|
}
|
|
|
|
static settings() {
|
|
const config = true;
|
|
const settingsData = {
|
|
showDismissLabel : {
|
|
scope: "client", config, default: true, type: Boolean,
|
|
},
|
|
showRevertLabel : {
|
|
scope: "client", config, default: true, type: Boolean,
|
|
},
|
|
dismissButtonScope : {
|
|
scope: "client", config, default: 'spawned', type: String, choices: {
|
|
disabled: MODULE.localize('setting.option.disabled'),
|
|
spawned: MODULE.localize('setting.option.spawnedOnly'),
|
|
all: MODULE.localize('setting.option.all')
|
|
}
|
|
},
|
|
revertButtonBehavior : {
|
|
scope: 'client', config, default: 'pop', type: String, choices: {
|
|
disabled: MODULE.localize('setting.option.disabled'),
|
|
pop: MODULE.localize('setting.option.popLatestMutation'),
|
|
menu: MODULE.localize('setting.option.showMutationList')
|
|
}
|
|
}
|
|
};
|
|
|
|
MODULE.applySettings(settingsData);
|
|
}
|
|
|
|
static _renderActorSheet(app, html, data) {
|
|
logger.debug("app |", app);
|
|
logger.debug("html |", html);
|
|
logger.debug("data |", data);
|
|
|
|
UserInterface.addDismissButton(app, html, data);
|
|
UserInterface.addRevertMutation(app, html, data);
|
|
}
|
|
|
|
static _shouldAddDismiss(token) {
|
|
|
|
if ( !(token instanceof TokenDocument) ) return false;
|
|
|
|
switch (MODULE.setting('dismissButtonScope')){
|
|
case 'disabled':
|
|
return false;
|
|
case 'spawned':
|
|
|
|
const controlData = token?.actor.getFlag(MODULE.data.name, 'control');
|
|
|
|
/** do not add the button if we are not the controlling actor AND we aren't the GM */
|
|
if ( !(controlData?.user === game.user.id) &&
|
|
!game.user.isGM) return false;
|
|
|
|
return !!controlData;
|
|
case 'all':
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
static addDismissButton(app, html/*, data*/) {
|
|
const token = app.token;
|
|
|
|
/** this is not a warpgate spawned actor */
|
|
if (!UserInterface._shouldAddDismiss(token)) return;
|
|
|
|
/* do not add duplicate buttons! */
|
|
if(html.closest('.app').find('.dismiss-warpgate').length !== 0) {
|
|
logger.debug(MODULE.localize('debug.dismissPresent'));
|
|
return;
|
|
}
|
|
|
|
const label = MODULE.setting('showDismissLabel') ? MODULE.localize("display.dismiss") : ""
|
|
let dismissButton = $(`<a class="dismiss-warpgate" title="${MODULE.localize('display.dismiss')}"><i class="fas fa-user-slash"></i>${label}</a>`);
|
|
|
|
dismissButton.click( (/*event*/) => {
|
|
if (!token) {
|
|
logger.error(MODULE.localize('error.sheetNoToken'));
|
|
return;
|
|
}
|
|
const {id, parent} = token;
|
|
Gateway.dismissSpawn(id, parent?.id);
|
|
|
|
/** close the actor sheet if provided */
|
|
app?.close({submit: false});
|
|
});
|
|
|
|
let title = html.closest('.app').find('.window-title');
|
|
dismissButton.insertAfter(title);
|
|
|
|
}
|
|
|
|
static _shouldAddRevert(token) {
|
|
|
|
if ( !(token instanceof TokenDocument) ) return false;
|
|
|
|
const mutateStack = warpgate.mutationStack(token).stack;
|
|
|
|
/* this is not a warpgate mutated actor,
|
|
* or there are no remaining stacks to peel */
|
|
if (mutateStack.length == 0) return false;
|
|
|
|
return MODULE.setting('revertButtonBehavior') !== 'disabled';
|
|
}
|
|
|
|
static _getTokenFromApp(app) {
|
|
|
|
const {token, actor} = app;
|
|
|
|
const hasToken = token instanceof TokenDocument;
|
|
|
|
if( !hasToken ) {
|
|
/* check if linked and has an active token on scene */
|
|
const candidates = actor?.getActiveTokens() ?? [];
|
|
const linkedToken = candidates.find( t => (MODULE.isV10?t.document:t.data).actorLink )?.document ?? null;
|
|
|
|
return linkedToken;
|
|
|
|
}
|
|
|
|
return token;
|
|
}
|
|
|
|
static addRevertMutation(app, html, data) {
|
|
|
|
/* do not add duplicate buttons! */
|
|
let foundButton = html.closest('.app').find('.revert-warpgate')
|
|
|
|
/* we remove the current button on each render
|
|
* in case the render was triggered by a mutation
|
|
* event and we need to update the tool tip
|
|
* on the revert stack
|
|
*/
|
|
if (foundButton) {
|
|
foundButton.remove();
|
|
}
|
|
|
|
const token = UserInterface._getTokenFromApp(app);
|
|
|
|
if(!UserInterface._shouldAddRevert(token)) return;
|
|
|
|
const mutateStack = token?.actor?.getFlag(MODULE.data.name, 'mutate');
|
|
|
|
/* construct the revert button */
|
|
const label = MODULE.setting('showRevertLabel') ? MODULE.localize("display.revert") : ""
|
|
const stackCount = mutateStack.length > 1 ? ` 1/${mutateStack.length}` : '';
|
|
let revertButton = $(`<a class="revert-warpgate" title="${MODULE.localize('display.revert')}${stackCount}"><i class="fas fa-undo-alt"></i>${label}</a>`);
|
|
|
|
revertButton.click( async (event) => {
|
|
const shouldShow = (shiftKey) => {
|
|
const mode = MODULE.setting('revertButtonBehavior')
|
|
const show = mode == 'menu' ? !shiftKey : shiftKey;
|
|
return show;
|
|
}
|
|
|
|
let name = undefined;
|
|
const showMenu = shouldShow(event.shiftKey);
|
|
|
|
if (showMenu) {
|
|
const buttons = mutateStack.map( mutation => {return {label: mutation.name, value: mutation.name}} )
|
|
name = await warpgate.buttonDialog({buttons, title: MODULE.localize('display.revertDialogTitle')}, 'column');
|
|
if (name === false) return;
|
|
}
|
|
|
|
/* need to queue this since 'click' could
|
|
* happen at any time.
|
|
* Do not need to remove the button here
|
|
* as it will be refreshed on the render call
|
|
*/
|
|
queueUpdate( async () => {
|
|
await Mutator.revertMutation(token, name);
|
|
app?.render(false);
|
|
});
|
|
|
|
});
|
|
|
|
let title = html.closest('.app').find('.window-title');
|
|
revertButton.insertAfter(title);
|
|
}
|
|
|
|
}
|