/** * Calculate and return the current selection rectangle * * @return A rectangle that spans from mousePos to mouseStartPos */ private Rectangle getSelectionRectangle() { int x = mousePosStart.x; int y = mousePosStart.y; int w = mousePos.x - mousePosStart.x; int h = mousePos.y - mousePosStart.y; if (w < 0) { x += w; w = -w; } if (h < 0) { y += h; h = -h; } if (aspectRatio) { /* Keep the aspect ratio by growing the rectangle; the * rectangle is always under the cursor. */ double aspectRatio = (double) nc.getWidth() / nc.getHeight(); if ((double) w / h < aspectRatio) { int neww = (int) (h * aspectRatio); if (mousePos.x < mousePosStart.x) { x += w - neww; } w = neww; } else { int newh = (int) (w / aspectRatio); if (mousePos.y < mousePosStart.y) { y += h - newh; } h = newh; } } return new Rectangle(x, y, w, h); }
private void paintLasso() { if (mousePos == null || mousePosStart == null || mousePos == mousePosStart) { return; } lasso.addPoint(mousePos.x, mousePos.y); nc.requestPaintPoly(lasso); }
/** * Register itself at the given event source. * * @param eventSource The emitter of the mouse events. * @param lassoMode {@code true} to enable lasso mode, {@code false} to disable it. */ public void register(NavigatableComponent eventSource, boolean lassoMode) { this.lassoMode = lassoMode; eventSource.addMouseListener(this); eventSource.addMouseMotionListener(this); selectionEndedListener.addPropertyChangeListener(this); eventSource.addPropertyChangeListener( "scale", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (mousePosStart != null) { paintRect(); mousePos = mousePosStart = null; } } }); }
/** Check the state of the keys and buttons and set the selection accordingly. */ @Override public void mouseReleased(MouseEvent e) { if (e.getButton() != MouseEvent.BUTTON1) return; if (mousePos == null || mousePosStart == null) return; // injected release from outside // disable the selection rect Rectangle r; if (!lassoMode) { nc.requestClearRect(); r = getSelectionRectangle(); lasso = rectToPolygon(r); } else { nc.requestClearPoly(); lasso.addPoint(mousePos.x, mousePos.y); r = lasso.getBounds(); } mousePosStart = null; mousePos = null; if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) == 0) { selectionEndedListener.selectionEnded(r, e); } }
@Override public void repaint(long tm, int x, int y, int width, int height) { // This is the main repaint method, all other methods are convenience methods and simply call // this method. // This is just an observation, not a must, but seems to be true for all implementations I found // so far. if (repaintListeners != null) { // Might get called early in super constructor for (RepaintListener l : repaintListeners) { l.repaint(tm, x, y, width, height); } } super.repaint(tm, x, y, width, height); }
/** * Return a list of all objects in the selection, respecting the different modifier. * * @param alt Whether the alt key was pressed, which means select all objects that are touched, * instead those which are completely covered. * @return The collection of selected objects. */ public Collection<OsmPrimitive> getSelectedObjects(boolean alt) { Collection<OsmPrimitive> selection = new LinkedList<>(); // whether user only clicked, not dragged. boolean clicked = false; Rectangle bounding = lasso.getBounds(); if (bounding.height <= 2 && bounding.width <= 2) { clicked = true; } if (clicked) { Point center = new Point(lasso.xpoints[0], lasso.ypoints[0]); OsmPrimitive osm = nc.getNearestNodeOrWay(center, OsmPrimitive.isSelectablePredicate, false); if (osm != null) { selection.add(osm); } } else { // nodes for (Node n : nc.getCurrentDataSet().getNodes()) { if (n.isSelectable() && lasso.contains(nc.getPoint2D(n))) { selection.add(n); } } // ways for (Way w : nc.getCurrentDataSet().getWays()) { if (!w.isSelectable() || w.getNodesCount() == 0) { continue; } if (alt) { for (Node n : w.getNodes()) { if (!n.isIncomplete() && lasso.contains(nc.getPoint2D(n))) { selection.add(w); break; } } } else { boolean allIn = true; for (Node n : w.getNodes()) { if (!n.isIncomplete() && !lasso.contains(nc.getPoint(n))) { allIn = false; break; } } if (allIn) { selection.add(w); } } } } return selection; }
/** Draws a selection rectangle on screen. */ private void paintRect() { if (mousePos == null || mousePosStart == null || mousePos == mousePosStart) return; nc.requestPaintRect(getSelectionRectangle()); }
/** Draw the component. */ @Override public void paint(Graphics g) { if (!prepareToDraw()) { return; } List<Layer> visibleLayers = getVisibleLayersInZOrder(); int nonChangedLayersCount = 0; for (Layer l : visibleLayers) { if (l.isChanged() || l == changedLayer) { break; } else { nonChangedLayersCount++; } } boolean canUseBuffer; synchronized (this) { canUseBuffer = !paintPreferencesChanged; paintPreferencesChanged = false; } canUseBuffer = canUseBuffer && nonChangedLayers.size() <= nonChangedLayersCount && lastViewID == getViewID() && lastClipBounds.contains(g.getClipBounds()); if (canUseBuffer) { for (int i = 0; i < nonChangedLayers.size(); i++) { if (visibleLayers.get(i) != nonChangedLayers.get(i)) { canUseBuffer = false; break; } } } if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth() || offscreenBuffer.getHeight() != getHeight()) { offscreenBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR); } Graphics2D tempG = offscreenBuffer.createGraphics(); tempG.setClip(g.getClip()); Bounds box = getLatLonBounds(g.getClipBounds()); if (!canUseBuffer || nonChangedLayersBuffer == null) { if (null == nonChangedLayersBuffer || nonChangedLayersBuffer.getWidth() != getWidth() || nonChangedLayersBuffer.getHeight() != getHeight()) { nonChangedLayersBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR); } Graphics2D g2 = nonChangedLayersBuffer.createGraphics(); g2.setClip(g.getClip()); g2.setColor(PaintColors.getBackgroundColor()); g2.fillRect(0, 0, getWidth(), getHeight()); for (int i = 0; i < nonChangedLayersCount; i++) { paintLayer(visibleLayers.get(i), g2, box); } } else { // Maybe there were more unchanged layers then last time - draw them to buffer if (nonChangedLayers.size() != nonChangedLayersCount) { Graphics2D g2 = nonChangedLayersBuffer.createGraphics(); g2.setClip(g.getClip()); for (int i = nonChangedLayers.size(); i < nonChangedLayersCount; i++) { paintLayer(visibleLayers.get(i), g2, box); } } } nonChangedLayers.clear(); changedLayer = null; for (int i = 0; i < nonChangedLayersCount; i++) { nonChangedLayers.add(visibleLayers.get(i)); } lastViewID = getViewID(); lastClipBounds = g.getClipBounds(); tempG.drawImage(nonChangedLayersBuffer, 0, 0, null); for (int i = nonChangedLayersCount; i < visibleLayers.size(); i++) { paintLayer(visibleLayers.get(i), tempG, box); } synchronized (temporaryLayers) { for (MapViewPaintable mvp : temporaryLayers) { mvp.paint(tempG, this, box); } } // draw world borders tempG.setColor(Color.WHITE); Bounds b = getProjection().getWorldBoundsLatLon(); double lat = b.getMinLat(); double lon = b.getMinLon(); Point p = getPoint(b.getMin()); GeneralPath path = new GeneralPath(); path.moveTo(p.x, p.y); double max = b.getMax().lat(); for (; lat <= max; lat += 1.0) { p = getPoint(new LatLon(lat >= max ? max : lat, lon)); path.lineTo(p.x, p.y); } lat = max; max = b.getMax().lon(); for (; lon <= max; lon += 1.0) { p = getPoint(new LatLon(lat, lon >= max ? max : lon)); path.lineTo(p.x, p.y); } lon = max; max = b.getMinLat(); for (; lat >= max; lat -= 1.0) { p = getPoint(new LatLon(lat <= max ? max : lat, lon)); path.lineTo(p.x, p.y); } lat = max; max = b.getMinLon(); for (; lon >= max; lon -= 1.0) { p = getPoint(new LatLon(lat, lon <= max ? max : lon)); path.lineTo(p.x, p.y); } int w = getWidth(); int h = getHeight(); // Work around OpenJDK having problems when drawing out of bounds final Area border = new Area(path); // Make the viewport 1px larger in every direction to prevent an // additional 1px border when zooming in final Area viewport = new Area(new Rectangle(-1, -1, w + 2, h + 2)); border.intersect(viewport); tempG.draw(border); if (Main.isDisplayingMapView() && Main.map.filterDialog != null) { Main.map.filterDialog.drawOSDText(tempG); } if (playHeadMarker != null) { playHeadMarker.paint(tempG, this); } g.drawImage(offscreenBuffer, 0, 0, null); super.paint(g); }