Changeset 8550 in josm


Ignore:
Timestamp:
2015-07-01T20:20:33+02:00 (6 years ago)
Author:
bastiK
Message:

applied #11629 - Fixed state errors in selection (rect/lasso) and made them draw on a temporary layer; added polygon fill effect for lasso selection. (patch by michael2402)

Location:
trunk/src/org/openstreetmap/josm
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java

    r8540 r8550  
    586586
    587587        if (mode == Mode.SELECT) {
     588            if (e.getButton() != MouseEvent.BUTTON1) {
     589                return;
     590            }
     591            selectionManager.endSelecting(e);
    588592            selectionManager.unregister(mv);
    589593
  • trunk/src/org/openstreetmap/josm/gui/SelectionManager.java

    r8512 r8550  
    22package org.openstreetmap.josm.gui;
    33
    4 import java.awt.Component;
     4import java.awt.Color;
     5import java.awt.Graphics2D;
    56import java.awt.Point;
    67import java.awt.Polygon;
     
    1718import org.openstreetmap.josm.Main;
    1819import org.openstreetmap.josm.actions.SelectByInternalPointAction;
     20import org.openstreetmap.josm.data.Bounds;
    1921import org.openstreetmap.josm.data.osm.Node;
    2022import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2123import org.openstreetmap.josm.data.osm.Way;
     24import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
     25import org.openstreetmap.josm.gui.layer.MapViewPaintable;
     26import org.openstreetmap.josm.tools.Utils;
    2227
    2328/**
    24  * Manages the selection of a rectangle. Listening to left and right mouse button
     29 * Manages the selection of a rectangle or a lasso loop. Listening to left and right mouse button
    2530 * presses and to mouse motions and draw the rectangle accordingly.
    2631 *
    2732 * Left mouse button selects a rectangle from the press until release. Pressing
    28  * right mouse button while left is still pressed enable the rectangle to move
     33 * right mouse button while left is still pressed enable the selection area to move
    2934 * around. Releasing the left button fires an action event to the listener given
    3035 * at constructor, except if the right is still pressed, which just remove the
    3136 * selection rectangle and does nothing.
    3237 *
     38 * It is possible to switch between lasso selection and rectangle selection by using {@link #setLassoMode(boolean)}.
     39 *
    3340 * The point where the left mouse button was pressed and the current mouse
    3441 * position are two opposite corners of the selection rectangle.
    3542 *
    36  * It is possible to specify an aspect ratio (width per height) which the
     43 * For rectangle mode, it is possible to specify an aspect ratio (width per height) which the
    3744 * selection rectangle always must have. In this case, the selection rectangle
    3845 * will be the largest window with this aspect ratio, where the position the left
     
    5663        /**
    5764         * Called, when the left mouse button was released.
    58          * @param r The rectangle that is currently the selection.
     65         * @param r The rectangle that encloses the current selection.
    5966         * @param e The mouse event.
    6067         * @see InputEvent#getModifiersEx()
     68         * @see SelectionManager#getSelectedObjects(boolean)
    6169         */
    6270        void selectionEnded(Rectangle r, MouseEvent e);
     
    7583        void removePropertyChangeListener(PropertyChangeListener listener);
    7684    }
     85
     86    /**
     87     * This draws the selection hint (rectangle or lasso polygon) on the screen.
     88     *
     89     * @author Michael Zangl
     90     */
     91    private class SelectionHintLayer implements MapViewPaintable {
     92        @Override
     93        public void paint(Graphics2D g, MapView mv, Bounds bbox) {
     94            if (mousePos == null || mousePosStart == null || mousePos == mousePosStart)
     95                return;
     96            Color color = Utils.complement(PaintColors.getBackgroundColor());
     97            g.setColor(color);
     98            if (lassoMode) {
     99                g.drawPolygon(lasso);
     100
     101                g.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha() / 8));
     102                g.fillPolygon(lasso);
     103            } else {
     104                Rectangle paintRect = getSelectionRectangle();
     105                g.drawRect(paintRect.x, paintRect.y, paintRect.width, paintRect.height);
     106            }
     107        }
     108    }
     109
    77110    /**
    78111     * The listener that receives the events after left mouse button is released.
     
    81114    /**
    82115     * Position of the map when the mouse button was pressed.
    83      * If this is not <code>null</code>, a rectangle is drawn on screen.
     116     * If this is not <code>null</code>, a rectangle/lasso line is drawn on screen.
     117     * If this is <code>null</code>, no selection is active.
    84118     */
    85119    private Point mousePosStart;
    86120    /**
    87      * Position of the map when the selection rectangle was last drawn.
     121     * The last position of the mouse while the mouse button was pressed.
    88122     */
    89123    private Point mousePos;
    90124    /**
    91      * The Component, the selection rectangle is drawn onto.
     125     * The Component that provides us with OSM data and the aspect is taken from.
    92126     */
    93127    private final NavigatableComponent nc;
     
    98132    private boolean aspectRatio;
    99133
     134    /**
     135     * <code>true</code> if we should paint a lasso instead of a rectangle.
     136     */
    100137    private boolean lassoMode;
     138    /**
     139     * The polygon to store the selection outline if {@link #lassoMode} is used.
     140     */
    101141    private Polygon lasso = new Polygon();
     142
     143    /**
     144     * The result of the last selection.
     145     */
     146    private Polygon selectionResult = new Polygon();
     147
     148    private final SelectionHintLayer selectionHintLayer = new SelectionHintLayer();
    102149
    103150    /**
     
    108155     * @param aspectRatio If true, the selection window must obtain the aspect
    109156     *      ratio of the drawComponent.
    110      * @param navComp The component, the rectangle is drawn onto.
     157     * @param navComp The component that provides us with OSM data and the aspect is taken from.
    111158     */
    112159    public SelectionManager(SelectionEnded selectionEndedListener, boolean aspectRatio, NavigatableComponent navComp) {
     
    117164
    118165    /**
    119      * Register itself at the given event source.
     166     * Register itself at the given event source and add a hint layer.
    120167     * @param eventSource The emitter of the mouse events.
    121168     * @param lassoMode {@code true} to enable lasso mode, {@code false} to disable it.
    122169     */
    123     public void register(NavigatableComponent eventSource, boolean lassoMode) {
     170    public void register(MapView eventSource, boolean lassoMode) {
    124171       this.lassoMode = lassoMode;
    125172        eventSource.addMouseListener(this);
     
    129176            @Override
    130177            public void propertyChange(PropertyChangeEvent evt) {
    131                 if (mousePosStart != null) {
    132                     paintRect();
    133                     mousePos = mousePosStart = null;
    134                 }
     178                abortSelecting();
    135179            }
    136180        });
    137     }
    138     /**
    139      * Unregister itself from the given event source. If a selection rectangle is
    140      * shown, hide it first.
     181        eventSource.addTemporaryLayer(selectionHintLayer);
     182    }
     183    /**
     184     * Unregister itself from the given event source and hide the selection hint layer.
    141185     *
    142186     * @param eventSource The emitter of the mouse events.
    143187     */
    144     public void unregister(Component eventSource) {
     188    public void unregister(MapView eventSource) {
     189        abortSelecting();
     190        eventSource.removeTemporaryLayer(selectionHintLayer);
    145191        eventSource.removeMouseListener(this);
    146192        eventSource.removeMouseMotionListener(this);
     
    176222                mousePosStart = mousePos = e.getPoint();
    177223            }
    178             if (!lassoMode) {
    179                 paintRect();
    180             }
     224            selectionAreaChanged();
    181225        }
    182226
    183227        if (buttonPressed == MouseEvent.BUTTON1_DOWN_MASK) {
    184228            mousePos = e.getPoint();
    185             if (lassoMode) {
    186                 paintLasso();
    187             } else {
    188                 paintRect();
    189             }
     229            addLassoPoint(e.getPoint());
     230            selectionAreaChanged();
    190231        } else if (buttonPressed == (MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK)) {
    191             mousePosStart.x += e.getX()-mousePos.x;
    192             mousePosStart.y += e.getY()-mousePos.y;
     232            moveSelection(e.getX()-mousePos.x, e.getY()-mousePos.y);
    193233            mousePos = e.getPoint();
    194             paintRect();
    195         }
     234            selectionAreaChanged();
     235        }
     236    }
     237
     238    /**
     239     * Moves the current selection by some pixels.
     240     * @param dx How much to move it in x direction.
     241     * @param dy How much to move it in y direction.
     242     */
     243    private void moveSelection(int dx, int dy) {
     244        mousePosStart.x += dx;
     245        mousePosStart.y += dy;
     246        lasso.translate(dx, dy);
    196247    }
    197248
     
    201252    @Override
    202253    public void mouseReleased(MouseEvent e) {
    203         if (e.getButton() != MouseEvent.BUTTON1)
     254        if (e.getButton() == MouseEvent.BUTTON1) {
     255            endSelecting(e);
     256        }
     257    }
     258
     259    /**
     260     * Ends the selection of the current area. This simulates a release of mouse button 1.
     261     * @param e A mouse event that caused this. Needed for backward compatibility.
     262     */
     263    public void endSelecting(MouseEvent e) {
     264        mousePos = e.getPoint();
     265        if (lassoMode) {
     266            addLassoPoint(e.getPoint());
     267        }
     268
     269        // Left mouse was released while right is still pressed.
     270        boolean rightMouseStillPressed = (e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) != 0;
     271
     272        if (!rightMouseStillPressed) {
     273            selectingDone(e);
     274        }
     275        abortSelecting();
     276    }
     277
     278    private void addLassoPoint(Point point) {
     279        if (isNoSelection()) {
    204280            return;
    205         if (mousePos == null || mousePosStart == null)
    206             return; // injected release from outside
    207         // disable the selection rect
    208         Rectangle r;
    209         if (!lassoMode) {
    210             nc.requestClearRect();
    211             r = getSelectionRectangle();
    212 
    213             lasso = rectToPolygon(r);
    214         } else {
    215             nc.requestClearPoly();
    216             lasso.addPoint(mousePos.x, mousePos.y);
    217             r = lasso.getBounds();
    218         }
    219         mousePosStart = null;
    220         mousePos = null;
    221 
    222         if ((e.getModifiersEx() & MouseEvent.BUTTON3_DOWN_MASK) == 0) {
    223             selectionEndedListener.selectionEnded(r, e);
    224         }
    225     }
    226 
    227     /**
    228      * Draws a selection rectangle on screen.
    229      */
    230     private void paintRect() {
    231         if (mousePos == null || mousePosStart == null || mousePos == mousePosStart)
    232             return;
    233         nc.requestPaintRect(getSelectionRectangle());
    234     }
    235 
    236     private void paintLasso() {
    237         if (mousePos == null || mousePosStart == null || mousePos == mousePosStart) {
    238             return;
    239         }
    240         lasso.addPoint(mousePos.x, mousePos.y);
    241         nc.requestPaintPoly(lasso);
     281        }
     282        lasso.addPoint(point.x, point.y);
     283    }
     284
     285    private boolean isNoSelection() {
     286        return mousePos == null || mousePosStart == null || mousePos == mousePosStart;
    242287    }
    243288
     
    287332    @Override
    288333    public void propertyChange(PropertyChangeEvent evt) {
    289         if ("active".equals(evt.getPropertyName()) && !(Boolean) evt.getNewValue() && mousePosStart != null) {
    290             paintRect();
    291             mousePosStart = null;
    292             mousePos = null;
    293         }
    294     }
    295 
    296     /**
    297      * Return a list of all objects in the selection, respecting the different
     334        if ("active".equals(evt.getPropertyName()) && !(Boolean)evt.getNewValue()) {
     335            abortSelecting();
     336        }
     337    }
     338
     339    /**
     340     * Stores the  current selection and stores the result in {@link #selectionResult} to  be retrieved by {@link #getSelectedObjects(boolean)} later.
     341     * @param e The mouse event that caused the selection to be finished.
     342     */
     343    private void selectingDone(MouseEvent e) {
     344        if (isNoSelection()) {
     345            // Nothing selected.
     346            return;
     347        }
     348        Rectangle r;
     349        if (lassoMode) {
     350            r = lasso.getBounds();
     351
     352            selectionResult = new Polygon(lasso.xpoints, lasso.ypoints, lasso.npoints);
     353        } else {
     354            r = getSelectionRectangle();
     355
     356            selectionResult = rectToPolygon(r);
     357        }
     358        selectionEndedListener.selectionEnded(r, e);
     359    }
     360
     361    private void abortSelecting() {
     362        if (mousePosStart != null) {
     363            mousePos = mousePosStart = null;
     364            lasso.reset();
     365            selectionAreaChanged();
     366        }
     367    }
     368
     369    private void selectionAreaChanged() {
     370        // Trigger a redraw of the map view.
     371        // A nicer way would be to provide change events for the temporary layer.
     372        Main.map.mapView.repaint();
     373    }
     374
     375    /**
     376     * Return a list of all objects in the active/last selection, respecting the different
    298377     * modifier.
    299378     *
     
    308387        // whether user only clicked, not dragged.
    309388        boolean clicked = false;
    310         Rectangle bounding = lasso.getBounds();
     389        Rectangle bounding = selectionResult.getBounds();
    311390        if (bounding.height <= 2 && bounding.width <= 2) {
    312391            clicked = true;
     
    314393
    315394        if (clicked) {
    316             Point center = new Point(lasso.xpoints[0], lasso.ypoints[0]);
     395            Point center = new Point(selectionResult.xpoints[0], selectionResult.ypoints[0]);
    317396            OsmPrimitive osm = nc.getNearestNodeOrWay(center, OsmPrimitive.isSelectablePredicate, false);
    318397            if (osm != null) {
     
    322401            // nodes
    323402            for (Node n : nc.getCurrentDataSet().getNodes()) {
    324                 if (n.isSelectable() && lasso.contains(nc.getPoint2D(n))) {
     403                if (n.isSelectable() && selectionResult.contains(nc.getPoint2D(n))) {
    325404                    selection.add(n);
    326405                }
     
    334413                if (alt) {
    335414                    for (Node n : w.getNodes()) {
    336                         if (!n.isIncomplete() && lasso.contains(nc.getPoint2D(n))) {
     415                        if (!n.isIncomplete() && selectionResult.contains(nc.getPoint2D(n))) {
    337416                            selection.add(w);
    338417                            break;
     
    342421                    boolean allIn = true;
    343422                    for (Node n : w.getNodes()) {
    344                         if (!n.isIncomplete() && !lasso.contains(nc.getPoint(n))) {
     423                        if (!n.isIncomplete() && !selectionResult.contains(nc.getPoint(n))) {
    345424                            allIn = false;
    346425                            break;
Note: See TracChangeset for help on using the changeset viewer.