1 package org.opentrafficsim.swing.gui;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.Container;
6 import java.awt.Dimension;
7 import java.awt.Graphics;
8 import java.awt.event.ActionEvent;
9 import java.awt.event.ActionListener;
10 import java.awt.event.ContainerEvent;
11 import java.awt.event.ContainerListener;
12 import java.awt.event.MouseAdapter;
13 import java.awt.event.MouseEvent;
14 import java.awt.event.MouseListener;
15 import java.awt.event.MouseWheelEvent;
16 import java.awt.event.MouseWheelListener;
17 import java.awt.event.WindowEvent;
18 import java.awt.event.WindowListener;
19 import java.awt.geom.Point2D;
20 import java.awt.geom.Rectangle2D;
21 import java.rmi.RemoteException;
22 import java.text.NumberFormat;
23 import java.util.ArrayList;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.swing.BoxLayout;
29 import javax.swing.Icon;
30 import javax.swing.JButton;
31 import javax.swing.JCheckBox;
32 import javax.swing.JFrame;
33 import javax.swing.JLabel;
34 import javax.swing.JPanel;
35 import javax.swing.JToggleButton;
36 import javax.swing.border.EmptyBorder;
37
38 import org.djutils.draw.bounds.Bounds2d;
39 import org.djutils.draw.point.Point;
40 import org.djutils.draw.point.Point2d;
41 import org.djutils.event.EventInterface;
42 import org.djutils.event.EventListenerInterface;
43 import org.djutils.event.TimedEvent;
44 import org.djutils.exceptions.Throw;
45 import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
46 import org.opentrafficsim.core.dsol.OTSAnimator;
47 import org.opentrafficsim.core.dsol.OTSModelInterface;
48 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
49 import org.opentrafficsim.core.gtu.GTU;
50 import org.opentrafficsim.core.network.Network;
51 import org.opentrafficsim.core.network.OTSNetwork;
52
53 import nl.tudelft.simulation.dsol.animation.Locatable;
54 import nl.tudelft.simulation.dsol.animation.D2.Renderable2DInterface;
55 import nl.tudelft.simulation.dsol.animation.gis.GisMapInterface;
56 import nl.tudelft.simulation.dsol.animation.gis.GisRenderable2D;
57 import nl.tudelft.simulation.dsol.experiment.ReplicationInterface;
58 import nl.tudelft.simulation.dsol.swing.animation.D2.AnimationPanel;
59 import nl.tudelft.simulation.dsol.swing.animation.D2.GridPanel;
60 import nl.tudelft.simulation.dsol.swing.animation.D2.InputListener;
61 import nl.tudelft.simulation.language.DSOLException;
62
63
64
65
66
67
68
69
70
71
72
73
74 public class OTSAnimationPanel extends OTSSimulationPanel implements ActionListener, WindowListener, EventListenerInterface
75 {
76
77 private static final long serialVersionUID = 20150617L;
78
79
80 private final AutoAnimationPanel animationPanel;
81
82
83 private final JPanel borderPanel;
84
85
86 private final JPanel togglePanel;
87
88
89 private JPanel demoPanel = null;
90
91
92 private Map<String, Class<? extends Locatable>> toggleLocatableMap = new LinkedHashMap<>();
93
94
95 private Map<Class<? extends Locatable>, JToggleButton> toggleButtons = new LinkedHashMap<>();
96
97
98 private Map<String, GisMapInterface> toggleGISMap = new LinkedHashMap<>();
99
100
101 private Map<String, JToggleButton> toggleGISButtons = new LinkedHashMap<>();
102
103
104 private GTUColorer gtuColorer = null;
105
106
107 private ColorControlPanel colorControlPanel = null;
108
109
110 private final JLabel coordinateField;
111
112
113 private final JLabel gtuCountField;
114
115
116 private int gtuCount = 0;
117
118
119 private final ArrayList<JButton> buttons = new ArrayList<>();
120
121
122 private static final NumberFormat FORMATTER = NumberFormat.getInstance();
123
124
125 @SuppressWarnings("checkstyle:visibilitymodifier")
126 protected boolean closeHandlerRegistered = false;
127
128
129 @SuppressWarnings("checkstyle:visibilitymodifier")
130 protected boolean windowExited = false;
131
132
133 private String autoPanId = null;
134
135
136 private OTSSearchPanel.ObjectKind<?> autoPanKind = null;
137
138
139 private boolean autoPanTrack = false;
140
141
142 private boolean autoPanOnNextPaintComponent = false;
143
144
145 static
146 {
147 FORMATTER.setMaximumFractionDigits(3);
148 }
149
150
151
152
153
154
155
156
157
158
159
160
161 public OTSAnimationPanel(final Rectangle2D extent, final Dimension size, final OTSAnimator simulator,
162 final OTSModelInterface otsModel, final GTUColorer gtuColorer, final OTSNetwork network)
163 throws RemoteException, DSOLException
164 {
165 super(simulator, otsModel);
166
167
168
169 this.animationPanel = new AutoAnimationPanel(extent, size, simulator, network);
170 this.animationPanel.showGrid(false);
171 this.borderPanel = new JPanel(new BorderLayout());
172 this.borderPanel.add(this.animationPanel, BorderLayout.CENTER);
173 getTabbedPane().addTab(0, "animation", this.borderPanel);
174 getTabbedPane().setSelectedIndex(0);
175
176
177 this.gtuColorer = gtuColorer;
178 this.colorControlPanel = new ColorControlPanel(this.gtuColorer);
179 JPanel buttonPanel = new JPanel();
180 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
181 this.borderPanel.add(buttonPanel, BorderLayout.NORTH);
182 buttonPanel.add(this.colorControlPanel);
183
184
185 this.togglePanel = new JPanel();
186 this.togglePanel.setLayout(new BoxLayout(this.togglePanel, BoxLayout.Y_AXIS));
187 this.borderPanel.add(this.togglePanel, BorderLayout.WEST);
188
189
190 buttonPanel.add(new JLabel(" "));
191 buttonPanel.add(makeButton("allButton", "/Expand.png", "ZoomAll", "Zoom whole network", true));
192 buttonPanel.add(makeButton("homeButton", "/Home.png", "Home", "Zoom to original extent", true));
193 buttonPanel.add(makeButton("gridButton", "/Grid.png", "Grid", "Toggle grid on/off", true));
194 buttonPanel.add(new JLabel(" "));
195
196
197 JPanel infoTextPanel = new JPanel();
198 buttonPanel.add(infoTextPanel);
199 infoTextPanel.setMinimumSize(new Dimension(250, 20));
200 infoTextPanel.setPreferredSize(new Dimension(250, 20));
201 infoTextPanel.setLayout(new BoxLayout(infoTextPanel, BoxLayout.Y_AXIS));
202 this.coordinateField = new JLabel("Mouse: ");
203 this.coordinateField.setMinimumSize(new Dimension(250, 10));
204 this.coordinateField.setPreferredSize(new Dimension(250, 10));
205 infoTextPanel.add(this.coordinateField);
206
207 JPanel gtuPanel = new JPanel();
208 gtuPanel.setAlignmentX(0.0f);
209 gtuPanel.setLayout(new BoxLayout(gtuPanel, BoxLayout.X_AXIS));
210 gtuPanel.setMinimumSize(new Dimension(250, 10));
211 gtuPanel.setPreferredSize(new Dimension(250, 10));
212 infoTextPanel.add(gtuPanel);
213 if (null != network)
214 {
215 network.addListener(this, Network.GTU_ADD_EVENT);
216 network.addListener(this, Network.GTU_REMOVE_EVENT);
217 }
218
219 this.gtuCountField = new JLabel("0 GTU's");
220 this.gtuCount = null == network ? 0 : network.getGTUs().size();
221 gtuPanel.add(this.gtuCountField);
222 setGtuCountText();
223
224
225 this.animationPanel.notify(new TimedEvent(ReplicationInterface.START_REPLICATION_EVENT, simulator.getSourceId(), null,
226 getSimulator().getSimulatorTime()));
227
228
229 this.animationPanel.setShowToolTip(false);
230
231
232 new UpdateTimer().start();
233
234
235 installWindowCloseHandler();
236
237 }
238
239
240
241
242
243
244
245 public void setAutoPan(final String newAutoPanId, final OTSSearchPanel.ObjectKind<?> newAutoPanKind,
246 final boolean newAutoPanTrack)
247 {
248 this.autoPanId = newAutoPanId;
249 this.autoPanKind = newAutoPanKind;
250 this.autoPanTrack = newAutoPanTrack;
251 this.autoPanOnNextPaintComponent = true;
252
253 if (null != this.autoPanId && this.autoPanId.length() > 0 && null != this.autoPanKind)
254 {
255 OTSAnimationPanel.this.animationPanel.repaint();
256 }
257 }
258
259
260
261
262
263
264
265
266
267
268 private JButton makeButton(final String name, final String iconPath, final String actionCommand, final String toolTipText,
269 final boolean enabled)
270 {
271
272 JButton result = new JButton(OTSControlPanel.loadIcon(iconPath));
273 result.setPreferredSize(new Dimension(34, 32));
274 result.setName(name);
275 result.setEnabled(enabled);
276 result.setActionCommand(actionCommand);
277 result.setToolTipText(toolTipText);
278 result.addActionListener(this);
279 this.buttons.add(result);
280 return result;
281 }
282
283
284
285
286
287
288
289
290
291
292
293
294 public final void addToggleAnimationButtonIcon(final String name, final Class<? extends Locatable> locatableClass,
295 final String iconPath, final String toolTipText, final boolean initiallyVisible, final boolean idButton)
296 {
297 JToggleButton button;
298 Icon icon = OTSControlPanel.loadIcon(iconPath);
299 Icon unIcon = OTSControlPanel.loadGrayscaleIcon(iconPath);
300 button = new JCheckBox();
301 button.setSelectedIcon(icon);
302 button.setIcon(unIcon);
303 button.setPreferredSize(new Dimension(32, 28));
304 button.setName(name);
305 button.setEnabled(true);
306 button.setSelected(initiallyVisible);
307 button.setActionCommand(name);
308 button.setToolTipText(toolTipText);
309 button.addActionListener(this);
310
311
312 if (idButton && this.togglePanel.getComponentCount() > 0)
313 {
314 JPanel lastToggleBox = (JPanel) this.togglePanel.getComponent(this.togglePanel.getComponentCount() - 1);
315 lastToggleBox.add(button);
316 }
317 else
318 {
319 JPanel toggleBox = new JPanel();
320 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
321 toggleBox.add(button);
322 this.togglePanel.add(toggleBox);
323 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
324 }
325
326 if (initiallyVisible)
327 {
328 this.animationPanel.showClass(locatableClass);
329 }
330 else
331 {
332 this.animationPanel.hideClass(locatableClass);
333 }
334 this.toggleLocatableMap.put(name, locatableClass);
335 this.toggleButtons.put(locatableClass, button);
336 }
337
338
339
340
341
342
343
344
345 public final void addToggleAnimationButtonText(final String name, final Class<? extends Locatable> locatableClass,
346 final String toolTipText, final boolean initiallyVisible)
347 {
348 JToggleButton button;
349 button = new JCheckBox(name);
350 button.setName(name);
351 button.setEnabled(true);
352 button.setSelected(initiallyVisible);
353 button.setActionCommand(name);
354 button.setToolTipText(toolTipText);
355 button.addActionListener(this);
356
357 JPanel toggleBox = new JPanel();
358 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
359 toggleBox.add(button);
360 this.togglePanel.add(toggleBox);
361 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
362
363 if (initiallyVisible)
364 {
365 this.animationPanel.showClass(locatableClass);
366 }
367 else
368 {
369 this.animationPanel.hideClass(locatableClass);
370 }
371 this.toggleLocatableMap.put(name, locatableClass);
372 this.toggleButtons.put(locatableClass, button);
373 }
374
375
376
377
378
379 public final void addToggleText(final String text)
380 {
381 JPanel textBox = new JPanel();
382 textBox.setLayout(new BoxLayout(textBox, BoxLayout.X_AXIS));
383 textBox.add(new JLabel(text));
384 this.togglePanel.add(textBox);
385 textBox.setAlignmentX(Component.LEFT_ALIGNMENT);
386 }
387
388
389
390
391
392
393
394 public final void addAllToggleGISButtonText(final String header, final GisRenderable2D gisMap, final String toolTipText)
395 {
396 addToggleText(" ");
397 addToggleText(header);
398 try
399 {
400 for (String layerName : gisMap.getMap().getLayerMap().keySet())
401 {
402 addToggleGISButtonText(layerName, layerName, gisMap, toolTipText);
403 }
404 }
405 catch (RemoteException exception)
406 {
407 exception.printStackTrace();
408 }
409 }
410
411
412
413
414
415
416
417
418 public final void addToggleGISButtonText(final String layerName, final String displayName, final GisRenderable2D gisMap,
419 final String toolTipText)
420 {
421 JToggleButton button;
422 button = new JCheckBox(displayName);
423 button.setName(layerName);
424 button.setEnabled(true);
425 button.setSelected(true);
426 button.setActionCommand(layerName);
427 button.setToolTipText(toolTipText);
428 button.addActionListener(this);
429
430 JPanel toggleBox = new JPanel();
431 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
432 toggleBox.add(button);
433 this.togglePanel.add(toggleBox);
434 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
435
436 this.toggleGISMap.put(layerName, gisMap.getMap());
437 this.toggleGISButtons.put(layerName, button);
438 }
439
440
441
442
443
444 public final void showGISLayer(final String layerName)
445 {
446 GisMapInterface gisMap = this.toggleGISMap.get(layerName);
447 if (gisMap != null)
448 {
449 try
450 {
451 gisMap.showLayer(layerName);
452 this.toggleGISButtons.get(layerName).setSelected(true);
453 this.animationPanel.repaint();
454 }
455 catch (RemoteException exception)
456 {
457 exception.printStackTrace();
458 }
459 }
460 }
461
462
463
464
465
466 public final void hideGISLayer(final String layerName)
467 {
468 GisMapInterface gisMap = this.toggleGISMap.get(layerName);
469 if (gisMap != null)
470 {
471 try
472 {
473 gisMap.hideLayer(layerName);
474 this.toggleGISButtons.get(layerName).setSelected(false);
475 this.animationPanel.repaint();
476 }
477 catch (RemoteException exception)
478 {
479 exception.printStackTrace();
480 }
481 }
482 }
483
484
485
486
487
488 public final void toggleGISLayer(final String layerName)
489 {
490 GisMapInterface gisMap = this.toggleGISMap.get(layerName);
491 if (gisMap != null)
492 {
493 try
494 {
495 if (gisMap.getVisibleLayers().contains(gisMap.getLayerMap().get(layerName)))
496 {
497 gisMap.hideLayer(layerName);
498 this.toggleGISButtons.get(layerName).setSelected(false);
499 }
500 else
501 {
502 gisMap.showLayer(layerName);
503 this.toggleGISButtons.get(layerName).setSelected(true);
504 }
505 this.animationPanel.repaint();
506 }
507 catch (RemoteException exception)
508 {
509 exception.printStackTrace();
510 }
511 }
512 }
513
514
515 @Override
516 public final void actionPerformed(final ActionEvent actionEvent)
517 {
518 String actionCommand = actionEvent.getActionCommand();
519
520 try
521 {
522 if (actionCommand.equals("Home"))
523 {
524 this.animationPanel.home();
525 }
526 if (actionCommand.equals("ZoomAll"))
527 {
528 this.animationPanel.zoomAll();
529 }
530 if (actionCommand.equals("Grid"))
531 {
532 this.animationPanel.showGrid(!this.animationPanel.isShowGrid());
533 }
534
535 if (this.toggleLocatableMap.containsKey(actionCommand))
536 {
537 Class<? extends Locatable> locatableClass = this.toggleLocatableMap.get(actionCommand);
538 this.animationPanel.toggleClass(locatableClass);
539 this.togglePanel.repaint();
540 }
541
542 if (this.toggleGISMap.containsKey(actionCommand))
543 {
544 this.toggleGISLayer(actionCommand);
545 this.togglePanel.repaint();
546 }
547 }
548 catch (Exception exception)
549 {
550 exception.printStackTrace();
551 }
552 }
553
554
555
556
557
558 public final AnimationPanel getAnimationPanel()
559 {
560 return this.animationPanel;
561 }
562
563
564
565
566
567
568 public void createDemoPanel(final DemoPanelPosition position)
569 {
570 Throw.when(this.demoPanel != null, IllegalStateException.class,
571 "Attempt to create demo panel, but it's already created");
572 Throw.whenNull(position, "Position may not be null.");
573 Container parent = this.animationPanel.getParent();
574 parent.remove(this.animationPanel);
575
576 JPanel splitPanel = new JPanel(new BorderLayout());
577 parent.add(splitPanel);
578 splitPanel.add(this.animationPanel, BorderLayout.CENTER);
579
580 this.demoPanel = new JPanel();
581 this.demoPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
582 splitPanel.add(this.demoPanel, position.getBorderLayoutPosition());
583 }
584
585
586
587
588
589 public JPanel getDemoPanel()
590 {
591 if (this.demoPanel == null)
592 {
593 createDemoPanel(DemoPanelPosition.RIGHT);
594
595
596
597
598
599 this.demoPanel.addContainerListener(new ContainerListener()
600 {
601 @Override
602 public void componentAdded(final ContainerEvent e)
603 {
604 try
605 {
606
607 }
608 catch (NullPointerException exception)
609 {
610
611 }
612 }
613
614 @Override
615 public void componentRemoved(final ContainerEvent e)
616 {
617
618 }
619 });
620 }
621 return this.demoPanel;
622 }
623
624
625
626
627
628 public final void updateAnimationClassCheckBox(final Class<? extends Locatable> locatableClass)
629 {
630 JToggleButton button = this.toggleButtons.get(locatableClass);
631 if (button == null)
632 {
633 return;
634 }
635 button.setSelected(getAnimationPanel().isShowClass(locatableClass));
636 }
637
638
639
640
641 protected final void updateWorldCoordinate()
642 {
643 String worldPoint = "(x=" + FORMATTER.format(this.animationPanel.getWorldCoordinate().getX()) + " ; y="
644 + FORMATTER.format(this.animationPanel.getWorldCoordinate().getY()) + ")";
645 this.coordinateField.setText("Mouse: " + worldPoint);
646 int requiredWidth = this.coordinateField.getGraphics().getFontMetrics().stringWidth(this.coordinateField.getText());
647 if (this.coordinateField.getPreferredSize().width < requiredWidth)
648 {
649 Dimension requiredSize = new Dimension(requiredWidth, this.coordinateField.getPreferredSize().height);
650 this.coordinateField.setPreferredSize(requiredSize);
651 this.coordinateField.setMinimumSize(requiredSize);
652 Container parent = this.coordinateField.getParent();
653 parent.setPreferredSize(requiredSize);
654 parent.setMinimumSize(requiredSize);
655
656 parent.revalidate();
657 }
658 this.coordinateField.repaint();
659 }
660
661
662
663
664
665
666 public final GTUColorer getGTUColorer()
667 {
668 return this.gtuColorer;
669 }
670
671
672
673
674
675
676 public final ColorControlPanel getColorControlPanel()
677 {
678 return this.colorControlPanel;
679 }
680
681
682
683
684 public final void installWindowCloseHandler()
685 {
686 if (this.closeHandlerRegistered)
687 {
688 return;
689 }
690
691
692 new DisposeOnCloseThread(this).start();
693 }
694
695
696 protected class DisposeOnCloseThread extends Thread
697 {
698
699 private OTSAnimationPanel panel;
700
701
702
703
704 public DisposeOnCloseThread(final OTSAnimationPanel panel)
705 {
706 this.panel = panel;
707 }
708
709
710 @Override
711 public final void run()
712 {
713 Container root = this.panel;
714 while (!(root instanceof JFrame))
715 {
716 try
717 {
718 Thread.sleep(10);
719 }
720 catch (InterruptedException exception)
721 {
722
723 }
724
725
726 root = this.panel;
727 while (null != root.getParent() && !(root instanceof JFrame))
728 {
729 root = root.getParent();
730 }
731 }
732 JFrame frame = (JFrame) root;
733 frame.addWindowListener(this.panel);
734 this.panel.closeHandlerRegistered = true;
735 }
736
737
738 @Override
739 public final String toString()
740 {
741 return "DisposeOnCloseThread of OTSAnimationPanel [panel=" + this.panel + "]";
742 }
743 }
744
745
746 @Override
747 public void windowOpened(final WindowEvent e)
748 {
749
750 }
751
752
753 @Override
754 public final void windowClosing(final WindowEvent e)
755 {
756
757 }
758
759
760 @Override
761 public final void windowClosed(final WindowEvent e)
762 {
763 this.windowExited = true;
764 }
765
766
767 @Override
768 public final void windowIconified(final WindowEvent e)
769 {
770
771 }
772
773
774 @Override
775 public final void windowDeiconified(final WindowEvent e)
776 {
777
778 }
779
780
781 @Override
782 public final void windowActivated(final WindowEvent e)
783 {
784
785 }
786
787
788 @Override
789 public final void windowDeactivated(final WindowEvent e)
790 {
791
792 }
793
794
795 @Override
796 public void notify(final EventInterface event) throws RemoteException
797 {
798 if (event.getType().equals(Network.GTU_ADD_EVENT))
799 {
800 this.gtuCount++;
801 setGtuCountText();
802 }
803 else if (event.getType().equals(Network.GTU_REMOVE_EVENT))
804 {
805 this.gtuCount--;
806 setGtuCountText();
807 }
808 }
809
810
811
812
813 private void setGtuCountText()
814 {
815 this.gtuCountField.setText(this.gtuCount + " GTU's");
816 }
817
818
819
820
821 protected class UpdateTimer extends Thread
822 {
823
824 @Override
825 public final void run()
826 {
827 while (!OTSAnimationPanel.this.windowExited)
828 {
829 if (OTSAnimationPanel.this.isShowing())
830 {
831 OTSAnimationPanel.this.updateWorldCoordinate();
832 }
833 try
834 {
835 Thread.sleep(50);
836 }
837 catch (InterruptedException exception)
838 {
839
840 }
841 }
842 }
843
844
845 @Override
846 public final String toString()
847 {
848 return "UpdateTimer thread for OTSAnimationPanel";
849 }
850
851 }
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866 private class AutoAnimationPanel extends AnimationPanel
867 {
868
869
870 private static final long serialVersionUID = 20180430L;
871
872
873 private final OTSNetwork network;
874
875
876 private GTU lastGtu;
877
878
879
880
881
882
883
884
885
886
887 AutoAnimationPanel(final Rectangle2D extent, final Dimension size, final OTSSimulatorInterface simulator,
888 final OTSNetwork network) throws RemoteException, DSOLException
889 {
890 super(new Bounds2d(extent.getMinX(), extent.getMaxX(), extent.getMinY(), extent.getMaxY()), simulator);
891 this.network = network;
892 MouseListener[] listeners = getMouseListeners();
893 for (MouseListener listener : listeners)
894 {
895 removeMouseListener(listener);
896 }
897 this.addMouseListener(new MouseAdapter()
898 {
899
900 @SuppressWarnings("synthetic-access")
901 @Override
902 public void mouseClicked(final MouseEvent e)
903 {
904 if (e.isControlDown())
905 {
906 GTU gtu = getSelectedGTU(e.getPoint());
907 if (gtu != null)
908 {
909 getOtsControlPanel().getOtsSearchPanel().selectAndTrackObject("GTU", gtu.getId(), true);
910 e.consume();
911 }
912 }
913 e.consume();
914 }
915 });
916 for (MouseListener listener : listeners)
917 {
918 addMouseListener(listener);
919 }
920
921 MouseWheelListener[] wheelListeners = getMouseWheelListeners();
922 for (MouseWheelListener wheelListener : wheelListeners)
923 {
924 removeMouseWheelListener(wheelListener);
925 }
926 this.addMouseWheelListener(new InputListener(this)
927 {
928
929 @Override
930 public void mouseWheelMoved(final MouseWheelEvent e)
931 {
932 if (e.isShiftDown())
933 {
934 int amount = e.getUnitsToScroll();
935 if (amount > 0)
936 {
937 zoomVertical(GridPanel.ZOOMFACTOR, e.getX(), e.getY());
938 }
939 else
940 {
941 zoomVertical(1.0 / GridPanel.ZOOMFACTOR, e.getX(), e.getY());
942 }
943 }
944 else if (e.isAltDown())
945 {
946 int amount = e.getUnitsToScroll();
947 if (amount > 0)
948 {
949 zoomHorizontal(GridPanel.ZOOMFACTOR, e.getX(), e.getY());
950 }
951 else
952 {
953 zoomHorizontal(1.0 / GridPanel.ZOOMFACTOR, e.getX(), e.getY());
954 }
955 }
956 else
957 {
958 super.mouseWheelMoved(e);
959 }
960 }
961 });
962 }
963
964
965
966
967
968
969
970 final synchronized void zoomVertical(final double factor, final int mouseX, final int mouseY)
971 {
972
973 this.zoom(factor, mouseX, mouseY);
974
975
976
977
978
979
980
981
982
983 }
984
985
986
987
988
989
990
991 final synchronized void zoomHorizontal(final double factor, final int mouseX, final int mouseY)
992 {
993 this.zoom(factor, mouseX, mouseY);
994
995
996
997
998
999
1000
1001
1002
1003 }
1004
1005
1006
1007
1008
1009
1010 @SuppressWarnings("synthetic-access")
1011 protected GTU getSelectedGTU(final Point2D mousePoint)
1012 {
1013 List<GTU> targets = new ArrayList<>();
1014 Point2d point = getRenderableScale().getWorldCoordinates(mousePoint, getExtent(), getSize());
1015 for (Renderable2DInterface<?> renderable : getElements())
1016 {
1017 if (isShowElement(renderable) && renderable.contains(point, getExtent()))
1018 {
1019 if (renderable.getSource() instanceof GTU)
1020 {
1021 targets.add((GTU) renderable.getSource());
1022 }
1023 }
1024 }
1025 if (targets.size() == 1)
1026 {
1027 return targets.get(0);
1028 }
1029 return null;
1030 }
1031
1032
1033 @SuppressWarnings("synthetic-access")
1034 @Override
1035 public void paintComponent(final Graphics g)
1036 {
1037 final OTSSearchPanel.ObjectKind<?> panKind = OTSAnimationPanel.this.autoPanKind;
1038 final String panId = OTSAnimationPanel.this.autoPanId;
1039 final boolean doPan = OTSAnimationPanel.this.autoPanOnNextPaintComponent;
1040 OTSAnimationPanel.this.autoPanOnNextPaintComponent = OTSAnimationPanel.this.autoPanTrack;
1041 if (doPan && panKind != null && panId != null)
1042 {
1043 Locatable locatable = panKind.searchNetwork(this.network, panId);
1044 if (null != locatable)
1045 {
1046 try
1047 {
1048 Point<?> point = locatable.getLocation();
1049 if (point != null)
1050 {
1051 double w = getExtent().getDeltaX();
1052 double h = getExtent().getDeltaY();
1053 setExtent(new Bounds2d(point.getX() - w / 2, point.getX() + w / 2, point.getY() - h / 2,
1054 point.getY() + h / 2));
1055 }
1056 }
1057 catch (RemoteException exception)
1058 {
1059 getSimulator().getLogger().always().warn(
1060 "Caught RemoteException trying to locate {} with id {} in network {}.", panKind, panId,
1061 this.network.getId());
1062 return;
1063 }
1064 }
1065 }
1066 super.paintComponent(g);
1067 }
1068
1069
1070 @Override
1071 public String toString()
1072 {
1073 return "AutoAnimationPanel [network=" + this.network + ", lastGtu=" + this.lastGtu + "]";
1074 }
1075 }
1076
1077
1078
1079
1080
1081 public enum DemoPanelPosition
1082 {
1083
1084 TOP("First"),
1085
1086
1087 BOTTOM("Last"),
1088
1089
1090 LEFT("Before"),
1091
1092
1093 RIGHT("After");
1094
1095
1096 private final String direction;
1097
1098
1099
1100
1101 DemoPanelPosition(final String direction)
1102 {
1103 this.direction = direction;
1104 }
1105
1106
1107
1108
1109 public String getBorderLayoutPosition()
1110 {
1111 return this.direction;
1112 }
1113 }
1114
1115 }