Files
new-shapes/src/main/java/ovh/gasser/newshapes/ui/Controller.java
2026-03-19 21:45:54 +01:00

178 lines
5.3 KiB
Java

package ovh.gasser.newshapes.ui;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ovh.gasser.newshapes.HTMLExporter;
import ovh.gasser.newshapes.Selection;
import ovh.gasser.newshapes.attributes.ColorAttributes;
import ovh.gasser.newshapes.shapes.SCollection;
import ovh.gasser.newshapes.shapes.SText;
import ovh.gasser.newshapes.shapes.Shape;
import ovh.gasser.newshapes.ui.listeners.SelectionListener;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.FileNotFoundException;
import java.util.Optional;
public class Controller {
private final static Logger logger = LoggerFactory.getLogger(Controller.class);
private final ShapesView view;
private final SCollection model;
private final Selection selection;
private Point lastMousePos;
private boolean addingText;
Controller(ShapesView view, SCollection model) {
this.view = view;
this.model = model;
this.selection = new Selection();
var adapter = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent evt) {
handleMousePressed(evt);
}
@Override
public void mouseDragged(MouseEvent evt) {
handleMouseDragged(evt);
}
};
this.view.addMouseMotionListener(adapter);
this.view.addMouseListener(adapter);
this.view.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
handleKeyPressed(e);
}
});
}
private void handleMouseDragged(MouseEvent evt) {
int dx = evt.getX() - lastMousePos.x;
int dy = evt.getY() - lastMousePos.y;
for (Shape shape : selection) {
shape.translate(dx, dy);
}
lastMousePos = evt.getPoint();
view.repaint();
}
private void handleMousePressed(MouseEvent evt) {
if (addingText) {
placeTextAt(evt.getPoint());
return;
}
getTarget(evt, this.model)
.ifPresentOrElse(
s -> {
if (!evt.isShiftDown()) {
resetSelection();
}
lastMousePos = evt.getPoint();
selection.add(s);
logger.debug("Selecting {}", s);
},
this::resetSelection
);
view.repaint();
}
public void enterTextMode() {
addingText = true;
}
private void placeTextAt(Point point) {
String input = JOptionPane.showInputDialog(view, "Enter text:", "Add text", JOptionPane.PLAIN_MESSAGE);
addingText = false;
if (input == null) {
return;
}
model.add(SText.create(point.x, point.y, input));
resetSelection();
view.repaint();
}
private void handleKeyPressed(KeyEvent evt) {
switch (evt.getKeyCode()) {
case KeyEvent.VK_DELETE -> deleteSelected();
case KeyEvent.VK_C -> copySelection();
case KeyEvent.VK_A -> changeSelectionColor();
case KeyEvent.VK_H -> exportHtml();
default -> logger.warn("Pressed unhandled key: {}", evt.getKeyChar());
}
}
private void exportHtml() {
logger.info("Exporting view to html");
try {
new HTMLExporter(this.model).export();
} catch (FileNotFoundException e) {
logger.error("Unable to export html: {}", e.getMessage());
}
}
private void changeSelectionColor(){
if (selection == null) {
logger.debug("No selection to change color of");
return;
}
for (Shape s : selection) {
if (s instanceof SCollection collection) {
collection.forEach(shape -> shape.addAttributes(new ColorAttributes(false, true, Color.BLACK, new Color((int) (Math.random() * 0x1000000)))));
} else {
s.addAttributes(new ColorAttributes(false, true, Color.BLACK, new Color((int) (Math.random() * 0x1000000))));
}
}
view.repaint();
}
private void copySelection() {
if (selection == null) {
logger.debug("No selection to copy");
return;
}
for (Shape shape : selection) {
this.model.add(shape.clone());
}
view.repaint();
}
public void deleteSelected() {
if (selection == null) return;
logger.debug("Deleting selected shape(s)");
for (Shape s : selection) {
this.model.remove(s);
}
resetSelection();
view.repaint();
}
private void resetSelection() {
logger.debug("Resetting selection");
selection.clear();
}
public void addSelectionChangeListener(SelectionListener listener) {
selection.addListener(listener);
}
private Optional<Shape> getTarget(MouseEvent evt, SCollection sc) {
return sc.stream()
.filter(s -> s.getBounds().contains(evt.getPoint()))
.findFirst();
}
}