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 * @author hneemann
*/ */
public class HighZException extends NodeException { public class HighZException extends RuntimeException {
public HighZException(ObservableValue... causedObservable) { public HighZException(ObservableValue... causedObservable) {
super("readOfHighZ", causedObservable); super("readOfHighZ");
} }
} }

View File

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

View File

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

View File

@ -1,5 +1,6 @@
package de.neemann.digital.gui.components; 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.*;
import de.neemann.digital.gui.draw.graphics.Polygon; import de.neemann.digital.gui.draw.graphics.Polygon;
import de.neemann.digital.gui.draw.parts.Circuit; import de.neemann.digital.gui.draw.parts.Circuit;
@ -19,7 +20,7 @@ import java.util.ArrayList;
/** /**
* @author hneemann * @author hneemann
*/ */
public class CircuitComponent extends JComponent { public class CircuitComponent extends JComponent implements Listener {
private static final String delAction = "myDelAction"; private static final String delAction = "myDelAction";
private final Circuit circuit; private final Circuit circuit;
@ -57,7 +58,7 @@ public class CircuitComponent extends JComponent {
switch (mode) { switch (mode) {
case part: case part:
listener = new PartMouseListener(); listener = new PartMouseListener();
setCursor(new Cursor(Cursor.HAND_CURSOR)); setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
break; break;
case wire: case wire:
listener = new WireMouseListener(); listener = new WireMouseListener();
@ -67,6 +68,10 @@ public class CircuitComponent extends JComponent {
listener = new SelectMouseListener(); listener = new SelectMouseListener();
setCursor(new Cursor(Cursor.MOVE_CURSOR)); setCursor(new Cursor(Cursor.MOVE_CURSOR));
break; break;
case running:
listener = new RunningMouseListener();
setCursor(new Cursor(Cursor.HAND_CURSOR));
break;
} }
addMouseMotionListener(listener); addMouseMotionListener(listener);
addMouseListener(listener); addMouseListener(listener);
@ -86,7 +91,7 @@ public class CircuitComponent extends JComponent {
g.fillRect(0, 0, getWidth(), getHeight()); g.fillRect(0, 0, getWidth(), getHeight());
GraphicSwing gr = new GraphicSwing((Graphics2D) g); GraphicSwing gr = new GraphicSwing((Graphics2D) g);
circuit.drawTo(gr); circuit.drawTo(gr, null);
listener.drawTo(gr); listener.drawTo(gr);
} }
@ -96,7 +101,12 @@ public class CircuitComponent extends JComponent {
((pos.y + GenericShape.SIZE2) / GenericShape.SIZE) * GenericShape.SIZE); ((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 { private interface Mouse extends MouseMotionListener, MouseListener {
void drawTo(Graphic gr); void drawTo(Graphic gr);
@ -156,7 +166,7 @@ public class CircuitComponent extends JComponent {
@Override @Override
public void drawTo(Graphic gr) { public void drawTo(Graphic gr) {
if (wire != null) if (wire != null)
wire.drawTo(gr); wire.drawTo(gr, null);
} }
} }
@ -232,7 +242,7 @@ public class CircuitComponent extends JComponent {
@Override @Override
public void drawTo(Graphic gr) { public void drawTo(Graphic gr) {
if (partToInsert != null) 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 class Style {
public static final Style NORMAL = new Style(2, false, Color.BLACK); 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 = 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 FILLED = new Style(2, true, Color.BLACK);
public static final Style THIN = new Style(1, false, Color.BLACK); public static final Style THIN = new Style(1, false, Color.BLACK);
;
private final int thickness; private final int thickness;
private final boolean filled; private final boolean filled;

View File

@ -1,9 +1,6 @@
package de.neemann.digital.gui.draw.model; package de.neemann.digital.gui.draw.model;
import de.neemann.digital.core.Model; import de.neemann.digital.core.*;
import de.neemann.digital.core.NodeException;
import de.neemann.digital.core.Part;
import de.neemann.digital.core.PartDescription;
import de.neemann.digital.gui.draw.parts.*; import de.neemann.digital.gui.draw.parts.*;
import java.util.ArrayList; import java.util.ArrayList;
@ -27,20 +24,21 @@ public class ModelDescription {
Part part = partDescription.create(); Part part = partDescription.create();
pins.setOutputs(part.getOutputs()); pins.setOutputs(part.getOutputs());
entries.add(new ModelEntry(part, pins, partDescription.getInputNames())); entries.add(new ModelEntry(part, pins, vp));
for (Pin p : pins) for (Pin p : pins)
netList.add(p); netList.add(p);
} }
} }
public Model create() throws PinException, NodeException { public Model create(Listener listener) throws PinException, NodeException {
for (Net n : netList) for (Net n : netList)
n.interconnect(); n.interconnect();
for (ModelEntry e : entries)
e.applyInputs();
Model m = new Model(); Model m = new Model();
for (ModelEntry e : entries)
e.applyInputs(listener, m);
for (ModelEntry e : entries) for (ModelEntry e : entries)
e.getPart().registerNodes(m); e.getPart().registerNodes(m);

View File

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

View File

@ -24,13 +24,13 @@ public class Circuit implements Drawable {
} }
@Override @Override
public void drawTo(Graphic graphic) { public void drawTo(Graphic graphic, State state) {
for (Wire w : wires) for (Wire w : wires)
w.drawTo(graphic); w.drawTo(graphic, state);
for (Vector d : dots) for (Vector d : dots)
graphic.drawCircle(d.sub(RAD), d.add(RAD), Style.WIRE); graphic.drawCircle(d.sub(RAD), d.add(RAD), Style.WIRE);
for (VisualPart p : visualParts) for (VisualPart p : visualParts)
p.drawTo(graphic); p.drawTo(graphic, state);
} }
public void add(VisualPart visualPart) { 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; 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.core.PartDescription;
import de.neemann.digital.gui.components.CircuitComponent;
import de.neemann.digital.gui.draw.graphics.*; import de.neemann.digital.gui.draw.graphics.*;
import de.neemann.digital.gui.draw.shapes.Drawable; 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 de.neemann.digital.gui.draw.shapes.Shape;
import javax.swing.*; import javax.swing.*;
@ -18,6 +22,8 @@ public class VisualPart implements Drawable, Moveable {
private transient GraphicMinMax minMax; private transient GraphicMinMax minMax;
private Vector pos; private Vector pos;
private int rotate; private int rotate;
private State state;
private Interactor interactor;
public VisualPart(PartDescription partDescription) { public VisualPart(PartDescription partDescription) {
this.partDescription = partDescription; this.partDescription = partDescription;
@ -61,10 +67,10 @@ public class VisualPart implements Drawable, Moveable {
} }
@Override @Override
public void drawTo(Graphic graphic) { public void drawTo(Graphic graphic, State state) {
Graphic gr = new GraphicTransform(graphic, createTransform()); Graphic gr = new GraphicTransform(graphic, createTransform());
Shape shape = partDescription.getShape(); Shape shape = partDescription.getShape();
shape.drawTo(gr); shape.drawTo(gr, this.state);
for (Pin p : shape.getPins(partDescription)) 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); 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() { public GraphicMinMax getMinMax() {
if (minMax == null) { if (minMax == null) {
minMax = new GraphicMinMax(); minMax = new GraphicMinMax();
drawTo(minMax); drawTo(minMax, state);
} }
return minMax; return minMax;
} }
@ -99,7 +105,7 @@ public class VisualPart implements Drawable, Moveable {
gr.fillRect(0, 0, bi.getWidth(), bi.getHeight()); gr.fillRect(0, 0, bi.getWidth(), bi.getHeight());
gr.translate(-mm.getMin().x, -mm.getMin().y); gr.translate(-mm.getMin().x, -mm.getMin().y);
GraphicSwing grs = new GraphicSwing(gr); GraphicSwing grs = new GraphicSwing(gr);
drawTo(grs); drawTo(grs, state);
return new ImageIcon(bi); return new ImageIcon(bi);
} }
@ -116,4 +122,21 @@ public class VisualPart implements Drawable, Moveable {
transformed.add(new Pin(tr.transform(p.getPos()), p)); transformed.add(new Pin(tr.transform(p.getPos()), p));
return transformed; 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 @Override
public void drawTo(Graphic graphic) { public void drawTo(Graphic graphic, State state) {
graphic.drawLine(p1, p2, Style.WIRE); graphic.drawLine(p1, p2, Style.WIRE);
} }

View File

@ -1,10 +1,17 @@
package de.neemann.digital.gui.draw.shapes; package de.neemann.digital.gui.draw.shapes;
import de.neemann.digital.gui.draw.graphics.Graphic; import de.neemann.digital.gui.draw.graphics.Graphic;
import de.neemann.digital.gui.draw.parts.State;
/** /**
* @author hneemann * @author hneemann
*/ */
public interface Drawable { 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; 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.ObservableValue;
import de.neemann.digital.core.PartDescription; import de.neemann.digital.core.PartDescription;
import de.neemann.digital.gui.draw.graphics.Graphic; 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.graphics.Vector;
import de.neemann.digital.gui.draw.parts.Pin; import de.neemann.digital.gui.draw.parts.Pin;
import de.neemann.digital.gui.draw.parts.Pins; import de.neemann.digital.gui.draw.parts.Pins;
import de.neemann.digital.gui.draw.parts.State;
/** /**
* @author hneemann * @author hneemann
@ -72,7 +75,12 @@ public class GenericShape implements Shape {
} }
@Override @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 max = Math.max(inputs, outputs);
int height = (max - 1) * SIZE + SIZE2; int height = (max - 1) * SIZE + SIZE2;

View File

@ -1,12 +1,17 @@
package de.neemann.digital.gui.draw.shapes; 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.core.PartDescription;
import de.neemann.digital.gui.components.CircuitComponent;
import de.neemann.digital.gui.draw.graphics.Graphic; import de.neemann.digital.gui.draw.graphics.Graphic;
import de.neemann.digital.gui.draw.graphics.Polygon; import de.neemann.digital.gui.draw.graphics.Polygon;
import de.neemann.digital.gui.draw.graphics.Style; import de.neemann.digital.gui.draw.graphics.Style;
import de.neemann.digital.gui.draw.graphics.Vector; import de.neemann.digital.gui.draw.graphics.Vector;
import de.neemann.digital.gui.draw.parts.Pin; import de.neemann.digital.gui.draw.parts.Pin;
import de.neemann.digital.gui.draw.parts.Pins; 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; 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 { public class InputShape implements Shape {
private final int bits; private final int bits;
private long lastValue = 0;
public InputShape(int bits) { public InputShape(int bits) {
this.bits = bits; this.bits = bits;
@ -27,7 +33,37 @@ public class InputShape implements Shape {
} }
@Override @Override
public void drawTo(Graphic graphic) { public Interactor applyStateMonitor(State state, Listener listener, Model model) {
graphic.drawPolygon(new Polygon(true).add(-SIZE * 2 - 2, -SIZE).add(-2, -SIZE).add(-2, SIZE).add(-SIZE * 2 - 2, SIZE), Style.NORMAL); 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; 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.core.PartDescription;
import de.neemann.digital.gui.draw.graphics.Graphic; import de.neemann.digital.gui.draw.graphics.Graphic;
import de.neemann.digital.gui.draw.graphics.Style; import de.neemann.digital.gui.draw.graphics.Style;
import de.neemann.digital.gui.draw.graphics.Vector; import de.neemann.digital.gui.draw.graphics.Vector;
import de.neemann.digital.gui.draw.parts.Pin; import de.neemann.digital.gui.draw.parts.Pin;
import de.neemann.digital.gui.draw.parts.Pins; import de.neemann.digital.gui.draw.parts.Pins;
import de.neemann.digital.gui.draw.parts.State;
/** /**
* @author hneemann * @author hneemann
@ -24,7 +27,28 @@ public class OutputShape implements Shape {
} }
@Override @Override
public void drawTo(Graphic graphic) { public Interactor applyStateMonitor(State state, Listener listener, Model model) {
graphic.drawCircle(new Vector(2 + SIZE * 2, -SIZE), new Vector(2, SIZE), Style.NORMAL); 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; 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.core.PartDescription;
import de.neemann.digital.gui.draw.parts.Pins; import de.neemann.digital.gui.draw.parts.Pins;
import de.neemann.digital.gui.draw.parts.State;
/** /**
* @author hneemann * @author hneemann
@ -11,9 +14,19 @@ public interface Shape extends Drawable {
/** /**
* Puts the pins name and the pins x-y-position together! * Puts the pins name and the pins x-y-position together!
* *
* @param partDescription * @param partDescription the description of the part
* @return the pins * @return the pins
*/ */
Pins getPins(PartDescription partDescription); 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 {
}