3b3c740f87544eb73a9110a15a48532cae5c5827
[Mograsim.git] / LogicUI / src / era / mi / gui / LogicUIStandalone.java
1 package era.mi.gui;
2
3 import java.util.concurrent.atomic.AtomicBoolean;
4
5 import org.eclipse.swt.SWT;
6 import org.eclipse.swt.layout.FillLayout;
7 import org.eclipse.swt.widgets.Display;
8 import org.eclipse.swt.widgets.Shell;
9
10 import era.mi.logic.timeline.Timeline;
11 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;
12 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
13
14 /**
15  * Standalone simulation visualizer.
16  * 
17  * @author Daniel Kirschten
18  */
19 public class LogicUIStandalone
20 {
21         private final Display display;
22         private final Shell shell;
23         private final LogicUICanvas ui;
24         private Timeline timeline;
25
26         public LogicUIStandalone(Timeline timeline)
27         {
28                 this.timeline = timeline;
29                 display = new Display();
30                 shell = new Shell(display);
31                 shell.setLayout(new FillLayout());
32                 ui = new LogicUICanvas(shell, SWT.NONE);
33
34                 ZoomableCanvasUserInput userInput = new ZoomableCanvasUserInput(ui);
35                 userInput.buttonDrag = 3;
36                 userInput.buttonZoom = 2;
37                 userInput.enableUserInput();
38                 new ZoomableCanvasOverlay(ui, null).enableScale();
39         }
40
41         public LogicUICanvas getLogicUICanvas()
42         {
43                 return ui;
44         }
45
46         /**
47          * Start the simulation timeline, and open the UI shell. Returns when the shell is closed.
48          */
49         public void run()
50         {
51                 AtomicBoolean running = new AtomicBoolean(true);
52                 Thread simulationThread = new Thread(() ->
53                 {
54                         while (running.get())
55                         {
56                                 // always execute to keep timeline from "hanging behind" for too long
57                                 timeline.executeUpTo(System.currentTimeMillis(), System.currentTimeMillis() + 10);
58                                 long sleepTime;
59                                 if (timeline.hasNext())
60                                         sleepTime = timeline.nextEventTime() - System.currentTimeMillis();
61                                 else
62                                         sleepTime = 10;
63                                 try
64                                 {
65                                         if (sleepTime > 0)
66                                                 Thread.sleep(sleepTime);
67                                 }
68                                 catch (InterruptedException e)
69                                 {
70                                 } // it is normal execution flow to be interrupted
71                         }
72                 });
73                 simulationThread.start();
74                 timeline.addEventAddedListener(event ->
75                 {
76                         if (event.getTiming() <= System.currentTimeMillis())
77                                 simulationThread.interrupt();
78                 });
79
80                 shell.open();
81                 while (!shell.isDisposed())
82                         if (!display.readAndDispatch())
83                                 display.sleep();
84                 running.set(false);
85                 simulationThread.interrupt();
86         }
87 }