Fixed a bug in Am2900; created dlatch8/80; relayouted some components
[Mograsim.git] / net.mograsim.logic.model / src / net / mograsim / logic / model / LogicUICanvas.java
index 609bf74..15346c6 100644 (file)
@@ -2,6 +2,9 @@ package net.mograsim.logic.model;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
 
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Color;
@@ -21,11 +24,11 @@ import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas;
 import net.mograsim.logic.core.types.Bit;
 import net.mograsim.logic.core.types.BitVector;
-import net.mograsim.logic.model.model.ViewModel;
-import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.model.LogicModel;
+import net.mograsim.logic.model.model.components.ModelComponent;
 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
 import net.mograsim.logic.model.model.components.submodels.SubmodelInterface;
-import net.mograsim.logic.model.model.wires.WireCrossPoint;
+import net.mograsim.logic.model.model.wires.ModelWireCrossPoint;
 import net.mograsim.preferences.Preferences;
 
 /**
@@ -37,23 +40,23 @@ public class LogicUICanvas extends ZoomableCanvas
 {
        private static final boolean OPEN_DEBUG_SETHIGHLEVELSTATE_SHELL = false;
 
-       private final ViewModel model;
+       private final LogicModel model;
 
-       public LogicUICanvas(Composite parent, int style, ViewModel model)
+       public LogicUICanvas(Composite parent, int style, LogicModel model)
        {
-               super(parent, style);
+               super(parent, style, Preferences.current().getBoolean("net.mograsim.logic.model.improvetext"));
 
                this.model = model;
 
                LogicUIRenderer renderer = new LogicUIRenderer(model);
                addZoomedRenderer(gc ->
                {
-                       Color background = Preferences.current().getColor("net.mograsim.logic.ui.color.background");
+                       Color background = Preferences.current().getColor("net.mograsim.logic.model.color.background");
                        if (background != null)
                                setBackground(background);// this.setBackground, not gc.setBackground to have the background fill the canvas
                        renderer.render(gc, new Rectangle(-offX / zoom, -offY / zoom, gW / zoom, gH / zoom));
                });
-               model.addRedrawListener(this::redrawThreadsafe);
+               model.setRedrawHandler(this::redrawThreadsafe);
 
                addListener(SWT.MouseDown, this::mouseDown);
 
@@ -66,7 +69,7 @@ public class LogicUICanvas extends ZoomableCanvas
                if (e.button == 1)
                {
                        Point click = canvasToWorldCoords(e.x, e.y);
-                       for (GUIComponent component : model.getComponentsByName().values())
+                       for (ModelComponent component : model.getComponentsByName().values())
                                if (component.getBounds().contains(click) && component.clicked(click.x, click.y))
                                {
                                        redraw();
@@ -75,17 +78,29 @@ public class LogicUICanvas extends ZoomableCanvas
                }
        }
 
-       private void openDebugSetHighLevelStateShell(ViewModel model)
+       private void openDebugSetHighLevelStateShell(LogicModel model)
        {
                Shell debugShell = new Shell();
                debugShell.setLayout(new GridLayout(2, false));
                new Label(debugShell, SWT.NONE).setText("Target component: ");
                Combo componentSelector = new Combo(debugShell, SWT.DROP_DOWN | SWT.READ_ONLY);
                componentSelector.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
-               List<GUIComponent> componentsByItemIndex = new ArrayList<>();
-               model.addComponentAddedListener(c -> recalculateComponentSelector(componentsByItemIndex, componentSelector, model));
-               model.addComponentRemovedListener(c -> recalculateComponentSelector(componentsByItemIndex, componentSelector, model));
-               recalculateComponentSelector(componentsByItemIndex, componentSelector, model);
+               List<ModelComponent> componentsByItemIndex = new ArrayList<>();
+               List<LogicModel> models = new ArrayList<>();
+               AtomicBoolean recalculateQueued = new AtomicBoolean();
+               AtomicReference<Consumer<? super ModelComponent>> compAdded = new AtomicReference<>();
+               AtomicReference<Consumer<? super ModelComponent>> compRemoved = new AtomicReference<>();
+               compAdded.set(c -> compsChanged(compAdded.get(), compRemoved.get(), c, models, componentsByItemIndex, componentSelector, model,
+                               recalculateQueued, true));
+               compRemoved.set(c -> compsChanged(compAdded.get(), compRemoved.get(), c, models, componentsByItemIndex, componentSelector, model,
+                               recalculateQueued, false));
+               iterateModelTree(compAdded.get(), compRemoved.get(), model, models, true);
+               debugShell.addListener(SWT.Dispose, e -> models.forEach(m ->
+               {
+                       m.removeComponentAddedListener(compAdded.get());
+                       m.removeComponentRemovedListener(compRemoved.get());
+               }));
+               queueRecalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model);
                new Label(debugShell, SWT.NONE).setText("Target state ID: ");
                Text stateIDText = new Text(debugShell, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
                stateIDText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
@@ -116,7 +131,7 @@ public class LogicUICanvas extends ZoomableCanvas
                                int componentIndex = componentSelector.getSelectionIndex();
                                if (componentIndex < 0 || componentIndex >= componentsByItemIndex.size())
                                        throw new RuntimeException("No component selected");
-                               GUIComponent target = componentsByItemIndex.get(componentIndex);
+                               ModelComponent target = componentsByItemIndex.get(componentIndex);
                                String valueString = valueText.getText();
                                Object value;
                                if (radioBit.getSelection())
@@ -154,24 +169,71 @@ public class LogicUICanvas extends ZoomableCanvas
                debugShell.open();
        }
 
-       private void recalculateComponentSelector(List<GUIComponent> componentsByItemIndex, Combo componentSelector, ViewModel model)
+       private void compsChanged(Consumer<? super ModelComponent> compAdded, Consumer<? super ModelComponent> compRemoved, ModelComponent c,
+                       List<LogicModel> models, List<ModelComponent> componentsByItemIndex, Combo componentSelector, LogicModel model,
+                       AtomicBoolean recalculateQueued, boolean add)
+       {
+               iterateSubmodelTree(compAdded, compRemoved, c, models, add);
+               queueRecalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model);
+       }
+
+       private void iterateSubmodelTree(Consumer<? super ModelComponent> compAdded, Consumer<? super ModelComponent> compRemoved,
+                       ModelComponent c, List<LogicModel> models, boolean add)
        {
+               if (c instanceof SubmodelComponent)
+                       iterateModelTree(compAdded, compRemoved, ((SubmodelComponent) c).submodel, models, add);
+       }
+
+       private void iterateModelTree(Consumer<? super ModelComponent> compAdded, Consumer<? super ModelComponent> compRemoved,
+                       LogicModel model, List<LogicModel> models, boolean add)
+       {
+               if (add ^ models.contains(model))
+               {
+                       if (add)
+                       {
+                               models.add(model);
+                               model.addComponentAddedListener(compAdded);
+                               model.addComponentRemovedListener(compRemoved);
+                       } else
+                       {
+                               models.remove(model);
+                               model.removeComponentAddedListener(compAdded);
+                               model.removeComponentRemovedListener(compRemoved);
+                       }
+                       for (ModelComponent c : model.getComponentsByName().values())
+                               iterateSubmodelTree(compAdded, compRemoved, c, models, add);
+               }
+       }
+
+       private void queueRecalculateComponentSelector(AtomicBoolean recalculateQueued, List<ModelComponent> componentsByItemIndex,
+                       Combo componentSelector, LogicModel model)
+       {
+               if (recalculateQueued.compareAndSet(false, true))
+                       getDisplay().asyncExec(() -> recalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model));
+       }
+
+       private void recalculateComponentSelector(AtomicBoolean recalculateQueued, List<ModelComponent> componentsByItemIndex,
+                       Combo componentSelector, LogicModel model)
+       {
+               recalculateQueued.set(false);
                componentsByItemIndex.clear();
                componentSelector.setItems();
                addComponentSelectorItems(componentsByItemIndex, "", componentSelector, model);
        }
 
-       private void addComponentSelectorItems(List<GUIComponent> componentsByItemIndex, String base, Combo componentSelector, ViewModel model)
+       private void addComponentSelectorItems(List<ModelComponent> componentsByItemIndex, String base, Combo componentSelector,
+                       LogicModel model)
        {
-               for (GUIComponent c : model.getComponentsByName().values())
-                       if (!(c instanceof WireCrossPoint || c instanceof SubmodelInterface))
+               model.getComponentsByName().values().stream().sorted((c1, c2) -> c1.getName().compareTo(c2.getName())).forEach(c ->
+               {
+                       if (!(c instanceof ModelWireCrossPoint || c instanceof SubmodelInterface))
                        {
-                               String item = base + c.name;
+                               String item = base + c.getName();
                                componentsByItemIndex.add(c);
                                componentSelector.add(item);
                                if (c instanceof SubmodelComponent)
                                        addComponentSelectorItems(componentsByItemIndex, item + " -> ", componentSelector, ((SubmodelComponent) c).submodel);
                        }
+               });
        }
-
 }
\ No newline at end of file