X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fgui%2Fmap%2FMapCanvas.java;h=d2f36ce165b45cfd5c315da68c6a70b5726a1f51;hb=1ee49ae3c8ef3aa2e63eadd458531e5f8bd4f92c;hp=e6236cde92a88dcba239635428519de6ba6e02a6;hpb=52bf9e8686c916be37a26a0b75340393d4478b05;p=GpsPrune.git diff --git a/tim/prune/gui/map/MapCanvas.java b/tim/prune/gui/map/MapCanvas.java index e6236cd..d2f36ce 100644 --- a/tim/prune/gui/map/MapCanvas.java +++ b/tim/prune/gui/map/MapCanvas.java @@ -27,7 +27,6 @@ import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JMenuItem; -import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSlider; @@ -36,8 +35,16 @@ import javax.swing.event.ChangeListener; import tim.prune.App; import tim.prune.DataSubscriber; +import tim.prune.FunctionLibrary; import tim.prune.I18nManager; +import tim.prune.UpdateMessageBroker; +import tim.prune.config.ColourScheme; +import tim.prune.config.Config; +import tim.prune.data.Coordinate; +import tim.prune.data.DataPoint; import tim.prune.data.DoubleRange; +import tim.prune.data.Latitude; +import tim.prune.data.Longitude; import tim.prune.data.Selection; import tim.prune.data.Track; import tim.prune.data.TrackInfo; @@ -53,6 +60,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe private App _app = null; /** Track object */ private Track _track = null; + /** TrackInfo object */ + private TrackInfo _trackInfo = null; /** Selection object */ private Selection _selection = null; /** Previously selected point */ @@ -63,6 +72,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe private BufferedImage _mapImage = null; /** Slider for transparency */ private JSlider _transparencySlider = null; + /** Checkbox for scale bar */ + private JCheckBox _scaleCheckBox = null; /** Checkbox for maps */ private JCheckBox _mapCheckBox = null; /** Checkbox for autopan */ @@ -75,6 +86,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe private JPanel _topPanel = null; /** Side component panel */ private JPanel _sidePanel = null; + /** Scale bar */ + private ScaleBar _scaleBar = null; /* Data */ private DoubleRange _latRange = null, _lonRange = null; private DoubleRange _xRange = null, _yRange = null; @@ -108,12 +121,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe private static final int AUTOPAN_DISTANCE = 75; // Colours - private static final Color COLOR_BG = Color.WHITE; - private static final Color COLOR_POINT = Color.BLUE; - private static final Color COLOR_CURR_RANGE = Color.GREEN; - private static final Color COLOR_CROSSHAIRS = Color.RED; - private static final Color COLOR_WAYPT_NAME = Color.BLACK; - private static final Color COLOR_PHOTO_PT = Color.ORANGE; + private static final Color COLOR_MESSAGES = Color.GRAY; /** @@ -124,6 +132,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe public MapCanvas(App inApp, TrackInfo inTrackInfo) { _app = inApp; + _trackInfo = inTrackInfo; _track = inTrackInfo.getTrack(); _selection = inTrackInfo.getSelection(); _mapPosition = new MapPosition(); @@ -146,7 +155,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe { _tileCacher.clearAll(); _recalculate = true; - repaint(); + Config.setConfigBoolean(Config.KEY_SHOW_MAP, e.getStateChange() == ItemEvent.SELECTED); + UpdateMessageBroker.informSubscribers(); // to let menu know } }; _topPanel = new JPanel(); @@ -167,6 +177,18 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe }); _transparencySlider.setFocusable(false); // stop slider from stealing keyboard focus _topPanel.add(_transparencySlider); + // Add checkbox button for enabling scale bar + _scaleCheckBox = new JCheckBox(IconManager.getImageIcon(IconManager.SCALEBAR_BUTTON), true); + _scaleCheckBox.setSelectedIcon(IconManager.getImageIcon(IconManager.SCALEBAR_BUTTON_ON)); + _scaleCheckBox.setOpaque(false); + _scaleCheckBox.setToolTipText(I18nManager.getText("menu.map.showscalebar")); + _scaleCheckBox.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + _scaleBar.setVisible(_scaleCheckBox.isSelected()); + } + }); + _scaleCheckBox.setFocusable(false); // stop button from stealing keyboard focus + _topPanel.add(_scaleCheckBox); // Add checkbox button for enabling maps or not _mapCheckBox = new JCheckBox(IconManager.getImageIcon(IconManager.MAP_BUTTON), false); _mapCheckBox.setSelectedIcon(IconManager.getImageIcon(IconManager.MAP_BUTTON_ON)); @@ -221,12 +243,16 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe zoomOutButton.setFocusable(false); // stop button from stealing keyboard focus _sidePanel.add(zoomOutButton); + // Bottom panel for scale bar + _scaleBar = new ScaleBar(); + // add control panels to this one setLayout(new BorderLayout()); _topPanel.setVisible(false); _sidePanel.setVisible(false); add(_topPanel, BorderLayout.NORTH); add(_sidePanel, BorderLayout.WEST); + add(_scaleBar, BorderLayout.SOUTH); // Make popup menu makePopup(); } @@ -264,13 +290,25 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe }}); zoomFullItem.setEnabled(true); _popup.add(zoomFullItem); + _popup.addSeparator(); + // Set background + JMenuItem setMapBgItem = new JMenuItem( + I18nManager.getText(FunctionLibrary.FUNCTION_SET_MAP_BG.getNameKey())); + setMapBgItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) + { + FunctionLibrary.FUNCTION_SET_MAP_BG.begin(); + }}); + _popup.add(setMapBgItem); // new point option JMenuItem newPointItem = new JMenuItem(I18nManager.getText("menu.map.newpoint")); newPointItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - _app.createPoint(MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(_popupMenuY, getHeight())), - MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(_popupMenuX, getWidth()))); + double lat = MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(_popupMenuY, getHeight())); + double lon = MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(_popupMenuX, getWidth())); + _app.createPoint(new DataPoint(new Latitude(lat, Coordinate.FORMAT_NONE), + new Longitude(lon, Coordinate.FORMAT_NONE), null)); }}); newPointItem.setEnabled(true); _popup.add(newPointItem); @@ -309,10 +347,10 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe if (_autopanCheckBox.isSelected()) { int selectedPoint = _selection.getCurrentPointIndex(); - if (selectedPoint > 0 && _dragFromX == -1 && selectedPoint != _prevSelectedPoint) + if (selectedPoint >= 0 && _dragFromX == -1 && selectedPoint != _prevSelectedPoint) { - int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(selectedPoint)); - int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(selectedPoint)); + int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(selectedPoint)); + int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(selectedPoint)); int panX = 0; int panY = 0; if (px < PAN_DISTANCE) { @@ -335,8 +373,10 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe } // Draw the mapImage if necessary - if ((_mapImage == null || _recalculate)) { + if ((_mapImage == null || _recalculate)) + { getMapTiles(); + _scaleBar.updateScale(_mapPosition.getZoom(), _mapPosition.getCentreTileY()); } // Draw the prepared image onto the panel if (_mapImage != null) { @@ -354,10 +394,11 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe } else { - inG.setColor(COLOR_BG); + inG.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_BACKGROUND)); inG.fillRect(0, 0, getWidth(), getHeight()); - inG.setColor(Color.GRAY); + inG.setColor(COLOR_MESSAGES); inG.drawString(I18nManager.getText("display.nodata"), 50, getHeight()/2); + _scaleBar.updateScale(-1, 0); } // Draw slider etc on top paintChildren(inG); @@ -376,14 +417,18 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe // Clear map Graphics g = _mapImage.getGraphics(); - // Clear to white - g.setColor(COLOR_BG); + // Clear to background + g.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_BACKGROUND)); g.fillRect(0, 0, getWidth(), getHeight()); + // Check whether maps are on or not + boolean showMap = Config.getConfigBoolean(Config.KEY_SHOW_MAP); + _mapCheckBox.setSelected(showMap); + // reset error message - if (!_mapCheckBox.isSelected()) {_shownOsmErrorAlready = false;} + if (!showMap) {_shownOsmErrorAlready = false;} // Only get map tiles if selected - if (_mapCheckBox.isSelected()) + if (showMap) { // init tile cacher _tileCacher.centreMap(_mapPosition.getZoom(), _mapPosition.getCentreTileX(), _mapPosition.getCentreTileY()); @@ -391,111 +436,179 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe boolean loadingFailed = false; if (_mapImage == null) return; - // Loop over tiles drawing each one - int[] tileIndices = _mapPosition.getTileIndices(getWidth(), getHeight()); - int[] pixelOffsets = _mapPosition.getDisplayOffsets(getWidth(), getHeight()); - for (int tileX = tileIndices[0]; tileX <= tileIndices[1] && !loadingFailed; tileX++) + if (_tileCacher.isOverzoomed()) + { + // display overzoom message + g.setColor(COLOR_MESSAGES); + g.drawString(I18nManager.getText("map.overzoom"), 50, getHeight()/2); + } + else { - int x = (tileX - tileIndices[0]) * 256 - pixelOffsets[0]; - for (int tileY = tileIndices[2]; tileY <= tileIndices[3]; tileY++) + // Loop over tiles drawing each one + int[] tileIndices = _mapPosition.getTileIndices(getWidth(), getHeight()); + int[] pixelOffsets = _mapPosition.getDisplayOffsets(getWidth(), getHeight()); + for (int tileX = tileIndices[0]; tileX <= tileIndices[1] && !loadingFailed; tileX++) { - int y = (tileY - tileIndices[2]) * 256 - pixelOffsets[1]; - Image image = _tileCacher.getTile(tileX, tileY); - if (image != null) { - g.drawImage(image, x, y, 256, 256, null); + int x = (tileX - tileIndices[0]) * 256 - pixelOffsets[0]; + for (int tileY = tileIndices[2]; tileY <= tileIndices[3]; tileY++) + { + int y = (tileY - tileIndices[2]) * 256 - pixelOffsets[1]; + Image image = _tileCacher.getTile(tileX, tileY); + if (image != null) { + g.drawImage(image, x, y, 256, 256, null); + } } } - } - // Make maps brighter / fainter - float[] scaleFactors = {1.0f, 1.05f, 1.1f, 1.2f, 1.6f, 2.0f}; - float scaleFactor = scaleFactors[_transparencySlider.getValue()]; - if (scaleFactor > 1.0f) { - RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - RescaleOp op = new RescaleOp(scaleFactor, 0, hints); - op.filter(_mapImage, _mapImage); + // Make maps brighter / fainter + float[] scaleFactors = {1.0f, 1.05f, 1.1f, 1.2f, 1.6f, 2.0f}; + float scaleFactor = scaleFactors[_transparencySlider.getValue()]; + if (scaleFactor > 1.0f) + { + RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + RescaleOp op = new RescaleOp(scaleFactor, 0, hints); + op.filter(_mapImage, _mapImage); + } } } + // Paint the track points on top + int pointsPainted = 1; + try + { + pointsPainted = paintPoints(g); + } + catch (NullPointerException npe) { // ignore, probably due to data being changed during drawing + } + + // free g + g.dispose(); + + _recalculate = false; + // Zoom to fit if no points found + if (pointsPainted <= 0 && _checkBounds) { + zoomToFit(); + _recalculate = true; + repaint(); + } + _checkBounds = false; + // enable / disable transparency slider + _transparencySlider.setEnabled(showMap); + } + + + /** + * Paint the points using the given graphics object + * @param inG Graphics object to use for painting + * @return number of points painted, if any + */ + private int paintPoints(Graphics inG) + { + // Set up colours + final Color pointColour = Config.getColourScheme().getColour(ColourScheme.IDX_POINT); + final Color rangeColour = Config.getColourScheme().getColour(ColourScheme.IDX_SELECTION); + final Color currentColour = Config.getColourScheme().getColour(ColourScheme.IDX_PRIMARY); + final Color secondColour = Config.getColourScheme().getColour(ColourScheme.IDX_SECONDARY); + final Color textColour = Config.getColourScheme().getColour(ColourScheme.IDX_TEXT); + int pointsPainted = 0; // draw track points - g.setColor(COLOR_POINT); + inG.setColor(pointColour); int prevX = -1, prevY = -1; boolean connectPoints = _connectCheckBox.isSelected(); + boolean prevPointVisible = false, currPointVisible = false; + boolean anyWaypoints = false; + boolean isWaypoint = false; for (int i=0; i<_track.getNumPoints(); i++) { - int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(i)); - int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(i)); - if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight()) + int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i)); + int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i)); + currPointVisible = px >= 0 && px < getWidth() && py >= 0 && py < getHeight(); + isWaypoint = _track.getPoint(i).isWaypoint(); + anyWaypoints = anyWaypoints || isWaypoint; + if (currPointVisible) { - if (!_track.getPoint(i).isWaypoint()) + if (!isWaypoint) { - g.drawRect(px-2, py-2, 3, 3); - // Connect track points - if (connectPoints && prevX != -1 && prevY != -1 && !_track.getPoint(i).getSegmentStart()) { - g.drawLine(prevX, prevY, px, py); + // Draw rectangle for track point + if (_track.getPoint(i).getDeleteFlag()) { + inG.setColor(currentColour); + } + else { + inG.setColor(pointColour); } + inG.drawRect(px-2, py-2, 3, 3); pointsPainted++; - prevX = px; prevY = py; } } - else { - prevX = -1; prevY = -1; + if (!isWaypoint) + { + // Connect track points if either of them are visible + if (connectPoints && (currPointVisible || prevPointVisible) + && !(prevX == -1 && prevY == -1) + && !_track.getPoint(i).getSegmentStart()) + { + inG.drawLine(prevX, prevY, px, py); + } + prevX = px; prevY = py; } + prevPointVisible = currPointVisible; } // Loop over points, just drawing blobs for waypoints - g.setColor(COLOR_WAYPT_NAME); - FontMetrics fm = g.getFontMetrics(); + inG.setColor(textColour); + FontMetrics fm = inG.getFontMetrics(); int nameHeight = fm.getHeight(); int width = getWidth(); int height = getHeight(); - for (int i=0; i<_track.getNumPoints(); i++) - { - if (_track.getPoint(i).isWaypoint()) + if (anyWaypoints) { + for (int i=0; i<_track.getNumPoints(); i++) { - int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(i)); - int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(i)); - if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight()) + if (_track.getPoint(i).isWaypoint()) { - g.fillRect(px-3, py-3, 6, 6); - pointsPainted++; + int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i)); + int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i)); + if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight()) + { + inG.fillRect(px-3, py-3, 6, 6); + pointsPainted++; + } } } - } - // Loop over points again, now draw names for waypoints - for (int i=0; i<_track.getNumPoints(); i++) - { - if (_track.getPoint(i).isWaypoint()) + // Loop over points again, now draw names for waypoints + for (int i=0; i<_track.getNumPoints(); i++) { - int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(i)); - int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(i)); - if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight()) + if (_track.getPoint(i).isWaypoint()) { - // Figure out where to draw waypoint name so it doesn't obscure track - String waypointName = _track.getPoint(i).getWaypointName(); - int nameWidth = fm.stringWidth(waypointName); - boolean drawnName = false; - // Make arrays for coordinates right left up down - int[] nameXs = {px + 2, px - nameWidth - 2, px - nameWidth/2, px - nameWidth/2}; - int[] nameYs = {py + (nameHeight/2), py + (nameHeight/2), py - 2, py + nameHeight + 2}; - for (int extraSpace = 4; extraSpace < 13 && !drawnName; extraSpace+=2) + int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i)); + int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i)); + if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight()) { - // Shift arrays for coordinates right left up down - nameXs[0] += 2; nameXs[1] -= 2; - nameYs[2] -= 2; nameYs[3] += 2; - // Check each direction in turn right left up down - for (int a=0; a<4; a++) + // Figure out where to draw waypoint name so it doesn't obscure track + String waypointName = _track.getPoint(i).getWaypointName(); + int nameWidth = fm.stringWidth(waypointName); + boolean drawnName = false; + // Make arrays for coordinates right left up down + int[] nameXs = {px + 2, px - nameWidth - 2, px - nameWidth/2, px - nameWidth/2}; + int[] nameYs = {py + (nameHeight/2), py + (nameHeight/2), py - 2, py + nameHeight + 2}; + for (int extraSpace = 4; extraSpace < 13 && !drawnName; extraSpace+=2) { - if (nameXs[a] > 0 && (nameXs[a] + nameWidth) < width - && nameYs[a] < height && (nameYs[a] - nameHeight) > 0 - && !overlapsPoints(nameXs[a], nameYs[a], nameWidth, nameHeight)) + // Shift arrays for coordinates right left up down + nameXs[0] += 2; nameXs[1] -= 2; + nameYs[2] -= 2; nameYs[3] += 2; + // Check each direction in turn right left up down + for (int a=0; a<4; a++) { - // Found a rectangle to fit - draw name here and quit - g.drawString(waypointName, nameXs[a], nameYs[a]); - drawnName = true; - break; + if (nameXs[a] > 0 && (nameXs[a] + nameWidth) < width + && nameYs[a] < height && (nameYs[a] - nameHeight) > 0 + && !overlapsPoints(nameXs[a], nameYs[a], nameWidth, nameHeight, textColour)) + { + // Found a rectangle to fit - draw name here and quit + inG.drawString(waypointName, nameXs[a], nameYs[a]); + drawnName = true; + break; + } } } } @@ -503,17 +616,17 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe } } // Loop over points, drawing blobs for photo points - g.setColor(COLOR_PHOTO_PT); + inG.setColor(secondColour); for (int i=0; i<_track.getNumPoints(); i++) { if (_track.getPoint(i).getPhoto() != null) { - int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(i)); - int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(i)); + int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i)); + int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i)); if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight()) { - g.drawRect(px-1, py-1, 2, 2); - g.drawRect(px-2, py-2, 4, 4); + inG.drawRect(px-1, py-1, 2, 2); + inG.drawRect(px-2, py-2, 4, 4); pointsPainted++; } } @@ -522,12 +635,12 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe // Draw selected range if (_selection.hasRangeSelected()) { - g.setColor(COLOR_CURR_RANGE); + inG.setColor(rangeColour); for (int i=_selection.getStart(); i<=_selection.getEnd(); i++) { - int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(i)); - int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(i)); - g.drawRect(px-1, py-1, 2, 2); + int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i)); + int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i)); + inG.drawRect(px-1, py-1, 2, 2); } } @@ -535,30 +648,18 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe int selectedPoint = _selection.getCurrentPointIndex(); if (selectedPoint >= 0) { - int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(selectedPoint)); - int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(selectedPoint)); - g.setColor(COLOR_CROSSHAIRS); + int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(selectedPoint)); + int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(selectedPoint)); + inG.setColor(currentColour); // crosshairs - g.drawLine(px, 0, px, getHeight()); - g.drawLine(0, py, getWidth(), py); + inG.drawLine(px, 0, px, getHeight()); + inG.drawLine(0, py, getWidth(), py); // oval - g.drawOval(px - 2, py - 2, 4, 4); - g.drawOval(px - 3, py - 3, 6, 6); - } - - // free g - g.dispose(); - - _recalculate = false; - // Zoom to fit if no points found - if (pointsPainted <= 0 && _checkBounds) { - zoomToFit(); - _recalculate = true; - repaint(); + inG.drawOval(px - 2, py - 2, 4, 4); + inG.drawOval(px - 3, py - 3, 6, 6); } - _checkBounds = false; - // enable / disable transparency slider - _transparencySlider.setEnabled(_mapCheckBox.isSelected()); + // Return the number of points painted + return pointsPainted; } @@ -568,12 +669,17 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe * @param inY bottom Y coordinate * @param inWidth width of rectangle * @param inHeight height of rectangle - * @return true if there's at least one data point in the rectangle + * @param inTextColour colour of text + * @return true if the rectangle overlaps stuff too close to the given colour */ - private boolean overlapsPoints(int inX, int inY, int inWidth, int inHeight) + private boolean overlapsPoints(int inX, int inY, int inWidth, int inHeight, Color inTextColour) { - // each of the colour channels must be brighter than this to count as empty - final int BRIGHTNESS_LIMIT = 210; + // each of the colour channels must be further away than this to count as empty + final int BRIGHTNESS_LIMIT = 80; + final int textRGB = inTextColour.getRGB(); + final int textLow = textRGB & 255; + final int textMid = (textRGB >> 8) & 255; + final int textHigh = (textRGB >> 16) & 255; try { // loop over x coordinate of rectangle @@ -584,11 +690,14 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe { int pixelColor = _mapImage.getRGB(inX + x, inY - y); // split into four components rgba - int lowestBit = pixelColor & 255; - int secondBit = (pixelColor >> 8) & 255; - int thirdBit = (pixelColor >> 16) & 255; + int pixLow = pixelColor & 255; + int pixMid = (pixelColor >> 8) & 255; + int pixHigh = (pixelColor >> 16) & 255; //int fourthBit = (pixelColor >> 24) & 255; // alpha ignored - if (lowestBit < BRIGHTNESS_LIMIT || secondBit < BRIGHTNESS_LIMIT || thirdBit < BRIGHTNESS_LIMIT) return true; + // If colours are too close in any channel then it's an overlap + if (Math.abs(pixLow-textLow) < BRIGHTNESS_LIMIT || + Math.abs(pixMid-textMid) < BRIGHTNESS_LIMIT || + Math.abs(pixHigh-textHigh) < BRIGHTNESS_LIMIT) {return true;} } } } @@ -601,22 +710,19 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe /** * Inform that tiles have been updated and the map can be repainted - * @param isOK true if data loaded ok, false for error + * @param inIsOk true if data loaded ok, false for error */ public synchronized void tilesUpdated(boolean inIsOk) { // Show message if loading failed (but not too many times) - if (!inIsOk && !_shownOsmErrorAlready) + if (!inIsOk && !_shownOsmErrorAlready && _mapCheckBox.isSelected()) { _shownOsmErrorAlready = true; // use separate thread to show message about failing to load osm images new Thread(new Runnable() { public void run() { try {Thread.sleep(500);} catch (InterruptedException ie) {} - JOptionPane.showMessageDialog(MapCanvas.this, - I18nManager.getText("error.osmimage.failed"), - I18nManager.getText("error.osmimage.dialogtitle"), - JOptionPane.ERROR_MESSAGE); + _app.showErrorMessage("error.osmimage.dialogtitle", "error.osmimage.failed"); } }).start(); } @@ -685,11 +791,17 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe // select point if it's a left-click if (!inE.isMetaDown()) { - int pointIndex = _track.getNearestPointIndexNew( + int pointIndex = _track.getNearestPointIndex( _mapPosition.getXFromPixels(inE.getX(), getWidth()), _mapPosition.getYFromPixels(inE.getY(), getHeight()), _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY), false); - _selection.selectPoint(pointIndex); + // Extend selection for shift-click + if (inE.isShiftDown()) { + _trackInfo.extendSelection(pointIndex); + } + else { + _trackInfo.selectPoint(pointIndex); + } } else { @@ -806,6 +918,9 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe if ((inUpdateType & DataSubscriber.DATA_ADDED_OR_REMOVED) > 0) { _checkBounds = true; } + if ((inUpdateType & DataSubscriber.MAPSERVER_CHANGED) > 0) { + _tileCacher.setTileConfig(new MapTileConfig()); + } repaint(); // enable or disable components boolean hasData = _track.getNumPoints() > 0; @@ -822,6 +937,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe public void keyPressed(KeyEvent inE) { int code = inE.getKeyCode(); + int currPointIndex = _selection.getCurrentPointIndex(); // Check for meta key if (inE.isControlDown()) { @@ -831,10 +947,10 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe else if (code == KeyEvent.VK_DOWN) zoomOut(); // Key nav for next/prev point - else if (code == KeyEvent.VK_LEFT) - _selection.selectPreviousPoint(); + else if (code == KeyEvent.VK_LEFT && currPointIndex > 0) + _trackInfo.selectPoint(currPointIndex-1); else if (code == KeyEvent.VK_RIGHT) - _selection.selectNextPoint(); + _trackInfo.selectPoint(currPointIndex+1); } else { @@ -851,7 +967,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe rightwardsPan = -PAN_DISTANCE; panMap(rightwardsPan, upwardsPan); // Check for delete key to delete current point - if (code == KeyEvent.VK_DELETE && _selection.getCurrentPointIndex() >= 0) + if (code == KeyEvent.VK_DELETE && currPointIndex >= 0) { _app.deleteCurrentPoint(); } @@ -885,4 +1001,12 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe else if (clicks > 0) zoomOut(); } + + /** + * @return current map position + */ + public MapPosition getMapPosition() + { + return _mapPosition; + } }