Aller au contenu principal

Système de layout

La lib calcule automatiquement les positions de chaque widget. Tu ne passes jamais de coordonnées x/y — tu déclares uniquement la structure (qui contient quoi, dans quel ordre).


Principe général

buildLayout(Column root) reçoit la colonne racine du panneau. Chaque widget ajouté s'empile vers le bas. Le LayoutEngine :

  1. Demande à chaque enfant sa hauteur préférée (getPreferredHeight).
  2. Assigne les positions absolues de haut en bas.
  3. Appelle render() sur chaque widget avec ces positions.

Cela fonctionne de façon récursive : une Card demande la hauteur de ses propres enfants, etc.

Vue d'ensemble d'un écran typique

ApocalyScreen
└── Column (root) ← reçue dans buildLayout()
├── Card ← sous-panneau avec fond/bordure
│ ├── Label ← texte avec valeur dynamique
│ └── KeyValueRow ← clé à gauche, valeur à droite
├── Spacer(4) ← espace vertical supplémentaire
├── Row ← layout horizontal
│ ├── Button ← occupe 50% de la Row
│ └── Button ← occupe 50% de la Row
└── ScrollableColumn ← zone défilante à hauteur fixe
├── Button
├── Button
└── Button

Column

Conteneur vertical. Empile ses enfants vers le bas avec un gap configurable (défaut : 4 px).

import ca.tawess123.apocalyinterface.api.layout.Column;

// Gap par défaut (4 px)
Column col = Column.create();

// Gap personnalisé
Column col = Column.withGap(8);

// Ajout de widgets (chaînable)
col.add(label).add(button).add(card);

La Column root passée à buildLayout utilise le gap par défaut.

Hauteur totale = somme des hauteurs des enfants + (N-1) × gap.

Quand l'utiliser : toujours. C'est le conteneur de base. Toute hiérarchie commence par une Column.


Row

Conteneur horizontal. Distribue la largeur disponible équitablement entre ses enfants.

import ca.tawess123.apocalyinterface.api.layout.Row;
import ca.tawess123.apocalyinterface.api.widget.Label;

// Deux labels côte à côte, chacun à 50% de la largeur
Row.create()
.add(Label.builder().text("monmod.label.membres").value(DataSource.of("8/15")).build())
.add(Label.builder().text("monmod.label.rang").value(DataSource.of("#2")).build());

Hauteur = hauteur maximale parmi les enfants.

Quand l'utiliser : pour aligner deux ou plusieurs widgets côte à côte — deux labels, deux boutons, une icône et un texte.

Distribution égale

La largeur est toujours divisée équitablement. Si tu as 3 enfants dans une Row de 210 px, chacun reçoit 70 px. Il n'existe pas d'option de largeur relative en v1.


Card

Sous-panneau avec fond (SUB_BG), bordure fine (SUB_BORDER, 1 px) et padding interne de 6 px. Regroupe visuellement des widgets liés.

import ca.tawess123.apocalyinterface.api.layout.Card;
import ca.tawess123.apocalyinterface.api.theme.ApocalyColors;

// Card standard
Card infoCard = Card.create();
infoCard.add(Label.builder().text("monmod.titre.infos").title().build());
infoCard.add(KeyValueRow.builder().key("monmod.row.points").value(DataSource.of("4200")).build());
root.add(infoCard);

// Card avec bordure de couleur (succès, danger, etc.)
Card alertCard = Card.create().borderColor(ApocalyColors.DANGER);

Hauteur = hauteur du contenu + 2 × padding (12 px au total).

Quand l'utiliser : pour regrouper visuellement des informations liées — infos clan, stats joueur, résumé d'une transaction.


Grid

Grille à N colonnes. Distribue les enfants en lignes successives.

import ca.tawess123.apocalyinterface.api.layout.Grid;
import ca.tawess123.apocalyinterface.api.widget.ItemIcon;
import net.minecraft.world.item.Items;

// Grille 3 colonnes — affiche 5 items (dernière ligne incomplète)
Grid recompenses = Grid.builder()
.columns(3)
.gap(4)
.add(ItemIcon.builder().item(Items.DIAMOND).build())
.add(ItemIcon.builder().item(Items.EMERALD).build())
.add(ItemIcon.builder().item(Items.GOLD_INGOT).build())
.add(ItemIcon.builder().item(Items.IRON_INGOT).build())
.add(ItemIcon.builder().item(Items.COAL).build())
.build();

Hauteur = (nombre de lignes × hauteur de cellule) + (lignes - 1) × gap.

Quand l'utiliser : afficher une collection d'objets identiques — récompenses de quête, items de boutique, icônes de membres.


ScrollableColumn

Zone à hauteur fixe qui scrolle son contenu en interne (molette + mini scrollbar). Indispensable quand le nombre d'éléments varie ou dépasse l'espace disponible.

import ca.tawess123.apocalyinterface.api.layout.ScrollableColumn;
import ca.tawess123.apocalyinterface.api.theme.ApocalyDimensions;

// Calcul de la hauteur : 5 boutons visibles × 20 px + 4 gaps × 4 px = 116 px
private static final int SCROLL_H =
5 * ApocalyDimensions.BUTTON_HEIGHT + 4 * Column.DEFAULT_GAP;

// Construire UNE SEULE FOIS dans le constructeur (pas dans buildLayout)
private final ScrollableColumn buttonScroll;

public MonEcran() {
super(Component.translatable("monmod.screen.hub"), 260);

buttonScroll = ScrollableColumn.builder().fixedHeight(SCROLL_H).build();
buttonScroll.add(Button.builder().text("monmod.btn.action1").command("cmd1").build());
buttonScroll.add(Button.builder().text("monmod.btn.action2").command("cmd2").build());
// ... autant de boutons que nécessaire
}

@Override
protected void buildLayout(Column root) {
root.add(buttonScroll); // ajouter (ne pas recréer)
}
Construire dans le constructeur, pas dans buildLayout

Si tu crées la ScrollableColumn dans buildLayout, l'offset de scroll est remis à zéro à chaque update() ou redimensionnement. Construis-la dans le constructeur et ajoute-la à root dans buildLayout.

Hauteur retournée = fixedHeight (constante, indépendante du contenu).

Quand l'utiliser : liste de boutons, liste de membres, historique de transactions — dès que le contenu peut dépasser l'espace visible.


Spacer

Espace vide de hauteur fixe. Ajoute un espacement ponctuel entre deux groupes logiques.

import ca.tawess123.apocalyinterface.api.layout.Spacer;

root.add(card);
root.add(Spacer.of(8)); // 8 px de vide supplémentaire
root.add(button);

Différence avec le gap de Column : le gap de Column s'applique uniformément entre tous les enfants. Le Spacer ajoute un espacement supplémentaire à un endroit précis, en complément du gap.


Divider

Ligne de séparation horizontale de 1 px (ApocalyColors.DIVIDER, blanc 33 % alpha).

import ca.tawess123.apocalyinterface.api.layout.Divider;
import ca.tawess123.apocalyinterface.api.theme.ApocalyColors;

// Divider standard
root.add(Spacer.of(4));
root.add(Divider.create());
root.add(Spacer.of(4));

// Divider avec couleur personnalisée
root.add(Divider.builder().color(ApocalyColors.BORDER).build());

Quand l'utiliser : pour séparer deux sections logiques dans un panneau — infos générales vs actions, stats vs historique.


Récapitulatif

ConteneurDirectionHauteurScroll interne
ColumnVerticalAuto (somme enfants + gaps)Non
RowHorizontalAuto (max enfants)Non
CardVerticalAuto + 12 px paddingNon
GridGrille N colonnesAuto (lignes × cellule)Non
ScrollableColumnVerticalFixe (paramètre)Oui
SpacerFixe (paramètre)
DividerHorizontal1 px

Le scroll global du panneau (quand le contenu total dépasse la hauteur de l'écran) est géré automatiquement par ApocalyScreen — tu n'as rien à coder.


Voir aussi