import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
+import java.util.function.Consumer;
import org.eclipse.swt.SWT;
* The model this wire is a part of.
*/
private final ViewModelModifiable model;
+ /**
+ * The name of this wire. Is unique for all wires in its model.
+ */
+ public final String name;
/**
* The logical width of this wire. Is equal to the logical with of {@link #pin1} and {@link #pin2}.
*/
*/
private double[] effectivePath;
- private final List<Runnable> redrawListeners;
-
- private final Set<PathChangedListener> pathChangedListeners;
+ private final List<Consumer<GUIWire>> pathChangedListeners;
/**
* A LogicObserver calling redrawListeners. Used for logic model bindings.
// creation and destruction
/**
- * Creates a new {@link GUIWire} with automatic interpolation.
+ * Creates a new {@link GUIWire} with automatic interpolation and using the default name.
*
* @author Daniel Kirschten
*/
public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, WireCrossPoint pin2)
{
- this(model, pin1, pin2, (Point[]) null);
+ this(model, null, pin1, pin2);
}
/**
- * Creates a new {@link GUIWire} with automatic interpolation.
+ * Creates a new {@link GUIWire} with automatic interpolation and using the default name.
*
* @author Daniel Kirschten
*/
public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, Pin pin2)
{
- this(model, pin1, pin2, (Point[]) null);
+ this(model, null, pin1, pin2);
}
/**
- * Creates a new {@link GUIWire} with automatic interpolation.
+ * Creates a new {@link GUIWire} with automatic interpolation and using the default name.
*
* @author Daniel Kirschten
*/
public GUIWire(ViewModelModifiable model, Pin pin1, WireCrossPoint pin2)
{
- this(model, pin1, pin2, (Point[]) null);
+ this(model, null, pin1, pin2);
}
/**
- * Creates a new {@link GUIWire} with automatic interpolation.
+ * Creates a new {@link GUIWire} with automatic interpolation and using the default name.
*
* @author Daniel Kirschten
*/
public GUIWire(ViewModelModifiable model, Pin pin1, Pin pin2)
{
- this(model, pin1, pin2, (Point[]) null);
+ this(model, null, pin1, pin2);
}
/**
- * Creates a new {@link GUIWire} without automatic interpolation.
+ * Creates a new {@link GUIWire} without automatic interpolation and using the default name.
*
* @author Daniel Kirschten
*/
public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, WireCrossPoint pin2, Point... path)
{
- this(model, pin1.getPin(), pin2.getPin(), path);
+ this(model, null, pin1, pin2, path);
}
/**
- * Creates a new {@link GUIWire} without automatic interpolation.
+ * Creates a new {@link GUIWire} without automatic interpolation and using the default name.
*
* @author Daniel Kirschten
*/
public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, Pin pin2, Point... path)
{
- this(model, pin1.getPin(), pin2, path);
+ this(model, null, pin1, pin2, path);
}
/**
- * Creates a new {@link GUIWire} without automatic interpolation.
+ * Creates a new {@link GUIWire} without automatic interpolation and using the default name.
*
* @author Daniel Kirschten
*/
public GUIWire(ViewModelModifiable model, Pin pin1, WireCrossPoint pin2, Point... path)
{
- this(model, pin1, pin2.getPin(), path);
+ this(model, null, pin1, pin2, path);
}
/**
- * Creates a new {@link GUIWire} without automatic interpolation.
+ * Creates a new {@link GUIWire} without automatic interpolation and using the default name.
*
* @author Daniel Kirschten
*/
public GUIWire(ViewModelModifiable model, Pin pin1, Pin pin2, Point... path)
{
- pathChangedListeners = new HashSet<>();
- logicObs = (i) -> callRedrawListeners();
+ this(model, null, pin1, pin2, path);
+ }
+
+ /**
+ * Creates a new {@link GUIWire} with automatic interpolation.
+ *
+ * @author Daniel Kirschten
+ */
+ public GUIWire(ViewModelModifiable model, String name, WireCrossPoint pin1, WireCrossPoint pin2)
+ {
+ this(model, name, pin1, pin2, (Point[]) null);
+ }
+
+ /**
+ * Creates a new {@link GUIWire} with automatic interpolation.
+ *
+ * @author Daniel Kirschten
+ */
+ public GUIWire(ViewModelModifiable model, String name, WireCrossPoint pin1, Pin pin2)
+ {
+ this(model, name, pin1, pin2, (Point[]) null);
+ }
+
+ /**
+ * Creates a new {@link GUIWire} with automatic interpolation.
+ *
+ * @author Daniel Kirschten
+ */
+ public GUIWire(ViewModelModifiable model, String name, Pin pin1, WireCrossPoint pin2)
+ {
+ this(model, name, pin1, pin2, (Point[]) null);
+ }
+
+ /**
+ * Creates a new {@link GUIWire} with automatic interpolation.
+ *
+ * @author Daniel Kirschten
+ */
+ public GUIWire(ViewModelModifiable model, String name, Pin pin1, Pin pin2)
+ {
+ this(model, name, pin1, pin2, (Point[]) null);
+ }
+
+ /**
+ * Creates a new {@link GUIWire} without automatic interpolation.
+ *
+ * @author Daniel Kirschten
+ */
+ public GUIWire(ViewModelModifiable model, String name, WireCrossPoint pin1, WireCrossPoint pin2, Point... path)
+ {
+ this(model, name, pin1.getPin(), pin2.getPin(), path);
+ }
+
+ /**
+ * Creates a new {@link GUIWire} without automatic interpolation.
+ *
+ * @author Daniel Kirschten
+ */
+ public GUIWire(ViewModelModifiable model, String name, WireCrossPoint pin1, Pin pin2, Point... path)
+ {
+ this(model, name, pin1.getPin(), pin2, path);
+ }
+
+ /**
+ * Creates a new {@link GUIWire} without automatic interpolation.
+ *
+ * @author Daniel Kirschten
+ */
+ public GUIWire(ViewModelModifiable model, String name, Pin pin1, WireCrossPoint pin2, Point... path)
+ {
+ this(model, name, pin1, pin2.getPin(), path);
+ }
+
+ /**
+ * Creates a new {@link GUIWire} without automatic interpolation.
+ *
+ * @author Daniel Kirschten
+ */
+ public GUIWire(ViewModelModifiable model, String name, Pin pin1, Pin pin2, Point... path)
+ {
this.model = model;
+ this.name = name == null ? model.getDefaultWireName() : name;
this.logicWidth = pin1.logicWidth;
if (pin2.logicWidth != pin1.logicWidth)
throw new IllegalArgumentException("Can't connect pins of different logic width");
this.path = path == null ? null : Arrays.copyOf(path, path.length);
this.bounds = new Rectangle(0, 0, -1, -1);
- redrawListeners = new ArrayList<>();
+ pathChangedListeners = new ArrayList<>();
+
+ logicObs = (i) -> model.requestRedraw();
pin1.addPinMovedListener(p -> pinMoved());
pin2.addPinMovedListener(p -> pinMoved());
private void pinMoved()
{
recalculateEffectivePath();
- callRedrawListeners();
+ model.requestRedraw();
}
// "graphical" operations
*/
public void render(GeneralGC gc)
{
+ // TODO maybe make wires with logicWidth!=1 thicker? Maybe make thickness selectable?
ColorDefinition wireColor = BitVectorFormatter.formatAsColor(end);
if (wireColor != null)
gc.setForeground(ColorManager.current().toColor(wireColor));
gc.drawPolyline(effectivePath);
}
+ // operations concerning the path
+
/**
* The user-defined path between {@link #pin1} and {@link #pin2}. Note that this is not neccessarily equal to the effective path drawn
* in {@link #render(GeneralGC)}.<br>
*/
public Point[] getPath()
{
- return path == null ? null : path.clone();
+ return deepPathCopy(path);
+ }
+
+ public void setPath(Point... path)
+ {
+ this.path = deepPathCopy(path);
+ recalculateEffectivePath();
+ callPathChangedListeners();
+ model.requestRedraw();
+ }
+
+ public Point getPathPoint(int index)
+ {
+ return pointCopy(path[index]);
+ }
+
+ public void setPathPoint(Point p, int index)
+ {
+ path[index] = pointCopy(p);
+ recalculateEffectivePath();
+ callPathChangedListeners();
+ model.requestRedraw();
+ }
+
+ public void insertPathPoint(Point p, int index)
+ {
+ if (path == null)
+ path = new Point[] { pointCopy(p) };
+ else
+ {
+ Point[] oldPath = path;
+ path = new Point[oldPath.length + 1];
+ System.arraycopy(oldPath, 0, path, 0, index);
+ if (index < oldPath.length)
+ System.arraycopy(oldPath, index, path, index + 1, oldPath.length - index);
+ path[index] = pointCopy(p);
+ }
+ recalculateEffectivePath();
+ callPathChangedListeners();
+ }
+
+ public void removePathPoint(int index)
+ {
+ if (path.length == 0)
+ path = null;
+ else
+ {
+ Point[] oldPath = path;
+ path = new Point[oldPath.length - 1];
+ System.arraycopy(oldPath, 0, path, 0, index);
+ if (index < oldPath.length - 1)
+ System.arraycopy(oldPath, index + 1, path, index, oldPath.length - index - 1);
+ }
+ recalculateEffectivePath();
+ callPathChangedListeners();
+ }
+
+ public double[] getEffectivePath()
+ {
+ return Arrays.copyOf(effectivePath, effectivePath.length);
+ }
+
+ private static Point[] deepPathCopy(Point[] path)
+ {
+ if (path == null)
+ return null;
+ Point[] copy = new Point[path.length];
+ for (int i = 0; i < path.length; i++)
+ copy[i] = pointCopy(path[i]);
+ return copy;
+ }
+
+ private static Point pointCopy(Point p)
+ {
+ return new Point(p.x, p.y);
}
// logic model binding
// listeners
// @formatter:off
- public void addRedrawListener (Runnable listener) {redrawListeners .add (listener);}
-
- public void removeRedrawListener(Runnable listener) {redrawListeners .remove(listener);}
-
- private void callRedrawListeners() {redrawListeners.forEach(l -> l.run());}
-
- public void addPathChangedListener(PathChangedListener l) { pathChangedListeners.add(l); }
+ public void addPathChangedListener (Consumer<GUIWire> listener) {pathChangedListeners.add (listener);}
- public void removePathChangedListener(PathChangedListener l) { pathChangedListeners.remove(l); }
+ public void removePathChangedListener(Consumer<GUIWire> listener) {pathChangedListeners.remove(listener);}
- public void callPathChangedListeners(int diff) { pathChangedListeners.forEach(l -> l.pathChanged(this, diff)); }
-
- @FunctionalInterface
- public static interface PathChangedListener
- {
- /**
- * Called whenever the {@link Wire}'s path changes
- *
- * @param wire The wire which had its path changed
- * @param diff The length difference between before and after the path change.
- */
- public void pathChanged(GUIWire wire, int diff);
- }
+ private void callPathChangedListeners() {pathChangedListeners.forEach(l -> l.accept(this));}
// @formatter:on
@Override
{
return "GUIWire [" + pin1 + "---" + pin2 + ", value=" + (end == null ? "null" : end.getValues()) + "]";
}
-
- public void setPath(Point[] path)
- {
- int diff = (path == null ? 0 : path.length) - (this.path == null ? 0 : this.path.length);
- this.path = path == null ? null : path.clone();
- recalculateEffectivePath();
- callPathChangedListeners(diff);
- callRedrawListeners();
- }
-
- public void setPathPoint(Point p, int index)
- {
- path[index] = p;
- recalculateEffectivePath();
- callPathChangedListeners(0);
- callRedrawListeners();
- }
-
- public void insertPathPoint(Point p, int index)
- {
- Point[] path = getPath();
- if (path == null)
- setPath(new Point[] { p });
- else
- {
- Point[] newPath = new Point[path.length + 1];
- System.arraycopy(path, 0, newPath, 0, index);
- if (index < path.length)
- System.arraycopy(path, index, newPath, index + 1, path.length - index);
- newPath[index] = p;
- setPath(newPath);
- }
- }
-
- public void removePathPoint(int index)
- {
- Point[] path = getPath();
- Point[] newPath = new Point[path.length - 1];
- System.arraycopy(path, 0, newPath, 0, index);
- if (index < path.length - 1)
- System.arraycopy(path, index + 1, newPath, index, path.length - index - 1);
- setPath(newPath);
- }
-
- /**
- * @throws IndexOutOfBoundsException
- */
- public Point getPathPoint(int index)
- {
- return path[index];
- }
-
- public int getPathLength()
- {
- return path.length;
- }
-
- public double[] getEffectivePath()
- {
- return effectivePath.clone();
- }
}
\ No newline at end of file