import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import org.eclipse.swt.SWT;
import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
import net.mograsim.logic.core.LogicObserver;
+import net.mograsim.logic.core.types.BitVector;
import net.mograsim.logic.core.types.BitVectorFormatter;
+import net.mograsim.logic.core.wires.Wire;
import net.mograsim.logic.core.wires.Wire.ReadEnd;
-import net.mograsim.logic.ui.ColorHelper;
import net.mograsim.logic.ui.model.ViewModelModifiable;
+import net.mograsim.preferences.ColorDefinition;
+import net.mograsim.preferences.ColorManager;
/**
* A wire connecting exactly two {@link Pin}s.
*/
public class GUIWire
{
+
+ private final Set<PathChangedListener> pathChangedListeners;
+
/**
* The model this wire is a part of.
*/
/**
* The effective path of this wire, including automatic interpolation and the position of both {@link Pin}s. Is never null.
*/
- private double[] effectivePath;
+ protected double[] effectivePath;
private final List<Runnable> redrawListeners;
*
* @author Daniel Kirschten
*/
- public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, WireCrossPoint pin2)
- {
- this(model, pin1, pin2, (Point[]) null);
- }
-
- /**
- * Creates a new {@link GUIWire} with automatic interpolation.
- *
- * @author Daniel Kirschten
- */
- public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, Pin pin2)
- {
- this(model, pin1, pin2, (Point[]) null);
- }
-
- /**
- * Creates a new {@link GUIWire} with automatic interpolation.
- *
- * @author Daniel Kirschten
- */
- public GUIWire(ViewModelModifiable model, Pin pin1, WireCrossPoint pin2)
- {
- this(model, pin1, pin2, (Point[]) null);
- }
-
- /**
- * Creates a new {@link GUIWire} with automatic interpolation.
- *
- * @author Daniel Kirschten
- */
- public GUIWire(ViewModelModifiable model, Pin pin1, Pin pin2)
+ public GUIWire(ViewModelModifiable model, ConnectionPoint pin1, ConnectionPoint pin2)
{
this(model, pin1, pin2, (Point[]) null);
}
*
* @author Daniel Kirschten
*/
- public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, WireCrossPoint pin2, Point... path)
+ public GUIWire(ViewModelModifiable model, ConnectionPoint pin1, ConnectionPoint pin2, Point... path)
{
this(model, pin1.getPin(), pin2.getPin(), path);
}
*
* @author Daniel Kirschten
*/
- public GUIWire(ViewModelModifiable model, WireCrossPoint pin1, Pin pin2, Point... path)
- {
- this(model, pin1.getPin(), pin2, path);
- }
-
- /**
- * Creates a new {@link GUIWire} without automatic interpolation.
- *
- * @author Daniel Kirschten
- */
- public GUIWire(ViewModelModifiable model, Pin pin1, WireCrossPoint pin2, Point... path)
- {
- this(model, pin1, pin2.getPin(), path);
- }
-
- /**
- * Creates a new {@link GUIWire} without automatic interpolation.
- *
- * @author Daniel Kirschten
- */
- public GUIWire(ViewModelModifiable model, Pin pin1, Pin pin2, Point... path)
+ GUIWire(ViewModelModifiable model, Pin pin1, Pin pin2, Point... path)
{
+ pathChangedListeners = new HashSet<>();
logicObs = (i) -> callRedrawListeners();
this.model = model;
this.logicWidth = pin1.logicWidth;
*/
public void render(GeneralGC gc)
{
- ColorHelper.executeWithDifferentForeground(gc, BitVectorFormatter.formatAsColor(end), () -> gc.drawPolyline(effectivePath));
+ ColorDefinition wireColor = BitVectorFormatter.formatAsColor(end);
+ if (wireColor != null)
+ gc.setForeground(ColorManager.current().toColor(wireColor));
+ gc.drawPolyline(effectivePath);
}
/**
end.registerObserver(logicObs);
}
+ /**
+ * Returns whether this {@link GUIWire} has a logic model binding or not.
+ *
+ * @author Daniel Kirschten
+ */
+ public boolean hasLogicModelBinding()
+ {
+ return end != null;
+ }
+
+ /**
+ * If this {@link GUIWire} has a logic model binding, delegates to {@link Wire#forceValues(BitVector)} for the {@link Wire}
+ * corresponding to this {@link GUIWire}.
+ *
+ * @author Daniel Kirschten
+ */
+ public void forceWireValues(BitVector values)
+ {
+ end.getWire().forceValues(values);
+ }
+
+ /**
+ * If this {@link GUIWire} has a logic model binding, delegates to {@link ReadEnd#getValues()} for the {@link ReadEnd} corresponding to
+ * this {@link GUIWire}.
+ *
+ * @author Daniel Kirschten
+ */
+ public BitVector getWireValues()
+ {
+ return end.getValues();
+ }
+
// listeners
// @formatter:off
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 removePathChangedListener(PathChangedListener l) { pathChangedListeners.remove(l); }
+
+ 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);
+ }
// @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