Implement Token UI adjustments

Implement the sub-module moving the attribute bars and nameplate
to work well with our dynamic borders.

The attribute bars are moved below the token, one on
top of the other, and the nameplate is moved above.

This is done by monkey patching the `_drawBar()` and
`_refreshNameplate()` functions from the Token class.
This is vulnerable to compatibility issues with other
modules, but is the only way I found for the changes
to be shown without further input.

Indeed, those functions are called after the `drawToken`
hook, which makes it impossible to move those UI elements
there.
We can do it in the `refreshToken` hook, which works *but*
requires the canvas view to be moved at least once for
the position change to be reflected, which looks a bit
broken.

So we monkey patch the functions, but bind them
beforehand to be able to call them within our custom
function as we don't want to duplicate what they do.

Update README and translations for the added setting.
This commit is contained in:
trotFunky 2025-06-01 18:37:18 +01:00
parent ab02dd139a
commit 22dc500801
4 changed files with 80 additions and 0 deletions

View file

@ -51,6 +51,19 @@ There are currently two main issues that need to be fixed :
and thus the border type, cannot be properly determined on scene switch.
- This can be fixed by receiving a combat update, either from the players or the GM, on the scene.
## Token UI adjustments
Given that we add a border *on* the tokens, it conflicts with the base attribute bars which are drawn over the token's
square.
The token UI adjustments move the two attribute bars below the token, outside its space, first HP then mana.
As this is where the nameplate of the token should be, move it above the token instead.
### Limitations
- The token's detailed UI when right-clicking will overlap the bars in their new positions (it already overlapped the name)
- The current implementation relies on monkey patching, which make it vulnerable to compatibility issues with
other modules manipulating the same methods.
# Compendia
- The only thing in the compendium pack is a macro automating the tinkerer's alchemy potions,

View file

@ -17,6 +17,14 @@
"Hint": "The image to use as a border for player tokens that have taken their turn."
}
}
},
"TokenUiAdjust": {
"Settings": {
"Enabled": {
"Name": "Token UI adjustments",
"Hint": "Moves both attribute bars below the token and the nameplate above."
}
}
}
}
}

View file

@ -17,6 +17,14 @@
"Hint": "L'image à utiliser comme bordure pour les jetons joueurs qui ont joué leur tour."
}
}
},
"TokenUiAdjust": {
"Settings": {
"Enabled": {
"Name": "Ajustements d'interface des tokens",
"Hint": "Déplace les barres d'attributs sous le token et le nom au dessus."
}
}
}
}
}

View file

@ -1,2 +1,53 @@
import * as MillsFabula from "./mills_fabula.mjs";
const TokenUiSettings = Object.freeze({
Enabled: "uiAdjustEnabled",
})
Hooks.once("setup", () => {
game.settings.register(MillsFabula.id, TokenUiSettings.Enabled, {
name: "MF.TokenUiAdjust.Settings.Enabled.Name",
hint: "MF.TokenUiAdjust.Settings.Enabled.Hint",
type: Boolean,
config: true,
scope: "world",
requiresReload: true,
default: true,
})
if (!game.settings.get(MillsFabula.id, TokenUiSettings.Enabled)) {
return;
}
/** Padding above and below the token, percentage of a grid square. */
const top_bot_padding = 5;
Hooks.on("drawToken", (drawn_token) => {
/*
* Drawing attribute bars and nameplates are handled by private functions called
* after the `drawToken` hook. That means that we cannot change their position in this hook.
*
* We could update them in the `refreshToken` hook, which works, but is called a lot more than
* necessary and needs a view update (move the view) from the canvas to show the updates.
*
* Instead : we can replace the draw functions handling the bars and nameplate.
* They are still useful, so make of copy bound to the drawn token so that we can call them
* in our replacement function, then make the changes that we need.
*/
let base_drawBar = drawn_token._drawBar.bind(drawn_token);
drawn_token._drawBar = (number, bar, data) => {
const token_height = drawn_token.getSize().height
const padding = drawn_token.scene.grid.size * top_bot_padding/100;
base_drawBar(number, bar, data)
bar.position.set(0, token_height + padding + number * bar.height)
}
let base_refreshNameplate = drawn_token._refreshNameplate.bind(drawn_token);
drawn_token._refreshNameplate = () => {
const token_width = drawn_token.getSize().width;
const padding = drawn_token.scene.grid.size * top_bot_padding/100;
base_refreshNameplate()
drawn_token.nameplate.position.set(token_width/2, -(padding + drawn_token.nameplate.height))
}
})
})