From 22dc500801d8cf0ccfbab9394cb1aa2068154593 Mon Sep 17 00:00:00 2001 From: trotFunky Date: Sun, 1 Jun 2025 18:37:18 +0100 Subject: [PATCH] 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. --- README.md | 13 ++++++++++ lang/en.json | 8 ++++++ lang/fr.json | 8 ++++++ scripts/token_ui_adjust.mjs | 51 +++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/README.md b/README.md index ff63d83..e2897c0 100644 --- a/README.md +++ b/README.md @@ -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, diff --git a/lang/en.json b/lang/en.json index 12be337..9a0f3ce 100644 --- a/lang/en.json +++ b/lang/en.json @@ -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." + } + } } } } diff --git a/lang/fr.json b/lang/fr.json index b0dc8f5..de723f1 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -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." + } + } } } } diff --git a/scripts/token_ui_adjust.mjs b/scripts/token_ui_adjust.mjs index d9fe92f..44af60e 100644 --- a/scripts/token_ui_adjust.mjs +++ b/scripts/token_ui_adjust.mjs @@ -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)) + } + }) +})