Ajoute une propriété "Ombre portée" (box-shadow), disponible sur tout widget

Nouveau groupe "Ombre" dans le panneau de propriétés, à côté de "Bordure"
(même universalité — voir UNIVERSAL_CONTROLS) : décalage X/Y, flou,
étendue, couleur et opacité, combinés en une seule valeur CSS box-shadow
(couleur+opacité fusionnées en rgba(), un <input type="color"> seul ne
portant pas de canal alpha). Décalages/flou/étendue tous à 0 = pas
d'ombre, même convention que border-width à 0 = pas de bordure.

Nouveau ctype "shadow" (c_shadow.py), suit exactement le même principe
que le ctype "size" déjà existant (size_override_controls.py) : plusieurs
entrées de formulaire pour un seul réglage, composées/décomposées dans
save_element_controls.py et control_value.py plutôt que passées par le
chemin générique clé->valeur.

Ajoute tests/test_shadow_controls.py (présence dans le panneau,
composition de la valeur CSS, aller-retour dans le formulaire, remise à
zéro qui retire l'ombre).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-08-25 14:37:38 +02:00
co-authored by Claude Sonnet 5
parent 9c9e3c5379
commit bda082bffd
7 changed files with 151 additions and 1 deletions
+20
View File
@@ -730,6 +730,26 @@
oninput="this.nextElementSibling.textContent = 'x' + this.value">
<span class="sliderValue tag">x{{ c.value }}</span>
</div>
{% elif c.type == 'shadow' %}
<div class="control">
<div class="fieldRow">
<div class="formField" style="flex:1;"><label class="label is-small">Décalage X</label><input class="input is-small" type="number" name="ctrl_{{ c.key }}_x" value="{{ c.value.x }}"></div>
<div class="formField" style="flex:1;"><label class="label is-small">Décalage Y</label><input class="input is-small" type="number" name="ctrl_{{ c.key }}_y" value="{{ c.value.y }}"></div>
</div>
<div class="fieldRow" style="margin-top:6px;">
<div class="formField" style="flex:1;"><label class="label is-small">Flou</label><input class="input is-small" type="number" min="0" name="ctrl_{{ c.key }}_blur" value="{{ c.value.blur }}"></div>
<div class="formField" style="flex:1;"><label class="label is-small">Étendue</label><input class="input is-small" type="number" min="0" name="ctrl_{{ c.key }}_spread" value="{{ c.value.spread }}"></div>
</div>
<div class="fieldRow" style="margin-top:6px; align-items:center;">
<input class="input" type="color" style="flex:0 0 60px; padding:2px;" name="ctrl_{{ c.key }}_color" value="{{ c.value.color }}">
<div class="sliderRow" style="flex:1;">
<input type="range" name="ctrl_{{ c.key }}_opacity" min="0" max="1" step="0.05" value="{{ c.value.opacity }}"
oninput="this.nextElementSibling.textContent = Math.round(this.value * 100) + '%'">
<span class="sliderValue tag">{{ (c.value.opacity * 100)|round|int }}%</span>
</div>
</div>
<p class="help">Décalages, flou et étendue tous à 0 = pas d'ombre.</p>
</div>
{% elif c.type == 'align' %}
<div class="control">
<div class="buttons has-addons alignGroup">