Some work on improving BitVector<->String conversions
[Mograsim.git] / plugins / net.mograsim.logic.model / src / net / mograsim / logic / model / LogicUICanvas.java
index c4a8c2d..9675167 100644 (file)
@@ -1,9 +1,10 @@
 package net.mograsim.logic.model;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
 
 import org.eclipse.swt.SWT;
@@ -24,11 +25,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.core.types.BitVectorFormatter;
 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.ModelWireCrossPoint;
+import net.mograsim.logic.model.snippets.highlevelstatehandlers.DefaultHighLevelStateHandler;
 import net.mograsim.preferences.Preferences;
 
 /**
@@ -54,7 +55,11 @@ public class LogicUICanvas extends ZoomableCanvas
                                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.setRedrawHandler(this::redrawThreadsafe);
+               model.setRedrawHandler(() ->
+               {
+                       if (!isDisposed())
+                               redrawThreadsafe();
+               });
 
                addListener(SWT.MouseDown, this::mouseDown);
 
@@ -64,7 +69,7 @@ public class LogicUICanvas extends ZoomableCanvas
 
        private void mouseDown(Event e)
        {
-               if (e.button == 1)
+               if (e.button == Preferences.current().getInt("net.mograsim.logic.model.button.action"))
                {
                        Point click = canvasToWorldCoords(e.x, e.y);
                        for (ModelComponent component : model.getComponentsByName().values())
@@ -86,17 +91,19 @@ public class LogicUICanvas extends ZoomableCanvas
                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);
+               @SuppressWarnings("unchecked")
+               Consumer<? super ModelComponent>[] compAdded = new Consumer[1];
+               @SuppressWarnings("unchecked")
+               Consumer<? super ModelComponent>[] compRemoved = new Consumer[1];
+               compAdded[0] = c -> compsChanged(compAdded[0], compRemoved[0], c, models, componentsByItemIndex, componentSelector, model,
+                               recalculateQueued, true);
+               compRemoved[0] = c -> compsChanged(compAdded[0], compRemoved[0], c, models, componentsByItemIndex, componentSelector, model,
+                               recalculateQueued, false);
+               iterateModelTree(compAdded[0], compRemoved[0], model, models, true);
                debugShell.addListener(SWT.Dispose, e -> models.forEach(m ->
                {
-                       m.removeComponentAddedListener(compAdded.get());
-                       m.removeComponentRemovedListener(compRemoved.get());
+                       m.removeComponentAddedListener(compAdded[0]);
+                       m.removeComponentRemovedListener(compRemoved[0]);
                }));
                queueRecalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model);
                new Label(debugShell, SWT.NONE).setText("Target state ID: ");
@@ -118,8 +125,12 @@ public class LogicUICanvas extends ZoomableCanvas
                valueText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
                Button send = new Button(debugShell, SWT.PUSH);
                send.setText("Send!");
+               Button addListener = new Button(debugShell, SWT.PUSH);
+               addListener.setText("Add sysout listener");
                Button get = new Button(debugShell, SWT.PUSH);
                get.setText("Get!");
+               Button removeListener = new Button(debugShell, SWT.PUSH);
+               removeListener.setText("Remove sysout listener");
                Text output = new Text(debugShell, SWT.READ_ONLY);
                output.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
                Listener sendAction = e ->
@@ -131,14 +142,24 @@ public class LogicUICanvas extends ZoomableCanvas
                                        throw new RuntimeException("No component selected");
                                ModelComponent target = componentsByItemIndex.get(componentIndex);
                                String valueString = valueText.getText();
+                               String stateID = stateIDText.getText();
                                Object value;
                                if (radioBit.getSelection())
                                        value = Bit.parse(valueString);
                                else if (radioBitVector.getSelection())
-                                       value = BitVector.parse(valueString);
-                               else
+                               {
+                                       Object hls = target.getHighLevelState(stateID);
+                                       int width;
+                                       if (hls instanceof Bit)
+                                               width = 1;
+                                       else if (hls instanceof BitVector)
+                                               width = ((BitVector) hls).length();
+                                       else
+                                               width = -1;
+                                       value = BitVectorFormatter.parseUserBitVector(valueString, width);
+                               } else
                                        throw new RuntimeException("No value type selected");
-                               target.setHighLevelState(stateIDText.getText(), value);
+                               target.setHighLevelState(stateID, value);
                                output.setText("Success!");
                        }
                        catch (Exception x)
@@ -150,8 +171,9 @@ public class LogicUICanvas extends ZoomableCanvas
                {
                        try
                        {
-                               if (componentSelector.getSelectionIndex() >= componentsByItemIndex.size())
-                                       throw new RuntimeException("No valid component selected");
+                               int componentIndex = componentSelector.getSelectionIndex();
+                               if (componentIndex < 0 || componentIndex >= componentsByItemIndex.size())
+                                       throw new RuntimeException("No component selected");
                                output.setText("Success! Value: \r\n"
                                                + componentsByItemIndex.get(componentSelector.getSelectionIndex()).getHighLevelState(stateIDText.getText()));
                        }
@@ -164,7 +186,55 @@ public class LogicUICanvas extends ZoomableCanvas
                valueText.addListener(SWT.DefaultSelection, sendAction);
                get.addListener(SWT.Selection, getAction);
                stateIDText.addListener(SWT.DefaultSelection, getAction);
+               Map<ModelComponent, Map<String, Consumer<Object>>> sysoutListenersPerHLSPerTarget = new HashMap<>();
+               addListener.addListener(SWT.Selection, e ->
+               {
+                       try
+                       {
+                               int componentIndex = componentSelector.getSelectionIndex();
+                               if (componentIndex < 0 || componentIndex >= componentsByItemIndex.size())
+                                       throw new RuntimeException("No component selected");
+                               ModelComponent target = componentsByItemIndex.get(componentIndex);
+                               Map<String, Consumer<Object>> sysoutListenersPerHLS = sysoutListenersPerHLSPerTarget.computeIfAbsent(target,
+                                               k -> new HashMap<>());
+                               String stateIDString = stateIDText.getText();
+                               if (sysoutListenersPerHLS.containsKey(stateIDString))
+                                       throw new RuntimeException("Listener already registered");
+                               Consumer<Object> sysoutListener = v -> System.out.println(stateIDString + ": " + v);
+                               target.addHighLevelStateListener(stateIDString, sysoutListener);
+                               sysoutListenersPerHLS.put(stateIDString, sysoutListener);
+                               output.setText("Success!");
+                       }
+                       catch (Exception x)
+                       {
+                               output.setText(x.getClass().getSimpleName() + (x.getMessage() == null ? "" : ": " + x.getMessage()));
+                       }
+               });
+               removeListener.addListener(SWT.Selection, e ->
+               {
+                       try
+                       {
+                               int componentIndex = componentSelector.getSelectionIndex();
+                               if (componentIndex < 0 || componentIndex >= componentsByItemIndex.size())
+                                       throw new RuntimeException("No component selected");
+                               ModelComponent target = componentsByItemIndex.get(componentIndex);
+                               Map<String, Consumer<Object>> sysoutListenersPerHLS = sysoutListenersPerHLSPerTarget.get(target);
+                               if (sysoutListenersPerHLS == null)
+                                       throw new RuntimeException("Listener not registered");
+                               String stateIDString = stateIDText.getText();
+                               Consumer<Object> sysoutListener = sysoutListenersPerHLS.remove(stateIDString);
+                               if (sysoutListener == null)
+                                       throw new RuntimeException("Listener not registered");
+                               target.removeHighLevelStateListener(stateIDString, sysoutListener);
+                               output.setText("Success!");
+                       }
+                       catch (Exception x)
+                       {
+                               output.setText(x.getClass().getSimpleName() + (x.getMessage() == null ? "" : ": " + x.getMessage()));
+                       }
+               });
                debugShell.open();
+               addDisposeListener(e -> debugShell.dispose());
        }
 
        private void compsChanged(Consumer<? super ModelComponent> compAdded, Consumer<? super ModelComponent> compRemoved, ModelComponent c,
@@ -216,21 +286,24 @@ public class LogicUICanvas extends ZoomableCanvas
                recalculateQueued.set(false);
                componentsByItemIndex.clear();
                componentSelector.setItems();
-               addComponentSelectorItems(componentsByItemIndex, "", componentSelector, model);
+               addComponentSelectorItems(componentsByItemIndex, "", componentSelector, model,
+                               Preferences.current().getInt("net.mograsim.logic.model.debug.hlsshelldepth") - 1);
        }
 
        private void addComponentSelectorItems(List<ModelComponent> componentsByItemIndex, String base, Combo componentSelector,
-                       LogicModel model)
+                       LogicModel model, int depth)
        {
                model.getComponentsByName().values().stream().sorted((c1, c2) -> c1.getName().compareTo(c2.getName())).forEach(c ->
                {
-                       if (!(c instanceof ModelWireCrossPoint || c instanceof SubmodelInterface))
+                       if (!(c.getHighLevelStateHandler() instanceof DefaultHighLevelStateHandler))
                        {
                                String item = base + c.getName();
                                componentsByItemIndex.add(c);
                                componentSelector.add(item);
-                               if (c instanceof SubmodelComponent)
-                                       addComponentSelectorItems(componentsByItemIndex, item + " -> ", componentSelector, ((SubmodelComponent) c).submodel);
+                               // this causes negative numbers to result in infinite depth
+                               if (depth != 0 && c instanceof SubmodelComponent)
+                                       addComponentSelectorItems(componentsByItemIndex, item + " -> ", componentSelector, ((SubmodelComponent) c).submodel,
+                                                       depth - 1);
                        }
                });
        }