[Feature] TokenConfig Actor Size Edit (#1470)

* Added the select and handliing

* Fixed so tokenPreview works with tokenSize

* Correction for prototypeToken

* Extracted common logic to token-config-mixin.mjs

* Update templates/sheets-settings/token-config/appearance.hbs

Co-authored-by: Carlos Fernandez <CarlosFdez@users.noreply.github.com>

---------

Co-authored-by: Carlos Fernandez <CarlosFdez@users.noreply.github.com>
This commit is contained in:
WBHarry 2025-12-25 02:12:36 +01:00 committed by GitHub
parent c63ba3b41d
commit 50a307b271
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 167 additions and 85 deletions

View file

@ -1,41 +1,30 @@
export default class DhPrototypeTokenConfig extends foundry.applications.sheets.PrototypeTokenConfig { import DHTokenConfigMixin from './token-config-mixin.mjs';
/** @override */ import { getActorSizeFromForm } from './token-config-mixin.mjs';
static PARTS = {
tabs: super.PARTS.tabs, export default class DhPrototypeTokenConfig extends DHTokenConfigMixin(
identity: super.PARTS.identity, foundry.applications.sheets.PrototypeTokenConfig
appearance: { ) {
template: 'systems/daggerheart/templates/sheets-settings/token-config/appearance.hbs', /** @inheritDoc */
scrollable: [''] static DEFAULT_OPTIONS = {
}, ...super.DEFAULT_OPTIONS,
vision: super.PARTS.vision, form: { handler: DhPrototypeTokenConfig.#onSubmit }
light: super.PARTS.light,
resources: super.PARTS.resources,
footer: super.PARTS.footer
}; };
/** @inheritDoc */ /**
async _prepareResourcesTab() { * Process form submission for the sheet
const token = this.token; * @this {PrototypeTokenConfig}
const usesTrackableAttributes = !foundry.utils.isEmpty(CONFIG.Actor.trackableAttributes); * @type {ApplicationFormSubmission}
const attributeSource = */
this.actor?.system instanceof foundry.abstract.DataModel && usesTrackableAttributes static async #onSubmit(event, form, formData) {
? this.actor?.type const submitData = this._processFormData(event, form, formData);
: this.actor?.system; submitData.detectionModes ??= []; // Clear detection modes array
const TokenDocument = foundry.utils.getDocumentClass('Token'); this._processChanges(submitData);
const attributes = TokenDocument.getTrackedAttributes(attributeSource); const changes = { prototypeToken: submitData };
return {
barAttributes: TokenDocument.getTrackedAttributeChoices(attributes, attributeSource),
bar1: token.getBarAttribute?.('bar1'),
bar2: token.getBarAttribute?.('bar2'),
turnMarkerModes: DhPrototypeTokenConfig.TURN_MARKER_MODES,
turnMarkerAnimations: CONFIG.Combat.settings.turnMarkerAnimations
};
}
async _prepareAppearanceTab() { const changedTokenSizeValue = getActorSizeFromForm(this.element, this.actor);
const context = await super._prepareAppearanceTab(); if (changedTokenSizeValue) changes.system = { size: changedTokenSizeValue };
context.actorSizeUsed = this.token.actor ? Boolean(this.token.actor.system.size) : false;
return context; this.actor.validate({ changes, clean: true, fallback: false });
await this.actor.update(changes);
} }
} }

View file

@ -0,0 +1,114 @@
export default function DHTokenConfigMixin(Base) {
class DHTokenConfigBase extends Base {
/** @override */
static PARTS = {
tabs: super.PARTS.tabs,
identity: super.PARTS.identity,
appearance: {
template: 'systems/daggerheart/templates/sheets-settings/token-config/appearance.hbs',
scrollable: ['']
},
vision: super.PARTS.vision,
light: super.PARTS.light,
resources: super.PARTS.resources,
footer: super.PARTS.footer
};
_attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options);
switch (partId) {
case 'appearance':
htmlElement
.querySelector('#dhTokenSize')
?.addEventListener('change', this.onTokenSizeChange.bind(this));
break;
}
}
/** @inheritDoc */
async _prepareResourcesTab() {
const token = this.token;
const usesTrackableAttributes = !foundry.utils.isEmpty(CONFIG.Actor.trackableAttributes);
const attributeSource =
this.actor?.system instanceof foundry.abstract.DataModel && usesTrackableAttributes
? this.actor?.type
: this.actor?.system;
const TokenDocument = foundry.utils.getDocumentClass('Token');
const attributes = TokenDocument.getTrackedAttributes(attributeSource);
return {
barAttributes: TokenDocument.getTrackedAttributeChoices(attributes, attributeSource),
bar1: token.getBarAttribute?.('bar1'),
bar2: token.getBarAttribute?.('bar2'),
turnMarkerModes: DHTokenConfigBase.TURN_MARKER_MODES,
turnMarkerAnimations: CONFIG.Combat.settings.turnMarkerAnimations
};
}
async _prepareAppearanceTab() {
const context = await super._prepareAppearanceTab();
context.tokenSizes = CONFIG.DH.ACTOR.tokenSize;
context.tokenSize = this.actor?.system?.size;
context.usesActorSize = this.actor?.system?.metadata?.usesSize;
context.actorSizeDisable = context.usesActorSize && this.actor.system.size !== 'custom';
return context;
}
/** @inheritDoc */
_previewChanges(changes) {
if (!changes || !this._preview) return;
const tokenSizeSelect = this.element?.querySelector('#dhTokenSize');
if (this.actor && tokenSizeSelect && tokenSizeSelect.value !== 'custom') {
const tokenSizes = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).tokenSizes;
const tokenSize = tokenSizes[tokenSizeSelect.value];
changes.width = tokenSize;
changes.height = tokenSize;
}
const deletions = { '-=actorId': null, '-=actorLink': null };
const mergeOptions = { inplace: false, performDeletions: true };
this._preview.updateSource(mergeObject(changes, deletions, mergeOptions));
if (this._preview?.object?.destroyed === false) {
this._preview.object.initializeSources();
this._preview.object.renderFlags.set({ refresh: true });
}
}
async onTokenSizeChange(event) {
const value = event.target.value;
const tokenSizeDimensions = this.element.querySelector('#tokenSizeDimensions');
if (tokenSizeDimensions) {
const disabled = value !== 'custom';
tokenSizeDimensions.dataset.tooltip = disabled
? game.i18n.localize('DAGGERHEART.APPLICATIONS.TokenConfig.actorSizeUsed')
: '';
const disabledIcon = tokenSizeDimensions.querySelector('i');
if (disabledIcon) {
disabledIcon.style.opacity = disabled ? '' : '0';
}
const dimensionsInputs = tokenSizeDimensions.querySelectorAll('.form-fields input');
for (const input of dimensionsInputs) {
input.disabled = disabled;
}
}
}
}
return DHTokenConfigBase;
}
export function getActorSizeFromForm(element, actor) {
const tokenSizeSelect = element.querySelector('#dhTokenSize');
const isSizeDifferent = tokenSizeSelect?.value !== actor?.system?.size;
if (tokenSizeSelect && actor && isSizeDifferent) {
return tokenSizeSelect.value;
}
return null;
}

View file

@ -1,41 +1,11 @@
export default class DhTokenConfig extends foundry.applications.sheets.TokenConfig { import DHTokenConfigMixin from './token-config-mixin.mjs';
/** @override */ import { getActorSizeFromForm } from './token-config-mixin.mjs';
static PARTS = {
tabs: super.PARTS.tabs,
identity: super.PARTS.identity,
appearance: {
template: 'systems/daggerheart/templates/sheets-settings/token-config/appearance.hbs',
scrollable: ['']
},
vision: super.PARTS.vision,
light: super.PARTS.light,
resources: super.PARTS.resources,
footer: super.PARTS.footer
};
/** @inheritDoc */ export default class DhTokenConfig extends DHTokenConfigMixin(foundry.applications.sheets.TokenConfig) {
async _prepareResourcesTab() { async _processSubmitData(event, form, submitData, options) {
const token = this.token; const changedTokenSizeValue = getActorSizeFromForm(this.element, this.actor);
const usesTrackableAttributes = !foundry.utils.isEmpty(CONFIG.Actor.trackableAttributes); if (changedTokenSizeValue) this.token.actor.update({ 'system.size': changedTokenSizeValue });
const attributeSource =
this.actor?.system instanceof foundry.abstract.DataModel && usesTrackableAttributes
? this.actor?.type
: this.actor?.system;
const TokenDocument = foundry.utils.getDocumentClass('Token');
const attributes = TokenDocument.getTrackedAttributes(attributeSource);
return {
barAttributes: TokenDocument.getTrackedAttributeChoices(attributes, attributeSource),
bar1: token.getBarAttribute?.('bar1'),
bar2: token.getBarAttribute?.('bar2'),
turnMarkerModes: DhTokenConfig.TURN_MARKER_MODES,
turnMarkerAnimations: CONFIG.Combat.settings.turnMarkerAnimations
};
}
async _prepareAppearanceTab() { super._processSubmitData(event, form, submitData, options);
const context = await super._prepareAppearanceTab();
context.actorSizeUsed = this.token.actor ? Boolean(this.token.actor.system.size) : false;
return context;
} }
} }

View file

@ -10,22 +10,31 @@
</select> </select>
</div> </div>
{{/if}} {{/if}}
<fieldset>
<legend>{{localize "Token Size"}}</legend>
{{#if usesActorSize}}
<div class="form-group lim">
<label>{{localize "Size Category"}}</label>
<select id="dhTokenSize">
{{selectOptions tokenSizes selected=tokenSize valueAttr="id" labelAttr="label" localize=true}}
</select>
</div>
{{/if}}
<div class="form-group slim" {{#if actorSizeUsed}}data-tooltip="{{localize "DAGGERHEART.APPLICATIONS.TokenConfig.actorSizeUsed"}}"{{/if}}> <div id="tokenSizeDimensions" class="form-group slim" {{#if actorSizeDisable}}data-tooltip="{{localize "DAGGERHEART.APPLICATIONS.TokenConfig.actorSizeUsed"}}"{{/if}}>
<label> <label>
{{localize "TOKEN.Dimensions"}} <span class="units">({{localize "GridSpaces"}})</span> {{localize "TOKEN.Dimensions"}} <span class="units">({{localize "GridSpaces"}})</span>
{{#if actorSizeUsed}} <i class="fa-solid fa-lock" {{#unless actorSizeDisable}}style="opacity: 0%;"{{/unless}}></i>
<i class="fa-solid fa-lock"></i> </label>
{{/if}} <div class="form-fields">
</label> <label for="{{rootId}}-width">{{localize "DOCUMENT.FIELDS.width.label"}}</label>
<div class="form-fields"> {{formInput fields.width value=source.width id=(concat rootId "-width") disabled=actorSizeDisable}}
<label for="{{rootId}}-width">{{localize "DOCUMENT.FIELDS.width.label"}}</label> <label for="{{rootId}}-height">{{localize "DOCUMENT.FIELDS.height.label"}}</label>
{{formInput fields.width value=source.width id=(concat rootId "-width") disabled=actorSizeUsed}} {{formInput fields.height value=source.height id=(concat rootId "-height") disabled=actorSizeDisable}}
<label for="{{rootId}}-height">{{localize "DOCUMENT.FIELDS.height.label"}}</label> </div>
{{formInput fields.height value=source.height id=(concat rootId "-height") disabled=actorSizeUsed}}
</div> </div>
</div> </fieldset>
{{#if shapes}} {{#if shapes}}
{{formGroup fields.shape value=source.shape choices=shapes classes="slim" rootId=rootId}} {{formGroup fields.shape value=source.shape choices=shapes classes="slim" rootId=rootId}}