Changeset 4327 in josm


Ignore:
Timestamp:
Aug 21, 2011 1:12:53 PM (21 months 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.