a752711546c0b63f89f95d7eec71a7cf7c8d7c2c
[Mograsim.git] / LogicUI / src / era / mi / gui / LogicUICanvas.java
1 package era.mi.gui;\r
2 \r
3 import java.util.HashSet;\r
4 import java.util.Set;\r
5 \r
6 import org.eclipse.swt.SWT;\r
7 import org.eclipse.swt.widgets.Composite;\r
8 import org.eclipse.swt.widgets.Event;\r
9 \r
10 import era.mi.gui.model.components.GUIComponent;\r
11 import era.mi.gui.model.wires.GUIWire;\r
12 import era.mi.gui.model.wires.Pin;\r
13 import net.haspamelodica.swt.helper.gcs.GeneralGC;\r
14 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;\r
15 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;\r
16 import net.haspamelodica.swt.helper.zoomablecanvas.ZoomableCanvas;\r
17 \r
18 /**\r
19  * Simulation visualizer canvas.\r
20  * \r
21  * @author Daniel Kirschten\r
22  */\r
23 public class LogicUICanvas extends ZoomableCanvas\r
24 {\r
25         private final Set<GUIComponent> components;\r
26         private final Set<GUIWire> wires;\r
27 \r
28         public LogicUICanvas(Composite parent, int style)\r
29         {\r
30                 super(parent, style);\r
31 \r
32                 components = new HashSet<>();\r
33                 wires = new HashSet<>();\r
34 \r
35                 addZoomedRenderer(gc ->\r
36                 {\r
37                         Rectangle visibleRegion = new Rectangle(offX, offY, gW / zoom, gH / zoom);\r
38                         components.forEach(c -> drawComponent(gc, c, visibleRegion));\r
39                 });\r
40                 addZoomedRenderer(gc -> wires.forEach(w -> w.render(gc)));\r
41                 addListener(SWT.MouseDown, this::mouseDown);\r
42         }\r
43 \r
44         /**\r
45          * Add a component to be drawn. Returns the given component for convenience.\r
46          * \r
47          * @author Daniel Kirschten\r
48          */\r
49         // TODO replace with model change listener\r
50         public <C extends GUIComponent> C addComponent(C component)\r
51         {\r
52                 components.add(component);\r
53                 return component;\r
54         }\r
55 \r
56         /**\r
57          * Add a graphical wire between the given connection points of the given components. The given components have to be added and the given\r
58          * connection points have to be connected logically first.\r
59          * \r
60          * @author Daniel Kirschten\r
61          */\r
62         // TODO replace with model change listener\r
63         public void addWire(Pin pin1, Pin pin2, Point... path)\r
64         {\r
65                 wires.add(new GUIWire(this::redrawThreadsafe, pin1, pin2, path));\r
66         }\r
67 \r
68         private void drawComponent(GeneralGC gc, GUIComponent component, Rectangle visibleRegion)\r
69         {\r
70                 component.render(gc, visibleRegion);\r
71                 gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_CYAN));\r
72                 for (Pin p : component.getPins())\r
73                 {\r
74                         Point pos = p.getPos();\r
75                         gc.fillOval(pos.x - 1, pos.y - 1, 2, 2);\r
76                 }\r
77         }\r
78 \r
79         private void mouseDown(Event e)\r
80         {\r
81                 if (e.button == 1)\r
82                 {\r
83                         Point click = displayToWorldCoords(e.x, e.y);\r
84                         for (GUIComponent component : components)\r
85                                 if (component.getBounds().contains(click))\r
86                                 {\r
87                                         if (component.clicked(click.x, click.y))\r
88                                                 redraw();\r
89                                         break;\r
90                                 }\r
91                 }\r
92         }\r
93 }