LogicUICanvas now uses the new listener system; changes in clicked()
authorDaniel Kirschten <daniel.kirschten@gmx.de>
Tue, 28 May 2019 09:44:30 +0000 (11:44 +0200)
committerDaniel Kirschten <daniel.kirschten@gmx.de>
Tue, 28 May 2019 09:48:09 +0000 (11:48 +0200)
LogicUI/src/era/mi/gui/LogicUICanvas.java
LogicUI/src/era/mi/gui/LogicUIStandalone.java
LogicUI/src/era/mi/gui/examples/Playground.java
LogicUI/src/era/mi/gui/model/ViewModel.java
LogicUI/src/era/mi/gui/model/components/GUIComponent.java
LogicUI/src/era/mi/gui/model/wires/GUIWire.java

index 4e61988..da33801 100644 (file)
@@ -1,14 +1,11 @@
 package era.mi.gui;
 
-import java.util.HashSet;
-import java.util.Set;
-
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Event;
 
+import era.mi.gui.model.ViewModel;
 import era.mi.gui.model.components.GUIComponent;
-import era.mi.gui.model.wires.GUIWire;
 import era.mi.gui.model.wires.Pin;
 import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
@@ -22,49 +19,26 @@ import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas;
  */
 public class LogicUICanvas extends ZoomableCanvas
 {
-       private final Set<GUIComponent> components;
-       private final Set<GUIWire> wires;
+       private final ViewModel model;
 
-       public LogicUICanvas(Composite parent, int style)
+       public LogicUICanvas(Composite parent, int style, ViewModel model)
        {
                super(parent, style);
 
-               components = new HashSet<>();
-               wires = new HashSet<>();
+               this.model = model;
+
+               model.addComponentAddedListener(c -> redrawThreadsafe());
+               model.addWireAddedListener(c -> redrawThreadsafe());
 
                addZoomedRenderer(gc ->
                {
                        Rectangle visibleRegion = new Rectangle(offX, offY, gW / zoom, gH / zoom);
-                       components.forEach(c -> drawComponent(gc, c, visibleRegion));
+                       model.getComponents().forEach(c -> drawComponent(gc, c, visibleRegion));
                });
-               addZoomedRenderer(gc -> wires.forEach(w -> w.render(gc)));
+               addZoomedRenderer(gc -> model.getWires().forEach(w -> w.render(gc)));
                addListener(SWT.MouseDown, this::mouseDown);
        }
 
-       /**
-        * Add a component to be drawn. Returns the given component for convenience.
-        * 
-        * @author Daniel Kirschten
-        */
-       // TODO replace with model change listener
-       public <C extends GUIComponent> C addComponent(C component)
-       {
-               components.add(component);
-               return component;
-       }
-
-       /**
-        * Add a graphical wire between the given connection points of the given components. The given components have to be added and the given
-        * connection points have to be connected logically first.
-        * 
-        * @author Daniel Kirschten
-        */
-       // TODO replace with model change listener
-       public void addWire(Pin pin1, Pin pin2, Point... path)
-       {
-               wires.add(new GUIWire(this::redrawThreadsafe, pin1, pin2, path));
-       }
-
        private void drawComponent(GeneralGC gc, GUIComponent component, Rectangle visibleRegion)
        {
                component.render(gc, visibleRegion);
@@ -81,11 +55,10 @@ public class LogicUICanvas extends ZoomableCanvas
                if (e.button == 1)
                {
                        Point click = displayToWorldCoords(e.x, e.y);
-                       for (GUIComponent component : components)
-                               if (component.getBounds().contains(click))
+                       for (GUIComponent component : model.getComponents())
+                               if (component.getBounds().contains(click) && component.clicked(click.x, click.y))
                                {
-                                       if (component.clicked(click.x, click.y))
-                                               redraw();
+                                       redraw();
                                        break;
                                }
                }
index 0bc5d8a..3079b50 100644 (file)
@@ -30,7 +30,7 @@ public class LogicUIStandalone
                display = new Display();
                shell = new Shell(display);
                shell.setLayout(new FillLayout());
-               ui = new LogicUICanvas(shell, SWT.NONE);
+               ui = new LogicUICanvas(shell, SWT.NONE, model);
 
                ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
                userInput.buttonDrag = 3;
index eafa1a5..74da19c 100644 (file)
@@ -5,6 +5,7 @@ import era.mi.gui.LogicUIStandalone;
 import era.mi.gui.model.ViewModel;
 import era.mi.gui.model.components.GUIAndGate;
 import era.mi.gui.model.components.GUINotGate;
+import era.mi.gui.model.wires.GUIWire;
 
 public class Playground
 {
@@ -22,11 +23,11 @@ public class Playground
 
        public static void addComponentsAndWires(LogicUICanvas ui, ViewModel model)
        {
-               GUIAndGate andGate = ui.addComponent(new GUIAndGate(model));
+               GUIAndGate andGate = new GUIAndGate(model);
                andGate.moveTo(10, 10);
-               GUINotGate notGate = ui.addComponent(new GUINotGate(model));
+               GUINotGate notGate = new GUINotGate(model);
                notGate.moveTo(10, 40);
 
-               ui.addWire(andGate.getPins().get(0), notGate.getPins().get(1));
+               new GUIWire(model, andGate.getPins().get(0), notGate.getPins().get(1));
        }
 }
\ No newline at end of file
index 5a41d0e..4eb81e8 100644 (file)
@@ -1,6 +1,7 @@
 package era.mi.gui.model;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.function.Consumer;
 
@@ -10,7 +11,9 @@ import era.mi.gui.model.wires.GUIWire;
 public class ViewModel
 {
        private final List<GUIComponent> components;
+       private final List<GUIComponent> componentsUnmodifiable;
        private final List<GUIWire> wires;
+       private final List<GUIWire> wiresUnmodifiable;
 
        private final List<Consumer<GUIComponent>> componentAddedListeners;
        private final List<Consumer<GUIComponent>> componentRemovedListeners;
@@ -20,7 +23,9 @@ public class ViewModel
        public ViewModel()
        {
                components = new ArrayList<>();
+               componentsUnmodifiable = Collections.unmodifiableList(components);
                wires = new ArrayList<>();
+               wiresUnmodifiable = Collections.unmodifiableList(wires);
 
                componentAddedListeners = new ArrayList<>();
                componentRemovedListeners = new ArrayList<>();
@@ -32,7 +37,7 @@ public class ViewModel
         * Adds the given component to the list of components and calls all componentAddedListeners. Don't call this method from application
         * code as it is automatically called in GUIComponent::new.
         */
-       public void addComponent(GUIComponent component)
+       public void componentCreated(GUIComponent component)
        {
                if (components.contains(component))
                        throw new IllegalStateException("Don't add the same component twice!");
@@ -44,7 +49,7 @@ public class ViewModel
         * Removes the given component from the list of components and calls all componentRemovedListeners. Don't call this method from
         * application code as it is automatically called in GUIComponent::destroy.
         */
-       public void removeComponent(GUIComponent component)
+       public void componentDestroyed(GUIComponent component)
        {
                if (!components.contains(component))
                        throw new IllegalStateException("Don't remove the same component twice!");
@@ -52,6 +57,40 @@ public class ViewModel
                callComponentRemovedListeners(component);
        }
 
+       /**
+        * Adds the given component to the list of components and calls all componentAddedListeners. Don't call this method from application
+        * code as it is automatically called in GUIComponent::new.
+        */
+       public void wireCreated(GUIWire wire)
+       {
+               if (wires.contains(wire))
+                       throw new IllegalStateException("Don't add the same wire twice!");
+               wires.add(wire);
+               callWireAddedListeners(wire);
+       }
+
+       /**
+        * Removes the given component from the list of components and calls all componentRemovedListeners. Don't call this method from
+        * application code as it is automatically called in GUIComponent::destroy.
+        */
+       public void wireDestroyed(GUIWire wire)
+       {
+               if (!wires.contains(wire))
+                       throw new IllegalStateException("Don't remove the same wire twice!");
+               wires.remove(wire);
+               callWireRemovedListeners(wire);
+       }
+
+       public List<GUIComponent> getComponents()
+       {
+               return componentsUnmodifiable;
+       }
+
+       public List<GUIWire> getWires()
+       {
+               return wiresUnmodifiable;
+       }
+
        // @formatter:off
        public void addComponentAddedListener     (Consumer<GUIComponent> listener){componentAddedListeners  .add   (listener);}
        public void addComponentRemovedListener   (Consumer<GUIComponent> listener){componentRemovedListeners.add   (listener);}
index 7f4107d..cf9b23a 100644 (file)
@@ -33,6 +33,8 @@ public abstract class GUIComponent
                this.componentMovedListeners = new ArrayList<>();
                this.pinAddedListeners = new ArrayList<>();
                this.pinRemovedListeners = new ArrayList<>();
+
+               model.componentCreated(this);
        }
 
        public void moveTo(double x, double y)
@@ -50,9 +52,9 @@ public abstract class GUIComponent
                return new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height);
        }
 
-       // TODO
        /**
-        * Called when this component is clicked. Relative coordinates of the click are given. Returns true if this component has to be redrawn.
+        * Called when this component is clicked. Absolute coordinates of the click are given. Returns true if this component consumed this
+        * click.
         */
        public boolean clicked(double x, double y)
        {
index d0bd990..649ddb6 100644 (file)
@@ -3,6 +3,7 @@ package era.mi.gui.model.wires;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Color;
 
+import era.mi.gui.model.ViewModel;
 import era.mi.logic.types.Bit;
 import era.mi.logic.wires.Wire;
 import net.haspamelodica.swt.helper.gcs.GeneralGC;
@@ -16,7 +17,7 @@ public class GUIWire
 
        private Wire wire;
 
-       public GUIWire(Runnable redraw, Pin pin1, Pin pin2, Point... path)
+       public GUIWire(ViewModel model, Pin pin1, Pin pin2, Point... path)
        {
                this.path = new double[path.length * 2 + 4];
                for (int srcI = 0, dstI = 2; srcI < path.length; srcI++, dstI += 2)
@@ -32,6 +33,8 @@ public class GUIWire
                pos = pin2.getPos();
                this.path[this.path.length - 2] = pos.x;
                this.path[this.path.length - 1] = pos.y;
+
+               model.wireCreated(this);
        }
 
        public void render(GeneralGC gc)