Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
1 result

Target

Select target project
No results found
Select Git revision
  • main
1 result
Show changes

Commits on Source 15

67 files
+ 1721
766
Compare changes
  • Side-by-side
  • Inline

Files

+4 −3
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ java {
}

ext {
    junitVersion = '5.10.2'
    junitVersion = '5.11.3'
}

tasks.withType(JavaCompile).configureEach {
@@ -28,8 +28,8 @@ tasks.withType(JavaCompile).configureEach {
}

application {
    mainModule = 'fr.univ_amu.m1info.board_game_library'
    mainClass = 'fr.univ_amu.m1info.board_game_library.HelloApplication'
    mainModule = 'fr.univ_amu.l3mi.drawing_app'
    mainClass = 'fr.univ_amu.l3mi.drawing_app.DrawingApp'
}

javafx {
@@ -38,6 +38,7 @@ javafx {
}

dependencies {
    testImplementation("org.assertj:assertj-core:3.26.3")
    testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
}
+1 −1
Original line number Diff line number Diff line
rootProject.name = "board_game_library"
 No newline at end of file
rootProject.name = "drawing_app"
 No newline at end of file
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app;

import fr.univ_amu.l3mi.drawing_app.controller.DrawingAppController;
import fr.univ_amu.l3mi.drawing_app.controller.canvas.Mode;
import fr.univ_amu.l3mi.drawing_app.view.*;


import fr.univ_amu.l3mi.drawing_app.view.configuration.*;

import java.util.List;

public class DrawingApp {

    public static void main(String[] args) {
        DrawingAppConfiguration drawingAppConfiguration = new DrawingAppConfiguration("Drawing App",
                new CanvasDimensions(1000, 800),
                List.of(new ColorPickerConfiguration("Color", "ColorPicker")),
                List.of(new ComboBoxConfiguration("Opacity", "OpacityComboBox", List.of("0", "0.25" , "0.5", "0.75", "1.0")),
                        new ComboBoxConfiguration("Stroke width", "StrokeWidthComboBox", List.of("1" , "2", "4", "8", "16")),
                        new ComboBoxConfiguration("Mode", "ModeComboBox", Mode.getNames())
                        ),
                List.of(new LabeledElementConfiguration("Undo", "UndoButton", LabeledElementKind.BUTTON),
                        new LabeledElementConfiguration("Redo", "RedoButton", LabeledElementKind.BUTTON),
                        new LabeledElementConfiguration("Clear", "ClearButton", LabeledElementKind.BUTTON),
                        new LabeledElementConfiguration("Save", "SaveButton", LabeledElementKind.BUTTON),
                        new LabeledElementConfiguration("Load", "LoadButton", LabeledElementKind.BUTTON),
                        new LabeledElementConfiguration("Export to SVG", "SVGButton", LabeledElementKind.BUTTON)
                ));
        Controller<DrawingAppView> controller = new DrawingAppController();
        DrawingAppLauncher<DrawingAppView> launcher = JavaFXAppLauncher.getInstance();
        launcher.launchApplication(drawingAppConfiguration, controller);
    }
}
 No newline at end of file
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.controller;

import fr.univ_amu.l3mi.drawing_app.model.Rectangle;
import fr.univ_amu.l3mi.drawing_app.model.Shape;
import fr.univ_amu.l3mi.drawing_app.model.ShapeVisitor;
import fr.univ_amu.l3mi.drawing_app.view.CanvasView;
import javafx.geometry.Point2D;
import javafx.scene.paint.Color;

import java.util.List;

public class DrawVisitor implements ShapeVisitor<Void> {
    protected final CanvasView view;

    public void drawShapes(List<Shape> shapes) {
        shapes.forEach(this::visit);
    }

    public DrawVisitor(CanvasView view) {
        this.view = view;
    }

    @Override
    public Void visit(Rectangle rectangle) {
        Point2D topLeftCorner = rectangle.getTopLeftCorner();
        double width = rectangle.getWidth();
        double height = rectangle.getHeight();
        Color fillColor = rectangle.getFillColor();
        Color strokeColor = rectangle.getStrokeColor();
        view.drawRectangle(topLeftCorner, width, height, fillColor, strokeColor, rectangle.getStrokeWidth());
        return null;
    }

    private void visit(Shape shape) {
        shape.accept(this);
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.controller;

import fr.univ_amu.l3mi.drawing_app.controller.canvas.Mode;
import fr.univ_amu.l3mi.drawing_app.controller.canvas.PencilValues;
import fr.univ_amu.l3mi.drawing_app.controller.canvas.ShapeCanvasController;
import fr.univ_amu.l3mi.drawing_app.model.file.NaiveShapeFileReader;
import fr.univ_amu.l3mi.drawing_app.model.file.SVGExporterVisitor;
import fr.univ_amu.l3mi.drawing_app.model.file.ShapeFileWriterVisitor;
import fr.univ_amu.l3mi.drawing_app.view.Controller;
import fr.univ_amu.l3mi.drawing_app.view.DrawingAppView;
import fr.univ_amu.l3mi.drawing_app.view.javafx.view.FileExtension;
import javafx.scene.paint.Color;

public class DrawingAppController implements Controller<DrawingAppView>, PencilValues {
    private DrawingAppView view;
    private Color strokeColor;
    private double opacity = 0.;
    private double strokeWidth = 1.0;
    private final ShapeCanvasController shapeCanvasController;

    public Color getStrokeColor() {
        return strokeColor;
    }

    @Override
    public Color getFillColor() {
        return new javafx.scene.paint.Color(strokeColor.getRed(), strokeColor.getGreen(), strokeColor.getBlue(), opacity);
    }

    @Override
    public double getStrokeWidth() {
        return strokeWidth;
    }

    public DrawingAppController() {
        shapeCanvasController = new ShapeCanvasController(this);
    }


    @Override
    public void buttonActionOnClick(String buttonId) {
        switch (buttonId){
            case "ClearButton" -> shapeCanvasController.clear();
            case "SVGButton" -> view.saveFile((writer) ->
                            new SVGExporterVisitor().writeShapes(shapeCanvasController.getShapeContainer(), writer),
                        FileExtension.SVG);
            case "SaveButton" -> view.saveFile((writer) ->
                            new ShapeFileWriterVisitor().writeShapes(shapeCanvasController.getShapeContainer(), writer),
                    FileExtension.DAFF);
            case "LoadButton" -> {
                view.readFile((reader) -> new NaiveShapeFileReader().readShapes(shapeCanvasController.getShapeContainer(), reader),
                        FileExtension.DAFF);
                shapeCanvasController.repaint();
            }
            case "UndoButton" -> shapeCanvasController.undo();
            case "RedoButton" -> shapeCanvasController.redo();
        }
    }

    @Override
    public void initializeViewOnStart(DrawingAppView view) {
        this.view = view;
        shapeCanvasController.setView(view);
        strokeColor = Color.BLACK;
        view.setColorPicked("ColorPicker", strokeColor);
    }

    @Override
    public void colorPicked(String id, Color color) {
        if(id.equals("ColorPicker"))
            strokeColor = color;
    }

    @Override
    public void actionOnKeyPressed(String key) {
        Mode mode = Mode.getModeByKey(key);
        view.setComboBoxChoice("ModeComboBox", mode.getName());
        shapeCanvasController.switchToMode(mode);
    }

    @Override
    public void choicePicked(String id, String choice) {
        switch (id){
            case "ModeComboBox" -> shapeCanvasController.switchToMode(Mode.getModeByName(choice));
            case "OpacityComboBox" -> opacity = Double.parseDouble(choice);
            case "StrokeWidthComboBox" -> strokeWidth = Double.parseDouble(choice);
        }

    }

    @Override
    public void actionOnLeftMousePressed(double x, double y) {
        shapeCanvasController.actionOnLeftMousePressed(x, y);
    }

    @Override
    public void actionOnLeftMouseReleased(double x, double y) {
        shapeCanvasController.actionOnLeftMouseReleased(x, y);
    }

    @Override
    public void actionOnRightMousePressed(double x, double y) {
        shapeCanvasController.actionOnRightMousePressed(x, y);
    }

    @Override
    public void actionOnRightMouseReleased(double x, double y) {
        shapeCanvasController.actionOnRightMouseReleased(x, y);
    }

    @Override
    public void actionOnMouseMoved(double x, double y) {
        shapeCanvasController.actionOnMouseMoved(x, y);
    }

}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.controller.canvas;

import fr.univ_amu.l3mi.drawing_app.controller.DrawVisitor;
import fr.univ_amu.l3mi.drawing_app.model.Rectangle;
import fr.univ_amu.l3mi.drawing_app.model.Shape;
import fr.univ_amu.l3mi.drawing_app.view.CanvasView;
import javafx.geometry.Point2D;
import javafx.scene.paint.Color;

public class CanvasControllerContext implements PencilValues {
    public static final int CROSS_STROKE_WIDTH = 2;
    private boolean rectangleEdition;
    private boolean rectangleEditionClicked;
    private Point2D mouseClickedPoint;
    private Point2D mousePoint;
    private final ShapeCanvasController shapeCanvasController;

    public CanvasControllerContext(ShapeCanvasController shapeCanvasController) {
        this.shapeCanvasController = shapeCanvasController;
    }

    public void actionOnLeftMousePressed(double x, double y) {
        if (rectangleEdition) {
            switchToRectangleEditionClicked(x, y);
        }
    }

    public void actionOnLeftMouseReleased(double x, double y) {
        if(rectangleEditionClicked) {
            mousePoint = new Point2D(x, y);
            Shape rectangle = new Rectangle(mouseClickedPoint, mousePoint, getFillColor(),
                    getStrokeColor(), shapeCanvasController.getStrokeWidth());
            addShape(rectangle);
            switchToRectangleEdition();
            repaint();
        }
    }

    public void actionOnMouseMoved(double x, double y) {
        mousePoint = new Point2D(x, y);
        shapeCanvasController.repaint();
    }

    private void switchToRectangleEdition(){
        rectangleEdition = true;
        rectangleEditionClicked = false;
    }

    private void switchToViewerMode(){
        rectangleEdition = false;
        rectangleEditionClicked = false;
    }

    private void switchToRectangleEditionClicked(double x, double y){
        rectangleEdition = false;
        rectangleEditionClicked = true;
        mouseClickedPoint = new Point2D(x, y);
        setMousePoint(new Point2D(x, y));
    }

    public void paint(CanvasView view){
        if(rectangleEdition) {
            strokeCross(view);
        }
        if(rectangleEditionClicked){
            strokeRectangleBetweenClickedPointAndMousePoint(view);
        }
    }

    public Point2D getMousePoint() {
        return mousePoint;
    }

    public void setMousePoint(Point2D mousePoint) {
        this.mousePoint = mousePoint;
    }

    private void strokeCross(CanvasView view) {
        Point2D p1 = getMousePoint().add(new Point2D(10,0));
        Point2D p2 = getMousePoint().add(new Point2D(-10,0));
        view.drawLine(p1, p2, Color.BLACK, CROSS_STROKE_WIDTH);
        Point2D p3 = getMousePoint().add(new Point2D(0,10));
        Point2D p4 = getMousePoint().add(new Point2D(0,-10));
        view.drawLine(p3, p4, Color.BLACK, CROSS_STROKE_WIDTH);
    }

    private void strokeRectangleBetweenClickedPointAndMousePoint(CanvasView view) {
        new DrawVisitor(view).visit(new Rectangle(mouseClickedPoint, getMousePoint(), Color.TRANSPARENT,
                getStrokeColor(), getStrokeWidth()));
    }

    public void actionOnRightMousePressed(double x, double y) {
    }

    public void actionOnRightMouseReleased(double x, double y) {

    }

    private void switchToMoveMode() {
        // TODO : add move mode
    }

    private void switchToCircleEdition() {
        // TODO : add circle edition
    }

    private void switchToPolygonEdition() {
        // TODO : add polygon edition
    }

    private void switchToDeleteMode() {
        // TODO : add delete mode
    }

    public void redo() {
        // TODO : add redo
    }

    public void undo() {
        // TODO : add undo
    }

    public void switchToMode(Mode mode) {
        switch (mode){
            case DELETE_MODE -> switchToDeleteMode();
            case VIEWER_MODE -> switchToViewerMode();
            case MOVE_EDITION -> switchToMoveMode();
            case CIRCLE_EDITION -> switchToCircleEdition();
            case POLYGON_EDITION -> switchToPolygonEdition();
            case RECTANGLE_EDITION -> switchToRectangleEdition();
        }
        repaint();
    }

    @Override
    public Color getStrokeColor() {
        return shapeCanvasController.getStrokeColor();
    }

    @Override
    public Color getFillColor() {
        return shapeCanvasController.getFillColor();
    }

    @Override
    public double getStrokeWidth() {
        return shapeCanvasController.getStrokeWidth();
    }

    public void addShape(Shape shape) {
        shapeCanvasController.addShape(shape);
    }
    public void repaint(){
        shapeCanvasController.repaint();
    }
}


Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.controller.canvas;

import java.util.Arrays;
import java.util.List;

public enum Mode {

    VIEWER_MODE("Viewer", "v"), RECTANGLE_EDITION("Rectangle", "r"),
    CIRCLE_EDITION("Circle", "c"), POLYGON_EDITION("Polygon", "p"),
    MOVE_EDITION("Move", "m"), DELETE_MODE("Delete", "d");

    private final String name;
    private final String key;

    Mode(String name, String key) {
        this.name = name;
        this.key = key;
    }

    public String getName() {
        return name;
    }

    public static List<String> getNames() {
        return Arrays.stream(values()).map(Mode::getName).toList();
    }

    public static Mode getModeByKey(String key) {
        for (Mode mode : Mode.values()) {
            if (mode.key.equals(key)) return mode;
        }
        throw new IllegalArgumentException("Unknown key: " + key);
    }
    public static Mode getModeByName(String name) {
        for (Mode mode : Mode.values()) {
            if (mode.name.equals(name)) return mode;
        }
        throw new IllegalArgumentException("Unknown name: " + name);
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.controller.canvas;

import fr.univ_amu.l3mi.drawing_app.controller.DrawVisitor;
import fr.univ_amu.l3mi.drawing_app.model.Shape;
import fr.univ_amu.l3mi.drawing_app.model.ShapeContainer;
import fr.univ_amu.l3mi.drawing_app.view.CanvasController;
import fr.univ_amu.l3mi.drawing_app.view.CanvasView;
import fr.univ_amu.l3mi.drawing_app.view.configuration.CanvasDimensions;
import javafx.scene.paint.Color;

public class ShapeCanvasController implements CanvasController, PencilValues {
    private final CanvasControllerContext context;
    private CanvasView view;
    private final ShapeContainer shapeContainer = new ShapeContainer();
    private final PencilValues pencilValues;

    public ShapeContainer getShapeContainer() {
        return shapeContainer;
    }

    public void setView(CanvasView view) {
        this.view = view;
        shapeContainer.setHeight(view.getCanvasDimensions().height());
        shapeContainer.setWidth(view.getCanvasDimensions().width());
    }

    @Override
    public Color getFillColor() {
        return pencilValues.getFillColor();
    }

    @Override
    public double getStrokeWidth() {
        return pencilValues.getStrokeWidth();
    }

    public void repaint(){
        view.clearCanvas();
        view.setCanvasDimensions(new CanvasDimensions(shapeContainer.getWidth(), shapeContainer.getHeight()));
        drawShapes();
        context.paint(view);
    }

    private void drawShapes() {
        new DrawVisitor(view).drawShapes(shapeContainer.getShapes());
    }

    public ShapeCanvasController(PencilValues pencilValues) {
        this.context = new CanvasControllerContext(this);
        this.pencilValues = pencilValues;
    }

    @Override
    public void actionOnLeftMousePressed(double x, double y) {
        context.actionOnLeftMousePressed(x, y);
    }

    @Override
    public void actionOnLeftMouseReleased(double x, double y) {
        context.actionOnLeftMouseReleased(x, y);
    }

    @Override
    public void actionOnRightMousePressed(double x, double y) {
        context.actionOnRightMousePressed(x, y);
    }

    @Override
    public void actionOnRightMouseReleased(double x, double y) {
        context.actionOnRightMouseReleased(x, y);
    }

    @Override
    public void actionOnMouseMoved(double x, double y) {
        context.actionOnMouseMoved(x, y);
    }

    public void clear(){
        shapeContainer.clear();
        repaint();
    }

   public void switchToMode(Mode mode){
        context.switchToMode(mode);
   }

    public void undo(){
        context.undo();
    }

    public void redo(){
        context.redo();
    }

    public void addShape(Shape shape) {
        shapeContainer.addShape(shape);
    }

    @Override
    public Color getStrokeColor() {
        return pencilValues.getStrokeColor();
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.model;

import javafx.geometry.Point2D;
import javafx.scene.paint.Color;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public abstract class AbstractShape implements Shape {
    private final List<Point2D> points = new ArrayList<>();
    private final Color fillColor;
    private final Color strokeColor;
    private final double strokeWidth;

    public AbstractShape(Color fillColor, Color strokeColor, double strokeWidth) {
        this.fillColor = fillColor;
        this.strokeColor = strokeColor;
        this.strokeWidth = strokeWidth;
    }

    @Override
    public int getPointsCount() {
        return points.size();
    }

    @Override
    public Color getFillColor(){
        return fillColor;
    }

    public Color getStrokeColor() {
        return strokeColor;
    }

    @Override
    public double getStrokeWidth() {
        return strokeWidth;
    }

    protected void addPoints(Point2D... points){
        this.addPoints(Arrays.asList(points));
    }

    protected void addPoints(List<Point2D> points){
        this.points.addAll(points);
    }

    @Override
    public Point2D getPoint(int index) {
        return points.get(index);
    }

}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.model;

import javafx.geometry.Point2D;
import javafx.scene.paint.Color;

public class Rectangle extends AbstractShape {

    public Rectangle(Point2D corner, Point2D oppositeCorner, Color fillColor, Color stokeColor, double strokeWidth) {
        super(fillColor, stokeColor, strokeWidth);
        double x = Math.min(corner.getX(), oppositeCorner.getX());
        double y = Math.min(corner.getY(), oppositeCorner.getY());
        double width = Math.abs(corner.getX() - oppositeCorner.getX());
        double height = Math.abs(corner.getY() - oppositeCorner.getY());
        Point2D topLeftCorner = new Point2D(x, y);
        Point2D bottomRightCorner = new Point2D(x + width, y + height);
        addPoints(topLeftCorner, bottomRightCorner);
    }

    public Point2D getTopLeftCorner() {
        return getPoint(0);
    }

    public double getWidth(){
        return getPoint(1).getX() - getPoint(0).getX();
    }

    public double getHeight(){
        return getPoint(1).getY() - getPoint(0).getY();
    }

    @Override
    public <R> R accept(ShapeVisitor<R> visitor) {
        return visitor.visit(this);
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.model;

import javafx.geometry.Point2D;
import javafx.scene.paint.Color;

public interface Shape {

    <R> R accept(ShapeVisitor<R> visitor);

    int getPointsCount();

    Color getFillColor();

    Color getStrokeColor();

    double getStrokeWidth();

    Point2D getPoint(int index);
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.model;

import java.util.ArrayList;
import java.util.List;

public class ShapeContainer {
    private final List<Shape> shapes = new ArrayList<>();
    private double width;
    private double height;

    public double getWidth() {
        return width;
    }

    public void setWidth(double width) {
        this.width = width;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public void addShape(Shape shape){
        shapes.add(shape);
    }

    public List<Shape> getShapes() {
        return shapes;
    }

    public void clear(){
        shapes.clear();
    }

}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.model.file;

import fr.univ_amu.l3mi.drawing_app.model.Rectangle;
import fr.univ_amu.l3mi.drawing_app.model.ShapeContainer;
import javafx.geometry.Point2D;
import javafx.scene.paint.Color;

import java.io.BufferedReader;
import java.io.IOException;

public class NaiveShapeFileReader implements ShapeFileReader {

    public static final int DEFAULT_WIDTH = 1000;
    public static final int DEFAULT_HEIGHT = 1000;


    @Override
    public void readShapes(ShapeContainer shapeContainer, BufferedReader reader) throws IOException {
        shapeContainer.clear();
        double width = DEFAULT_WIDTH;
        double height = DEFAULT_HEIGHT;
        int lineNumber = 0;

        for (String line = reader.readLine(); line != null; line = reader.readLine()){
            String[] tokens = line.split(" ");
            switch (tokens[0]){
                case "Width" -> width = Double.parseDouble(tokens[1]);
                case "Height" -> height = Double.parseDouble(tokens[1]);
                case "Rectangle" -> readRectangle(tokens, shapeContainer);
                default -> throw new IOException("Parse error line " + lineNumber);
            }
            lineNumber++;
        }
        shapeContainer.setWidth(width);
        shapeContainer.setHeight(height);
    }

    private void readRectangle(String[] tokens, ShapeContainer shapeContainer) {
        double x1 = Double.parseDouble(tokens[1]);
        double y1 = Double.parseDouble(tokens[2]);
        double x2 = Double.parseDouble(tokens[3]);
        double y2 = Double.parseDouble(tokens[4]);
        Point2D corner1 = new Point2D(x1, y1);
        Point2D corner2 = new Point2D(x2, y2);
        Color fillColor = Color.web(tokens[5]);
        Color strokeColor = Color.web(tokens[6]);
        double strokeWidth = Double.parseDouble(tokens[7]);
        shapeContainer.addShape(new Rectangle(corner1, corner2, fillColor, strokeColor, strokeWidth));
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.model.file;

import fr.univ_amu.l3mi.drawing_app.model.Rectangle;
import fr.univ_amu.l3mi.drawing_app.model.Shape;
import fr.univ_amu.l3mi.drawing_app.model.ShapeContainer;
import fr.univ_amu.l3mi.drawing_app.model.ShapeVisitor;
import javafx.geometry.Point2D;
import javafx.scene.paint.Color;

import java.io.BufferedWriter;
import java.io.IOException;

public class SVGExporterVisitor implements ShapeVisitor<String>, ShapeFileWriter {
    public static final int COLOR_RANGE = 255;

    String convertColorToString(Color color) {
        return "rgba(" + color.getRed() * COLOR_RANGE +
                ',' +
                color.getGreen() * COLOR_RANGE +
                ',' +
                color.getBlue() * COLOR_RANGE +
                ',' +
                color.getOpacity() +
                ')';
    }


    @Override
    public String visit(Rectangle rectangle) {
        Point2D topLeftCorner = rectangle.getTopLeftCorner();
        double width = rectangle.getWidth();
        double height = rectangle.getHeight();
        return "<rect x=\"" + topLeftCorner.getX() +
                "\" y=\"" +
                topLeftCorner.getY() +
                "\" width=\"" +
                width +
                "\" height=\"" +
                height +
                "\" fill=\"" +
                convertColorToString(rectangle.getFillColor()) +
                "\" stroke=\"" +
                convertColorToString(rectangle.getStrokeColor()) +
                "\" stroke-width=\"" +
                rectangle.getStrokeWidth() +
                "\" />";
    }

    @Override
    public void writeShapes(ShapeContainer shapeContainer, BufferedWriter writer) throws IOException {
        writer.write("<svg width=\"" + shapeContainer.getWidth());
        writer.write("\" height=\"" + shapeContainer.getHeight());
        writer.write("\" xmlns=\"http://www.w3.org/2000/svg\">\n");
        for (Shape shape : shapeContainer.getShapes()) {
            writer.write(shape.accept(this) + "\n");
        }
        writer.write("</svg>\n");
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.model.file;

import fr.univ_amu.l3mi.drawing_app.model.ShapeContainer;

import java.io.BufferedReader;
import java.io.IOException;

public interface ShapeFileReader {
    void readShapes(ShapeContainer shapeContainer, BufferedReader reader) throws IOException;
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.model.file;

import fr.univ_amu.l3mi.drawing_app.model.ShapeContainer;

import java.io.BufferedWriter;
import java.io.IOException;

public interface ShapeFileWriter {
    void writeShapes(ShapeContainer shapeContainer, BufferedWriter writer) throws IOException;
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.model.file;

import fr.univ_amu.l3mi.drawing_app.model.Rectangle;
import fr.univ_amu.l3mi.drawing_app.model.Shape;
import fr.univ_amu.l3mi.drawing_app.model.ShapeContainer;
import fr.univ_amu.l3mi.drawing_app.model.ShapeVisitor;

import java.io.BufferedWriter;
import java.io.IOException;

public class ShapeFileWriterVisitor implements ShapeVisitor<String>, ShapeFileWriter {

    @Override
    public void writeShapes(ShapeContainer shapeContainer, BufferedWriter writer) throws IOException {
        writer.write("Width " + shapeContainer.getWidth() + "\n");
        writer.write("Height " + shapeContainer.getHeight() + "\n");
        for (Shape shape : shapeContainer.getShapes()) {
            writer.write(shape.accept(this)+"\n");
        }
    }

    @Override
    public String visit(Rectangle r) {
        return "Rectangle " + r.getPoint(0).getX() + " " + r.getPoint(0).getY()
                + " " + r.getPoint(1).getX() + " " + r.getPoint(1).getY()  + " "
                + r.getFillColor() + " " + r.getStrokeColor()
                + " " + r.getStrokeWidth();
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view;

/**
 * The CanvasController interface defines methods for handling mouse actions
 * on a canvas. Implementations of this interface should provide specific actions
 * for left and right mouse button presses, releases, and movement.
 */
public interface CanvasController {

    /**
     * Invoked when the left mouse button is pressed on the canvas.
     *
     * @param x the x-coordinate where the mouse was pressed.
     * @param y the y-coordinate where the mouse was pressed.
     */
    void actionOnLeftMousePressed(double x, double y);

    /**
     * Invoked when the left mouse button is released on the canvas.
     *
     * @param x the x-coordinate where the mouse was released.
     * @param y the y-coordinate where the mouse was released.
     */
    void actionOnLeftMouseReleased(double x, double y);

    /**
     * Invoked when the right mouse button is pressed on the canvas.
     *
     * @param x the x-coordinate where the mouse was pressed.
     * @param y the y-coordinate where the mouse was pressed.
     */
    void actionOnRightMousePressed(double x, double y);

    /**
     * Invoked when the right mouse button is released on the canvas.
     *
     * @param x the x-coordinate where the mouse was released.
     * @param y the y-coordinate where the mouse was released.
     */
    void actionOnRightMouseReleased(double x, double y);

    /**
     * Invoked when the mouse is moved on the canvas.
     *
     * @param x the current x-coordinate of the mouse.
     * @param y the current y-coordinate of the mouse.
     */
    void actionOnMouseMoved(double x, double y);
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view;

import fr.univ_amu.l3mi.drawing_app.view.configuration.CanvasDimensions;
import javafx.geometry.Point2D;
import javafx.scene.paint.Color;

/**
 * The CanvasView interface defines methods for drawing shapes and managing
 * a canvas for graphical representations. Implementations of this interface
 * should provide functionalities for clearing the canvas, drawing basic shapes,
 * and configuring the canvas dimensions.
 */
public interface CanvasView {

    /**
     * Clears the entire canvas, removing any drawn shapes or content.
     */
    void clearCanvas();

    /**
     * Draws a rectangle on the canvas.
     *
     * @param topLeftCorner the top-left corner of the rectangle.
     * @param width the width of the rectangle.
     * @param height the height of the rectangle.
     * @param fillColor the color used to fill the rectangle.
     * @param strokeColor the color of the rectangle's border.
     * @param strokeWidth the thickness of the rectangle's border.
     */
    void drawRectangle(Point2D topLeftCorner, double width, double height, Color fillColor, Color strokeColor, double strokeWidth);

    /**
     * Draws a circle on the canvas.
     *
     * @param center the center point of the circle.
     * @param radius the radius of the circle.
     * @param fillColor the color used to fill the circle.
     * @param strokeColor the color of the circle's border.
     * @param strokeWidth the thickness of the circle's border.
     */
    void drawCircle(Point2D center, double radius, Color fillColor, Color strokeColor, double strokeWidth);

    /**
     * Draws a polygon on the canvas.
     *
     * @param points an array of points representing the vertices of the polygon.
     * @param fillColor the color used to fill the polygon.
     * @param strokeColor the color of the polygon's border.
     * @param strokeWidth the thickness of the polygon's border.
     */
    void drawPolygon(Point2D[] points, Color fillColor, Color strokeColor, double strokeWidth);

    /**
     * Draws a line on the canvas.
     *
     * @param startPoint the starting point of the line.
     * @param endPoint the ending point of the line.
     * @param color the color of the line.
     * @param strokeWidth the thickness of the line.
     */
    void drawLine(Point2D startPoint, Point2D endPoint, Color color, double strokeWidth);

    /**
     * Retrieves the current dimensions of the canvas.
     *
     * @return a CanvasDimensions object representing the canvas's width and height.
     */
    CanvasDimensions getCanvasDimensions();

    /**
     * Sets the dimensions of the canvas.
     *
     * @param canvasDimensions a CanvasDimensions object specifying the new width and height of the canvas.
     */
    void setCanvasDimensions(CanvasDimensions canvasDimensions);
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view;


import javafx.scene.paint.Color;

public interface Controller<V> extends CanvasController{

    void actionOnKeyPressed(String key);

    void buttonActionOnClick(String buttonId);

    void initializeViewOnStart(V view);

    void colorPicked(String id, Color color);

    void choicePicked(String id, String choice);
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view;

import fr.univ_amu.l3mi.drawing_app.view.configuration.DrawingAppConfiguration;

public interface DrawingAppLauncher<V> {

    void launchApplication(DrawingAppConfiguration configuration,
                           Controller<V> controller);
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view;

import fr.univ_amu.l3mi.drawing_app.view.javafx.view.FileExtension;
import fr.univ_amu.l3mi.drawing_app.view.javafx.view.FileReader;
import fr.univ_amu.l3mi.drawing_app.view.javafx.view.FileWriter;
import javafx.scene.paint.Color;



public interface DrawingAppView extends CanvasView {

    void setComboBoxChoice(String id, String choice);

    void setColorPicked(String id, Color color);

    void saveFile(FileWriter fileWriter, FileExtension fileExtension);

    void readFile(FileReader fileReader, FileExtension fileExtension);

}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view;

import fr.univ_amu.l3mi.drawing_app.view.configuration.DrawingAppConfiguration;

import fr.univ_amu.l3mi.drawing_app.view.javafx.app.JavaFXDrawingApp;
import javafx.application.Application;

import java.util.Locale;


public class JavaFXAppLauncher implements DrawingAppLauncher<DrawingAppView> {

    private static JavaFXAppLauncher instance = null;

    private DrawingAppConfiguration configuration;

    private Controller<DrawingAppView> controller;

    private JavaFXAppLauncher() {}

    public static JavaFXAppLauncher getInstance() {
        Locale.setDefault(Locale.ENGLISH);
        JavaFXAppLauncher result = instance;
        if (result != null) {
            return result;
        }
        synchronized(JavaFXAppLauncher.class) {
            if (instance == null) {
                instance = new JavaFXAppLauncher();
            }
            return instance;
        }
    }

    public DrawingAppConfiguration getConfiguration() {
        return configuration;
    }

    public Controller<DrawingAppView> getController() {
        return controller;
    }

    @Override
    public void launchApplication(DrawingAppConfiguration configuration,
                                  Controller<DrawingAppView> controller) {
        this.configuration = configuration;
        this.controller = controller;
        Application.launch(JavaFXDrawingApp.class);
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view.configuration;

import java.util.List;


public record DrawingAppConfiguration(String title,
                                      CanvasDimensions dimensions,
                                      List<ColorPickerConfiguration> colorPickerConfigurations,
                                      List<ComboBoxConfiguration> comboBoxConfigurations,
                                      List<LabeledElementConfiguration> labeledElementConfigurations) {
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.configuration;
package fr.univ_amu.l3mi.drawing_app.view.configuration;

/**
 * Record representing the configuration of a labeled element in a board game.
 * Record representing the configuration of a labeled element in a drawing app.
 * It stores the label, an identifier, and the type of the labeled element.
 *
 * @param label the text label of the element.
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.configuration;
package fr.univ_amu.l3mi.drawing_app.view.configuration;

/**
 * Enum representing the types of labeled elements in a board game.
 * Enum representing the types of labeled elements in a drawing app.
 * These elements can either be interactive buttons or simple text displays.
 */
public enum LabeledElementKind {
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view.javafx.app;

import fr.univ_amu.l3mi.drawing_app.view.Controller;
import fr.univ_amu.l3mi.drawing_app.view.DrawingAppView;
import fr.univ_amu.l3mi.drawing_app.view.JavaFXAppLauncher;
import fr.univ_amu.l3mi.drawing_app.view.javafx.view.DrawingAppConfigurator;
import fr.univ_amu.l3mi.drawing_app.view.javafx.view.DrawingAppControllableView;
import fr.univ_amu.l3mi.drawing_app.view.javafx.view.JavaFXDrawingAppViewBuilder;
import javafx.application.Application;
import javafx.stage.Stage;

public class JavaFXDrawingApp extends Application {


    @Override
    public void start(Stage stage) {
        var launcher = JavaFXAppLauncher.getInstance();
        var configuration = launcher.getConfiguration();
        Controller<DrawingAppView> controller = launcher.getController();
        final JavaFXDrawingAppViewBuilder viewBuilder = new JavaFXDrawingAppViewBuilder(stage);
        new DrawingAppConfigurator().configure(viewBuilder, configuration);
        DrawingAppControllableView view = viewBuilder.getView();
        view.setController(controller);
        controller.initializeViewOnStart(view);
        stage.show();
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.bar;
package fr.univ_amu.l3mi.drawing_app.view.javafx.bar;

import javafx.collections.FXCollections;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Labeled;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;


import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Bar extends HBox {
    private final Map<String, Labeled> labeledElements = new HashMap<>();
    private final Map<String, Button> buttons = new HashMap<>();
    private final Map<String, ColorPicker> colorPickers = new HashMap<>();
    private final Map<String, ComboBox<String>> comboBoxes = new HashMap<>();

    public Bar() {
        super();
@@ -35,6 +38,25 @@ public class Bar extends HBox {
       buttons.get(id).setOnAction(_ -> buttonActionOnClick.onClick());
    }


    public Color getPickedColor(String id){
        return colorPickers.get(id).getValue();
    }

    public String getPickedChoice(String id){
        return comboBoxes.get(id).getValue();
    }

    public void setColorPickerAction(String id, ColorPickedAction colorPickedAction){
        ColorPicker colorPicker = colorPickers.get(id);
        colorPicker.setOnAction(_ -> colorPickedAction.onColorPicked(colorPicker.getValue()));
    }

    public void setComboBoxAction(String id, ChoicePickedAction choicePickedAction){
        ComboBox<String> comboBox = comboBoxes.get(id);
        comboBox.setOnAction(_ -> choicePickedAction.onChoicePicked(comboBox.getValue()));
    }

    public void addButton(String id, String label){
        Button button = new Button(label);
        labeledElements.put(id, button);
@@ -42,9 +64,30 @@ public class Bar extends HBox {
        this.getChildren().add(button);
    }

    public void updateLabel(String id, String newText){
        if(labeledElements.containsKey(id)){
            labeledElements.get(id).setText(newText);
    public void addColorPicker(String id, String label){
        addLabel(id+"Label", label);
        ColorPicker colorPicker = new ColorPicker();
        colorPickers.put(id, colorPicker);
        this.getChildren().add(colorPicker);
    }

    public void addComboBox(String id, String label, List<String> choices){
        addLabel(id+"Label", label);
        ComboBox<String> comboBox = new ComboBox<>(FXCollections.observableList(choices));
        comboBox.setValue(choices.getFirst());
        comboBoxes.put(id, comboBox);
        this.getChildren().add(comboBox);
    }

    public void updateColorPicker(String id, Color newColor){
        if(colorPickers.containsKey(id)){
            colorPickers.get(id).setValue(newColor);
        }
    }
    public void updateComboBox(String id, String choice){
        if(comboBoxes.containsKey(id)){
            comboBoxes.get(id).setValue(choice);
        }
    }

}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view.javafx.canvas;

import fr.univ_amu.l3mi.drawing_app.view.Controller;
import fr.univ_amu.l3mi.drawing_app.view.DrawingAppView;
import javafx.geometry.Point2D;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseButton;
import javafx.scene.paint.Color;

import java.util.Arrays;


public class DrawingCanvasView extends Canvas {
    private final GraphicsContext gc;

    public DrawingCanvasView() {
        gc = getGraphicsContext2D();
    }

    public void setDimensions(double width, double height) {
        super.setWidth(width);
        super.setHeight(height);
    }

    public void clear() {
        this.getGraphicsContext2D().clearRect(0,0,this.getWidth(),this.getHeight());
    }

    public void setController(Controller<DrawingAppView> controller) {
        setOnMousePressed(event->{
            if(event.getButton() == MouseButton.PRIMARY)
                controller.actionOnLeftMousePressed(event.getX(), event.getY());
            else
                if(event.getButton() == MouseButton.SECONDARY)
                    controller.actionOnRightMousePressed(event.getX(), event.getY());
        });
        setOnMouseReleased(event->{
            if(event.getButton() == MouseButton.PRIMARY)
                controller.actionOnLeftMouseReleased(event.getX(), event.getY());
            else
                if(event.getButton() == MouseButton.SECONDARY)
                    controller.actionOnRightMouseReleased(event.getX(), event.getY());
        });
        setOnMouseMoved(event->controller.actionOnMouseMoved(event.getX(), event.getY()));
        setOnMouseDragged(event->controller.actionOnMouseMoved(event.getX(), event.getY()));
    }

    public void strokeLine(Point2D endPoint1, Point2D endPoint2, Color color, double strokeWidth) {
        setStroke(color, strokeWidth);
        gc.strokeLine(endPoint1.getX(), endPoint1.getY(), endPoint2.getX(), endPoint2.getY());
    }

    private static Points getPoints(Point2D[] points) {
        double[] xPoints = Arrays.stream(points).mapToDouble(Point2D::getX).toArray();
        double[] yPoints = Arrays.stream(points).mapToDouble(Point2D::getY).toArray();
        int nbPoints = points.length;
        return new Points(xPoints, yPoints, nbPoints);
    }

    private record Points(double[] xPoints, double[] yPoints, int nbPoints) {
    }


    public void fillPolygon(Point2D[] points, Color color) {
        setFill(color);
        Points pointsCoordinates = getPoints(points);
        gc.fillPolygon(pointsCoordinates.xPoints(), pointsCoordinates.yPoints(), pointsCoordinates.nbPoints());
    }


    public void strokePolygon(Point2D[] points, Color color, double strokeWidth) {
        setStroke(color, strokeWidth);
        Points pointsCoordinates = getPoints(points);
        gc.strokePolygon(pointsCoordinates.xPoints(), pointsCoordinates.yPoints(), pointsCoordinates.nbPoints());
    }

    private void setStroke(Color color, double strokeWidth) {
        gc.setStroke(color);
        gc.setLineWidth(strokeWidth);
    }

    private void setFill(Color color) {
        gc.setFill(color);
    }


    public void strokeCircle(Point2D center, double radius, Color color, double strokeWidth) {
        setStroke(color,strokeWidth);
        gc.strokeOval(center.getX()-radius, center.getY()-radius, 2*radius, 2*radius);

    }

    public void fillCircle(Point2D center, double radius, Color color) {
        setFill(color);
        gc.fillOval(center.getX()-radius, center.getY()-radius, 2*radius, 2*radius);
    }

    public void strokeRectangle(Point2D leftTopCorner, double width, double height, Color color, double strokeWidth) {
        setStroke(color, strokeWidth);
        gc.strokeRect(leftTopCorner.getX(), leftTopCorner.getY(), width, height);
    }

    public void fillRectangle(Point2D leftTopCorner, double width, double height, Color color) {
        setFill(color);
        gc.fillRect(leftTopCorner.getX(), leftTopCorner.getY(), width, height);
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view.javafx.view;

import fr.univ_amu.l3mi.drawing_app.view.configuration.ColorPickerConfiguration;
import fr.univ_amu.l3mi.drawing_app.view.configuration.ComboBoxConfiguration;
import fr.univ_amu.l3mi.drawing_app.view.configuration.DrawingAppConfiguration;
import fr.univ_amu.l3mi.drawing_app.view.configuration.LabeledElementConfiguration;

public class DrawingAppConfigurator {
    public void configure(DrawingAppViewBuilder drawingAppViewBuilder,
                          DrawingAppConfiguration drawingAppConfiguration) {
        drawingAppViewBuilder = drawingAppViewBuilder
                .resetView()
                .setTitle(drawingAppConfiguration.title())
                .setCanvasDimensions(drawingAppConfiguration.dimensions().width(),
                        drawingAppConfiguration.dimensions().height());
        for(ColorPickerConfiguration colorPickerConfiguration : drawingAppConfiguration.colorPickerConfigurations())
            drawingAppViewBuilder = drawingAppViewBuilder.addColorPicker(colorPickerConfiguration.id(),
                    colorPickerConfiguration.label());
        for (ComboBoxConfiguration comboBoxConfiguration : drawingAppConfiguration.comboBoxConfigurations())
            drawingAppViewBuilder = drawingAppViewBuilder.addComboBox(comboBoxConfiguration.id(),
                    comboBoxConfiguration.label(),
                    comboBoxConfiguration.choices());
        for (LabeledElementConfiguration elementConfiguration : drawingAppConfiguration.labeledElementConfigurations()) {
            switch (elementConfiguration.kind()) {
                case BUTTON -> drawingAppViewBuilder = drawingAppViewBuilder.addButton(elementConfiguration.id(), elementConfiguration.label());
                case TEXT -> drawingAppViewBuilder = drawingAppViewBuilder.addLabel(elementConfiguration.id(), elementConfiguration.label());
            }
        }
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view.javafx.view;

import fr.univ_amu.l3mi.drawing_app.view.Controller;
import fr.univ_amu.l3mi.drawing_app.view.DrawingAppView;


public interface DrawingAppControllableView extends DrawingAppView {
    void setController(Controller<DrawingAppView> controller);
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view.javafx.view;

import java.util.List;

public interface DrawingAppViewBuilder {
    DrawingAppViewBuilder resetView();
    DrawingAppViewBuilder setCanvasDimensions(double width, double height);
    DrawingAppViewBuilder setTitle(String title);
    DrawingAppViewBuilder addLabel(String id, String initialText);
    DrawingAppViewBuilder addButton(String id, String label);
    DrawingAppViewBuilder addColorPicker(String id, String label);
    DrawingAppViewBuilder addComboBox(String id, String label, List<String> choice);
    DrawingAppControllableView getView();
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view.javafx.view;

public enum FileExtension {
    SVG("*.svg", "Scalable Vector Graphics"),
    DAFF("*.daff", "Drawing App File Format");

    public final String extension;
    public final String fileFormatName;

    FileExtension(String extension, String FileFormatName) {
        this.extension = extension;
        this.fileFormatName = FileFormatName;
    }

}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view.javafx.view;


import fr.univ_amu.l3mi.drawing_app.view.Controller;
import fr.univ_amu.l3mi.drawing_app.view.DrawingAppView;
import fr.univ_amu.l3mi.drawing_app.view.configuration.CanvasDimensions;
import fr.univ_amu.l3mi.drawing_app.view.javafx.bar.Bar;
import fr.univ_amu.l3mi.drawing_app.view.javafx.canvas.DrawingCanvasView;
import javafx.application.Platform;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

public class JavaFXDrawingAppView implements DrawingAppControllableView {
    private final Stage stage;
    private DrawingCanvasView drawingCanvasView;
    private Bar bar;
    private Controller<DrawingAppView> controller;
    private VBox vBox;

    public void setController(Controller<DrawingAppView> controller) {
        this.controller = controller;
        drawingCanvasView.setController(controller);
        vBox.setOnKeyPressed(event -> controller.actionOnKeyPressed(event.getText()));
    }

    public JavaFXDrawingAppView(Stage stage) {
        this.stage = stage;
        stage.setOnCloseRequest(_ -> Platform.exit());
        stage.setResizable(false);
        stage.sizeToScene();
    }

    public synchronized void reset() {
        vBox = new VBox();
        bar = new Bar();
        drawingCanvasView = new DrawingCanvasView();
        vBox.getChildren().add(bar);
        vBox.getChildren().add(drawingCanvasView);
        Scene scene = new Scene(vBox);
        stage.setScene(scene);
    }

    @Override
    public void clearCanvas() {
        drawingCanvasView.clear();
    }

    @Override
    public void drawRectangle(Point2D topLeftCorner, double width, double height, Color fillColor, Color strokeColor, double strokeWidth) {
        drawingCanvasView.fillRectangle(topLeftCorner, width, height, fillColor);
        drawingCanvasView.strokeRectangle(topLeftCorner, width, height, strokeColor, strokeWidth);
    }


    @Override
    public void drawCircle(Point2D center, double radius, Color fillColor, Color strokeColor, double strokeWidth) {
        drawingCanvasView.fillCircle(center, radius, fillColor);
        drawingCanvasView.strokeCircle(center, radius, strokeColor, strokeWidth);
    }

    @Override
    public CanvasDimensions getCanvasDimensions() {
        return new CanvasDimensions(drawingCanvasView.getWidth(), drawingCanvasView.getHeight());
    }

    @Override
    public void setCanvasDimensions(CanvasDimensions canvasDimensions) {
        drawingCanvasView.setDimensions(canvasDimensions.width(), canvasDimensions.height());
    }

    @Override
    public void drawPolygon(Point2D[] points, Color fillColor, Color strokeColor, double strokeWidth) {
        drawingCanvasView.fillPolygon(points, fillColor);
        drawingCanvasView.strokePolygon(points, strokeColor, strokeWidth);
    }

    @Override
    public void drawLine(Point2D endPoint1, Point2D endPoint2, Color color, double strokeWidth) {
        drawingCanvasView.strokeLine(endPoint1,endPoint2, color, strokeWidth);
    }

    public DrawingCanvasView getDrawingCanvasView() {
        return drawingCanvasView;
    }

    public Stage getStage() {
        return stage;
    }

    public Bar getBar() {
        return bar;
    }

    public void buttonActionOnclick(String id){
        controller.buttonActionOnClick(id);
    }

    public void actionOnColorPicked(String id){
        controller.colorPicked(id, bar.getPickedColor(id));
    }

    public void actionOnChoicePicked(String id){
        controller.choicePicked(id, bar.getPickedChoice(id));
    }

    public void setComboBoxChoice(String id, String choice) {
        bar.updateComboBox(id, choice);
    }

    @Override
    public void setColorPicked(String id, Color color) {
        bar.updateColorPicker(id, color);
    }


    public void saveFile(FileWriter fileWriter, FileExtension fileExtension) {
        FileChooser fileChooser = new FileChooser();

        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(fileExtension.fileFormatName,
                fileExtension.extension));

        File file = fileChooser.showSaveDialog(stage);

        if (file != null) {
            try {
                BufferedWriter stream = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_16);
                fileWriter.write(stream);
                stream.close();
            }
            catch(IOException exception){
                exception.printStackTrace();
            }
        }
    }


    @Override
    public void readFile(FileReader fileReader, FileExtension fileExtension) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(fileExtension.fileFormatName,
                fileExtension.extension));
        File file = fileChooser.showOpenDialog(stage);

        if (file != null) {
            try {
                BufferedReader bufferedReader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_16);
                fileReader.read(bufferedReader);
                bufferedReader.close();
            }
            catch(IOException exception){
                exception.printStackTrace();
            }
        }
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.view.javafx.view;

import javafx.stage.Stage;

import java.util.List;

public class JavaFXDrawingAppViewBuilder implements DrawingAppViewBuilder {
    JavaFXDrawingAppView drawingAppView;

    public JavaFXDrawingAppViewBuilder(Stage primaryStage) {
        drawingAppView = new JavaFXDrawingAppView(primaryStage);
    }

    public DrawingAppViewBuilder resetView(){
        drawingAppView.reset();
        return this;
    }


    @Override
    public DrawingAppViewBuilder addColorPicker(String id, String label) {
        drawingAppView.getBar().addColorPicker(id, label);
        drawingAppView.getBar().setColorPickerAction(id, _->drawingAppView.actionOnColorPicked(id));
        return this;
    }

    @Override
    public DrawingAppViewBuilder addComboBox(String id, String label, List<String> choice) {
        drawingAppView.getBar().addComboBox(id, label, choice);
        drawingAppView.getBar().setComboBoxAction(id, _ -> drawingAppView.actionOnChoicePicked(id));
        return this;
    }



    @Override
    public DrawingAppViewBuilder setCanvasDimensions(double width, double height) {
        drawingAppView.getDrawingCanvasView().setDimensions(width, height);
        return this;
    }

    @Override
    public DrawingAppViewBuilder setTitle(String title) {
        drawingAppView.getStage().setTitle(title);
        return this;
    }

    @Override
    public DrawingAppViewBuilder addLabel(String id, String initialText) {
        drawingAppView.getBar().addLabel(id, initialText);
        return this;
    }

    @Override
    public DrawingAppViewBuilder addButton(String id, String label) {
        drawingAppView.getBar().addButton(id, label);
        drawingAppView.getBar().setButtonAction(id, ()-> drawingAppView.buttonActionOnclick(id));
        return this;
    }

    @Override
    public DrawingAppControllableView getView() {
        return drawingAppView;
    }

}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library;

import fr.univ_amu.m1info.board_game_library.graphics.*;
import fr.univ_amu.m1info.board_game_library.graphics.configuration.BoardGameConfiguration;
import fr.univ_amu.m1info.board_game_library.graphics.configuration.LabeledElementConfiguration;
import fr.univ_amu.m1info.board_game_library.graphics.configuration.LabeledElementKind;
import fr.univ_amu.m1info.board_game_library.graphics.configuration.BoardGameDimensions;

import java.util.List;

public class HelloApplication {

    private static class HelloController implements BoardGameController {
        private BoardGameView view;

        @Override
        public void initializeViewOnStart(BoardGameView view) {
            changeCellColors(view, Color.GREEN, Color.LIGHTGREEN);
            changeShapes(view, Shape.TRIANGLE, Color.BLACK, Shape.CIRCLE, Color.RED);
            this.view = view;
        }


        @Override
        public void boardActionOnClick(int row, int column) {
            view.removeShapesAtCell(row, column);
        }

        @Override
        public void buttonActionOnClick(String buttonId) {
            switch (buttonId) {
                case "ButtonChangeLabel" -> {
                    view.updateLabeledElement("SampleLabel", "Updated Text");
                    view.updateLabeledElement("ButtonChangeLabel", "Updated Text");
                }
                case "ButtonStarSquare" -> {
                    changeCellColors(view, Color.GREEN, Color.DARKGREEN);
                    changeShapes(view, Shape.STAR, Color.DARKBLUE, Shape.SQUARE, Color.DARKRED);
                }
                case "ButtonDiamondCircle" -> {
                    changeCellColors(view, Color.WHITE, Color.DARKBLUE);
                    changeShapes(view, Shape.DIAMOND, Color.LIGHTBLUE, Shape.CIRCLE, Color.RED);
                }
                default -> throw new IllegalStateException("Unexpected event, button id : " + buttonId);
            }
        }
    }

    public static void main(String[] args) {
        BoardGameConfiguration boardGameConfiguration = new BoardGameConfiguration("Hello World",
                new BoardGameDimensions(8, 8),
                List.of(new LabeledElementConfiguration("Change button & label", "ButtonChangeLabel", LabeledElementKind.BUTTON),
                        new LabeledElementConfiguration("Add squares and stars", "ButtonStarSquare", LabeledElementKind.BUTTON),
                        new LabeledElementConfiguration("Add diamonds and circles", "ButtonDiamondCircle", LabeledElementKind.BUTTON),
                        new LabeledElementConfiguration("Initial Text", "Initial Text", LabeledElementKind.TEXT)
                ));
        BoardGameController controller = new HelloController();
        BoardGameApplicationLauncher launcher = JavaFXBoardGameApplicationLauncher.getInstance();
        launcher.launchApplication(boardGameConfiguration, controller);
    }

    private static void changeCellColors(BoardGameView view, Color oddColor, Color evenColor) {
        for (int row = 0; row < 8; row++) {
            for (int column = 0; column < 8; column++) {
                boolean isEven = (row + column) % 2 == 0;
                Color colorSquare = isEven ? evenColor : oddColor;
                view.setCellColor(row, column, colorSquare);
                view.addShapeAtCell(row, column, Shape.TRIANGLE, Color.BLACK);
            }
        }
    }

    private static void changeShapes(BoardGameView view, Shape oddShape, Color oddColor, Shape evenShape, Color evenColor) {
        for (int row = 0; row < 8; row++) {
            for (int column = 0; column < 8; column++) {
                boolean isEven = (row + column) % 2 == 0;
                Color colorShape = isEven ? evenColor : oddColor;
                Shape shape = isEven ? evenShape : oddShape;
                view.removeShapesAtCell(row, column);
                view.addShapeAtCell(row, column, shape, colorShape);
            }
        }
    }
}
 No newline at end of file
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics;

import fr.univ_amu.m1info.board_game_library.graphics.configuration.BoardGameConfiguration;

/**
 * Interface responsible for launching a board game application.
 * It defines a method to initialize and start the game with the provided configuration,
 * controller, and view initializer.
 */
public interface BoardGameApplicationLauncher {

    /**
     * Launches the board game application with the specified configuration and controller.
     *
     * @param configuration the configuration of the board game, represented by {@link BoardGameConfiguration}.
     * @param controller    the controller that manages game interactions, implemented by {@link BoardGameController}.
     */
    void launchApplication(BoardGameConfiguration configuration,
                           BoardGameController controller);
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics;

/**
 * Interface representing the controller for a board game.
 * It handles user interactions with the game view.
 */
public interface BoardGameController {

    /**
     * Method called when the user clicks on a cell in the game board.
     *
     * @param row the row of the clicked cell.
     * @param column the column of the clicked cell.
     */
    void boardActionOnClick(int row, int column);

    /**
     * Method called when the user clicks on a specific button.
     *
     * @param buttonId the identifier of the clicked button.
     */
    void buttonActionOnClick(String buttonId);

    /**
     * Initialize the view, method called at the start of the application.
     *
     * @param view the game view to be initialized, implemented by the {@link BoardGameView} interface.
     */
    void initializeViewOnStart(BoardGameView view);


}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics;

/**
 * Interface representing the view for a board game.
 * It defines methods for updating the visual elements of the game.
 */
public interface BoardGameView {

    /**
     * Updates the text of a labeled element in the game view.
     *
     * @param id the identifier of the labeled element to update.
     * @param newText the new text to display.
     */
    void updateLabeledElement(String id, String newText);

    /**
     * Sets the color of a specific cell on the game board.
     *
     * @param row the row of the cell to update.
     * @param column the column of the cell to update.
     * @param color the new color to apply to the cell.
     */
    void setCellColor(int row, int column, Color color);

    /**
     * Adds a shape to a specific cell on the game board.
     *
     * @param row the row of the cell where the shape will be added.
     * @param column the column of the cell where the shape will be added.
     * @param shape the shape to add.
     * @param color the color of the shape.
     */
    void addShapeAtCell(int row, int column, Shape shape, Color color);

    /**
     * Removes all shapes from a specific cell on the game board.
     *
     * @param row the row of the cell to clear.
     * @param column the column of the cell to clear.
     */
    void removeShapesAtCell(int row, int column);


}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics;

/**
 * Enum representing various colors that can be used in a board game.
 * These colors may be applied to game elements such as shapes or cells on the board.
 */
public enum Color {

    /** The color red. */
    RED,

    /** The color green. */
    GREEN,

    /** The color blue. */
    BLUE,

    /** The color white. */
    WHITE,

    /** The color black. */
    BLACK,

    /** A light shade of green. */
    LIGHTGREEN,

    /** A dark shade of green. */
    DARKGREEN,

    /** A light shade of red. */
    LIGHT_RED,

    /** A dark shade of red. */
    DARKRED,

    /** A light shade of blue. */
    LIGHTBLUE,

    /** A dark shade of blue. */
    DARKBLUE
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics;

import fr.univ_amu.m1info.board_game_library.graphics.configuration.BoardGameConfiguration;

import fr.univ_amu.m1info.board_game_library.graphics.javafx.app.JavaFXBoardGameApplication;
import javafx.application.Application;


/**
 * Singleton class responsible for launching a board game application using JavaFX.
 * It implements the {@link BoardGameApplicationLauncher} interface and manages the configuration, controller,
 * and view initializer for the game.
 */
public class JavaFXBoardGameApplicationLauncher implements BoardGameApplicationLauncher {

    /** The singleton instance of the launcher. */
    private static JavaFXBoardGameApplicationLauncher instance = null;

    /** The configuration of the board game. */
    private BoardGameConfiguration configuration;

    /** The controller that manages game interactions. */
    private BoardGameController controller;

    /** Private constructor to prevent direct instantiation. */
    private JavaFXBoardGameApplicationLauncher() {}

    /**
     * Retrieves the singleton instance of the {@code JavaFXBoardGameApplicationLauncher}.
     * If the instance does not already exist, it is created in a thread-safe manner.
     *
     * @return the singleton instance of the launcher.
     */
    public static JavaFXBoardGameApplicationLauncher getInstance() {
        JavaFXBoardGameApplicationLauncher result = instance;
        if (result != null) {
            return result;
        }
        synchronized(JavaFXBoardGameApplicationLauncher.class) {
            if (instance == null) {
                instance = new JavaFXBoardGameApplicationLauncher();
            }
            return instance;
        }
    }

    /**
     * Retrieves the current board game configuration.
     *
     * @return the {@link BoardGameConfiguration} for the game.
     */
    public BoardGameConfiguration getConfiguration() {
        return configuration;
    }

    /**
     * Retrieves the current controller managing the game.
     *
     * @return the {@link BoardGameController} for the game.
     */
    public BoardGameController getController() {
        return controller;
    }

    /**
     * Launches the JavaFX board game application with the specified configuration and controller.
     * This method sets the internal fields and starts the JavaFX application.
     *
     * @param configuration the configuration of the board game, represented by {@link BoardGameConfiguration}.
     * @param controller    the controller that manages game interactions, implemented by {@link BoardGameController}.
     */
    @Override
    public void launchApplication(BoardGameConfiguration configuration,
                                  BoardGameController controller) {
        this.configuration = configuration;
        this.controller = controller;
        Application.launch(JavaFXBoardGameApplication.class);
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics;

/**
 * Enum representing different shapes that can be used in a board game.
 * Each shape can be displayed on the game board to represent various game elements.
 */
public enum Shape {

    /** A square shape. */
    SQUARE,

    /** A circular shape. */
    CIRCLE,

    /** A diamond shape. */
    DIAMOND,

    /** A star-shaped figure. */
    STAR,

    /** A triangular shape. */
    TRIANGLE
}
 No newline at end of file
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.configuration;

import java.util.List;

/**
 * Record that represents the configuration of a board game.
 * It stores essential information such as the game's title, dimensions, and labeled elements.
 *
 * @param title the title of the board game.
 * @param dimensions the dimensions of the board, represented by {@link BoardGameDimensions}.
 * @param labeledElementConfigurations the list of configurations for labeled elements in the game,
 *                                     represented by {@link LabeledElementConfiguration}.
 */
public record BoardGameConfiguration(String title,
                                     BoardGameDimensions dimensions,
                                     List<LabeledElementConfiguration> labeledElementConfigurations) {
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.configuration;

/**
 * Record representing the dimensions of a board game.
 * It defines the number of rows and columns that the game board consists of.
 *
 * @param rowCount the number of rows on the game board.
 * @param columnCount the number of columns on the game board.
 */
public record BoardGameDimensions(int rowCount, int columnCount) {
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.app;

import fr.univ_amu.m1info.board_game_library.graphics.JavaFXBoardGameApplicationLauncher;
import fr.univ_amu.m1info.board_game_library.graphics.javafx.view.BoardGameConfigurator;
import fr.univ_amu.m1info.board_game_library.graphics.javafx.view.BoardGameControllableView;
import fr.univ_amu.m1info.board_game_library.graphics.javafx.view.JavaFXBoardGameViewBuilder;
import javafx.application.Application;
import javafx.stage.Stage;

public class JavaFXBoardGameApplication extends Application {


    @Override
    public void start(Stage stage) {
        var launcher = JavaFXBoardGameApplicationLauncher.getInstance();
        var configuration = launcher.getConfiguration();
        var controller = launcher.getController();
        final JavaFXBoardGameViewBuilder viewBuilder = new JavaFXBoardGameViewBuilder(stage);
        new BoardGameConfigurator().configure(viewBuilder, configuration);
        BoardGameControllableView view = viewBuilder.getView();
        view.setController(controller);
        controller.initializeViewOnStart(view);
        stage.show();
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.board;

import fr.univ_amu.m1info.board_game_library.graphics.Color;
import fr.univ_amu.m1info.board_game_library.graphics.Shape;
import fr.univ_amu.m1info.board_game_library.graphics.javafx.color.JavaFXColorMapper;
import javafx.scene.layout.GridPane;


public class BoardGridView extends GridPane {
    private final static int BASE_SQUARE_SIZE = 65;
    private SquareView[][] squareViews;
    private int rowCount;
    private int columnCount;
    private BoardActionOnClick boardActionOnClick;

    public BoardGridView() {
    }

    public void setDimensions(int rowCount, int columnCount) {
        squareViews = new SquareView[rowCount][columnCount];
        this.rowCount = rowCount;
        this.columnCount = columnCount;
        for (int row = 0; row < rowCount; row++) {
            for (int column = 0; column < columnCount; column++) {
                addSquareView(row, column);
            }
        }
        setActionOnSquares();
    }

    private void addSquareView(int row, int column) {
        squareViews[row][column] = new SquareView(column, row, BASE_SQUARE_SIZE);
        this.add(squareViews[row][column], column, row);
    }

    public void setColorSquare(int row, int column, Color color) {
        squareViews[row][column].setColor(JavaFXColorMapper.getJavaFXColor(color));
    }

    public void setAction(BoardActionOnClick boardActionOnClick) {
        this.boardActionOnClick = boardActionOnClick;
        setActionOnSquares();
    }

    public void setActionOnSquares() {
        for (int row = 0; row < rowCount; row++) {
            for (int column = 0; column < columnCount; column++) {
                squareViews[row][column].setAction(boardActionOnClick);
            }
        }
    }

    public void addShapeAtSquare(int row, int column, Shape shape, Color color) {
        squareViews[row][column].addShape(shape, color);
    }

    public void removeShapesAtSquare(int row, int column) {
        squareViews[row][column].removeShapes();
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.board;

import fr.univ_amu.m1info.board_game_library.graphics.Shape;
import javafx.collections.ObservableList;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;

public class ShapeFactory {

    public static final double SHAPE_SIZE_RATIO = (3. / 4);

    public static javafx.scene.shape.Shape makeShape(Shape shape, double squareSize){
        return switch (shape) {
            case CIRCLE -> makeCircle(squareSize);
            case SQUARE -> makeSquare(squareSize);
            case DIAMOND -> makeDiamond(squareSize);
            case TRIANGLE -> makeTriangle(squareSize);
            case STAR -> makeStar(squareSize);
        };
    }

    private static javafx.scene.shape.Shape makeStar(double squareSize) {
        Polygon polygon = new Polygon();
        var points = polygon.getPoints();
        for (int i = 0; i < 10; i++) {
            double radius = (i%2 == 0) ? SHAPE_SIZE_RATIO /2 * squareSize : SHAPE_SIZE_RATIO /4 * squareSize;
            double angle = Math.PI * i / 5 + Math.PI / 10;
            points.add(radius * Math.cos(angle));
            points.add(radius * Math.sin(angle));
        }
        return polygon;
    }

    private static javafx.scene.shape.Shape makeTriangle(double squareSize) {
        Polygon polygon = new Polygon();
        ObservableList<Double> points = polygon.getPoints();
        points.addAll(0.0, 0.0);
        points.addAll(SHAPE_SIZE_RATIO * squareSize, 0.);
        points.addAll(SHAPE_SIZE_RATIO / 2 * squareSize, SHAPE_SIZE_RATIO * squareSize);
        return polygon;
    }

    private static Rectangle makeDiamond(double squareSize) {
        Rectangle rectangle = new Rectangle(SHAPE_SIZE_RATIO /Math.sqrt(2) * squareSize,
                SHAPE_SIZE_RATIO /Math.sqrt(2) * squareSize);
        rectangle.getTransforms().add(new Rotate(45, 0, 0));
        return rectangle;
    }

    private static Rectangle makeSquare(double squareSize) {
        return new Rectangle(SHAPE_SIZE_RATIO * squareSize, SHAPE_SIZE_RATIO * squareSize);
    }

    private static Circle makeCircle(double squareSize) {
        return new Circle((3. / 8) * squareSize);
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.board;

import fr.univ_amu.m1info.board_game_library.graphics.Shape;
import fr.univ_amu.m1info.board_game_library.graphics.javafx.color.JavaFXColorMapper;
import javafx.scene.Group;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;

public class SquareView extends StackPane {
    private final int column;
    private final int row;
    private final Rectangle squareBackground;
    private final Group shapes = new Group();
    private final int squareSize;


    public SquareView(int column, int row, int squareSize) {
        this.column = column;
        this.row = row;
        this.squareSize = squareSize;
        setWidth(squareSize);
        setHeight(squareSize);
        this.squareBackground = new Rectangle(squareSize, squareSize);
        this.getChildren().add(squareBackground);
        this.getChildren().add(shapes);
        squareBackground.setStroke(Color.BLACK);
        setColor(Color.WHITE);
    }

    public void setColor(Color backgroundColor) {
        squareBackground.setFill(backgroundColor);
    }

    public void setAction(BoardActionOnClick positionHandler) {
        this.setOnMouseClicked(_ -> positionHandler.onClick(this.row, this.column));
    }

    void addShape(Shape shape, fr.univ_amu.m1info.board_game_library.graphics.Color color){
        javafx.scene.shape.Shape shapeFX = ShapeFactory.makeShape(shape, squareSize);
        shapeFX.setFill(JavaFXColorMapper.getJavaFXColor(color));
        shapes.getChildren().add(shapeFX);
    }

    public void removeShapes() {
        shapes.getChildren().clear();
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.color;


import fr.univ_amu.m1info.board_game_library.graphics.Color;

public class JavaFXColorMapper {
    private final static javafx.scene.paint.Color LIGHT_RED = javafx.scene.paint.Color.valueOf("#ff474c");

    private JavaFXColorMapper() {}

    public static javafx.scene.paint.Color getJavaFXColor(Color color) {
        return switch (color) {
            case BLUE -> javafx.scene.paint.Color.BLUE;
            case RED -> javafx.scene.paint.Color.RED;
            case GREEN -> javafx.scene.paint.Color.GREEN;
            case BLACK -> javafx.scene.paint.Color.BLACK;
            case WHITE -> javafx.scene.paint.Color.WHITE;
            case DARKRED -> javafx.scene.paint.Color.DARKRED;
            case DARKGREEN -> javafx.scene.paint.Color.DARKGREEN;
            case DARKBLUE -> javafx.scene.paint.Color.DARKBLUE;
            case LIGHTBLUE -> javafx.scene.paint.Color.LIGHTBLUE;
            case LIGHTGREEN -> javafx.scene.paint.Color.LIGHTGREEN;
            case LIGHT_RED -> LIGHT_RED;
        };
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.view;

import fr.univ_amu.m1info.board_game_library.graphics.configuration.BoardGameConfiguration;
import fr.univ_amu.m1info.board_game_library.graphics.configuration.LabeledElementConfiguration;

public class BoardGameConfigurator {
    public void configure(BoardGameViewBuilder boardGameViewBuilder,
                   BoardGameConfiguration boardGameConfiguration) {
        boardGameViewBuilder = boardGameViewBuilder
                .resetView()
                .setTitle(boardGameConfiguration.title())
                .setBoardGameDimensions(boardGameConfiguration.dimensions().rowCount(),
                        boardGameConfiguration.dimensions().columnCount());
        for (LabeledElementConfiguration elementConfiguration : boardGameConfiguration.labeledElementConfigurations()) {
            switch (elementConfiguration.kind()) {
                case BUTTON -> boardGameViewBuilder = boardGameViewBuilder.addButton(elementConfiguration.id(), elementConfiguration.label());
                case TEXT -> boardGameViewBuilder = boardGameViewBuilder.addLabel(elementConfiguration.id(), elementConfiguration.label());
            }
        }
    }
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.view;

import fr.univ_amu.m1info.board_game_library.graphics.BoardGameController;
import fr.univ_amu.m1info.board_game_library.graphics.BoardGameView;


public interface BoardGameControllableView extends BoardGameView {
    void setController(BoardGameController controller);
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.view;

public interface BoardGameViewBuilder {
    BoardGameViewBuilder resetView();
    BoardGameViewBuilder setBoardGameDimensions(int rowCount, int columnCount);
    BoardGameViewBuilder setTitle(String title);
    BoardGameViewBuilder addLabel(String id, String initialText);
    BoardGameViewBuilder addButton(String id, String label);
    BoardGameControllableView getView();
}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.view;

import fr.univ_amu.m1info.board_game_library.graphics.BoardGameController;
import fr.univ_amu.m1info.board_game_library.graphics.javafx.bar.Bar;
import fr.univ_amu.m1info.board_game_library.graphics.javafx.board.BoardGridView;
import fr.univ_amu.m1info.board_game_library.graphics.Color;
import fr.univ_amu.m1info.board_game_library.graphics.Shape;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class JavaFXBoardGameView implements BoardGameControllableView {
    private final Stage stage;
    private BoardGridView boardGridView;
    private Bar bar;
    private BoardGameController controller;

    public void setController(BoardGameController controller) {
        this.controller = controller;
    }

    public JavaFXBoardGameView(Stage stage) {
        this.stage = stage;
        stage.setOnCloseRequest(_ -> Platform.exit());
        stage.setResizable(false);
        stage.sizeToScene();
    }

    public synchronized void reset() {
        VBox vBox = new VBox();
        bar = new Bar();
        boardGridView = new BoardGridView();
        vBox.getChildren().add(bar);
        vBox.getChildren().add(boardGridView);
        Scene scene = new Scene(vBox);
        stage.setScene(scene);
    }

    @Override
    public synchronized void updateLabeledElement(String id, String newText) {
        bar.updateLabel(id, newText);
    }

    @Override
    public synchronized void setCellColor(int row, int column, Color color) {
        boardGridView.setColorSquare(row, column, color);
    }

    @Override
    public synchronized void addShapeAtCell(int row, int column, Shape shape, Color color) {
        boardGridView.addShapeAtSquare(row, column, shape, color);
    }

    @Override
    public synchronized void removeShapesAtCell(int row, int column) {
        boardGridView.removeShapesAtSquare(row, column);
    }

    public BoardGridView getBoardGridView() {
        return boardGridView;
    }

    public Stage getStage() {
        return stage;
    }

    public Bar getBar() {
        return bar;
    }



    public void buttonActionOnclick(String id){
        controller.buttonActionOnClick(id);
    }

    public void boardActionOnclick(int row, int column){
        controller.boardActionOnClick(row, column);
    }


}
Original line number Diff line number Diff line
package fr.univ_amu.m1info.board_game_library.graphics.javafx.view;

import javafx.stage.Stage;

public class JavaFXBoardGameViewBuilder implements BoardGameViewBuilder {
    JavaFXBoardGameView boardGameView;

    public JavaFXBoardGameViewBuilder(Stage primaryStage) {
        boardGameView = new JavaFXBoardGameView(primaryStage);
    }

    public BoardGameViewBuilder resetView(){
        boardGameView.reset();
        boardGameView.getBoardGridView().setAction(boardGameView::boardActionOnclick);
        return this;
    }


    @Override
    public BoardGameViewBuilder setBoardGameDimensions(int rowCount, int columnCount) {
        boardGameView.getBoardGridView().setDimensions(rowCount, columnCount);
        return this;
    }

    @Override
    public BoardGameViewBuilder setTitle(String title) {
        boardGameView.getStage().setTitle(title);
        return this;
    }

    @Override
    public BoardGameViewBuilder addLabel(String id, String initialText) {
        boardGameView.getBar().addLabel(id, initialText);
        return this;
    }

    @Override
    public BoardGameViewBuilder addButton(String id, String label) {
        boardGameView.getBar().addButton(id, label);
        boardGameView.getBar().setButtonAction(id, ()->boardGameView.buttonActionOnclick(id));
        return this;
    }

    @Override
    public BoardGameControllableView getView() {
        return boardGameView;
    }

}
Original line number Diff line number Diff line
module fr.univ_amu.m1info.board_game_library {
module fr.univ_amu.l3mi.drawing_app {
    requires javafx.controls;
    requires javafx.fxml;
    requires java.desktop;

    exports fr.univ_amu.m1info.board_game_library.graphics;
    exports fr.univ_amu.m1info.board_game_library;
    exports fr.univ_amu.m1info.board_game_library.graphics.javafx.app;
    exports fr.univ_amu.m1info.board_game_library.graphics.configuration;
    exports fr.univ_amu.m1info.board_game_library.graphics.javafx.view;
    exports fr.univ_amu.m1info.board_game_library.graphics.javafx.bar;
    exports fr.univ_amu.m1info.board_game_library.graphics.javafx.board;
    exports fr.univ_amu.l3mi.drawing_app.view;
    exports fr.univ_amu.l3mi.drawing_app;
    exports fr.univ_amu.l3mi.drawing_app.view.javafx.app;
    exports fr.univ_amu.l3mi.drawing_app.view.configuration;
    exports fr.univ_amu.l3mi.drawing_app.view.javafx.view;
    exports fr.univ_amu.l3mi.drawing_app.view.javafx.bar;
    exports fr.univ_amu.l3mi.drawing_app.view.javafx.canvas;
    exports fr.univ_amu.l3mi.drawing_app.controller;
    exports fr.univ_amu.l3mi.drawing_app.model;
    exports fr.univ_amu.l3mi.drawing_app.controller.canvas;
    exports fr.univ_amu.l3mi.drawing_app.model.file;
}
 No newline at end of file
Original line number Diff line number Diff line
package fr.univ_amu.l3mi.drawing_app.model;
import javafx.geometry.Point2D;
import javafx.scene.paint.Color;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.*;


class RectangleTest {
    int x1, y1, x2, y2;
    Point2D corner1;
    Point2D oppositeCorner1;
    Point2D corner2;
    Point2D oppositeCorner2;
    Color fillColor;
    Color stokeColor;
    int strokeWidth;
    Rectangle rectangle1;
    Rectangle rectangle2;
    Rectangle rectangle3;
    Rectangle rectangle4;

    @BeforeEach
    void setUp() {
        x1 = 10;
        x2 = 20;
        y1 = 30;
        y2 = 50;
        corner1 = new Point2D(x1, y1);
        oppositeCorner1 = new Point2D(x2, y2);
        corner2 = new Point2D(x2, y1);
        oppositeCorner2 = new Point2D(x1, y2);
        fillColor = Color.ALICEBLUE;
        stokeColor = Color.AZURE;
        strokeWidth = 10;
        rectangle1 = new Rectangle(corner1, oppositeCorner1, fillColor,
                stokeColor, strokeWidth);
        rectangle2 = new Rectangle(corner2, oppositeCorner2, fillColor,
                stokeColor, strokeWidth);
        rectangle3 = new Rectangle(oppositeCorner2, corner2, fillColor,
                stokeColor, strokeWidth);
        rectangle4 = new Rectangle(oppositeCorner1, corner1, fillColor,
                stokeColor, strokeWidth);
    }

    @Test
    void testGetPoint(){
        assertThat(rectangle1.getPoint(0)).isEqualTo(corner1);
        assertThat(rectangle2.getPoint(0)).isEqualTo(corner1);
        assertThat(rectangle3.getPoint(0)).isEqualTo(corner1);
        assertThat(rectangle4.getPoint(0)).isEqualTo(corner1);
        assertThat(rectangle1.getPoint(1)).isEqualTo(oppositeCorner1);
        assertThat(rectangle2.getPoint(1)).isEqualTo(oppositeCorner1);
        assertThat(rectangle3.getPoint(1)).isEqualTo(oppositeCorner1);
        assertThat(rectangle4.getPoint(1)).isEqualTo(oppositeCorner1);
    }

    @Test
    void testGetTopLeftCorner(){
        assertThat(rectangle1.getTopLeftCorner()).isEqualTo(corner1);
        assertThat(rectangle2.getTopLeftCorner()).isEqualTo(corner1);
        assertThat(rectangle3.getTopLeftCorner()).isEqualTo(corner1);
        assertThat(rectangle4.getTopLeftCorner()).isEqualTo(corner1);
    }

    @Test
    void testGetWidth(){
        assertThat(rectangle1.getWidth()).isEqualTo(x2-x1);
        assertThat(rectangle2.getWidth()).isEqualTo(x2-x1);
        assertThat(rectangle3.getWidth()).isEqualTo(x2-x1);
        assertThat(rectangle4.getWidth()).isEqualTo(x2-x1);
    }

    @Test
    void testGetHeight(){
        assertThat(rectangle1.getHeight()).isEqualTo(y2-y1);
        assertThat(rectangle2.getHeight()).isEqualTo(y2-y1);
        assertThat(rectangle3.getHeight()).isEqualTo(y2-y1);
        assertThat(rectangle4.getHeight()).isEqualTo(y2-y1);
    }
}
 No newline at end of file