Index: /trunk/.settings/org.eclipse.jdt.ui.prefs
===================================================================
--- /trunk/.settings/org.eclipse.jdt.ui.prefs	(revision 607)
+++ /trunk/.settings/org.eclipse.jdt.ui.prefs	(revision 608)
@@ -1,5 +1,5 @@
-#Thu Nov 01 00:40:04 CET 2007
+#Wed Apr 16 17:01:39 CEST 2008
 eclipse.preferences.version=1
 formatter_profile=_josm
 formatter_settings_version=10
-org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">// License\: GPL. \n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">// License\: GPL. Copyright 2007 by Immanuel Scholz and others\n${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">// License\: GPL. \n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">// License\: GPL. For details, see LICENSE file.\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
Index: /trunk/src/org/openstreetmap/josm/actions/AlignInRectangleAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/AlignInRectangleAction.java	(revision 608)
+++ /trunk/src/org/openstreetmap/josm/actions/AlignInRectangleAction.java	(revision 608)
@@ -0,0 +1,135 @@
+// License: GPL. See LICENSE file for details.
+//
+package org.openstreetmap.josm.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.MoveCommand;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Way;
+
+/**
+ * Aligns all selected nodes within a rectangle. 
+ * 
+ * There are many ways this could be done, for example:
+ * - find smallest rectangle to contain all points (rectangular hull) OR
+ * - find largest rectangle to fit inside OR
+ * - find both and compute the average
+ * 
+ * Also, it would be possible to let the user specify more input, e.g.
+ * two nodes that should remain where they are.
+ * 
+ * This method uses the following algorithm:
+ * 1. compute "heading" of all four edges
+ * 2. select the edge that is oriented closest to the average of all headings
+ * @author Frederik Ramm <frederik@remote.org>
+ */
+public final class AlignInRectangleAction extends JosmAction {
+
+	public AlignInRectangleAction() {
+		super(tr("Align Nodes in Rectangle"), "aligncircle", tr("Move the selected nodes into a rectangle."), KeyEvent.VK_Q, 0, true);
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		Collection<OsmPrimitive> sel = Main.ds.getSelected();
+		Way myWay = null;
+		if (sel.size() == 1) 
+			for (OsmPrimitive osm : sel)
+				if (osm instanceof Way)
+					myWay = (Way) osm;
+		
+		if ((myWay == null) || (myWay.nodes.size() != 5) || (!myWay.nodes.get(0).equals(myWay.nodes.get(4)))) {
+			JOptionPane.showMessageDialog(Main.parent, tr("Please select one circular way of exactly four nodes."));
+			return;
+		}
+
+		// find orientation of all four edges, compute average
+		double avg_angle = 0;
+		double angle[] = new double[4];
+		EastNorth en[] = new EastNorth[5];
+		for (int i=0; i<5; i++) en[i] = new EastNorth(myWay.nodes.get(i).eastNorth.east(), myWay.nodes.get(i).eastNorth.north());
+		for (int i=0; i<4; i++) {
+			angle[i] = Math.asin((en[i+1].north()-en[i].north())/en[i+1].distance(en[i])) + 2 * Math.PI;
+		    while(angle[i] > Math.PI/4) angle[i] -= Math.PI/2;
+			avg_angle += angle[i];
+		}
+		avg_angle /= 4;
+		
+		// select edge that is closest to average, and use it as the base for the following
+		double best_dist = 0; 
+		int base = 0;
+		for (int i=0; i<4; i++)
+		{
+			if ((i==0)||(Math.abs(angle[i]-avg_angle))<best_dist)
+			{
+				best_dist = Math.abs(angle[i]-avg_angle);
+				base = i;
+			}
+		}
+
+
+		// nice symbolic names for the nodes we're working with
+		EastNorth begin = en[base]; // first node of base segment
+		EastNorth end = en[(base+1)%4]; // second node of base segment
+		EastNorth next = en[(base+2)%4]; // node following the second node of the base seg
+		EastNorth prev= en[(base+3)%4];  // node before the first node of the base seg
+		
+		// find a parallel to the base segment
+		double base_slope = (end.north() - begin.north()) / (end.east() - begin.east());
+		// base intercept of parallels that go through "next" and "prev" points
+		double b1 = next.north() - base_slope * next.east();
+		double b2 = prev.north() - base_slope * prev.east();
+		// average of both
+		double opposite_b = (b1+b2)/2;
+
+		// find the point on the base segment from which distance to "next" is shortest
+		double u = ((next.east()-begin.east())*(end.east()-begin.east()) + (next.north()-begin.north())*(end.north()-begin.north()))/end.distanceSq(begin);
+		EastNorth end2 = new EastNorth(begin.east()+u*(end.east()-begin.east()), begin.north()+u*(end.north()-begin.north()));
+
+		// same for "prev"
+		u = ((prev.east()-begin.east())*(end.east()-begin.east()) + (prev.north()-begin.north())*(end.north()-begin.north()))/end.distanceSq(begin);
+		EastNorth begin2 = new EastNorth(begin.east()+u*(end.east()-begin.east()), begin.north()+u*(end.north()-begin.north()));
+		
+		// new "begin" and "end" points are halfway between their old position and 
+		// the base points found above
+		end = new EastNorth((end2.east()+end.east())/2, (end2.north()+end.north())/2);
+		begin = new EastNorth((begin2.east()+begin.east())/2, (begin2.north()+begin.north())/2);
+		
+		double other_slope = -1 / base_slope;
+		double next_b = end.north() - other_slope * end.east();
+		double prev_b = begin.north() - other_slope * begin.east();
+		
+		double x = (opposite_b-next_b)/(other_slope-base_slope);
+		double y = opposite_b + base_slope * x;
+		next = new EastNorth(x, y);
+		
+		x = (opposite_b-prev_b)/(other_slope-base_slope);
+		y = opposite_b + base_slope * x;
+		prev = new EastNorth(x, y);
+		
+		Collection<Command> cmds = new LinkedList<Command>();
+		for (int i=0; i<4; i++) {
+			Node n = myWay.nodes.get(i);
+			EastNorth ref = (i == base) ? begin : (i == (base+1)%4) ? end : (i==(base+2)%4) ? next : prev;
+			double dx = ref.east()-n.eastNorth.east();
+			double dy = ref.north()-n.eastNorth.north();
+			cmds.add(new MoveCommand(n, dx, dy));
+		}
+
+		Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Rectangle"), cmds));
+		Main.map.repaint();
+	}
+}
Index: /trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java	(revision 608)
@@ -1,13 +1,21 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
 package org.openstreetmap.josm.actions.mapmode;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.AWTEvent;
+import java.awt.BasicStroke;
+import java.awt.Color;
 import java.awt.Cursor;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.awt.event.AWTEventListener;
 import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
-import javax.swing.KeyStroke;
-import javax.swing.JComponent;
+import java.awt.geom.GeneralPath;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -16,10 +24,12 @@
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.LinkedList;
-import java.util.List;
-
+
+import javax.swing.JComponent;
 import javax.swing.JOptionPane;
+import javax.swing.KeyStroke;
 
 import org.openstreetmap.josm.Main;
@@ -28,20 +38,38 @@
 import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.tools.Pair;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.layer.MapViewPaintable;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Pair;
 
 /**
  *
- */
-public class DrawAction extends MapMode {
-	
+ */ 
+public class DrawAction extends MapMode implements MapViewPaintable, SelectionChangedListener, AWTEventListener {
+		
 	private static Node lastUsedNode = null;
-
+	private double PHI=Math.toRadians(90);
+
+	private boolean ctrl;
+	private boolean alt;
+	private boolean shift;
+	private boolean mouseOnExistingNode;
+	private boolean drawHelperLine;
+	private Point mousePos;
+	private Color selectedColor;
+	
+	private Node currentBaseNode;
+	private EastNorth currentMouseEastNorth;
+	
 	public DrawAction(MapFrame mapFrame) {
 		super(tr("Draw"), "node/autonode", tr("Draw nodes"),
@@ -53,4 +81,7 @@
 		
 		//putValue("help", "Action/AddNode/Autnode");
+		selectedColor = Preferences.getPreferencesColor("selected", Color.YELLOW);
+		
+		drawHelperLine = Main.pref.getBoolean("draw.helper-line", true);
 	}
 
@@ -66,9 +97,41 @@
 		super.enterMode();
 		Main.map.mapView.addMouseListener(this);
-	}
-
+		Main.map.mapView.addMouseMotionListener(this);
+		Main.map.mapView.addTemporaryLayer(this);
+		DataSet.selListeners.add(this);
+		try {
+			Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
+		} catch (SecurityException ex) {
+		}
+		// would like to but haven't got mouse position yet:
+		// computeHelperLine(false, false, false);
+	}
 	@Override public void exitMode() {
 		super.exitMode();
 		Main.map.mapView.removeMouseListener(this);
+		Main.map.mapView.removeMouseMotionListener(this);
+		Main.map.mapView.removeTemporaryLayer(this);
+		DataSet.selListeners.remove(this);
+		try {
+			Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+		} catch (SecurityException ex) {
+		}
+	}
+	
+	/**
+	 * redraw to (possibly) get rid of helper line if selection changes.
+	 */
+	public void eventDispatched(AWTEvent event) {
+		InputEvent e = (InputEvent) event;
+		ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+		alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+		shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+		computeHelperLine();
+	}
+	/**
+	 * redraw to (possibly) get rid of helper line if selection changes.
+	 */
+	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+		computeHelperLine();
 	}
 
@@ -80,10 +143,15 @@
 	 */
 	@Override public void mouseClicked(MouseEvent e) {
+
 		if (e.getButton() != MouseEvent.BUTTON1)
 			return;
 
-		boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-		boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
-		boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+		// we copy ctrl/alt/shift from the event just in case our global
+		// AWTEvent didn't make it through the security manager. Unclear
+		// if that can ever happen but better be safe.
+		ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+		alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+		shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+		mousePos = e.getPoint();
 		
 		Collection<OsmPrimitive> selection = Main.ds.getSelected();
@@ -94,6 +162,7 @@
 		boolean newNode = false;
 		Node n = null;
+		
 		if (!ctrl) {
-			n = Main.map.mapView.getNearestNode(e.getPoint());
+			n = Main.map.mapView.getNearestNode(mousePos);
 		}
 		
@@ -256,4 +325,112 @@
 		Main.main.undoRedo.add(c);
 		lastUsedNode = n;
+		computeHelperLine();
+		Main.map.mapView.repaint();
+	}
+	
+	@Override public void mouseMoved(MouseEvent e) {
+
+		// we copy ctrl/alt/shift from the event just in case our global
+		// AWTEvent didn't make it through the security manager. Unclear
+		// if that can ever happen but better be safe.
+		
+		ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+		alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+		shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+		mousePos = e.getPoint();
+		
+		computeHelperLine();
+	}
+	
+	/**
+	 * This method prepares data required for painting the "helper line" from
+	 * the last used position to the mouse cursor. It duplicates some code from
+	 * mouseClicked() (FIXME).
+	 */
+	private void computeHelperLine() {
+		
+		double distance = -1;
+		double angle = -1;
+
+		Collection<OsmPrimitive> selection = Main.ds.getSelected();
+
+		Node selectedNode = null;
+		Way selectedWay = null;
+		Node currentMouseNode = null;
+		mouseOnExistingNode = false;
+
+		Main.map.statusLine.setAngle(-1);
+		Main.map.statusLine.setHeading(-1);
+		Main.map.statusLine.setDist(-1);
+
+		if (!ctrl && mousePos != null) {
+			currentMouseNode = Main.map.mapView.getNearestNode(mousePos);
+		}
+		
+		if (currentMouseNode != null) {
+			// user clicked on node
+			if (selection.isEmpty()) return;
+			currentMouseEastNorth = currentMouseNode.eastNorth;
+			mouseOnExistingNode = true;
+		} else {
+			// no node found in clicked area
+			currentMouseEastNorth = Main.map.mapView.getEastNorth(mousePos.x, mousePos.y);
+		}
+		
+		for (OsmPrimitive p : selection) {
+			if (p instanceof Node) {
+				if (selectedNode != null) return;
+				selectedNode = (Node) p;
+			} else if (p instanceof Way) {
+				if (selectedWay != null) return;
+				selectedWay = (Way) p;
+			}
+		}
+		
+		// the node from which we make a connection
+		currentBaseNode = null;
+		Node previousNode = null;
+		
+		if (selectedNode == null) {
+			if (selectedWay == null) return;
+			if (lastUsedNode == selectedWay.nodes.get(0) || lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
+				currentBaseNode = lastUsedNode;
+				if (lastUsedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1) && selectedWay.nodes.size() > 1) {
+					previousNode = selectedWay.nodes.get(selectedWay.nodes.size()-2);
+				}
+			}
+		} else if (selectedWay == null) {
+			currentBaseNode = selectedNode;
+		} else {
+			if (selectedNode == selectedWay.nodes.get(0) || selectedNode == selectedWay.nodes.get(selectedWay.nodes.size()-1)) {
+				currentBaseNode = selectedNode;
+			}			
+		}
+		
+		if (currentBaseNode == null || currentBaseNode == currentMouseNode) {
+			return; // Don't create zero length way segments.
+		}
+		
+		Main.map.mapView.repaint();
+		
+		// find out the distance, in metres, between the base point and the mouse cursor
+		LatLon mouseLatLon = Main.proj.eastNorth2latlon(currentMouseEastNorth);
+		distance = currentBaseNode.coor.greatCircleDistance(mouseLatLon);
+		double hdg = Math.toDegrees(currentBaseNode.coor.heading(mouseLatLon));
+		if (previousNode != null) {
+			angle = hdg - Math.toDegrees(previousNode.coor.heading(currentBaseNode.coor));
+			if (angle < 0) angle += 360;
+		}
+		Main.map.statusLine.setAngle(angle);
+		Main.map.statusLine.setHeading(hdg);
+		Main.map.statusLine.setDist(distance);
+		updateStatusLine();
+	}
+	
+	/**
+	 * Repaint on mouse exit so that the helper line goes away.
+	 */
+	@Override public void mouseExited(MouseEvent e) {
+		mousePos = e.getPoint();
 		Main.map.mapView.repaint();
 	}
@@ -347,7 +524,7 @@
 			A = seg.a.eastNorth;
 			B = seg.b.eastNorth;
-			double a = P.distance(B);
-			double b = P.distance(A);
-			double c = A.distance(B);
+			double a = P.distanceSq(B);
+			double b = P.distanceSq(A);
+			double c = A.distanceSq(B);
 			double q = (a - b + c) / (2*c);
 			n.eastNorth = new EastNorth(
@@ -362,8 +539,69 @@
 		return a * d - b * c;
 	}
-
+	
+	public void paint(Graphics g, MapView mv) {
+
+		// don't draw line if disabled in prefs
+		if (!drawHelperLine) return;
+		
+		// sanity checks
+		if (Main.map.mapView == null) return;
+		if (mousePos == null) return;
+		
+		// if shift key is held ("no auto-connect"), don't draw a line
+		if (shift) return;
+		
+		// don't draw line if we don't know where from or where to
+		if (currentBaseNode == null) return;
+		if (currentMouseEastNorth == null) return;
+		
+		// don't draw line if mouse is outside window
+		if (!Main.map.mapView.getBounds().contains(mousePos)) return;
+		
+		Graphics2D g2 = (Graphics2D) g;
+		g2.setColor(selectedColor);
+		g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+		GeneralPath b = new GeneralPath();
+		Point p1=mv.getPoint(currentBaseNode.eastNorth);
+		Point p2=mv.getPoint(currentMouseEastNorth);
+
+		double t = Math.atan2(p2.y-p1.y, p2.x-p1.x) + Math.PI;
+		
+		b.moveTo(p1.x,p1.y); b.lineTo(p2.x, p2.y);
+		
+		// if alt key is held ("start new way"), draw a little perpendicular line
+		if (alt) {
+			b.moveTo((int)(p1.x + 8*Math.cos(t+PHI)), (int)(p1.y + 8*Math.sin(t+PHI)));
+			b.lineTo((int)(p1.x + 8*Math.cos(t-PHI)), (int)(p1.y + 8*Math.sin(t-PHI)));
+		}
+		
+		g2.draw(b);
+		g2.setStroke(new BasicStroke(1));	
+
+	}
 	
 	@Override public String getModeHelpText() {
-		return tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way");
+		String rv;
+		
+		if (currentBaseNode != null && !shift) {
+			if (mouseOnExistingNode) {
+				if (alt && /* FIXME: way exists */true)
+				    rv = tr("Click to create a new way to the existing node.");
+				else	
+					rv =tr("Click to make a connection to the existing node.");
+			} else {
+				if (alt && /* FIXME: way exists */true)
+				    rv = tr("Click to insert a nose and create a new way.");
+				else	
+					rv = tr("Click to insert a new node and make a connection.");
+			}
+		}
+		else {
+			rv = tr("Click to insert a new node.");
+		}
+
+		//rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way"));
+		//rv.append(tr("Click to add a new node. Ctrl: no node re-use/auto-insert. Shift: no auto-connect. Alt: new way"));
+		return rv.toString();
 	}
 }
Index: /trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java	(revision 608)
+++ /trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java	(revision 608)
@@ -0,0 +1,271 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.actions.mapmode;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.geom.GeneralPath;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.ChangeCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.layer.MapViewPaintable;
+import org.openstreetmap.josm.tools.ImageProvider;
+/**
+ * Makes a rectangle from a line, or modifies a rectangle.
+ * 
+ * This class currently contains some "sleeping" code copied from DrawAction (move and rotate)
+ * which can eventually be removed, but it may also get activated here and removed in DrawAction.
+ */
+public class ExtrudeAction extends MapMode implements MapViewPaintable {
+
+	enum Mode { EXTRUDE, rotate, select }
+	private Mode mode = null;
+	private long mouseDownTime = 0;
+	private WaySegment selectedSegment = null;
+	private Color selectedColor;
+
+	double xoff;
+	double yoff;
+	double distance;
+	
+	/**
+	 * The old cursor before the user pressed the mouse button.
+	 */
+	private Cursor oldCursor;
+	/**
+	 * The curren tposition of the mouse 
+	 */
+	private Point mousePos;
+	/** 
+	 * The position of the mouse cursor when the drag action was initiated.
+	 */
+	private Point initialMousePos;
+	/**
+	 * The time which needs to pass between click and release before something
+	 * counts as a move, in milliseconds
+	 */
+	private int initialMoveDelay = 200;
+
+	/**
+	 * The screen distance which needs to be travelled before something
+	 * counts as a move, in pixels
+	 */
+	private int initialMoveThreshold = 15;
+	private boolean initialMoveThresholdExceeded = false;
+	/**
+	 * Create a new SelectAction
+	 * @param mapFrame The MapFrame this action belongs to.
+	 */
+	public ExtrudeAction(MapFrame mapFrame) {
+		super(tr("Extrude"), "extrude/extrude", tr("Create areas"),
+			KeyEvent.VK_X, mapFrame,
+			getCursor("normal", "selection", Cursor.DEFAULT_CURSOR));
+		putValue("help", "Action/Extrude/Extrude");
+		try { initialMoveDelay = Integer.parseInt(Main.pref.get("edit.initial-move-delay","200")); } catch (NumberFormatException x) {}
+		try { initialMoveThreshold = Integer.parseInt(Main.pref.get("edit.initial-move-threshold","5")); } catch (NumberFormatException x) {}
+		selectedColor = Preferences.getPreferencesColor("selected", Color.YELLOW);
+	}
+
+	private static Cursor getCursor(String name, String mod, int def) {
+		try {
+	        return ImageProvider.getCursor(name, mod);
+        } catch (Exception e) {
+        }
+	    return Cursor.getPredefinedCursor(def);
+    }
+
+	private void setCursor(Cursor c) {
+		if (oldCursor == null) {
+			oldCursor = Main.map.mapView.getCursor();
+			Main.map.mapView.setCursor(c);
+		}
+	}
+
+	private void restoreCursor() {
+		if (oldCursor != null) {
+			Main.map.mapView.setCursor(oldCursor);
+			oldCursor = null;
+		}
+	}
+	
+	@Override public void enterMode() {
+		super.enterMode();
+		Main.map.mapView.addMouseListener(this);
+		Main.map.mapView.addMouseMotionListener(this);
+	}
+
+	@Override public void exitMode() {
+		super.exitMode();
+		Main.map.mapView.removeMouseListener(this);
+		Main.map.mapView.removeMouseMotionListener(this);
+		Main.map.mapView.removeTemporaryLayer(this);
+
+	}
+
+	/**
+	 * If the left mouse button is pressed, move all currently selected
+	 * objects (if one of them is under the mouse) or the current one under the
+	 * mouse (which will become selected).
+	 */
+	@Override public void mouseDragged(MouseEvent e) {
+		if (mode == Mode.select) return;
+		
+		// do not count anything as a move if it lasts less than 100 milliseconds.
+		if ((mode == Mode.EXTRUDE) && (System.currentTimeMillis() - mouseDownTime < initialMoveDelay)) return;
+
+		if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) == 0)
+			return;
+
+		if (mode == Mode.EXTRUDE) {
+			setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+		}
+
+		if (mousePos == null) {
+			mousePos = e.getPoint();
+			return;
+		}
+		
+		Main.map.mapView.repaint();
+		mousePos = e.getPoint();
+
+	}
+
+	public void paint(Graphics g, MapView mv) {
+		if (selectedSegment != null) {
+			Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
+			Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
+			
+			EastNorth en1 = n1.eastNorth;
+			EastNorth en2 = n2.eastNorth;
+			if (en1.east() < en2.east()) { en2 = en1; en1 = n2.eastNorth; }
+			EastNorth en3 = mv.getEastNorth(mousePos.x, mousePos.y);
+			
+			double u = ((en3.east()-en1.east())*(en2.east()-en1.east()) + (en3.north()-en1.north())*(en2.north()-en1.north()))/en2.distanceSq(en1);
+			// the point on the segment from which the distance to mouse pos is shortest
+			EastNorth base = new EastNorth(en1.east()+u*(en2.east()-en1.east()), en1.north()+u*(en2.north()-en1.north()));
+			
+			// the distance, in projection units, between the base point and the mouse cursor
+			double len = base.distance(en3);
+			
+			// find out the distance, in metres, between the base point and the mouse cursor
+			distance = Main.proj.eastNorth2latlon(base).greatCircleDistance(Main.proj.eastNorth2latlon(en3));
+			Main.map.statusLine.setDist(distance);
+			updateStatusLine();
+			
+			// compute the angle at which the segment is drawn
+			// and use it to compute the x and y offsets for the
+			// corner points. 
+			double sin_alpha = (en2.north()-en1.north())/en2.distance(en1);
+			
+			// this is a kludge because sometimes extrusion just goes the wrong direction
+			if ((en3.east()>base.east()) ^ (sin_alpha < 0)) len=-len;
+			xoff = sin_alpha * len;
+			yoff = Math.sqrt(1-sin_alpha*sin_alpha) * len;
+			
+			Graphics2D g2 = (Graphics2D) g;
+			g2.setColor(selectedColor);
+			g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+			GeneralPath b = new GeneralPath();
+			Point p1=mv.getPoint(en1);
+			Point p2=mv.getPoint(en2);
+			Point p3=mv.getPoint(en1.add(-xoff, -yoff));
+			Point p4=mv.getPoint(en2.add(-xoff, -yoff));
+			
+			b.moveTo(p1.x,p1.y); b.lineTo(p3.x, p3.y);
+			b.lineTo(p4.x, p4.y); b.lineTo(p2.x, p2.y);
+			b.lineTo(p1.x,p1.y);
+			g2.draw(b);
+			g2.setStroke(new BasicStroke(1));	
+		}
+	}
+	
+	/**
+	 */
+	@Override public void mousePressed(MouseEvent e) {
+		if (!(Boolean)this.getValue("active")) return;
+		if (e.getButton() != MouseEvent.BUTTON1)
+			return;
+		// boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
+		// boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
+		// boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
+		
+		mouseDownTime = System.currentTimeMillis();
+		
+		selectedSegment =
+			Main.map.mapView.getNearestWaySegment(e.getPoint());
+
+		mode = (selectedSegment == null) ? Mode.select : Mode.EXTRUDE;
+		oldCursor = Main.map.mapView.getCursor();
+
+		updateStatusLine();
+		Main.map.mapView.addTemporaryLayer(this);
+		Main.map.mapView.repaint();
+
+		mousePos = e.getPoint();
+		initialMousePos = e.getPoint();
+	}
+
+	/**
+	 * Restore the old mouse cursor.
+	 */
+	@Override public void mouseReleased(MouseEvent e) {
+		restoreCursor();
+		if (selectedSegment == null) return;
+		if (mousePos.distance(initialMousePos) > 10) {
+			Node n1 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex);
+			Node n2 = selectedSegment.way.nodes.get(selectedSegment.lowerIndex+1);
+			EastNorth en3 = n2.eastNorth.add(-xoff, -yoff);
+			Node n3 = new Node(Main.proj.eastNorth2latlon(en3));
+			EastNorth en4 = n1.eastNorth.add(-xoff, -yoff);
+			Node n4 = new Node(Main.proj.eastNorth2latlon(en4));
+			Way wnew = new Way(selectedSegment.way);
+			wnew.nodes.add(selectedSegment.lowerIndex+1, n3);
+			wnew.nodes.add(selectedSegment.lowerIndex+1, n4);
+			if (wnew.nodes.size() == 4) wnew.nodes.add(n1);
+			Collection<Command> cmds = new LinkedList<Command>();
+			cmds.add(new AddCommand(n4));
+			cmds.add(new AddCommand(n3));
+			cmds.add(new ChangeCommand(selectedSegment.way, wnew));
+			Command c = new SequenceCommand(tr("Extrude Way"), cmds);
+			Main.main.undoRedo.add(c);
+		}
+		
+		Main.map.mapView.removeTemporaryLayer(this);
+		mode = null;
+		updateStatusLine();
+		Main.map.mapView.repaint();	
+	}
+
+	@Override public String getModeHelpText() {
+		if (mode == Mode.select) {
+			return tr("Release the mouse button to select the objects in the rectangle.");
+		} else if (mode == Mode.EXTRUDE) {
+			return tr("Draw a rectangle of the desired size, then release the mouse button.");
+		} else if (mode == Mode.rotate) {
+			return tr("Release the mouse button to stop rotating.");
+		} else {
+			return tr("Drag a way segment to make a rectangle.");
+		}
+	}
+	
+
+}
Index: /trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 608)
@@ -1,3 +1,3 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
 package org.openstreetmap.josm.actions.mapmode;
 
@@ -18,5 +18,5 @@
  * is another.
  * 
- * MapModes should register/deregister all necessary listener on the map's view
+ * MapModes should register/deregister all necessary listeners on the map's view
  * control. 
  */
@@ -57,4 +57,5 @@
 	protected void updateStatusLine() {
 		Main.map.statusLine.setHelpText(getModeHelpText());
+		Main.map.statusLine.repaint();
 	}
 	
Index: /trunk/src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 608)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.data;
 
+import java.awt.Color;
 import java.io.BufferedReader;
 import java.io.File;
@@ -18,4 +19,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.tools.ColorHelper;
 
 
@@ -259,3 +261,19 @@
 		out.close();
 	}
+	
+	/**
+	 * Convenience method for accessing colour preferences.
+	 * 
+	 * @param colName name of the colour
+	 * @param def default value
+	 * @return a Color object for the configured colour, or the default value if none configured.
+	 */
+	public static Color getPreferencesColor(String colName, Color def) {
+		String colStr = Main.pref.get("color."+colName);
+		if (colStr.equals("")) {
+			Main.pref.put("color."+colName, ColorHelper.color2html(def));
+			return def;
+		}
+		return ColorHelper.html2color(colStr);
+	}
 }
Index: /trunk/src/org/openstreetmap/josm/data/coor/Coordinate.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/coor/Coordinate.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/data/coor/Coordinate.java	(revision 608)
@@ -41,4 +41,7 @@
 	 * Return the squared distance of the northing/easting values between 
 	 * this and the argument.
+	 * 
+	 * This method does NOT compute a great circle distance between two 
+	 * locations!
 	 *
 	 * @param other The other point to calculate the distance to.
@@ -46,6 +49,21 @@
 	 * 		regarding to the x/y values.
 	 */
+	public double distanceSq(Coordinate other) {
+		return (x-other.x)*(x-other.x)+(y-other.y)*(y-other.y);
+	}
+	
+	/** 
+	 * Return the distance of the northing/easting values between this and
+	 * the argument.
+	 * 
+	 * This method does NOT compute a great circle distance between two 
+	 * locations!
+	 * 
+	 * @param other The other point to calculate the distance to.
+	 * @return The square of the distance between this and the other point,
+	 * 		regarding to the x/y values.
+	 */
 	public double distance(Coordinate other) {
-		return (x-other.x)*(x-other.x)+(y-other.y)*(y-other.y);
+		return Math.sqrt(distanceSq(other));
 	}
 
Index: /trunk/src/org/openstreetmap/josm/data/coor/LatLon.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 608)
@@ -58,9 +58,28 @@
 	 * @return distance in metres.
 	 */
-	public int distance(LatLon other) {
-		return (int) (Math.acos(
+	public double greatCircleDistance(LatLon other) {
+		return (Math.acos(
 			Math.sin(Math.toRadians(lat())) * Math.sin(Math.toRadians(other.lat())) + 
 		    Math.cos(Math.toRadians(lat()))*Math.cos(Math.toRadians(other.lat())) *
 		                  Math.cos(Math.toRadians(other.lon()-lon()))) * 6378135);
+	}
+	
+	/**
+	 * Returns the heading, in radians, that you have to use to get from 
+	 * this lat/lon to another.
+	 * 
+	 * @param other the "destination" position
+	 * @return heading 
+	 */
+	public double heading(LatLon other) {
+		double rv;
+		if (other.lat() == lat()) {
+			rv = (other.lon()>lon() ? Math.PI / 2 : Math.PI * 3 / 2);
+		} else {
+			rv = Math.atan((other.lon()-lon())/(other.lat()-lat()));
+			if (rv < 0) rv += Math.PI;
+			if (other.lon() < lon()) rv += Math.PI;
+		}
+		return rv;
 	}
 
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java	(revision 608)
@@ -18,4 +18,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
@@ -335,25 +336,16 @@
 		}
 	}
-	
-	public static Color getPreferencesColor(String colName, Color def) {
-		String colStr = Main.pref.get("color."+colName);
-		if (colStr.equals("")) {
-			Main.pref.put("color."+colName, ColorHelper.color2html(def));
-			return def;
-		}
-		return ColorHelper.html2color(colStr);
-	}
 
 	// NW 111106 Overridden from SimplePaintVisitor in josm-1.4-nw1
 	// Shows areas before non-areas
 	public void visitAll(DataSet data) {
-		inactiveColor = getPreferencesColor("inactive", Color.DARK_GRAY);
-		selectedColor = getPreferencesColor("selected", Color.YELLOW);
-		nodeColor = getPreferencesColor("node", Color.RED);
-		dfltWayColor = getPreferencesColor("way", darkblue);
-		incompleteColor = getPreferencesColor("incomplete way", darkerblue);
-		backgroundColor = getPreferencesColor("background", Color.BLACK);
-		untaggedColor = getPreferencesColor("untagged",Color.GRAY);
-		textColor = getPreferencesColor ("text", Color.WHITE);
+		inactiveColor = Preferences.getPreferencesColor("inactive", Color.DARK_GRAY);
+		selectedColor = Preferences.getPreferencesColor("selected", Color.YELLOW);
+		nodeColor = Preferences.getPreferencesColor("node", Color.RED);
+		dfltWayColor = Preferences.getPreferencesColor("way", darkblue);
+		incompleteColor = Preferences.getPreferencesColor("incomplete way", darkerblue);
+		backgroundColor = Preferences.getPreferencesColor("background", Color.BLACK);
+		untaggedColor = Preferences.getPreferencesColor("untagged",Color.GRAY);
+		textColor = Preferences.getPreferencesColor ("text", Color.WHITE);
 		showDirectionArrow = Main.pref.getBoolean("draw.segment.direction");
 		showRelevantDirectionsOnly = Main.pref.getBoolean("draw.segment.relevant_directions_only");
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java	(revision 608)
@@ -11,4 +11,5 @@
 import java.util.Iterator;
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Relation;
@@ -68,11 +69,11 @@
 
 	public void visitAll(DataSet data) {
-		inactiveColor = getPreferencesColor("inactive", Color.DARK_GRAY);
-		selectedColor = getPreferencesColor("selected", Color.WHITE);
-		nodeColor = getPreferencesColor("node", Color.RED);
-		dfltWayColor = getPreferencesColor("way", darkblue);
-		untaggedWayColor = getPreferencesColor("untagged way", darkgreen);
-		incompleteColor = getPreferencesColor("incomplete way", darkerblue);
-		backgroundColor = getPreferencesColor("background", Color.BLACK);
+		inactiveColor = Preferences.getPreferencesColor("inactive", Color.DARK_GRAY);
+		selectedColor = Preferences.getPreferencesColor("selected", Color.WHITE);
+		nodeColor = Preferences.getPreferencesColor("node", Color.RED);
+		dfltWayColor = Preferences.getPreferencesColor("way", darkblue);
+		untaggedWayColor = Preferences.getPreferencesColor("untagged way", darkgreen);
+		incompleteColor = Preferences.getPreferencesColor("incomplete way", darkerblue);
+		backgroundColor = Preferences.getPreferencesColor("background", Color.BLACK);
 		showDirectionArrow = Main.pref.getBoolean("draw.segment.direction");
 		showRelevantDirectionsOnly = Main.pref.getBoolean("draw.segment.relevant_directions_only");
@@ -226,13 +227,4 @@
 		return screen.intersects(bbox);
         }
-
-	public static Color getPreferencesColor(String colName, Color def) {
-		String colStr = Main.pref.get("color."+colName);
-		if (colStr.equals("")) {
-			Main.pref.put("color."+colName, ColorHelper.color2html(def));
-			return def;
-		}
-		return ColorHelper.html2color(colStr);
-	}
 	
 	public void setGraphics(Graphics g) {
Index: /trunk/src/org/openstreetmap/josm/gui/GettingStarted.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/GettingStarted.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/GettingStarted.java	(revision 608)
@@ -1,3 +1,4 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
+
 package org.openstreetmap.josm.gui;
 
@@ -48,15 +49,16 @@
 		panel = new JPanel(new GridBagLayout());
 		
-		panel.add(new JLabel(tr("<html><h2>You are running the latest JOSM version with built-in mappaint support.</h2>" +
-                "<h3>The mappaint plugin is no longer necessary and has been removed from your configuration<br>" +
-                "file (if it was present). You can now switch between the \"classic\" display and the mappaint<br>" +
-                "style by toggling the \"Wireframe\" option in the \"View\" menu.</h3>" +
-                "<h3>If you have not used new JOSM versions for a while, you will also discover that this JOSM<br>" +
-                "is \"modeless\". It (almost) does away with the old edit modes, like \"add node and connect\" etc.;<br>"+
-                "instead, there are only four modes: zoom, select, edit, and delete. The edit mode will do what<br>"+
-                "you want in most cases (also see the mini help about modifier keys at the bottom of the screen)." +
+		panel.add(new JLabel(tr("<html><h2>You are running the latest JOSM version with some geometry extensions.</h2>" +
+                "<h3>New elements in the status bar will inform you about the orientation and size<br>" +
+                "of the object being drawn. There is a new \"extrude\" mode that you can use to create<br>" +
+                "rectangular shapes (see below for a short video on this).</h3>" +
+                "<h3>There is also a new option in the tools menu that will make existing shapes into proper<br>" +
+                "rectangles. Note that all this is dependend on the projection you're using; you must use<br>"+
+                "a projection in which rectangles look rectangular and not skewed. Try it out.</h3>"+
+                "<h3>If you dislike the helper line dangling from the mouse cursor, set the \"draw.helper-line\"<br>"+
+                "preference to \"false\"."+
 		"</h3>")), GBC.eol());
 
-		// remove these two keys from preferences if present
+        /*
 		boolean changePrefs = ! (
 			"0.5".equals(Main.pref.get("osm-server.version", "0.5")) &&
@@ -69,6 +71,8 @@
 			panel.add(new JLabel(tr("<html><h3>Your preferences have been changed by removing <b>osm-server.version</b> and/or <b>osm-server.additional-versions</b> which were still referring to 0.4.</h3></html>")), GBC.eol());
 		}
+        */
 		
 		addLine("wiki", tr("Read the [Wiki page on API 0.5]"));
+		addLine("extrudevideo", tr("Short (sound-less) [video] demonstrating the new \"extrude\" feature"));
 
 		addLine("audio", tr("This version also has built-in support for [Audio Mapping] with continuously recorded sound tracks."));
@@ -120,4 +124,6 @@
 		else if (e.getActionCommand().equals("mailinglist"))
 			OpenBrowser.displayUrl("mailto:newbies-subscribe@openstreetmap.org?subject=subscribe");
+		else if (e.getActionCommand().equals("extrudevideo"))
+			OpenBrowser.displayUrl("http://josm.openstreetmap.de/download/tutorials/josm-extrude-feature.mpeg");
     }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 608)
@@ -1,3 +1,4 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
+
 package org.openstreetmap.josm.gui;
 
@@ -14,4 +15,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.AlignInRectangleAction;
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.actions.AboutAction;
@@ -93,4 +95,5 @@
 	public final JosmAction alignInCircle = new AlignInCircleAction();
 	public final JosmAction alignInLine = new AlignInLineAction();
+	public final JosmAction alignInRect = new AlignInRectangleAction();
 	public final JosmAction mergeNodes = new MergeNodesAction();
 	public final JosmAction joinNodeWay = new JoinNodeWayAction();
@@ -207,4 +210,6 @@
 		current = toolsMenu.add(alignInLine);
 		current.setAccelerator(alignInLine.shortCut);
+		current = toolsMenu.add(alignInRect);
+		current.setAccelerator(alignInRect.shortCut);
 		toolsMenu.addSeparator();
 		current = toolsMenu.add(mergeNodes);
Index: /trunk/src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 608)
@@ -1,3 +1,4 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
+
 package org.openstreetmap.josm.gui;
 
@@ -16,4 +17,5 @@
 import org.openstreetmap.josm.actions.mapmode.DeleteAction;
 import org.openstreetmap.josm.actions.mapmode.DrawAction;
+import org.openstreetmap.josm.actions.mapmode.ExtrudeAction;
 import org.openstreetmap.josm.actions.mapmode.MapMode;
 import org.openstreetmap.josm.actions.mapmode.SelectAction;
@@ -81,5 +83,6 @@
 		toolBarActions.add(new IconToggleButton(new DrawAction(this)));
 		toolBarActions.add(new IconToggleButton(new DeleteAction(this)));
-
+		toolBarActions.add(new IconToggleButton(new ExtrudeAction(this)));
+		
 		for (Component c : toolBarActions.getComponents())
 			toolGroup.add((AbstractButton)c);
Index: /trunk/src/org/openstreetmap/josm/gui/MapScaler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MapScaler.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/MapScaler.java	(revision 608)
@@ -1,3 +1,4 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
+
 package org.openstreetmap.josm.gui;
 
@@ -28,6 +29,6 @@
 		LatLon ll1 = mv.getLatLon(0,0);
 		LatLon ll2 = mv.getLatLon(100,0);
-		int dist = ll1.distance(ll2);
-		String text = dist > 1000 ? (Math.round(dist/100)/10.0)+"km" : dist+"m";
+		double dist = ll1.greatCircleDistance(ll2);
+		String text = dist > 1000 ? (Math.round(dist/100)/10.0)+"km" : Math.round(dist*10)/10+"m";
 		Rectangle2D bound = g.getFontMetrics().getStringBounds(text, g);
 		g.setColor(ColorHelper.html2color(Main.pref.get("color.scale", "#ffffff")));
Index: /trunk/src/org/openstreetmap/josm/gui/MapStatus.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MapStatus.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/MapStatus.java	(revision 608)
@@ -1,3 +1,4 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
+
 package org.openstreetmap.josm.gui;
 
@@ -5,4 +6,5 @@
 
 import java.awt.AWTEvent;
+import java.awt.Color;
 import java.awt.Cursor;
 import java.awt.Dimension;
@@ -38,4 +40,5 @@
 import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
 
 /**
@@ -47,5 +50,5 @@
  *
  * The background thread does not alter any data of the map (read only thread).
- * Also it is rather fail safe. In case of some error in the data, it just do
+ * Also it is rather fail safe. In case of some error in the data, it just does
  * nothing instead of whining and complaining.
  *
@@ -55,23 +58,45 @@
 
 	/**
-	 * The MapView this status belongs.
+	 * The MapView this status belongs to.
 	 */
 	final MapView mv;
-	/**
-	 * The position of the mouse cursor.
-	 */
-	DecimalFormat latlon = new DecimalFormat("###0.0000000");
-	JTextField positionText = new JTextField(25);
 	
-	/**
-	 * The field holding the name of the object under the mouse.
-	 */
-	JTextField nameText = new JTextField(30);
-
-	/**
-	 * The field holding information about what the user can do.
-	 */
-	JTextField helpText = new JTextField();
-	
+	/** 
+	 * A small user interface component that consists of an image label and
+	 * a fixed text content to the right of the image.
+	 */
+	class ImageLabel extends JPanel {
+		private JLabel tf; 
+		private JLabel lbl;
+		private int chars;
+		public ImageLabel(String img, String tooltip, int chars) {
+			super();
+			setLayout(new GridBagLayout());
+			setBackground(Color.decode("#b8cfe5"));
+			add(lbl = new JLabel(ImageProvider.get("statusline/"+img+".png")), GBC.std().anchor(GBC.WEST).insets(0,1,1,0));
+			add(tf = new JLabel(), GBC.std().fill(GBC.BOTH).anchor(GBC.WEST).insets(2,1,1,0));
+			setToolTipText(tooltip);
+			this.chars = chars;
+		}
+		public void setText(String t) {
+			tf.setText(t);
+		}
+		@Override public Dimension getPreferredSize() {
+			return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getPreferredSize().height);
+		}
+		@Override public Dimension getMinimumSize() {
+			return new Dimension(25 + chars*tf.getFontMetrics(tf.getFont()).charWidth('0'), super.getMinimumSize().height);	
+		}
+	}
+
+    DecimalFormat latlon = new DecimalFormat("###0.0000");
+    ImageLabel lonText = new ImageLabel("lon", tr("The geographic longitude at the mouse pointer."), 8);
+    ImageLabel nameText = new ImageLabel("name", tr("The name of the object at the mouse pointer."), 20);
+    JTextField helpText = new JTextField();
+    ImageLabel latText = new ImageLabel("lat", tr("The geograpgic latitude at the mouse pointer."), 7);
+    ImageLabel angleText = new ImageLabel("angle", tr("The angle between the previous and the current way segment."), 6);
+    ImageLabel headingText = new ImageLabel("heading", tr("The (compass) heading of the line segment being drawn."), 6);
+    ImageLabel distText = new ImageLabel("dist", tr("The length of the new way segment being drawn."), 8);
+
 	/**
 	 * The collector class that waits for notification and then update
@@ -119,4 +144,14 @@
 					continue;
 
+				OsmPrimitive osmNearest = null;
+				// Set the text label in the bottom status bar
+				osmNearest = mv.getNearest(ms.mousePos);
+				if (osmNearest != null) {
+					NameVisitor visitor = new NameVisitor();
+					osmNearest.visit(visitor);
+					nameText.setText(visitor.name);
+				} else
+					nameText.setText("(no object)");				
+
 				// This try/catch is a hack to stop the flooding bug reports about this.
 				// The exception needed to handle with in the first place, means that this
@@ -132,19 +167,4 @@
 						if (osms != null && osms.equals(osmStatus) && ms.modifiers == oldModifiers)
 							continue;
-					/*
-					osmStatus = osms;
-					oldModifiers = ms.modifiers;
-
-					OsmPrimitive osmNearest = null;
-					// Set the text label in the bottom status bar
-					osmNearest = mv.getNearest(ms.mousePos);
-					if (osmNearest != null) {
-						NameVisitor visitor = new NameVisitor();
-						osmNearest.visit(visitor);
-						nameText.setText(visitor.name);
-					} else
-						nameText.setText("");
-					*/
-					
 
 						if (popup != null) {
@@ -247,20 +267,22 @@
 				if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) == 0) {
 					LatLon p = mv.getLatLon(e.getX(),e.getY());
-					positionText.setText(latlon.format(p.lat())+" "+latlon.format(p.lon()));
+					latText.setText(latlon.format(p.lat()));
+					lonText.setText(latlon.format(p.lon()));
 				}
 			}
 		});
 
-		positionText.setEditable(false);
-		nameText.setEditable(false);
-		helpText.setEditable(false);
 		setLayout(new GridBagLayout());
 		setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-		add(new JLabel(tr("Lat/Lon")+" "), GBC.std());
-		add(positionText, GBC.std());
-		//add(new JLabel(" "+tr("Object")+" "));
-		//add(nameText);
-		add(helpText, GBC.eol().fill(GBC.HORIZONTAL));
-		positionText.setMinimumSize(new Dimension(positionText.getMinimumSize().height, 200));
+
+        add(latText, GBC.std());
+        add(lonText, GBC.std().insets(3,0,0,0));
+        add(headingText, GBC.std().insets(3,0,0,0));
+        add(angleText, GBC.std().insets(3,0,0,0));
+        add(distText, GBC.std().insets(3,0,0,0));
+
+		helpText.setEditable(false);
+		add(nameText, GBC.std().insets(3,0,0,0));
+		add(helpText, GBC.eol().insets(3,0,0,0).fill(GBC.HORIZONTAL));
 		
 		// The background thread
@@ -317,4 +339,16 @@
 	public void setHelpText(String t) {
 		helpText.setText(t);
-	}
+		helpText.setToolTipText(t);
+	}
+	public void setAngle(double a) {
+		angleText.setText(a < 0 ? "--" : Math.round(a*10)/10.0 + "°");
+	}
+	public void setHeading(double h) {
+		headingText.setText(h < 0 ? "--" : Math.round(h*10)/10.0 + "°");
+	}
+	public void setDist(double dist) {
+		String text = dist > 1000 ? (Math.round(dist/100)/10.0)+"km" : Math.round(dist*10)/10 +"m";
+		distText.setText(dist < 0 ? "--" : text);
+	}
+	
 }
Index: /trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 608)
@@ -1,3 +1,4 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
+
 package org.openstreetmap.josm.gui;
 
@@ -23,4 +24,5 @@
 import org.openstreetmap.josm.actions.MoveAction;
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.coor.EastNorth;
@@ -29,7 +31,7 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
-import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.MapViewPaintable;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer.ModifiedChangedListener;
@@ -79,4 +81,6 @@
 	private Layer activeLayer;
 	
+	private LinkedList<MapViewPaintable> temporaryLayers = new LinkedList<MapViewPaintable>();
+	
 	/**
 	 * The listener of the active layer changes.
@@ -195,5 +199,5 @@
 		if (center == null)
 			return; // no data loaded yet.
-		g.setColor(SimplePaintVisitor.getPreferencesColor("background", Color.BLACK));
+		g.setColor(Preferences.getPreferencesColor("background", Color.BLACK));
 		g.fillRect(0, 0, getWidth(), getHeight());
 
@@ -203,7 +207,12 @@
 				l.paint(g, this);
 		}
+		
 		if (getActiveLayer() != null && getActiveLayer().visible)
 			getActiveLayer().paint(g, this);
 
+		for (MapViewPaintable mvp : temporaryLayers) {
+			mvp.paint(g, this);
+		}
+		
 		// draw world borders
 		g.setColor(Color.WHITE);
@@ -330,3 +339,12 @@
 			firePropertyChange("scale", oldScale, scale);
 	}
+	
+	public boolean addTemporaryLayer(MapViewPaintable mvp) {
+		if (temporaryLayers.contains(mvp)) return false;
+		return temporaryLayers.add(mvp);
+	}
+	
+	public boolean removeTemporaryLayer(MapViewPaintable mvp) {
+		return temporaryLayers.remove(mvp);
+	}
 }
Index: /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 608)
@@ -1,3 +1,4 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
+
 package org.openstreetmap.josm.gui;
 
@@ -98,8 +99,6 @@
 	 */
 	public LatLon getLatLon(int x, int y) {
-		EastNorth eastNorth = new EastNorth(
-				center.east() + (x - getWidth()/2.0)*scale,
-				center.north() - (y - getHeight()/2.0)*scale);
-		return getProjection().eastNorth2latlon(eastNorth);
+
+		return getProjection().eastNorth2latlon(getEastNorth(x, y));
 	}
 
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java	(revision 608)
@@ -1,3 +1,3 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
 package org.openstreetmap.josm.gui.dialogs;
 
@@ -31,4 +31,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.command.ConflictResolveCommand;
+import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.SelectionChangedListener;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -38,5 +39,4 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
 import org.openstreetmap.josm.gui.ConflictResolver;
@@ -144,5 +144,5 @@
 	 */
 	public void paintConflicts(final Graphics g, final NavigatableComponent nc) {
-		Color preferencesColor = SimplePaintVisitor.getPreferencesColor("conflict", Color.gray);
+		Color preferencesColor = Preferences.getPreferencesColor("conflict", Color.gray);
 		if (preferencesColor.equals(Color.BLACK))
 			return;
Index: /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 608)
@@ -1,3 +1,3 @@
-//License: GPL. Copyright 2007 by Immanuel Scholz, Raphael Mack and others
+// License: GPL. See LICENSE file for details.
 
 package org.openstreetmap.josm.gui.layer;
@@ -321,5 +321,5 @@
 						
                                             // draw line, if no maxLineLength is set or the line is shorter.
-                                            if (maxLineLength == -1 || trkPnt.latlon.distance(oldWp.latlon) <= maxLineLength){
+                                            if (maxLineLength == -1 || trkPnt.latlon.greatCircleDistance(oldWp.latlon) <= maxLineLength){
                                                 g.drawLine(old.x, old.y, screen.x, screen.y);
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 608)
@@ -1,3 +1,4 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
+
 package org.openstreetmap.josm.gui.layer;
 
@@ -29,5 +30,5 @@
  * @author imi
  */
-abstract public class Layer implements Destroyable {
+abstract public class Layer implements Destroyable, MapViewPaintable {
 
 	/**
Index: /trunk/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java	(revision 608)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/MapViewPaintable.java	(revision 608)
@@ -0,0 +1,16 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+package org.openstreetmap.josm.gui.layer;
+
+import java.awt.Graphics;
+
+import org.openstreetmap.josm.gui.MapView;
+
+public interface MapViewPaintable {
+
+	/**
+	 * Paint the dataset using the engine set.
+	 * @param mv The object that can translate GeoPoints to screen coordinates.
+	 */
+	abstract public void paint(Graphics g, MapView mv);
+
+}
Index: /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 608)
@@ -1,3 +1,4 @@
-// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// License: GPL. See LICENSE file for details.
+
 package org.openstreetmap.josm.gui.layer;
 
@@ -33,4 +34,5 @@
 import org.openstreetmap.josm.actions.SaveAsAction;
 import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -153,6 +155,6 @@
 					Point p1 = mv.getPoint(en1);
 					Point p2 = mv.getPoint(en2);
-					Color color = inactive ? SimplePaintVisitor.getPreferencesColor("inactive", Color.DARK_GRAY) :
-							SimplePaintVisitor.getPreferencesColor("downloaded Area", Color.YELLOW);
+					Color color = inactive ? Preferences.getPreferencesColor("inactive", Color.DARK_GRAY) :
+							Preferences.getPreferencesColor("downloaded Area", Color.YELLOW);
 					g.setColor(color);
 					g.drawRect(Math.min(p1.x,p2.x), Math.min(p1.y, p2.y), Math.abs(p2.x-p1.x), Math.abs(p2.y-p1.y));
Index: /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/PlayHeadMarker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/PlayHeadMarker.java	(revision 607)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/PlayHeadMarker.java	(revision 608)
@@ -1,2 +1,4 @@
+// License: GPL. See LICENSE file for details.
+
 package org.openstreetmap.josm.gui.layer.markerlayer;
 
@@ -226,5 +228,5 @@
 			for (Marker m : AudioMarker.recentlyPlayedMarker().parentLayer.data) {
 				if (m instanceof AudioMarker) {
-					double distanceSquared = m.eastNorth.distance(en);
+					double distanceSquared = m.eastNorth.distanceSq(en);
 					if (distanceSquared < closestAudioMarkerDistanceSquared) {
 						ca = (AudioMarker) m;
