From 574dc13c06a5bc596cf3ee56d4eccaebf25cb8ee Mon Sep 17 00:00:00 2001 From: Emi Boucly Date: Thu, 27 Mar 2025 09:50:53 +0100 Subject: [PATCH] =?UTF-8?q?feat(network):=20cr=C3=A9ation=20de=20canvas=20?= =?UTF-8?q?=C3=A0=20distance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../emiko/graphicalapp/HelloController.java | 106 ++++++++++++++---- .../java/fr/emiko/graphicsElement/Line.java | 14 +-- .../java/fr/emiko/graphicsElement/Stroke.java | 2 +- .../graphicsElement/layerListViewCell.java | 34 ++++++ .../main/java/fr/emiko/net/DrawServer.java | 26 ++++- .../src/main/java/fr/emiko/net/Event.java | 2 + .../fr/emiko/graphicalapp/hello-view.fxml | 21 +--- 7 files changed, 154 insertions(+), 51 deletions(-) create mode 100644 graphical-app/src/main/java/fr/emiko/graphicsElement/layerListViewCell.java diff --git a/graphical-app/src/main/java/fr/emiko/graphicalapp/HelloController.java b/graphical-app/src/main/java/fr/emiko/graphicalapp/HelloController.java index 2c99a19..5d9e2df 100644 --- a/graphical-app/src/main/java/fr/emiko/graphicalapp/HelloController.java +++ b/graphical-app/src/main/java/fr/emiko/graphicalapp/HelloController.java @@ -1,6 +1,7 @@ package fr.emiko.graphicalapp; import fr.emiko.graphicsElement.Line; +import fr.emiko.graphicsElement.layerListViewCell; import fr.emiko.net.DrawClient; import fr.emiko.net.DrawServer; import fr.emiko.net.Event; @@ -46,7 +47,6 @@ public class HelloController implements Initializable { public MenuItem loadButton; public MenuItem newCanvasButton; public Slider brushSizeSlider; - public Slider zoomSlider; public ScrollPane scrollPane; public Label brushSizeLabel; public Pane pane; @@ -56,7 +56,7 @@ public class HelloController implements Initializable { public SplitPane mainPane; public MenuItem stopHostButton; public ColorPicker colorPicker; - public ListView layerListView; + public ListView layerListView; public Button addLayerButton; public Button removeLayerButton; private double posX = 0; @@ -71,7 +71,6 @@ public class HelloController implements Initializable { private DrawClient client; private ToggleButton hostButtonToggle = new ToggleButton(); private DrawServer server; - private Canvas currentLayer; private ObservableList layerObservableList = FXCollections.observableArrayList(); @@ -83,7 +82,7 @@ public class HelloController implements Initializable { scrollPane.setOnScroll(this::onScrollZoom); scrollPane.setOnKeyPressed(this::onActionKeyPressed); brushSizeLabel.textProperty().bind(brushSizeSlider.valueProperty().asString()); - setupCanvas(); + setupCanvas(drawingCanvas); scrollPane.prefViewportHeightProperty().bind(pane.layoutYProperty()); scrollPane.prefViewportWidthProperty().bind(pane.layoutXProperty()); @@ -92,12 +91,42 @@ public class HelloController implements Initializable { joinButton.setOnAction(this::onActionJoin); disconnectButton.setOnAction(this::onActionDisconnect); + newCanvasButton.disableProperty().bind(hostButtonToggle.selectedProperty().not()); stopHostButton.disableProperty().bind(hostButtonToggle.selectedProperty().not()); disconnectButton.disableProperty().bind(hostButtonToggle.selectedProperty().not()); hostButtonToggle.setSelected(false); mainPane.disableProperty().bind(hostButtonToggle.selectedProperty().not()); + layerListView.setCellFactory(layerListView -> new layerListViewCell()); layerListView.setItems(layerObservableList); + layerListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + //addLayerButton.setOnAction(this::onActionAddLayer); + //removeLayerButton.setOnAction(this::onActionRemoveLayer); + //layerListView.setOnMouseClicked(this::onActionSelectCanvas); + } + + private void onActionSelectCanvas(MouseEvent mouseEvent) { + layerListView.getSelectionModel().getSelectedItem().requestFocus(); + layerListView.getSelectionModel().getSelectedItem().toFront(); + } + + private void onActionRemoveLayer(ActionEvent actionEvent) { + pane.getChildren().remove(layerListView.getSelectionModel().getSelectedItem()); + layerObservableList.remove(layerListView.getSelectionModel().getSelectedItem()); + layerListView.refresh(); + layerListView.getSelectionModel().select(layerObservableList.getFirst()); + } + + private void onActionAddLayer(ActionEvent actionEvent) { + Canvas newLayer = new Canvas( + layerListView.getSelectionModel().getSelectedItem().getWidth(), + layerListView.getSelectionModel().getSelectedItem().getHeight() + ); + pane.getChildren().add(newLayer); + layerObservableList.addFirst(newLayer); + layerListView.getSelectionModel().select(newLayer); + setupCanvas(newLayer); + layerListView.refresh(); } private void onActionStopHost(ActionEvent actionEvent) { @@ -109,10 +138,12 @@ public class HelloController implements Initializable { showErrorDialog(e, "Could not close server instance"); } } + hostButtonToggle.setSelected(false); } private void onActionDisconnect(ActionEvent actionEvent) { client.close(); + hostButtonToggle.setSelected(false); } @@ -129,6 +160,7 @@ public class HelloController implements Initializable { String host = matcher.group(1); String port = matcher.group(2); connectClient(host, port == null ? 8090 : Integer.parseInt(port)); + client.sendEvent(new Event(Event.LINELST, new JSONObject())); } catch (NumberFormatException e) { showErrorDialog(e, "Invalid distant address"); } catch (IOException e) { @@ -194,15 +226,20 @@ public class HelloController implements Initializable { alert.showAndWait(); } - private void setupCanvas() { - drawingCanvas.requestFocus(); - drawingCanvas.getGraphicsContext2D().setFill(Color.WHITE); - drawingCanvas.getGraphicsContext2D().fillRect(0, 0, drawingCanvas.getWidth(), drawingCanvas.getHeight()); + private void setupCanvas(Canvas canvas) { + canvas.requestFocus(); + canvas.getGraphicsContext2D().setFill(Color.WHITE); + canvas.getGraphicsContext2D().fillRect(0, 0, drawingCanvas.getWidth(), drawingCanvas.getHeight()); brushSizeSlider.setValue(1); - drawingCanvas.setTranslateX(scrollPane.getWidth()/2); - drawingCanvas.setTranslateY(scrollPane.getHeight()/2); - drawingCanvas.setOnMouseDragged(this::printLine); - drawingCanvas.setOnMouseClicked(this::resetPos); +// canvas.setTranslateX(scrollPane.getWidth()/2); +// canvas.setTranslateY(scrollPane.getHeight()/2); + colorPicker.setValue(Color.BLACK); + canvas.setOnMouseDragged(this::printLine); + canvas.setOnMouseClicked(this::resetPos); + + layerListView.getSelectionModel().select(drawingCanvas); + layerObservableList.add(drawingCanvas); + layerListView.refresh(); scrollPane.addEventFilter(ScrollEvent.ANY, new EventHandler() { @Override public void handle(ScrollEvent event) { @@ -221,10 +258,14 @@ public class HelloController implements Initializable { if (keyEvent.isControlDown() && keyEvent.getCode().equals(KeyCode.Z)) { System.out.println("CTRL Z"); System.out.println(lines); + System.out.println(lines); lines.remove(lines.lastElement()); - GraphicsContext gc = drawingCanvas.getGraphicsContext2D(); + Canvas currentLayer = layerListView.getSelectionModel().getSelectedItem(); + GraphicsContext gc = currentLayer.getGraphicsContext2D(); gc.setFill(Color.WHITE); - gc.fillRect(0, 0, drawingCanvas.getWidth(), drawingCanvas.getHeight()); + gc.fillRect(0, 0, currentLayer.getWidth(), currentLayer.getHeight()); + gc.clearRect(0, 0, currentLayer.getWidth(), currentLayer.getHeight()); + gc.fill(); for (Vector strokeVector : lines) { for (Stroke stroke: strokeVector) { stroke.draw(gc, stroke.getColor()); @@ -277,6 +318,7 @@ public class HelloController implements Initializable { drawingCanvas.getGraphicsContext2D().fill(); pane.setScaleX(1); pane.setScaleY(1); + client.sendEvent(new Event(Event.ADDCANVAS, new JSONObject().put("width", drawingCanvas.getWidth()).put("height", drawingCanvas.getHeight()))); System.out.println("New canvas created"); } } catch (IOException ignored) { @@ -337,8 +379,9 @@ public class HelloController implements Initializable { } private void printLine(MouseEvent mouseEvent) { + Canvas currentLayer = layerListView.getSelectionModel().getSelectedItem(); if (mouseEvent.isPrimaryButtonDown()) { - GraphicsContext gc = drawingCanvas.getGraphicsContext2D(); + GraphicsContext gc = currentLayer.getGraphicsContext2D(); if (posX == 0 || posY == 0) { posX = mouseEvent.getX(); @@ -354,7 +397,19 @@ public class HelloController implements Initializable { } else if (mouseEvent.isSecondaryButtonDown()) { + GraphicsContext gc = currentLayer.getGraphicsContext2D(); + if (posX == 0 || posY == 0) { + posX = mouseEvent.getX(); + posY = mouseEvent.getY(); + } + + Stroke stroke = new Stroke(posX, posY, mouseEvent.getX(), mouseEvent.getY(), brushSizeSlider.getValue(), colorPicker.getValue()); + strokes.add(stroke); + stroke.draw(gc, Color.WHITE); + + posX = mouseEvent.getX(); + posY = mouseEvent.getY(); } } @@ -368,10 +423,25 @@ public class HelloController implements Initializable { case Event.DELLINE -> { doDeleteLine(event.getContent()); } + case Event.CNVS -> { + doAddCanvas(event.getContent()); + } default -> {} } } + private void doAddCanvas(JSONObject content) { + drawingCanvas.setWidth(content.getDouble("width")); + drawingCanvas.setHeight(content.getDouble("height")); + drawingCanvas.getGraphicsContext2D().setFill(Color.WHITE); + drawingCanvas.getGraphicsContext2D().fillRect(0, 0, drawingCanvas.getWidth(), drawingCanvas.getHeight()); + drawingCanvas.getGraphicsContext2D().fill(); + pane.setScaleX(1); + pane.setScaleY(1); + + setupCanvas(drawingCanvas); + } + private void doDeleteLine(JSONObject content) { lines.remove(Line.fromJSONArray(content.getJSONArray("line"))); @@ -409,10 +479,8 @@ public class HelloController implements Initializable { } } }); - for (Line line: lines) { - for (Stroke stroke: line) { - stroke.draw(gc, colorPicker.getValue()); - } + for (Stroke stroke: importedLine) { + stroke.draw(gc, stroke.getColor()); } } } \ No newline at end of file diff --git a/graphical-app/src/main/java/fr/emiko/graphicsElement/Line.java b/graphical-app/src/main/java/fr/emiko/graphicsElement/Line.java index 716780c..6b332b7 100644 --- a/graphical-app/src/main/java/fr/emiko/graphicsElement/Line.java +++ b/graphical-app/src/main/java/fr/emiko/graphicsElement/Line.java @@ -3,18 +3,18 @@ package fr.emiko.graphicsElement; import org.json.JSONArray; import org.json.JSONObject; +import java.util.UUID; import java.util.Vector; public class Line extends Vector { private int timestamp; - private int layer; - private javafx.scene.paint.Color color; + public JSONObject toJSONObject() { JSONArray jsonArray = new JSONArray(); for (Stroke stroke: this) { jsonArray.put(stroke.toJSON()); } - return new JSONObject().put("line", jsonArray); + return new JSONObject().put("line", jsonArray).put("timestamp", timestamp); } public static Line fromJSONArray(JSONArray jsonArray) { @@ -32,12 +32,4 @@ public class Line extends Vector { public void setTimestamp(int timestamp) { this.timestamp = timestamp; } - - public int getLayer() { - return layer; - } - - public void setLayer(int layer) { - this.layer = layer; - } } diff --git a/graphical-app/src/main/java/fr/emiko/graphicsElement/Stroke.java b/graphical-app/src/main/java/fr/emiko/graphicsElement/Stroke.java index 19e4426..ecfcf5b 100644 --- a/graphical-app/src/main/java/fr/emiko/graphicsElement/Stroke.java +++ b/graphical-app/src/main/java/fr/emiko/graphicsElement/Stroke.java @@ -35,7 +35,7 @@ public class Stroke { jsonObject.getDouble("toX"), jsonObject.getDouble("toY"), jsonObject.getDouble("brushSize"), - (Color) jsonObject.get("color") + Color.valueOf(jsonObject.get("color").toString()) ); } diff --git a/graphical-app/src/main/java/fr/emiko/graphicsElement/layerListViewCell.java b/graphical-app/src/main/java/fr/emiko/graphicsElement/layerListViewCell.java new file mode 100644 index 0000000..796e358 --- /dev/null +++ b/graphical-app/src/main/java/fr/emiko/graphicsElement/layerListViewCell.java @@ -0,0 +1,34 @@ +package fr.emiko.graphicsElement; + +import javafx.geometry.Pos; +import javafx.scene.control.ListCell; +import javafx.scene.canvas.Canvas; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.text.Text; + +public class layerListViewCell extends ListCell { + + @Override + protected void updateItem(Canvas item, boolean empty) { + super.updateItem(item, empty); + if (empty) { + setGraphic(null); + } else { + updateItem(item); + } + } + + + private void updateItem(Canvas item) { + ImageView imageView = new ImageView(); + imageView.setImage(item.snapshot(null, null)); + imageView.setFitHeight(25); + imageView.setFitWidth(25); + Text text = new Text(item.toString()); + HBox hbox = new HBox(imageView, text); + hbox.setSpacing(10); + hbox.setAlignment(Pos.CENTER_LEFT); + setGraphic(hbox); + } +} diff --git a/graphical-app/src/main/java/fr/emiko/net/DrawServer.java b/graphical-app/src/main/java/fr/emiko/net/DrawServer.java index bdafaad..b8346a7 100644 --- a/graphical-app/src/main/java/fr/emiko/net/DrawServer.java +++ b/graphical-app/src/main/java/fr/emiko/net/DrawServer.java @@ -17,6 +17,8 @@ public class DrawServer { private ServerSocket passiveSocket; private Vector clientList = new Vector(); private Vector lines; + private double canvasWidth; + private double canvasHeight; public DrawServer(int port) throws IOException { passiveSocket = new ServerSocket(port); } @@ -158,16 +160,26 @@ public class DrawServer { doDelLine(event.getContent()); return true; } - case Event.LSTLINE -> { + case Event.LINELST -> { doSendLines(); return true; } + case Event.ADDCANVAS -> { + doAddCanvas(event.getContent()); + return true; + } default -> { return false; } } } + private void doAddCanvas(JSONObject content) throws JSONException { + canvasWidth = content.getDouble("width"); + canvasHeight = content.getDouble("height"); + sendAllOtherUsers(new Event(Event.CNVS, content)); + } + private void doDelLine(JSONObject content) { Line line = Line.fromJSONArray(content.getJSONArray("line")); this.user.getLines().remove(line); @@ -189,9 +201,11 @@ public class DrawServer { } private void sendAllOtherUsers(Event event) { + System.out.println("current user: " + this.user.getUsername()); for (DrawClientHandler client : clientList) { + System.out.println("calculating user: " + client.user.getUsername()); if (client.user != this.user) { - System.out.println(client.user.getUsername()); + System.out.println("found user: " + client.user.getUsername()); sendEvent(client, event); } } @@ -203,6 +217,12 @@ public class DrawServer { } private void doSendLines() { + out.println( + new Event("CNVS", new JSONObject() + .put("width", canvasWidth) + .put("height", canvasHeight)) + ); + Vector lines = new Vector<>(); for (DrawClientHandler client: clientList) { for (Line line: client.user.getLines()) { @@ -210,7 +230,7 @@ public class DrawServer { } } for (Line line: lines) { - out.println(new Event("LINELST", line.toJSONObject())); + out.println(new Event("LINE", line.toJSONObject())); } } diff --git a/graphical-app/src/main/java/fr/emiko/net/Event.java b/graphical-app/src/main/java/fr/emiko/net/Event.java index 73d7cd1..519059d 100644 --- a/graphical-app/src/main/java/fr/emiko/net/Event.java +++ b/graphical-app/src/main/java/fr/emiko/net/Event.java @@ -9,6 +9,8 @@ public class Event { public static final String DELLINE = "DELLINE"; public static final String LINE = "LINE"; public static final String LINELST = "LINELST"; + public static final String ADDCANVAS = "ADDCANVAS"; + public static final String CNVS = "CNVS"; private String type; private JSONObject content; diff --git a/graphical-app/src/main/resources/fr/emiko/graphicalapp/hello-view.fxml b/graphical-app/src/main/resources/fr/emiko/graphicalapp/hello-view.fxml index 166c06e..bbb4cef 100644 --- a/graphical-app/src/main/resources/fr/emiko/graphicalapp/hello-view.fxml +++ b/graphical-app/src/main/resources/fr/emiko/graphicalapp/hello-view.fxml @@ -50,23 +50,10 @@ - + - + - - - - - - - - - - - @@ -117,7 +104,7 @@ - + @@ -129,7 +116,7 @@