]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/gui/MapChart.java
a5e7819ba209ab14e6b565fc31e49cca1523e091
[GpsPrune.git] / tim / prune / gui / MapChart.java
1 package tim.prune.gui;
2
3 import java.awt.Color;
4 import java.awt.Dimension;
5 import java.awt.FontMetrics;
6 import java.awt.Graphics;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.awt.event.KeyEvent;
10 import java.awt.event.KeyListener;
11 import java.awt.event.MouseEvent;
12 import java.awt.event.MouseMotionListener;
13 import java.awt.event.MouseWheelEvent;
14 import java.awt.event.MouseWheelListener;
15 import java.awt.image.BufferedImage;
16
17 import javax.swing.JCheckBoxMenuItem;
18 import javax.swing.JMenuItem;
19 import javax.swing.JPopupMenu;
20
21 import tim.prune.App;
22 import tim.prune.DataSubscriber;
23 import tim.prune.I18nManager;
24 import tim.prune.data.DataPoint;
25 import tim.prune.data.TrackInfo;
26 //import tim.prune.gui.map.MapWindow;
27
28
29 /**
30  * Display component for the main map
31  */
32 public class MapChart extends GenericChart implements MouseWheelListener, KeyListener, MouseMotionListener
33 {
34         // Constants
35         private static final int POINT_RADIUS = 4;
36         private static final int CLICK_SENSITIVITY = 10;
37         private static final double ZOOM_SCALE_FACTOR = 1.2;
38         private static final int PAN_DISTANCE = 10;
39         private static final int LIMIT_WAYPOINT_NAMES = 40;
40
41         // Colours
42         private static final Color COLOR_BG         = Color.WHITE;
43         private static final Color COLOR_POINT      = Color.BLUE;
44         private static final Color COLOR_CURR_RANGE = Color.GREEN;
45         private static final Color COLOR_CROSSHAIRS = Color.RED;
46         private static final Color COLOR_WAYPT_NAME = Color.BLACK;
47
48         // Instance variables
49         private App _app = null;
50         private BufferedImage _image = null;
51         private JPopupMenu _popup = null;
52         private JCheckBoxMenuItem _autoPanMenuItem = null;
53         private JCheckBoxMenuItem _connectPointsMenuItem = null;
54         private int _numPoints = -1;
55         private double _scale;
56         private double _offsetX, _offsetY, _zoomScale;
57         private int _lastSelectedPoint = -1;
58         private int _dragStartX = -1, _dragStartY = -1;
59         private int _zoomDragFromX = -1, _zoomDragFromY = -1;
60         private int _zoomDragToX = -1, _zoomDragToY = -1;
61         private boolean _zoomDragging = false;
62
63
64         /**
65          * Constructor
66          * @param inApp App object for callbacks
67          * @param inTrackInfo track info object
68          */
69         public MapChart(App inApp, TrackInfo inTrackInfo)
70         {
71                 super(inTrackInfo);
72                 _app = inApp;
73                 makePopup();
74                 addMouseListener(this);
75                 addMouseWheelListener(this);
76                 addMouseMotionListener(this);
77                 setFocusable(true);
78                 addKeyListener(this);
79                 MINIMUM_SIZE = new Dimension(200, 250);
80                 _zoomScale = 1.0;
81         }
82
83
84         /**
85          * Override track updating to refresh image
86          */
87         public void dataUpdated(byte inUpdateType)
88         {
89                 // Check if number of points has changed or data has been edited
90                 if (_track.getNumPoints() != _numPoints || (inUpdateType & DATA_EDITED) > 0)
91                 {
92                         _image = null;
93                         _lastSelectedPoint = -1;
94                         _numPoints = _track.getNumPoints();
95                 }
96                 super.dataUpdated(inUpdateType);
97         }
98
99
100         /**
101          * Override paint method to draw map
102          * @param inG graphics object
103          */
104         public void paint(Graphics inG)
105         {
106                 if (_track == null)
107                 {
108                         super.paint(inG);
109                         return;
110                 }
111
112                 int width = getWidth();
113                 int height = getHeight();
114                 int x, y;
115
116                 // Find x and y ranges, and scale to fit
117                 double scaleX = (_track.getXRange().getMaximum() - _track.getXRange().getMinimum())
118                   / (width - 2 * (BORDER_WIDTH + POINT_RADIUS));
119                 double scaleY = (_track.getYRange().getMaximum() - _track.getYRange().getMinimum())
120                   / (height - 2 * (BORDER_WIDTH + POINT_RADIUS));
121                 _scale = scaleX;
122                 if (scaleY > _scale) _scale = scaleY;
123
124                 // Autopan if necessary
125                 int selectedPoint = _trackInfo.getSelection().getCurrentPointIndex();
126                 if (_autoPanMenuItem.isSelected() && selectedPoint >= 0 && selectedPoint != _lastSelectedPoint)
127                 {
128                         // Autopan is enabled and a point is selected - work out x and y to see if it's within range
129                         x = width/2 + (int) ((_track.getX(selectedPoint) - _offsetX) / _scale * _zoomScale);
130                         y = height/2 - (int) ((_track.getY(selectedPoint) - _offsetY) / _scale * _zoomScale);
131                         if (x <= BORDER_WIDTH)
132                         {
133                                 // autopan left
134                                 _offsetX -= (width / 4 - x) * _scale / _zoomScale;
135                                 _image = null;
136                         }
137                         else if (x >= (width - BORDER_WIDTH))
138                         {
139                                 // autopan right
140                                 _offsetX += (x - width * 3/4) * _scale / _zoomScale;
141                                 _image = null;
142                         }
143                         if (y <= BORDER_WIDTH)
144                         {
145                                 // autopan up
146                                 _offsetY += (height / 4 - y) * _scale / _zoomScale;
147                                 _image = null;
148                         }
149                         else if (y >= (height - BORDER_WIDTH))
150                         {
151                                 // autopan down
152                                 _offsetY -= (y - height * 3/4) * _scale / _zoomScale;
153                                 _image = null;
154                         }
155                 }
156                 _lastSelectedPoint = selectedPoint;
157
158                 // Create background if necessary
159                 if (_image == null || width != _image.getWidth() || height != _image.getHeight())
160                 {
161                         createBackgroundImage();
162                 }
163                 // return if image has been set to null by other thread
164                 if (_image == null) {return;}
165
166                 // draw buffered image onto g
167                 inG.drawImage(_image, 0, 0, width, height, COLOR_BG, null);
168
169                 // draw selected range, if any
170                 if (_trackInfo.getSelection().hasRangeSelected() && !_zoomDragging)
171                 {
172                         int rangeStart = _trackInfo.getSelection().getStart();
173                         int rangeEnd = _trackInfo.getSelection().getEnd();
174                         inG.setColor(COLOR_CURR_RANGE);
175                         for (int i=rangeStart; i<=rangeEnd; i++)
176                         {
177                                 x = width/2 + (int) ((_track.getX(i) - _offsetX) / _scale * _zoomScale);
178                                 y = height/2 - (int) ((_track.getY(i) - _offsetY) / _scale * _zoomScale);
179                                 if (x > BORDER_WIDTH && x < (width - BORDER_WIDTH)
180                                         && y < (height - BORDER_WIDTH) && y > BORDER_WIDTH)
181                                 {
182                                         inG.drawRect(x - 2, y - 2, 4, 4);
183                                 }
184                         }
185                 }
186
187                 // Highlight selected point
188                 if (selectedPoint >= 0 && !_zoomDragging)
189                 {
190                         inG.setColor(COLOR_CROSSHAIRS);
191                         x = width/2 + (int) ((_track.getX(selectedPoint) - _offsetX) / _scale * _zoomScale);
192                         y = height/2 - (int) ((_track.getY(selectedPoint) - _offsetY) / _scale * _zoomScale);
193                         if (x > BORDER_WIDTH && x < (width - BORDER_WIDTH)
194                                 && y < (height - BORDER_WIDTH) && y > BORDER_WIDTH)
195                         {
196                                 // Draw cross-hairs for current point
197                                 inG.drawLine(x, BORDER_WIDTH, x, height - BORDER_WIDTH);
198                                 inG.drawLine(BORDER_WIDTH, y, width - BORDER_WIDTH, y);
199
200                                 // Show selected point afterwards to make sure it's on top
201                                 inG.drawOval(x - 2, y - 2, 4, 4);
202                                 inG.drawOval(x - 3, y - 3, 6, 6);
203                         }
204                 }
205
206                 // Draw rectangle for dragging zoom area
207                 if (_zoomDragging)
208                 {
209                         inG.setColor(COLOR_CROSSHAIRS);
210                         inG.drawLine(_zoomDragFromX, _zoomDragFromY, _zoomDragFromX, _zoomDragToY);
211                         inG.drawLine(_zoomDragFromX, _zoomDragFromY, _zoomDragToX, _zoomDragFromY);
212                         inG.drawLine(_zoomDragToX, _zoomDragFromY, _zoomDragToX, _zoomDragToY);
213                         inG.drawLine(_zoomDragFromX, _zoomDragToY, _zoomDragToX, _zoomDragToY);
214                 }
215
216                 // Attempt to grab keyboard focus if possible
217                 //requestFocus();  (causes problems here)
218         }
219
220
221         /**
222          * Plot the points onto an offscreen image
223          * which doesn't have to be redrawn when the selection changes
224          */
225         private void createBackgroundImage()
226         {
227                 int width = getWidth();
228                 int height = getHeight();
229                 int x, y;
230                 int lastX = 0, lastY = 0;
231                 // Initialise image
232                 if (_image == null || _image.getWidth() != width || _image.getHeight() != height) {
233                         _image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
234                 }
235                 Graphics bufferedG = _image.getGraphics();
236                 super.paint(bufferedG);
237
238                 // Loop and show all points
239                 int numPoints = _track.getNumPoints();
240                 bufferedG.setColor(COLOR_POINT);
241                 int halfWidth = width/2;
242                 int halfHeight = height/2;
243                 boolean currPointTrackpoint = false, lastPointTrackpoint = false;
244                 for (int i=0; i<numPoints; i++)
245                 {
246                         x = halfWidth + (int) ((_track.getX(i) - _offsetX) / _scale * _zoomScale);
247                         y = halfHeight - (int) ((_track.getY(i) - _offsetY) / _scale * _zoomScale);
248                         if (x > BORDER_WIDTH && x < (width - BORDER_WIDTH)
249                                 && y < (height - BORDER_WIDTH) && y > BORDER_WIDTH)
250                         {
251                                 // draw block for point (a bit faster than circles)
252                                 bufferedG.drawRect(x - 2, y - 2, 3, 3);
253
254                                 // See whether to connect the point with previous one or not
255                                 currPointTrackpoint = !_track.getPoint(i).isWaypoint() && _track.getPoint(i).getPhoto() == null;
256                                 if (_connectPointsMenuItem.isSelected() && currPointTrackpoint && lastPointTrackpoint)
257                                 {
258                                         bufferedG.drawLine(lastX, lastY, x, y);
259                                 }
260                                 lastPointTrackpoint = currPointTrackpoint;
261                         }
262                         else {
263                                 lastPointTrackpoint = false;
264                         }
265                         lastX = x; lastY = y;
266                 }
267
268                 // Loop again and show waypoints with names
269                 bufferedG.setColor(COLOR_WAYPT_NAME);
270                 FontMetrics fm = bufferedG.getFontMetrics();
271                 int nameHeight = fm.getHeight();
272                 int numWaypointNamesShown = 0;
273                 for (int i=0; i<numPoints; i++)
274                 {
275                         DataPoint point = _track.getPoint(i);
276                         String waypointName = point.getWaypointName();
277                         if (waypointName != null && !waypointName.equals(""))
278                         {
279                                 // escape if nothing more to do
280                                 if (numWaypointNamesShown >= LIMIT_WAYPOINT_NAMES || _image == null) {break;}
281                                 // calculate coordinates of point
282                                 x = halfWidth + (int) ((_track.getX(i) - _offsetX) / _scale * _zoomScale);
283                                 y = halfHeight - (int) ((_track.getY(i) - _offsetY) / _scale * _zoomScale);
284                                 if (x > BORDER_WIDTH && x < (width - BORDER_WIDTH)
285                                                 && y < (height - BORDER_WIDTH) && y > BORDER_WIDTH)
286                                 {
287                                         bufferedG.fillOval(x - 3, y - 3, 6, 6);
288                                         // Figure out where to draw name so it doesn't obscure track
289                                         int nameWidth = fm.stringWidth(waypointName);
290                                         if (nameWidth < (width - 2 * BORDER_WIDTH))
291                                         {
292                                                 boolean drawnName = false;
293                                                 // Make arrays for coordinates right left up down
294                                                 int[] nameXs = {x + 2, x - nameWidth - 2, x - nameWidth/2, x - nameWidth/2};
295                                                 int[] nameYs = {y + (nameHeight/2), y + (nameHeight/2), y - 2, y + nameHeight + 2};
296                                                 for (int extraSpace = 4; extraSpace < 13 && !drawnName; extraSpace+=2)
297                                                 {
298                                                         // Shift arrays for coordinates right left up down
299                                                         nameXs[0] += 2; nameXs[1] -= 2;
300                                                         nameYs[2] -= 2; nameYs[3] += 2;
301                                                         // Check each direction in turn right left up down
302                                                         for (int a=0; a<4; a++)
303                                                         {
304                                                                 if (nameXs[a] > BORDER_WIDTH && (nameXs[a] + nameWidth) < (width - BORDER_WIDTH)
305                                                                         && nameYs[a] < (height - BORDER_WIDTH) && (nameYs[a] - nameHeight) > BORDER_WIDTH
306                                                                         && !overlapsPoints(nameXs[a], nameYs[a], nameWidth, nameHeight))
307                                                                 {
308                                                                         // Found a rectangle to fit - draw name here and quit
309                                                                         bufferedG.drawString(waypointName, nameXs[a], nameYs[a]);
310                                                                         drawnName = true;
311                                                                         break;
312                                                                 }
313                                                         }
314                                                 }
315                                         }
316                                 }
317                         }
318                 }
319                 bufferedG.dispose();
320         }
321
322
323         /**
324          * Tests whether there are any data points within the specified x,y rectangle
325          * @param inX left X coordinate
326          * @param inY bottom Y coordinate
327          * @param inWidth width of rectangle
328          * @param inHeight height of rectangle
329          * @return true if there's at least one data point in the rectangle
330          */
331         private boolean overlapsPoints(int inX, int inY, int inWidth, int inHeight)
332         {
333                 try
334                 {
335                         // loop over x coordinate of rectangle
336                         for (int x=0; x<inWidth; x++)
337                         {
338                                 // loop over y coordinate of rectangle
339                                 for (int y=0; y<inHeight; y++)
340                                 {
341                                         int pixelColor = _image.getRGB(inX + x, inY - y);
342                                         if (pixelColor != -1) return true;
343                                 }
344                         }
345                 }
346                 catch (NullPointerException e) {
347                         // ignore null pointers, just return false
348                 }
349                 return false;
350         }
351
352
353         /**
354          * Make the popup menu for right-clicking the map
355          */
356         private void makePopup()
357         {
358                 _popup = new JPopupMenu();
359                 JMenuItem zoomIn = new JMenuItem(I18nManager.getText("menu.map.zoomin"));
360                 zoomIn.addActionListener(new ActionListener() {
361                         public void actionPerformed(ActionEvent e)
362                         {
363                                 zoomMap(true);
364                         }});
365                 zoomIn.setEnabled(true);
366                 _popup.add(zoomIn);
367                 JMenuItem zoomOut = new JMenuItem(I18nManager.getText("menu.map.zoomout"));
368                 zoomOut.addActionListener(new ActionListener() {
369                         public void actionPerformed(ActionEvent e)
370                         {
371                                 zoomMap(false);
372                         }});
373                 zoomOut.setEnabled(true);
374                 _popup.add(zoomOut);
375                 JMenuItem zoomFull = new JMenuItem(I18nManager.getText("menu.map.zoomfull"));
376                 zoomFull.addActionListener(new ActionListener() {
377                         public void actionPerformed(ActionEvent e)
378                         {
379                                 zoomToFullScale();
380                         }});
381                 zoomFull.setEnabled(true);
382                 _popup.add(zoomFull);
383                 _connectPointsMenuItem = new JCheckBoxMenuItem(I18nManager.getText("menu.map.connect"));
384                 _connectPointsMenuItem.addActionListener(new ActionListener() {
385                         public void actionPerformed(ActionEvent e)
386                         {
387                                 // redraw map
388                                 dataUpdated(DataSubscriber.ALL);
389                         }
390                 });
391                 _connectPointsMenuItem.setSelected(false);
392                 _popup.add(_connectPointsMenuItem);
393                 _autoPanMenuItem = new JCheckBoxMenuItem(I18nManager.getText("menu.map.autopan"));
394                 _autoPanMenuItem.setSelected(true);
395                 _popup.add(_autoPanMenuItem);
396 /*
397                 JMenuItem mapItem = new JMenuItem("Show map");
398                 mapItem.addActionListener(new ActionListener() {
399                         public void actionPerformed(ActionEvent e)
400                         {
401                                 showMap();
402                         }
403                 });
404                 _popup.add(mapItem);
405 */
406         }
407
408
409         /**
410          * Zoom map to full scale
411          */
412         private void zoomToFullScale()
413         {
414                 _zoomScale = 1.0;
415                 _offsetX = 0.0;
416                 _offsetY = 0.0;
417                 _numPoints = 0;
418                 dataUpdated(DataSubscriber.ALL);
419         }
420
421
422         /**
423          * Zoom map either in or out by one step
424          * @param inZoomIn true to zoom in, false for out
425          */
426         private void zoomMap(boolean inZoomIn)
427         {
428                 if (inZoomIn)
429                 {
430                         // Zoom in
431                         _zoomScale *= ZOOM_SCALE_FACTOR;
432                 }
433                 else
434                 {
435                         // Zoom out
436                         _zoomScale /= ZOOM_SCALE_FACTOR;
437                         if (_zoomScale < 0.5) _zoomScale = 0.5;
438                 }
439                 _numPoints = 0;
440                 dataUpdated(DataSubscriber.ALL);
441         }
442
443
444         /**
445          * Pan the map by the specified amounts
446          * @param inUp upwards pan
447          * @param inRight rightwards pan
448          */
449         private void panMap(int inUp, int inRight)
450         {
451                 double panFactor = _scale / _zoomScale;
452                 _offsetY = _offsetY + (inUp * panFactor);
453                 _offsetX = _offsetX - (inRight * panFactor);
454                 // Limit pan to sensible range??
455                 _numPoints = 0;
456                 _image = null;
457                 repaint();
458         }
459
460
461         /**
462          * React to click on map display
463          * @param inE mouse event
464          */
465         public void mouseClicked(MouseEvent inE)
466         {
467                 this.requestFocus();
468                 if (_track != null)
469                 {
470                         int xClick = inE.getX();
471                         int yClick = inE.getY();
472                         // Check click is within main area (not in border)
473                         if (xClick > BORDER_WIDTH && yClick > BORDER_WIDTH && xClick < (getWidth() - BORDER_WIDTH)
474                                 && yClick < (getHeight() - BORDER_WIDTH))
475                         {
476                                 // Check left click or right click
477                                 if (inE.isMetaDown())
478                                 {
479                                         // Only show popup if track has data
480                                         if (_track != null && _track.getNumPoints() > 0)
481                                                 _popup.show(this, xClick, yClick);
482                                 }
483                                 else
484                                 {
485                                         // Find point within range of click point
486                                         double pointX = (xClick - getWidth()/2) * _scale / _zoomScale + _offsetX;
487                                         double pointY = (getHeight()/2 - yClick) * _scale / _zoomScale + _offsetY;
488                                         int selectedPointIndex = _track.getNearestPointIndex(
489                                                 pointX, pointY, CLICK_SENSITIVITY * _scale, false);
490                                         // Select the given point (or deselect if no point was found)
491                                         _trackInfo.getSelection().selectPoint(selectedPointIndex);
492                                 }
493                         }
494                 }
495         }
496
497
498         /**
499          * Respond to mouse released to reset dragging
500          * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
501          */
502         public void mouseReleased(MouseEvent e)
503         {
504                 _dragStartX = _dragStartY = -1;
505                 if (e.isMetaDown())
506                 {
507                         if (_zoomDragFromX >= 0 || _zoomDragFromY >= 0)
508                         {
509                                 // zoom area marked out - calculate offset and zoom
510                                 int xPan = (getWidth() - _zoomDragFromX - e.getX()) / 2;
511                                 int yPan = (getHeight() - _zoomDragFromY - e.getY()) / 2;
512                                 double xZoom = Math.abs(getWidth() * 1.0 / (e.getX() - _zoomDragFromX));
513                                 double yZoom = Math.abs(getHeight() * 1.0 / (e.getY() - _zoomDragFromY));
514                                 double extraZoom = (xZoom>yZoom?yZoom:xZoom);
515                                 // deselect point if selected (to stop autopan)
516                                 _trackInfo.getSelection().selectPoint(-1);
517                                 // Pan first to ensure pan occurs with correct scale
518                                 panMap(yPan, xPan);
519                                 // Then zoom in and request repaint
520                                 _zoomScale = _zoomScale * extraZoom;
521                                 _image = null;
522                                 repaint();
523                         }
524                         _zoomDragFromX = _zoomDragFromY = -1;
525                         _zoomDragging = false;
526                 }
527         }
528
529
530         /**
531          * Respond to mouse wheel events to zoom the map
532          * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent)
533          */
534         public void mouseWheelMoved(MouseWheelEvent e)
535         {
536                 zoomMap(e.getWheelRotation() < 0);
537         }
538
539
540         /**
541          * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
542          */
543         public void keyPressed(KeyEvent e)
544         {
545                 int code = e.getKeyCode();
546                 // Check for meta key
547                 if (e.isControlDown())
548                 {
549                         // Check for arrow keys to zoom in and out
550                         if (code == KeyEvent.VK_UP)
551                                 zoomMap(true);
552                         else if (code == KeyEvent.VK_DOWN)
553                                 zoomMap(false);
554                         // Key nav for next/prev point
555                         else if (code == KeyEvent.VK_LEFT)
556                                 _trackInfo.getSelection().selectPreviousPoint();
557                         else if (code == KeyEvent.VK_RIGHT)
558                                 _trackInfo.getSelection().selectNextPoint();
559                 }
560                 else
561                 {
562                         // Check for arrow keys to pan
563                         int upwardsPan = 0;
564                         if (code == KeyEvent.VK_UP)
565                                 upwardsPan = PAN_DISTANCE;
566                         else if (code == KeyEvent.VK_DOWN)
567                                 upwardsPan = -PAN_DISTANCE;
568                         int rightwardsPan = 0;
569                         if (code == KeyEvent.VK_RIGHT)
570                                 rightwardsPan = -PAN_DISTANCE;
571                         else if (code == KeyEvent.VK_LEFT)
572                                 rightwardsPan = PAN_DISTANCE;
573                         panMap(upwardsPan, rightwardsPan);
574                         // Check for delete key to delete current point
575                         if (code == KeyEvent.VK_DELETE && _trackInfo.getSelection().getCurrentPointIndex() >= 0)
576                         {
577                                 _app.deleteCurrentPoint();
578                                 // reset last selected point to trigger autopan
579                                 _lastSelectedPoint = -1;
580                         }
581                 }
582         }
583
584
585         /**
586          * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
587          */
588         public void keyReleased(KeyEvent e)
589         {
590                 // ignore
591         }
592
593
594         /**
595          * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
596          */
597         public void keyTyped(KeyEvent e)
598         {
599                 // ignore
600         }
601
602
603         /**
604          * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
605          */
606         public void mouseDragged(MouseEvent e)
607         {
608                 if (!e.isMetaDown())
609                 {
610                         if (_dragStartX > 0)
611                         {
612                                 int xShift = e.getX() - _dragStartX;
613                                 int yShift = e.getY() - _dragStartY;
614                                 panMap(yShift, xShift);
615                         }
616                         _dragStartX = e.getX();
617                         _dragStartY = e.getY();
618                 }
619                 else
620                 {
621                         // Right click-and-drag for zoom
622                         if (_zoomDragFromX < 0 || _zoomDragFromY < 0)
623                         {
624                                 _zoomDragFromX = e.getX();
625                                 _zoomDragFromY = e.getY();
626                         }
627                         else
628                         {
629                                 _zoomDragToX = e.getX();
630                                 _zoomDragToY = e.getY();
631                                 _zoomDragging = true;
632                         }
633                         repaint();
634                 }
635         }
636
637
638         /**
639          * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
640          */
641         public void mouseMoved(MouseEvent e)
642         {
643                 // ignore
644         }
645
646         /**
647          * Show a map window - probably only temporarily here until it gets fixed
648          */
649 /*
650         private void showMap()
651         {
652                 MapWindow map = new MapWindow(_track);
653                 map.show();
654         }
655 */
656 }