1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.diyefi.openlogviewer.graphing;
24
25 import java.awt.Dimension;
26 import java.awt.event.ActionEvent;
27 import java.awt.event.ActionListener;
28 import java.awt.event.InputEvent;
29 import java.awt.event.KeyEvent;
30 import java.awt.event.KeyListener;
31 import java.awt.event.MouseEvent;
32 import java.awt.event.MouseListener;
33 import java.awt.event.MouseMotionListener;
34 import java.awt.event.MouseWheelEvent;
35 import java.awt.event.MouseWheelListener;
36
37 import javax.swing.JPanel;
38 import javax.swing.Timer;
39
40 import org.diyefi.openlogviewer.OpenLogViewer;
41 import org.diyefi.openlogviewer.genericlog.GenericLog;
42
43 public class EntireGraphingPanel extends JPanel implements ActionListener, MouseMotionListener, MouseListener, MouseWheelListener, KeyListener {
44 private static final long serialVersionUID = 1L;
45
46 private MultiGraphLayeredPane multiGraph;
47 private GraphPositionPanel graphPositionPanel;
48 private double graphPosition;
49 private int graphSize;
50 private boolean playing;
51 private boolean wasPlaying;
52 private Timer playTimer;
53 private Timer flingTimer;
54 private boolean dragging;
55 private boolean flinging;
56 private long thePast;
57 private int prevDragXCoord;
58 private int flingInertia;
59 private int zoom;
60 private boolean zoomedOutBeyondOneToOne;
61
62 public EntireGraphingPanel() {
63 super();
64 init();
65 }
66
67 private void init() {
68 this.setName("Graphing Panel");
69 this.setLayout(new java.awt.BorderLayout());
70 multiGraph = new MultiGraphLayeredPane();
71 multiGraph.setPreferredSize(new Dimension(600, 400));
72 this.add(multiGraph, java.awt.BorderLayout.CENTER);
73 graphPositionPanel = new GraphPositionPanel();
74 graphPositionPanel.setPreferredSize(new Dimension(600, 20));
75 this.add(graphPositionPanel, java.awt.BorderLayout.SOUTH);
76 zoom = 1;
77 zoomedOutBeyondOneToOne = false;
78 resetGraphPosition();
79 setGraphSize(0);
80 playing = false;
81 wasPlaying = false;
82 playTimer = new Timer(10, this);
83 playTimer.setInitialDelay(0);
84 flingTimer = new Timer(10, this);
85 flingTimer.setInitialDelay(0);
86 addMouseListener(this);
87 addMouseMotionListener(this);
88 addMouseWheelListener(this);
89 addMouseListener(multiGraph.getInfoPanel());
90 addMouseMotionListener(multiGraph.getInfoPanel());
91 stopDragging();
92 stopFlinging();
93 thePast = System.currentTimeMillis();
94 }
95
96 public final void actionPerformed(final ActionEvent e) {
97 if (playing && graphPosition < getGraphPositionMax()) {
98 if(zoomedOutBeyondOneToOne){
99 moveGraphPosition(zoom);
100 } else {
101 moveGraphPosition(1);
102 }
103 } else if ((flinging && graphPosition < getGraphPositionMax()) && (graphPosition > getGraphPositionMin())) {
104 if (flingInertia == 0) {
105 stopFlinging();
106 } else {
107 moveEntireGraphingPanel(flingInertia);
108 if (flingInertia > 0) {
109 flingInertia--;
110 } else {
111 flingInertia++;
112 }
113 }
114 }
115 }
116
117 public final MultiGraphLayeredPane getMultiGraphLayeredPane() {
118 return multiGraph;
119 }
120
121 public final GraphPositionPanel getGraphPositionPanel() {
122 return graphPositionPanel;
123 }
124
125 public final void setLog(final GenericLog genLog) {
126 playing = false;
127 resetGraphPosition();
128 multiGraph.setLog(genLog);
129 graphPositionPanel.setLog(genLog);
130 }
131
132
133
134
135
136 private final int getTightestZoom(){
137 return this.getWidth() - 1;
138 }
139
140
141
142
143 private final int getWidestZoom(){
144 return Integer.MAX_VALUE;
145 }
146
147
148
149
150
151
152
153 public final void zoomIn() {
154 final double graphWidth = this.getWidth();
155 double move = 0;
156
157 if(zoomedOutBeyondOneToOne) {
158 if (zoom == 2) {
159 zoomedOutBeyondOneToOne = false;
160 }
161 zoom--;
162 move = graphWidth / (double)(zoom * 2);
163 } else if (zoom < getTightestZoom()) {
164 move = graphWidth / (double)(zoom * 2);
165 zoom++;
166 }
167
168 moveEntireGraphingPanel(move);
169 }
170
171
172
173
174
175
176
177 public final void zoomInCoarse(){
178 final int zoomAmount = (int)Math.sqrt(zoom);
179 for (int i = 0; i < zoomAmount; i++){
180 zoomIn();
181 }
182 }
183
184
185
186
187
188
189
190 public final void zoomOut() {
191 final double graphWidth = this.getWidth();
192 double move = 0;
193
194 if (!zoomedOutBeyondOneToOne) {
195 if (zoom == 1) {
196 zoomedOutBeyondOneToOne = true;
197 zoom = 2;
198 move = graphWidth / (double)(zoom * 2);
199 } else {
200 move = graphWidth / (double)(zoom * 2);
201 zoom--;
202 }
203 } else if (zoom < getWidestZoom()){
204 zoom++;
205 move = graphWidth / (double)(zoom * 2);
206 }
207
208 moveEntireGraphingPanel(-move);
209 }
210
211
212
213
214
215
216
217 public final void zoomOutCoarse(){
218 final int zoomAmount = (int)Math.sqrt(zoom);
219 for (int i = 0; i < zoomAmount; i++){
220 zoomOut();
221 }
222 }
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 private final void zoomGraphToFit(final int dataPointsToFit){
238 final int graphWindowWidth = this.getWidth() - 8;
239 int dataPointsThatFitInDisplay = 0;
240 if (zoomedOutBeyondOneToOne){
241 dataPointsThatFitInDisplay = graphWindowWidth * zoom;
242 } else {
243 dataPointsThatFitInDisplay = graphWindowWidth / zoom;
244 }
245
246
247 while (dataPointsToFit < dataPointsThatFitInDisplay && zoom != getTightestZoom()){
248 zoomIn();
249 if (zoomedOutBeyondOneToOne){
250 dataPointsThatFitInDisplay = graphWindowWidth * zoom;
251 } else {
252 dataPointsThatFitInDisplay = graphWindowWidth / zoom;
253 }
254 }
255
256
257 while (dataPointsToFit > dataPointsThatFitInDisplay && zoom != getWidestZoom()){
258 zoomOut();
259 if (zoomedOutBeyondOneToOne){
260 dataPointsThatFitInDisplay = graphWindowWidth * zoom;
261 } else {
262 dataPointsThatFitInDisplay = graphWindowWidth / zoom;
263 }
264 }
265 }
266
267 public boolean isZoomedOutBeyondOneToOne(){
268 return zoomedOutBeyondOneToOne;
269 }
270
271 public final void play() {
272 if (playing) {
273 pause();
274 } else {
275 playing = true;
276 stopDragging();
277 stopFlinging();
278 playTimer.start();
279 }
280 }
281
282 public final void pause() {
283 playing = false;
284 playTimer.stop();
285 stopDragging();
286 stopFlinging();
287 }
288
289
290
291
292 public final void fastForward() {
293 final int currentDelay = playTimer.getDelay();
294 if (currentDelay > 0) {
295 playTimer.setDelay(currentDelay - 1);
296 }
297 }
298
299 public final void eject() {
300 resetGraphPosition();
301 }
302
303 public final void stop() {
304 playing = false;
305 wasPlaying = false;
306 playTimer.stop();
307 resetGraphPosition();
308 }
309
310
311
312
313 public final void slowDown() {
314 final int currentDelay = playTimer.getDelay();
315 playTimer.setDelay(currentDelay + 1);
316 }
317
318 public final void fling() {
319 flinging = true;
320 flingTimer.start();
321 }
322
323 private final double getGraphPositionMin(){
324 double min = 0.0;
325 if(zoomedOutBeyondOneToOne){
326 min = -((this.getWidth() - 1) * zoom);
327 } else {
328 min = -(((double)this.getWidth() - 1.0) / (double)zoom);
329 }
330 return min;
331 }
332
333 public final double getGraphPosition() {
334 return graphPosition;
335 }
336
337 private final int getGraphPositionMax() {
338 return graphSize;
339 }
340
341 public final void setGraphPosition(final double newPos) {
342 graphPosition = newPos;
343 repaint();
344 }
345
346
347
348
349 public final void setGraphSize(final int newGraphSize) {
350 graphSize = newGraphSize;
351 if(graphSize > 0){
352 centerGraphPosition(0, graphSize);
353 zoomGraphToFit(graphSize);
354 }
355 }
356
357
358
359
360
361 private final void resetGraphPosition() {
362 setGraphPosition(getGraphPositionMin());
363 }
364
365
366
367
368
369
370
371
372 private final void centerGraphPosition(final int beginPosition, final int endPosition) {
373 final int halfScreen = this.getWidth() / 2;
374 double pointsThatFitInHalfScreen = 0;
375 if (zoomedOutBeyondOneToOne){
376 pointsThatFitInHalfScreen = halfScreen * zoom;
377 } else {
378 pointsThatFitInHalfScreen = halfScreen / zoom;
379 }
380 final int distanceBetweenPositions = endPosition - beginPosition;
381 final double halfwayBetweenTwoPositions = distanceBetweenPositions / 2;
382 final double centerPosition = (beginPosition + halfwayBetweenTwoPositions) - pointsThatFitInHalfScreen;
383 setGraphPosition(centerPosition);
384 }
385
386
387
388
389
390 private void goToLastGraphPosition() {
391 setGraphPosition(getGraphPositionMax());
392 }
393
394 public final boolean isPlaying() {
395 return playing;
396 }
397
398 public final int getZoom() {
399 return zoom;
400 }
401
402
403
404
405 private void moveGraphPosition(final double amount) {
406 final double newPos = graphPosition + amount;
407 if (newPos > getGraphPositionMax()){
408 goToLastGraphPosition();
409 } else if (newPos < getGraphPositionMin()){
410 resetGraphPosition();
411 } else {
412 setGraphPosition(newPos);
413 }
414 }
415
416
417
418
419
420 private void moveEntireGraphingPanel(final double newPosition) {
421 double move = -1.0;
422 if(zoomedOutBeyondOneToOne){
423 move = newPosition * zoom;
424 } else {
425 move = newPosition / zoom;
426 }
427 if (graphPosition + move < getGraphPositionMax()) {
428 if (graphPosition + move < getGraphPositionMin()) {
429 resetGraphPosition();
430 } else {
431 moveGraphPosition(move);
432 }
433 } else {
434 goToLastGraphPosition();
435 }
436 }
437
438 private void stopDragging() {
439 dragging = false;
440 prevDragXCoord = -1;
441 }
442
443 private void stopFlinging() {
444 flinging = false;
445 flingInertia = 0;
446 }
447
448
449 @Override
450 public final void mouseClicked(final MouseEvent e) {
451 if (!dragging) {
452 final int half = this.getWidth() / 2;
453 moveEntireGraphingPanel(e.getX() - half);
454 } else {
455 stopDragging();
456 stopFlinging();
457 }
458 }
459
460 @Override
461 public final void mouseDragged(final MouseEvent e) {
462 dragging = true;
463 final int xMouseCoord = e.getX();
464 if ((prevDragXCoord > 0) && (prevDragXCoord != xMouseCoord)) {
465 moveEntireGraphingPanel(prevDragXCoord - xMouseCoord);
466 flingInertia = ((prevDragXCoord - xMouseCoord) * 2);
467 thePast = System.currentTimeMillis();
468 }
469 prevDragXCoord = xMouseCoord;
470 }
471
472 @Override
473 public final void mouseMoved(final MouseEvent e) {
474
475
476 }
477
478 @Override
479 public final void mouseEntered(final MouseEvent e) {
480
481
482 }
483
484 @Override
485 public final void mouseExited(final MouseEvent e) {
486
487
488 }
489
490 @Override
491 public final void mousePressed(final MouseEvent e) {
492 wasPlaying = playing;
493 if (playing) {
494 pause();
495 }
496
497 stopDragging();
498 stopFlinging();
499 }
500
501 @Override
502 public final void mouseReleased(final MouseEvent e) {
503 stopDragging();
504
505 final long now = System.currentTimeMillis();
506 if ((now - thePast) > 50) {
507 stopFlinging();
508 }
509
510 if (flingInertia != 0) {
511 fling();
512 }
513
514 if (wasPlaying) {
515 play();
516 }
517 }
518
519 @Override
520 public final void mouseWheelMoved(final MouseWheelEvent e) {
521 final int xMouseCoord = e.getX();
522 final double center = this.getWidth() / 2.0;
523 final int notches = e.getWheelRotation();
524 double move = 0;
525 final int zoomAmount = (int)Math.sqrt(zoom);
526 if (notches < 0) {
527 for (int i = 0; i < zoomAmount; i++){
528 if(zoomedOutBeyondOneToOne){
529 move = (xMouseCoord - center) / (zoom - 1.0);
530 } else {
531 move = (xMouseCoord - center) / zoom;
532 }
533 if (!(!zoomedOutBeyondOneToOne && zoom == getTightestZoom())){
534 zoomIn();
535 moveEntireGraphingPanel(move);
536 }
537 }
538 } else {
539 for (int i = 0; i < zoomAmount; i++){
540 if(zoomedOutBeyondOneToOne || zoom == 1){
541 move = -(xMouseCoord - center) / (zoom + 1.0);
542 } else {
543 move = -(xMouseCoord - center) / zoom;
544 }
545 if (!(zoomedOutBeyondOneToOne && zoom == getWidestZoom())){
546 zoomOut();
547 moveEntireGraphingPanel(move);
548 }
549 }
550 }
551 }
552
553
554 @Override
555 public final void keyPressed(final KeyEvent e) {
556 switch (e.getKeyCode()) {
557
558 case KeyEvent.VK_SPACE: {
559 play();
560 break;
561 }
562
563
564 case KeyEvent.VK_ENTER: {
565 if (e.getModifiers() == InputEvent.ALT_MASK
566 && e.getKeyLocation() == KeyEvent.KEY_LOCATION_STANDARD) {
567 OpenLogViewer.getInstance().enterFullScreen();
568 }
569 break;
570 }
571
572
573 case KeyEvent.VK_ESCAPE: {
574 OpenLogViewer.getInstance().exitFullScreen();
575 break;
576 }
577
578
579 case KeyEvent.VK_F11: {
580 OpenLogViewer.getInstance().toggleFullScreen();
581 break;
582 }
583
584
585 case KeyEvent.VK_HOME: {
586 resetGraphPosition();
587 break;
588 }
589
590
591 case KeyEvent.VK_END: {
592 goToLastGraphPosition();
593 break;
594 }
595
596
597 case KeyEvent.VK_PAGE_UP: {
598
599 moveEntireGraphingPanel(-(this.getWidth() * 0.75));
600 break;
601 }
602
603 case KeyEvent.VK_LEFT: {
604 int localZoom = zoom;
605 if(zoomedOutBeyondOneToOne){
606 localZoom = 1;
607 }
608 if (e.getModifiers() == InputEvent.CTRL_MASK) {
609
610 moveEntireGraphingPanel(-(this.getWidth() * 0.75));
611 } else {
612 moveEntireGraphingPanel(-localZoom);
613 }
614 break;
615 }
616
617 case KeyEvent.VK_KP_LEFT: {
618 int localZoom = zoom;
619 if(zoomedOutBeyondOneToOne){
620 localZoom = 1;
621 }
622 if (e.getModifiers() == InputEvent.CTRL_MASK) {
623
624 moveEntireGraphingPanel(-(this.getWidth() * 0.75));
625 } else {
626 moveEntireGraphingPanel(-localZoom);
627 }
628 break;
629 }
630
631
632 case KeyEvent.VK_PAGE_DOWN: {
633
634 moveEntireGraphingPanel(this.getWidth() * 0.75);
635 break;
636 }
637
638 case KeyEvent.VK_RIGHT: {
639 int localZoom = zoom;
640 if(zoomedOutBeyondOneToOne){
641 localZoom = 1;
642 }
643 if (e.getModifiers() == InputEvent.CTRL_MASK) {
644
645 moveEntireGraphingPanel(this.getWidth() * 0.75);
646 } else {
647 moveEntireGraphingPanel(localZoom);
648 }
649 break;
650 }
651
652 case KeyEvent.VK_KP_RIGHT: {
653 int localZoom = zoom;
654 if(zoomedOutBeyondOneToOne){
655 localZoom = 1;
656 }
657 if (e.getModifiers() == InputEvent.CTRL_MASK) {
658
659 moveEntireGraphingPanel(this.getWidth() * 0.75);
660 } else {
661 moveEntireGraphingPanel(localZoom);
662 }
663 break;
664 }
665
666
667 case KeyEvent.VK_UP:
668 case KeyEvent.VK_KP_UP: {
669 zoomInCoarse();
670 break;
671 }
672
673 case KeyEvent.VK_ADD: {
674 if (e.getModifiers() == InputEvent.CTRL_MASK) {
675 zoomInCoarse();
676 }
677 break;
678 }
679
680
681 case KeyEvent.VK_DOWN:
682 case KeyEvent.VK_KP_DOWN: {
683 zoomOutCoarse();
684 break;
685 }
686
687 case KeyEvent.VK_SUBTRACT: {
688 if (e.getModifiers() == InputEvent.CTRL_MASK) {
689 zoomOutCoarse();
690 }
691 break;
692 }
693 }
694 }
695
696 @Override
697 public final void keyReleased(final KeyEvent e) {
698
699
700 }
701
702 @Override
703 public final void keyTyped(final KeyEvent e) {
704
705
706 }
707 }