Index: trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 4781)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 4782)
@@ -2,7 +2,9 @@
 package org.openstreetmap.josm.actions.mapmode;
 
+import javax.swing.JCheckBoxMenuItem;
 import static org.openstreetmap.josm.tools.I18n.tr;
 import static org.openstreetmap.josm.tools.I18n.trn;
 import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
 
 import java.awt.AWTEvent;
@@ -16,4 +18,5 @@
 import java.awt.event.AWTEventListener;
 import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
@@ -32,9 +35,12 @@
 import java.util.Set;
 
+import java.util.TreeSet;
 import javax.swing.AbstractAction;
 import javax.swing.JOptionPane;
 
 import javax.swing.SwingUtilities;
+import javax.swing.Timer;
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.command.AddCommand;
 import org.openstreetmap.josm.command.ChangeCommand;
@@ -51,4 +57,5 @@
 import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
+import org.openstreetmap.josm.gui.MainMenu;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.MapView;
@@ -90,5 +97,6 @@
     private Shortcut backspaceShortcut;
     
-    boolean snapOn;
+    private JCheckBoxMenuItem snapCheckboxMenuItem;
+    
             
     public DrawAction(MapFrame mapFrame) {
@@ -100,5 +108,7 @@
         extraShortcut = Shortcut.registerShortcut("mapmode:drawfocus", tr("Mode: Draw Focus"), KeyEvent.VK_N, Shortcut.GROUP_EDIT);
         Main.registerActionShortcut(this, extraShortcut);
-
+        
+        snapCheckboxMenuItem = MainMenu.addWithCheckbox(Main.main.menu.editMenu, new SnapChangeAction(),  MainMenu.WINDOW_MENU_GROUP.VOLATILE);
+        snapHelper.setMenuCheckBox(snapCheckboxMenuItem);
         cursorJoinNode = ImageProvider.getCursor("crosshair", "joinnode");
         cursorJoinWay = ImageProvider.getCursor("crosshair", "joinway");
@@ -135,4 +145,16 @@
         wayIsFinished = false;
         snapHelper.init();
+        snapCheckboxMenuItem.getAction().setEnabled(true);
+        
+         timer = new Timer(0, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                 timer.stop();
+                 if (set.remove(releaseEvent.getKeyCode())) {
+                   doKeyReleaseEvent(releaseEvent);
+                 }
+            }
+
+        });
         
         backspaceShortcut = Shortcut.registerShortcut("mapmode:backspace", tr("Backspace in Add mode"), KeyEvent.VK_BACK_SPACE, Shortcut.GROUP_EDIT);
@@ -160,5 +182,6 @@
         Main.unregisterActionShortcut(backspaceShortcut);
         snapHelper.unsetFixedMode();
-
+        snapCheckboxMenuItem.getAction().setEnabled(false);
+        
         removeHighlighting();
         try {
@@ -183,9 +206,5 @@
             return;
         if (event instanceof KeyEvent) {
-                KeyEvent ke = (KeyEvent) event;
-                if (ke.getKeyCode() == KeyEvent.VK_TAB && 
-                    ke.getID()==KeyEvent.KEY_PRESSED) {
-                    snapHelper.nextSnapMode();
-                }
+                processKeyEvent((KeyEvent) event);
         } //  toggle angle snapping
         updateKeyModifiers((InputEvent) event);
@@ -194,4 +213,48 @@
         redrawIfRequired();
     }
+    
+    
+    // events for crossplatform key holding processing 
+    // thanks to http://www.arco.in-berlin.de/keyevent.html 
+    private final TreeSet<Integer> set = new TreeSet<Integer>();
+    private KeyEvent releaseEvent;
+    private Timer timer;
+    void processKeyEvent(KeyEvent e) {
+        if (e.getKeyCode() != KeyEvent.VK_TAB) return;
+	e.consume();
+
+        if (e.getID() == KeyEvent.KEY_PRESSED) {
+             if (timer.isRunning()) {
+                  timer.stop();
+                } else {
+                  if (set.add((e.getKeyCode()))) doKeyPressEvent(e);
+                }
+             
+        }
+        if (e.getID() == KeyEvent.KEY_RELEASED) {
+            if (timer.isRunning()) {
+              timer.stop();
+               if (set.remove(e.getKeyCode())) {
+                  doKeyReleaseEvent(e);
+               }
+            } else {
+              releaseEvent = e;
+              timer.restart();
+            }
+        }
+        
+    }
+    
+    private void doKeyPressEvent(KeyEvent e) {
+        if (e.getKeyCode() != KeyEvent.VK_TAB) return;
+        snapHelper.setFixedMode();
+        computeHelperLine(); redrawIfRequired();
+    }
+    private void doKeyReleaseEvent(KeyEvent e) {
+        if (e.getKeyCode() != KeyEvent.VK_TAB) return;
+        snapHelper.unFixOrTurnOff();
+        computeHelperLine(); redrawIfRequired();
+    }
+
     /**
      * redraw to (possibly) get rid of helper line if selection changes.
@@ -265,5 +328,5 @@
         //
         Main.map.mapView.requestFocus();
-
+        
         if(e.getClickCount() > 1 && mousePos != null && mousePos.equals(oldMousePos)) {
             // A double click equals "user clicked last node again, finish way"
@@ -325,5 +388,5 @@
             } else { // n==null, no node found in clicked area
                 EastNorth mouseEN = Main.map.mapView.getEastNorth(e.getX(), e.getY());
-                newEN = snapOn ? snapHelper.getSnapPoint(mouseEN) : mouseEN;
+                newEN = snapHelper.isSnapOn() ? snapHelper.getSnapPoint(mouseEN) : mouseEN;
                 n = new Node(newEN); //create node at clicked point
                 newNode = true;
@@ -699,5 +762,5 @@
         }
         
-        if (snapOn) snapHelper.checkAngleSnapping(currentMouseEastNorth,angle);
+        snapHelper.checkAngleSnapping(currentMouseEastNorth,angle);
         
         Main.map.statusLine.setAngle(angle);
@@ -949,5 +1012,5 @@
         
         Graphics2D g2 = g;
-        if (snapOn) snapHelper.draw(g2,mv);
+        snapHelper.drawIfNeeded(g2,mv);
         if (!drawHelperLine || wayIsFinished || shift) return;
         
@@ -955,4 +1018,6 @@
             g2.setColor(selectedColor);
             g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+        } else {
+            if (!snapHelper.drawConstructionGeometry) return;
         }
         GeneralPath b = new GeneralPath();
@@ -1019,6 +1084,6 @@
                 rv += " " + tr("Continue way from last node.");
             }
-            if (snapOn) {
-                rv += " "+ tr("Angle snapping ON.");
+            if (snapHelper.isSnapOn()) {
+                rv += " "+ tr("Angle snapping active.");
             }
         }
@@ -1093,7 +1158,14 @@
 
     private class SnapHelper {
+        boolean snapOn; // snapping is turned on
+        
         private boolean active; // snapping is activa for current mouse position
         private boolean fixed; // snap angle is fixed
         private boolean absoluteFix; // snap angle is absolute
+        
+        private boolean drawConstructionGeometry; 
+        private boolean showProjectedPoint; 
+        private boolean showAngle; 
+        
         EastNorth dir2;
         EastNorth projected;
@@ -1111,9 +1183,12 @@
         private Stroke normalStroke;
         private Stroke helperStroke;
-
-        private  void init() {
+        
+        JCheckBoxMenuItem checkBox;
+        
+        public void init() {
             snapOn=false;
+            checkBox.setState(snapOn);
             fixed=false; absoluteFix=false;
-            
+                        
             Collection<String> angles = Main.pref.getCollection("draw.anglesnap.angles", 
                     Arrays.asList("0","30","45","60","90","120","135","150","210","225","240","270","300","315","330"));
@@ -1131,4 +1206,7 @@
             }
             snapAngleTolerance = Main.pref.getDouble("draw.anglesnap.tolerance", 5.0);
+            drawConstructionGeometry = Main.pref.getBoolean("draw.anglesnap.drawConstructionGeometry", true);
+            showProjectedPoint = Main.pref.getBoolean("draw.anglesnap.drawProjectedPoint", true);
+            showAngle = Main.pref.getBoolean("draw.anglesnap.showAngle", true);
 
             normalStroke = new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
@@ -1141,11 +1219,11 @@
         }
         
-        private void noSnapNow() {
-            active=false; 
-            dir2=null; projected=null;
-            labelText=null;
-        }
-
-        private void draw(Graphics2D g2, MapView mv) {
+        public  void setMenuCheckBox(JCheckBoxMenuItem checkBox) {
+            this.checkBox = checkBox;
+        }
+        
+
+        public  void drawIfNeeded(Graphics2D g2, MapView mv) {
+            if (!snapOn) return;
             if (!active) return;
             Point p1=mv.getPoint(currentBaseNode);
@@ -1153,17 +1231,18 @@
             Point p3=mv.getPoint(projected);
             GeneralPath b;
-            
-            g2.setColor(snapHelperColor);
-            g2.setStroke(helperStroke);
-            
-            b = new GeneralPath();
-            if (absoluteFix) {
-                b.moveTo(p2.x,p2.y); 
-                b.lineTo(2*p1.x-p2.x,2*p1.y-p2.y); // bi-directional line
-            } else {
-                b.moveTo(p2.x,p2.y);
-                b.lineTo(p3.x,p3.y);
-            } 
-            g2.draw(b);
+            if (drawConstructionGeometry) {
+                g2.setColor(snapHelperColor);
+                g2.setStroke(helperStroke);
+
+                b = new GeneralPath();
+                if (absoluteFix) {
+                    b.moveTo(p2.x,p2.y); 
+                    b.lineTo(2*p1.x-p2.x,2*p1.y-p2.y); // bi-directional line
+                } else {
+                    b.moveTo(p2.x,p2.y);
+                    b.lineTo(p3.x,p3.y);
+                } 
+                g2.draw(b);
+            }
 
             g2.setColor(selectedColor);
@@ -1175,6 +1254,8 @@
             
             g2.drawString(labelText, p3.x-5, p3.y+20);
-            g2.setStroke(normalStroke);
-            g2.drawOval(p3.x-5, p3.y-5, 10, 10); // projected point
+            if (showProjectedPoint) {
+                g2.setStroke(normalStroke);
+                g2.drawOval(p3.x-5, p3.y-5, 10, 10); // projected point
+            }
             
             g2.setColor(snapHelperColor);
@@ -1183,12 +1264,8 @@
         }
         
-        private double getAngleDelta(double a, double b) {
-            double delta = Math.abs(a-b);
-            if (delta>180) return 360-delta; else return delta;
-        }
-
         /* If mouse position is close to line at 15-30-45-... angle, remembers this direction
          */
-        private void checkAngleSnapping(EastNorth currentEN, double angle) {
+        public  void checkAngleSnapping(EastNorth currentEN, double angle) {
+            if (!snapOn) return;
             if (!absoluteFix && previousNode==null) return;
             
@@ -1208,9 +1285,16 @@
                 EastNorth p0 = currentBaseNode.getEastNorth();
                 e0=p0.east(); n0=p0.north();
-
-                if (fixed) {
-                    if (absoluteFix) labelText = "=";
-                                else labelText = String.format(fixFmt, (int) nearestAngle);
-                } else labelText = String.format("%d", (int) nearestAngle);
+                
+                if (showAngle)  {
+                    if (fixed) {
+                        if (absoluteFix) labelText = "=";
+                                    else labelText = String.format(fixFmt, (int) nearestAngle);
+                    } else labelText = String.format("%d", (int) nearestAngle);
+                } else {
+                    if (fixed) {
+                        if (absoluteFix) labelText = "=";
+                        else labelText = String.format(tr("FIX"),0);
+                    } else labelText="";
+                } 
                 
                 if (absoluteFix) {
@@ -1237,5 +1321,5 @@
         }
         
-        private EastNorth getSnapPoint(EastNorth p) {
+        public  EastNorth getSnapPoint(EastNorth p) {
             if (!active) return p;
             double de=p.east()-e0;
@@ -1246,39 +1330,12 @@
         }
         
-        private void unsetFixedMode() {
-            fixed=false; absoluteFix=false;
-            lastAngle=0;
-            active=false;
-        }
-        
-        private void nextSnapMode() {
-            if (snapOn) {
-                // turn off snapping if we are in fixed mode or no actile snapping line exist
-                if (fixed || !active) { snapOn=false; unsetFixedMode(); } 
-                else if (active) { fixed=true; }
-            } else {
-                snapOn=true;
-                unsetFixedMode();
-            }
-        }
-
-        private boolean isActive() {
-            return active;
-        }
-
-        private double getNearestAngle(double angle) {
-            double delta,minDelta=1e5, bestAngle=0.0;
-            for (int i=0; i<snapAngles.length; i++) {
-                delta = getAngleDelta(angle,snapAngles[i]);
-                if (delta<minDelta) {
-                    minDelta=delta;
-                    bestAngle=snapAngles[i];
-                }
-            }
-            if (Math.abs(bestAngle-360)<1e-3) bestAngle=0;
-            return bestAngle;
-        }
-
-        private void fixToSegment(WaySegment seg) {
+        
+        public void noSnapNow() {
+            active=false; 
+            dir2=null; projected=null;
+            labelText=null;
+        }
+
+        public void fixToSegment(WaySegment seg) {
             if (seg==null) return;
             double hdg = seg.getFirstNode().getEastNorth().heading(seg.getSecondNode().getEastNorth());
@@ -1290,4 +1347,77 @@
             lastAngle=hdg;
         }
+
+        private void nextSnapMode() {
+            if (snapOn) {
+                // turn off snapping if we are in fixed mode or no actile snapping line exist
+                if (fixed || !active) { snapOn=false; unsetFixedMode(); } 
+                else setFixedMode();
+            } else {
+                snapOn=true;
+                unsetFixedMode();
+            }
+            checkBox.setState(snapOn);
+        }
+        
+        private void toggleSnapping() {
+            snapOn = !snapOn;
+            checkBox.setState(snapOn);
+            unsetFixedMode();
+        }
+                
+        public void setFixedMode() {
+            if (active) { fixed=true; }
+        }
+        
+        
+        public  void unsetFixedMode() {
+            fixed=false; absoluteFix=false;
+            lastAngle=0;
+            active=false;
+        }
+        
+        public  boolean isActive() {
+            return active;
+        }
+        
+        public  boolean isSnapOn() {
+            return snapOn;
+        }
+
+        private double getNearestAngle(double angle) {
+            double delta,minDelta=1e5, bestAngle=0.0;
+            for (int i=0; i<snapAngles.length; i++) {
+                delta = getAngleDelta(angle,snapAngles[i]);
+                if (delta<minDelta) {
+                    minDelta=delta;
+                    bestAngle=snapAngles[i];
+                }
+            }
+            if (Math.abs(bestAngle-360)<1e-3) bestAngle=0;
+            return bestAngle;
+        }
+
+        private double getAngleDelta(double a, double b) {
+            double delta = Math.abs(a-b);
+            if (delta>180) return 360-delta; else return delta;
+        }
+
+        private void unFixOrTurnOff() {
+            if (absoluteFix) unsetFixedMode(); else toggleSnapping();
+        }
+    }
+    
+    private class SnapChangeAction extends JosmAction {
+        public SnapChangeAction() {
+             super(tr("Angle snapping"), "anglesnap", 
+ 		   tr("Switch angle snapping mode while drawing"), 
+ 		   null, false);
+             putValue("help", ht("/Action/Draw/AngleSnap"));
+        }
+        @Override 
+        public void actionPerformed(ActionEvent e) {
+               if (snapHelper!=null) snapHelper.toggleSnapping(); 
+        }
+        
     }
 }
