added move and delete

This commit is contained in:
hneemann 2016-03-16 22:50:05 +01:00
parent 1095d1c626
commit 12d5f00312
8 changed files with 362 additions and 35 deletions

View File

@ -38,7 +38,13 @@ public class Main extends JFrame {
parts.add(createSimpleMenu("OR", inputs -> Or.createFactory(1, inputs)));
parts.add(createSimpleMenu("NAND", inputs -> NAnd.createFactory(1, inputs)));
parts.add(createSimpleMenu("NOR", inputs -> NOr.createFactory(1, inputs)));
parts.add(new InsertAbstractAction("Not", Not.createFactory(1)));
parts.add(new InsertAction("Not", Not.createFactory(1)));
JMenu edit = new JMenu("Edit");
bar.add(edit);
edit.add(new JMenuItem(new ModeAction("Wire", CircuitComponent.Mode.wire)));
edit.add(new JMenuItem(new ModeAction("Parts", CircuitComponent.Mode.part)));
edit.add(new JMenuItem(new ModeAction("Move", CircuitComponent.Mode.move)));
setJMenuBar(bar);
}
@ -50,7 +56,7 @@ public class Main extends JFrame {
private JMenu createSimpleMenu(String name, DescriptionFactory factory) {
JMenu m = new JMenu(name);
for (int i = 2; i < 16; i++) {
m.add(new JMenuItem(new InsertAbstractAction(Integer.toString(i), factory.create(i))));
m.add(new JMenuItem(new InsertAction(Integer.toString(i), factory.create(i))));
}
return m;
}
@ -59,18 +65,33 @@ public class Main extends JFrame {
PartDescription create(int inputs);
}
private class InsertAbstractAction extends AbstractAction {
private class InsertAction extends AbstractAction {
private final PartDescription partDescription;
public InsertAbstractAction(String name, PartDescription partDescription) {
public InsertAction(String name, PartDescription partDescription) {
super(name);
this.partDescription = partDescription;
}
@Override
public void actionPerformed(ActionEvent e) {
cr.add(new VisualPart(partDescription).setPos(new Vector(10, 10)));
VisualPart visualPart = new VisualPart(partDescription).setPos(new Vector(10, 10));
cr.add(visualPart);
circuitComponent.setPartToDrag(visualPart);
}
}
private class ModeAction extends AbstractAction {
private final CircuitComponent.Mode mode;
public ModeAction(String name, CircuitComponent.Mode mode) {
super(name);
this.mode = mode;
}
@Override
public void actionPerformed(ActionEvent e) {
circuitComponent.setMode(mode);
}
}
}

View File

@ -1,30 +1,79 @@
package de.neemann.digital.gui.components;
import de.neemann.digital.gui.draw.graphics.GraphicSwing;
import de.neemann.digital.gui.draw.graphics.Vector;
import de.neemann.digital.gui.draw.graphics.*;
import de.neemann.digital.gui.draw.graphics.Polygon;
import de.neemann.digital.gui.draw.parts.Circuit;
import de.neemann.digital.gui.draw.parts.Moveable;
import de.neemann.digital.gui.draw.parts.VisualPart;
import de.neemann.digital.gui.draw.parts.Wire;
import de.neemann.digital.gui.draw.shapes.GenericShape;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
/**
* @author hneemann
*/
public class CircuitComponent extends JComponent {
private static final String delAction = "myDelAction";
private final Circuit circuit;
;
private Mouse listener;
public CircuitComponent(Circuit circuit) {
this.circuit = circuit;
setMode(Mode.part);
MyMouseMotionListener l = new MyMouseMotionListener();
addMouseMotionListener(l);
addMouseListener(l);
KeyStroke delKey = KeyStroke.getKeyStroke("DELETE");
getInputMap().put(delKey, delAction);
getActionMap().put(delAction, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
if (listener instanceof MoveMouseListener) {
MoveMouseListener mml = (MoveMouseListener) listener;
if (mml.corner1 != null && mml.corner2 != null) {
circuit.delete(Vector.min(mml.corner1, mml.corner2), Vector.max(mml.corner1, mml.corner2));
mml.reset();
repaint();
}
}
}
});
}
public void setMode(Mode mode) {
if (listener != null) {
removeMouseListener(listener);
removeMouseMotionListener(listener);
}
switch (mode) {
case part:
listener = new PartMouseListener();
setCursor(new Cursor(Cursor.HAND_CURSOR));
break;
case wire:
listener = new WireMouseListener();
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
break;
case move:
listener = new MoveMouseListener();
setCursor(new Cursor(Cursor.MOVE_CURSOR));
break;
}
addMouseMotionListener(listener);
addMouseListener(listener);
repaint();
}
public void setPartToDrag(VisualPart part) {
setMode(Mode.part);
((PartMouseListener) listener).setPartToDrag(part);
}
@Override
@ -35,6 +84,8 @@ public class CircuitComponent extends JComponent {
GraphicSwing gr = new GraphicSwing((Graphics2D) g);
circuit.drawTo(gr);
listener.drawTo(gr);
}
private Vector raster(Vector pos) {
@ -42,21 +93,84 @@ public class CircuitComponent extends JComponent {
((pos.y + GenericShape.SIZE2) / GenericShape.SIZE) * GenericShape.SIZE);
}
private class MyMouseMotionListener implements MouseMotionListener, MouseListener {
public enum Mode {part, move, wire}
private interface Mouse extends MouseMotionListener, MouseListener {
void drawTo(Graphic gr);
}
private class WireMouseListener implements Mouse {
private Wire wire;
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
if (wire != null) {
circuit.add(wire);
repaint();
}
Vector startPos = raster(new Vector(e.getX(), e.getY()));
wire = new Wire(startPos, startPos);
repaint();
} else {
wire = null;
repaint();
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseMoved(MouseEvent e) {
if (wire != null) {
wire.setP2(raster(new Vector(e.getX(), e.getY())));
repaint();
}
}
@Override
public void drawTo(Graphic gr) {
if (wire != null)
wire.drawTo(gr);
}
}
private class PartMouseListener implements Mouse {
private Vector lastPos;
private VisualPart partToDrag;
private boolean autoPick = false;
private Vector delta;
@Override
public void mouseDragged(MouseEvent e) {
Vector pos = new Vector(e.getX(), e.getY());
if (partToDrag != null) {
partToDrag.move(pos.sub(lastPos));
partToDrag.setPos(raster(pos.add(delta)));
repaint();
}
lastPos = pos;
}
@Override
@ -70,28 +184,129 @@ public class CircuitComponent extends JComponent {
@Override
public void mousePressed(MouseEvent e) {
lastPos = new Vector(e.getX(), e.getY());
Vector pos = new Vector(e.getX(), e.getY());
for (VisualPart vp : circuit.getParts())
if (vp.matches(lastPos)) {
if (vp.matches(pos)) {
partToDrag = vp;
delta = partToDrag.getPos().sub(pos);
break;
}
}
@Override
public void mouseReleased(MouseEvent e) {
partToDrag.setPos(raster(partToDrag.getPos()));
repaint();
partToDrag = null;
if (partToDrag != null) {
partToDrag.setPos(raster(partToDrag.getPos()));
repaint();
partToDrag = null;
}
}
@Override
public void mouseEntered(MouseEvent e) {
if (autoPick && partToDrag != null) {
partToDrag.setPos(raster(new Vector(e.getX(), e.getY())));
autoPick = false;
repaint();
}
}
@Override
public void mouseExited(MouseEvent e) {
}
public void setPartToDrag(VisualPart partToDrag) {
this.partToDrag = partToDrag;
autoPick = true;
}
@Override
public void drawTo(Graphic gr) {
}
}
private class MoveMouseListener implements Mouse {
private Vector corner1;
private Vector corner2;
private ArrayList<Moveable> elementsToMove;
private Vector lastPos;
@Override
public void mouseClicked(MouseEvent e) {
reset();
repaint();
}
private void reset() {
corner1 = null;
corner2 = null;
elementsToMove = null;
}
@Override
public void mousePressed(MouseEvent e) {
if (corner1 == null) {
corner1 = new Vector(e.getX(), e.getY());
} else {
elementsToMove = circuit.getElementsMatching(Vector.min(corner1, corner2), Vector.max(corner1, corner2));
lastPos = new Vector(e.getX(), e.getY());
}
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseDragged(MouseEvent e) {
if (elementsToMove != null) {
Vector pos = new Vector(e.getX(), e.getY());
Vector delta = raster(pos.sub(lastPos));
if (delta.x != 0 || delta.y != 0) {
for (Moveable m : elementsToMove)
m.move(delta);
corner1.move(delta);
corner2.move(delta);
repaint();
lastPos = lastPos.add(delta);
}
} else {
corner2 = new Vector(e.getX(), e.getY());
repaint();
}
}
@Override
public void mouseMoved(MouseEvent e) {
}
@Override
public void drawTo(Graphic gr) {
if (corner1 != null && corner2 != null) {
Polygon p = new Polygon(true)
.add(corner1)
.add(new Vector(corner1.x, corner2.y))
.add(corner2)
.add(new Vector(corner2.x, corner1.y));
gr.drawPolygon(p, Style.THIN);
}
}
}
}

View File

@ -7,8 +7,10 @@ import java.awt.*;
*/
public class Style {
public static final Style NORMAL = new Style(2, false, Color.BLACK);
public static final Style WIRE = new Style(2, false, Color.BLUE);
public static final Style WIRE = new Style(2, true, Color.BLUE);
public static final Style FILLED = new Style(2, true, Color.BLACK);
public static final Style THIN = new Style(1, false, Color.BLACK);
;
private final int thickness;
private final boolean filled;

View File

@ -1,12 +1,14 @@
package de.neemann.digital.gui.draw.graphics;
import de.neemann.digital.gui.draw.parts.Moveable;
/**
* @author hneemann
*/
public class Vector {
public class Vector implements Moveable {
public final int x;
public final int y;
public int x;
public int y;
public Vector(int x, int y) {
this.x = x;
@ -66,4 +68,14 @@ public class Vector {
", y=" + y +
'}';
}
@Override
public void move(Vector delta) {
x += delta.x;
y += delta.y;
}
public boolean inside(Vector min, Vector max) {
return min.x <= x && x <= max.x && min.y <= y && y <= max.y;
}
}

View File

@ -1,9 +1,11 @@
package de.neemann.digital.gui.draw.parts;
import de.neemann.digital.gui.draw.graphics.Graphic;
import de.neemann.digital.gui.draw.graphics.Vector;
import de.neemann.digital.gui.draw.shapes.Drawable;
import java.util.ArrayList;
import java.util.Iterator;
/**
* @author hneemann
@ -30,7 +32,44 @@ public class Circuit implements Drawable {
visualParts.add(visualPart);
}
public void add(Wire wire) {
wires.add(wire);
}
public ArrayList<VisualPart> getParts() {
return visualParts;
}
public ArrayList<Moveable> getElementsMatching(Vector min, Vector max) {
ArrayList<Moveable> m = new ArrayList<>();
for (VisualPart vp : visualParts)
if (vp.matches(min, max))
m.add(vp);
for (Wire w : wires) {
if (w.p1.inside(min, max))
m.add(w.p1);
if (w.p2.inside(min, max))
m.add(w.p2);
}
return m;
}
public void delete(Vector min, Vector max) {
{
Iterator<VisualPart> it = visualParts.iterator();
while (it.hasNext())
if (it.next().matches(min, max))
it.remove();
}
{
Iterator<Wire> it = wires.iterator();
while (it.hasNext()) {
Wire w = it.next();
if (w.p1.inside(min, max) || w.p2.inside(min, max))
it.remove();
}
}
}
}

View File

@ -37,6 +37,15 @@ public class VisualPart implements Drawable, Moveable {
(p.y <= m.getMax().y);
}
public boolean matches(Vector min, Vector max) {
GraphicMinMax m = getMinMax();
return (min.x <= m.getMin().x) &&
(m.getMax().x <= max.x) &&
(min.y <= m.getMin().y) &&
(m.getMax().y <= max.y);
}
public int getRotate() {
return rotate;
}

View File

@ -10,8 +10,13 @@ import de.neemann.digital.gui.draw.shapes.Drawable;
*/
public class Wire implements Drawable, Moveable {
private Vector p1;
private Vector p2;
public Vector p1;
public Vector p2;
public Wire(Vector p1, Vector p2) {
this.p1 = p1;
this.p2 = p2;
}
@Override
public void drawTo(Graphic graphic) {
@ -23,4 +28,8 @@ public class Wire implements Drawable, Moveable {
p1 = p1.add(delta);
p2 = p2.add(delta);
}
public void setP2(Vector p2) {
this.p2 = p2;
}
}

View File

@ -19,9 +19,12 @@ public class GenericShape implements Shape {
private final String name;
private final int inputs;
private final int outputs;
private transient ArrayList<Pin> pins;
private final int width;
private final boolean symetric;
private boolean invert = false;
private transient ArrayList<Pin> pins;
public GenericShape(String name, int inputs) {
this(name, inputs, 1);
}
@ -30,6 +33,8 @@ public class GenericShape implements Shape {
this.name = name;
this.inputs = inputs;
this.outputs = outputs;
width = inputs == 1 && outputs == 1 ? 1 : 3;
symetric = outputs == 1;
}
public GenericShape invert(boolean invert) {
@ -43,15 +48,25 @@ public class GenericShape implements Shape {
ObservableValue[] outputValues = partDescription.create().getOutputs();
String[] inputs = partDescription.getInputNames();
pins = new ArrayList<>(inputs.length + outputs);
for (int i = 0; i < inputs.length; i++)
pins.add(new Pin(new Vector(0, i * SIZE), inputs[i], Pin.Direction.input));
int offs = symetric ? inputs.length / 2 * SIZE : 0;
for (int i = 0; i < inputs.length; i++) {
int correct = 0;
if (symetric && ((inputs.length & 1) == 0) && i >= inputs.length / 2)
correct = SIZE;
pins.add(new Pin(new Vector(0, i * SIZE + correct), inputs[i], Pin.Direction.input));
}
if (invert) {
for (int i = 0; i < outputs; i++)
pins.add(new Pin(new Vector(SIZE * 4, i * SIZE), outputValues[i].getName(), Pin.Direction.output));
pins.add(new Pin(new Vector(SIZE * (width + 1), i * SIZE + offs), outputValues[i].getName(), Pin.Direction.output));
} else {
for (int i = 0; i < outputs; i++)
pins.add(new Pin(new Vector(SIZE * 3, i * SIZE), outputValues[i].getName(), Pin.Direction.output));
pins.add(new Pin(new Vector(SIZE * width, i * SIZE + offs), outputValues[i].getName(), Pin.Direction.output));
}
}
return pins;
@ -61,15 +76,20 @@ public class GenericShape implements Shape {
public void drawTo(Graphic graphic) {
int max = Math.max(inputs, outputs);
int height = (max - 1) * SIZE + SIZE2;
if (symetric && ((inputs & 1) == 0)) height += SIZE;
graphic.drawPolygon(new Polygon(true)
.add(1, -SIZE2)
.add(SIZE * 3 - 1, -SIZE2)
.add(SIZE * 3 - 1, height)
.add(SIZE * width - 1, -SIZE2)
.add(SIZE * width - 1, height)
.add(1, height), Style.NORMAL);
if (invert) {
int offs = symetric ? inputs / 2 * SIZE : 0;
for (int i = 0; i < outputs; i++)
graphic.drawCircle(new Vector(SIZE * 3, i * SIZE - SIZE2 + 1), new Vector(SIZE * 4 - 2, i * SIZE + SIZE2 - 1), Style.NORMAL);
graphic.drawCircle(new Vector(SIZE * width, i * SIZE - SIZE2 + 1 + offs),
new Vector(SIZE * (width + 1) - 2, i * SIZE + SIZE2 - 1 + offs), Style.NORMAL);
}