Improved rendering:
authorDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 3 Jun 2019 13:28:27 +0000 (15:28 +0200)
committerDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 3 Jun 2019 13:35:02 +0000 (15:35 +0200)
-Splitted LogicUICanvas and LogicUIRenderer
-The ViewModel hierarchy supports redraw listeners

net.mograsim.logic.ui/src/net/mograsim/logic/ui/LogicUICanvas.java
net.mograsim.logic.ui/src/net/mograsim/logic/ui/LogicUIRenderer.java [new file with mode: 0644]
net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/ViewModel.java
net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIBitDisplay.java
net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIComponent.java
net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/components/GUIManualSwitch.java
net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/GUIWire.java
net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/Pin.java
net.mograsim.logic.ui/src/net/mograsim/logic/ui/model/wires/WireCrossPoint.java

index 3a08097..08dc4eb 100644 (file)
@@ -1,19 +1,14 @@
 package net.mograsim.logic.ui;
 
-import java.util.function.Consumer;
-
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Event;
 
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas;
 import net.mograsim.logic.ui.model.ViewModel;
 import net.mograsim.logic.ui.model.components.GUIComponent;
-import net.mograsim.logic.ui.model.wires.GUIWire;
-import net.mograsim.logic.ui.model.wires.Pin;
 
 /**
  * Simulation visualizer canvas.
@@ -22,8 +17,6 @@ import net.mograsim.logic.ui.model.wires.Pin;
  */
 public class LogicUICanvas extends ZoomableCanvas
 {
-       private static final boolean DRAW_PINS = false;
-
        private final ViewModel model;
 
        public LogicUICanvas(Composite parent, int style, ViewModel model)
@@ -32,72 +25,13 @@ public class LogicUICanvas extends ZoomableCanvas
 
                this.model = model;
 
-               Consumer<Object> redrawConsumer = o -> redrawThreadsafe();
-               Consumer<Pin> pinAddedListener = p ->
-               {
-                       p.addPinMovedListener(redrawConsumer);
-                       redrawThreadsafe();
-               };
-               Consumer<Pin> pinRemovedListener = p ->
-               {
-                       p.removePinMovedListener(redrawConsumer);
-                       redrawThreadsafe();
-               };
-               Consumer<? super GUIComponent> componentAddedListener = c ->
-               {
-                       c.addComponentLookChangedListener(redrawConsumer);
-                       c.addComponentMovedListener(redrawConsumer);
-                       c.addPinAddedListener(pinAddedListener);
-                       c.addPinRemovedListener(pinRemovedListener);
-                       redrawThreadsafe();
-               };
-               model.addComponentAddedListener(componentAddedListener);
-               model.getComponents().forEach(componentAddedListener);
-               model.addComponentRemovedListener(c ->
-               {
-                       c.removeComponentLookChangedListener(redrawConsumer);
-                       c.removeComponentMovedListener(redrawConsumer);
-                       c.removePinAddedListener(pinAddedListener);
-                       c.removePinRemovedListener(pinRemovedListener);
-                       redrawThreadsafe();
-               });
-               Consumer<? super GUIWire> wireAddedListener = w ->
-               {
-                       w.addWireLookChangedListener(redrawConsumer);
-                       redrawThreadsafe();
-               };
-               model.addWireAddedListener(wireAddedListener);
-               model.getWires().forEach(wireAddedListener);
-               model.addWireRemovedListener(w ->
-               {
-                       w.removeWireLookChangedListener(redrawConsumer);
-                       redrawThreadsafe();
-               });
+               LogicUIRenderer renderer = new LogicUIRenderer(model);
+               addZoomedRenderer(gc -> renderer.render(gc, new Rectangle(offX, offY, gW / zoom, gH / zoom)));
+               model.addRedrawListener(this::redrawThreadsafe);
 
-               addZoomedRenderer(gc ->
-               {
-                       gc.setLineWidth(.5);
-                       model.getWires().forEach(w -> w.render(gc));
-                       Rectangle visibleRegion = new Rectangle(offX, offY, gW / zoom, gH / zoom);
-                       model.getComponents().forEach(c -> drawComponent(gc, c, visibleRegion));
-               });
                addListener(SWT.MouseDown, this::mouseDown);
        }
 
-       private void drawComponent(GeneralGC gc, GUIComponent component, Rectangle visibleRegion)
-       {
-               component.render(gc, visibleRegion);
-               if (DRAW_PINS)
-               {
-                       gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_DARK_CYAN));
-                       for (Pin p : component.getPins())
-                       {
-                               Point pos = p.getPos();
-                               gc.fillOval(pos.x - 1, pos.y - 1, 2, 2);
-                       }
-               }
-       }
-
        private void mouseDown(Event e)
        {
                if (e.button == 1)
diff --git a/net.mograsim.logic.ui/src/net/mograsim/logic/ui/LogicUIRenderer.java b/net.mograsim.logic.ui/src/net/mograsim/logic/ui/LogicUIRenderer.java
new file mode 100644 (file)
index 0000000..ce20459
--- /dev/null
@@ -0,0 +1,44 @@
+package net.mograsim.logic.ui;
+
+import org.eclipse.swt.SWT;
+
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+import net.mograsim.logic.ui.model.ViewModel;
+import net.mograsim.logic.ui.model.components.GUIComponent;
+import net.mograsim.logic.ui.model.wires.Pin;
+
+public class LogicUIRenderer
+{
+       private static final boolean DRAW_PINS = false;
+
+       private final ViewModel model;
+
+       public LogicUIRenderer(ViewModel model)
+       {
+               this.model = model;
+       }
+
+       public void render(GeneralGC gc, Rectangle visibleRegion)
+       {
+               gc.setLineWidth(.5);
+               model.getWires().forEach(w -> w.render(gc));
+               model.getComponents().forEach(c -> drawComponent(gc, c, visibleRegion));
+       }
+
+       private static void drawComponent(GeneralGC gc, GUIComponent component, Rectangle visibleRegion)
+       {
+               component.render(gc, visibleRegion);
+               if (DRAW_PINS)
+               {
+                       gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_DARK_CYAN));
+                       for (Pin p : component.getPins())
+                       {
+                               Point pos = p.getPos();
+                               gc.fillOval(pos.x - 1, pos.y - 1, 2, 2);
+                       }
+               }
+       }
+
+}
\ No newline at end of file
index 717ee13..7f9b113 100644 (file)
@@ -19,6 +19,9 @@ public class ViewModel
        private final List<Consumer<? super GUIComponent>> componentRemovedListeners;
        private final List<Consumer<? super GUIWire>> wireAddedListeners;
        private final List<Consumer<? super GUIWire>> wireRemovedListeners;
+       private final List<Runnable> redrawListeners;
+
+       private final Runnable redrawListenerForSubcomponents;
 
        public ViewModel()
        {
@@ -31,6 +34,9 @@ public class ViewModel
                componentRemovedListeners = new ArrayList<>();
                wireAddedListeners = new ArrayList<>();
                wireRemovedListeners = new ArrayList<>();
+               redrawListeners = new ArrayList<>();
+
+               redrawListenerForSubcomponents = this::callRedrawListeners;
        }
 
        /**
@@ -43,6 +49,8 @@ public class ViewModel
                        throw new IllegalStateException("Don't add the same component twice!");
                components.add(component);
                callComponentAddedListeners(component);
+               component.addRedrawListener(redrawListenerForSubcomponents);
+               callRedrawListeners();
        }
 
        /**
@@ -55,6 +63,8 @@ public class ViewModel
                        throw new IllegalStateException("Don't remove the same component twice!");
                components.remove(component);
                callComponentRemovedListeners(component);
+               component.removeRedrawListener(redrawListenerForSubcomponents);
+               callRedrawListeners();
        }
 
        /**
@@ -67,6 +77,8 @@ public class ViewModel
                        throw new IllegalStateException("Don't add the same wire twice!");
                wires.add(wire);
                callWireAddedListeners(wire);
+               wire.addRedrawListener(redrawListenerForSubcomponents);
+               callRedrawListeners();
        }
 
        /**
@@ -79,6 +91,8 @@ public class ViewModel
                        throw new IllegalStateException("Don't remove the same wire twice!");
                wires.remove(wire);
                callWireRemovedListeners(wire);
+               wire.removeRedrawListener(redrawListenerForSubcomponents);
+               callRedrawListeners();
        }
 
        public List<GUIComponent> getComponents()
@@ -91,20 +105,28 @@ public class ViewModel
                return wiresUnmodifiable;
        }
 
+//     public void requestRedraw()
+//     {
+//             callRedrawListeners();
+//     }
+
        // @formatter:off
-       public void addComponentAddedListener     (Consumer<? super GUIComponent> listener){componentAddedListeners  .add   (listener);}
-       public void addComponentRemovedListener   (Consumer<? super GUIComponent> listener){componentRemovedListeners.add   (listener);}
-       public void addWireAddedListener          (Consumer<? super GUIWire     > listener){wireAddedListeners       .add   (listener);}
-       public void addWireRemovedListener        (Consumer<? super GUIWire     > listener){wireRemovedListeners     .add   (listener);}
+       public void addComponentAddedListener     (Consumer<? super GUIComponent> listener) {componentAddedListeners  .add   (listener);}
+       public void addComponentRemovedListener   (Consumer<? super GUIComponent> listener) {componentRemovedListeners.add   (listener);}
+       public void addWireAddedListener          (Consumer<? super GUIWire     > listener) {wireAddedListeners       .add   (listener);}
+       public void addWireRemovedListener        (Consumer<? super GUIWire     > listener) {wireRemovedListeners     .add   (listener);}
+       public void addRedrawListener             (Runnable                       listener) {redrawListeners          .add   (listener);}
 
-       public void removeComponentAddedListener  (Consumer<? super GUIComponent> listener){componentAddedListeners  .remove(listener);}
-       public void removeComponentRemovedListener(Consumer<? super GUIComponent> listener){componentRemovedListeners.remove(listener);}
-       public void removeWireAddedListener       (Consumer<? super GUIWire     > listener){wireAddedListeners       .remove(listener);}
-       public void removeWireRemovedListener     (Consumer<? super GUIWire     > listener){wireRemovedListeners     .remove(listener);}
+       public void removeComponentAddedListener  (Consumer<? super GUIComponent> listener) {componentAddedListeners  .remove(listener);}
+       public void removeComponentRemovedListener(Consumer<? super GUIComponent> listener) {componentRemovedListeners.remove(listener);}
+       public void removeWireAddedListener       (Consumer<? super GUIWire     > listener) {wireAddedListeners       .remove(listener);}
+       public void removeWireRemovedListener     (Consumer<? super GUIWire     > listener) {wireRemovedListeners     .remove(listener);}
+       public void removeRedrawListener          (Runnable                       listener) {redrawListeners          .remove(listener);}
 
        private void callComponentAddedListeners  (GUIComponent c) {componentAddedListeners  .forEach(l -> l.accept(c));}
        private void callComponentRemovedListeners(GUIComponent c) {componentRemovedListeners.forEach(l -> l.accept(c));}
        private void callWireAddedListeners       (GUIWire w     ) {wireAddedListeners       .forEach(l -> l.accept(w));}
        private void callWireRemovedListeners     (GUIWire w     ) {wireRemovedListeners     .forEach(l -> l.accept(w));}
+       private void callRedrawListeners          (              ) {redrawListeners          .forEach(l -> l.run(    ));}
        // @formatter:on
 }
\ No newline at end of file
index 4a75f54..abaec56 100644 (file)
@@ -25,7 +25,7 @@ public class GUIBitDisplay extends GUIComponent
        public GUIBitDisplay(ViewModel model)
        {
                super(model);
-               logicObs = (i) -> callComponentLookChangedListeners();
+               logicObs = (i) -> requestRedraw();
 
                setSize(width, height);
                addPin(this.inputPin = new Pin(this, 1, 0, height / 2));
index 9cea86a..ca21622 100644 (file)
@@ -17,10 +17,12 @@ public abstract class GUIComponent
        private final List<Pin> pins;
        protected final List<Pin> pinsUnmodifiable;
 
-       private final List<Consumer<? super GUIComponent>> componentLookChangedListeners;
        private final List<Consumer<? super GUIComponent>> componentMovedListeners;
        private final List<Consumer<? super Pin>> pinAddedListeners;
        private final List<Consumer<? super Pin>> pinRemovedListeners;
+       private final List<Runnable> redrawListeners;
+
+       private final Runnable redrawListenerForSubcomponents;
 
        public GUIComponent(ViewModel model)
        {
@@ -29,10 +31,12 @@ public abstract class GUIComponent
                this.pins = new ArrayList<>();
                this.pinsUnmodifiable = Collections.unmodifiableList(pins);
 
-               this.componentLookChangedListeners = new ArrayList<>();
                this.componentMovedListeners = new ArrayList<>();
                this.pinAddedListeners = new ArrayList<>();
                this.pinRemovedListeners = new ArrayList<>();
+               this.redrawListeners = new ArrayList<>();
+
+               redrawListenerForSubcomponents = this::callRedrawListeners;
 
                model.componentCreated(this);
        }
@@ -77,43 +81,52 @@ public abstract class GUIComponent
        }
 
        // @formatter:off
-       public void addComponentLookChangedListener   (Consumer<? super GUIComponent> listener) {componentLookChangedListeners.add   (listener);}
-       public void addComponentMovedListener         (Consumer<? super GUIComponent> listener) {componentMovedListeners      .add   (listener);}
-       public void addPinAddedListener               (Consumer<? super Pin         > listener) {pinAddedListeners            .add   (listener);}
-       public void addPinRemovedListener             (Consumer<? super Pin         > listener) {pinRemovedListeners          .add   (listener);}
-                                                  
-       public void removeComponentLookChangedListener(Consumer<? super GUIComponent> listener) {componentLookChangedListeners.remove(listener);}
-       public void removeComponentMovedListener      (Consumer<? super GUIComponent> listener) {componentMovedListeners      .remove(listener);}
-       public void removePinAddedListener            (Consumer<? super Pin         > listener) {pinAddedListeners            .remove(listener);}
-       public void removePinRemovedListener          (Consumer<? super Pin         > listener) {pinRemovedListeners          .remove(listener);}
-
-       protected void callComponentLookChangedListeners(     ) {componentLookChangedListeners.forEach(l -> l.accept(this));}
-       private   void callComponentMovedListeners      (     ) {componentMovedListeners      .forEach(l -> l.accept(this));}
-       private   void callPinAddedListeners            (Pin p) {pinAddedListeners            .forEach(l -> l.accept(p   ));}
-       private   void callPinRemovedListeners          (Pin p) {pinRemovedListeners          .forEach(l -> l.accept(p   ));}
-       // @form  atter:on
+       public void addComponentMovedListener   (Consumer<? super GUIComponent> listener) {componentMovedListeners.add   (listener);}
+       public void addPinAddedListener         (Consumer<? super Pin         > listener) {pinAddedListeners      .add   (listener);}
+       public void addPinRemovedListener       (Consumer<? super Pin         > listener) {pinRemovedListeners    .add   (listener);}
+       public void addRedrawListener           (Runnable                       listener) {redrawListeners        .add   (listener);}
+
+       public void removeComponentMovedListener(Consumer<? super GUIComponent> listener) {componentMovedListeners .remove(listener);}
+       public void removePinAddedListener      (Consumer<? super Pin         > listener) {pinAddedListeners       .remove(listener);}
+       public void removePinRemovedListener    (Consumer<? super Pin         > listener) {pinRemovedListeners     .remove(listener);}
+       public void removeRedrawListener        (Runnable                       listener) {redrawListeners         .remove(listener);}
+
+       private void callComponentMovedListeners(     ) {componentMovedListeners.forEach(l -> l.accept(this));}
+       private void callPinAddedListeners      (Pin p) {pinAddedListeners      .forEach(l -> l.accept(p   ));}
+       private void callPinRemovedListeners    (Pin p) {pinRemovedListeners    .forEach(l -> l.accept(p   ));}
+       private void callRedrawListeners        (     ) {redrawListeners        .forEach(l -> l.run(       ));}
+       // @formatter:on
 
        /**
         * Render this component to the given gc.
         */
        public abstract void render(GeneralGC gc, Rectangle visibleRegion);
 
+       protected void requestRedraw()
+       {
+               callRedrawListeners();
+       }
+
        protected void setSize(double width, double height)
        {
                bounds.width = width;
                bounds.height = height;
-               callComponentLookChangedListeners();
+               callRedrawListeners();
        }
 
        protected void addPin(Pin pin)
        {
                pins.add(pin);
                callPinAddedListeners(pin);
+               pin.addRedrawListener(redrawListenerForSubcomponents);
+               callRedrawListeners();
        }
 
        protected void removePin(Pin pin)
        {
                pins.remove(pin);
                callPinRemovedListeners(pin);
+               pin.removeRedrawListener(redrawListenerForSubcomponents);
+               callRedrawListeners();
        }
 }
\ No newline at end of file
index 265efa3..dbeabd2 100644 (file)
@@ -27,7 +27,7 @@ public class GUIManualSwitch extends GUIComponent
        public GUIManualSwitch(ViewModel model)
        {
                super(model);
-               logicObs = (i) -> callComponentLookChangedListeners();
+               logicObs = (i) -> requestRedraw();
 
                setSize(width, height);
                addPin(this.outputPin = new Pin(this, 1, width, height / 2));
index c6c9432..50871fe 100644 (file)
@@ -2,14 +2,15 @@ package net.mograsim.logic.ui.model.wires;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.function.Consumer;
 
-import net.mograsim.logic.ui.ColorHelper;
-import net.mograsim.logic.ui.model.ViewModel;
 import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.mograsim.logic.core.LogicObservable;
+import net.mograsim.logic.core.LogicObserver;
 import net.mograsim.logic.core.types.BitVectorFormatter;
 import net.mograsim.logic.core.wires.Wire.ReadEnd;
+import net.mograsim.logic.ui.ColorHelper;
+import net.mograsim.logic.ui.model.ViewModel;
 
 public class GUIWire
 {
@@ -19,12 +20,14 @@ public class GUIWire
        private Pin pin2;
        private double[] path;
 
-       private final List<Consumer<? super GUIWire>> wireLookChangedListeners;
+       private final List<Runnable> redrawListeners;
 
+       private final LogicObserver logicObs;
        private ReadEnd end;
 
        public GUIWire(ViewModel model, Pin pin1, Pin pin2, Point... path)
        {
+               logicObs = (i) -> callRedrawListeners();
                this.model = model;
                this.logicWidth = pin1.logicWidth;
                if (pin2.logicWidth != pin1.logicWidth)
@@ -39,7 +42,7 @@ public class GUIWire
                this.pin1 = pin1;
                this.pin2 = pin2;
 
-               wireLookChangedListeners = new ArrayList<>();
+               redrawListeners = new ArrayList<>();
 
                pin1.addPinMovedListener(p -> pin1Moved());
                pin2.addPinMovedListener(p -> pin2Moved());
@@ -54,6 +57,7 @@ public class GUIWire
                Point pos = pin1.getPos();
                this.path[0] = pos.x;
                this.path[1] = pos.y;
+               callRedrawListeners();
        }
 
        private void pin2Moved()
@@ -61,6 +65,7 @@ public class GUIWire
                Point pos = pin2.getPos();
                this.path[this.path.length - 2] = pos.x;
                this.path[this.path.length - 1] = pos.y;
+               callRedrawListeners();
        }
 
        public void destroy()
@@ -75,8 +80,21 @@ public class GUIWire
 
        public void setLogicModelBinding(ReadEnd end)
        {
+               deregisterLogicObs(this.end);
                this.end = end;
-               end.registerObserver((i) -> callWireLookChangedListeners());
+               registerLogicObs(end);
+       }
+
+       private void registerLogicObs(LogicObservable observable)
+       {
+               if (observable != null)
+                       observable.registerObserver(logicObs);
+       }
+
+       private void deregisterLogicObs(LogicObservable observable)
+       {
+               if (observable != null)
+                       observable.deregisterObserver(logicObs);
        }
 
        public Pin getPin1()
@@ -90,11 +108,11 @@ public class GUIWire
        }
 
        // @formatter:off
-       public void addWireLookChangedListener   (Consumer<? super GUIWire> listener) {wireLookChangedListeners.add   (listener);}
+       public void addRedrawListener   (Runnable listener) {redrawListeners         .add   (listener);}
 
-       public void removeWireLookChangedListener(Consumer<? super GUIWire> listener) {wireLookChangedListeners.remove(listener);}
+       public void removeRedrawListener(Runnable listener) {redrawListeners         .remove(listener);}
 
-       private void callWireLookChangedListeners() {wireLookChangedListeners.forEach(l -> l.accept(this));}
+       private void callRedrawListeners() {redrawListeners.forEach(l -> l.run());}
        // @formatter:on
 
 }
\ No newline at end of file
index 5163583..8c0333a 100644 (file)
@@ -18,6 +18,7 @@ public class Pin
        protected double relY;
 
        private final List<Consumer<? super Pin>> pinMovedListeners;
+       private final List<Runnable> redrawListeners;
 
        public Pin(GUIComponent component, int logicWidth, double relX, double relY)
        {
@@ -27,6 +28,7 @@ public class Pin
                this.relY = relY;
 
                this.pinMovedListeners = new ArrayList<>();
+               this.redrawListeners = new ArrayList<>();
 
                component.addComponentMovedListener(c -> callPinMovedListeners());
        }
@@ -52,18 +54,23 @@ public class Pin
                return new Point(relX + componentBounds.x, relY + componentBounds.y);
        }
 
+       protected void setRelPos(double relX, double relY)
+       {
+               this.relX = relX;
+               this.relY = relY;
+               callPinMovedListeners();
+               callRedrawListeners();
+       }
+
        // @formatter:off
        public void addPinMovedListener   (Consumer<? super Pin> listener){pinMovedListeners.add   (listener);}
+       public void addRedrawListener     (Runnable              listener){redrawListeners  .add   (listener);}
 
        public void removePinMovedListener(Consumer<? super Pin> listener){pinMovedListeners.remove(listener);}
+       public void removeRedrawListener  (Runnable              listener){redrawListeners  .remove(listener);}
 
        private void callPinMovedListeners() {pinMovedListeners.forEach(l -> l.accept(this));}
+       private void callRedrawListeners  () {redrawListeners  .forEach(l -> l.run   (    ));}
        // @formatter:on
 
-       protected void setRelPos(double relX, double relY)
-       {
-               this.relX = relX;
-               this.relY = relY;
-               callPinMovedListeners();
-       }
 }
\ No newline at end of file
index 927e4e5..4626280 100644 (file)
@@ -1,23 +1,28 @@
 package net.mograsim.logic.ui.model.wires;
 
-import net.mograsim.logic.ui.ColorHelper;
-import net.mograsim.logic.ui.model.ViewModel;
-import net.mograsim.logic.ui.model.components.GUIComponent;
 import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+import net.mograsim.logic.core.LogicObservable;
+import net.mograsim.logic.core.LogicObserver;
 import net.mograsim.logic.core.types.BitVectorFormatter;
 import net.mograsim.logic.core.wires.Wire.ReadEnd;
+import net.mograsim.logic.ui.ColorHelper;
+import net.mograsim.logic.ui.model.ViewModel;
+import net.mograsim.logic.ui.model.components.GUIComponent;
 
 public class WireCrossPoint extends GUIComponent
 {
        private final Pin pin;
+       private final int logicWidth;
 
+       private final LogicObserver logicObs;
        private ReadEnd end;
-       private final int logicWidth;
 
        public WireCrossPoint(ViewModel model, int logicWidth)
        {
                super(model);
+               logicObs = (i) -> requestRedraw();
+
                this.logicWidth = logicWidth;
                setSize(0, 0);
                addPin(this.pin = new Pin(this, logicWidth, 0, 0));
@@ -33,8 +38,21 @@ public class WireCrossPoint extends GUIComponent
 
        public void setLogicModelBinding(ReadEnd end)
        {
+               deregisterLogicObs(this.end);
                this.end = end;
-               end.registerObserver((i) -> callComponentLookChangedListeners());
+               registerLogicObs(end);
+       }
+
+       private void registerLogicObs(LogicObservable observable)
+       {
+               if (observable != null)
+                       observable.registerObserver(logicObs);
+       }
+
+       private void deregisterLogicObs(LogicObservable observable)
+       {
+               if (observable != null)
+                       observable.deregisterObserver(logicObs);
        }
 
        public int getLogicWidth()