Added the RenderPreference LINE_DASH_IMPROVEMENT_FACTOR
[Mograsim.git] / plugins / net.mograsim.logic.model / src / net / mograsim / logic / model / LogicUICanvas.java
index 162e002..3af6c89 100644 (file)
@@ -1,9 +1,17 @@
 package net.mograsim.logic.model;
 
+import static net.mograsim.logic.model.preferences.RenderPreferences.ACTION_BUTTON;
+import static net.mograsim.logic.model.preferences.RenderPreferences.BACKGROUND_COLOR;
+import static net.mograsim.logic.model.preferences.RenderPreferences.DEBUG_HLSSHELL_DEPTH;
+import static net.mograsim.logic.model.preferences.RenderPreferences.DEBUG_OPEN_HLSSHELL;
+import static net.mograsim.logic.model.preferences.RenderPreferences.IMPROVE_SCALING;
+import static net.mograsim.logic.model.preferences.RenderPreferences.LINE_DASH_IMPROVEMENT_FACTOR;
+
 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;
@@ -27,8 +35,8 @@ import net.mograsim.logic.core.types.BitVector;
 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.preferences.RenderPreferences;
 import net.mograsim.logic.model.snippets.highlevelstatehandlers.DefaultHighLevelStateHandler;
-import net.mograsim.preferences.Preferences;
 
 /**
  * Simulation visualizer canvas.
@@ -37,33 +45,40 @@ import net.mograsim.preferences.Preferences;
  */
 public class LogicUICanvas extends ZoomableCanvas
 {
-       private final LogicModel model;
+       protected final LogicModel model;
+       protected final RenderPreferences renderPrefs;
 
-       public LogicUICanvas(Composite parent, int style, LogicModel model)
+       public LogicUICanvas(Composite parent, int style, LogicModel model, RenderPreferences renderPrefs)
        {
-               super(parent, style, Preferences.current().getBoolean("net.mograsim.logic.model.improvetext"));
+               // TODO add a listener
+               super(parent, style, renderPrefs.getBoolean(IMPROVE_SCALING), (float) renderPrefs.getDouble(LINE_DASH_IMPROVEMENT_FACTOR));
 
+               this.renderPrefs = renderPrefs;
                this.model = model;
 
+               // TODO add listeners for the render prefs
+
+               Color background = renderPrefs.getColor(BACKGROUND_COLOR);
+               if (background != null)
+                       setBackground(background);
+
                LogicUIRenderer renderer = new LogicUIRenderer(model);
-               addZoomedRenderer(gc ->
+               addZoomedRenderer(gc -> renderer.render(gc, renderPrefs, new Rectangle(-offX / zoom, -offY / zoom, gW / zoom, gH / zoom)));
+               model.setRedrawHandler(() ->
                {
-                       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));
+                       if (!isDisposed())
+                               redrawThreadsafe();
                });
-               model.setRedrawHandler(this::redrawThreadsafe);
 
                addListener(SWT.MouseDown, this::mouseDown);
 
-               if (Preferences.current().getBoolean("net.mograsim.logic.model.debug.openhlsshell"))
-                       openDebugSetHighLevelStateShell(model);
+               if (renderPrefs.getBoolean(DEBUG_OPEN_HLSSHELL))
+                       openDebugSetHighLevelStateShell(model, renderPrefs.getInt(DEBUG_HLSSHELL_DEPTH) - 1);
        }
 
        private void mouseDown(Event e)
        {
-               if (e.button == Preferences.current().getInt("net.mograsim.logic.model.button.action"))
+               if (e.button == renderPrefs.getInt(ACTION_BUTTON))
                {
                        Point click = canvasToWorldCoords(e.x, e.y);
                        for (ModelComponent component : model.getComponentsByName().values())
@@ -75,7 +90,7 @@ public class LogicUICanvas extends ZoomableCanvas
                }
        }
 
-       private void openDebugSetHighLevelStateShell(LogicModel model)
+       private void openDebugSetHighLevelStateShell(LogicModel model, int depth)
        {
                Shell debugShell = new Shell();
                debugShell.setLayout(new GridLayout(2, false));
@@ -85,19 +100,21 @@ 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, depth, true);
+               compRemoved[0] = c -> compsChanged(compAdded[0], compRemoved[0], c, models, componentsByItemIndex, componentSelector, model,
+                               recalculateQueued, depth, 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);
+               queueRecalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model, depth);
                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));
@@ -117,8 +134,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 ->
@@ -130,14 +151,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)
@@ -149,8 +180,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()));
                        }
@@ -163,16 +195,63 @@ 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,
                        List<LogicModel> models, List<ModelComponent> componentsByItemIndex, Combo componentSelector, LogicModel model,
-                       AtomicBoolean recalculateQueued, boolean add)
+                       AtomicBoolean recalculateQueued, int depth, boolean add)
        {
                iterateSubmodelTree(compAdded, compRemoved, c, models, add);
-               queueRecalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model);
+               queueRecalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model, depth);
        }
 
        private void iterateSubmodelTree(Consumer<? super ModelComponent> compAdded, Consumer<? super ModelComponent> compRemoved,
@@ -204,20 +283,20 @@ public class LogicUICanvas extends ZoomableCanvas
        }
 
        private void queueRecalculateComponentSelector(AtomicBoolean recalculateQueued, List<ModelComponent> componentsByItemIndex,
-                       Combo componentSelector, LogicModel model)
+                       Combo componentSelector, LogicModel model, int depth)
        {
                if (recalculateQueued.compareAndSet(false, true))
-                       getDisplay().asyncExec(() -> recalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model));
+                       getDisplay().asyncExec(
+                                       () -> recalculateComponentSelector(recalculateQueued, componentsByItemIndex, componentSelector, model, depth));
        }
 
        private void recalculateComponentSelector(AtomicBoolean recalculateQueued, List<ModelComponent> componentsByItemIndex,
-                       Combo componentSelector, LogicModel model)
+                       Combo componentSelector, LogicModel model, int depth)
        {
                recalculateQueued.set(false);
                componentsByItemIndex.clear();
                componentSelector.setItems();
-               addComponentSelectorItems(componentsByItemIndex, "", componentSelector, model,
-                               Preferences.current().getInt("net.mograsim.logic.model.debug.hlsshelldepth") - 1);
+               addComponentSelectorItems(componentsByItemIndex, "", componentSelector, model, depth);
        }
 
        private void addComponentSelectorItems(List<ModelComponent> componentsByItemIndex, String base, Combo componentSelector,