Updated to new SWTHelper version
[Mograsim.git] / net.mograsim.logic.ui / src / net / mograsim / logic / ui / LogicUICanvas.java
1 package net.mograsim.logic.ui;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
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;
18
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.submodels.SubmodelComponent;
27 import net.mograsim.logic.ui.model.components.submodels.SubmodelInterface;
28 import net.mograsim.logic.ui.model.wires.WireCrossPoint;
29 import net.mograsim.preferences.Preferences;
30
31 /**
32  * Simulation visualizer canvas.
33  * 
34  * @author Daniel Kirschten
35  */
36 public class LogicUICanvas extends ZoomableCanvas
37 {
38         private static final boolean OPEN_DEBUG_SETHIGHLEVELSTATE_SHELL = false;
39
40         private final ViewModel model;
41
42         public LogicUICanvas(Composite parent, int style, ViewModel model)
43         {
44                 super(parent, style);
45
46                 this.model = model;
47
48                 LogicUIRenderer renderer = new LogicUIRenderer(model);
49                 addZoomedRenderer(gc ->
50                 {
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));
55                 });
56                 model.addRedrawListener(this::redrawThreadsafe);
57
58                 addListener(SWT.MouseDown, this::mouseDown);
59
60                 if (OPEN_DEBUG_SETHIGHLEVELSTATE_SHELL)
61                         openDebugSetHighLevelStateShell(model);
62         }
63
64         private void mouseDown(Event e)
65         {
66                 if (e.button == 1)
67                 {
68                         Point click = canvasToWorldCoords(e.x, e.y);
69                         for (GUIComponent component : model.getComponentsByName().values())
70                                 if (component.getBounds().contains(click) && component.clicked(click.x, click.y))
71                                 {
72                                         redraw();
73                                         break;
74                                 }
75                 }
76         }
77
78         private void openDebugSetHighLevelStateShell(ViewModel model)
79         {
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: \n(Bit vectors: MSBit...LSBit)");
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                 send.setText("Send!");
108                 Button get = new Button(debugShell, SWT.PUSH);
109                 get.setText("Get!");
110                 Text output = new Text(debugShell, SWT.READ_ONLY);
111                 output.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
112                 Listener sendAction = e ->
113                 {
114                         try
115                         {
116                                 int componentIndex = componentSelector.getSelectionIndex();
117                                 if (componentIndex < 0 || componentIndex >= componentsByItemIndex.size())
118                                         throw new RuntimeException("No component selected");
119                                 GUIComponent target = componentsByItemIndex.get(componentIndex);
120                                 String valueString = valueText.getText();
121                                 Object value;
122                                 if (radioBit.getSelection())
123                                         value = Bit.parse(valueString);
124                                 else if (radioBitVector.getSelection())
125                                         value = BitVector.parseMSBFirst(valueString);
126                                 else
127                                         throw new RuntimeException("No value type selected");
128                                 target.setHighLevelState(stateIDText.getText(), value);
129                                 output.setText("Success!");
130                         }
131                         catch (Exception x)
132                         {
133                                 output.setText(x.getClass().getSimpleName() + (x.getMessage() == null ? "" : ": " + x.getMessage()));
134                         }
135                 };
136                 Listener getAction = e ->
137                 {
138                         try
139                         {
140                                 if (componentSelector.getSelectionIndex() >= componentsByItemIndex.size())
141                                         throw new RuntimeException("No valid component selected");
142                                 output.setText("Success! Value: \r\n"
143                                                 + componentsByItemIndex.get(componentSelector.getSelectionIndex()).getHighLevelState(stateIDText.getText()));
144                         }
145                         catch (Exception x)
146                         {
147                                 output.setText(x.getClass().getSimpleName() + (x.getMessage() == null ? "" : ": " + x.getMessage()));
148                         }
149                 };
150                 send.addListener(SWT.Selection, sendAction);
151                 valueText.addListener(SWT.DefaultSelection, sendAction);
152                 get.addListener(SWT.Selection, getAction);
153                 stateIDText.addListener(SWT.DefaultSelection, getAction);
154                 debugShell.open();
155         }
156
157         private void recalculateComponentSelector(List<GUIComponent> componentsByItemIndex, Combo componentSelector, ViewModel model)
158         {
159                 componentsByItemIndex.clear();
160                 componentSelector.setItems();
161                 addComponentSelectorItems(componentsByItemIndex, "", componentSelector, model);
162         }
163
164         private void addComponentSelectorItems(List<GUIComponent> componentsByItemIndex, String base, Combo componentSelector, ViewModel model)
165         {
166                 for (GUIComponent c : model.getComponentsByName().values())
167                         if (!(c instanceof WireCrossPoint || c instanceof SubmodelInterface))
168                         {
169                                 String item = base + c.name;
170                                 componentsByItemIndex.add(c);
171                                 componentSelector.add(item);
172                                 if (c instanceof SubmodelComponent)
173                                         addComponentSelectorItems(componentsByItemIndex, item + " -> ", componentSelector, ((SubmodelComponent) c).submodel);
174                         }
175         }
176
177 }