Add basic support for registering custom icons that override icons provided by the system/modules
This commit is contained in:
parent
c90137b18f
commit
c7541db1d9
9 changed files with 279 additions and 6 deletions
132
module/apps/StatusEffectIconConfig.mjs
Normal file
132
module/apps/StatusEffectIconConfig.mjs
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
import { __ID__, filePath } from "../consts.mjs";
|
||||
import { key as customStatusIconsKey } from "../tweaks/customStatusIcons.mjs";
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
const { SettingsConfig } = foundry.applications.settings;
|
||||
|
||||
export class StatusEffectIconConfig extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
// #region Options
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: `form`,
|
||||
classes: [
|
||||
__ID__,
|
||||
`StatusEffectIconConfig`,
|
||||
],
|
||||
window: {
|
||||
title: `OFT.apps.StatusEffectIconConfig.title`,
|
||||
},
|
||||
position: {
|
||||
width: 550,
|
||||
},
|
||||
form: {
|
||||
handler: this.#onSubmit,
|
||||
closeOnSubmit: true,
|
||||
submitOnChange: false,
|
||||
},
|
||||
actions: {
|
||||
pickViaImageTagger: this.#pickViaImageTagger,
|
||||
removeOverride: this.#removeOverride,
|
||||
},
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
list: {
|
||||
template: filePath(`templates/StatusEffectIconConfig/effects.hbs`),
|
||||
scrollable: [``],
|
||||
},
|
||||
footer: {
|
||||
template: filePath(`templates/StatusEffectIconConfig/footer.hbs`),
|
||||
},
|
||||
};
|
||||
// #endregion Options
|
||||
|
||||
// #region Instance Data
|
||||
#overrides = null;
|
||||
#originalOverrides = null;
|
||||
// #endregion Instance Data
|
||||
|
||||
// #region Lifecycle
|
||||
async _onRender() {
|
||||
const pickers = this.element.querySelectorAll(`file-picker`);
|
||||
for (const picker of pickers) {
|
||||
picker.addEventListener(`change`, this.#onChangeFilePicker.bind(this));
|
||||
};
|
||||
};
|
||||
// #endregion Lifecycle
|
||||
|
||||
// #region Data Prep
|
||||
_prepareContext() {
|
||||
const ctx = {
|
||||
meta: {
|
||||
idp: this.id,
|
||||
},
|
||||
showImageTaggerButton: game.modules.get(`image-tagger`).active,
|
||||
};
|
||||
|
||||
const effects = Object.values(CONFIG.statusEffects);
|
||||
|
||||
this.#overrides ??= game.settings.get(__ID__, customStatusIconsKey);
|
||||
this.#originalOverrides ??= foundry.utils.deepClone(this.#overrides);
|
||||
// console.log({ original: this.#originalOverrides, current: this.#overrides });
|
||||
|
||||
ctx.effects = [];
|
||||
for (const effect of effects) {
|
||||
|
||||
let preview = this.#overrides[effect.id] ?? effect.img;
|
||||
if (
|
||||
this.#originalOverrides[effect.id] != null
|
||||
&& this.#overrides[effect.id] === null
|
||||
) {
|
||||
preview = null;
|
||||
}
|
||||
|
||||
ctx.effects.push({
|
||||
id: effect.id,
|
||||
preview,
|
||||
name: game.i18n.localize(effect.name),
|
||||
img: this.#overrides[effect.id],
|
||||
hasOverride: this.#overrides[effect.id] != null,
|
||||
});
|
||||
};
|
||||
|
||||
return ctx;
|
||||
};
|
||||
// #endregion Data Prep
|
||||
|
||||
// #region Event Listeners
|
||||
async #onChangeFilePicker(event) {
|
||||
const target = event.currentTarget;
|
||||
const id = target.closest(`[data-effect-id]`).dataset.effectId;
|
||||
this.#overrides[id] = target.value || null;
|
||||
await this.render();
|
||||
};
|
||||
|
||||
/** @this {StatusEffectIconConfig} */
|
||||
static async #onSubmit() {
|
||||
game.settings.set(__ID__, customStatusIconsKey, this.#overrides);
|
||||
SettingsConfig.reloadConfirm({ world: true });
|
||||
};
|
||||
// #endregion Event Listeners
|
||||
|
||||
// #region Actions
|
||||
/** @this {StatusEffectIconConfig} */
|
||||
static async #pickViaImageTagger(event, element) {
|
||||
const id = element.closest(`[data-effect-id]`)?.dataset.effectId;
|
||||
if (!id) { return };
|
||||
|
||||
const ArtBrowser = game.modules.get(`image-tagger`).api.Apps.ArtBrowser;
|
||||
const newImage = await ArtBrowser.select();
|
||||
if (!newImage) { return };
|
||||
this.#overrides[id] = newImage;
|
||||
|
||||
await this.render();
|
||||
};
|
||||
|
||||
/** @this {StatusEffectIconConfig} */
|
||||
static async #removeOverride(event, element) {
|
||||
const id = element.closest(`[data-effect-id]`)?.dataset.effectId;
|
||||
this.#overrides[id] = null;
|
||||
await this.render();
|
||||
};
|
||||
// #endregion Actions
|
||||
};
|
||||
|
|
@ -4,6 +4,7 @@ import { addGlobalDocReferrer } from "../tweaks/addGlobalDocReferrer.mjs";
|
|||
import { autoUnpauseOnLoad } from "../tweaks/autoUnpauseOnLoad.mjs";
|
||||
import { chatImageLinks } from "../tweaks/chatImageLinks.mjs";
|
||||
import { chatSidebarBackground } from "../tweaks/chatSidebarBackground.mjs";
|
||||
import { customStatusIcons } from "../tweaks/customStatusIcons.mjs";
|
||||
import { defaultHotbarPage } from "../tweaks/defaultHotbarPage.mjs";
|
||||
import { hotbarButtonGap } from "../tweaks/hotbarButtonGap.mjs";
|
||||
import { hotbarButtonSize } from "../tweaks/hotbarButtonSize.mjs";
|
||||
|
|
@ -48,6 +49,7 @@ Hooks.on(`setup`, () => {
|
|||
hotbarButtonGap();
|
||||
repositionHotbar();
|
||||
|
||||
customStatusIcons();
|
||||
chatImageLinks();
|
||||
chatSidebarBackground();
|
||||
startSidebarExpanded();
|
||||
|
|
|
|||
44
module/tweaks/customStatusIcons.mjs
Normal file
44
module/tweaks/customStatusIcons.mjs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { SettingStatusEnum, status } from "../utils/SettingStatus.mjs";
|
||||
import { __ID__ } from "../consts.mjs";
|
||||
import { Logger } from "../utils/Logger.mjs";
|
||||
import { preventTweakRegistration } from "../utils/preRegisterTweak.mjs";
|
||||
import { StatusEffectIconConfig } from "../apps/StatusEffectIconConfig.mjs";
|
||||
|
||||
export const key = `customStatusIcons`;
|
||||
|
||||
export function customStatusIcons() {
|
||||
status[key] = SettingStatusEnum.Unknown;
|
||||
if (preventTweakRegistration(key)) { return };
|
||||
|
||||
// #region Registration
|
||||
Logger.log(`Registering tweak: ${key}`);
|
||||
game.settings.registerMenu(__ID__, `${key}Menu`, {
|
||||
name: `OFT.menu.${key}.name`,
|
||||
hint: `OFT.menu.${key}.hint`,
|
||||
label: `OFT.menu.${key}.label`,
|
||||
restricted: true,
|
||||
type: StatusEffectIconConfig,
|
||||
});
|
||||
game.settings.register(__ID__, key, {
|
||||
scope: `world`,
|
||||
config: false,
|
||||
type: Object,
|
||||
default: {},
|
||||
});
|
||||
// #endregion Registration
|
||||
|
||||
// #region Implementation
|
||||
Hooks.on(`ready`, () => {
|
||||
const value = game.settings.get(__ID__, key);
|
||||
|
||||
const effects = Object.values(CONFIG.statusEffects);
|
||||
for (const effect of effects) {
|
||||
if (value[effect.id] != null) {
|
||||
effect.img = value[effect.id];
|
||||
};
|
||||
};
|
||||
});
|
||||
// #endregion Implementation
|
||||
|
||||
status[key] = SettingStatusEnum.Registered;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue