1 package net.mograsim.logic.ui;
3 import java.util.ArrayList;
6 import org.eclipse.swt.SWT;
7 import org.eclipse.swt.graphics.Color;
8 import org.eclipse.swt.layout.GridData;
9 import org.eclipse.swt.layout.GridLayout;
10 import org.eclipse.swt.widgets.Button;
11 import org.eclipse.swt.widgets.Combo;
12 import org.eclipse.swt.widgets.Composite;
13 import org.eclipse.swt.widgets.Event;
14 import org.eclipse.swt.widgets.Label;
15 import org.eclipse.swt.widgets.Listener;
16 import org.eclipse.swt.widgets.Shell;
17 import org.eclipse.swt.widgets.Text;
19 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
20 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
21 import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas;
22 import net.mograsim.logic.core.types.Bit;
23 import net.mograsim.logic.core.types.BitVector;
24 import net.mograsim.logic.ui.model.ViewModel;
25 import net.mograsim.logic.ui.model.components.GUIComponent;
26 import net.mograsim.logic.ui.model.components.SubmodelComponent;
27 import net.mograsim.logic.ui.model.components.SubmodelInterface;
28 import net.mograsim.logic.ui.model.wires.WireCrossPoint;
29 import net.mograsim.preferences.Preferences;
32 * Simulation visualizer canvas.
34 * @author Daniel Kirschten
36 public class LogicUICanvas extends ZoomableCanvas
38 private static final boolean OPEN_DEBUG_SETHIGHLEVELSTATE_SHELL = false;
40 private final ViewModel model;
42 public LogicUICanvas(Composite parent, int style, ViewModel model)
48 LogicUIRenderer renderer = new LogicUIRenderer(model);
49 addZoomedRenderer(gc ->
51 Color background = Preferences.current().getColor("net.mograsim.logic.ui.color.background");
52 if (background != null)
53 setBackground(background);// this.setBackground, not gc.setBackground to have the background fill the canvas
54 renderer.render(gc, new Rectangle(-offX / zoom, -offY / zoom, gW / zoom, gH / zoom));
56 model.addRedrawListener(this::redrawThreadsafe);
58 addListener(SWT.MouseDown, this::mouseDown);
60 if (OPEN_DEBUG_SETHIGHLEVELSTATE_SHELL)
61 openDebugSetHighLevelStateShell(model);
64 private void mouseDown(Event e)
68 Point click = displayToWorldCoords(e.x, e.y);
69 for (GUIComponent component : model.getComponents())
70 if (component.getBounds().contains(click) && component.clicked(click.x, click.y))
78 private void openDebugSetHighLevelStateShell(ViewModel model)
80 Shell debugShell = new Shell();
81 debugShell.setLayout(new GridLayout(2, false));
82 new Label(debugShell, SWT.NONE).setText("Target component: ");
83 Combo componentSelector = new Combo(debugShell, SWT.DROP_DOWN | SWT.READ_ONLY);
84 componentSelector.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
85 List<GUIComponent> componentsByItemIndex = new ArrayList<>();
86 model.addComponentAddedListener(c -> recalculateComponentSelector(componentsByItemIndex, componentSelector, model));
87 model.addComponentRemovedListener(c -> recalculateComponentSelector(componentsByItemIndex, componentSelector, model));
88 recalculateComponentSelector(componentsByItemIndex, componentSelector, model);
89 new Label(debugShell, SWT.NONE).setText("Target state ID: ");
90 Text stateIDText = new Text(debugShell, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
91 stateIDText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
92 new Label(debugShell, SWT.NONE).setText("Value type: ");
93 Composite radioGroup = new Composite(debugShell, SWT.NONE);
94 radioGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
95 GridLayout radioGroupLayout = new GridLayout(2, false);
96 radioGroupLayout.marginHeight = 0;
97 radioGroupLayout.marginWidth = 0;
98 radioGroup.setLayout(radioGroupLayout);
99 Button radioBit = new Button(radioGroup, SWT.RADIO);
100 radioBit.setText("Single bit");
101 Button radioBitVector = new Button(radioGroup, SWT.RADIO);
102 radioBitVector.setText("Bitvector");
103 new Label(debugShell, SWT.NONE).setText("Value string representation: ");
104 Text valueText = new Text(debugShell, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
105 valueText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
106 Button send = new Button(debugShell, SWT.PUSH);
107 Text lastError = new Text(debugShell, SWT.READ_ONLY);
108 lastError.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
109 send.setText("Send!");
110 Listener sendAction = e ->
114 if (componentSelector.getSelectionIndex() >= componentsByItemIndex.size())
115 throw new RuntimeException("No valid component selected");
116 GUIComponent target = componentsByItemIndex.get(componentSelector.getSelectionIndex());
117 String valueString = valueText.getText();
119 if (radioBit.getSelection())
120 value = Bit.parse(valueString);
121 else if (radioBitVector.getSelection())
122 value = BitVector.parse(valueString);
124 throw new RuntimeException("No value type selected");
125 target.setHighLevelState(stateIDText.getText(), value);
126 lastError.setText("Success!");
130 lastError.setText(x.getMessage());
133 stateIDText.addListener(SWT.DefaultSelection, sendAction);
134 valueText.addListener(SWT.DefaultSelection, sendAction);
135 send.addListener(SWT.Selection, sendAction);
139 private void recalculateComponentSelector(List<GUIComponent> componentsByItemIndex, Combo componentSelector, ViewModel model)
141 componentsByItemIndex.clear();
142 componentSelector.setItems();
143 addComponentSelectorItems(componentsByItemIndex, "", componentSelector, model);
146 private void addComponentSelectorItems(List<GUIComponent> componentsByItemIndex, String base, Combo componentSelector, ViewModel model)
148 for (GUIComponent c : model.getComponents())
149 if (!(c instanceof WireCrossPoint || c instanceof SubmodelInterface))
151 String item = base + c.getIdentifier();
152 componentsByItemIndex.add(c);
153 componentSelector.add(item);
154 if (c instanceof SubmodelComponent)
155 addComponentSelectorItems(componentsByItemIndex, item + " -> ", componentSelector, ((SubmodelComponent) c).submodel);