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 getTarget(MouseEvent evt, SCollection sc) { return sc.stream() .filter(s -> s.getBounds().contains(evt.getPoint())) .findFirst(); } }