X-Git-Url: https://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fgui%2Fmap%2FMapCanvas.java;h=2717fcb66952417dc90189a95b49e75a963bc437;hb=c0387c124840c9407e040600fda88f3c3e8f6aa6;hp=2af4ae8e6a9a53c4561b89c62614debb9e9b718e;hpb=112bb0c9b46894adca9a33ed8c99ea712b253185;p=GpsPrune.git diff --git a/tim/prune/gui/map/MapCanvas.java b/tim/prune/gui/map/MapCanvas.java index 2af4ae8..2717fcb 100644 --- a/tim/prune/gui/map/MapCanvas.java +++ b/tim/prune/gui/map/MapCanvas.java @@ -37,7 +37,15 @@ 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.Checker; +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; @@ -59,8 +67,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe private Selection _selection = null; /** Previously selected point */ private int _prevSelectedPoint = -1; - /** Tile cacher */ - private MapTileCacher _tileCacher = new MapTileCacher(this); + /** Tile manager */ + private MapTileManager _tileManager = new MapTileManager(this); /** Image to display */ private BufferedImage _mapImage = null; /** Slider for transparency */ @@ -114,14 +122,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_MESSAGES = Color.GRAY; - private static final Color COLOR_POINT = Color.BLUE; - private static final Color COLOR_POINT_DELETED = Color.RED; - 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; /** @@ -153,9 +154,10 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe ItemListener mapCheckListener = new ItemListener() { public void itemStateChanged(ItemEvent e) { - _tileCacher.clearAll(); + _tileManager.clearMemoryCaches(); _recalculate = true; - repaint(); + Config.setConfigBoolean(Config.KEY_SHOW_MAP, e.getStateChange() == ItemEvent.SELECTED); + UpdateMessageBroker.informSubscribers(); // to let menu know } }; _topPanel = new JPanel(); @@ -304,8 +306,10 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe 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); @@ -369,10 +373,10 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe _prevSelectedPoint = selectedPoint; } - // Draw the mapImage if necessary + // Draw the map contents if necessary if ((_mapImage == null || _recalculate)) { - getMapTiles(); + paintMapContents(); _scaleBar.updateScale(_mapPosition.getZoom(), _mapPosition.getCentreTileY()); } // Draw the prepared image onto the panel @@ -391,7 +395,7 @@ 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_MESSAGES); inG.drawString(I18nManager.getText("display.nodata"), 50, getHeight()/2); @@ -403,9 +407,9 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe /** - * Get the map tiles for the current zoom level and given tile parameters + * Paint the map tiles and the points on to the _mapImage */ - private void getMapTiles() + private void paintMapContents() { if (_mapImage == null || _mapImage.getWidth() != getWidth() || _mapImage.getHeight() != getHeight()) { @@ -414,22 +418,27 @@ 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;} + _recalculate = false; // Only get map tiles if selected - if (_mapCheckBox.isSelected()) + if (showMap) { // init tile cacher - _tileCacher.centreMap(_mapPosition.getZoom(), _mapPosition.getCentreTileX(), _mapPosition.getCentreTileY()); + _tileManager.centreMap(_mapPosition.getZoom(), _mapPosition.getCentreTileX(), _mapPosition.getCentreTileY()); boolean loadingFailed = false; if (_mapImage == null) return; - if (_tileCacher.isOverzoomed()) + if (_tileManager.isOverzoomed()) { // display overzoom message g.setColor(COLOR_MESSAGES); @@ -437,6 +446,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe } else { + int numLayers = _tileManager.getNumLayers(); // Loop over tiles drawing each one int[] tileIndices = _mapPosition.getTileIndices(getWidth(), getHeight()); int[] pixelOffsets = _mapPosition.getDisplayOffsets(getWidth(), getHeight()); @@ -446,9 +456,13 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe 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); + // Loop over layers + for (int l=0; l= 0 && px < getWidth() && py >= 0 && py < getHeight(); + isWaypoint = _track.getPoint(i).isWaypoint(); + anyWaypoints = anyWaypoints || isWaypoint; if (currPointVisible) { - if (!_track.getPoint(i).isWaypoint()) + if (!isWaypoint) { // Draw rectangle for track point if (_track.getPoint(i).getDeleteFlag()) { - inG.setColor(COLOR_POINT_DELETED); + inG.setColor(currentColour); } else { - inG.setColor(COLOR_POINT); + inG.setColor(pointColour); } inG.drawRect(px-2, py-2, 3, 3); pointsPainted++; } } - if (!_track.getPoint(i).isWaypoint()) + if (!isWaypoint) { // Connect track points if either of them are visible if (connectPoints && (currPointVisible || prevPointVisible) @@ -539,56 +563,58 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe } // Loop over points, just drawing blobs for waypoints - inG.setColor(COLOR_WAYPT_NAME); + 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.getX(i)); - int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i)); - if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight()) + if (_track.getPoint(i).isWaypoint()) { - inG.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.getX(i)); - int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(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 - inG.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; + } } } } @@ -596,7 +622,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe } } // Loop over points, drawing blobs for photo points - inG.setColor(COLOR_PHOTO_PT); + inG.setColor(secondColour); for (int i=0; i<_track.getNumPoints(); i++) { if (_track.getPoint(i).getPhoto() != null) @@ -615,7 +641,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe // Draw selected range if (_selection.hasRangeSelected()) { - inG.setColor(COLOR_CURR_RANGE); + inG.setColor(rangeColour); for (int i=_selection.getStart(); i<=_selection.getEnd(); i++) { int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i)); @@ -630,7 +656,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe { int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(selectedPoint)); int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(selectedPoint)); - inG.setColor(COLOR_CROSSHAIRS); + inG.setColor(currentColour); // crosshairs inG.drawLine(px, 0, px, getHeight()); inG.drawLine(0, py, getWidth(), py); @@ -649,12 +675,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 @@ -665,11 +696,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;} } } } @@ -767,7 +801,13 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe _mapPosition.getXFromPixels(inE.getX(), getWidth()), _mapPosition.getYFromPixels(inE.getY(), getHeight()), _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY), false); - _trackInfo.selectPoint(pointIndex); + // Extend selection for shift-click + if (inE.isShiftDown()) { + _trackInfo.extendSelection(pointIndex); + } + else { + _trackInfo.selectPoint(pointIndex); + } } else { @@ -885,7 +925,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe _checkBounds = true; } if ((inUpdateType & DataSubscriber.MAPSERVER_CHANGED) > 0) { - _tileCacher.setTileConfig(new MapTileConfig()); + _tileManager.resetConfig(); } repaint(); // enable or disable components @@ -904,8 +944,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe { int code = inE.getKeyCode(); int currPointIndex = _selection.getCurrentPointIndex(); - // Check for meta key - if (inE.isControlDown()) + // Check for Ctrl key (for Linux/Win) or meta key (Clover key for Mac) + if (inE.isControlDown() || inE.isMetaDown()) { // Check for arrow keys to zoom in and out if (code == KeyEvent.VK_UP) @@ -917,6 +957,17 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe _trackInfo.selectPoint(currPointIndex-1); else if (code == KeyEvent.VK_RIGHT) _trackInfo.selectPoint(currPointIndex+1); + else if (code == KeyEvent.VK_PAGE_UP) + _trackInfo.selectPoint(Checker.getPreviousSegmentStart( + _trackInfo.getTrack(), _trackInfo.getSelection().getCurrentPointIndex())); + else if (code == KeyEvent.VK_PAGE_DOWN) + _trackInfo.selectPoint(Checker.getNextSegmentStart( + _trackInfo.getTrack(), _trackInfo.getSelection().getCurrentPointIndex())); + // Check for home and end + else if (code == KeyEvent.VK_HOME) + _trackInfo.selectPoint(0); + else if (code == KeyEvent.VK_END) + _trackInfo.selectPoint(_trackInfo.getTrack().getNumPoints()-1); } else { @@ -932,9 +983,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe else if (code == KeyEvent.VK_LEFT) rightwardsPan = -PAN_DISTANCE; panMap(rightwardsPan, upwardsPan); - // Check for delete key to delete current point - if (code == KeyEvent.VK_DELETE && currPointIndex >= 0) - { + // Check for backspace key to delete current point (delete key already handled by menu) + if (code == KeyEvent.VK_BACK_SPACE && currPointIndex >= 0) { _app.deleteCurrentPoint(); } }