Files
SAE41_2025/app/src/main/java/sae/chuzzle/VueGrille.java
T

259 lines
9.0 KiB
Java
Raw Normal View History

2026-03-29 00:30:52 +01:00
package sae.chuzzle;
2026-03-19 10:22:48 +01:00
import android.content.Context;
2026-03-23 12:03:12 +01:00
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
2026-03-19 10:22:48 +01:00
import android.graphics.Canvas;
import android.graphics.Paint;
2026-03-23 12:03:12 +01:00
import android.graphics.RectF;
2026-03-19 10:22:48 +01:00
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
public class VueGrille extends View {
// Constantes
private static final int NB_LIGNES = 6;
private static final int NB_COLONNES = 6;
private static final int NB_TYPES = 7;
/** Symboles pour le mode daltonien, un par type. */
private static final String[] SYMBOLES = {"", "", "", "", "", "", ""};
2026-03-29 00:30:52 +01:00
// Données nécessaires au dessin
private int[][] grille = new int[NB_LIGNES][NB_COLONNES];
2026-03-19 10:22:48 +01:00
private boolean[][] verrous = new boolean[NB_LIGNES][NB_COLONNES];
2026-03-29 00:30:52 +01:00
private Boolean animEstLigne = null;
2026-03-19 10:22:48 +01:00
private int animIndex = 0;
private float animDecalagePx = 0f;
// Outils de dessin
2026-03-23 12:03:12 +01:00
private final Paint pinceauCase = new Paint();
private final Paint pinceauSymbole = new Paint();
private final Paint pinceauSelection = new Paint();
private Bitmap imageChaine;
2026-03-19 10:22:48 +01:00
// Constructeurs
public VueGrille(Context contexte) {
super(contexte);
initPinceaux();
}
public VueGrille(Context context, AttributeSet attrs) {
super(context, attrs);
initPinceaux();
}
private void initPinceaux() {
pinceauCase.setAntiAlias(true);
pinceauCase.setStyle(Paint.Style.FILL);
pinceauSymbole.setAntiAlias(true);
pinceauSymbole.setColor(0xFF000000);
pinceauSymbole.setTextAlign(Paint.Align.CENTER);
2026-03-23 12:03:12 +01:00
pinceauSelection.setAntiAlias(true);
pinceauSelection.setStyle(Paint.Style.STROKE);
pinceauSelection.setStrokeWidth(12f);
pinceauSelection.setColor(0xFFFFFFFF);
imageChaine = BitmapFactory.decodeResource(getResources(), R.drawable.chaine);
2026-03-19 10:22:48 +01:00
}
2026-03-29 00:30:52 +01:00
// -
2026-03-19 10:22:48 +01:00
public void definirGrille(int[][] nouvelleGrille) {
for (int l = 0; l < NB_LIGNES; l++) {
System.arraycopy(nouvelleGrille[l], 0, grille[l], 0, NB_COLONNES);
}
invalidate();
}
public void definirVerrous(boolean[][] nouveauxVerrous) {
for (int l = 0; l < NB_LIGNES; l++) {
System.arraycopy(nouveauxVerrous[l], 0, verrous[l], 0, NB_COLONNES);
}
invalidate();
}
2026-03-29 00:30:52 +01:00
// animation de glissement
2026-03-23 12:03:12 +01:00
2026-03-19 10:22:48 +01:00
public void definirGlissement(boolean estLigne, int index, float decalagePx) {
this.animEstLigne = estLigne;
this.animIndex = index;
this.animDecalagePx = decalagePx;
invalidate();
}
public void annulerGlissement() {
this.animEstLigne = null;
invalidate();
}
// Dessin
@Override
protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas);
2026-03-23 12:03:12 +01:00
// Mise à jour de la couleur du contour de sélection si bloqué
if (animEstLigne != null) {
if (estSelectionBloquee()) {
pinceauSelection.setColor(0xFF000000); // Noir
} else {
pinceauSelection.setColor(0xFFFFFFFF); // Blanc
}
}
2026-03-29 00:30:52 +01:00
int largeur = getWidth() - getPaddingLeft() - getPaddingRight();
int hauteur = getHeight() - getPaddingTop() - getPaddingBottom();
2026-03-19 10:22:48 +01:00
float tailleCase = Math.min(
largeur / (float) NB_COLONNES,
hauteur / (float) NB_LIGNES
);
2026-03-29 00:30:52 +01:00
float margeGauche = getPaddingLeft() + (largeur - tailleCase * NB_COLONNES) / 2f;
float margeHaut = getPaddingTop() + (hauteur - tailleCase * NB_LIGNES) / 2f;
2026-03-19 10:22:48 +01:00
2026-03-29 00:30:52 +01:00
// Limite le dessin à la zone de la grille
2026-03-23 12:03:12 +01:00
canvas.save();
2026-03-29 00:30:52 +01:00
canvas.clipRect(margeGauche, margeHaut,
margeGauche + NB_COLONNES * tailleCase,
2026-03-23 12:03:12 +01:00
margeHaut + NB_LIGNES * tailleCase);
2026-03-19 10:22:48 +01:00
pinceauSymbole.setTextSize(tailleCase * 0.4f);
for (int ligne = 0; ligne < NB_LIGNES; ligne++) {
for (int colonne = 0; colonne < NB_COLONNES; colonne++) {
float offsetX = 0f;
float offsetY = 0f;
if (animEstLigne != null) {
2026-03-23 12:03:12 +01:00
int nbCases = Math.round(animDecalagePx / tailleCase);
2026-03-19 10:22:48 +01:00
if (animEstLigne && ligne == animIndex) {
2026-03-23 12:03:12 +01:00
offsetX = nbCases * tailleCase;
2026-03-19 10:22:48 +01:00
} else if (!animEstLigne && colonne == animIndex) {
2026-03-23 12:03:12 +01:00
offsetY = nbCases * tailleCase;
2026-03-19 10:22:48 +01:00
}
}
float x1 = margeGauche + colonne * tailleCase + 6 + offsetX;
float y1 = margeHaut + ligne * tailleCase + 6 + offsetY;
float x2 = margeGauche + (colonne + 1) * tailleCase - 6 + offsetX;
float y2 = margeHaut + (ligne + 1) * tailleCase - 6 + offsetY;
dessinerCase(canvas, ligne, colonne, x1, y1, x2, y2,
tailleCase, margeGauche, margeHaut, offsetX, offsetY);
}
}
2026-03-23 12:03:12 +01:00
canvas.restore();
2026-03-19 10:22:48 +01:00
}
private void dessinerCase(Canvas canvas,
int ligne, int colonne,
float x1, float y1, float x2, float y2,
float tailleCase,
float margeGauche, float margeHaut,
float offsetX, float offsetY) {
float largeurGrille = NB_COLONNES * tailleCase;
2026-03-29 00:30:52 +01:00
float hauteurGrille = NB_LIGNES * tailleCase;
2026-03-19 10:22:48 +01:00
2026-03-23 12:03:12 +01:00
// Dessin case principale
2026-03-29 00:30:52 +01:00
dessinerRectCase(canvas, ligne, colonne, x1, y1, x2, y2);
2026-03-19 10:22:48 +01:00
2026-03-29 00:30:52 +01:00
// Réapparition de l'autre côté (wrap)
2026-03-19 10:22:48 +01:00
if (offsetX != 0f) {
2026-03-23 12:03:12 +01:00
float bordD = margeGauche + largeurGrille;
float bordG = margeGauche;
if (x2 > bordD) {
2026-03-29 00:30:52 +01:00
dessinerRectCase(canvas, ligne, colonne, x1 - largeurGrille, y1, x2 - largeurGrille, y2);
2026-03-23 12:03:12 +01:00
} else if (x1 < bordG) {
2026-03-29 00:30:52 +01:00
dessinerRectCase(canvas, ligne, colonne, x1 + largeurGrille, y1, x2 + largeurGrille, y2);
2026-03-19 10:22:48 +01:00
}
}
if (offsetY != 0f) {
2026-03-23 12:03:12 +01:00
float bordB = margeHaut + hauteurGrille;
float bordH = margeHaut;
if (y2 > bordB) {
2026-03-29 00:30:52 +01:00
dessinerRectCase(canvas, ligne, colonne, x1, y1 - hauteurGrille, x2, y2 - hauteurGrille);
2026-03-23 12:03:12 +01:00
} else if (y1 < bordH) {
2026-03-29 00:30:52 +01:00
dessinerRectCase(canvas, ligne, colonne, x1, y1 + hauteurGrille, x2, y2 + hauteurGrille);
2026-03-19 10:22:48 +01:00
}
}
}
/**
* Dessine le rectangle coloré d'une case + verrou + symbole daltonien.
2026-03-23 12:03:12 +01:00
* Ajoute un contour gras si la case est sélectionnée.
2026-03-19 10:22:48 +01:00
*/
2026-03-29 00:30:52 +01:00
private void dessinerRectCase(Canvas canvas,
2026-03-19 10:22:48 +01:00
int ligne, int colonne,
float x1, float y1, float x2, float y2) {
2026-03-29 00:30:52 +01:00
int type = grille[ligne][colonne];
2026-03-19 10:22:48 +01:00
definirCouleur(type);
canvas.drawRoundRect(x1, y1, x2, y2, 20, 20, pinceauCase);
2026-03-23 12:03:12 +01:00
if (animEstLigne != null) {
2026-03-29 00:30:52 +01:00
if ((animEstLigne && ligne == animIndex)
|| (!animEstLigne && colonne == animIndex)) {
2026-03-23 12:03:12 +01:00
canvas.drawRoundRect(x1, y1, x2, y2, 20, 20, pinceauSelection);
}
}
2026-03-19 10:22:48 +01:00
// Assombrir si verrouillée
if (verrous[ligne][colonne]) {
pinceauCase.setARGB(120, 0, 0, 0);
canvas.drawRoundRect(x1, y1, x2, y2, 20, 20, pinceauCase);
}
float cx = (x1 + x2) / 2f;
2026-03-23 12:03:12 +01:00
float cy = (y1 + y2) / 2f - (pinceauSymbole.descent() + pinceauSymbole.ascent()) / 2f;
2026-03-19 10:22:48 +01:00
2026-03-29 00:30:52 +01:00
canvas.drawText(SYMBOLES[type % NB_TYPES], cx, cy, pinceauSymbole);
2026-03-28 16:01:01 +01:00
2026-03-23 12:03:12 +01:00
// Dessin de l'image de la chaine si verrouillée
if (verrous[ligne][colonne] && imageChaine != null) {
2026-03-29 00:30:52 +01:00
float size = (x2 - x1);
float chainSize = size * 0.55f;
2026-03-23 12:03:12 +01:00
canvas.drawBitmap(imageChaine, null, new RectF(x1, y1, x1 + chainSize, y1 + chainSize), null);
canvas.drawBitmap(imageChaine, null, new RectF(x2 - chainSize, y2 - chainSize, x2, y2), null);
2026-03-19 10:22:48 +01:00
}
}
private void definirCouleur(int type) {
switch (type % NB_TYPES) {
case 0: pinceauCase.setARGB(255, 200, 200, 200); break;
case 1: pinceauCase.setARGB(255, 255, 105, 180); break;
case 2: pinceauCase.setARGB(255, 90, 230, 200); break;
case 3: pinceauCase.setARGB(255, 100, 170, 255); break;
case 4: pinceauCase.setARGB(255, 255, 220, 90); break;
case 5: pinceauCase.setARGB(255, 255, 140, 90); break;
case 6: pinceauCase.setARGB(255, 255, 90, 90); break;
}
}
2026-03-29 00:30:52 +01:00
/** Vérifie si la ligne/colonne en cours de glissement contient un verrou. */
private boolean estSelectionBloquee() {
if (animEstLigne == null) return false;
if (animEstLigne) {
for (int c = 0; c < NB_COLONNES; c++)
if (verrous[animIndex][c]) return true;
} else {
for (int l = 0; l < NB_LIGNES; l++)
if (verrous[l][animIndex]) return true;
}
return false;
}
2026-03-23 12:03:12 +01:00
}