interaction is possible

This commit is contained in:
hneemann 2016-03-17 17:05:24 +01:00
parent 5b9de1b763
commit fab4d99cc8
18 changed files with 255 additions and 47 deletions

View File

@ -3,9 +3,9 @@ package de.neemann.digital.core;
/**
* @author hneemann
*/
public class HighZException extends NodeException {
public class HighZException extends RuntimeException {
public HighZException(ObservableValue... causedObservable) {
super("readOfHighZ", causedObservable);
super("readOfHighZ");
}
}

View File

@ -38,7 +38,7 @@ public class ObservableValue extends Value {
return bits;
}
public long getValue() throws NodeException {
public long getValue() {
if (highZ)
throw new HighZException(this);
return value;
@ -52,7 +52,7 @@ public class ObservableValue extends Value {
}
}
public long getValueBits() throws NodeException {
public long getValueBits() {
return getValueBits(getValue());
}

View File

@ -68,8 +68,9 @@ public class Main extends JFrame {
public void actionPerformed(ActionEvent e) {
try {
ModelDescription m = new ModelDescription(cr);
Model model = m.create();
System.out.println(model);
Model model = m.create(circuitComponent);
model.init(true);
circuitComponent.setMode(CircuitComponent.Mode.running);
} catch (Exception e1) {
new ErrorMessage("error creating model").addCause(e1).show(Main.this);
}

View File

@ -1,5 +1,6 @@
package de.neemann.digital.gui.components;
import de.neemann.digital.core.Listener;
import de.neemann.digital.gui.draw.graphics.*;
import de.neemann.digital.gui.draw.graphics.Polygon;
import de.neemann.digital.gui.draw.parts.Circuit;
@ -19,7 +20,7 @@ import java.util.ArrayList;
/**
* @author hneemann
*/
public class CircuitComponent extends JComponent {
public class CircuitComponent extends JComponent implements Listener {
private static final String delAction = "myDelAction";
private final Circuit circuit;
@ -57,7 +58,7 @@ public class CircuitComponent extends JComponent {
switch (mode) {
case part:
listener = new PartMouseListener();
setCursor(new Cursor(Cursor.HAND_CURSOR));
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
break;
case wire:
listener = new WireMouseListener();
@ -67,6 +68,10 @@ public class CircuitComponent extends JComponent {
listener = new SelectMouseListener();
setCursor(new Cursor(Cursor.MOVE_CURSOR));
break;
case running:
listener = new RunningMouseListener();
setCursor(new Cursor(Cursor.HAND_CURSOR));
break;
}
addMouseMotionListener(listener);
addMouseListener(listener);
@ -86,7 +91,7 @@ public class CircuitComponent extends JComponent {
g.fillRect(0, 0, getWidth(), getHeight());
GraphicSwing gr = new GraphicSwing((Graphics2D) g);
circuit.drawTo(gr);
circuit.drawTo(gr, null);
listener.drawTo(gr);
}
@ -96,7 +101,12 @@ public class CircuitComponent extends JComponent {
((pos.y + GenericShape.SIZE2) / GenericShape.SIZE) * GenericShape.SIZE);
}
public enum Mode {part, wire, select}
@Override
public void needsUpdate() {
repaint();
}
public enum Mode {part, wire, running, select}
private interface Mouse extends MouseMotionListener, MouseListener {
void drawTo(Graphic gr);
@ -156,7 +166,7 @@ public class CircuitComponent extends JComponent {
@Override
public void drawTo(Graphic gr) {
if (wire != null)
wire.drawTo(gr);
wire.drawTo(gr, null);
}
}
@ -232,7 +242,7 @@ public class CircuitComponent extends JComponent {
@Override
public void drawTo(Graphic gr) {
if (partToInsert != null)
partToInsert.drawTo(gr);
partToInsert.drawTo(gr, null);
}
}
@ -320,4 +330,50 @@ public class CircuitComponent extends JComponent {
}
}
private class RunningMouseListener implements Mouse {
@Override
public void drawTo(Graphic gr) {
}
@Override
public void mouseClicked(MouseEvent e) {
Vector pos = new Vector(e.getX(), e.getY());
for (VisualPart vp : circuit.getParts())
if (vp.matches(pos)) {
vp.clicked(CircuitComponent.this, pos);
}
}
@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) {
}
}
}

View File

@ -8,9 +8,9 @@ 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, true, Color.BLUE);
public static final Style WIRE_HIGH = new Style(2, true, new Color(0, 153, 255));
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,9 +1,6 @@
package de.neemann.digital.gui.draw.model;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.Part;
import de.neemann.digital.core.PartDescription;
import de.neemann.digital.core.*;
import de.neemann.digital.gui.draw.parts.*;
import java.util.ArrayList;
@ -27,20 +24,21 @@ public class ModelDescription {
Part part = partDescription.create();
pins.setOutputs(part.getOutputs());
entries.add(new ModelEntry(part, pins, partDescription.getInputNames()));
entries.add(new ModelEntry(part, pins, vp));
for (Pin p : pins)
netList.add(p);
}
}
public Model create() throws PinException, NodeException {
public Model create(Listener listener) throws PinException, NodeException {
for (Net n : netList)
n.interconnect();
for (ModelEntry e : entries)
e.applyInputs();
Model m = new Model();
for (ModelEntry e : entries)
e.applyInputs(listener, m);
for (ModelEntry e : entries)
e.getPart().registerNodes(m);

View File

@ -1,11 +1,7 @@
package de.neemann.digital.gui.draw.model;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.ObservableValue;
import de.neemann.digital.core.Part;
import de.neemann.digital.gui.draw.parts.Pin;
import de.neemann.digital.gui.draw.parts.PinException;
import de.neemann.digital.gui.draw.parts.Pins;
import de.neemann.digital.core.*;
import de.neemann.digital.gui.draw.parts.*;
import java.util.HashMap;
@ -16,18 +12,20 @@ public class ModelEntry {
private final Part part;
private final Pins pins;
private final String[] names;
private final VisualPart visualPart;
public ModelEntry(Part part, Pins pins, String[] names) {
public ModelEntry(Part part, Pins pins, VisualPart visualPart) {
this.part = part;
this.pins = pins;
this.names = names;
this.visualPart = visualPart;
this.names = visualPart.getPartDescription().getInputNames();
}
public void applyInputs() throws PinException, NodeException {
public void applyInputs(Listener listener, Model model) throws PinException, NodeException {
HashMap<String, Pin> ins = pins.getInputs();
ObservableValue[] inputs = new ObservableValue[names.length];
if (names.length > 0) {
ObservableValue[] inputs = new ObservableValue[names.length];
for (int i = 0; i < names.length; i++) {
Pin pin = ins.get(names[i]);
if (pin == null)
@ -41,6 +39,7 @@ public class ModelEntry {
}
part.setInputs(inputs);
}
visualPart.setState(new State(inputs, part.getOutputs()), listener, model);
}
public Part getPart() {

View File

@ -24,13 +24,13 @@ public class Circuit implements Drawable {
}
@Override
public void drawTo(Graphic graphic) {
public void drawTo(Graphic graphic, State state) {
for (Wire w : wires)
w.drawTo(graphic);
w.drawTo(graphic, state);
for (Vector d : dots)
graphic.drawCircle(d.sub(RAD), d.add(RAD), Style.WIRE);
for (VisualPart p : visualParts)
p.drawTo(graphic);
p.drawTo(graphic, state);
}
public void add(VisualPart visualPart) {

View File

@ -0,0 +1,24 @@
package de.neemann.digital.gui.draw.parts;
import de.neemann.digital.core.ObservableValue;
/**
* @author hneemann
*/
public class State {
private final ObservableValue[] inputs;
private final ObservableValue[] outputs;
public State(ObservableValue[] inputs, ObservableValue[] outputs) {
this.inputs = inputs;
this.outputs = outputs;
}
public ObservableValue getInput(int i) {
return inputs[i];
}
public ObservableValue getOutput(int i) {
return outputs[i];
}
}

View File

@ -1,8 +1,12 @@
package de.neemann.digital.gui.draw.parts;
import de.neemann.digital.core.Listener;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.PartDescription;
import de.neemann.digital.gui.components.CircuitComponent;
import de.neemann.digital.gui.draw.graphics.*;
import de.neemann.digital.gui.draw.shapes.Drawable;
import de.neemann.digital.gui.draw.shapes.Interactor;
import de.neemann.digital.gui.draw.shapes.Shape;
import javax.swing.*;
@ -18,6 +22,8 @@ public class VisualPart implements Drawable, Moveable {
private transient GraphicMinMax minMax;
private Vector pos;
private int rotate;
private State state;
private Interactor interactor;
public VisualPart(PartDescription partDescription) {
this.partDescription = partDescription;
@ -61,10 +67,10 @@ public class VisualPart implements Drawable, Moveable {
}
@Override
public void drawTo(Graphic graphic) {
public void drawTo(Graphic graphic, State state) {
Graphic gr = new GraphicTransform(graphic, createTransform());
Shape shape = partDescription.getShape();
shape.drawTo(gr);
shape.drawTo(gr, this.state);
for (Pin p : shape.getPins(partDescription))
gr.drawCircle(p.getPos().add(-PIN, -PIN), p.getPos().add(PIN, PIN), p.getDirection() == Pin.Direction.input ? Style.NORMAL : Style.FILLED);
}
@ -76,7 +82,7 @@ public class VisualPart implements Drawable, Moveable {
public GraphicMinMax getMinMax() {
if (minMax == null) {
minMax = new GraphicMinMax();
drawTo(minMax);
drawTo(minMax, state);
}
return minMax;
}
@ -99,7 +105,7 @@ public class VisualPart implements Drawable, Moveable {
gr.fillRect(0, 0, bi.getWidth(), bi.getHeight());
gr.translate(-mm.getMin().x, -mm.getMin().y);
GraphicSwing grs = new GraphicSwing(gr);
drawTo(grs);
drawTo(grs, state);
return new ImageIcon(bi);
}
@ -116,4 +122,21 @@ public class VisualPart implements Drawable, Moveable {
transformed.add(new Pin(tr.transform(p.getPos()), p));
return transformed;
}
/**
* Sets the state of the parts inputs and outputs
*
* @param state actual state
* @param listener
* @param model
*/
public void setState(State state, Listener listener, Model model) {
this.state = state;
interactor = partDescription.getShape().applyStateMonitor(state, listener, model);
}
public void clicked(CircuitComponent cc, Vector pos) {
if (interactor != null)
interactor.interact(cc, pos, state);
}
}

View File

@ -19,7 +19,7 @@ public class Wire implements Drawable, Moveable {
}
@Override
public void drawTo(Graphic graphic) {
public void drawTo(Graphic graphic, State state) {
graphic.drawLine(p1, p2, Style.WIRE);
}

View File

@ -1,10 +1,17 @@
package de.neemann.digital.gui.draw.shapes;
import de.neemann.digital.gui.draw.graphics.Graphic;
import de.neemann.digital.gui.draw.parts.State;
/**
* @author hneemann
*/
public interface Drawable {
void drawTo(Graphic graphic);
/**
* Draws a part depending on its state
*
* @param graphic
* @param state maybe null
*/
void drawTo(Graphic graphic, State state);
}

View File

@ -1,5 +1,7 @@
package de.neemann.digital.gui.draw.shapes;
import de.neemann.digital.core.Listener;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.ObservableValue;
import de.neemann.digital.core.PartDescription;
import de.neemann.digital.gui.draw.graphics.Graphic;
@ -8,6 +10,7 @@ import de.neemann.digital.gui.draw.graphics.Style;
import de.neemann.digital.gui.draw.graphics.Vector;
import de.neemann.digital.gui.draw.parts.Pin;
import de.neemann.digital.gui.draw.parts.Pins;
import de.neemann.digital.gui.draw.parts.State;
/**
* @author hneemann
@ -72,7 +75,12 @@ public class GenericShape implements Shape {
}
@Override
public void drawTo(Graphic graphic) {
public Interactor applyStateMonitor(State state, Listener listener, Model model) {
return null;
}
@Override
public void drawTo(Graphic graphic, State state) {
int max = Math.max(inputs, outputs);
int height = (max - 1) * SIZE + SIZE2;

View File

@ -1,12 +1,17 @@
package de.neemann.digital.gui.draw.shapes;
import de.neemann.digital.core.Listener;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.PartDescription;
import de.neemann.digital.gui.components.CircuitComponent;
import de.neemann.digital.gui.draw.graphics.Graphic;
import de.neemann.digital.gui.draw.graphics.Polygon;
import de.neemann.digital.gui.draw.graphics.Style;
import de.neemann.digital.gui.draw.graphics.Vector;
import de.neemann.digital.gui.draw.parts.Pin;
import de.neemann.digital.gui.draw.parts.Pins;
import de.neemann.digital.gui.draw.parts.State;
import static de.neemann.digital.gui.draw.shapes.OutputShape.SIZE;
@ -16,6 +21,7 @@ import static de.neemann.digital.gui.draw.shapes.OutputShape.SIZE;
public class InputShape implements Shape {
private final int bits;
private long lastValue = 0;
public InputShape(int bits) {
this.bits = bits;
@ -27,7 +33,37 @@ public class InputShape implements Shape {
}
@Override
public void drawTo(Graphic graphic) {
graphic.drawPolygon(new Polygon(true).add(-SIZE * 2 - 2, -SIZE).add(-2, -SIZE).add(-2, SIZE).add(-SIZE * 2 - 2, SIZE), Style.NORMAL);
public Interactor applyStateMonitor(State state, Listener listener, Model model) {
state.getOutput(0).addListener(new Listener() {
@Override
public void needsUpdate() {
long value = state.getOutput(0).getValue();
if (lastValue != value) {
lastValue = value;
listener.needsUpdate();
}
}
});
return new Interactor() {
@Override
public void interact(CircuitComponent cc, Vector pos, State state) {
long v = state.getOutput(0).getValue();
state.getOutput(0).setValue(1 - v);
try {
model.doStep();
} catch (NodeException e) {
e.printStackTrace();
}
}
};
}
@Override
public void drawTo(Graphic graphic, State state) {
Style style = Style.WIRE;
if (state != null && state.getOutput(0).getValue() != 0)
style = Style.WIRE_HIGH;
graphic.drawPolygon(new Polygon(true).add(-SIZE * 2 - 2, -SIZE).add(-2, -SIZE).add(-2, SIZE).add(-SIZE * 2 - 2, SIZE), style);
}
}

View File

@ -0,0 +1,12 @@
package de.neemann.digital.gui.draw.shapes;
import de.neemann.digital.gui.components.CircuitComponent;
import de.neemann.digital.gui.draw.graphics.Vector;
import de.neemann.digital.gui.draw.parts.State;
/**
* @author hneemann
*/
public interface Interactor {
void interact(CircuitComponent cc, Vector pos, State state);
}

View File

@ -1,11 +1,14 @@
package de.neemann.digital.gui.draw.shapes;
import de.neemann.digital.core.Listener;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.PartDescription;
import de.neemann.digital.gui.draw.graphics.Graphic;
import de.neemann.digital.gui.draw.graphics.Style;
import de.neemann.digital.gui.draw.graphics.Vector;
import de.neemann.digital.gui.draw.parts.Pin;
import de.neemann.digital.gui.draw.parts.Pins;
import de.neemann.digital.gui.draw.parts.State;
/**
* @author hneemann
@ -24,7 +27,28 @@ public class OutputShape implements Shape {
}
@Override
public void drawTo(Graphic graphic) {
graphic.drawCircle(new Vector(2 + SIZE * 2, -SIZE), new Vector(2, SIZE), Style.NORMAL);
public Interactor applyStateMonitor(State state, Listener listener, Model model) {
state.getInput(0).addListener(new Listener() {
public long lastValue = 0;
@Override
public void needsUpdate() {
long value = state.getInput(0).getValue();
if (lastValue != value) {
lastValue = value;
listener.needsUpdate();
}
}
});
return null;
}
@Override
public void drawTo(Graphic graphic, State state) {
Style style = Style.WIRE;
if (state != null && state.getInput(0).getValue() != 0)
style = Style.WIRE_HIGH;
graphic.drawCircle(new Vector(2 + SIZE * 2, -SIZE), new Vector(2, SIZE), style);
}
}

View File

@ -1,7 +1,10 @@
package de.neemann.digital.gui.draw.shapes;
import de.neemann.digital.core.Listener;
import de.neemann.digital.core.Model;
import de.neemann.digital.core.PartDescription;
import de.neemann.digital.gui.draw.parts.Pins;
import de.neemann.digital.gui.draw.parts.State;
/**
* @author hneemann
@ -11,9 +14,19 @@ public interface Shape extends Drawable {
/**
* Puts the pins name and the pins x-y-position together!
*
* @param partDescription
* @param partDescription the description of the part
* @return the pins
*/
Pins getPins(PartDescription partDescription);
/**
* If the look of the shape depends on an input or output state, the
* shape can register a state monitor to the state.
* If the monitor decides to update the GUI it can call listener.needsUpdate.
* Caution: Don't store state in the shape itself!
*
* @param state the state
*/
Interactor applyStateMonitor(State state, Listener listener, Model model);
}

View File

@ -0,0 +1,7 @@
package de.neemann.digital.gui.draw.shapes;
/**
* @author hneemann
*/
public interface StateMonitor {
}