Changeset 4327 in josm for trunk/src


Ignore:
Timestamp:
2011-08-21T13:12:53+02:00 (13 years ago)
Author:
xeen
Message:

updates visual appearance of highlights and adds them to select and delete action

in more detail:

  • add target highlighting to select action
  • add target cursor to select action
  • add target highlighting to delete action
  • unify ctrl/alt/shift modifier detection in MapMode actions
  • highlights are now a halo around the way/node instead of a color change
  • default highlight color is now the same as the select color (red)
  • ability to highlight WaySegments and VirtualNodes
  • various style/whitespace nits
  • fixes #2411

This patch touches a lot of areas, so please report any regressions in the map mode
tools. Also please add a comment to #2411 if you find to highlighting in select
mode distracting, so it can be fine tuned (or turned off by default).

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

Legend:

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

    r3919 r4327  
    66import java.awt.AWTEvent;
    77import java.awt.Cursor;
    8 import java.awt.EventQueue;
    98import java.awt.Toolkit;
    109import java.awt.event.AWTEventListener;
     
    1413import java.awt.event.MouseEvent;
    1514import java.util.Collections;
     15import java.util.HashSet;
     16import java.util.Set;
    1617
    1718import org.openstreetmap.josm.Main;
    1819import org.openstreetmap.josm.command.Command;
    1920import org.openstreetmap.josm.command.DeleteCommand;
     21import org.openstreetmap.josm.data.osm.DataSet;
    2022import org.openstreetmap.josm.data.osm.Node;
    2123import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    4547 * @author imi
    4648 */
    47 
    48 /**
    49  * This class contains stubs for highlighting affected primitives when affected.
    50  * However, way segments can be deleted as well, but cannot be highlighted
    51  * alone. If the highlight feature for this delete action is to be implemented
    52  * properly, highlighting way segments must be possible first. --xeen, 2009-09-02
    53  */
    5449public class DeleteAction extends MapMode implements AWTEventListener {
    5550    // Cache previous mouse event (needed when only the modifier keys are
    5651    // pressed but the mouse isn't moved)
    5752    private MouseEvent oldEvent = null;
     53
     54    /**
     55     * elements that have been highlighted in the previous iteration. Used
     56     * to remove the highlight from them again as otherwise the whole data
     57     * set would have to be checked.
     58     */
     59    private Set<OsmPrimitive> oldHighlights = new HashSet<OsmPrimitive>();
     60
     61    private boolean drawTargetHighlight;
    5862
    5963    private enum DeleteMode {
     
    101105            return;
    102106
     107        drawTargetHighlight = Main.pref.getBoolean("draw.target-highlight", true);
     108
    103109        Main.map.mapView.addMouseListener(this);
    104110        Main.map.mapView.addMouseMotionListener(this);
     
    120126            System.out.println(ex);
    121127        }
     128        removeHighlighting();
    122129    }
    123130
     
    157164    @Override public void mouseMoved(MouseEvent e) {
    158165        oldEvent = e;
    159         updateCursor(e, e.getModifiers());
     166        giveUserFeedback(e);
     167    }
     168
     169    /**
     170     * removes any highlighting that may have been set beforehand.
     171     */
     172    private void removeHighlighting() {
     173        for(OsmPrimitive prim : oldHighlights) {
     174            prim.setHighlighted(false);
     175        }
     176        oldHighlights = new HashSet<OsmPrimitive>();
     177        DataSet ds = getCurrentDataSet();
     178        if(ds != null) {
     179            ds.clearHighlightedWaySegments();
     180        }
     181    }
     182
     183    /**
     184     * handles everything related to highlighting primitives and way
     185     * segments for the given pointer position (via MouseEvent) and
     186     * modifiers.
     187     * @param e
     188     * @param modifiers
     189     */
     190    private void addHighlighting(MouseEvent e, int modifiers) {
     191        if(!drawTargetHighlight)
     192            return;
     193        removeHighlighting();
     194
     195        DeleteParameters parameters = getDeleteParameters(e, modifiers);
     196
     197        if(parameters.mode == DeleteMode.segment) {
     198            // deleting segments is the only action not working on OsmPrimitives
     199            // so we have to handle them separately.
     200            DataSet ds = getCurrentDataSet();
     201            if(ds != null) {
     202                ds.setHighlightedWaySegments(Collections.singleton(parameters.nearestSegment));
     203            }
     204        } else {
     205            // don't call buildDeleteCommands for DeleteMode.segment because it doesn't support
     206            // silent operation and SplitWayAction will show dialogs. A lot.
     207            Command delCmd = buildDeleteCommands(e, modifiers, true);
     208            if(delCmd == null) {
     209                Main.map.mapView.repaint();
     210                return;
     211            }
     212
     213            // all other cases delete OsmPrimitives directly, so we can
     214            // safely do the following
     215            for(OsmPrimitive osm : delCmd.getParticipatingPrimitives()) {
     216                osm.setHighlighted(true);
     217                oldHighlights.add(osm);
     218            }
     219        }
     220        Main.map.mapView.repaint();
    160221    }
    161222
    162223    /**
    163224     * This function handles all work related to updating the cursor and
    164      * highlights. For now, only the cursor is enabled because highlighting
    165      * requires WaySegment to be highlightable.
     225     * highlights
    166226     *
     227     * @param MouseEvent
     228     * @param int modifiers
     229     */
     230    private void updateCursor(MouseEvent e, int modifiers) {
     231        if (!Main.isDisplayingMapView())
     232            return;
     233        if(!Main.map.mapView.isActiveLayerVisible() || e == null)
     234            return;
     235
     236        DeleteParameters parameters = getDeleteParameters(e, modifiers);
     237        Main.map.mapView.setNewCursor(parameters.mode.cursor(), this);
     238    }
     239    /**
     240     * Gives the user feedback for the action he/she is about to do. Currently
     241     * calls the cursor and target highlighting routines. Allows for modifiers
     242     * not taken from the given mouse event.
     243     *
    167244     * Normally the mouse event also contains the modifiers. However, when the
    168245     * mouse is not moved and only modifier keys are pressed, no mouse event
     
    170247     * mouseevent. Instead we copy the previous event and only update the
    171248     * modifiers.
    172      *
    173      * @param MouseEvent
    174      * @param int modifiers
    175      */
    176     private void updateCursor(MouseEvent e, int modifiers) {
    177         if (!Main.isDisplayingMapView())
    178             return;
    179         if(!Main.map.mapView.isActiveLayerVisible() || e == null)
    180             return;
    181 
    182         DeleteParameters parameters = getDeleteParameters(e, modifiers);
    183         Main.map.mapView.setNewCursor(parameters.mode.cursor(), this);
     249     */
     250    private void giveUserFeedback(MouseEvent e, int modifiers) {
     251        updateCursor(e, modifiers);
     252        addHighlighting(e, modifiers);
     253    }
     254
     255    /**
     256     * Gives the user feedback for the action he/she is about to do. Currently
     257     * calls the cursor and target highlighting routines. Extracts modifiers
     258     * from mouse event.
     259     */
     260    private void giveUserFeedback(MouseEvent e) {
     261        giveUserFeedback(e, e.getModifiers());
    184262    }
    185263
     
    204282
    205283        getCurrentDataSet().setSelected();
     284        giveUserFeedback(e);
    206285        Main.map.mapView.repaint();
    207286    }
     
    242321
    243322    private DeleteParameters getDeleteParameters(MouseEvent e, int modifiers) {
    244         // Note: CTRL is the only modifier that is checked in MouseMove, don't
    245         // forget updating it there
    246         boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
    247         boolean shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
    248         boolean alt = (modifiers & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
     323        updateKeyModifiers(modifiers);
    249324
    250325        DeleteParameters result = new DeleteParameters();
     
    288363            return DeleteCommand.delete(getEditLayer(),Collections.singleton(parameters.nearestNode), false, silent);
    289364        case node_with_references:
    290             return DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(parameters.nearestNode));
     365            return DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(parameters.nearestNode), silent);
    291366        case segment:
    292367            return DeleteCommand.deleteWaySegment(getEditLayer(), parameters.nearestSegment);
     
    296371            return DeleteCommand.delete(getEditLayer(), Collections.singleton(parameters.nearestSegment.way), true, silent);
    297372        case way_with_references:
    298             return DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(parameters.nearestSegment.way),true);
     373            return DeleteCommand.deleteWithReferences(getEditLayer(), Collections.singleton(parameters.nearestSegment.way), true);
    299374        default:
    300375            return null;
     
    306381     */
    307382    public void eventDispatched(AWTEvent e) {
     383        if(e == null)
     384            return;
    308385        // We don't have a mouse event, so we pass the old mouse event but the
    309386        // new modifiers.
    310         updateCursor(oldEvent, ((InputEvent)e).getModifiers());
     387        giveUserFeedback(oldEvent, ((InputEvent) e).getModifiers());
    311388    }
    312389}
  • trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java

    r4191 r4327  
    99import java.awt.Color;
    1010import java.awt.Cursor;
    11 import java.awt.EventQueue;
    1211import java.awt.Graphics2D;
    1312import java.awt.Point;
    1413import java.awt.Toolkit;
    1514import java.awt.event.AWTEventListener;
    16 import java.awt.event.ActionEvent;
    1715import java.awt.event.InputEvent;
    1816import java.awt.event.KeyEvent;
     
    6664    private double PHI=Math.toRadians(90);
    6765
    68     private boolean ctrl;
    69     private boolean alt;
    70     private boolean shift;
    7166    private Node mouseOnExistingNode;
    7267    private Set<Way> mouseOnExistingWays = new HashSet<Way>();
     
    513508        getCurrentDataSet().setSelected(newSelection);
    514509
    515         // "viewport following" mode for tracing long features 
    516         // from aerial imagery or GPS tracks. 
     510        // "viewport following" mode for tracing long features
     511        // from aerial imagery or GPS tracks.
    517512        if (n != null && Main.map.mapView.viewportFollowing) {
    518513            Main.map.mapView.smoothScrollTo(n.getEastNorth());
     
    602597    }
    603598
    604     private void updateKeyModifiers(InputEvent e) {
    605         ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    606         alt = (e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
    607         shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    608     }
    609 
    610     private void updateKeyModifiers(MouseEvent e) {
    611         ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    612         alt = (e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
    613         shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    614     }
    615 
    616599    /**
    617600     * This method prepares data required for painting the "helper line" from
  • trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java

    r4142 r4327  
    185185            return;
    186186
     187        updateKeyModifiers(e);
     188
    187189        selectedSegment = Main.map.mapView.getNearestWaySegment(e.getPoint(), OsmPrimitive.isSelectablePredicate);
    188190
     
    192194            // Otherwise switch to another mode
    193195
    194             if ((e.getModifiers() & ActionEvent.CTRL_MASK) != 0) {
     196            if (ctrl) {
    195197                mode = Mode.translate;
    196             } else if ((e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0) {
     198            } else if (alt) {
    197199                mode = Mode.create_new;
    198200                // create a new segment and then select and extrude the new segment
     
    202204                mode = Mode.extrude;
    203205                getCurrentDataSet().setSelected(selectedSegment.way);
    204                 alwaysCreateNodes = ((e.getModifiers() & ActionEvent.SHIFT_MASK) != 0);
     206                alwaysCreateNodes = shift;
    205207            }
    206208
  • trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java

    r3919 r4327  
    44import java.awt.Cursor;
    55import java.awt.event.ActionEvent;
     6import java.awt.event.InputEvent;
    67import java.awt.event.MouseEvent;
    78import java.awt.event.MouseListener;
     
    2526abstract public class MapMode extends JosmAction implements MouseListener, MouseMotionListener {
    2627    protected final Cursor cursor;
     28    protected boolean ctrl;
     29    protected boolean alt;
     30    protected boolean shift;
    2731
    2832    /**
     
    7781    }
    7882
     83    protected void updateKeyModifiers(InputEvent e) {
     84        updateKeyModifiers(e.getModifiers());
     85    }
     86
     87    protected void updateKeyModifiers(MouseEvent e) {
     88        updateKeyModifiers(e.getModifiers());
     89    }
     90
     91    protected void updateKeyModifiers(int modifiers) {
     92        ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
     93        alt = (modifiers & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
     94        shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
     95    }
     96
    7997    public void mouseReleased(MouseEvent e) {}
    8098    public void mouseExited(MouseEvent e) {}
  • trunk/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java

    r4251 r4327  
    1414import java.awt.Toolkit;
    1515import java.awt.event.AWTEventListener;
    16 import java.awt.event.ActionEvent;
    1716import java.awt.event.InputEvent;
    1817import java.awt.event.KeyEvent;
     
    109108    private final MapView mv;
    110109
    111     private boolean ctrl;
    112     private boolean alt;
    113     private boolean shift;
    114 
    115110    // Mouse tracking state
    116111    private Point mousePressedPos;
     
    233228    private boolean updateModifiersState(InputEvent e) {
    234229        boolean oldAlt = alt, oldShift = shift, oldCtrl = ctrl;
    235         alt = (e.getModifiers() & (ActionEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0;
    236         ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    237         shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     230        updateKeyModifiers(e);
    238231        boolean changed = (oldAlt != alt || oldShift != shift || oldCtrl != ctrl);
    239232        return changed;
     
    394387            if (!isModifiersValidForDragMode())
    395388                return;
    396             if (!initParallelWays(mousePressedPos, copyTags)) {
     389            if (!initParallelWays(mousePressedPos, copyTags))
    397390                return;
    398             }
    399391            setMode(Mode.dragging);
    400392        }
     
    409401        double realD = mv.getProjection().eastNorth2latlon(enp).greatCircleDistance(mv.getProjection().eastNorth2latlon(nearestPointOnRefLine));
    410402        double snappedRealD = realD;
    411        
     403
    412404        // TODO: abuse of isToTheRightSideOfLine function.
    413405        boolean toTheRight = Geometry.isToTheRightSideOfLine(referenceSegment.getFirstNode(),
     
    431423        }
    432424        pWays.changeOffset(d);
    433        
     425
    434426        Main.map.statusLine.setDist(Math.abs(snappedRealD));
    435427        Main.map.statusLine.repaint();
  • trunk/src/org/openstreetmap/josm/actions/mapmode/PlayHeadDragMode.java

    r2808 r4327  
    66import java.awt.Cursor;
    77import java.awt.Point;
    8 import java.awt.event.ActionEvent;
    98import java.awt.event.MouseEvent;
    109
     
    2827    public PlayHeadDragMode(PlayHeadMarker m) {
    2928        super(tr("Drag play head"), "playheaddrag", tr("Drag play head"), null,
    30         Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
     29                Main.map, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    3130        playHeadMarker = m;
    3231    }
     
    6867        if (ev.getButton() != MouseEvent.BUTTON1 || p == null || ! dragging)
    6968            return;
    70         boolean shift = (ev.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     69
     70        updateKeyModifiers(ev);
     71
    7172        EastNorth en = Main.map.mapView.getEastNorth(ev.getX(), ev.getY());
    7273        if (! shift) {
  • trunk/src/org/openstreetmap/josm/actions/mapmode/SelectAction.java

    r4191 r4327  
    66import static org.openstreetmap.josm.tools.I18n.trn;
    77
     8import java.awt.AWTEvent;
    89import java.awt.Cursor;
    910import java.awt.Point;
    1011import java.awt.Rectangle;
     12import java.awt.Toolkit;
     13import java.awt.event.AWTEventListener;
    1114import java.awt.event.ActionEvent;
    1215import java.awt.event.InputEvent;
     
    1619import java.util.Collection;
    1720import java.util.Collections;
     21import java.util.HashSet;
    1822import java.util.Iterator;
    1923import java.util.LinkedList;
     24import java.util.Set;
    2025
    2126import javax.swing.JOptionPane;
     
    6065 * @author imi
    6166 */
    62 public class SelectAction extends MapMode implements SelectionEnded {
     67public class SelectAction extends MapMode implements AWTEventListener, SelectionEnded {
     68    // "select" means the selection rectangle and "move" means either dragging
     69    // or select if no mouse movement occurs (i.e. just clicking)
    6370    enum Mode { move, rotate, scale, select }
    64    
     71
     72    // contains all possible cases the cursor can be in the SelectAction except the
     73    // the move pointer (latter is a system one and not an image)
     74    private enum SelectActionCursor {
     75        rect("normal", "selection"),
     76        rect_add("normal", "select_add"),
     77        rect_rm("normal", "select_remove"),
     78        way("normal", "select_way"),
     79        way_add("normal", "select_way_add"),
     80        way_rm("normal", "select_way_remove"),
     81        node("normal", "select_node"),
     82        node_add("normal", "select_node_add"),
     83        node_rm("normal", "select_node_remove"),
     84        virtual_node("normal", "addnode"),
     85        scale("scale", null),
     86        rotate("rotate", null);
     87
     88        private final Cursor c;
     89        private SelectActionCursor(String main, String sub) {
     90            c = ImageProvider.getCursor(main, sub);
     91        }
     92        public Cursor cursor() {
     93            return c;
     94        }
     95    }
     96
     97    // Cache previous mouse event (needed when only the modifier keys are
     98    // pressed but the mouse isn't moved)
     99    private MouseEvent oldEvent = null;
     100
    65101    private Mode mode = null;
    66102    private SelectionManager selectionManager;
    67103    private boolean cancelDrawMode = false;
     104    private boolean drawTargetHighlight;
    68105    private boolean didMouseDrag = false;
    69106    /**
     
    94131    private int initialMoveThreshold;
    95132    private boolean initialMoveThresholdExceeded = false;
     133
     134    /**
     135     * elements that have been highlighted in the previous iteration. Used
     136     * to remove the highlight from them again as otherwise the whole data
     137     * set would have to be checked.
     138     */
     139    private Set<OsmPrimitive> oldHighlights = new HashSet<OsmPrimitive>();
    96140
    97141    /**
     
    109153        initialMoveDelay = Main.pref.getInteger("edit.initial-move-delay", 200);
    110154        initialMoveThreshold = Main.pref.getInteger("edit.initial-move-threshold", 5);
     155        drawTargetHighlight = Main.pref.getBoolean("draw.target-highlight", true);
     156        // This is required to update the cursors when ctrl/shift/alt is pressed
     157        try {
     158            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
     159        } catch (SecurityException ex) {
     160            System.out.println(ex);
     161        }
    111162    }
    112163
     
    127178        mv.removeMouseMotionListener(this);
    128179        mv.setVirtualNodesEnabled(false);
     180        removeHighlighting();
     181    }
     182
     183    /**
     184     * works out which cursor should be displayed for most of SelectAction's
     185     * features. The only exception is the "move" cursor when actually dragging
     186     * primitives.
     187     * @param nearbyStuff  primitives near the cursor
     188     * @return the cursor that should be displayed
     189     */
     190    private Cursor getCursor(Collection<OsmPrimitive> nearbyStuff) {
     191        String c = "rect";
     192        switch(mode) {
     193        case move:
     194            if(virtualNode != null) {
     195                c = "virtual_node";
     196                break;
     197            }
     198
     199            // nearbyStuff cannot be empty as otherwise we would be in
     200            // Move.select and not Move.move
     201            OsmPrimitive osm = nearbyStuff.iterator().next();
     202
     203            c = (osm instanceof Node) ? "node" : c;
     204            c = (osm instanceof Way) ? "way" : c;
     205
     206            if(shift) {
     207                c += "_add";
     208            } else if(ctrl) {
     209                c += osm.isSelected() ? "_rm" : "_add";
     210            }
     211            break;
     212        case rotate:
     213            c = "rotate";
     214            break;
     215        case scale:
     216            c = "scale";
     217            break;
     218        case select:
     219            c = "rect" + (shift ? "_add" : (ctrl ? "_rm" : ""));
     220            break;
     221        }
     222        return SelectActionCursor.valueOf(c).cursor();
     223    }
     224
     225    /**
     226     * Removes all existing highlights.
     227     * @return true if a repaint is required
     228     */
     229    private boolean removeHighlighting() {
     230        boolean needsRepaint = false;
     231        DataSet ds = getCurrentDataSet();
     232        if(ds != null && !ds.getHighlightedVirtualNodes().isEmpty()) {
     233            needsRepaint = true;
     234            ds.clearHighlightedVirtualNodes();
     235        }
     236        if(oldHighlights.isEmpty())
     237            return needsRepaint;
     238
     239        for(OsmPrimitive prim : oldHighlights) {
     240            prim.setHighlighted(false);
     241        }
     242        oldHighlights = new HashSet<OsmPrimitive>();
     243        return true;
     244    }
     245
     246    /**
     247     * handles adding highlights and updating the cursor for the given mouse event.
     248     * @param MouseEvent which should be used as base for the feedback
     249     * @return true if repaint is required
     250     */
     251    private boolean giveUserFeedback(MouseEvent e) {
     252        return giveUserFeedback(e, e.getModifiers());
     253    }
     254
     255    /**
     256     * handles adding highlights and updating the cursor for the given mouse event.
     257     * @param MouseEvent which should be used as base for the feedback
     258     * @param define custom keyboard modifiers if the ones from MouseEvent are outdated or similar
     259     * @return true if repaint is required
     260     */
     261    private boolean giveUserFeedback(MouseEvent e, int modifiers) {
     262        boolean needsRepaint = false;
     263
     264        Collection<OsmPrimitive> c = MapView.asColl(
     265                mv.getNearestNodeOrWay(e.getPoint(), OsmPrimitive.isSelectablePredicate, true));
     266
     267        updateKeyModifiers(modifiers);
     268        determineMapMode(!c.isEmpty());
     269
     270        if(drawTargetHighlight) {
     271            needsRepaint = removeHighlighting();
     272        }
     273
     274        virtualWays.clear();
     275        virtualNode = null;
     276        if(mode == Mode.move && setupVirtual(e)) {
     277            DataSet ds = getCurrentDataSet();
     278            if (ds != null) {
     279                ds.setHighlightedVirtualNodes(virtualWays);
     280            }
     281            mv.setNewCursor(SelectActionCursor.virtual_node.cursor(), this);
     282            // don't highlight anything else if a virtual node will be
     283            return true;
     284        }
     285
     286        mv.setNewCursor(getCursor(c), this);
     287
     288        // return early if there can't be any highlights
     289        if(!drawTargetHighlight || mode != Mode.move || c.isEmpty())
     290            return needsRepaint;
     291
     292        for(OsmPrimitive x : c) {
     293            // only highlight primitives that will change the selection
     294            // when clicked. I.e. don't highlight selected elements unless
     295            // we are in toggle mode.
     296            if(ctrl || !x.isSelected()) {
     297                x.setHighlighted(true);
     298                oldHighlights.add(x);
     299            }
     300        }
     301        return needsRepaint || !oldHighlights.isEmpty();
     302    }
     303
     304    /**
     305     * This is called whenever the keyboard modifier status changes
     306     */
     307    public void eventDispatched(AWTEvent e) {
     308        if(oldEvent == null)
     309            return;
     310        // We don't have a mouse event, so we pass the old mouse event but the
     311        // new modifiers.
     312        giveUserFeedback(oldEvent, ((InputEvent) e).getModifiers());
    129313    }
    130314
     
    264448    public void mouseMoved(MouseEvent e) {
    265449        // Mac OSX simulates with  ctrl + mouse 1  the second mouse button hence no dragging events get fired.
    266         //
    267450        if ((Main.platform instanceof PlatformHookOsx) && (mode == Mode.rotate || mode == Mode.scale)) {
    268451            mouseDragged(e);
    269         }
    270     }
     452            return;
     453        }
     454        oldEvent = e;
     455        if(giveUserFeedback(e)) {
     456            mv.repaint();
     457        }
     458    }
     459
     460    @Override
     461    public void mouseExited(MouseEvent e) {
     462        if(removeHighlighting()) {
     463            mv.repaint();
     464        }
     465    }
     466
    271467    private Node virtualNode = null;
    272468    private Collection<WaySegment> virtualWays = new LinkedList<WaySegment>();
     
    339535            Point p = e.getPoint();
    340536            boolean waitForMouseUp = Main.pref.getBoolean("mappaint.select.waits-for-mouse-up", false);
    341             boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    342             boolean alt = ((e.getModifiers() & (ActionEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0 || Main.pref.getBoolean("selectaction.cycles.multiple.matches", false));
     537            updateKeyModifiers(e);
     538            alt = alt || Main.pref.getBoolean("selectaction.cycles.multiple.matches", false);
    343539
    344540            if (!alt) {
     
    389585
    390586    /**
     587     * sets the mapmode according to key modifiers and if there are any
     588     * selectables nearby. Everything has to be pre-determined for this
     589     * function; its main purpose is to centralize what the modifiers do.
     590     * @param nearSelectables
     591     */
     592    private void determineMapMode(boolean hasSelectionNearby) {
     593        if (shift && ctrl) {
     594            mode = Mode.rotate;
     595        } else if (alt && ctrl) {
     596            mode = Mode.scale;
     597        } else if (hasSelectionNearby) {
     598            mode = Mode.move;
     599        } else {
     600            mode = Mode.select;
     601        }
     602    }
     603
     604    /**
    391605     * Look, whether any object is selected. If not, select the nearest node.
    392606     * If there are no nodes in the dataset, do nothing.
     
    400614    public void mousePressed(MouseEvent e) {
    401615        // return early
    402         if (!mv.isActiveLayerVisible() || !(Boolean) this.getValue("active") || e.getButton() != MouseEvent.BUTTON1) {
    403             return;
    404         }
     616        if (!mv.isActiveLayerVisible() || !(Boolean) this.getValue("active") || e.getButton() != MouseEvent.BUTTON1)
     617            return;
    405618
    406619        // request focus in order to enable the expected keyboard shortcuts
    407620        mv.requestFocus();
    408621
    409         boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    410         boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
    411         boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
     622        // update which modifiers are pressed (shift, alt, ctrl)
     623        updateKeyModifiers(e);
    412624
    413625        // We don't want to change to draw tool if the user tries to (de)select
     
    422634                mv.getNearestNodeOrWay(e.getPoint(), OsmPrimitive.isSelectablePredicate, true));
    423635
    424         if (shift && ctrl) {
    425             mode = Mode.rotate;
    426 
     636        determineMapMode(!c.isEmpty());
     637        switch(mode) {
     638        case rotate:
     639        case scale:
    427640            if (getCurrentDataSet().getSelected().isEmpty()) {
    428641                getCurrentDataSet().setSelected(c);
     
    432645            // Mode.move   redraws when mouseDragged is called
    433646            // Mode.rotate redraws here
    434             mv.setNewCursor(ImageProvider.getCursor("rotate", null), this);
    435             mv.repaint();
    436         } else if (alt && ctrl) {
    437             mode = Mode.scale;
    438 
    439             if (getCurrentDataSet().getSelected().isEmpty()) {
    440                 getCurrentDataSet().setSelected(c);
    441             }
    442 
    443             // Mode.select redraws when selectPrims is called
    444             // Mode.move   redraws when mouseDragged is called
    445647            // Mode.scale redraws here
    446             mv.setNewCursor(ImageProvider.getCursor("scale", null), this);
    447             mv.repaint();
    448         } else if (!c.isEmpty()) {
    449             mode = Mode.move;
    450 
     648            break;
     649        case move:
    451650            if (!cancelDrawMode && c.iterator().next() instanceof Way) {
    452651                setupVirtual(e);
     
    454653
    455654            selectPrims(cycleSetup(c, e), e, false, false);
    456         } else {
    457             mode = Mode.select;
    458 
     655            break;
     656        case select:
     657        default:
    459658            selectionManager.register(mv);
    460659            selectionManager.mousePressed(e);
    461         }
    462 
     660            break;
     661        }
     662        giveUserFeedback(e);
     663        mv.repaint();
    463664        updateStatusLine();
    464665    }
     
    466667    @Override
    467668    public void mouseReleased(MouseEvent e) {
    468         if (!mv.isActiveLayerVisible()) {
    469             return;
    470         }
     669        if (!mv.isActiveLayerVisible())
     670            return;
    471671
    472672        startingDraggingPos = null;
    473673
    474         mv.setNewCursor(cursor, this);
    475674        if (mode == Mode.select) {
    476675            selectionManager.unregister(mv);
     
    489688                virtualNode = null;
    490689
    491                 // do nothing if the click was to short to be recognized as a drag,
     690                // do nothing if the click was to short too be recognized as a drag,
    492691                // but the release position is farther than 10px away from the press position
    493                 if (lastMousePos.distanceSq(e.getPoint()) < 100) {
     692                if (lastMousePos == null || lastMousePos.distanceSq(e.getPoint()) < 100) {
    494693                    selectPrims(cyclePrims(cycleList, e), e, true, false);
    495694
     
    500699                        // click and switch back to SelectMode
    501700                        Main.worker.execute(new Runnable() {
    502 
    503701                            public void run() {
    504702                                Main.map.selectDrawTool(true);
     
    539737        }
    540738
    541         // I don't see why we need this.
    542         //updateStatusLine();
    543739        mode = null;
     740        giveUserFeedback(e);
    544741        updateStatusLine();
    545742    }
    546743
    547744    public void selectionEnded(Rectangle r, MouseEvent e) {
    548         boolean alt = (e.getModifiersEx() & (MouseEvent.ALT_DOWN_MASK | MouseEvent.ALT_GRAPH_DOWN_MASK)) != 0;
     745        updateKeyModifiers(e);
    549746        selectPrims(selectionManager.getObjectsInRectangle(r, alt), e, true, true);
    550747    }
     
    554751     * selection cycle given by <code>prims</code>.
    555752     * @param prims the primitives that form the selection cycle
    556      * @param shift whether shift is pressed
    557      * @param ctrl whether ctrl is pressed
     753     * @param mouse event
    558754     * @return the next element of cycle list <code>prims</code>.
    559755     */
     
    562758
    563759        if (prims.size() > 1) {
    564             boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    565             boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     760            updateKeyModifiers(e);
    566761
    567762            DataSet ds = getCurrentDataSet();
     
    630825
    631826    private void selectPrims(Collection<OsmPrimitive> prims, MouseEvent e, boolean released, boolean area) {
    632         boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
    633         boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
     827        updateKeyModifiers(e);
    634828        DataSet ds = getCurrentDataSet();
    635829
    636830        // not allowed together: do not change dataset selection, return early
    637         if ((shift && ctrl) || (ctrl && !released) || (!virtualWays.isEmpty())) {
    638             return;
    639         }
     831        if ((shift && ctrl) || (ctrl && !released) || (!virtualWays.isEmpty()))
     832            return;
    640833
    641834        if (!released) {
     
    666859    @Override
    667860    public String getModeHelpText() {
    668         if (mode == Mode.select) {
     861        if (mode == Mode.select)
    669862            return tr("Release the mouse button to select the objects in the rectangle.");
    670         } else if (mode == Mode.move) {
     863        else if (mode == Mode.move)
    671864            return tr("Release the mouse button to stop moving. Ctrl to merge with nearest node.");
    672         } else if (mode == Mode.rotate) {
     865        else if (mode == Mode.rotate)
    673866            return tr("Release the mouse button to stop rotating.");
    674         } else if (mode == Mode.scale) {
     867        else if (mode == Mode.scale)
    675868            return tr("Release the mouse button to stop scaling.");
    676         } else {
     869        else
    677870            return tr("Move objects by dragging; Shift to add to selection (Ctrl to toggle); Shift-Ctrl to rotate selected; Alt-Ctrl to scale selected; or change selection");
    678         }
    679871    }
    680872
  • trunk/src/org/openstreetmap/josm/data/osm/DataSet.java

    r4310 r4327  
    115115    private CopyOnWriteArrayList<DataSetListener> listeners = new CopyOnWriteArrayList<DataSetListener>();
    116116
     117    // provide means to highlight map elements that are not osm primitives
     118    private Collection<WaySegment> highlightedVirtualNodes = new LinkedList<WaySegment>();
     119    private Collection<WaySegment> highlightedWaySegments = new LinkedList<WaySegment>();
     120
    117121    // Number of open calls to beginUpdate
    118122    private int updateCount;
     
    431435
    432436    /**
     437     * returns an unmodifiable collection of *WaySegments* whose virtual
     438     * nodes should be highlighted. WaySegments are used to avoid having
     439     * to create a VirtualNode class that wouldn't have much purpose otherwise.
     440     *
     441     * @return unmodifiable collection of WaySegments
     442     */
     443    public Collection<WaySegment> getHighlightedVirtualNodes() {
     444        return Collections.unmodifiableCollection(highlightedVirtualNodes);
     445    }
     446
     447    /**
     448     * returns an unmodifiable collection of WaySegments that should be
     449     * highlighted.
     450     *
     451     * @return unmodifiable collection of WaySegments
     452     */
     453    public Collection<WaySegment> getHighlightedWaySegments() {
     454        return Collections.unmodifiableCollection(highlightedWaySegments);
     455    }
     456
     457    /**
    433458     * Replies an unmodifiable collection of primitives currently selected
    434459     * in this dataset. May be empty, but not null.
     
    505530        selectionSnapshot = null;
    506531        return true;
     532    }
     533
     534    /**
     535     * set what virtual nodes should be highlighted. Requires a Collection of
     536     * *WaySegments* to avoid a VirtualNode class that wouldn't have much use
     537     * otherwise.
     538     * @param Collection of waySegments
     539     */
     540    public void setHighlightedVirtualNodes(Collection<WaySegment> waySegments) {
     541        if(highlightedVirtualNodes.isEmpty() && waySegments.isEmpty())
     542            return;
     543
     544        highlightedVirtualNodes = waySegments;
     545        // can't use fireHighlightingChanged because it requires an OsmPrimitive
     546        highlightUpdateCount++;
     547    }
     548
     549    /**
     550     * set what virtual ways should be highlighted.
     551     * @param Collection of waySegments
     552     */
     553    public void setHighlightedWaySegments(Collection<WaySegment> waySegments) {
     554        if(highlightedWaySegments.isEmpty() && waySegments.isEmpty())
     555            return;
     556
     557        highlightedWaySegments = waySegments;
     558        // can't use fireHighlightingChanged because it requires an OsmPrimitive
     559        highlightUpdateCount++;
    507560    }
    508561
     
    590643        }
    591644        return changed;
     645    }
     646
     647    /**
     648     * clear all highlights of virtual nodes
     649     */
     650    public void clearHighlightedVirtualNodes() {
     651        setHighlightedVirtualNodes(new ArrayList<WaySegment>());
     652    }
     653
     654    /**
     655     * clear all highlights of way segments
     656     */
     657    public void clearHighlightedWaySegments() {
     658        setHighlightedWaySegments(new ArrayList<WaySegment>());
    592659    }
    593660
  • trunk/src/org/openstreetmap/josm/data/osm/WaySegment.java

    r3557 r4327  
    3030    }
    3131
     32    /**
     33     * returns this way segment as complete way.
     34     * @return
     35     */
     36    public Way toWay() {
     37        Way w = new Way();
     38        w.addNode(getFirstNode());
     39        w.addNode(getSecondNode());
     40        return w;
     41    }
     42
    3243    @Override public boolean equals(Object o) {
    3344        return o != null && o instanceof WaySegment
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java

    r4319 r4327  
    3535import org.openstreetmap.josm.data.osm.RelationMember;
    3636import org.openstreetmap.josm.data.osm.Way;
     37import org.openstreetmap.josm.data.osm.WaySegment;
    3738import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
    3839import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData;
    3940import org.openstreetmap.josm.gui.NavigatableComponent;
    4041import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle;
     42import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
     43import org.openstreetmap.josm.gui.mappaint.TextElement;
    4144import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle.HorizontalTextAlignment;
    4245import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle.VerticalTextAlignment;
    43 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
    4446import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.Symbol;
    45 import org.openstreetmap.josm.gui.mappaint.TextElement;
    4647import org.openstreetmap.josm.tools.ImageProvider;
    4748import org.openstreetmap.josm.tools.Pair;
     
    5354    private final boolean inactive;
    5455    private final MapPaintSettings settings;
     56    private final Collection<WaySegment> highlightWaySegments;
    5557
    5658    private final boolean useStrokes;
     
    6466    private final Color relationSelectedColor;
    6567    private final Color nodeColor;
     68    private final Color highlightColor;
     69    private final Color highlightColorTransparent;
    6670    private final Color backgroundColor;
    6771
     
    8185    public MapPainter(MapPaintSettings settings, Graphics2D g,
    8286            boolean inactive, NavigatableComponent nc, boolean virtual,
    83             double circum, boolean leftHandTraffic){
     87            double circum, boolean leftHandTraffic,
     88            Collection<WaySegment> highlightWaySegments){
    8489        this.settings = settings;
    8590        this.g = g;
    8691        this.inactive = inactive;
    8792        this.nc = nc;
     93        this.highlightWaySegments = highlightWaySegments;
    8894        this.useStrokes = settings.getUseStrokesDistance() > circum;
    8995        this.showNames = settings.getShowNamesDistance() > circum;
     
    96102        this.relationSelectedColor = PaintColors.RELATIONSELECTED.get();
    97103        this.nodeColor = PaintColors.NODE.get();
     104        this.highlightColor = PaintColors.HIGHLIGHT.get();
     105        this.highlightColorTransparent = new Color(highlightColor.getRed(), highlightColor.getGreen(), highlightColor.getBlue(), 100);
    98106        this.backgroundColor = PaintColors.getBackgroundColor();
    99107
     
    131139        List<Node> wayNodes = way.getNodes();
    132140        if (wayNodes.size() < 2) return;
    133        
    134         Iterator<Point> it = new OffsetIterator(way.getNodes(), offset);
     141
     142        // only highlight the segment if the way itself is not highlighted
     143        if(!way.isHighlighted()) {
     144            GeneralPath highlightSegs = null;
     145            for(WaySegment ws : highlightWaySegments) {
     146                if(ws.way != way || ws.lowerIndex < offset) {
     147                    continue;
     148                }
     149                if(highlightSegs == null) {
     150                    highlightSegs = new GeneralPath();
     151                }
     152
     153                Point p1 = nc.getPoint(ws.getFirstNode());
     154                Point p2 = nc.getPoint(ws.getSecondNode());
     155                highlightSegs.moveTo(p1.x, p1.y);
     156                highlightSegs.lineTo(p2.x, p2.y);
     157            }
     158
     159            drawPathHighlight(highlightSegs, line);
     160        }
     161
     162
     163        Iterator<Point> it = new OffsetIterator(wayNodes, offset);
    135164        while (it.hasNext()) {
    136165            Point p = it.next();
     
    209238            lastPoint = p;
    210239        }
     240        if(way.isHighlighted()) {
     241            drawPathHighlight(path, line);
     242        }
    211243        displaySegments(path, orientationArrows, onewayArrows, onewayArrowsCasing, color, line, dashes, dashedColor);
    212244    }
     
    221253     */
    222254    public class OffsetIterator implements Iterator<Point> {
    223        
     255
    224256        private List<Node> nodes;
    225257        private int offset;
    226258        private int idx;
    227        
     259
    228260        private Point prev = null;
    229261        /* 'prev0' is a point that has distance 'offset' from 'prev' and the
     
    238270            idx = 0;
    239271        }
    240        
     272
    241273        @Override
    242274        public boolean hasNext() {
     
    247279        public Point next() {
    248280            if (offset == 0) return nc.getPoint(nodes.get(idx++));
    249            
     281
    250282            Point current = nc.getPoint(nodes.get(idx));
    251            
     283
    252284            if (idx == nodes.size() - 1) {
    253285                ++idx;
     
    277309                int dx_prev = current.x - prev.x;
    278310                int dy_prev = current.y - prev.y;
    279                
     311
    280312                // determine intersection of the lines parallel to the two
    281313                // segments
    282314                int det = dx_next*dy_prev - dx_prev*dy_next;
    283                
     315
    284316                if (det == 0) {
    285317                    ++idx;
     
    292324                int m = dx_next*(y_current0 - y_prev0) - dy_next*(x_current0 - x_prev0);
    293325
    294                 int cx_ = x_prev0 + (int) Math.round(m * dx_prev / det);
    295                 int cy_ = y_prev0 + (int) Math.round(m * dy_prev / det);
     326                int cx_ = x_prev0 + Math.round(m * dx_prev / det);
     327                int cy_ = y_prev0 + Math.round(m * dy_prev / det);
    296328                ++idx;
    297329                prev = current;
     
    307339        }
    308340    }
    309    
     341
    310342    private void displaySegments(GeneralPath path, GeneralPath orientationArrows, GeneralPath onewayArrows, GeneralPath onewayArrowsCasing,
    311343            Color color, BasicStroke line, BasicStroke dashes, Color dashedColor) {
     
    337369        if(useStrokes) {
    338370            g.setStroke(new BasicStroke());
     371        }
     372    }
     373
     374    /**
     375     * highlights a given GeneralPath using the settings from BasicStroke to match the line's
     376     * style. Width of the highlight is hard coded.
     377     * @param path
     378     * @param line
     379     */
     380    private void drawPathHighlight(GeneralPath path, BasicStroke line) {
     381        if(path == null)
     382            return;
     383        g.setColor(highlightColorTransparent);
     384        float w = (line.getLineWidth() + 4);
     385        while(w >= line.getLineWidth()) {
     386            g.setStroke(new BasicStroke(w, line.getEndCap(), line.getLineJoin(), line.getMiterLimit()));
     387            g.draw(path);
     388            w -= 4;
    339389        }
    340390    }
     
    498548    public void drawNodeIcon(Node n, ImageIcon icon, float iconAlpha, boolean selected, boolean member) {
    499549        Point p = nc.getPoint(n);
    500         if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
    501 
    502         int w = icon.getIconWidth(), h=icon.getIconHeight();
     550
     551        final int w = icon.getIconWidth(), h=icon.getIconHeight();
     552        if(n.isHighlighted()) {
     553            drawPointHighlight(p, Math.max(w, h));
     554        }
     555
    503556        if (iconAlpha != 1f) {
    504557            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, iconAlpha));
     
    530583    public void drawNodeSymbol(Node n, Symbol s, Color fillColor, Color strokeColor) {
    531584        Point p = nc.getPoint(n);
    532         if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
    533585        int radius = s.size / 2;
     586
     587        if(n.isHighlighted()) {
     588            drawPointHighlight(p, s.size);
     589        }
    534590
    535591        if (fillColor != null) {
     
    612668     */
    613669    public void drawNode(Node n, Color color, int size, boolean fill) {
     670        if(size <= 0 && !n.isHighlighted())
     671            return;
     672
     673        Point p = nc.getPoint(n);
     674
     675        if(n.isHighlighted()) {
     676            drawPointHighlight(p, size);
     677        }
     678
    614679        if (size > 1) {
    615             Point p = nc.getPoint(n);
    616680            if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
    617681            int radius = size / 2;
     
    623687            }
    624688            if (fill) {
    625                 g.fillRect(p.x - radius, p.y - radius, size + 1, size + 1);
     689                g.fillRect(p.x-radius-1, p.y-radius-1, size + 1, size + 1);
    626690            } else {
    627                 g.drawRect(p.x - radius, p.y - radius, size, size);
    628             }
     691                g.drawRect(p.x-radius-1, p.y-radius-1, size, size);
     692            }
     693        }
     694    }
     695
     696    /**
     697     * highlights a given point by drawing a rounded rectangle around it. Give the
     698     * size of the object you want to be highlighted, width is added automatically.
     699     */
     700    private void drawPointHighlight(Point p, int size) {
     701        g.setColor(highlightColorTransparent);
     702        int s = size + 7;
     703        while(s >= size) {
     704            int r = (int) Math.floor(s/2);
     705            g.fillRoundRect(p.x-r, p.y-r, s, s, r, r);
     706            s -= 4;
    629707        }
    630708    }
     
    633711        if (!isShowNames() || bs == null)
    634712            return;
    635        
    636         Point p = nc.getPoint((Node) n);
     713
     714        Point p = nc.getPoint(n);
    637715        TextElement text = bs.text;
    638716        String s = text.labelCompositionStrategy.compose(n);
     
    823901
    824902    public void drawRestriction(Relation r, NodeElemStyle icon) {
    825 
    826903        Way fromWay = null;
    827904        Way toWay = null;
     
    9981075    }
    9991076
    1000     public void drawVirtualNodes(Collection<Way> ways) {
    1001 
    1002         if (virtualNodeSize != 0) {
    1003             GeneralPath path = new GeneralPath();
    1004             for (Way osm: ways){
    1005                 if (osm.isUsable() && !osm.isDisabled()) {
    1006                     visitVirtual(path, osm);
    1007                 }
    1008             }
    1009             g.setColor(nodeColor);
    1010             g.draw(path);
    1011         }
     1077    public void drawVirtualNodes(Collection<Way> ways, Collection<WaySegment> highlightVirtualNodes) {
     1078        if (virtualNodeSize == 0)
     1079            return;
     1080        // print normal virtual nodes
     1081        GeneralPath path = new GeneralPath();
     1082        for (Way osm: ways){
     1083            if (osm.isUsable() && !osm.isDisabled()) {
     1084                visitVirtual(path, osm);
     1085            }
     1086        }
     1087        g.setColor(nodeColor);
     1088        g.draw(path);
     1089        // print highlighted virtual nodes. Since only the color changes, simply
     1090        // drawing them over the existing ones works fine (at least in their current
     1091        // simple style)
     1092        path = new GeneralPath();
     1093        for (WaySegment wseg: highlightVirtualNodes){
     1094            if (wseg.way.isUsable() && !wseg.way.isDisabled()) {
     1095                visitVirtual(path, wseg.toWay());
     1096            }
     1097        }
     1098        g.setColor(highlightColor);
     1099        g.draw(path);
    10121100    }
    10131101
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/PaintColors.java

    r3896 r4327  
    1010import org.openstreetmap.josm.data.Preferences.ColorKey;
    1111import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
     12import org.openstreetmap.josm.gui.mappaint.StyleSource;
    1213import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.MapPaintSylesUpdateListener;
    13 import org.openstreetmap.josm.gui.mappaint.StyleSource;
    1414
    1515public enum PaintColors implements ColorKey {
     
    2626    INCOMPLETE_WAY(marktr("incomplete way"), new Color(0,0,96)), // darker blue
    2727    BACKGROUND(marktr("background"), Color.BLACK),
    28     HIGHLIGHT(marktr("highlight"), new Color(0, 255, 186)), // lighteal
     28    HIGHLIGHT(marktr("highlight"), SELECTED.get()),
    2929
    3030    UNTAGGED(marktr("untagged"),Color.GRAY),
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

    r4317 r4327  
    55import java.awt.RenderingHints;
    66import java.util.ArrayList;
     7import java.util.Collection;
    78import java.util.Collections;
    89import java.util.List;
     
    1617import org.openstreetmap.josm.data.osm.Relation;
    1718import org.openstreetmap.josm.data.osm.Way;
     19import org.openstreetmap.josm.data.osm.WaySegment;
    1820import org.openstreetmap.josm.gui.NavigatableComponent;
    1921import org.openstreetmap.josm.gui.mappaint.AreaElemStyle;
     
    220222                        RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
    221223
    222         this.painter = new MapPainter(paintSettings, g, isInactiveMode, nc, renderVirtualNodes, circum, leftHandTraffic);
     224        Collection<WaySegment> hws = data.getHighlightedWaySegments();
     225
     226        this.painter = new MapPainter(paintSettings, g, isInactiveMode, nc, renderVirtualNodes, circum, leftHandTraffic, hws);
    223227
    224228        StyleCollector sc = new StyleCollector(drawArea, drawMultipolygon, drawRestriction);
     
    229233        sc.drawAll();
    230234        sc = null;
    231         painter.drawVirtualNodes(data.searchWays(bbox));
     235        painter.drawVirtualNodes(data.searchWays(bbox), data.getHighlightedVirtualNodes());
    232236
    233237        //long now = System.currentTimeMillis();
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/WireframeMapRenderer.java

    r4087 r4327  
    2525import org.openstreetmap.josm.data.osm.RelationMember;
    2626import org.openstreetmap.josm.data.osm.Way;
     27import org.openstreetmap.josm.data.osm.WaySegment;
    2728import org.openstreetmap.josm.data.osm.visitor.Visitor;
    2829import org.openstreetmap.josm.gui.NavigatableComponent;
     
    168169            }
    169170        }
    170         drawVirtualNodes(data.searchWays(bbox));
     171        drawVirtualNodes(data.searchWays(bbox), data.getHighlightedVirtualNodes());
     172
     173        // draw highlighted way segments over the already drawn ways. Otherwise each
     174        // way would have to be checked if it contains a way segment to highlight when
     175        // in most of the cases there won't be more than one segment. Since the wireframe
     176        // renderer does not feature any transparency there should be no visual difference.
     177        for(final WaySegment wseg : data.getHighlightedWaySegments()) {
     178            drawSegment(nc.getPoint(wseg.getFirstNode()), nc.getPoint(wseg.getSecondNode()), highlightColor, false);
     179        }
     180        displaySegments();
    171181    }
    172182
     
    228238    }
    229239
    230     public void drawVirtualNodes(Collection<Way> ways) {
    231 
    232         if (virtualNodeSize != 0) {
    233             GeneralPath path = new GeneralPath();
    234             for (Way osm: ways){
    235                 if (osm.isUsable() && !osm.isDisabledAndHidden() && !osm.isDisabled()) {
    236                     visitVirtual(path, osm);
    237                 }
    238             }
    239             g.setColor(nodeColor);
    240             g.draw(path);
    241         }
     240    public void drawVirtualNodes(Collection<Way> ways, Collection<WaySegment> highlightVirtualNodes) {
     241        if (virtualNodeSize == 0)
     242            return;
     243        // print normal virtual nodes
     244        GeneralPath path = new GeneralPath();
     245        for (Way osm : ways) {
     246            if (osm.isUsable() && !osm.isDisabledAndHidden() && !osm.isDisabled()) {
     247                visitVirtual(path, osm);
     248            }
     249        }
     250        g.setColor(nodeColor);
     251        g.draw(path);
     252        // print highlighted virtual nodes. Since only the color changes, simply
     253        // drawing them over the existing ones works fine (at least in their current
     254        // simple style)
     255        path = new GeneralPath();
     256        for (WaySegment wseg: highlightVirtualNodes){
     257            if (wseg.way.isUsable() && !wseg.way.isDisabled()) {
     258                visitVirtual(path, wseg.toWay());
     259            }
     260        }
     261        g.setColor(highlightColor);
     262        g.draw(path);
    242263    }
    243264
  • trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java

    r4316 r4327  
    221221
    222222        Color myColor = color;
    223         if(w.isHighlighted()) {
    224             myColor = paintSettings.getHighlightColor();
    225         } else if (selected) {
     223        if (selected) {
    226224            myColor = paintSettings.getSelectedColor(color.getAlpha());
    227225        } else if (member) {
     
    292290            '}';
    293291    }
    294    
     292
    295293    public String linejoinToString(int linejoin) {
    296294        switch (linejoin) {
  • trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java

    r4319 r4327  
    111111            symbol = createSymbol(env);
    112112        }
    113        
     113
    114114        // optimization: if we neither have a symbol, nor an icon
    115115        // we don't have to check for the remaining style properties and we don't
     
    243243                Color fillColor = symbol.fillColor;
    244244                if (fillColor != null) {
    245                     if (n.isHighlighted()) {
    246                         fillColor = settings.getHighlightColor();
    247                     } else {
    248                         if (painter.isInactiveMode() || n.isDisabled()) {
    249                             fillColor = settings.getInactiveColor();
    250                         } else if (selected) {
    251                             fillColor = settings.getSelectedColor(fillColor.getAlpha());
    252                         } else if (member) {
    253                             fillColor = settings.getRelationSelectedColor(fillColor.getAlpha());
    254                         }
     245                    if (painter.isInactiveMode() || n.isDisabled()) {
     246                        fillColor = settings.getInactiveColor();
     247                    } else if (selected) {
     248                        fillColor = settings.getSelectedColor(fillColor.getAlpha());
     249                    } else if (member) {
     250                        fillColor = settings.getRelationSelectedColor(fillColor.getAlpha());
    255251                    }
    256252                }
    257253                Color strokeColor = symbol.strokeColor;
    258254                if (strokeColor != null) {
    259                     if (n.isHighlighted()) {
    260                         strokeColor = settings.getHighlightColor();
    261                     } else {
    262                         if (painter.isInactiveMode() || n.isDisabled()) {
    263                             strokeColor = settings.getInactiveColor();
    264                         } else if (selected) {
    265                             strokeColor = settings.getSelectedColor(strokeColor.getAlpha());
    266                         } else if (member) {
    267                             strokeColor = settings.getRelationSelectedColor(strokeColor.getAlpha());
    268                         }
     255                    if (painter.isInactiveMode() || n.isDisabled()) {
     256                        strokeColor = settings.getInactiveColor();
     257                    } else if (selected) {
     258                        strokeColor = settings.getSelectedColor(strokeColor.getAlpha());
     259                    } else if (member) {
     260                        strokeColor = settings.getRelationSelectedColor(strokeColor.getAlpha());
    269261                    }
    270262                }
    271263                painter.drawNodeSymbol(n, symbol, fillColor, strokeColor);
    272264            } else {
    273                 if (n.isHighlighted()) {
    274                     painter.drawNode(n, settings.getHighlightColor(), settings.getSelectedNodeSize(), settings.isFillSelectedNode());
     265                Color color;
     266                boolean isConnection = n.isConnectionNode();
     267
     268                if (painter.isInactiveMode() || n.isDisabled()) {
     269                    color = settings.getInactiveColor();
     270                } else if (selected) {
     271                    color = settings.getSelectedColor();
     272                } else if (member) {
     273                    color = settings.getRelationSelectedColor();
     274                } else if (isConnection) {
     275                    if (n.isTagged()) {
     276                        color = settings.getTaggedConnectionColor();
     277                    } else {
     278                        color = settings.getConnectionColor();
     279                    }
    275280                } else {
    276                     Color color;
    277                     boolean isConnection = n.isConnectionNode();
    278 
    279                     if (painter.isInactiveMode() || n.isDisabled()) {
    280                         color = settings.getInactiveColor();
    281                     } else if (selected) {
    282                         color = settings.getSelectedColor();
    283                     } else if (member) {
    284                         color = settings.getRelationSelectedColor();
    285                     } else if (isConnection) {
    286                         if (n.isTagged()) {
    287                             color = settings.getTaggedConnectionColor();
    288                         } else {
    289                             color = settings.getConnectionColor();
    290                         }
     281                    if (n.isTagged()) {
     282                        color = settings.getTaggedColor();
    291283                    } else {
    292                         if (n.isTagged()) {
    293                             color = settings.getTaggedColor();
    294                         } else {
    295                             color = settings.getNodeColor();
    296                         }
     284                        color = settings.getNodeColor();
    297285                    }
    298 
    299                     final int size = Utils.max((selected ? settings.getSelectedNodeSize() : 0),
    300                             (n.isTagged() ? settings.getTaggedNodeSize() : 0),
    301                             (isConnection ? settings.getConnectionNodeSize() : 0),
    302                             settings.getUnselectedNodeSize());
    303 
    304                     final boolean fill = (selected && settings.isFillSelectedNode()) ||
    305                             (n.isTagged() && settings.isFillTaggedNode()) ||
    306                             (isConnection && settings.isFillConnectionNode()) ||
    307                             settings.isFillUnselectedNode();
    308 
    309                     painter.drawNode(n, color, size, fill);
    310286                }
     287
     288                final int size = Utils.max((selected ? settings.getSelectedNodeSize() : 0),
     289                        (n.isTagged() ? settings.getTaggedNodeSize() : 0),
     290                        (isConnection ? settings.getConnectionNodeSize() : 0),
     291                        settings.getUnselectedNodeSize());
     292
     293                final boolean fill = (selected && settings.isFillSelectedNode()) ||
     294                (n.isTagged() && settings.isFillTaggedNode()) ||
     295                (isConnection && settings.isFillConnectionNode()) ||
     296                settings.isFillUnselectedNode();
     297
     298                painter.drawNode(n, color, size, fill);
     299
    311300            }
    312301        } else if (primitive instanceof Relation && icon != null) {
     
    322311        return disabledIcon = new ImageIcon(GrayFilter.createDisabledImage(icon.getImage()));
    323312    }
    324    
     313
    325314    public Rectangle getBox() {
    326315        if (icon != null) {
Note: See TracChangeset for help on using the changeset viewer.