123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- package holeg.ui.view.canvas;
- import holeg.model.*;
- import holeg.ui.controller.Control;
- import holeg.ui.model.GuiSettings;
- import holeg.utility.math.vector.Geometry;
- import holeg.utility.math.vector.Vec2i;
- import javax.swing.*;
- import java.awt.*;
- import java.awt.event.MouseEvent;
- import java.awt.event.MouseListener;
- import java.awt.event.MouseMotionListener;
- import java.util.HashSet;
- import java.util.Optional;
- import java.util.Set;
- import java.util.logging.Logger;
- public class Canvas extends JPanel {
- private static final Logger log = Logger.getLogger(Canvas.class.getName());
- private final GroupNode groupNode;
- private final Control control;
- private final CanvasMouseListener canvasMouseListener = new CanvasMouseListener();
- private boolean enabled = true;
- public Canvas(Control control, GroupNode groupNode) {
- this.control = control;
- this.groupNode = groupNode;
- control.OnGuiSetEnabled.addListener(this::setCanvasEnabled);
- control.OnSelectionChanged.addListener(this::repaint);
- // TODO(Tom2022-01-14): remove listener when not needed anymore
- this.addMouseListener(canvasMouseListener);
- this.addMouseMotionListener(canvasMouseListener);
- }
- public static Rectangle getBoundsOfObject(AbstractCanvasObject obj) {
- int pictureScale = GuiSettings.getPictureScale();
- int pictureScaleDiv2 = GuiSettings.getPictureScaleDiv2();
- Vec2i pos = obj.getPosition();
- return new Rectangle(pos.getX() - pictureScaleDiv2, pos.getY() - pictureScaleDiv2, pictureScale, pictureScale);
- }
- private void setCanvasEnabled(boolean state) {
- enabled = state;
- }
- public GroupNode getGroupNode() {
- return this.groupNode;
- }
- @Override
- public void paintComponent(java.awt.Graphics g) {
- super.paintComponent(g);
- log.info("Draw");
- Graphics2D g2d = Rendering.initGraphics2D(g);
- Rendering.drawSelection(g2d);
- control.getModel().getEdgesOnCanvas().forEach(edge -> {
- boolean edgeAinside = edge.getA().getGroupNode().get() == groupNode;
- boolean edgeBinside = edge.getB().getGroupNode().get() == groupNode;
- //both
- if (edgeAinside && edgeBinside) {
- Rendering.drawEdge(g2d, edge);
- }
- //TODO(Tom2022-01-16): oneside
- //none
- });
- groupNode.getHolonObjects().forEach(hO -> Rendering.drawHolonObject(g2d, hO));
- groupNode.getSwitches().forEach(hS -> Rendering.drawSwitchObject(g2d, hS));
- groupNode.getGroupNodes().forEach(groupNode -> Rendering.drawGroupNode(g2d, groupNode));
- groupNode.getNodes().forEach(node -> Rendering.drawNode(g2d, node));
- switch (canvasMouseListener.state) {
- case BoxSelection -> Rendering.drawSelectionBox(g2d, canvasMouseListener.getRectangleOfSelectionBox());
- case EdgeCreation -> Rendering.drawNewEdgeLine(g2d, canvasMouseListener.selectedOnPressed.getPosition(), canvasMouseListener.lastPosition);
- }
- }
- private Optional<AbstractCanvasObject> getObjectAtPosition(Vec2i pos) {
- return groupNode.getObjectsInThisLayer().filter(obj ->
- getBoundsOfObject(obj).contains(pos.getX(), pos.getY())
- ).findAny();
- }
- //TODO(Tom2022-01-17): checkForReplacement replace with getObjectAtPosition
- public Optional<AbstractCanvasObject> checkForReplacement(int x, int y) {
- return Optional.empty();
- }
- /**
- * Microsoft Windows10 selection & dragging behavior
- */
- private class CanvasMouseListener implements MouseListener, MouseMotionListener {
- private Vec2i lastPosition = new Vec2i();
- private Vec2i pressedPosition = new Vec2i();
- private Set<AbstractCanvasObject> selectionBeforeBoxSelection = new HashSet<>();
- private State state = State.None;
- private AbstractCanvasObject selectedOnPressed = null;
- @Override
- public void mousePressed(MouseEvent e) {
- if (!enabled) {
- return;
- }
- log.info(state.toString());
- if (!e.isControlDown()) {
- GuiSettings.getSelectedObjects().clear();
- }
- Vec2i pos = new Vec2i(e.getPoint());
- getObjectAtPosition(pos).ifPresentOrElse(obj -> {
- if (!GuiSettings.getSelectedObjects().contains(obj)) {
- state = State.Selection;
- GuiSettings.getSelectedObjects().add(obj);
- }
- selectedOnPressed = obj;
- }, () -> {
- state = State.BoxSelection;
- selectionBeforeBoxSelection = Set.copyOf(GuiSettings.getSelectedObjects());
- });
- control.OnSelectionChanged.broadcast();
- lastPosition = pressedPosition = pos;
- }
- @Override
- public void mouseDragged(MouseEvent e) {
- if (!enabled) {
- return;
- }
- log.info(state.toString());
- Vec2i actualPos = new Vec2i(e.getPoint());
- switch (state) {
- case None, Selection -> {
- // Not handle to small mouse dragging
- if (!(pressedPosition.getSquaredDistance(actualPos) > GuiSettings.dragThresholdDistance)) {
- return;
- }
- if (SwingUtilities.isLeftMouseButton(e)) {
- state = State.ObjectDragging;
- } else if (SwingUtilities.isRightMouseButton(e)) {
- state = State.EdgeCreation;
- }
- }
- case BoxSelection -> {
- Rectangle selectionBox = getRectangleOfSelectionBox();
- groupNode.getObjectsInThisLayer().forEach(obj -> {
- Rectangle bounds = getBoundsOfObject(obj);
- if (selectionBox.intersects(bounds) ^ selectionBeforeBoxSelection.contains(obj)) {
- control.addSelectedObject(obj);
- } else {
- control.removeObjectFromSelection(obj);
- }
- });
- repaint();
- }
- case ObjectDragging -> {
- Vec2i delta = actualPos.subtract(lastPosition);
- GuiSettings.getSelectedObjects().forEach(obj -> obj.getPosition().addAssign(delta));
- repaint();
- }
- case EdgeCreation -> repaint();
- }
- lastPosition = actualPos;
- }
- @Override
- public void mouseReleased(MouseEvent e) {
- if (!enabled) {
- return;
- }
- log.info(state.toString());
- switch (state) {
- case None -> {
- if (GuiSettings.getSelectedObjects().contains(selectedOnPressed)) {
- control.removeObjectFromSelection(selectedOnPressed);
- } else {
- control.addSelectedObject(selectedOnPressed);
- }
- }
- case EdgeCreation -> {
- getObjectAtPosition(lastPosition).ifPresentOrElse(obj -> control.addEdgeOnCanvas(new Edge(selectedOnPressed, obj, GuiSettings.maxCapacityForNewCreatedEdges)), () -> {
- Node node = new Node("Node");
- groupNode.add(node);
- node.setPosition(new Vec2i(lastPosition));
- control.addEdgeOnCanvas(new Edge(selectedOnPressed, node, GuiSettings.maxCapacityForNewCreatedEdges));
- });
- control.calculateStateAndVisualForCurrentTimeStep();
- }
- }
- state = State.None;
- repaint();
- }
- @Override
- public void mouseClicked(MouseEvent e) {
- boolean doubleLeftClick = e.getClickCount() % 2 == 0 && SwingUtilities.isLeftMouseButton(e);
- if (doubleLeftClick) {
- log.info(state.toString());
- getObjectAtPosition(new Vec2i(e.getPoint())).ifPresent(obj -> {
- if (obj instanceof HolonSwitch sw) {
- sw.setMode(HolonSwitch.SwitchMode.Manual);
- sw.flipManualState();
- control.calculateStateAndVisualForCurrentTimeStep();
- }
- });
- }
- }
- Rectangle getRectangleOfSelectionBox() {
- return Geometry.createRectangleFromCorners(lastPosition, pressedPosition);
- }
- @Override
- public void mouseEntered(MouseEvent e) {
- }
- @Override
- public void mouseExited(MouseEvent e) {
- }
- @Override
- public void mouseMoved(MouseEvent e) {
- }
- private enum State {
- None, BoxSelection, EdgeCreation, ObjectDragging, Selection
- }
- }
- }
|