Aller au contenu principal

Changelog — ApocalyInterfaceLib


Phase 7 — Repro UIs + build + doc

Commit 4 — Build Maven local + documentation complète (2026-05-23)

Build & distribution

  • build.gradle — publication Maven complétée : groupId, artifactId, version et métadonnées POM (name, description) explicitement déclarés dans le bloc publishing. Coordonnées publiées : ca.tawess123.apocalyinterface:apocalyinterfacelib:1.0.0. La tâche ./gradlew publishToMavenLocal était déjà fonctionnelle via le plugin maven-publish ; les coordonnées sont maintenant lisibles sans ambiguïté dans le POM généré.
  • src/main/resources/META-INF/mods.toml — conforme §7.2 (vérifié) : displayTest="IGNORE_ALL_VERSION", dépendances Forge et Minecraft en side="CLIENT".

Documentation — audit et trous comblés

Audit widget/conteneur vs docs reference : aucun widget ni conteneur manquant.

Fichiers créés :

  • docs/README.md — vue d'ensemble du projet, démarrage rapide, structure de la doc
  • docs/guide/01-installation.md — lignes exactes build.gradle (mavenLocal() + fg.deobf(...)) et bloc mods.toml pour un mod consommateur ; guide reproductible pour brancher le mod Clan sur la lib
  • docs/guide/02-premier-ecran.md — exemple complet copiable de A à Z basé sur ClanHubDemoScreen : classe, ouverture depuis packet S2C, refresh, clés i18n requises
  • docs/guide/03-widgets.md — catalogue commenté des 11 widgets + visibleIf, avec liens vers reference/widgets/
  • docs/guide/04-layout.md — système de layout : Column, Row, Card, Grid, Spacer, Divider, ScrollableColumn ; tableau récapitulatif ; note scroll global automatique
  • docs/guide/05-i18n.md — guide i18n complet : structure de fichiers, conventions de nommage des clés, usage dans chaque type de widget, fallback LocaleResolver
  • docs/reference/data-source.md — référence manquante : interface DataSource<T>, source statique vs lambda, widgets acceptant un DataSource, pattern avec update(), scope v1/v2

Critère de réussite

./gradlew publishToMavenLocal publie le JAR avec les coordonnées ca.tawess123.apocalyinterface:apocalyinterfacelib:1.0.0 dans le dépôt Maven local. Un mod consommateur peut ajouter mavenLocal() + fg.deobf("ca.tawess123.apocalyinterface:apocalyinterfacelib:1.0.0") dans son build.gradle et le bloc [[dependencies.monmod]] dans mods.toml — la lib charge et l'API publique est accessible. La documentation couvre tous les widgets, layouts, screens et concepts clés.


Commit 3 — visibleIf : visibilité conditionnelle sur tous les widgets (2026-05-23)

Principe

visibleIf(boolean) est un raccourci de builder qui conditionne la visibilité d'un widget. Un widget invisible prend zéro pixel dans le layout — ni rendu, ni compté dans la hauteur, et les widgets suivants remontent. Tout gap autour du widget masqué est également absorbé.

API publique — Interface Widget

  • api/widget/Widget.java — ajout de la méthode default boolean isVisible() retournant true. Contrat : les conteneurs appellent isVisible() avant toute opération de layout ou de rendu sur leurs enfants.

API publique — Widgets (builder)

Tous les widgets suivants exposent désormais .visibleIf(boolean) dans leur builder :

  • Label, Button, KeyValueRow, ProgressBar, SearchField
  • ItemIcon, TabBar, ScrollableList<T>, ClickableList<T>, SlotGrid

Chaque widget stocke le booléen et override isVisible(). La valeur par défaut est true — aucun écran existant ne change de comportement (rétrocompatibilité totale).

API publique — Conteneurs

  • Column, Cardvisible(boolean) fluent sur l'instance ; logique mise à jour pour sauter les enfants invisibles dans getPreferredHeight, render, mouseClicked, mouseScrolled, keyPressed, charTyped. Le gap n'est ajouté qu'entre deux widgets visibles consécutifs.
  • Row — idem ; la largeur disponible est redistribuée entre les enfants visibles uniquement (childWidth recalculé sur countVisible()).
  • ScrollableColumnvisibleIf(boolean) dans le Builder ; render, mouseClicked, mouseScrolled et syncController travaillent sur la liste filtrée visibleChildren().

Avertissement sécurité (documenté explicitement)

visibleIf est un confort d'affichage — pas de sécurité. Masquer un bouton côté client ne protège aucune action serveur. Toute action sensible doit être revérifiée côté serveur.

Mod démo

  • VisibilityDemoScreen.java (nouveau) — touche V : 3 boutons (toggle, cible, dessous). Clic sur toggle → cible disparaît et bouton dessous remonte immédiatement. Clic à nouveau → réapparaît.
  • KeyBindings.java — ajout keybind V (open_visibility) ouvrant VisibilityDemoScreen
  • Lang files en_us / fr_ca — 7 nouvelles clés visibility.*

Documentation

  • docs/reference/widgets/visibleif.md — référence complète : principe, API par type, comportement du gap, pattern toggle avec init(), avertissement sécurité mis en évidence, démo in-game

Critère de réussite

Touche V en jeu → écran Démo visibleIf. Clic « Masquer » → bouton central disparaît, bouton en dessous remonte (zéro gap orphelin). Clic « Afficher » → bouton réapparaît. Tous les autres écrans (J, M, C, R, H) inchangés.


Commit 2 — ScrollableColumn : zone scrollable interne (2026-05-23)

Nouveauté

  • api/layout/ScrollableColumn — nouveau conteneur à hauteur fixe qui scrolle ses enfants en interne (molette, scissor, mini scrollbar). Réutilise ScrollController (1 enfant = 1 ligne). Le fixedHeight doit être un multiple exact de (hauteur_enfant + gap) pour éviter tout enfant à moitié coupé.

Démo mise à jour

  • ClanHubDemoScreen — pattern card sticky + ScrollableColumn de boutons. 9 boutons, 5 visibles (fixedHeight = 116 px = 5×20+4×4). ScrollableColumn conservée en champ final → scroll préservé au refresh.

Documentation

  • docs/reference/layout/scrollable-column.md — ajouté.

Commit 1 — Color overrides sur tous les widgets publics (2026-05-23)

Principe

Chaque option est optionnelle. Si non précisée, le widget lit la constante par défaut dans ApocalyColors — aucun écran existant ne change d'apparence (rétrocompatibilité totale).

API publique — Widgets

  • api/widget/Label.java — ajout .color(int argb) : surcharge directe de la couleur du texte, complémentaire aux raccourcis .accent() / .muted() / .title() existants.

  • api/widget/KeyValueRow.java — ajout .keyColor(int argb) (défaut : TEXT) et .valueColor(int argb) (défaut : ACCENT) : chaque côté de la ligne est colorable indépendamment.

  • api/widget/Button.java — ajout .borderColor(int argb) (bordure au repos actif) et .accentColor(int argb) (bordure + texte au survol actif). La lib dérive automatiquement les états désactivés en appliquant un facteur ×0,4 sur R, G, B (alpha préservé). .textColor(int) existant est conservé et compatible.

  • api/widget/ProgressBar.java — ajout .backgroundColor(int argb) (défaut : PANEL_BG). .fillColor(int) existant est conservé.

API publique — Layout

  • api/layout/Card.java — ajout .borderColor(int argb) fluent (défaut : SUB_BORDER) : surcharge la bordure 1 px du sous-panneau. Import ApocalyColors ajouté.

API publique — Screen

  • api/screen/ApocalyScreen.java — ajout de deux setters protégés finals : borderColor(int argb) et titleColor(int argb), à appeler dans le constructeur de la sous-classe. Stockés sur l'instance, ré-appliqués à chaque init() et update().

Core interne

  • core/render/PanelRenderer.java — restructuration : les versions sans couleur délèguent aux nouvelles surcharges drawPanel(..., borderColor, titleColor) et drawSubPanel(..., borderColor). Rétrocompatibilité totale des appelants existants.
  • core/layout/PanelHost.java — ajout des champs borderColor / titleColor (-1 = thème par défaut) et des setters setBorderColor(int) / setTitleColor(int) ; le rendu utilise la surcharge colorée de PanelRenderer.

Mod démo

  • DemoScreen.java — ajout section « Surcharge de couleurs » :
    • Label.color(0xFF00CCFF) — cyan vif
    • Button par défaut (repère orange) côte à côte avec Button.accentColor(SUCCESS) (vert)
    • Card.borderColor(0xFF7755FF) (bordure violette) contenant un KeyValueRow avec .keyColor(MUTED_TEXT) et .valueColor(0xFFFFCC44) (or)
  • Lang files en_us / fr_ca — 5 nouvelles clés color.*

Documentation

  • docs/reference/widgets/label.md.color(int) ajouté au builder
  • docs/reference/widgets/key-value-row.md.keyColor / .valueColor ajoutés
  • docs/reference/widgets/button.md.borderColor / .accentColor ajoutés, tableau des états mis à jour avec la logique de dérivation
  • docs/reference/widgets/progress-bar.md.backgroundColor ajouté
  • docs/reference/layout/card.md.borderColor ajouté
  • docs/reference/screen/apocaly-screen.md — section « Surcharge de couleurs du panneau » ajoutée

Critère de réussite

Touche J en jeu → faire défiler jusqu'à la section « Surcharge de couleurs ». Vérifier : label cyan visible, bouton vert au survol (≠ orange par défaut), bordure violette de la Card. Tous les autres écrans (hub, marchand, container, refresh) affichent toujours les couleurs orange / cyan du thème — aucune régression.


Phase 6 — DataSource + refresh (2026-05-23)

Commit 1 — update() + démo refresh (2026-05-23)

API publique (api/screen/)

  • api/screen/ApocalyScreen.java — ajout de public final void update() : relance buildLayout() et recalcule le layout sans fermer ni recréer l'écran (SPEC §6.3). La position de défilement courante est préservée automatiquement via PanelHost.getScrollOffset() / setScrollOffset() — exactement le même mécanisme que la persistance du scroll au resize. Les DataSource statiques (DataSource.of(val)) capturent la valeur fraîche à chaque buildLayout : aucun mécanisme supplémentaire n'est requis pour afficher des données mises à jour.

DataSource (§6.2) — confirmé conforme

  • DataSource.of(value) présent depuis Phase 3, conforme à la spec.
  • Label, KeyValueRow, ProgressBar acceptent tous un DataSource<T> via leur builder depuis Phase 3–4 — aucune modification nécessaire.

Mod démo (client/)

  • RefreshDemoScreen.java (nouveau) — écran de démonstration Phase 6 :
    • Champs d'instance points et membres mis à jour à chaque clic du bouton
    • Card avec 3 KeyValueRow et un ProgressBar (membres/10) — valeurs recréées via DataSource.of(...) à chaque buildLayout appelé par update()
    • Bouton « Simuler refresh » : points += 50; membres = min(membres+1,10); update()
    • ScrollableList de 12 membres (5 lignes visibles) pour valider que le scroll est préservé au refresh
  • KeyBindings.java — ajout keybind R (open_refresh) ouvrant RefreshDemoScreen
  • Lang files en_us / fr_ca — clés refresh.* + key.open_refresh

Critère de réussite

Touche R en jeu → écran Phase 6. Clic sur « Simuler refresh » → Points et barre de progression se mettent à jour instantanément, sans fermer l'écran. Faire défiler la liste jusqu'en bas, puis cliquer refresh → la liste reste en position (scroll préservé).

Documentation

  • docs/reference/screen/apocaly-screen.md — ajout section « Refresh dynamique (§6.3) »
    • update() dans le tableau API + note dans les « Notes »

Phase 5 — Container + slots vanilla (2026-05-23 →)

Commit 1 — Spacer + Divider (2026-05-23)

API publique (api/layout/)

  • api/layout/Spacer.java — espace vide de hauteur configurable (SPEC §4.2) : factory Spacer.of(int height). render ne fait rien ; getPreferredHeight retourne la hauteur configurée. Complète le gap global d'une Column pour un espacement ponctuel entre groupes logiques.
  • api/layout/Divider.java — ligne de séparation horizontale 1 px (SPEC §4.2) : couleur par défaut ApocalyColors.DIVIDER (0x55FFFFFF). Factory Divider.create() + Divider.builder().color(int).build() pour couleur personnalisée. RenderSystem.enableBlend() appelé avant le fill (couleur semi-transparente).

Mod démo

  • DemoScreen.java — ajout d'un Spacer(6) + Divider + Spacer(6) entre la section Clan Hub (Phase 3) et la section ScrollableList (Phase 4), pour valider visuellement les deux widgets.

Documentation

  • docs/reference/layout/spacer.md — factory, comportement, note gap vs spacer
  • docs/reference/layout/divider.md — factory, builder color, pattern combiné avec Spacer

Commit 5 — Démo 3×3 slots (2026-05-23)

Mod démo (client/container/)

  • TestContainerMenu.java — ajout de 9 slots (grille 3×3) dans un SimpleContainer. Positions calculées pour s'aligner pixel-parfaitement avec SlotGrid : x = 11 + col×20, y = 32 + row×20 (stride 20 px = 18 slot + 2 gap). SLOT_ORIGIN_X = 11 (fond à leftPos+10 = début de la zone de contenu), SLOT_ORIGIN_Y = 32 (fond à topPos+31 = DIVIDER_OFFSET + 1 + CONTENT_TOP_GAP). Constantes exposées en package-private pour référence depuis TestContainerScreen.
  • TestContainerScreen.javabuildLayout remplacé : uniquement un SlotGrid sur this.menu.slots + screenOrigin(this.leftPos, this.topPos).

Critère de réussite

Touche C en jeu → 9 slots stylés Apocaly (fond noir translucide + bordure blanche) disposés en 3×3 dans le panneau, sans fond gris vanilla. Items déposés dans les slots apparaissent par-dessus les fonds.


Commit 4 — SlotGrid (2026-05-23)

API publique (api/widget/)

  • api/widget/SlotGrid.java — widget fond de slots vanilla (SPEC §4.3) : lit slot.x / slot.y du menu (source de vérité), dessine fond SLOT_BG 18×18 px
    • contour 1 px SUB_BORDER à (leftPos + slot.x - 1, topPos + slot.y - 1). Rendu dans renderBg() — les fonds apparaissent sous les items (Forge les dessine par-dessus via AbstractContainerScreen.render()). Builder .slots(List<Slot>) + .screenOrigin(leftPos, topPos). getPreferredHeight = maxY − minY + 18 (span des fonds réels depuis les positions du menu).

API publique — Thème

  • api/theme/ApocalyColors — ajout SLOT_BG = 0x80050505 (fond slot, noir 50 % alpha).

Documentation

  • docs/reference/widgets/slot-grid.md — contrat alignement Menu = source de vérité, formule de positionnement leftPos + slot.x - 1, avertissement MenuType null (démo client-only vs production DeferredRegister), ordre de rendu critique

Commit 3 — ApocalyContainerScreen<T> (2026-05-23)

API publique (api/screen/)

  • api/screen/ApocalyContainerScreen.java — classe de base pour les écrans à inventaire (SPEC §4.1) : étend AbstractContainerScreen<T extends AbstractContainerMenu>. imageWidth/imageHeight fixés dans le constructeur avant super.init()AbstractContainerScreen.init() calcule leftPos/topPos à partir de ces valeurs ; les fixer après causerait un désalignement panneau/slots. Méthode abstraite buildLayout(Row root) — la Row racine couvre la zone de contenu sous le divider. renderBg() dessine le panneau Apocaly à (leftPos, topPos) — même origine que les slots vanilla, garantissant l'alignement pixel-parfait. renderLabels() vide (titre déjà dans le panneau). Propagation événements : layout en priorité, puis vanilla (slots).

Mod démo (client/container/)

  • TestContainerMenu.javaAbstractContainerMenu minimal (MenuType null — client-only, pas de réseau), sans slots. stillValid → true, quickMoveStack → EMPTY.
  • TestContainerScreen.javaApocalyContainerScreen<TestContainerMenu>, panneau 220 × 120, buildLayout : une colonne avec un Label et un KeyValueRow indiquant « 0 slots (commit 5) ».
  • KeyBindings.java — ajout keybind C (open_container) ouvrant TestContainerScreen.
  • Lang files en_us / fr_ca — clés container.title, container.label.info, container.row.slots, open_container.

Critère de réussite

Touche C en jeu → panneau Apocaly centré (fond translucide, bordures jaunes, barre de titre), sans fond gris vanilla visible derrière.

Documentation

  • docs/reference/screen/apocaly-container-screen.md — pipeline de rendu, piège initialisation, contrat Menu = source de vérité des positions de slots

Commit 2 — Grid (2026-05-23)

API publique (api/layout/)

  • api/layout/Grid.java — grille à N colonnes (SPEC §4.2) : distribution équitable de largeur identique à Row, hauteur de cellule = max des hauteurs préférées. Nombre de lignes calculé par division entière avec plafond (nbEnfants + cols - 1) / cols — une grille de 5 enfants sur 3 colonnes produit bien 2 lignes. Builder .columns(int) (obligatoire), .gap(int), .add(Widget). Propagation événements : mouseClicked/mouseScrolled par hit-test de cellule ; keyPressed/charTyped séquentiels sur tous les enfants.

Mod démo

  • DemoScreen.java — ajout section « Grille » : Grid 3 colonnes avec 5 ItemIcon (Diamant, Émeraude, Or, Fer, Charbon) pour valider explicitement le cas d'un nombre d'enfants non multiple du nombre de colonnes (2 lignes, dernière incomplète).
  • Lang files en_us / fr_ca — clé section.grid.

Documentation

  • docs/reference/layout/grid.md — distribution de largeur/hauteur, division plafond, propagation d'événements, note SlotGrid vs Grid

Bonus — Écrans multi-panneaux (hors roadmap SPEC) (2026-05-22)

Commit 2 — ApocalyMultiScreen + démo Marchand (2026-05-22)

API publique (api/screen/)

  • api/screen/PanelConfig.java — descripteur d'un panneau : titre (Component), largeur (px) et fonction de layout (Consumer<Column>). Constructeur statique PanelConfig.of(title, width, layout).
  • api/screen/ApocalyMultiScreen.java — nouvelle classe de base pour les écrans à N panneaux côte à côte : méthode abstraite buildPanels() retournant List<PanelConfig>. Comportement : groupe centré horizontalement, hauteur partagée (max des hauteurs désirées, clampée à l'écran), espacement PANEL_GAP entre panneaux, scroll indépendant par panneau persisté entre les init(). Propagation d'événements : premier consommateur de la liste remporte (mouseClicked / mouseScrolled / keyPressed / charTyped).

API publique — Dimensions

  • api/theme/ApocalyDimensions — ajout PANEL_GAP = 8 px.

Mod démo

  • MarchandDemoScreen.java — écran 3 panneaux : Boutique (140 px, SearchField + ClickableList 8 articles), Détails (170 px, nom dynamique + KeyValueRow prix/stock/ vendeur + ProgressBar disponibilité + 2 boutons Acheter/Vendre), Inventaire (120 px, solde accent + Row de 3 ItemIcon + KeyValueRow achats/ventes). Sélection d'un article dans la boutique met à jour le panneau détails via onSelect → init().
  • KeyBindings.java — ajout keybind M (open_marchand) ouvrant MarchandDemoScreen.
  • Lang files en_us / fr_ca — 20 nouvelles clés apocalyinterfacedemo.marchand.*.

Documentation

  • docs/reference/screen/apocaly-multi-screen.md — référence complète : API, comportement layout, propagation événements, exemple 3 colonnes, notes d'usage.
  • docs/SPEC.md §4.1 — ajout de ApocalyMultiScreen dans les classes de base.

Commit 1 — PanelHost (refactor interne) (2026-05-22)

Core interne (core/layout/)

  • core/layout/PanelHost.java — encapsule toute la logique d'un panneau individuel : construction du layout (layout(screenHeight)), assignation de position (place(left, top, height)), rendu complet (fond/bordure/titre/scissor/scrollbar), propagation événements, persistance du scroll (getScrollOffset / setScrollOffset).
  • api/screen/ApocalyScreen — refactorisé pour déléguer entièrement à PanelHost ; l'API publique (buildLayout(Column), constructeurs, événements) est inchangée.

Correctif — Overflow scroll (2026-05-22)

Bug corrigé

En GUI scale « normal » (écran MC plus petit en coordonnées GUI), un écran avec 15+ widgets produisait un panneau plus haut que l'écran : le contenu débordait verticalement hors de l'affichage.

core/layout/LayoutEngine

  • computeMaxPanelHeight(int screenHeight) — nouvelle méthode : retourne max(60, screenHeight - 2×SCREEN_EDGE_MARGIN), équivalent du Math.min(DESIRED_H, height-8) du mod Clan.
  • computeVisibleContentHeight(int panelHeight) — nouvelle méthode : inverse de computePanelHeight, calcule la hauteur de la zone de contenu visible dans un panneau clampé.

api/screen/ApocalyScreen

  • init() — clamp la hauteur du panneau via computeMaxPanelHeight avant de centrer. Le décalage pixelScrollOffset est conservé entre les init() (resize) et reclampé à la plage [0, max(0, total - visible)].
  • render() — si le contenu déborde : applique enableScissor / disableScissor sur la zone de contenu, puis délègue à drawScrollBar(). Sans débordement : rendu identique à avant.
  • mouseScrolled() — les widgets enfants (ScrollableList, ClickableList) conservent la priorité ; si aucun enfant ne consomme et que maxScroll > 0, le décalage écran est mis à jour (12 px / unité de molette).
  • drawScrollBar() (privé) — piste BUTTON_BORDER 3 px + curseur BORDER jaune proportionnel dans la marge droite du panneau.

Documentation

  • docs/reference/screen/apocaly-screen.md — section « Overflow scroll » ajoutée.

Phase 4 — Widgets avancés (2026-05-22 →)

Commit 7 — TabBar (2026-05-22)

API publique (api/widget/)

  • api/widget/TabBar.java — barre d'onglets horizontale (SPEC §4.3) : largeur équitable par onglet, onglet actif → fond HEADER_BG + soulignement BORDER 2 px + texte TITLE, survol inactif → BUTTON_HOVER_BG + HOVER_TEXT. Record interne Tab(labelKey, onSelect). Builder .tab(String, Runnable) + .activeTab(int). Clic onglet actif ignoré. activeIndex clampé à [0, tabs.size()-1].

Mod démo

  • DemoScreen.java — ajout section « Barre d'onglets » : 3 onglets (Membres / Stats / Items). Clic → init() relayout. Onglet 0 : ScrollableList membres ; onglet 1 : KeyValueRow victoires/défaites ; onglet 2 : Row de 3 ItemIcon.
  • Lang files — ajout section.tabs, tab.membres/stats/items, tab.content.victoires/defaites (EN + FR-CA)

Documentation

  • docs/reference/widgets/tab-bar.md — tableau visuel des états, pattern init() pour switcher de contenu

Commit 6 — ItemIcon + Row (2026-05-22)

API publique — Nouveau conteneur de layout

  • api/layout/Row.java — pendant horizontal de Column (SPEC §4.2) : distribution égale de la largeur (total − (n−1)×gap) / n, hauteur = max des enfants. Propage mouseClicked / mouseScrolled (filtre par X), keyPressed / charTyped (tous enfants).

API publique — Nouveau widget

  • api/widget/ItemIcon.java — item MC 16 × 16 px centré dans la zone allouée (SPEC §4.3) : renderItem + renderItemDecorations optionnel (count + durabilité) + renderTooltip vanilla au survol. Stack vide → rien dessiné. Builder .item(Item) / .item(ItemStack), .showCount(boolean), .showTooltip(boolean).

Mod démo

  • DemoScreen.java — ajout section « Icônes d'items » : Row avec 3 ItemIcon (Diamant, Émeraude, Lingot de Fer ×5 avec count).
  • Lang files — ajout section.items (EN + FR-CA)

Documentation

  • docs/reference/layout/row.md — distribution de largeur, tableau de propagation d'événements
  • docs/reference/widgets/item-icon.md — builder, comportement stack vide, usage Row

Commit 5 — SearchField + hooks keyPressed/charTyped (2026-05-22)

API publique — Interface Widget

  • api/widget/Widget.java — ajout de deux méthodes default : keyPressed(int, int, int) et charTyped(char, int), retournant false (non-consommé). Contrat identique à mouseClicked.

API publique — Conteneurs de layout

  • api/layout/Column.java — ajout keyPressed / charTyped : itère tous les enfants (pas de filtre par position — les events clavier sont non-positionnés).
  • api/layout/Card.java — idem.

API publique — Screen de base

  • api/screen/ApocalyScreen.java — ajout keyPressed / charTyped final : délégation à root, puis super si non consommé.

API publique — Nouveau widget

  • api/widget/SearchField.java — champ de saisie stylé Apocaly (SPEC §4.3) : wrapping EditBox avec setBordered(false), fond PANEL_BG, bordure BUTTON_BORDER / BORDER (focus), placeholder i18n MUTED_TEXT, onChange(Consumer<String>), rebuild préservant texte et focus si la largeur change. Taper « j » focalisé écrit « j » (événement consommé, aucun keybind déclenché).

Mod démo

  • DemoScreen.java — ajout section « Champ de recherche » : SearchField + Label dynamique affichant la valeur courante (DataSource lambda).
  • Lang files — ajout section.search, search.placeholder, search.value (EN + FR-CA)

Documentation

  • docs/reference/widgets/search-field.md — comportement focus/bordure, note filtrage v2

Commit 4 — ProgressBar (2026-05-22)

API publique (api/widget/)

  • api/widget/ProgressBar.java — barre de progression (SPEC §4.3) : hauteur fixe 14 px, DataSource<Float> pour valeur dynamique, .value(float) raccourci statique, .labelKey(String) i18n, .showPercent(boolean), .fillColor(int) pour couleurs sémantiques. Fond PANEL_BG, remplissage ACCENT, contour BUTTON_BORDER, texte centré TEXT.

Mod démo

  • DemoScreen.java — ajout section « Barres de progression » : XP 45% (ACCENT), Jobs 78% (SUCCESS), HP 20% (DANGER).
  • Lang files — ajout section.progress, bar.xp, bar.jobs, bar.hp (EN + FR-CA)

Documentation

  • docs/reference/widgets/progress-bar.md — builder, couleurs sémantiques, constante HEIGHT

Commit 3 — ClickableList<T> (2026-05-22)

API publique (api/widget/)

  • api/widget/ClickableList.java — liste défilante cliquable (SPEC §4.3) : réutilise ScrollableList.RowRenderer<T>, fond HOVER_FILL avant le renderer, onSelect(Consumer<T>) au clic gauche, scroll/indicateur/scissor identiques à ScrollableList. La coloration podium est laissée au mod consommateur.

Mod démo

  • DemoScreen.java — ajout section « Liste cliquable » : 4 lignes visibles, clic → Label dynamique (DataSource lambda) affiche le membre sélectionné.
  • Lang files — ajout section.click_list, label.selected (EN + FR-CA)

Documentation

  • docs/reference/widgets/clickable-list.md — contrat, builder, note podium générique

Commit 2 — ScrollableList<T> (2026-05-22)

API publique (api/widget/)

  • api/widget/ScrollableList.java — liste défilante générique (SPEC §4.3) : interface imbriquée RowRenderer<T>, builder .items/.visibleRows/.rowHeight/.rowRenderer, filtrage par index + enableScissor/disableScissor, indicateur i18n scroll.position en MUTED_TEXT bas-droite, mouseScrolled délégué à ScrollController.

Mod démo

  • DemoScreen.java — ajout section « Liste défilante » : 12 membres fictifs, 5 lignes visibles, rowHeight 14 px, renderer texte simple.
  • assets/apocalyinterfacedemo/lang/en_us.json — ajout section.scroll_list
  • assets/apocalyinterfacedemo/lang/fr_ca.json — idem FR-CA

Documentation

  • docs/reference/widgets/scrollable-list.md — contrat, builder, RowRenderer, clés i18n

Commit 1 — ScrollController (2026-05-22)

Core interne (core/scroll/)

  • core/scroll/ScrollController.java — contrôleur de défilement centralisé (SPEC §5.4) : scrollOffset, totalRows, visibleRows, mouseScrolled(delta) avec clamp, canScroll(), getIndicatorText() i18n via clé apocalyinterface.scroll.position.

Assets — Lang files

  • en_us.json — ajout apocalyinterface.scroll.position : "Scroll: %s/%s"
  • fr_ca.json — ajout apocalyinterface.scroll.position : "Défilement : %s/%s"
  • fr_fr.json — idem FR-FR

Documentation

  • docs/reference/scroll-controller.md — contrat, API, comportement du clamp, clés i18n

Phase 3 — Layout + widgets de base (2026-05-21)

Bibliothèque — API publique (api/)

  • api/widget/Widget.java — interface racine (SPEC §4.6) : setBounds, render, getPreferredHeight, mouseClicked, mouseScrolled. setBounds est toujours appelé avant getPreferredHeight (contrat de layout).
  • api/data/DataSource.java — provider statique/dynamique (SPEC §6.2) : get() + factory of(T).
  • api/screen/ApocalyScreen.java — classe de base abstraite : init()/render()/mouseClicked()/mouseScrolled() en final, buildLayout(Column) abstraite. Largeur par défaut 240 px.
  • api/layout/Column.java — empilage vertical, create() / withGap(int), add(Widget) chaînable, gap par défaut 4 px. Implémente Widget.
  • api/layout/Card.java — sous-panneau encadré (SUB_BG + SUB_BORDER 1 px), marge interne CARD_PADDING (6 px). Implémente Widget.
  • api/widget/Label.java — texte mono-ligne i18n, builder : text/value/accent/muted/title/centered.
  • api/widget/KeyValueRow.java — ligne clé (gauche, TEXT) + valeur (droite, ACCENT), builder : key/value.
  • api/widget/Button.java — bouton 4 états (SPEC §3.6), builder : text/onClick/command/disabled/textColor.

Bibliothèque — Core interne (core/)

  • core/layout/LayoutEngine.java — calcul du rectangle de panneau : computePanelHeight, computePanelX, computePanelY, computeContentY.
  • core/render/PanelRenderer.java — ajout drawSubPanel(gfx, x, y, w, h) pour Card.
  • core/render/RenderUtils.java — surcharge outline(gfx, x, y, w, h, color) à 1 px.

API publique — Thème

  • api/theme/ApocalyColors.java — ajout 9 constantes bouton-états (SPEC §3.6) : BUTTON_HOVER_BG, BUTTON_DISABLED_BG/HOVER_BG, BUTTON_BORDER, BUTTON_DISABLED_BORDER/HOVER_BORDER, BUTTON_TEXT, BUTTON_DISABLED_TEXT/HOVER_TEXT.
  • api/theme/ApocalyDimensions.java — ajout CARD_PADDING = 6.

Mod démo

  • DemoScreen.java — remplacé : étend désormais ApocalyScreen, plus aucun import core/. Affiche le haut du Clan Hub : Card avec 3 KeyValueRow + 3 Button.
  • assets/apocalyinterfacedemo/lang/fr_ca.json — nouvelles clés Phase 3 (screen, rows, boutons).
  • assets/apocalyinterfacedemo/lang/en_us.json — idem en EN-US.

Documentation

  • docs/reference/screen/apocaly-screen.md — référence ApocalyScreen
  • docs/reference/layout/column.md — référence Column
  • docs/reference/layout/card.md — référence Card
  • docs/reference/widgets/label.md — référence Label
  • docs/reference/widgets/key-value-row.md — référence KeyValueRow
  • docs/reference/widgets/button.md — référence Button

Critère « done » Phase 3

Column/Card/Label/KeyValueRow/Button fonctionnels, ApocalyScreen remplace Screen pour le mod démo, keybind J ouvre un écran reproduisant le haut du Clan Hub (card d'infos + 3 boutons) sans aucun calcul de coordonnées dans le code consommateur.


Phase 2 — Theme + i18n + rendu du panneau (2026-05-20)

Bibliothèque — API publique (api/theme/)

  • ApocalyColors.java — palette complète ARGB (§3.2 + §3.3 du SPEC) : panneaux, bordures, texte, sémantique, podium, difficulté
  • ApocalyDimensions.java — constantes de dimensions (§3.4) : épaisseurs, hauteurs, marges, espacements
  • ApocalyTheme.java — façade publique avec singleton DEFAULT ; extensible pour la v2 (thèmes alternatifs)

Bibliothèque — Core interne (core/)

  • core/theme/ThemeManager.java — singleton interne retournant le thème actif (DEFAULT en v1)
  • core/render/PanelRenderer.javadrawPanel() reproduisant l'ordre exact §3.5 : fond, 4 bordures 2 px, barre de titre, divider, titre centré avec ombre
  • core/render/RenderUtils.java — primitives fill() et outline() sur GuiGraphics
  • core/render/TextUtils.javaellipsize() via font.plainSubstrByWidth + suffixe « … »
  • core/i18n/LocaleResolver.java — wrap Component.translatable avec fallback gracieux (clé absente → affiche la clé brute)

Assets — Lang files

  • assets/apocalyinterface/lang/en_us.json — clés internes lib : screen.close, scroll.indicator
  • assets/apocalyinterface/lang/fr_ca.json — idem en FR-CA
  • assets/apocalyinterface/lang/fr_fr.json — idem en FR-FR
  • assets/apocalyinterfacedemo/lang/en_us.json — ajout clé panel.demo
  • assets/apocalyinterfacedemo/lang/fr_ca.json — ajout clé panel.demo

Mod démo

  • DemoScreen.java — affiche un panneau Apocaly centré (220 × 150 px) avec titre traduit via PanelRenderer.drawPanel() ; keybind J permet le test visuel in-game

Documentation

  • docs/reference/colors.md — référence complète de la palette + états des boutons
  • docs/reference/panel.md — documentation de PanelRenderer : ordre de dessin, paramètres, primitives

Critère « done » Phase 2

ApocalyColors/ApocalyDimensions accessibles, fr_ca/en_us chargés, keybind J affiche un panneau stylé reproduisant le style Clan (fond translucide, 4 bordures jaunes, barre de titre, divider, titre centré).


Phase 1 — Setup projet Forge + mod démo (2026-05-20)

Bibliothèque (apocalyinterfacelib)

  • Constants.javaMOD_ID = "apocalyinterfacelib"
  • ApocalyInterfaceLib.java — classe @Mod principale ; setup via FMLClientSetupEvent uniquement (client-only)
  • mods.toml — configuré displayTest="IGNORE_ALL_VERSION", dépendances Forge/MC en side="CLIENT"
  • gradle.propertiesmod_group_id corrigé en ca.tawess123.apocalyinterface
  • Lang files — structure créée pour en_us, fr_ca, fr_fr (vides, prêts pour Phase 2+)
  • Boilerplate MDK (com.example.examplemod) supprimé

Mod démo (apocalyinterfacedemo)

  • ApocalyInterfaceLibDemo.java — classe @Mod du mod démo, même JAR de dev
  • KeyBindings.java — keybind J (configurable) enregistré via RegisterKeyMappingsEvent ; tick listener ouvre l'écran
  • DemoScreen.java — écran vide (renderBackground + titre) ; sera enrichi à chaque phase
  • Lang files — traductions EN/FR-CA des libellés du keybind

Critère « done » Phase 1

Lib + mod démo chargent en jeu, keybind J ouvre un écran vide.


Prochaine phase → Phase 5 : containers + slots vanilla (ApocalyContainerScreen, Spacer, Divider, Grid, SlotGrid)