[med-svn] [imagej] 01/06: New upstream version 1.51i+dfsg

Andreas Tille tille at debian.org
Sun Dec 25 08:29:52 UTC 2016


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository imagej.

commit 80946189290d785888f17c9533cf14122bd41a0e
Author: Andreas Tille <tille at debian.org>
Date:   Sun Dec 25 09:04:46 2016 +0100

    New upstream version 1.51i+dfsg
---
 IJ_Props.txt                               |   4 +-
 ij/IJ.java                                 |  10 +-
 ij/ImageJ.java                             |  10 +-
 ij/ImagePlus.java                          |  78 +++++++-----
 ij/ImageStack.java                         |  11 +-
 ij/Macro.java                              |   8 --
 ij/Menus.java                              |   2 +
 ij/OtherInstance.java                      |  17 +--
 ij/Prefs.java                              |  28 ++--
 ij/Undo.java                               |   2 +-
 ij/VirtualStack.java                       |  24 +++-
 ij/gui/GenericDialog.java                  |  57 ++++++++-
 ij/gui/ImageCanvas.java                    |   7 +-
 ij/gui/ImageWindow.java                    |  26 +++-
 ij/gui/MultiLineLabel.java                 |   3 +-
 ij/gui/NewImage.java                       |  72 ++++++++---
 ij/gui/Overlay.java                        |   9 +-
 ij/gui/Plot.java                           | 118 +++++++++++++++--
 ij/gui/PlotContentsStyleDialog.java        |  87 +++++++++++++
 ij/gui/PlotWindow.java                     |  33 +++--
 ij/gui/PointRoi.java                       | 110 +++++++++++++---
 ij/gui/PolygonRoi.java                     |   5 +-
 ij/gui/Roi.java                            | 197 ++++++++++++++++++++++++++++-
 ij/gui/RoiProperties.java                  |  17 ++-
 ij/gui/ShapeRoi.java                       |   4 +-
 ij/gui/StackWindow.java                    |   2 +-
 ij/gui/TextRoi.java                        |   7 +-
 ij/io/FileOpener.java                      |  22 +++-
 ij/io/FileSaver.java                       |   2 +-
 ij/io/ImportDialog.java                    |  13 +-
 ij/io/OpenDialog.java                      |   9 +-
 ij/io/Opener.java                          |   8 +-
 ij/io/RoiDecoder.java                      |   4 +
 ij/macro/Functions.java                    |  46 ++++++-
 ij/macro/Interpreter.java                  |   4 +-
 ij/macro/MacroConstants.java               |   2 +-
 ij/macro/MacroRunner.java                  |   7 +-
 ij/measure/CurveFitter.java                |  39 ++++--
 ij/measure/Measurements.java               |   6 +
 ij/measure/ResultsTable.java               |  11 +-
 ij/plugin/Animator.java                    |   4 +-
 ij/plugin/AppearanceOptions.java           |  22 ++--
 ij/plugin/BatchConverter.java              |   2 +-
 ij/plugin/CommandFinder.java               |  26 ++--
 ij/plugin/Commands.java                    |   8 +-
 ij/plugin/Compiler.java                    |  35 +++--
 ij/plugin/Concatenator.java                |  63 ++++++++-
 ij/plugin/ContrastEnhancer.java            |   2 +-
 ij/plugin/Coordinates.java                 | 124 ++++++++++++++++++
 ij/plugin/DICOM.java                       |  61 ++++++++-
 ij/plugin/Duplicator.java                  | 151 ++++++++++++++++------
 ij/plugin/FFT.java                         |   6 +-
 ij/plugin/FITS_Reader.java                 |   2 +-
 ij/plugin/FileInfoVirtualStack.java        |   6 +-
 ij/plugin/FolderOpener.java                |  17 ++-
 ij/plugin/GelAnalyzer.java                 |  17 ++-
 ij/plugin/Hotkeys.java                     |   8 +-
 ij/plugin/ImageCalculator.java             |   2 +-
 ij/plugin/ImageInfo.java                   |  22 +++-
 ij/plugin/ImageJ_Updater.java              |   4 +
 ij/plugin/MontageMaker.java                |  49 ++++---
 ij/plugin/Options.java                     |   6 +-
 ij/plugin/OverlayCommands.java             |  77 ++++++-----
 ij/plugin/OverlayLabels.java               |   4 +-
 ij/plugin/PointToolOptions.java            |  40 ++++--
 ij/plugin/Profiler.java                    |   2 +-
 ij/plugin/Resizer.java                     |  57 +--------
 ij/plugin/RoiEnlarger.java                 |  11 +-
 ij/plugin/Scaler.java                      |  43 ++++---
 ij/plugin/Selection.java                   |  33 ++++-
 ij/plugin/SimpleCommands.java              |   2 +-
 ij/plugin/Slicer.java                      |  36 ++++--
 ij/plugin/StackCombiner.java               |  29 ++++-
 ij/plugin/Startup.java                     |   7 +-
 ij/plugin/SubstackMaker.java               |   3 +-
 ij/plugin/ZAxisProfiler.java               |  34 ++++-
 ij/plugin/ZProjector.java                  |   8 +-
 ij/plugin/filter/Analyzer.java             |  58 +++++++--
 ij/plugin/filter/Convolver.java            |   2 +-
 ij/plugin/filter/FractalBoxCounter.java    |   2 +-
 ij/plugin/filter/ImageMath.java            |  15 +++
 ij/plugin/filter/MaximumFinder.java        |   4 +-
 ij/plugin/filter/ParticleAnalyzer.java     |  17 ++-
 ij/plugin/filter/Rotator.java              |   2 +-
 ij/plugin/filter/StackLabeler.java         |   8 +-
 ij/plugin/filter/ThresholdToSelection.java |  11 +-
 ij/plugin/frame/Channels.java              |   2 +-
 ij/plugin/frame/ContrastAdjuster.java      |   7 +-
 ij/plugin/frame/LineWidthAdjuster.java     |  15 ++-
 ij/plugin/frame/PlugInDialog.java          |  11 +-
 ij/plugin/frame/PlugInFrame.java           |   2 +-
 ij/plugin/frame/Recorder.java              |   2 +
 ij/plugin/frame/RoiManager.java            |  35 +++--
 ij/plugin/frame/ThresholdAdjuster.java     |  18 +--
 ij/process/AutoThresholder.java            |   8 +-
 ij/process/ByteProcessor.java              |   1 +
 ij/process/ByteStatistics.java             |   4 +-
 ij/process/FloatProcessor.java             |   3 +-
 ij/process/FloatStatistics.java            |   7 +-
 ij/process/ImageProcessor.java             |  61 +++++++--
 ij/process/ImageStatistics.java            |   6 +
 ij/process/ShortProcessor.java             |  16 +--
 ij/text/TextCanvas.java                    |  25 ++--
 ij/text/TextPanel.java                     |  22 +++-
 release-notes.html                         |  58 ++++++---
 105 files changed, 1933 insertions(+), 633 deletions(-)

diff --git a/IJ_Props.txt b/IJ_Props.txt
index 2727193..aecadc9 100644
--- a/IJ_Props.txt
+++ b/IJ_Props.txt
@@ -5,7 +5,7 @@
 
 # Note that commands must be unique.
 
-# Version 1.50
+# Version 1.51
 
 # Commands installed in the right-click popup menu
 # Overridden in StartupMacros
@@ -123,6 +123,8 @@ adjust05="Color Threshold...",ij.plugin.frame.ColorThresholder
 adjust06="Size...",ij.plugin.Resizer
 adjust07="Canvas Size...",ij.plugin.CanvasResizer
 adjust08="Line Width... ",ij.plugin.frame.LineWidthAdjuster
+adjust09="Coordinates...",ij.plugin.Coordinates
+
 
 # Plugins installed in the Image/Color submenu
 color01="Split Channels",ij.plugin.ChannelSplitter
diff --git a/ij/IJ.java b/ij/IJ.java
index 820860c..23a6517 100644
--- a/ij/IJ.java
+++ b/ij/IJ.java
@@ -48,7 +48,7 @@ public class IJ {
 	private static ProgressBar progressBar;
 	private static TextPanel textPanel;
 	private static String osname, osarch;
-	private static boolean isMac, isWin, isJava16, isJava17, isJava18, isLinux, is64Bit;
+	private static boolean isMac, isWin, isJava16, isJava17, isJava18, isJava19, isLinux, is64Bit;
 	private static boolean controlDown, altDown, spaceDown, shiftDown;
 	private static boolean macroRunning;
 	private static Thread previousThread;
@@ -78,6 +78,7 @@ public class IJ {
 			isJava16 = version.compareTo("1.5")>0;
 			isJava17 = version.compareTo("1.6")>0;
 			isJava18 = version.compareTo("1.7")>0;
+			isJava19 = version.compareTo("1.8")>0;
 		}
 		dfs = new DecimalFormatSymbols(Locale.US);
 		df = new DecimalFormat[10];
@@ -793,7 +794,7 @@ public class IJ {
 			return "3.4e38";
 		double np = n;
 		if (n<0.0) np = -n;
-		if (decimalPlaces<0) {
+		if (decimalPlaces<0) synchronized(IJ.class) {
 			decimalPlaces = -decimalPlaces;
 			if (decimalPlaces>9) decimalPlaces=9;
 			if (sf==null) {
@@ -983,6 +984,11 @@ public class IJ {
 		return isJava18;
 	}
 
+	/** Returns true if ImageJ is running on a Java 1.9 or greater JVM. */
+	public static boolean isJava19() {
+		return isJava19;
+	}
+
 	/** Returns true if ImageJ is running on Linux. */
 	public static boolean isLinux() {
 		return isLinux;
diff --git a/ij/ImageJ.java b/ij/ImageJ.java
index 202f0dc..f640a38 100644
--- a/ij/ImageJ.java
+++ b/ij/ImageJ.java
@@ -79,7 +79,7 @@ public class ImageJ extends Frame implements ActionListener,
 	MouseListener, KeyListener, WindowListener, ItemListener, Runnable {
 
 	/** Plugins should call IJ.getVersion() or IJ.getFullVersion() to get the version string. */
-	public static final String VERSION = "1.50i";
+	public static final String VERSION = "1.51i";
 	public static final String BUILD = "";
 	public static Color backgroundColor = new Color(237,237,237);
 	/** SansSerif, 12-point, plain font. */
@@ -189,6 +189,7 @@ public class ImageJ extends Frame implements ActionListener,
 			if (IJ.isWindows()) try {setIcon();} catch(Exception e) {}
 			setLocation(loc.x, loc.y);
 			setResizable(false);
+			setAlwaysOnTop(Prefs.alwaysOnTop);
 			pack();
 			setVisible(true);
 		}
@@ -386,7 +387,6 @@ public class ImageJ extends Frame implements ActionListener,
 	public void mouseEntered(MouseEvent e) {}
 
  	public void keyPressed(KeyEvent e) {
- 		//if (e.isConsumed()) return;
 		int keyCode = e.getKeyCode();
 		IJ.setKeyDown(keyCode);
 		hotkey = false;
@@ -463,6 +463,8 @@ public class ImageJ extends Frame implements ActionListener,
 				case KeyEvent.VK_BACK_SPACE: // delete
 					if (deleteOverlayRoi(imp))
 						return;
+					if (imp!=null&&imp.getOverlay()!=null&&imp==GelAnalyzer.getGelImage())
+						return;
 					cmd="Clear";
 					hotkey=true;
 					break; 
@@ -610,6 +612,7 @@ public class ImageJ extends Frame implements ActionListener,
 			if (mb!=null && mb!=getMenuBar()) {
 				setMenuBar(mb);
 				Menus.setMenuBarCount++;
+				if (IJ.debugMode) IJ.log("setMenuBar: "+Menus.setMenuBarCount);
 			}
 		}
 	}
@@ -691,7 +694,8 @@ public class ImageJ extends Frame implements ActionListener,
 		}
   		// If existing ImageJ instance, pass arguments to it and quit.
   		boolean passArgs = mode==STANDALONE && !noGUI;
-		if (IJ.isMacOSX() && !commandLine) passArgs = false;
+		if (IJ.isMacOSX() && !commandLine)
+			passArgs = false;
 		if (passArgs && isRunning(args)) 
   			return;
  		ImageJ ij = IJ.getInstance();    	
diff --git a/ij/ImagePlus.java b/ij/ImagePlus.java
index c6717ca..6f66790 100644
--- a/ij/ImagePlus.java
+++ b/ij/ImagePlus.java
@@ -90,7 +90,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
 	private static int default16bitDisplayRange;
 	private boolean antialiasRendering = true;
 	private boolean ignoreGlobalCalibration;
-	public boolean setIJMenuBar = true;
+	public boolean setIJMenuBar = Prefs.setIJMenuBar;
 	public boolean typeSet;
 	
 
@@ -444,6 +444,8 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
 				if (c>1 || z>1 || t>1)
 					setPosition(c, z, t);
 			}
+			if (setIJMenuBar)
+				IJ.wait(25);
 			notifyListeners(OPENED);
 		}
 	}
@@ -820,42 +822,47 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
 		return mask;
 	}
 
-	/** Returns an ImageStatistics object generated using the standard
-		measurement options (area, mean, mode, min and max).
-		This plugin demonstrates how get the area, mean and max of the
-		current image or selection:
+	/** Get calibrated statistics for this image or ROI, including 
+		 histogram, area, mean, min and max, standard
+		 deviation and mode.
+		This code demonstrates how to get the area, mean
+		max and median of the current image or selection:
 		<pre>
-   public class Get_Statistics implements PlugIn {
-      public void run(String arg) {
-         ImagePlus imp = IJ.getImage();
-         ImageStatistics stats = imp.getStatistics();
+         imp = IJ.getImage();
+         stats = imp.getStatistics();
          IJ.log("Area: "+stats.area);
          IJ.log("Mean: "+stats.mean);
          IJ.log("Max: "+stats.max);
-      }
-   }
 		</pre>
+		@see #getAllStatistics
+		@see #getRawStatistics
+		@see ij.process.ImageProcessor#getStats
 		@see ij.process.ImageStatistics
 		@see ij.process.ImageStatistics#getStatistics
 		*/
 	public ImageStatistics getStatistics() {
-		return getStatistics(AREA+MEAN+MODE+MIN_MAX);
+		return getStatistics(AREA+MEAN+STD_DEV+MODE+MIN_MAX+RECT);
 	}
 	
+	/** This method returns complete calibrated statistics for this image or ROI
+		(with "Limit to threshold"), but it is up to 70 times slower than getStatistics().*/
+	public ImageStatistics getAllStatistics() {
+		return getStatistics(ALL_STATS+LIMIT);
+	}
+
+	/* Returns uncalibrated statistics for this image or ROI, including
+		256 bin histogram, pixelCount, mean, mode, min and max. */
+	public ImageStatistics getRawStatistics() {
+		setupProcessor();
+		if (roi!=null && roi.isArea())
+			ip.setRoi(roi);
+		else
+			ip.resetRoi();
+		return ImageStatistics.getStatistics(ip, AREA+MEAN+MODE+MIN_MAX, null);
+	}
+
 	/** Returns an ImageStatistics object generated using the
-		specified measurement options. This plugin demonstrates how
-		get the area and centroid of the current selection:
-		<pre>
-   public class Get_Statistics implements PlugIn, Measurements {
-      public void run(String arg) {
-         ImagePlus imp = IJ.getImage();
-         ImageStatistics stats = imp.getStatistics(MEDIAN+CENTROID);
-         IJ.log("Median: "+stats.median);
-         IJ.log("xCentroid: "+stats.xCentroid);
-         IJ.log("yCentroid: "+stats.yCentroid);
-      }
-   }
-		</pre>
+		specified measurement options.
 		@see ij.process.ImageStatistics
 		@see ij.measure.Measurements
 	*/
@@ -1541,10 +1548,10 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
 			setCurrentSlice(n);
 			Object pixels = null;
 			Overlay overlay2 = null;
-			if (stack.isVirtual() && !(stack instanceof FileInfoVirtualStack)) {
+			if (stack.isVirtual() && !((stack instanceof FileInfoVirtualStack)||(stack instanceof AVI_Reader))) {
 				ImageProcessor ip2 = stack.getProcessor(currentSlice);
 				overlay2 = ip2.getOverlay();
-				if (overlay2!=null || getOverlay()!=null)
+				if (overlay2!=null)
 					setOverlay(overlay2);
 				pixels = ip2.getPixels();
 			} else
@@ -1564,7 +1571,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
 			if (win!=null && win instanceof StackWindow)
 				((StackWindow)win).updateSliceSelector();
 			if ((Prefs.autoContrast||IJ.shiftKeyDown()) && nChannels==1 && imageType!=COLOR_RGB) {
-				(new ContrastEnhancer()).stretchHistogram(ip,0.35,ip.getStatistics());
+				(new ContrastEnhancer()).stretchHistogram(ip,0.35,ip.getStats());
 				ContrastAdjuster.update();
 				//IJ.showStatus(n+": min="+ip.getMin()+", max="+ip.getMax());
 			}
@@ -1993,11 +2000,22 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
 	}
 	
 
-	/** Returns a copy (clone) of this ImagePlus. */
+	/** Returns a copy of this image or stack, cropped if there is an ROI.
+	* @see #crop
+	* @see ij.plugin.Duplicator#run
+	*/
 	public ImagePlus duplicate() {
 		return (new Duplicator()).run(this);
 	}
 
+	/** Returns a copy this image or stack slice, cropped if there is an ROI.
+	* @see #duplicate
+	* @see ij.plugin.Duplicator#crop
+	*/
+	public ImagePlus crop() {
+		return (new Duplicator()).crop(this);
+	}
+
 	/** Returns a new ImagePlus with this image's attributes
 		(e.g. spatial scale), but no image. */
 	public ImagePlus createImagePlus() {
@@ -2679,7 +2697,7 @@ public class ImagePlus implements ImageObserver, Measurements, Cloneable {
     }
     
     public boolean setIJMenuBar() {
-    	return setIJMenuBar;
+    	return setIJMenuBar && Prefs.setIJMenuBar;
     }
     
 }
diff --git a/ij/ImageStack.java b/ij/ImageStack.java
index 7bf59e7..f3c2f29 100644
--- a/ij/ImageStack.java
+++ b/ij/ImageStack.java
@@ -103,7 +103,7 @@ public class ImageStack {
 		the string 'sliceLabel' as the slice metadata. */
 	public void addSlice(String sliceLabel, ImageProcessor ip) {
 		if (ip.getWidth()!=width || ip.getHeight()!=height)
-			throw new IllegalArgumentException("Dimensions do not match");
+			throw new IllegalArgumentException("ImageStack.addSlice(): dimensions do not match");
 		if (nSlices==0) {
 			cm = ip.getColorModel();
 			min = ip.getMin();
@@ -193,6 +193,8 @@ public class ImageStack {
 		if (n<1 || n>nSlices)
 			throw new IllegalArgumentException(outOfRange+n);
 		stack[n-1] = pixels;
+		if (type==UNKNOWN)
+			setType(pixels);
 	}
 	
 	/** Returns the stack as an array of 1D pixel arrays. Note
@@ -344,7 +346,8 @@ public class ImageStack {
 		return ("stack["+getWidth()+"x"+getHeight()+"x"+getSize()+v+"]");
 	}
 	
-	/** Returns, as a double, the specified voxel. Use the
+	/** Returns, as a double, the specified voxel. Returns
+	 * NaN if x, y or z are beyond the stack limits. Use the
 	 * ImagePlus.getStackIndex() method to convert a C,Z,T
 	 * hyperstack position (one-based) into a z index (zero-based).
 	 * @see ij.ImagePlus#getStackIndex
@@ -364,10 +367,10 @@ public class ImageStack {
 				case RGB:
 					int[] ints = (int[])stack[z];
 					return ints[y*width+x]&0xffffffff;
-				default: return 0.0;
+				default: return Double.NaN;
 			}
 		} else
-			return 0.0;
+			throw new IndexOutOfBoundsException();
 	}
 		
 	/* Sets the value of the specified voxel. */
diff --git a/ij/Macro.java b/ij/Macro.java
index 2bfec53..e1a2e92 100644
--- a/ij/Macro.java
+++ b/ij/Macro.java
@@ -134,14 +134,6 @@ public class Macro {
 			else
 				return options.substring(1, index);
 		} else {
-			//if (options.indexOf('=')==-1) {
-			//	options = options.trim();
-			//	IJ.log("getValue: "+key+"  |"+options+"|");
-			//	if (options.length()>0)
-			//		return options;
-			//	else
-			//		return defaultValue;
-			//}
 			index = options.indexOf(" ");
 			if (index<0)
 				return defaultValue;
diff --git a/ij/Menus.java b/ij/Menus.java
index 9148eab..cab9bd9 100644
--- a/ij/Menus.java
+++ b/ij/Menus.java
@@ -293,6 +293,7 @@ public class Menus {
 		addExample(submenu, "Overlay", "Overlay.js");
 		addExample(submenu, "Stack Overlay", "Stack_Overlay.js");
 		addExample(submenu, "Dual Progress Bars", "Dual_Progress_Bars.js");
+		addExample(submenu, "Gamma Adjuster", "Gamma_Adjuster.js");
 		submenu.addActionListener(listener);
 		menu.add(submenu);
 		submenu = new Menu("BeanShell");
@@ -316,6 +317,7 @@ public class Menus {
 		addExample(submenu, "Plugin Filter", "Filter_Plugin.java");
 		addExample(submenu, "Plugin Frame", "Plugin_Frame.java");
 		addExample(submenu, "Plugin Tool", "Prototype_Tool.java");
+		addExample(submenu, "Gamma Adjuster", "Gamma_Adjuster.java");
 		submenu.addActionListener(listener);
 		menu.add(submenu);
 		menu.addSeparator();
diff --git a/ij/OtherInstance.java b/ij/OtherInstance.java
index 0b2d58d..0b989eb 100644
--- a/ij/OtherInstance.java
+++ b/ij/OtherInstance.java
@@ -124,19 +124,18 @@ public class OtherInstance {
 		if (!isRMIEnabled())
 			return false;
 		String file = getStubPath();
-		if (args.length>0) try {
+		try {
 			FileInputStream in = new FileInputStream(file);
 			ImageJInstance instance = (ImageJInstance) new ObjectInputStream(in).readObject();
 			in.close();
 			if (instance==null)
 				return false;
-
-			//IJ.log("sendArguments3: "+instance);
 			instance.sendArgument("user.dir "+System.getProperty("user.dir"));
 			int macros = 0;
 			for (int i=0; i<args.length; i++) {
 				String arg = args[i];
-				if (arg==null) continue;
+				if (arg==null)
+					continue;
 				String cmd = null;
 				if (macros==0 && arg.endsWith(".ijm")) {
 					cmd = "macro " + arg;
@@ -157,8 +156,6 @@ public class OtherInstance {
 				if (cmd!=null)
 					instance.sendArgument(cmd);
 			} // for
-
-			//IJ.log("sendArguments: return true");
 			return true;
 		} catch (Exception e) {
 			if (IJ.debugMode) {
@@ -240,13 +237,7 @@ public class OtherInstance {
 		String env = System.getenv("IJ_PREFS_DIR");
 		if (env != null)
 			return env;
-		if (IJ.isWindows())
-			return System.getProperty("user.dir");
-		String prefsDir = System.getProperty("user.home");
-		if (IJ.isMacOSX())
-			prefsDir += "/Library/Preferences";
 		else
-			prefsDir += "/.imagej";
-		return prefsDir;
+			return Prefs.getPrefsDir();
 	}
 }
diff --git a/ij/Prefs.java b/ij/Prefs.java
index b905866..fb4b787 100644
--- a/ij/Prefs.java
+++ b/ij/Prefs.java
@@ -83,7 +83,7 @@ public class Prefs {
 	public static boolean requireControlKey;
 	/** Open 8-bit images with inverting LUT so 0 is white and 255 is black. */
 	public static boolean useInvertingLut;
-	/** Draw tool icons using antialiasing. */
+	/** Draw tool icons using antialiasing (always true). */
 	public static boolean antialiasedTools = true;
 	/** Export TIFF and Raw using little-endian byte order. */
 	public static boolean intelByteOrder;
@@ -157,6 +157,13 @@ public class Prefs {
 	public static boolean autoRunExamples = true;
 	/** Ignore stack positions when displaying points. */
 	public static boolean showAllPoints;
+	/** Set MenuBar on Macs running Java 8. */
+	public static boolean setIJMenuBar = IJ.isMacOSX();
+	/** "ImageJ" window is always on top. */
+	public static boolean alwaysOnTop;
+	/** Automatically spline fit line selections */
+	public static boolean splineFitLines;
+
 	
 
 	static Properties ijPrefs = new Properties();
@@ -178,12 +185,6 @@ public class Prefs {
 			return loadAppletProps(f, applet);
 		if (homeDir==null)
 			homeDir = System.getProperty("user.dir");
-		String userHome = System.getProperty("user.home");
-		prefsDir = userHome; // User's home directory
-		if (IJ.isMacOSX())
-			prefsDir += "/Library/Preferences";
-		else
-			prefsDir += File.separator+".imagej";
 		if (f==null) {
 			try {f = new FileInputStream(homeDir+"/"+PROPS_NAME);}
 			catch (FileNotFoundException e) {f=null;}
@@ -252,9 +253,17 @@ public class Prefs {
 			return path;
 	}
 
-	/** Gets the path to the directory where the 
+	/** Returns the path to the directory where the 
 		preferences file (IJPrefs.txt) is saved. */
 	public static String getPrefsDir() {
+		if (prefsDir==null) {
+			String dir = System.getProperty("user.home");
+			if (IJ.isMacOSX())
+				dir += "/Library/Preferences";
+			else
+				dir += File.separator+".imagej";
+			prefsDir = dir;
+		}
 		return prefsDir;
 	}
 
@@ -342,7 +351,7 @@ public class Prefs {
 
 	/** Opens the IJ_Prefs.txt file. */
 	static void loadPreferences() {
-		String path = prefsDir+separator+PREFS_NAME;
+		String path = getPrefsDir()+separator+PREFS_NAME;
 		boolean ok =  loadPrefs(path);
 		if (!ok) { // not found
 			if (IJ.isWindows())
@@ -394,6 +403,7 @@ public class Prefs {
 			ImportDialog.savePreferences(prefs);
 			PlotWindow.savePreferences(prefs);
 			NewImage.savePreferences(prefs);
+			String prefsDir = getPrefsDir();
 			path = prefsDir+separator+PREFS_NAME;
 			if (prefsDir.endsWith(".imagej")) {
 				File f = new File(prefsDir);
diff --git a/ij/Undo.java b/ij/Undo.java
index 823118b..e27c327 100644
--- a/ij/Undo.java
+++ b/ij/Undo.java
@@ -91,7 +91,7 @@ public class Undo {
 		calCopy = null;
 		roiCopy = null;
 		lutCopy = null;
-		if (IJ.debugMode) IJ.log("Undo.reset");
+		//if (IJ.debugMode) IJ.log("Undo.reset");
 	}
 	
 
diff --git a/ij/VirtualStack.java b/ij/VirtualStack.java
index 9639ed1..012b1ed 100644
--- a/ij/VirtualStack.java
+++ b/ij/VirtualStack.java
@@ -15,11 +15,12 @@ public class VirtualStack extends ImageStack {
 	private String[] names;
 	private String[] labels;
 	private int bitDepth;
+	private ImageProcessor ip;
 	
 	/** Default constructor. */
 	public VirtualStack() { }
 
-	/** Creates a new, empty virtual stack. */
+	/** Creates an empty virtual stack. */
 	public VirtualStack(int width, int height, ColorModel cm, String path) {
 		super(width, height, cm);
 		this.path = path;
@@ -28,6 +29,20 @@ public class VirtualStack extends ImageStack {
 		//IJ.log("VirtualStack: "+path);
 	}
 
+	/** Creates a virtual stack with no backing storage.
+	This example creates a one million slice virtual
+	stack that uses just 1MB of RAM:
+	<pre>
+    stack = new VirtualStack(1024,1024,1000000);
+    new ImagePlus("No Backing Store Virtual Stack",stack).show();
+	</pre>
+	*/
+	public VirtualStack(int width, int height, int slices) {
+		super(width, height, null);
+		nSlices = slices;
+		bitDepth = 8;
+	}
+
 	 /** Adds an image to the end of the stack. */
 	public void addSlice(String name) {
 		if (name==null) 
@@ -94,6 +109,11 @@ public class VirtualStack extends ImageStack {
 	*/
 	public ImageProcessor getProcessor(int n) {
 		//IJ.log("getProcessor: "+n+"  "+names[n-1]+"  "+bitDepth);
+		if (path==null) {
+			if (ip==null)
+				ip = new ByteProcessor(getWidth(), getHeight());
+			return ip;
+		}
 		Opener opener = new Opener();
 		opener.setSilentMode(true);
 		IJ.redirectErrorMessages(true);
@@ -154,6 +174,8 @@ public class VirtualStack extends ImageStack {
 
 	/** Returns the label of the Nth image. */
 	public String getSliceLabel(int n) {
+		if (labels==null)
+			return null;
 		String label = labels[n-1];
 		if (label==null)
 			return names[n-1];
diff --git a/ij/gui/GenericDialog.java b/ij/gui/GenericDialog.java
index 010fd81..e251c9e 100644
--- a/ij/gui/GenericDialog.java
+++ b/ij/gui/GenericDialog.java
@@ -79,14 +79,28 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
     private String helpURL;
     private String yesLabel, noLabel;
     private boolean smartRecording;
+    private Vector imagePanels;
+    private static GenericDialog instance;
 
     /** Creates a new GenericDialog with the specified title. Uses the current image
     	image window as the parent frame or the ImageJ frame if no image windows
     	are open. Dialog parameters are recorded by ImageJ's command recorder but
     	this requires that the first word of each label be unique. */
 	public GenericDialog(String title) {
-		this(title, WindowManager.getCurrentImage()!=null?
-			(Frame)WindowManager.getCurrentImage().getWindow():IJ.getInstance()!=null?IJ.getInstance():new Frame());
+		this(title, getParentFrame());
+	}
+	
+	private static Frame getParentFrame() {
+		Frame parent = WindowManager.getCurrentImage()!=null?
+			(Frame)WindowManager.getCurrentImage().getWindow():IJ.getInstance()!=null?IJ.getInstance():new Frame();
+		if (IJ.isMacOSX() && IJ.isJava18()) {
+			ImageJ ij = IJ.getInstance();
+			if (ij!=null && ij.isActive())
+				parent = ij;
+			else
+				parent = null;
+		}
+		return parent;
 	}
 
     /** Creates a new GenericDialog using the specified title and parent frame. */
@@ -549,15 +563,18 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
 	* @param columns	the number of columns
 	*/
     public void addTextAreas(String text1, String text2, int rows, int columns) {
-    	if (textArea1!=null) return;
-    	Panel panel = new Panel();
+		if (textArea1!=null) return;
+		Panel panel = new Panel();
+		Font font = new Font("SansSerif", Font.PLAIN, 14);
 		textArea1 = new TextArea(text1,rows,columns,TextArea.SCROLLBARS_NONE);
 		if (IJ.isLinux()) textArea1.setBackground(Color.white);
+		textArea1.setFont(font);
 		textArea1.addTextListener(this);
 		panel.add(textArea1);
 		if (text2!=null) {
 			textArea2 = new TextArea(text2,rows,columns,TextArea.SCROLLBARS_NONE);
 			if (IJ.isLinux()) textArea2.setBackground(Color.white);
+			textArea2.setFont(font);
 			panel.add(textArea2);
 		}
 		c.gridx = 0; c.gridy = y;
@@ -684,7 +701,11 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
     
 	/** Adds an image to the dialog. */
     public void addImage(ImagePlus image) {
-    	addPanel(new ImagePanel(image));
+    	ImagePanel imagePanel = new ImagePanel(image);
+    	addPanel(imagePanel);
+    	if (imagePanels==null)
+    		imagePanels = new Vector();
+    	imagePanels.add(imagePanel);
     }
 
     
@@ -1148,6 +1169,8 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
 			add(buttons);
 			if (IJ.isMacintosh())
 				setResizable(false);
+			if (IJ.isMacOSX()&&IJ.isJava18())
+				instance = this;
 			pack();
 			setup();
 			if (centerDialog) GUI.center(this);
@@ -1261,6 +1284,11 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
     	super.setLocation(x, y);
     	centerDialog = false;
     }
+    
+    public void setDefaultString(int index, String str) {
+    	if (defaultStrings!=null && index>=0 && index<defaultStrings.size())
+    		defaultStrings.set(index, str);
+    }
 
     protected void setup() {
 	}
@@ -1323,7 +1351,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
 	public void keyPressed(KeyEvent e) { 
 		int keyCode = e.getKeyCode(); 
 		IJ.setKeyDown(keyCode); 
-		if (keyCode==KeyEvent.VK_ENTER && textArea1==null) {
+		if (keyCode==KeyEvent.VK_ENTER && textArea1==null && okay!=null && okay.isEnabled()) {
 			wasOKed = true;
 			if (IJ.isMacOSX())
 				accessTextFields();
@@ -1411,6 +1439,14 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
         	repaint(); // OSX 10.4 bug delays update of enabled until the next input
     }
 
+	public void repaint() {
+		super.repaint();
+		if (imagePanels!=null) {
+			for (int i=0; i<imagePanels.size(); i++)
+				((ImagePanel)imagePanels.get(i)).repaint();
+		}
+	}
+
 	public void paint(Graphics g) {
 		super.paint(g);
 		if (firstPaint) {
@@ -1453,6 +1489,15 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
 		return macro;
 	}
     
+	public static GenericDialog getInstance() {
+		return instance;
+	}
+
+	public void dispose() {
+		super.dispose();
+		instance = null;
+	}
+
     public void windowActivated(WindowEvent e) {}
     public void windowOpened(WindowEvent e) {}
     public void windowClosed(WindowEvent e) {}
diff --git a/ij/gui/ImageCanvas.java b/ij/gui/ImageCanvas.java
index dbb14ab..0b3c57a 100644
--- a/ij/gui/ImageCanvas.java
+++ b/ij/gui/ImageCanvas.java
@@ -123,9 +123,13 @@ public class ImageCanvas extends Canvas implements MouseListener, MouseMotionLis
 		setSize(ic.dstWidth, ic.dstHeight);
 	}
 
+	/** Sets the region of the image (in pixels) to be displayed. */
 	public void setSourceRect(Rectangle r) {
 		if (r==null)
 			return;
+		r = new Rectangle(r.x, r.y, r.width, r.height);
+		imageWidth = imp.getWidth();
+		imageHeight = imp.getHeight();
 		if (r.x<0) r.x = 0;
 		if (r.y<0) r.y = 0;
 		if (r.width<1)
@@ -141,7 +145,7 @@ public class ImageCanvas extends Canvas implements MouseListener, MouseMotionLis
 		if (r.y+r.height>imageHeight)
 			r.y = imageHeight-r.height;
 		if (srcRect==null)
-			srcRect = new Rectangle(r.x, r.y, r.width, r.height);
+			srcRect = r;
 		else {
 			srcRect.x = r.x;
 			srcRect.y = r.y;
@@ -371,7 +375,6 @@ public class ImageCanvas extends Canvas implements MouseListener, MouseMotionLis
     }
     
     void drawRoi(Graphics g, Roi roi, int index) {
-    	int type = roi.getType();
 		ImagePlus imp2 = roi.getImage();
 		roi.setImage(imp);
 		Color saveColor = roi.getStrokeColor();
diff --git a/ij/gui/ImageWindow.java b/ij/gui/ImageWindow.java
index 9e2cd82..8466c53 100644
--- a/ij/gui/ImageWindow.java
+++ b/ij/gui/ImageWindow.java
@@ -45,6 +45,7 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
 	private static int count;
 	private static boolean centerOnScreen;
 	private static Point nextLocation;
+	public static long setMenuBarTime;
 	
     private int textGap = centerOnScreen?0:TEXT_GAP;
 	
@@ -143,6 +144,8 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
      }
     
 	private void setLocationAndSize(boolean updating) {
+		if (imp==null)
+			return;
 		int width = imp.getWidth();
 		int height = imp.getHeight();
 		Rectangle maxWindow = getMaxWindow(0, 0);
@@ -245,6 +248,8 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
 	/** Override Container getInsets() to make room for some text above the image. */
 	public Insets getInsets() {
 		Insets insets = super.getInsets();
+		if (imp==null)
+			return insets;
 		double mag = ic.getMagnification();
 		int extraWidth = (int)((MIN_WIDTH - imp.getWidth()*mag)/2.0);
 		if (extraWidth<0) extraWidth = 0;
@@ -256,6 +261,8 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
 
     /** Draws the subtitle. */
     public void drawInfo(Graphics g) {
+    	if (imp==null)
+    		return;
         if (textGap!=0) {
 			Insets insets = super.getInsets();
 			if (imp.isComposite()) {
@@ -275,6 +282,8 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
     /** Creates the subtitle. */
     public String createSubtitle() {
     	String s="";
+    	if (imp==null)
+    		return s;
     	int nSlices = imp.getStackSize();
     	if (nSlices>1) {
     		ImageStack stack = imp.getStack();
@@ -467,10 +476,12 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
 	}
 	
 	public Rectangle getMaximumBounds() {
+		Rectangle maxWindow = GUI.getMaxWindowBounds();
+		if (imp==null)
+			return maxWindow;
 		double width = imp.getWidth();
 		double height = imp.getHeight();
 		double iAspectRatio = width/height;
-		Rectangle maxWindow = GUI.getMaxWindowBounds();
 		maxWindowBounds = maxWindow;
 		if (iAspectRatio/((double)maxWindow.width/maxWindow.height)>0.75) {
 			maxWindow.y += 22;  // uncover ImageJ menu bar
@@ -521,6 +532,8 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
 	}
 	
 	public void maximize() {
+		if (GenericDialog.getInstance()!=null)
+			return; // workaround for OSX/Java 8 maximize bug 
 		Rectangle rect = getMaximumBounds();
 		if (IJ.debugMode) IJ.log("maximize: "+rect);
 		setLocationAndSize(rect.x, rect.y, rect.width, rect.height);
@@ -554,8 +567,6 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
 		ImageJ ij = IJ.getInstance();
 		if (ij!=null && !closed && !ij.quitting() && !Interpreter.isBatchMode())
 			WindowManager.setCurrentWindow(this);
-		if (imp.isComposite())
-			Channels.updateChannels();
 		Roi roi = imp.getRoi();
 		if (roi!=null && (roi instanceof PointRoi))
 			PointToolOptions.update();
@@ -697,10 +708,17 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
 		MenuBar mb = Menus.getMenuBar();
 		if (mb!=null && mb==win.getMenuBar())
 			setMenuBar = false;
-		if (ij!=null && !ij.quitting() && !Interpreter.nonBatchMacroRunning() && setMenuBar) {
+		setMenuBarTime = 0L;
+		if (setMenuBar && ij!=null && !ij.quitting() && !Interpreter.nonBatchMacroRunning()) {
 			IJ.wait(10); // may be needed for Java 1.4 on OS X
+			long t0 = System.currentTimeMillis();
 			win.setMenuBar(mb);
+			long time = System.currentTimeMillis()-t0;
+			setMenuBarTime = time;
 			Menus.setMenuBarCount++;
+			if (IJ.debugMode) IJ.log("setMenuBar: "+time+"ms ("+Menus.setMenuBarCount+")");
+			if (time>2000L)
+				Prefs.setIJMenuBar = false;
 		}
 		if (imp!=null) imp.setIJMenuBar(true);
 	}
diff --git a/ij/gui/MultiLineLabel.java b/ij/gui/MultiLineLabel.java
index d632976..1d9ffae 100644
--- a/ij/gui/MultiLineLabel.java
+++ b/ij/gui/MultiLineLabel.java
@@ -37,7 +37,8 @@ public class MultiLineLabel extends Canvas {
     // Figures out how wide each line of the label
     // is, and how wide the widest line is.
     protected void measure() {
-        FontMetrics fm = this.getFontMetrics(this.getFont());
+        Font font = getFont();
+        FontMetrics fm = font!=null?getFontMetrics(font):null;
         // If we don't have font metrics yet, just return.
         if (fm == null) return;
         line_height = fm.getHeight();
diff --git a/ij/gui/NewImage.java b/ij/gui/NewImage.java
index 839c6a9..9d1f037 100644
--- a/ij/gui/NewImage.java
+++ b/ij/gui/NewImage.java
@@ -22,8 +22,8 @@ public class NewImage {
 	static final String SLICES = "new.slices";
 
     private static String name = "Untitled";
-    private static int width = Prefs.getInt(WIDTH, 400);
-    private static int height = Prefs.getInt(HEIGHT, 400);
+    private static int width = Prefs.getInt(WIDTH, 512);
+    private static int height = Prefs.getInt(HEIGHT, 512);
     private static int slices = Prefs.getInt(SLICES, 1);
     private static int type = Prefs.getInt(TYPE, GRAY8);
     private static int fillWith = Prefs.getInt(FILL, FILL_BLACK);
@@ -43,7 +43,8 @@ public class NewImage {
 		if (type==GRAY16) bytesPerPixel = 2;
 		else if (type==GRAY32||type==RGB) bytesPerPixel = 4;
 		long size = (long)width*height*nSlices*bytesPerPixel;
-		boolean bigStack = size/(1024*1024)>=50;
+		int sizeThreshold = fill==FILL_RANDOM?10:250;
+		boolean bigStack = size/(1024*1024)>=sizeThreshold;
 		String size2 = size/(1024*1024)+"MB ("+width+"x"+height+"x"+nSlices+")";
 		if ((options&CHECK_AVAILABLE_MEMORY)!=0) {
 			long max = IJ.maxMemory(); // - 100*1024*1024;
@@ -69,7 +70,8 @@ public class NewImage {
 		ImageStack stack = imp.createEmptyStack();
 		int inc = nSlices/40;
 		if (inc<1) inc = 1;
-		IJ.showStatus("Allocating "+size2+". Press 'Esc' to abort.");
+		if (bigStack)
+			IJ.showStatus("Allocating "+size2+". Press 'Esc' to abort.");
 		IJ.resetEscape();
 		try {
 			stack.addSlice(null, ip);
@@ -78,12 +80,24 @@ public class NewImage {
 					IJ.showProgress(i, nSlices);
 				Object pixels2 = null;
 				switch (type) {
-					case GRAY8: pixels2 = new byte[width*height]; break;
-					case GRAY16: pixels2 = new short[width*height]; break;
-					case GRAY32: pixels2 = new float[width*height]; break;
-					case RGB: pixels2 = new int[width*height]; break;
+					case GRAY8: pixels2 = new byte[width*height];
+						if (fill==FILL_RANDOM)
+							fillRandomByte(new ByteProcessor(width,height,(byte[])pixels2));
+						break;
+					case GRAY16: pixels2 = new short[width*height];
+						if (fill==FILL_RANDOM)
+							fillRandomShort(new ShortProcessor(width,height,(short[])pixels2,null));
+						break;
+					case GRAY32: pixels2 = new float[width*height];
+						if (fill==FILL_RANDOM)
+							fillRandomFloat(new FloatProcessor(width,height,(float[])pixels2,null));
+						break;
+					case RGB: pixels2 = new int[width*height];
+						if (fill==FILL_RANDOM)
+							fillRandomRGB(new ColorProcessor(width,height,(int[])pixels2));
+						break;
 				}
-				if (fill!=FILL_BLACK || type==RGB)
+				if ((fill==FILL_WHITE||fill==FILL_RAMP) || ((type==RGB)&&(fill!=FILL_RANDOM)))
 					System.arraycopy(ip.getPixels(), 0, pixels2, 0, width*height);
 				stack.addSlice(null, pixels2);
 				if (IJ.escapePressed()) {IJ.beep(); break;};
@@ -135,8 +149,7 @@ public class NewImage {
 				}
 				break;
 			case FILL_RANDOM:
-				ip.add(127);
-				ip.noise(31);
+				fillRandomByte(ip);
 				break;
 		}
 		ImagePlus imp = new ImagePlus(title, ip);
@@ -146,6 +159,11 @@ public class NewImage {
 		}
 		return imp;
 	}
+	
+	private static void fillRandomByte(ImageProcessor ip) {
+		ip.add(127);
+		ip.noise(31);
+	}
 
 	public static ImagePlus createRGBImage(String title, int width, int height, int slices, int options) {
 		int fill = getFill(options);
@@ -176,12 +194,7 @@ public class NewImage {
 				}
 				break;
 			case FILL_RANDOM:
-				ByteProcessor rr = new ByteProcessor(width, height);
-				ByteProcessor gg = new ByteProcessor(width, height);
-				ByteProcessor bb = new ByteProcessor(width, height);
-				rr.add(127); gg.add(127); bb.add(127);
-				rr.noise(31); gg.noise(31); bb.noise(31);
-				ip.setChannel(1,rr); ip.setChannel(2,gg); ip.setChannel(3,bb);
+				fillRandomRGB(ip);
 				break;
 		}
 		ImagePlus imp = new ImagePlus(title, ip);
@@ -192,6 +205,15 @@ public class NewImage {
 		return imp;
 	}
 	
+	private static void fillRandomRGB(ColorProcessor ip) {
+		ByteProcessor rr = new ByteProcessor(width, height);
+		ByteProcessor gg = new ByteProcessor(width, height);
+		ByteProcessor bb = new ByteProcessor(width, height);
+		rr.add(127); gg.add(127); bb.add(127);
+		rr.noise(31); gg.noise(31); bb.noise(31);
+		ip.setChannel(1,rr); ip.setChannel(2,gg); ip.setChannel(3,bb);
+	}
+
 	/** Creates an unsigned short image. */
 	public static ImagePlus createShortImage(String title, int width, int height, int slices, int options) {
 		int fill = getFill(options);
@@ -214,8 +236,7 @@ public class NewImage {
 				}
 				break;
 			case FILL_RANDOM:
-				ip.add(32767);
-				ip.noise(7940);
+				fillRandomShort(ip);
 				break;
 		}
 	    if (fill==FILL_WHITE)
@@ -229,6 +250,11 @@ public class NewImage {
 		return imp;
 	}
 
+	private static void fillRandomShort(ImageProcessor ip) {
+		ip.add(32767);
+		ip.noise(7940);
+	}
+
 	/**
 	* @deprecated
 	* Short images are always unsigned.
@@ -258,7 +284,7 @@ public class NewImage {
 				}
 				break;
 			case FILL_RANDOM:
-				ip.noise(1);
+				fillRandomFloat(ip);
 				break;
 		}
 	    if (fill==FILL_WHITE)
@@ -273,6 +299,10 @@ public class NewImage {
 		return imp;
 	}
 
+	private static void fillRandomFloat(ImageProcessor ip) {
+		ip.noise(1);
+	}
+
 	private static int getSize(int width, int height) {
 		long size = (long)width*height;
 		if (size>Integer.MAX_VALUE) {
@@ -313,7 +343,7 @@ public class NewImage {
 			type = GRAY8;
 		if (fillWith<OLD_FILL_WHITE||fillWith>FILL_RANDOM)
 			fillWith = FILL_WHITE;
-		GenericDialog gd = new GenericDialog("New Image...", IJ.getInstance());
+		GenericDialog gd = new GenericDialog("New Image...");
 		gd.addStringField("Name:", name, 12);
 		gd.addChoice("Type:", types, types[type]);
 		gd.addChoice("Fill with:", fill, fill[fillWith]);
diff --git a/ij/gui/Overlay.java b/ij/gui/Overlay.java
index 4c2eaef..0ec378b 100644
--- a/ij/gui/Overlay.java
+++ b/ij/gui/Overlay.java
@@ -23,12 +23,14 @@ public class Overlay {
     /** Constructs an Overlay and adds the specified ROI. */
     public Overlay(Roi roi) {
     	list = new Vector();
-    	list.add(roi);
+    	if (roi!=null)
+    		list.add(roi);
     }
 
     /** Adds an ROI to this Overlay. */
     public void add(Roi roi) {
-    	list.add(roi);
+    	if (roi!=null)
+    		list.add(roi);
     }
         
     /** Adds an ROI to this Overlay using the specified name. */
@@ -39,7 +41,8 @@ public class Overlay {
 
     /** Adds an ROI to this Overlay. */
     public void addElement(Roi roi) {
-    	list.add(roi);
+    	if (roi!=null)
+    		list.add(roi);
     }
 
     /** Removes the ROI with the specified index from this Overlay. */
diff --git a/ij/gui/Plot.java b/ij/gui/Plot.java
index 7e3355e..0abe1d2 100644
--- a/ij/gui/Plot.java
+++ b/ij/gui/Plot.java
@@ -38,6 +38,8 @@ public class Plot implements Cloneable {
 	public static final int CIRCLE = 0;
 	/** Display points using an X-shaped mark. */
 	public static final int X = 1;
+	/** Connect points with solid lines. */
+	public static final int LINE = 2;
 	/** Display points using a square box-shaped mark. */
 	public static final int BOX = 3;
 	/** Display points using an tiangular mark. */
@@ -46,10 +48,15 @@ public class Plot implements Cloneable {
 	public static final int CROSS = 5;
 	/** Display points using a single pixel. */
 	public static final int DOT = 6;
-	/** Connect points with solid lines. */
-	public static final int LINE = 2;
 	/** Draw black lines between the dots and a circle with the given color at each dot */
-	public static final int CONNECTED_CIRCLES = 7;	
+	public static final int CONNECTED_CIRCLES = 7;
+	/** Names for the shapes as an array */
+	final static String[] SHAPE_NAMES = new String[] {
+			"Circle", "X", "Line", "Box", "Triangle", "+", "Dot", "Connected Circles"};
+	/** Names in nicely sorting order for menus */
+	final static String[] SORTED_SHAPES = new String[] {
+			SHAPE_NAMES[LINE], SHAPE_NAMES[CONNECTED_CIRCLES], SHAPE_NAMES[CIRCLE], SHAPE_NAMES[BOX], SHAPE_NAMES[TRIANGLE],
+			SHAPE_NAMES[CROSS], SHAPE_NAMES[X], SHAPE_NAMES[DOT] };
 	/** flag for numeric labels of x-axis ticks */
 	public static final int X_NUMBERS = 0x1;
 	/** flag for numeric labels of x-axis ticks */
@@ -567,7 +574,8 @@ public class Plot implements Cloneable {
 	public void add(String shape, double[] x, double[] y) {
 		addPoints(Tools.toFloat(x), Tools.toFloat(y), null, toShape(shape), null);
 	}
-	
+
+	/** Returns the number for a given plot symbol shape, -1 for xError and -2 for yError (all case-insensitive) */
 	public static int toShape(String str) {
 		str = str.toLowerCase(Locale.US);
 		int shape = Plot.CIRCLE;
@@ -579,7 +587,7 @@ public class Plot implements Cloneable {
 			shape = Plot.BOX;
 		else if (str.contains("triangle"))
 			shape = Plot.TRIANGLE;
-		else if (str.contains("cross"))
+		else if (str.contains("cross") || str.contains("+"))
 			shape = Plot.CROSS;		
 		else if (str.contains("dot"))
 			shape = Plot.DOT;		
@@ -734,9 +742,8 @@ public class Plot implements Cloneable {
 	 *	The frame and labels are always drawn in black. */
 	public void setColor(Color c) {
 		currentColor = c;
-		if (c.getRed() != c.getGreen() || c.getGreen() != c.getBlue())
-			isColor = true;
 		currentColor2 = null;
+		checkForColor(c);
 	}
 	
 	public void setColor(String color) {
@@ -753,9 +760,8 @@ public class Plot implements Cloneable {
 	public void setColor(Color c, Color c2) {
 		currentColor = c;
 		currentColor2 = c2;
-		if (c.getRed() != c.getGreen() || c.getGreen() != c.getBlue() || (c2 != null && (
-				c2.getRed() != c2.getGreen() || c2.getGreen() != c2.getBlue())))
-			isColor = true;
+		checkForColor(c);
+		checkForColor(c2);
 	}
 	
 	/** Sets the drawing color for the next objects that will be added to the plot. */
@@ -766,7 +772,7 @@ public class Plot implements Cloneable {
 	/** Set the plot frame background color. */
 	public void setBackgroundColor(Color c) {
 		backgroundColor = c;
-		isColor = true;
+		checkForColor(c);
 	}
 
 	/** Set the plot frame background color. */
@@ -875,6 +881,89 @@ public class Plot implements Cloneable {
 		return p==null ? null : p.yValues;
 	}
 
+	/** Get an array with human-readable designations of the PlotObjects (curves, labels, ...)
+	 *  in the sequence they are plotted (i.e., foreground last). **/
+	public String[] getPlotObjectDesignations() {
+	    int nObjects = allPlotObjects.size();
+		String[] names = new String[nObjects];
+		if (names.length == 0) return names;
+		String[] labels = null;
+		if (legend != null && legend.label != null)
+			labels = legend.label.split("[\t\n]");
+		int iData = 1, iArrow = 1, iLine = 1, iText = 1;                        //Human readable counters of each object type
+		int firstObject = allPlotObjects.get(0).hasFlag(PlotObject.CONSTRUCTOR_DATA) ? 1 : 0; //PlotObject passed with constructor is plotted last
+		for (int i=0, p=firstObject; i<nObjects; i++, p++) {
+			if (p >= allPlotObjects.size()) p = 0;                              //might be PlotObject passed with Constructor
+			PlotObject plotObject = allPlotObjects.get(p);
+			int type = plotObject.type;
+			String label = plotObject.label;
+			switch (type) {
+				case PlotObject.XY_DATA:
+					names[i] = "Data Set "+iData+": "+(labels!=null && labels.length>=iData ?
+							labels[iData-1] : "(" + plotObject.yValues.length + " data points)");
+					iData++;
+					break;
+				case PlotObject.ARROWS:
+					names[i] = "Arrow Set "+iArrow+" ("+ plotObject.xValues.length + ")";
+					iArrow++;
+					break;
+				case PlotObject.LINE: case PlotObject.NORMALIZED_LINE: case PlotObject.DOTTED_LINE:
+					String detail = "";
+					if (type == PlotObject.DOTTED_LINE) detail = "dotted ";
+					if (plotObject.x ==plotObject.xEnd) detail += "vertical";
+					else if (plotObject.y ==plotObject.yEnd) detail += "horizontal";
+					if (detail.length()>0) detail = " ("+detail.trim()+")";
+					names[i] = "Straight Line "+iLine+detail;
+					iLine++;
+					break;
+				case PlotObject.LABEL: case PlotObject.NORMALIZED_LABEL:
+				    String text = plotObject.label.replaceAll("\n"," ");
+				    if (text.length()>45) text = text.substring(0, 40)+"...";
+					names[i] = "Text "+iText+": \""+text+'"';
+					iText++;
+					break;
+			}
+		}
+		return names;
+	}
+
+	/** Get the style of the i-th PlotObject (curve, label, ...) in the sequence
+	 *  they are plotted (i.e., foreground last), as String with comma delimiters:
+	 *  Main Color, Secondary Color (or "none"), Line Width [, Symbol shape for XY_DATA] **/
+	public String getPlotObjectStyles(int i) {
+		if (allPlotObjects.get(0).hasFlag(PlotObject.CONSTRUCTOR_DATA)) i++;
+		if (i == allPlotObjects.size()) i = 0;                      //PlotObject passed with Constructor (#0) is last
+		PlotObject plotObject = allPlotObjects.get(i);
+	    String styleString = Colors.colorToString(plotObject.color) + "," +
+				Colors.colorToString(plotObject.color2) + "," +
+				plotObject.lineWidth;
+		if (plotObject.type == PlotObject.XY_DATA)
+			styleString += ","+SHAPE_NAMES[plotObject.shape];
+		return styleString;
+	}
+
+	/** Set the style of the i-th PlotObject (curve, label, ...) in the sequence
+	 *  they are plotted (i.e., foreground last), from a String with comma delimiters:
+	 *  Main Color, Secondary Color (or "none"), Line Width [, Symbol shape for XY_DATA] **/
+	public void setPlotObjectStyles(int i, String styleString) {
+		if (allPlotObjects.get(0).hasFlag(PlotObject.CONSTRUCTOR_DATA)) i++;
+		if (i == allPlotObjects.size()) i = 0;                      //PlotObject passed with Constructor (#0) is last
+		PlotObject plotObject = allPlotObjects.get(i);
+		String[] items = styleString.split(",");
+		plotObject.color = Colors.decode(items[0].trim(), plotObject.color);
+		plotObject.color2 = Colors.decode(items[1].trim(), null);
+		checkForColor(plotObject.color);
+		checkForColor(plotObject.color2);
+		float lineWidth = plotObject.lineWidth;
+		if (items.length >= 3) try {
+			plotObject.lineWidth = Float.parseFloat(items[2].trim());
+		} catch (NumberFormatException e) {};
+		if (items.length >= 4)
+			plotObject.shape = toShape(items[3].trim());
+		updateImage();
+		return;
+	}
+
 	/** Sets the plot range to the initial value determined from minima&maxima or given by setLimits.
 	 *	Updates the image if existing and updateImg is true */
 	public void setLimitsToDefaults(boolean updateImg) {
@@ -1179,6 +1268,13 @@ public class Plot implements Cloneable {
 		return scale==1 ? font : font.deriveFont(size*scale);
 	}
 
+	/** Converts the plot to color if the given color requires it */
+	void checkForColor(Color c) {
+		if (c == null) return;
+		if (c.getRed() != c.getGreen() || c.getGreen() != c.getBlue())
+			isColor = true;
+	}
+
 	/** Draws the plot contents (all PlotObjects and the frame and legend), without axes etc. */
 	void drawContents(ImageProcessor ip) {
 		makeRangeGetSteps();
diff --git a/ij/gui/PlotContentsStyleDialog.java b/ij/gui/PlotContentsStyleDialog.java
new file mode 100644
index 0000000..447572d
--- /dev/null
+++ b/ij/gui/PlotContentsStyleDialog.java
@@ -0,0 +1,87 @@
+package ij.gui;
+import ij.*;
+import ij.process.*;
+import java.awt.*;
+import java.util.Vector;
+
+/** This class implements the Plot Window's More>Contents Style dialog */
+public class PlotContentsStyleDialog implements DialogListener {
+	private Plot plot;
+
+	/** Creator that sets a plot to use */
+	public PlotContentsStyleDialog(Plot plot) {
+		this.plot = plot;
+	}
+
+	/** Shows the dialog, with a given parent Frame */
+	public void showDialog(Frame parent) {
+		String[] designations = plot.getPlotObjectDesignations();
+		if (designations.length==0) {
+			IJ.error("Empty Plot");
+			return;
+		}
+		String[] stylesBackup = new String[designations.length];
+		for (int i=0; i<stylesBackup.length; i++)
+			stylesBackup[i] = plot.getPlotObjectStyles(i);
+		GenericDialog gd = new GenericDialog("Plot Contents Style", parent);
+		IJ.wait(100);	//needed to avoid hanging
+		gd.addChoice("Item:", designations, designations[0]);
+		gd.addStringField("Color:", "#########");
+		gd.addStringField("Secondary (fill) color:", "#########");
+		gd.addNumericField("Line width: ", 1.0, 1);
+		gd.addChoice("Symbol:", Plot.SORTED_SHAPES, Plot.SORTED_SHAPES[2]);
+		gd.addDialogListener(this);
+		IJ.wait(100);	//needed to avoid hanging
+		updateDialog(gd, 0);	//fill in style for index 0
+
+		gd.showDialog();
+		if (gd.wasCanceled()) {
+			for (int i=0; i<stylesBackup.length; i++)
+				plot.setPlotObjectStyles(i, stylesBackup[i]);
+		}
+	}
+	
+	public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
+		if (e == null) return true;	//gets called with e=null upon OK
+		//IJ.log("dialogItemChanged e="+e);IJ.wait(50);
+		int index = gd.getNextChoiceIndex();
+		String color = gd.getNextString();
+		String color2 = gd.getNextString();
+		double width = gd.getNextNumber();
+		String symbol = gd.getNextChoice();
+		Choice designationsC = (Choice)(gd.getChoices().get(0));
+		if (e.getSource() == designationsC)
+			updateDialog(gd, index);
+		else
+			plot.setPlotObjectStyles(index, color.trim()+","+color2.trim()+","+(float)width+","+symbol);
+		return true;
+	}
+
+	private void updateDialog(GenericDialog gd, int index) {
+		Vector stringFields = gd.getStringFields();
+		Vector choices = gd.getChoices();
+		Choice designationsC = (Choice)(choices.get(0));
+		TextField colorF = (TextField)(stringFields.get(0));
+		TextField color2F = (TextField)(stringFields.get(1));
+		TextField widthF = (TextField)(gd.getNumericFields().get(0));
+		Choice symbolC = (Choice)(choices.get(1));
+		String styleString = plot.getPlotObjectStyles(index);
+		String[] items = styleString.split(",");
+		//IJ.log(items.length+" items from "+allStyles[index]);
+		colorF.setText(items[0]);
+		color2F.setText(items[1]);
+		widthF.setText(items[2]);
+		if (items.length >= 4)
+			symbolC.select(items[3]);
+		String designation = designationsC.getSelectedItem();
+		boolean isData = designation.startsWith("Data");
+		boolean isText = designation.startsWith("Text");
+		color2F.setEnabled(isData);	//only (some) data symbols have secondary color
+		widthF.setEnabled(!isText); //all non-Text types have line width
+		symbolC.setEnabled(isData); //only data have a symbol to choose
+	}
+
+	public void setNPasses(int nPasses) {
+	}
+
+}
diff --git a/ij/gui/PlotWindow.java b/ij/gui/PlotWindow.java
index d9ab447..8df48ce 100644
--- a/ij/gui/PlotWindow.java
+++ b/ij/gui/PlotWindow.java
@@ -10,6 +10,7 @@ import ij.process.*;
 import ij.util.*;
 import ij.text.TextWindow;
 import ij.plugin.filter.Analyzer;
+import ij.plugin.filter.PlugInFilterRunner;
 import ij.measure.*;
 import ij.io.SaveDialog;
 
@@ -245,7 +246,9 @@ public class PlotWindow extends ImageWindow implements ActionListener,	ItemListe
 
 	/** Releases the resources used by this PlotWindow */
 	public void dispose() {
-		plot.dispose();
+		if (plot!=null)
+			plot.dispose();
+		removeListeners();
 		plot = null;
 		plotMaker = null;
 		srcImp = null;
@@ -262,15 +265,15 @@ public class PlotWindow extends ImageWindow implements ActionListener,	ItemListe
 
 	//names for popupMenu items
 	private static int COPY=0, COPY_ALL=1, SET_RANGE=2, PREV_RANGE=3, RESET_RANGE=4, FIT_RANGE=5,
-			ZOOM_SELECTION=6, AXIS_OPTIONS=7, LEGEND=8, RESET_PLOT=9, FREEZE=10, HI_RESOLUTION=11,
-			PROFILE_PLOT_OPTIONS=12;
+			ZOOM_SELECTION=6, AXIS_OPTIONS=7, LEGEND=8, STYLE=9, RESET_PLOT=10, FREEZE=11, HI_RESOLUTION=12,
+			PROFILE_PLOT_OPTIONS=13;
 	//the following commands are disabled when the plot is frozen
 	private static int[] DISABLED_WHEN_FROZEN = new int[]{SET_RANGE, PREV_RANGE, RESET_RANGE,
-			FIT_RANGE, ZOOM_SELECTION, AXIS_OPTIONS, LEGEND, RESET_PLOT};
+			FIT_RANGE, ZOOM_SELECTION, AXIS_OPTIONS, LEGEND, STYLE, RESET_PLOT};
 	/** Prepares and returns the popupMenu of the More>> button*/
 	PopupMenu getPopupMenu() {
 		popupMenu = new PopupMenu();
-		menuItems = new MenuItem[13];
+		menuItems = new MenuItem[14];
 		menuItems[COPY] = addPopupItem(popupMenu, "Copy 1st Data Set");
 		menuItems[COPY_ALL] = addPopupItem(popupMenu, "Copy All Data");
 		popupMenu.addSeparator();
@@ -282,6 +285,7 @@ public class PlotWindow extends ImageWindow implements ActionListener,	ItemListe
 		popupMenu.addSeparator();
 		menuItems[AXIS_OPTIONS] = addPopupItem(popupMenu, "Axis Options...");
 		menuItems[LEGEND] = addPopupItem(popupMenu, "Legend...");
+		menuItems[STYLE] = addPopupItem(popupMenu, "Contents Style...");
 		menuItems[RESET_PLOT] = addPopupItem(popupMenu, "Reset Format");
 		menuItems[FREEZE] = addPopupItem(popupMenu, "Freeze Plot", true);
 		menuItems[HI_RESOLUTION] = addPopupItem(popupMenu, "High-Resolution Plot...");
@@ -309,6 +313,7 @@ public class PlotWindow extends ImageWindow implements ActionListener,	ItemListe
 
 	/** Called if user has activated a button or popup menu item */
 	public void actionPerformed(ActionEvent e) {
+		try {
 		Object b = e.getSource();
 		if (b==live)
 			toggleLiveProfiling();
@@ -342,6 +347,8 @@ public class PlotWindow extends ImageWindow implements ActionListener,	ItemListe
 			new PlotDialog(plot, PlotDialog.AXIS_OPTIONS).showDialog(this);
 		else if (b==menuItems[LEGEND])
 			new PlotDialog(plot, PlotDialog.LEGEND).showDialog(this);
+		else if (b==menuItems[STYLE])
+			new PlotContentsStyleDialog(plot).showDialog(this);
 		else if (b==menuItems[RESET_PLOT]) {
 			plot.setFont(Font.PLAIN, Prefs.getInt(PREFS_FONT_SIZE, FONT_SIZE));
 			plot.setAxisLabelFont(Font.PLAIN, Prefs.getInt(PREFS_FONT_SIZE, FONT_SIZE));
@@ -352,6 +359,7 @@ public class PlotWindow extends ImageWindow implements ActionListener,	ItemListe
 		else if (b==menuItems[PROFILE_PLOT_OPTIONS])
 			IJ.doCommand("Plots...");
 		ic.requestFocus();	//have focus on the canvas, not the button, so that pressing the space bar allows panning
+		} catch (Exception ex) { IJ.handleException(ex); }
 	}
 
 	/** Called if the user activates/deactivates a CheckboxMenuItem */
@@ -645,6 +653,16 @@ public class PlotWindow extends ImageWindow implements ActionListener,	ItemListe
 		else
 			enableLiveProfiling();
 	}
+	
+	/*
+	public static void setLiveMode(Boolean set) {
+		ImagePlus imp = WindowManager.getCurrentImage();
+		ImageWindow win = imp!=null?imp.getWindow():null;
+		PlotWindow pw = win!=null && (win instanceof PlotWindow)?(PlotWindow)win:null;
+		if (pw!=null && pw.live.getForeground()!=Color.red)
+			pw.enableLiveProfiling();
+	}
+	*/
 
 	private void enableLiveProfiling() {
 		if (plotMaker==null)
@@ -700,7 +718,7 @@ public class PlotWindow extends ImageWindow implements ActionListener,	ItemListe
 	public void run() {
 		while (true) {
 			IJ.wait(50);	//delay to make sure the roi has been updated
-			Plot plot = plotMaker.getPlot();
+			Plot plot = plotMaker!=null?plotMaker.getPlot():null;
 			if (doUpdate && plot!=null) {
 				plot.useTemplate(this.plot, this.plot.templateFlags);
 				plot.setPlotMaker(plotMaker);
@@ -737,7 +755,7 @@ public class PlotWindow extends ImageWindow implements ActionListener,	ItemListe
 	}
 	
 	private void removeListeners() {
-		if (IJ.debugMode) IJ.log("PlotWindow.removeListeners");
+		if (IJ.debugMode) IJ.log("PlotWindow.removeListeners: "+srcImp);
 		if (srcImp==null)
 			return;
 		ImagePlus.removeImageListener(this);
@@ -761,4 +779,3 @@ public class PlotWindow extends ImageWindow implements ActionListener,	ItemListe
 	
 }
 
-
diff --git a/ij/gui/PointRoi.java b/ij/gui/PointRoi.java
index a1b03af..887851a 100644
--- a/ij/gui/PointRoi.java
+++ b/ij/gui/PointRoi.java
@@ -1,6 +1,4 @@
 package ij.gui;
-import java.awt.*;
-import java.awt.image.*;
 import ij.*;
 import ij.process.*;
 import ij.measure.*;
@@ -9,8 +7,11 @@ import ij.plugin.PointToolOptions;
 import ij.plugin.filter.Analyzer;
 import ij.plugin.frame.Recorder;
 import ij.util.Java2; 
+import java.awt.*;
+import java.awt.image.*;
 import java.awt.event.KeyEvent;
-import java.util.Random;
+import java.util.*;
+import java.awt.geom.Point2D;
 
 /** This class represents a collection of points. */
 public class PointRoi extends PolygonRoi {
@@ -42,6 +43,8 @@ public class PointRoi extends PolygonRoi {
 	private int[] counts = new int[MAX_COUNTERS];
 	private ResultsTable rt;
 	private long lastPointTime;
+	private double scale;
+	private int[] counterInfo;
 	
 	static {
 		setDefaultType((int)Prefs.get(TYPE_KEY, HYBRID));
@@ -90,6 +93,7 @@ public class PointRoi extends PolygonRoi {
 	/** Creates a new PointRoi using the specified screen coordinates. */
 	public PointRoi(int sx, int sy, ImagePlus imp) {
 		super(makeXArray(sx, imp), makeYArray(sy, imp), 1, POINT);
+		defaultCounter = 0;
 		setImage(imp);
 		width=1; height=1;
 		type = defaultType;
@@ -143,11 +147,17 @@ public class PointRoi extends PolygonRoi {
 	/** Draws the points on the image. */
 	public void draw(Graphics g) {
 		updatePolygon();
-		if (ic!=null) mag = ic.getMagnification();
+		//scale = ic!=null?ic.getMagnification():1.0;
+		//if (type!=CIRCLE) scale=1.0;
+		scale = 1.0;
 		if (showLabels && nPoints>1) {
 			fontSize = 8;
 			fontSize += convertSizeToIndex(size);
-			if (fontSize>18) fontSize = 18;
+			if (fontSize>18)
+				fontSize = 18;
+			double scale2 = 0.7*scale;
+			if (scale2<1.0) scale2=1.0;
+			fontSize = (int)Math.round(fontSize*scale2);
 			font = new Font("SansSerif", Font.PLAIN, fontSize);
 			g.setFont(font);
 			if (fontSize>9)
@@ -178,7 +188,7 @@ public class PointRoi extends PolygonRoi {
 			else
 				color = Color.cyan;
 		}
-		if (nCounters>1 && counters!=null)
+		if (nCounters>1 && counters!=null && n<=counters.length)
 			color = getColor(counters[n-1]);
 		if (type==HYBRID || type==CROSSHAIR) {
 			if (type==HYBRID)
@@ -211,13 +221,16 @@ public class PointRoi extends PolygonRoi {
 				g.fillRect(x-size2, y-size2, size, size);
 		}
 		if (showLabels && nPoints>1) {
+			int offset = (int)Math.round(0.4*size*scale);
+			if (offset<1) offset=1;
+			offset++;
 			if (nCounters==1) {
 				if (!colorSet)
 					g.setColor(color);
-				g.drawString(""+n, x+4, y+fontSize+2);
+				g.drawString(""+n, x+offset, y+offset+fontSize);
 			} else if (counters!=null) {
 				g.setColor(getColor(counters[n-1]));
-				g.drawString(""+counters[n-1], x+4, y+fontSize+2);
+				g.drawString(""+counters[n-1], x+offset, y+offset+fontSize);
 			}
 		}
 		if ((size>TINY||type==DOT) && (type==HYBRID||type==DOT)) {
@@ -230,12 +243,13 @@ public class PointRoi extends PolygonRoi {
 				g.drawOval(x-(size2+1), y-(size2+1), size+1, size+1);
 		}
 		if (type==CIRCLE) {
-			int csize = size + 2;
-			int csize2 = csize/2;
+			int scaledSize = (int)Math.round((size+1)*scale);
 			g.setColor(color);
-			if (size>LARGE)
+			if (scale!=1.0)
+				g2d.setStroke(new BasicStroke((float)scale*(size>LARGE?2:1)));
+			else if (size>LARGE)
 				g2d.setStroke(twoPixelsWide);
-			g.drawOval(x-(csize2+1), y-(csize2+1), csize+1, csize+1);
+			g.drawOval(x-scaledSize/2, y-scaledSize/2, scaledSize, scaledSize);
 		}
 	}
 	
@@ -252,6 +266,8 @@ public class PointRoi extends PolygonRoi {
 		if (nPoints==xpf.length)
 			enlargeArrays();
 		addPoint2(imp, ox, oy);
+		resetBoundingRect();
+		width+=1; height+=1;
 	}
 	
 	private void addPoint2(ImagePlus imp, double ox, double oy) {
@@ -286,9 +302,10 @@ public class PointRoi extends PolygonRoi {
 	}
 
 	private synchronized void incrementCounter(ImagePlus imp) {
+		//IJ.log("incrementCounter: "+nPoints+" "+counter+" "+(counters!=null?""+counters.length:"null"));
 		counts[counter]++;
 		boolean isStack = imp!=null && imp.getStackSize()>1;
-		if (counter!=0 || isStack) {
+		if (counter!=0 || isStack || counters!=null) {
 			if (counters==null) {
 				counters = new short[nPoints*2];
 				positions = new short[nPoints*2];
@@ -339,9 +356,8 @@ public class PointRoi extends PolygonRoi {
 		if (cachedMask!=null && cachedMask.getPixels()!=null)
 			return cachedMask;
 		ImageProcessor mask = new ByteProcessor(width, height);
-		for (int i=0; i<nPoints; i++) {
-			mask.putPixel((int)xpf[i], (int)ypf[i], 255);
-		}
+		for (int i=0; i<nPoints; i++)
+			mask.putPixel((int)Math.round(xpf[i]), (int)Math.round(ypf[i]), 255);
 		cachedMask = mask;
 		return mask;
 	}
@@ -489,13 +505,20 @@ public class PointRoi extends PolygonRoi {
 			return counts[counter];
 	}
 	
+	/** Returns the counter assocated with the specified point. */
+	public int getCounter(int index) {
+		if (counters==null || index>=counters.length)
+			return 0;
+		else
+			return counters[index];
+	}
+
 	public int[] getCounters() {
 		if (counters==null)
 			return null;
 		int[] temp = new int[nPoints];
-		for (int i=0; i<nPoints; i++) {
+		for (int i=0; i<nPoints; i++)
 			temp[i] = (counters[i]&0xff) + ((positions[i]&0xffff)<<8);
-		}
 		return temp;
 	}
 
@@ -667,6 +690,49 @@ public class PointRoi extends PolygonRoi {
 		}
 		return handle;
 	}
+	
+	/** Returns the points as an array of Points. */
+	public Point[] getContainedPoints() {
+		Polygon p = getPolygon();
+		Point[] points = new Point[p.npoints];
+		for (int i=0; i<p.npoints; i++)
+			points[i] = new Point(p.xpoints[i],p.ypoints[i]);
+		return points;
+	}
+
+	/** Returns the points as a FloatPolygon. */
+	public FloatPolygon getContainedFloatPoints() {
+		return getFloatPolygon();
+	}
+
+	/**
+	 * Custom iterator for points contained in a {@link PointRoi}.
+	 * @author W. Burger
+	 */
+	public Iterator<Point> iterator() {	
+		return new Iterator<Point>() {
+			final Point[] pnts = getContainedPoints();
+			final int n = pnts.length;
+			int next = (n == 0) ? 1 : 0;
+			@Override
+			public boolean hasNext() {
+				return next < n;
+			}
+			@Override
+			public Point next() {
+				if (next >= n) {
+					throw new NoSuchElementException();
+				}
+				Point pnt = pnts[next];
+				next = next + 1;
+				return pnt;
+			}
+			@Override
+			public void remove() {
+				throw new UnsupportedOperationException();
+			}
+		};
+	}
 
 	/** Returns a copy of this PointRoi. */
 	public synchronized Object clone() {
@@ -688,6 +754,14 @@ public class PointRoi extends PolygonRoi {
 		}
 		return r;
 	}
+	
+	public void setCounterInfo(int[] info) {
+		counterInfo = info;
+	}
+
+	public int[] getCounterInfo() {
+		return counterInfo;
+	}
 
 	/** @deprecated */
 	public void setHideLabels(boolean hideLabels) {
diff --git a/ij/gui/PolygonRoi.java b/ij/gui/PolygonRoi.java
index f10b669..94c8cd1 100644
--- a/ij/gui/PolygonRoi.java
+++ b/ij/gui/PolygonRoi.java
@@ -516,7 +516,7 @@ public class PolygonRoi extends Roi {
 			xp[nPoints-1] = ox-x;
 			yp[nPoints-1] = oy-y;
 		}
-		if (type==POLYLINE && subPixelResolution()) {
+		if (type==POLYLINE && Prefs.splineFitLines) {
 			fitSpline();
 			imp.draw();
 		} else
@@ -656,7 +656,7 @@ public class PolygonRoi extends Roi {
 		imp.draw(xmin2-m, ymin2-m, xmax2-xmin2+m*2, ymax2-ymin2+m*2);
 	}
 
-	private void resetBoundingRect() {
+	protected void resetBoundingRect() {
 		//IJ.log("resetBoundingRect");
 		if (xpf!=null) {
 			resetSubPixelBoundingRect();
@@ -1616,6 +1616,7 @@ public class PolygonRoi extends Roi {
 			xpf = toFloat(xp);
 			ypf = toFloat(yp);
 		}
+		subPixel = true;
 	}
 
 	public String getDebugInfo() {
diff --git a/ij/gui/Roi.java b/ij/gui/Roi.java
index 87a91dc..974d62d 100644
--- a/ij/gui/Roi.java
+++ b/ij/gui/Roi.java
@@ -6,6 +6,7 @@ import ij.plugin.frame.Recorder;
 import ij.plugin.filter.Analyzer;
 import ij.plugin.filter.ThresholdToSelection;
 import ij.plugin.RectToolOptions;
+import ij.plugin.Selection;
 import ij.macro.Interpreter;
 import ij.io.RoiDecoder;
 import java.awt.*;
@@ -15,8 +16,19 @@ import java.awt.image.*;
 import java.awt.event.*;
 import java.awt.geom.*;
 
-/** A rectangular region of interest and superclass for the other ROI classes. */
-public class Roi extends Object implements Cloneable, java.io.Serializable {
+/** 
+ * A rectangular region of interest and superclass for the other ROI classes. 
+ * 
+ * This class implements {@code Iterable<Point>} and can thus be
+ * used to iterate over the contained coordinates. Usage example: 
+ * <pre>
+ * Roi roi = ...;
+ * for (Point p : roi) {
+ *   // process p
+ * }
+ * </pre>
+ */
+public class Roi extends Object implements Cloneable, java.io.Serializable, Iterable<Point> {
 
 	public static final int CONSTRUCTING=0, MOVING=1, RESIZING=2, NORMAL=3, MOVING_HANDLE=4; // States
 	public static final int RECTANGLE=0, OVAL=1, POLYGON=2, FREEROI=3, TRACED_ROI=4, LINE=5, 
@@ -390,8 +402,10 @@ public class Roi extends Object implements Cloneable, java.io.Serializable {
 		if (cornerDiameter>0) {
 			ImageProcessor ip = getMask();
 			Roi roi2 = (new ThresholdToSelection()).convert(ip);
-			roi2.setLocation(x, y);
-			return roi2.getFloatPolygon();
+			if (roi2!=null) {
+				roi2.setLocation(x, y);
+				return roi2.getFloatPolygon();
+			}
 		}
 		if (subPixelResolution() && bounds!=null) {
 			float[] xpoints = new float[4];
@@ -528,6 +542,54 @@ public class Roi extends Object implements Cloneable, java.io.Serializable {
 		return fPoly;
 	}
 	
+	/** Returns the coordinates of the pixels inside this ROI as an array of Points.
+	 * @see #getContainedFloatPoints()
+	 * @see #Iterator()
+	 */
+	public Point[] getContainedPoints() {
+		if (isLine()) {
+			FloatPolygon p = getInterpolatedPolygon();
+			Point[] points = new Point[p.npoints];
+			for (int i=0; i<p.npoints; i++)
+				points[i] = new Point((int)Math.round(p.xpoints[i]),(int)Math.round(p.ypoints[i]));
+			return points;
+		}
+		ImageProcessor mask = getMask();
+		Rectangle bounds = getBounds();
+		ArrayList points = new ArrayList();
+		for (int y=0; y<bounds.height; y++) {
+			for (int x=0; x<bounds.width; x++) {
+				if (mask==null || mask.getPixel(x,y)!=0)
+					points.add(new Point(this.x+x,this.y+y));
+			}
+		}
+		return (Point[])points.toArray(new Point[points.size()]);
+	}
+	
+	/** Returns the coordinates of the pixels inside this ROI as a FloatPolygon.
+	 * @see #getContainedPoints()
+	 * @see #Iterator()
+	 */
+	public FloatPolygon getContainedFloatPoints() {
+		Roi roi2 = this;
+		if (isLine()) {
+			if (getStrokeWidth()<=1)
+				return roi2.getInterpolatedPolygon();
+			else
+				roi2 = Selection.lineToArea(this);
+		}
+		ImageProcessor mask = roi2.getMask();
+		Rectangle bounds = roi2.getBounds();
+		FloatPolygon points = new FloatPolygon();
+		for (int y=0; y<bounds.height; y++) {
+			for (int x=0; x<bounds.width; x++) {
+				if (mask==null || mask.getPixel(x,y)!=0)
+					points.addPoint((float)(bounds.x+x),(float)(bounds.y+y));
+			}
+		}
+		return points;
+	}
+
 	/**
 	 * <pre>
 	 * Calculates intersections of a line segment with a circle
@@ -1180,7 +1242,8 @@ public class Roi extends Object implements Cloneable, java.io.Serializable {
 	public int isHandle(int sx, int sy) {
 		if (clipboard!=null || ic==null) return -1;
 		double mag = ic.getMagnification();
-		int size = HANDLE_SIZE+3;
+		int margin = IJ.getScreenSize().width>1280?5:3;
+		int size = HANDLE_SIZE+margin;
 		int halfSize = size/2;
 		double x = getXBase();
 		double y = getYBase();
@@ -1521,13 +1584,17 @@ public class Roi extends Object implements Cloneable, java.io.Serializable {
 	public void setStrokeWidth(float width) {
 		if (width<0f)
 			width = 0f;
+		boolean notify = listeners.size()>0 && isLine() && getStrokeWidth()!=width;
 		if (width==0)
 			stroke = null;
 		else if (wideLine)
 			this.stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
 		else
 			this.stroke = new BasicStroke(width);
-		if (width>1f) fillColor = null;
+		if (width>1f)
+			fillColor = null;
+		if (notify)
+			notifyListeners(RoiListener.MODIFIED);
 	}
 
 	/** This is a version of setStrokeWidth() that accepts a double argument. */
@@ -2039,5 +2106,123 @@ public class Roi extends Object implements Cloneable, java.io.Serializable {
 	public static void removeRoiListener(RoiListener listener) {
 		listeners.removeElement(listener);
 	}
+	
+	/**
+	 * Required by the {@link Interable} interface.
+	 * Use to iterate over the contained coordinates. Usage example: 
+	 * <pre>
+	 * for (Point p : roi) {
+	 *   // process p
+	 * }
+	 * </pre>
+	 * @see #getContainedPoints()
+	 * @see #getContainedFloatPoints()
+	 * @author Wilhelm Burger
+	 */
+	public Iterator<Point> iterator() {
+		if (isLine() && getStrokeWidth()<=1.0)
+			return new RoiPointsIteratorLine();
+		else
+			return new RoiPointsIteratorMask();
+	}
+	
+
+	/**
+	 * Custom iterator over points contained in a straight line-type {@link Roi}.
+	 * @author W. Burger
+	 */
+	private class RoiPointsIteratorLine implements Iterator<Point> {
+		private final FloatPolygon p;
+		private int next = 0;
+
+		RoiPointsIteratorLine() {
+			p = getInterpolatedPolygon();
+		}
+
+		@Override
+		public boolean hasNext() {
+			return next<p.npoints;
+		}
+
+		@Override
+		public Point next() {
+			if (next >= p.npoints)
+				throw new NoSuchElementException();
+			int x = (int)Math.round(p.xpoints[next]);
+			int y = (int)Math.round(p.ypoints[next]);
+			next = next + 1;
+			return new Point(x, y);
+		}
+		
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+
+	}
+	
+	/**
+	 * Custom iterator over points contained in a mask-backed {@link Roi}.
+	 * @author W. Burger
+	 */
+	private class RoiPointsIteratorMask implements Iterator<Point> {
+		private final ImageProcessor mask;
+		private final Rectangle bounds;
+		private final int xbase, ybase;
+		private final int n;
+		private int next;
+		
+		RoiPointsIteratorMask() {
+			if (isLine()) {
+				Roi roi2 = Selection.lineToArea(Roi.this);
+				mask = roi2.getMask();
+				bounds = roi2.getBounds();
+				xbase = roi2.x;
+				ybase = roi2.y;
+			} else {
+				mask = getMask();
+				bounds = getBounds();
+				xbase = Roi.this.x;
+				ybase = Roi.this.y;
+			}
+			n = bounds.width * bounds.height;
+			findNext(0);	// sets next
+		}
+
+		@Override
+		public boolean hasNext() {
+			return next < n;
+		}
+
+		@Override
+		public Point next() {
+			if (next >= n)
+				throw new NoSuchElementException();
+			int x = next % bounds.width;
+			int y = next / bounds.width;
+			findNext(next+1);
+			return new Point(xbase+x, ybase+y);
+		}
+		
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();
+		}
+		
+		// finds the next element (from start), sets next
+		private void findNext(int start) {
+			if (mask == null)
+				next = start;
+			else {
+				next = n;
+				for (int i=start; i<n; i++) {
+					if (mask.get(i)!=0) {
+						next = i;
+						break;
+					}
+				}
+			}
+		}
+	}
 
 }
diff --git a/ij/gui/RoiProperties.java b/ij/gui/RoiProperties.java
index 3bf6bde..6aad86d 100644
--- a/ij/gui/RoiProperties.java
+++ b/ij/gui/RoiProperties.java
@@ -24,6 +24,7 @@ public class RoiProperties {
 	private boolean setPositions;
 	private boolean listCoordinates;
 	private boolean listProperties;
+	private boolean showPointCounts;
 	private static final String[] justNames = {"Left", "Center", "Right"};
 	private int nProperties;
 
@@ -151,8 +152,13 @@ public class RoiProperties {
 		if (isText)
 			gd.addCheckbox("Antialiased text", antialias);
 		if (showListCoordinates) {
+			if ((roi instanceof PointRoi) && Toolbar.getMultiPointMode())
+				showPointCounts = true;
 			int n = roi.getFloatPolygon().npoints;
-			gd.addCheckbox("List coordinates ("+n+")", listCoordinates);
+			if (showPointCounts)
+				gd.addCheckbox("Show point counts (shortcut: alt+y)", listCoordinates);
+			else
+				gd.addCheckbox("List coordinates ("+n+")", listCoordinates);
 			if (nProperties>0)
 				gd.addCheckbox("List properties ("+nProperties+")", listProperties);
 			else {
@@ -200,6 +206,7 @@ public class RoiProperties {
 						imp.setHideOverlay(true);
 				} else {
 					overlay.drawLabels(labels);
+					Analyzer.drawLabels(labels);
 					overlay.drawBackgrounds(true);
 					if (imp.getHideOverlay())
 						imp.setHideOverlay(false);
@@ -247,8 +254,12 @@ public class RoiProperties {
 			}
 			imp.draw();
 		}
-		if (listCoordinates)
-			listCoordinates(roi);
+		if (listCoordinates) {
+			if (showPointCounts && (roi instanceof PointRoi))
+				((PointRoi)roi).displayCounts();
+			else
+				listCoordinates(roi);
+		}
 		if (listProperties && nProperties>0)
 			listProperties(roi);
 		return true;
diff --git a/ij/gui/ShapeRoi.java b/ij/gui/ShapeRoi.java
index e54754c..f3b4841 100644
--- a/ij/gui/ShapeRoi.java
+++ b/ij/gui/ShapeRoi.java
@@ -223,6 +223,7 @@ public class ShapeRoi extends Roi {
 		setShape(new GeneralPath(at.createTransformedShape(a1)));
 		x = r.x;
 		y = r.y;
+		cachedMask = null;
 		return this;
 	}
 
@@ -854,8 +855,9 @@ public class ShapeRoi extends Roi {
 	 * control points of the curves segments in the iteration order;
 	 * @return <strong><code>true</code></strong> if successful.*/
 	boolean parsePath(PathIterator pIter, double[] params, Vector segments, Vector rois, Vector handles) {
+		if (pIter==null || pIter.isDone())
+			return false;
 		boolean result = true;
-		if (pIter==null) return false;
 		double pw = 1.0, ph = 1.0;
 		if (imp!=null) {
 			Calibration cal = imp.getCalibration();
diff --git a/ij/gui/StackWindow.java b/ij/gui/StackWindow.java
index 7a22c8e..17fc374 100644
--- a/ij/gui/StackWindow.java
+++ b/ij/gui/StackWindow.java
@@ -269,7 +269,7 @@ public class StackWindow extends ImageWindow implements Runnable, AdjustmentList
     }
     
     public boolean isHyperStack() {
-    	return hyperStack;
+    	return hyperStack && getNScrollbars()>0;
     }
     
     public void setPosition(int channel, int slice, int frame) {
diff --git a/ij/gui/TextRoi.java b/ij/gui/TextRoi.java
index b6b02d4..d566269 100644
--- a/ij/gui/TextRoi.java
+++ b/ij/gui/TextRoi.java
@@ -364,11 +364,16 @@ public class TextRoi extends Roi {
 		return instanceFont;
 	}
 	
-	/** Returns the state of global 'antialiasedText' variable, which is used by the "Fonts" widget. */
+	/** Returns the state of the global 'antialiasedText' variable, which is used by the "Fonts" widget. */
 	public static boolean isAntialiased() {
 		return antialiasedText;
 	}
 
+	/** Sets the state of the global 'antialiasedText' variable. */
+	public static void setAntialiasedText(boolean antialiased) {
+		antialiasedText = antialiased;
+	}
+	
 	/** Sets the 'antialiased' instance variable. */
 	public void setAntialiased(boolean antialiased) {
 		this.antialiased = antialiased;
diff --git a/ij/io/FileOpener.java b/ij/io/FileOpener.java
index 505f58e..8dec36c 100644
--- a/ij/io/FileOpener.java
+++ b/ij/io/FileOpener.java
@@ -46,13 +46,17 @@ public class FileOpener {
 		if (IJ.debugMode) IJ.log("FileInfo: "+fi);
 	}
 	
+	/** Opens the image and returns it has an ImagePlus object. */
+	public ImagePlus openImage() {
+		return open(false);
+	}
+
 	/** Opens the image and displays it. */
 	public void open() {
 		open(true);
 	}
 	
-	/** Opens the image. Displays it if 'show' is
-	true. Returns an ImagePlus object if successful. */
+	/** Obsolete, replaced by openImage() and open(). */
 	public ImagePlus open(boolean show) {
 
 		ImagePlus imp=null;
@@ -162,10 +166,13 @@ public class FileOpener {
 	
 	void setOverlay(ImagePlus imp, byte[][] rois) {
 		Overlay overlay = new Overlay();
+		Overlay proto = null;
 		for (int i=0; i<rois.length; i++) {
 			Roi roi = RoiDecoder.openFromByteArray(rois[i]);
-			if (i==0) {
-				Overlay proto = roi.getPrototypeOverlay();
+			if (roi==null)
+				continue;
+			if (proto==null) {
+				proto = roi.getPrototypeOverlay();
 				overlay.drawLabels(proto.getDrawLabels());
 				overlay.drawNames(proto.getDrawNames());
 				overlay.drawBackgrounds(proto.getDrawBackgrounds());
@@ -320,6 +327,13 @@ public class FileOpener {
 		Calibration cal = imp.getCalibration();
 		boolean calibrated = false;
 		if (fi.pixelWidth>0.0 && fi.unit!=null) {
+			if (fi.pixelWidth<=0.0001 && fi.unit.equals("cm")) {
+				fi.pixelWidth *= 10000.0;
+				fi.pixelHeight *= 10000.0;
+				if (fi.pixelDepth!=1.0)
+					fi.pixelDepth *= 10000.0;
+				fi.unit = "um";
+			}
 			cal.pixelWidth = fi.pixelWidth;
 			cal.pixelHeight = fi.pixelHeight;
 			cal.pixelDepth = fi.pixelDepth;
diff --git a/ij/io/FileSaver.java b/ij/io/FileSaver.java
index 56ebb4c..d2f8013 100644
--- a/ij/io/FileSaver.java
+++ b/ij/io/FileSaver.java
@@ -130,7 +130,7 @@ public class FileSaver {
 		if (obj==null) return;
 		FHT fht = (obj instanceof FHT)?(FHT)obj:null;
 		if (fht==null) return;
-		if (fht.originalColorModel!=null)
+		if (fht.originalColorModel!=null && fht.originalBitDepth!=24)
 			fht.setColorModel(fht.originalColorModel);
 		ImagePlus imp2 = new ImagePlus(imp.getTitle(), fht);
 		imp2.setProperty("Info", imp.getProperty("Info"));
diff --git a/ij/io/ImportDialog.java b/ij/io/ImportDialog.java
index 175f679..b664455 100644
--- a/ij/io/ImportDialog.java
+++ b/ij/io/ImportDialog.java
@@ -82,7 +82,7 @@ public class ImportDialog {
 		if (choiceSelection>=types.length)
 			choiceSelection = 0;
 		getDimensionsFromName(fileName);
-		GenericDialog gd = new GenericDialog("Import>Raw...", IJ.getInstance());
+		GenericDialog gd = new GenericDialog("Import>Raw...");
 		gd.addChoice("Image type:", types, types[choiceSelection]);
 		gd.addNumericField("Width:", width, 0, 6, "pixels");
 		gd.addNumericField("Height:", height, 0, 6, "pixels");
@@ -97,15 +97,16 @@ public class ImportDialog {
 		gd.showDialog();
 		if (gd.wasCanceled())
 			return false;
-		gd.setSmartRecording(true);
 		choiceSelection = gd.getNextChoiceIndex();
-		gd.setSmartRecording(false);
 		width = (int)gd.getNextNumber();
 		height = (int)gd.getNextNumber();
-		gd.setSmartRecording(true);
+		gd.setSmartRecording(offset==0);
 		offset = (long)gd.getNextNumber();
+		gd.setSmartRecording(nImages==1);
 		nImages = (int)gd.getNextNumber();
+		gd.setSmartRecording(gapBetweenImages==0);
 		gapBetweenImages = (int)gd.getNextNumber();
+		gd.setSmartRecording(false);
 		whiteIsZero = gd.getNextBoolean();
 		intelByteOrder = gd.getNextBoolean();
 		openAll = gd.getNextBoolean();
@@ -140,7 +141,7 @@ public class ImportDialog {
 			if (list[i].startsWith("."))
 				continue;
 			fi.fileName = list[i];
-			imp = new FileOpener(fi).open(false);
+			imp = new FileOpener(fi).openImage();
 			if (imp==null)
 				IJ.log(list[i] + ": unable to open");
 			else {
@@ -200,7 +201,7 @@ public class ImportDialog {
 			new FileInfoVirtualStack(fi);
 		else {
 			FileOpener fo = new FileOpener(fi);
-			ImagePlus imp = fo.open(false);
+			ImagePlus imp = fo.openImage();
 			if (imp!=null) {
 				imp.show();
 				int n = imp.getStackSize();
diff --git a/ij/io/OpenDialog.java b/ij/io/OpenDialog.java
index b1c075e..a913189 100644
--- a/ij/io/OpenDialog.java
+++ b/ij/io/OpenDialog.java
@@ -150,6 +150,13 @@ import javax.swing.filechooser.*;
 			if (sharedFrame==null) sharedFrame = new Frame();
 			parent = sharedFrame;
 		}
+		if (IJ.isMacOSX() && IJ.isJava18()) {
+			ImageJ ij = IJ.getInstance();
+			if (ij!=null && ij.isActive())
+				parent = ij;
+			else
+				parent = null;
+		}
 		FileDialog fd = new FileDialog(parent, title);
 		if (path!=null)
 			fd.setDirectory(path);
@@ -214,7 +221,7 @@ import javax.swing.filechooser.*;
 	/** Sets the current working directory. */
 	public static void setDefaultDirectory(String defaultDir) {
 		defaultDirectory = defaultDir;
-		if (!defaultDirectory.endsWith(File.separator) && !defaultDirectory.endsWith("/"))
+		if (defaultDirectory!=null && !defaultDirectory.endsWith(File.separator) && !defaultDirectory.endsWith("/"))
 			defaultDirectory = defaultDirectory + File.separator;
 	}
 	
diff --git a/ij/io/Opener.java b/ij/io/Opener.java
index d54c1f1..758b7a8 100644
--- a/ij/io/Opener.java
+++ b/ij/io/Opener.java
@@ -719,7 +719,7 @@ public class Opener {
 			return null;
 		FileInfo fi = info[0];
 		if (fi.nImages>1)
-			return new FileOpener(fi).open(false); // open contiguous images as stack
+			return new FileOpener(fi).openImage(); // open contiguous images as stack
 		else {
 			ColorModel cm = createColorModel(fi);
 			ImageStack stack = new ImageStack(fi.width, fi.height, cm);
@@ -876,7 +876,7 @@ public class Opener {
 			fi.stripLengths = info[n-1].stripLengths; 
 		}
 		FileOpener fo = new FileOpener(fi);
-		return fo.open(false);
+		return fo.openImage();
 	}
 
 	/** Returns the FileInfo of the specified TIFF file. */
@@ -980,7 +980,7 @@ public class Opener {
 			return null;
 		}
 		FileOpener opener = new FileOpener(info[0]);
-		ImagePlus imp = opener.open(false);
+		ImagePlus imp = opener.openImage();
 		if (imp==null)
 			return null;
 		imp.setTitle(info[0].fileName);
@@ -1037,7 +1037,7 @@ public class Opener {
 				return imp;
 		}
 		FileOpener fo = new FileOpener(info[0]);
-		imp = fo.open(false);
+		imp = fo.openImage();
 		if (imp==null) return null;
 		int[] offsets = info[0].stripOffsets;
 		if (offsets!=null&&offsets.length>1 && offsets[offsets.length-1]<offsets[0])
diff --git a/ij/io/RoiDecoder.java b/ij/io/RoiDecoder.java
index 3c24dde..8566bdd 100644
--- a/ij/io/RoiDecoder.java
+++ b/ij/io/RoiDecoder.java
@@ -329,6 +329,8 @@ public class RoiDecoder {
 		// read stroke width, stroke color and fill color (1.43i or later)
 		if (version>=218) {
 			getStrokeWidthAndColor(roi, hdr2Offset);
+			if (type==point)
+				roi.setStrokeWidth(0);
 			boolean splineFit = (options&SPLINE_FIT)!=0;
 			if (splineFit && roi instanceof PolygonRoi)
 				((PolygonRoi)roi).fitSpline();
@@ -543,6 +545,8 @@ public class RoiDecoder {
 	/** Opens an ROI from a byte array. */
 	public static Roi openFromByteArray(byte[] bytes) {
 		Roi roi = null;
+		if (bytes==null || bytes.length==0)
+			return roi;
 		try {
 			RoiDecoder decoder = new RoiDecoder(bytes, null);
 			roi = decoder.getRoi();
diff --git a/ij/macro/Functions.java b/ij/macro/Functions.java
index c0a7199..ca35e1f 100644
--- a/ij/macro/Functions.java
+++ b/ij/macro/Functions.java
@@ -755,6 +755,7 @@ public class Functions implements MacroConstants, Measurements {
 		if (previousRoi!=null && roi!=null)
 			updateRoi(roi);
 		resetImage();
+		shiftKeyDown = altKeyDown = false;
 	}
 	
 	void makeRectangle() {
@@ -780,6 +781,7 @@ public class Functions implements MacroConstants, Measurements {
 		if (previousRoi!=null && roi!=null)
 			updateRoi(roi);
 		resetImage();
+		shiftKeyDown = altKeyDown = false;
 		IJ.setKeyUp(IJ.ALL_KEYS);
 	}
 	
@@ -2016,6 +2018,7 @@ public class Functions implements MacroConstants, Measurements {
 				updateRoi(roi); 
 		}
 		updateNeeded = false;
+		shiftKeyDown = altKeyDown = false;
 	}
 
 	void doPlot() {
@@ -3776,6 +3779,7 @@ public class Functions implements MacroConstants, Measurements {
 		if (previousRoi!=null && roi!=null)
 			updateRoi(roi); 
 		resetImage(); 
+		shiftKeyDown = altKeyDown = false;
 	}
 	
 	void updateRoi(Roi roi) {
@@ -4196,6 +4200,8 @@ public class Functions implements MacroConstants, Measurements {
 			Prefs.useJFileChooser = state;
 		else if (arg1.startsWith("auto"))
 			Prefs.autoContrast = state;
+		else if (arg1.equals("antialiasedtext"))
+			TextRoi.setAntialiasedText(state);
 		else
 			interp.error("Invalid option");
 	}
@@ -4942,13 +4948,18 @@ public class Functions implements MacroConstants, Measurements {
 	}
 
 	void setMeasurements() {
-		interp.getParens();
+		String arg = "";
+		if (interp.nextToken()=='(') {
+			interp.getLeftParen();
+			if (interp.nextToken() != ')')
+				arg = getString().toLowerCase(Locale.US);
+			interp.getRightParen();
+		}
 		props.clear();
 		ImagePlus imp = getImage();
-		int measurements = AREA+MEAN+STD_DEV+MODE+MIN_MAX+
-			CENTROID+CENTER_OF_MASS+PERIMETER+RECT+
-			ELLIPSE+SHAPE_DESCRIPTORS+FERET+INTEGRATED_DENSITY+
-			MEDIAN+SKEWNESS+KURTOSIS+AREA_FRACTION;
+		int measurements = ALL_STATS;
+		if (arg.contains("limit"))
+			measurements += LIMIT;
 		ImageStatistics stats = imp.getStatistics(measurements);
 		ResultsTable rt = new ResultsTable();
 		Analyzer analyzer = new Analyzer(imp, measurements, rt);
@@ -4999,7 +5010,8 @@ public class Functions implements MacroConstants, Measurements {
 			IJ.makePoint((int)x, (int)y);
 		else
 			IJ.makePoint(x, y);
-		resetImage(); 
+		resetImage();
+		shiftKeyDown = altKeyDown = false;
 	}
 
 	void makeText() {
@@ -5032,6 +5044,7 @@ public class Functions implements MacroConstants, Measurements {
 		if (previousRoi!=null && roi!=null)
 			updateRoi(roi);
 		resetImage();
+		shiftKeyDown = altKeyDown = false;
 	}
 	
 	double fit() {
@@ -5788,6 +5801,8 @@ public class Functions implements MacroConstants, Measurements {
 			int index = (int)getArg();
 			checkIndex(index, 0, size-1);
 			Roi roi = overlay.get(index);
+			if (roi==null)
+				return Double.NaN;;
 			if (imp.getStackSize()>1) {
 				if (imp.isHyperStack()) {
 					int c = roi.getCPosition();
@@ -6174,6 +6189,9 @@ public class Functions implements MacroConstants, Measurements {
 		} else if (name.equals("getCoordinates")) {
 			getCoordinates();
 			return null;
+		} else if (name.equals("getContainedPoints")) {
+			getContainedPoints(roi);
+			return null;
 		} else if (name.equals("getName")) {
 			interp.getParens();
 			String roiName = roi.getName();
@@ -6227,6 +6245,20 @@ public class Functions implements MacroConstants, Measurements {
 		return null;
 	}
 	
+	private void getContainedPoints(Roi roi) {
+		Variable xCoordinates = getFirstArrayVariable();
+		Variable yCoordinates = getLastArrayVariable();
+		FloatPolygon points = roi.getContainedFloatPoints();
+		Variable[] xa = new Variable[points.npoints];
+		Variable[] ya = new Variable[points.npoints];
+		for (int i=0; i<points.npoints; i++) {
+			xa[i] = new Variable(points.xpoints[i]);
+			ya[i] = new Variable(points.ypoints[i]);
+		}
+		xCoordinates.setArray(xa);
+		yCoordinates.setArray(ya);
+	}
+
 	private String getSplineAnchors(Roi roi) {
 		Variable xCoordinates = getFirstArrayVariable();
 		Variable yCoordinates = getLastArrayVariable();
@@ -6270,6 +6302,6 @@ public class Functions implements MacroConstants, Measurements {
 		imp.setRoi(roi);
 		return null;
 	}
-
+	
 } // class Functions
 
diff --git a/ij/macro/Interpreter.java b/ij/macro/Interpreter.java
index 9591ae4..d67eac8 100644
--- a/ij/macro/Interpreter.java
+++ b/ij/macro/Interpreter.java
@@ -1179,7 +1179,7 @@ public class Interpreter implements MacroConstants {
 		WindowManager.setTempCurrentImage(null);
 		wasError = true;
 		instance = null;
-		if (showMessage) {
+		if (showMessage && message!=null) {
 			String line = getErrorLine();
 			done = true;
 			if (line.length()>120)
@@ -1870,7 +1870,7 @@ public class Interpreter implements MacroConstants {
 	/** Returns the batch mode RoiManager instance. */
 	public static RoiManager getBatchModeRoiManager() {
 		Interpreter interp = getInstance();
-		if (interp!=null && isBatchMode() && RoiManager.getInstance()==null) {
+		if (interp!=null && isBatchMode() && RoiManager.getRawInstance()==null) {
 			if (interp.func.roiManager==null)
 				interp.func.roiManager = new RoiManager(true);
 			return interp.func.roiManager;
diff --git a/ij/macro/MacroConstants.java b/ij/macro/MacroConstants.java
index 0a26c15..ae62cda 100644
--- a/ij/macro/MacroConstants.java
+++ b/ij/macro/MacroConstants.java
@@ -60,7 +60,7 @@ public interface MacroConstants {
 		"waitForUser", "makePoint", "makeText", "makeEllipse", "getDisplayedArea",
 		"toScaled", "toUnscaled", "makeArrow"};
 	static final int[] functionIDs = {RUN, INVERT, SELECT, WAIT, BEEP, RESET_MIN_MAX, RESET_THRESHOLD,
-		PRINT, WRITE,	 DO_WAND, SET_MIN_MAX, SET_THRESHOLD, SET_TOOL,
+		PRINT, WRITE, DO_WAND, SET_MIN_MAX, SET_THRESHOLD, SET_TOOL,
 		SET_FOREGROUND, SET_BACKGROUND, MAKE_LINE, MAKE_OVAL, MAKE_RECTANGLE,
 		DUMP, MOVE_TO, LINE_TO, DRAW_LINE, REQUIRES, AUTO_UPDATE, UPDATE_DISPLAY, DRAW_STRING,
 		SET_PASTE_MODE, DO_COMMAND, SHOW_STATUS, SHOW_PROGRESS, SHOW_MESSAGE, PUT_PIXEL, SET_PIXEL,
diff --git a/ij/macro/MacroRunner.java b/ij/macro/MacroRunner.java
index 327d1df..b023297 100644
--- a/ij/macro/MacroRunner.java
+++ b/ij/macro/MacroRunner.java
@@ -156,10 +156,13 @@ public class MacroRunner implements Runnable {
 			IJ.showStatus("");
 			IJ.showProgress(1.0);
 			ImagePlus imp = WindowManager.getCurrentImage();
-			if (imp!=null) imp.unlock();
+			if (imp!=null)
+				imp.unlock();
 			String msg = e.getMessage();
-			if (e instanceof RuntimeException && msg!=null && e.getMessage().equals(Macro.MACRO_CANCELED))
+			if (e instanceof RuntimeException && msg!=null && e.getMessage().equals(Macro.MACRO_CANCELED)) {
+				interp.error(null);
 				return;
+			}
 			IJ.handleException(e);
 		} finally {
 			if (thread!=null)
diff --git a/ij/measure/CurveFitter.java b/ij/measure/CurveFitter.java
index c9a542f..40813c4 100644
--- a/ij/measure/CurveFitter.java
+++ b/ij/measure/CurveFitter.java
@@ -37,6 +37,7 @@ import java.util.Hashtable;
  *  2013-09-24: Added "Exponential Recovery (no offset)" and "Chapman-Richards" (3-parameter) fit types.
  *  2013-10-11: bugfixes, added setStatusAndEsc to show iterations and enable abort by ESC
  *  2015-03-26: bugfix, did not use linear regression for RODBARD
+ *  2016-11-28: added static getNumParams methods
  */
 
 public class CurveFitter implements UserFunction{
@@ -220,15 +221,7 @@ public class CurveFitter implements UserFunction{
 	 */
 	public int doCustomFit(String equation, double[] initialParams, boolean showSettings) {
 		customFormula = null;
-		customParamCount = 0;
-		Program pgm = (new Tokenizer()).tokenize(equation);
-		if (!pgm.hasWord("y") ||  !pgm.hasWord("x"))
-		    return 0;
-		String[] params = {"a","b","c","d","e","f"};
-		for (int i=0; i<params.length; i++) {
-			if (pgm.hasWord(params[i]))
-				customParamCount++;
-		}
+		customParamCount = getNumParams(equation);
 		if (customParamCount==0)
 			return 0;
 		customFormula = equation;
@@ -322,6 +315,15 @@ public class CurveFitter implements UserFunction{
 	/** Get number of parameters for current fit formula
 	 *	Do not use before 'doFit', because the fit function would be undefined.	 */
 	public int getNumParams() {
+		if (fitType == CUSTOM)
+			return customParamCount;
+		else
+			return getNumParams(fitType);
+	}
+
+	/** Returns the number of parameters for a given fit type, except for the 'custom' fit,
+	 *  where the number of parameters is given by the equation: see getNumParams(String) */
+	public static int getNumParams(int fitType) {
 		switch (fitType) {
 			case STRAIGHT_LINE: return 2;
 			case POLY2: return 3;
@@ -343,11 +345,28 @@ public class CurveFitter implements UserFunction{
 			case RODBARD: case RODBARD2: case INV_RODBARD: case RODBARD_INTERNAL: return 4;
 			case GAMMA_VARIATE: return 4;
 			case GAUSSIAN: case GAUSSIAN_INTERNAL: return 4;
-			case CUSTOM: return customParamCount;
 		}
 		return 0;
 	}
 
+	/** Returns the number of parameters for a custom equation given as a macro String,
+	 *  like "y = a + b*x + c*x*x" .  Restricted to 6 parameters "a" ... "f"
+	 *  (fitting more parameters is not likely to yield an accurate result anyhow).
+	 *  Returns 0 if a very basic check does not find a formula of this type. */
+	public static int getNumParams(String customFormula) {
+		Program pgm = (new Tokenizer()).tokenize(customFormula);
+		if (!pgm.hasWord("y") ||  !pgm.hasWord("x"))
+		    return 0;
+		String[] params = {"a","b","c","d","e","f"};
+		int customParamCount = 0;
+		for (int i=0; i<params.length; i++) {
+			if (pgm.hasWord(params[i])) {
+				customParamCount++;
+			}
+		}
+		return customParamCount;
+	}
+
 	/** Returns the formula value for parameters 'p' at 'x'.
 	 *	Do not use before 'doFit', because the fit function would be undefined. */
 	public final double f(double x) {
diff --git a/ij/measure/Measurements.java b/ij/measure/Measurements.java
index b1cf4c3..c599cd9 100644
--- a/ij/measure/Measurements.java
+++ b/ij/measure/Measurements.java
@@ -11,5 +11,11 @@ public interface Measurements {
 		
 	/** Maximum number of calibration standard (20) */
 	public static final int MAX_STANDARDS = 20;
+	
+	/** All measurement options */
+	public static final int ALL_STATS = AREA+MEAN+STD_DEV+MODE+MIN_MAX+
+		CENTROID+CENTER_OF_MASS+PERIMETER+RECT+
+		ELLIPSE+SHAPE_DESCRIPTORS+FERET+INTEGRATED_DENSITY+
+		MEDIAN+SKEWNESS+KURTOSIS+AREA_FRACTION;
 
 }
diff --git a/ij/measure/ResultsTable.java b/ij/measure/ResultsTable.java
index 5f52e1e..98877ed 100644
--- a/ij/measure/ResultsTable.java
+++ b/ij/measure/ResultsTable.java
@@ -377,6 +377,15 @@ public class ResultsTable implements Cloneable {
 		//IJ.log("col: "+col+" "+(col==COLUMN_NOT_FOUND?"not found":""+columns[col]));
 		return getValueAsDouble(col,row);
 	}
+	
+	/** Returns 'true' if the specified column exists and is not emptly. */
+	public boolean columnExists(String column) {
+		int col = getColumnIndex(column);
+		if (col==COLUMN_NOT_FOUND)
+			return false;
+		else
+			return (col<columns.length && columns[col]!=null);
+	}
 
 	/** Returns the string value of the given column and row,
 		where row must be greater than or equal zero
@@ -1120,5 +1129,5 @@ public class ResultsTable implements Cloneable {
 	public String toString() {
 		return ("ctr="+counter+", hdr="+getColumnHeadings());
 	}
-	
+		
 }
diff --git a/ij/plugin/Animator.java b/ij/plugin/Animator.java
index f9d3aed..724e6ed 100644
--- a/ij/plugin/Animator.java
+++ b/ij/plugin/Animator.java
@@ -100,8 +100,10 @@ public class Animator implements PlugIn {
 		Calibration cal = imp.getCalibration();
 		if (cal.fps!=0.0)
 			animationRate = cal.fps;
-		if (animationRate<0.1)
+		if (animationRate<0.1) {
 			animationRate = 1.0;
+			cal.fps = animationRate;
+		}
 		int frames = imp.getNFrames();
 		int slices = imp.getNSlices();
 		
diff --git a/ij/plugin/AppearanceOptions.java b/ij/plugin/AppearanceOptions.java
index bdd44f5..54f67a1 100644
--- a/ij/plugin/AppearanceOptions.java
+++ b/ij/plugin/AppearanceOptions.java
@@ -15,7 +15,6 @@ public class AppearanceOptions implements PlugIn, DialogListener {
 	private boolean black = Prefs.blackCanvas;
 	private boolean noBorder = Prefs.noBorder;
 	private boolean inverting = Prefs.useInvertingLut;
-	private boolean antialiased = Prefs.antialiasedTools;
 	private int rangeIndex = ContrastAdjuster.get16bitRangeIndex();
 	private LUT[] luts = getLuts();
 	private int setMenuSize = Menus.getFontSize();
@@ -27,28 +26,25 @@ public class AppearanceOptions implements PlugIn, DialogListener {
 		
 	void showDialog() {
 		String[] ranges = ContrastAdjuster.getSixteenBitRanges();
-		GenericDialog gd = new GenericDialog("Appearance", IJ.getInstance());
+		GenericDialog gd = new GenericDialog("Appearance");
 		gd.addCheckbox("Interpolate zoomed images", Prefs.interpolateScaledImages);
 		gd.addCheckbox("Open images at 100%", Prefs.open100Percent);
 		gd.addCheckbox("Black canvas", Prefs.blackCanvas);
 		gd.addCheckbox("No image border", Prefs.noBorder);
 		gd.addCheckbox("Use inverting lookup table", Prefs.useInvertingLut);
-		gd.addCheckbox("Antialiased tool icons", Prefs.antialiasedTools);
 		gd.addCheckbox("Auto contrast stacks (or use shift key)", Prefs.autoContrast);
+		gd.addCheckbox("IJ window always on top", Prefs.alwaysOnTop);
 		gd.addChoice("16-bit range:", ranges, ranges[rangeIndex]);
 		gd.addNumericField("Menu font size:", Menus.getFontSize(), 0, 3, "points");
-        gd.addHelp(IJ.URL+"/docs/menus/edit.html#appearance");
-        gd.addDialogListener(this);
+		gd.addHelp(IJ.URL+"/docs/menus/edit.html#appearance");
+		gd.addDialogListener(this);
 		gd.showDialog();
 		if (gd.wasCanceled()) {
-			if (antialiased!=Prefs.antialiasedTools)
-				Toolbar.getInstance().repaint();
 			Prefs.interpolateScaledImages = interpolate;
 			Prefs.open100Percent = open100;
 			Prefs.blackCanvas = black;
 			Prefs.noBorder = noBorder;
 			Prefs.useInvertingLut = inverting;
-			Prefs.antialiasedTools = antialiased;
 			if (redrawn) draw();
 			if (repainted) repaintWindow();
 			Prefs.open100Percent = open100;
@@ -91,11 +87,9 @@ public class AppearanceOptions implements PlugIn, DialogListener {
 		boolean blackCanvas = gd.getNextBoolean();
 		boolean noBorder = gd.getNextBoolean();
 		Prefs.useInvertingLut = gd.getNextBoolean();
-		boolean antialiasedTools = gd.getNextBoolean();
-		boolean toolbarChange = antialiasedTools!=Prefs.antialiasedTools;
-		Prefs.antialiasedTools = antialiasedTools;
+		boolean alwaysOnTop = Prefs.alwaysOnTop;
 		Prefs.autoContrast = gd.getNextBoolean();
-		if (toolbarChange) Toolbar.getInstance().repaint();
+		Prefs.alwaysOnTop = gd.getNextBoolean();
 		setMenuSize = (int)gd.getNextNumber();
 		if (interpolate!=Prefs.interpolateScaledImages) {
 			Prefs.interpolateScaledImages = interpolate;
@@ -109,6 +103,10 @@ public class AppearanceOptions implements PlugIn, DialogListener {
 			Prefs.noBorder = noBorder;
 			repaintWindow();
 		}
+		if (alwaysOnTop!=Prefs.alwaysOnTop) {
+			ImageJ ij = IJ.getInstance();
+			if (ij!=null) ij.setAlwaysOnTop(Prefs.alwaysOnTop);
+		}
 		int rangeIndex2 = gd.getNextChoiceIndex();
 		int range1 = ImagePlus.getDefault16bitRange();
 		int range2 = ContrastAdjuster.set16bitRange(rangeIndex2);
diff --git a/ij/plugin/BatchConverter.java b/ij/plugin/BatchConverter.java
index 3adfa85..2fb8f6c 100644
--- a/ij/plugin/BatchConverter.java
+++ b/ij/plugin/BatchConverter.java
@@ -102,7 +102,7 @@ import java.io.*;
 		gd = new GenericDialog("Batch Convert");
 		addPanels(gd);
 		gd.setInsets(15, 0, 5);
-		gd.addChoice("Output format:", formats, format);
+		gd.addChoice("Output_format:", formats, format);
 		gd.addChoice("Interpolation:", methods, methods[interpolationMethod]);
 		//gd.addStringField("Height (pixels): ", height==0?"\u2014":""+height, 6);
 		gd.addNumericField("Scale factor:", scale, 2);
diff --git a/ij/plugin/CommandFinder.java b/ij/plugin/CommandFinder.java
index 1768b34..ae878b1 100644
--- a/ij/plugin/CommandFinder.java
+++ b/ij/plugin/CommandFinder.java
@@ -26,6 +26,7 @@ package ij.plugin;
 import ij.*;
 import ij.text.*;
 import ij.plugin.frame.Editor;
+import ij.gui.HTMLDialog;
 import java.awt.*;
 import java.awt.event.*;
 import java.util.*;
@@ -45,7 +46,7 @@ public class CommandFinder implements PlugIn, ActionListener, WindowListener, Ke
 	private static JFrame frame;
 	private JTextField prompt;
 	private JScrollPane scrollPane;
-	private JButton runButton, sourceButton, closeButton;
+	private JButton runButton, sourceButton, closeButton, helpButton;
 	private JCheckBox closeCheckBox;
 	private Hashtable commandsHash;
 	private String [] commands;
@@ -131,6 +132,13 @@ public class CommandFinder implements PlugIn, ActionListener, WindowListener, Ke
 			showSource(tableModel.getCommand(row));
 		} else if (source == closeButton) {
 			closeWindow();
+		} else if (source == helpButton) {
+			String text = "<html>Shortcuts:<br>"
+				+ " ↑ ↓  Select items<br>"
+				+ " ↵  Open item<br>"
+				+ " A-Z  Alphabetic scroll<br>"
+				+ " ⌫ Activate search field</html>";
+			new HTMLDialog("", text);
 		}
 	}
 
@@ -458,18 +466,6 @@ public class CommandFinder implements PlugIn, ActionListener, WindowListener, Ke
 			}
 		});
 
-		// List the most useful shortcuts in a tooltip. Tooltips
-		// can be an annoyance so we'll increase delay times
-		ToolTipManager ttm = ToolTipManager.sharedInstance();
-		ttm.setInitialDelay(2 * ttm.getInitialDelay());
-		ttm.setReshowDelay(2 * ttm.getReshowDelay());
-		ttm.setDismissDelay(2 * ttm.getDismissDelay());
-		table.setToolTipText("<html>Shortcuts:<br>"
-				+ " ↑ ↓  Select items<br>"
-				+ " ↵  Open item<br>"
-				+ " A-Z  Alphabetic scroll<br>"
-				+ " ⌫ Activate search field</html>");
-
 		scrollPane = new JScrollPane(table);
 		if (initialSearch==null)
 			initialSearch = "";
@@ -480,12 +476,15 @@ public class CommandFinder implements PlugIn, ActionListener, WindowListener, Ke
 		runButton = new JButton("Run");
 		sourceButton = new JButton("Source");
 		closeButton = new JButton("Close");
+		helpButton = new JButton("Help");
 		runButton.addActionListener(this);
 		sourceButton.addActionListener(this);
 		closeButton.addActionListener(this);
+		helpButton.addActionListener(this);
 		runButton.addKeyListener(this);
 		sourceButton.addKeyListener(this);
 		closeButton.addKeyListener(this);
+		helpButton.addKeyListener(this);
 
 		JPanel southPanel = new JPanel();
 		southPanel.setLayout(new BorderLayout());
@@ -497,6 +496,7 @@ public class CommandFinder implements PlugIn, ActionListener, WindowListener, Ke
 		buttonsPanel.add(runButton);
 		buttonsPanel.add(sourceButton);
 		buttonsPanel.add(closeButton);
+		buttonsPanel.add(helpButton);
 
 		southPanel.add(optionsPanel, BorderLayout.CENTER);
 		southPanel.add(buttonsPanel, BorderLayout.SOUTH);
diff --git a/ij/plugin/Commands.java b/ij/plugin/Commands.java
index 970ef29..4aa9531 100644
--- a/ij/plugin/Commands.java
+++ b/ij/plugin/Commands.java
@@ -146,15 +146,19 @@ public class Commands implements PlugIn {
 	// Plugins>Macros>Open Startup Macros command
 	void openStartupMacros() {
 		Applet applet = IJ.getApplet();
-		if (applet!=null) {
+		if (applet!=null)
 			IJ.run("URL...", "url="+IJ.URL+"/applet/StartupMacros.txt");
-		} else {
+		else {
 			String path = IJ.getDirectory("macros")+"StartupMacros.txt";
 			File f = new File(path);
 			if (!f.exists()) {
 				path = IJ.getDirectory("macros")+"StartupMacros.ijm";
 				f = new File(path);
 			}
+			if (!f.exists()) {
+				path = IJ.getDirectory("macros")+"StartupMacros.fiji.ijm";
+				f = new File(path);
+			}
 			if (!f.exists())
 				IJ.error("\"StartupMacros.txt\" not found in ImageJ/macros/");
 			else
diff --git a/ij/plugin/Compiler.java b/ij/plugin/Compiler.java
index 8ec8519..5b65c00 100644
--- a/ij/plugin/Compiler.java
+++ b/ij/plugin/Compiler.java
@@ -15,8 +15,8 @@ import javax.tools.*;
 /** Compiles and runs plugins using the javac compiler. */
 public class Compiler implements PlugIn, FilenameFilter {
 
-	private static final int TARGET14=0, TARGET15=1, TARGET16=2,  TARGET17=3,  TARGET18=4;
-	private static final String[] targets = {"1.4", "1.5", "1.6", "1.7", "1.8"};
+	private static final int TARGET14=0, TARGET15=1, TARGET16=2,  TARGET17=3,  TARGET18=4, TARGET19=5;
+	private static final String[] targets = {"1.4", "1.5", "1.6", "1.7", "1.8", "1.9"};
 	private static final String TARGET_KEY = "javac.target";
 	private static CompilerTool compilerTool;
 	private static String dir, name;
@@ -125,7 +125,6 @@ public class Compiler implements PlugIn, FilenameFilter {
 		Vector sources = new Vector();
 		sources.add(path);
 		
-		/*
 		if (IJ.debugMode) {
 			StringBuilder builder = new StringBuilder();
 			builder.append("javac");
@@ -139,7 +138,6 @@ public class Compiler implements PlugIn, FilenameFilter {
 			}
 			IJ.log(builder.toString());
 		}
-		*/
 		
 		boolean errors = true;
 		String s = "not compiled";
@@ -180,16 +178,18 @@ public class Compiler implements PlugIn, FilenameFilter {
 		File f = new File(path);
 		if (f.exists() && f.isDirectory())
 			list = f.list();
-		if (list==null) return;
+		if (list==null)
+			return;
+		boolean isJarsFolder = path.endsWith("jars");
 		if (!path.endsWith(File.separator))
 			path += File.separator;
 		for (int i=0; i<list.length; i++) {
 			File f2 = new File(path+list[i]);
 			if (f2.isDirectory())
 				addJars(path+list[i], sb);
-			else if (list[i].endsWith(".jar")&&(list[i].indexOf("_")==-1||list[i].equals("loci_tools.jar")||list[i].contains("3D_Viewer"))) {
+			else if (list[i].endsWith(".jar")&&(!list[i].contains("_")||isJarsFolder||list[i].equals("loci_tools.jar"))) {
 				sb.append(File.pathSeparator+path+list[i]);
-				//if (IJ.debugMode) IJ.log("javac classpath: "+path+list[i]);
+				//IJ.log("javac classpath: "+path+list[i]);
 			}
 		}
 	}
@@ -199,8 +199,12 @@ public class Compiler implements PlugIn, FilenameFilter {
 			errors = (Editor)IJ.runPlugIn("ij.plugin.frame.Editor", "");
 			errors.setFont(new Font("Monospaced", Font.PLAIN, 12));
 		}
-		if (errors!=null)
+		if (errors!=null) {
+			ImageJ ij = IJ.getInstance();
+			if (ij!=null)
+				s = ij.getInfo()+"\n \n"+s;
 			errors.display("Errors", s);
+		}
 		IJ.showStatus("done (errors)");
 	}
 
@@ -274,20 +278,23 @@ public class Compiler implements PlugIn, FilenameFilter {
 	}
 	
 	void validateTarget() {
-		if (target<0 || target>TARGET18)
-			target = TARGET16;
-		if (target>TARGET15 && !(IJ.isJava16()||IJ.isJava17()||IJ.isJava18()))
+		if (target>TARGET19)
+			target = TARGET19;
+		if (target<TARGET15)
 			target = TARGET15;
-		if (target>TARGET16 && !(IJ.isJava17()||IJ.isJava18()))
+		if (target>TARGET15 && !(IJ.isJava16()||IJ.isJava17()||IJ.isJava18()||IJ.isJava19()))
 			target = TARGET16;
-		if (target>TARGET17 && !IJ.isJava18())
+		if (target>TARGET16 && !(IJ.isJava17()||IJ.isJava18()||IJ.isJava19()))
+			target = TARGET16;
+		if (target>TARGET17 && !(IJ.isJava18()||IJ.isJava19()))
 			target = TARGET17;
+		if (target>TARGET18 && !IJ.isJava19())
+			target = TARGET18;
 		Prefs.set(TARGET_KEY, target);
 	}
 	
 }
 
-
 class PlugInExecuter implements Runnable {
 	private String plugin;
 	private Thread thread;
diff --git a/ij/plugin/Concatenator.java b/ij/plugin/Concatenator.java
index f95da23..75c5d12 100644
--- a/ij/plugin/Concatenator.java
+++ b/ij/plugin/Concatenator.java
@@ -6,6 +6,7 @@ import ij.gui.*;
 import java.awt.*;
 import ij.measure.*;
 import ij.plugin.filter.*;
+import ij.plugin.frame.Recorder;
 import java.awt.event.*;
 import java.util.*;
 import java.lang.*;
@@ -37,6 +38,8 @@ public class Concatenator implements PlugIn, ItemListener{
 	private int stackSize;
 	private double min = 0, max = Float.MAX_VALUE;
 	private int maxWidth, maxHeight;
+	private boolean showingDialog;
+
 	
 	/** Optional string argument sets the name dialog boxes if called from another plugin. */
 	public void run(String arg) {
@@ -61,13 +64,40 @@ public class Concatenator implements PlugIn, ItemListener{
 	}
 	
 	/** Concatenate two images or stacks. */
-	public ImagePlus concatenate(ImagePlus imp1, ImagePlus imp2, boolean keep) {
-		images = new ImagePlus[2];
-		images[0] = imp1;
-		images[1] = imp2;
-		return concatenate(images, keep);
+	public static ImagePlus run(ImagePlus img1, ImagePlus img2) {
+		ImagePlus[] images = new ImagePlus[2];
+		images[0]=img1; images[1]=img2;
+		return (new Concatenator()).concatenate(images, false);
 	}
-	
+
+	/** Concatenate three images or stacks. */
+	public static ImagePlus run(ImagePlus img1, ImagePlus img2, ImagePlus img3) {
+		ImagePlus[] images = new ImagePlus[3];
+		images[0]=img1; images[1]=img2;  images[2]=img3;
+		return (new Concatenator()).concatenate(images, false);
+	}
+
+	/** Concatenate four images or stacks. */
+	public static ImagePlus run(ImagePlus img1, ImagePlus img2, ImagePlus img3, ImagePlus img4) {
+		ImagePlus[] images = new ImagePlus[4];
+		images[0]=img1; images[1]=img2;  images[2]=img3; images[2]=img4;
+		return (new Concatenator()).concatenate(images, false);
+	}
+
+	/** Concatenate five images or stacks. */
+	public static ImagePlus run(ImagePlus img1, ImagePlus img2, ImagePlus img3, ImagePlus img4, ImagePlus img5) {
+		ImagePlus[] images = new ImagePlus[5];
+		images[0]=img1; images[1]=img2;  images[2]=img3; images[2]=img4; images[5]=img5;
+		return (new Concatenator()).concatenate(images, false);
+	}
+
+	/*
+	// Why does this not work with Java 6?
+	public static ImagePlus run(ImagePlus... args) {
+		return (new Concatenator()).concatenate(args, false);
+	}
+	*/
+
 	/** Concatenate two or more images or stacks. */
 	public ImagePlus concatenate(ImagePlus[] ims, boolean keepIms) {
 		images = ims;
@@ -86,6 +116,14 @@ public class Concatenator implements PlugIn, ItemListener{
 		return newImp;
 	}
 	
+	/** Concatenate two images or stacks. */
+	public ImagePlus concatenate(ImagePlus imp1, ImagePlus imp2, boolean keep) {
+		images = new ImagePlus[2];
+		images[0] = imp1;
+		images[1] = imp2;
+		return concatenate(images, keep);
+	}
+	
 	ImagePlus createHypervol() {
 		boolean firstImage = true;
 		boolean duplicated;
@@ -115,7 +153,10 @@ public class Concatenator implements PlugIn, ItemListener{
 				}
 				
 				// Safety Checks
-				if (currentImp.getNSlices() != stackSize && im4D) {
+				boolean unequalSizes = currentImp.getNSlices()!=stackSize;
+				if (unequalSizes && !showingDialog)
+					im4D = false;
+				if (unequalSizes && im4D) {
 					IJ.error(pluginName, "Cannot create 4D image because stack sizes are not equal.");
 					return null;
 				}
@@ -148,6 +189,12 @@ public class Concatenator implements PlugIn, ItemListener{
 			imp.setDimensions(1, stackSize, imp.getStackSize()/stackSize);
 			imp.setOpenAsHyperStack(true);
 		}
+		if (Recorder.scriptMode()) {
+			String args = "imp1";
+			for (int i=1; i<images.length; i++)
+				args += ", imp"+(i+1);
+			Recorder.recordCall("imp"+(images.length+1)+" = Concatenator.run("+args+");");
+		}
 		return imp;
 	}
 	
@@ -263,6 +310,7 @@ public class Concatenator implements PlugIn, ItemListener{
 		batch = Interpreter.isBatchMode();
 		macro = macro || (IJ.isMacro()&&Macro.getOptions()!=null);
 		im4D = Menus.commandInUse("Stack to Image5D") && ! batch;
+		showingDialog = Macro.getOptions()==null;
 		if (macro) {
 			String options = Macro.getOptions();
 			if (options.contains("stack1")&&options.contains("stack2"))
@@ -405,6 +453,7 @@ public class Concatenator implements PlugIn, ItemListener{
 	
 	public void setIm5D(boolean bool) {
 		im4D_option = bool;
+		im4D = bool;
 	}
 	
 	private void findMaxDimensions(ImagePlus[] images) {
diff --git a/ij/plugin/ContrastEnhancer.java b/ij/plugin/ContrastEnhancer.java
index b44bf8b..3f32522 100644
--- a/ij/plugin/ContrastEnhancer.java
+++ b/ij/plugin/ContrastEnhancer.java
@@ -291,7 +291,7 @@ public class ContrastEnhancer implements PlugIn, Measurements {
 		if (imp.getBitDepth()==16 && processStack && imp.getStackSize()>1) {
 			ImageStack stack = imp.getStack();
 			ImageProcessor ip = stack.getProcessor(stack.getSize()/2);
-			ImageStatistics stats = ip.getStatistics();
+			ImageStatistics stats = ip.getStats();
 			imp.getProcessor().setMinAndMax(stats.min, stats.max);
 		} else
 			imp.getProcessor().resetMinAndMax();
diff --git a/ij/plugin/Coordinates.java b/ij/plugin/Coordinates.java
new file mode 100644
index 0000000..5d3e3da
--- /dev/null
+++ b/ij/plugin/Coordinates.java
@@ -0,0 +1,124 @@
+package ij.plugin;
+import ij.*;
+import ij.gui.*;
+import ij.measure.Calibration;
+import java.awt.AWTEvent;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * The plugin implements the Image/Adjust/Coordinates command. It allows
+ * the user to set the corner coordinates of the selection bounds or the full image.
+ * This modifies the image scale (pixelWidth, pixelHeight) and the xOrigin, yOrigin.
+ * If a single point is selected, the coordinates of the point can be specified, which only
+ * sets the xOrigin and yOrigin.
+ * The units for x and y can be also selected.
+ * 2016-08-30 Michael Schmid
+ */
+ 
+public class Coordinates implements PlugIn, DialogListener {
+
+	private static final String help = "<html>"
+	+"<h1>Image>Adjust>Coordinates</h1>"
+	+"<font size=+1>"
+	+"This command allows the user to set the corner coordinates of<br>the selection bounds "
+	+"or the full image. This modifies the image<br>scale (<i>pixelWidth</i>, <i>pixelHeight</i>) and <i>xOrigin</i> and <i>yOrigin</i>. "
+	+"If a<br>single point is selected, the coordinates of the point can be<br>specified, which only "
+	+"sets <i>xOrigin</i> and <i>yOrigin</i>. The units for X<br>and Y can be also selected.<br> "
+	+"</font>";
+
+	private final static String SAME_AS_X = "<same as x unit>";
+	private final static int IMAGE = 0, ROI_BOUNDS = 1, POINT = 2;	//mode: coordinates of what to specify
+	private int mode = IMAGE;
+
+
+	public void run(String arg) {
+		ImagePlus imp = IJ.getImage();
+		int imageHeight = imp.getHeight();
+		Calibration cal = imp.getCalibration();
+		Roi roi = imp.getRoi();
+		Rectangle2D.Double bounds = null;
+		if (roi != null) {
+			bounds = roi.getFloatBounds();
+			if (bounds.width==0 && bounds.height==0)
+				mode = POINT;
+			else
+				mode = ROI_BOUNDS;
+		} else {	//no Roi, use image bounds
+			bounds = new Rectangle2D.Double(0, 0, imp.getWidth(), imp.getHeight());
+		}
+		String title = (mode==IMAGE ? "Image" : "Selection") +" Coordinates";
+		if (mode == POINT)
+			title = "Point Coordinates";
+		GenericDialog gd = new GenericDialog(title);
+		if (mode == POINT) {
+			gd.addNumericField("X:", cal.getX(bounds.x), 2, 8, "");
+			gd.addNumericField("Y:", cal.getY(bounds.y, imageHeight), 2, 8, "");
+		} else {
+			gd.addNumericField("Left:", cal.getX(bounds.x), 2, 8, "");
+			gd.addNumericField("Right:", cal.getX(bounds.x+bounds.width), 2, 8, "");
+			gd.addNumericField("Top:", cal.getY(bounds.y, imageHeight), 2, 8, "");
+			gd.addNumericField("Bottom:", cal.getY(bounds.y+bounds.height, imageHeight), 2, 8, "");
+		}
+		String xUnit = cal.getUnit();
+		String yUnit = cal.getYUnit();
+		gd.addStringField("X_unit:", xUnit, 18);
+		gd.addStringField("Y_unit:", yUnit.equals(xUnit) ? SAME_AS_X : yUnit, 18);
+		gd.addHelp(help);
+		gd.addDialogListener(this);
+		gd.showDialog();
+		if (gd.wasCanceled())
+			return;
+		if (mode == POINT) {
+			double x = gd.getNextNumber();
+			double y = gd.getNextNumber();
+			if (gd.invalidNumber()) {
+				IJ.error("Invalid number");
+				return;
+			}
+			cal.xOrigin = coordinate2offset(x, bounds.x, cal.pixelWidth);
+			cal.yOrigin = coordinate2offset(y, bounds.y, cal.getInvertY() ? -cal.pixelHeight : cal.pixelHeight);
+		} else {
+			double xl = gd.getNextNumber();
+			double xr = gd.getNextNumber();
+			double yt = gd.getNextNumber();
+			double yb = gd.getNextNumber();
+			if (gd.invalidNumber()) {
+				IJ.error("Invalid number");
+				return;
+			}
+			cal.pixelWidth = (xr-xl)/bounds.width;
+			cal.pixelHeight = (yb-yt)/bounds.height;
+			cal.xOrigin = coordinate2offset(xl, bounds.x, cal.pixelWidth);
+			cal.yOrigin = coordinate2offset(yt, bounds.y, cal.pixelHeight);
+			cal.setInvertY(cal.pixelHeight < 0);
+			if (cal.pixelHeight < 0)
+				cal.pixelHeight = -cal.pixelHeight;
+		}
+		cal.setXUnit(gd.getNextString());
+		yUnit = gd.getNextString();
+		cal.setYUnit((yUnit.equals("") || yUnit.equals(SAME_AS_X)) ? null : yUnit);
+		ImageWindow win = imp.getWindow();
+		imp.repaintWindow();
+	}
+
+	// In interactive mode, disable 'ok' in case of input errors (bad numbers, zero range or inverted x)
+	public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
+		if (mode == POINT) {
+			gd.getNextNumber();
+			gd.getNextNumber();
+			return (!gd.invalidNumber());
+		} else {
+			double xl = gd.getNextNumber();
+			double xr = gd.getNextNumber();
+			double yt = gd.getNextNumber();
+			double yb = gd.getNextNumber();
+			return (!gd.invalidNumber() && xr>xl && yt!=yb);
+		}
+	}
+
+	// Calculates pixel offset from scaled coordinates of a point with given pixel position
+	private double coordinate2offset(double coordinate, double pixelPos, double pixelSize) {
+		return	pixelPos - coordinate/pixelSize;
+	}
+
+}
diff --git a/ij/plugin/DICOM.java b/ij/plugin/DICOM.java
index b1c79de..611e519 100644
--- a/ij/plugin/DICOM.java
+++ b/ij/plugin/DICOM.java
@@ -110,7 +110,7 @@ public class DICOM extends ImagePlus implements PlugIn {
 		}
 		if (fi!=null && fi.width>0 && fi.height>0 && fi.offset>0) {
 			FileOpener fo = new FileOpener(fi);
-			ImagePlus imp = fo.open(false);
+			ImagePlus imp = fo.openImage();
 			ImageProcessor ip = imp.getProcessor();
 			if (Prefs.openDicomsAsFloat) {
 				ip = ip.convertToFloat();
@@ -325,6 +325,15 @@ class DicomDecoder {
 		else
 			return ((b0 << 8) + b1);
 	}
+	
+	int getSShort() throws IOException {
+		short b0 = (short)getByte();
+		short b1 = (short)getByte();
+		if (littleEndian)
+			return ((b1 << 8) + b0);
+		else
+			return ((b0 << 8) + b1);
+	}
   
 	final int getInt() throws IOException {
 		int b0 = getByte();
@@ -336,6 +345,17 @@ class DicomDecoder {
 		else
 			return ((b0<<24) + (b1<<16) + (b2<<8) + b3);
 	}
+	
+	long getUInt() throws IOException {
+		long b0 = getByte();
+		long b1 = getByte();
+		long b2 = getByte();
+		long b3 = getByte();
+		if (littleEndian)
+			return ((b3<<24) + (b2<<16) + (b1<<8) + b0);
+		else
+			return ((b0<<24) + (b1<<16) + (b2<<8) + b3);
+	}
 
 	double getDouble() throws IOException {
 		int b0 = getByte();
@@ -793,6 +813,45 @@ class DicomDecoder {
 					value = sb.toString();
 				}
 				break;
+			case SS:
+				if (elementLength==2)
+					value = Integer.toString(getSShort());
+				else {
+					int n = elementLength/2;
+					StringBuilder sb = new StringBuilder();
+					for (int i=0; i<n; i++) {
+						sb.append(Integer.toString(getSShort()));
+						sb.append(" ");
+					}
+					value = sb.toString();
+				}
+				break;
+			case UL:
+				if (elementLength==4)
+					value = Long.toString(getUInt());
+				else {
+					int n = elementLength/4;
+					StringBuilder sb = new StringBuilder();
+					for (int i=0; i<n; i++) {
+						sb.append(Long.toString(getUInt()));
+						sb.append(" ");
+					}
+					value = sb.toString();
+				}
+				break;
+			case SL:
+				if (elementLength==4)
+					value = Long.toString(getInt());
+				else {
+					int n = elementLength/4;
+					StringBuilder sb = new StringBuilder();
+					for (int i=0; i<n; i++) {
+						sb.append(Long.toString(getInt()));
+						sb.append(" ");
+					}
+					value = sb.toString();
+				}
+				break;
 			case IMPLICIT_VR:
 				value = getString(elementLength);
 				if (elementLength>44) value=null;
diff --git a/ij/plugin/Duplicator.java b/ij/plugin/Duplicator.java
index 12f811e..2fd327b 100644
--- a/ij/plugin/Duplicator.java
+++ b/ij/plugin/Duplicator.java
@@ -18,39 +18,45 @@ import ij.measure.Calibration;
    img2.show();
 </pre>
 */
-public class Duplicator implements PlugIn, TextListener {
-	private static boolean duplicateStack;
-	private boolean duplicateSubstack;
+public class Duplicator implements PlugIn, TextListener, ItemListener {
+	private static boolean staticDuplicateStack;
+	private boolean duplicateStack;
 	private int first, last;
 	private Checkbox checkbox;
-	private TextField rangeField;
+	private TextField titleField, rangeField;
 	private TextField[] rangeFields;
 	private int firstC, lastC, firstZ, lastZ, firstT, lastT;
-	private boolean isCommand;
+	private String defaultTitle;
+	private String sliceLabel;
+	private ImagePlus imp;
+	private boolean legacyMacro;
+	private boolean titleChanged;
+	private GenericDialog gd;
 
 	public void run(String arg) {
-		isCommand = true;
-		ImagePlus imp = IJ.getImage();
+		imp = IJ.getImage();
 		int stackSize = imp.getStackSize();
 		String title = imp.getTitle();
 		String newTitle = WindowManager.getUniqueName(title);
+		defaultTitle = newTitle;
+		duplicateStack = staticDuplicateStack && !IJ.isMacro();
 		if (!IJ.altKeyDown()||stackSize>1) {
 			if (imp.isHyperStack() || imp.isComposite()) {
 				duplicateHyperstack(imp, newTitle);
 				return;
 			} else
-				newTitle = showDialog(imp, "Duplicate...", "Title: ", newTitle);
+				newTitle = showDialog(imp, "Duplicate...", "Title: ");
 		}
 		if (newTitle==null)
 			return;
 		ImagePlus imp2;
 		Roi roi = imp.getRoi();
-		if (duplicateSubstack && (first>1||last<stackSize))
+		if (duplicateStack && (first>1||last<stackSize))
 			imp2 = run(imp, first, last);
 		else if (duplicateStack || imp.getStackSize()==1)
 			imp2 = run(imp);
 		else
-			imp2 = duplicateImage(imp);
+			imp2 = crop(imp);
 		Calibration cal = imp2.getCalibration();
 		if (roi!=null && (cal.xOrigin!=0.0||cal.yOrigin!=0.0)) {
 			cal.xOrigin -= roi.getBounds().x;
@@ -65,15 +71,14 @@ public class Duplicator implements PlugIn, TextListener {
 		imp2.show();
 		if (stackSize>1 && imp2.getStackSize()==stackSize)
 			imp2.setSlice(imp.getCurrentSlice());
-
 	}
                 
-	/** Returns a copy of the image, stack or hyperstack contained in the specified ImagePlus. */
+	/** Returns a copy of the image, stack or hyperstack contained in the specified ImagePlus.
+	* @see ij.ImagePlus#duplicate
+	*/
 	public ImagePlus run(ImagePlus imp) {
-   		if (Recorder.record&&isCommand)
-   			Recorder.recordCall("imp = new Duplicator().run(imp);");
 		if (imp.getStackSize()==1)
-			return duplicateImage(imp);
+			return crop(imp);
 		Rectangle rect = null;
 		Roi roi = imp.getRoi();
 		Roi roi2 = cropRoi(imp, roi);
@@ -108,10 +113,15 @@ public class Duplicator implements PlugIn, TextListener {
 		Overlay overlay = imp.getOverlay();
 		if (overlay!=null && !imp.getHideOverlay())
 			imp2.setOverlay(overlay.crop(rect));
+   		if (Recorder.record)
+   			Recorder.recordCall("imp2 = imp.duplicate();");
 		return imp2;
 	}
 	
-	ImagePlus duplicateImage(ImagePlus imp) {
+	/** Returns a copy the current stack image, cropped if there is a selection.
+	* @see ij.ImagePlus#crop
+	*/
+	public ImagePlus crop(ImagePlus imp) {
 		ImageProcessor ip = imp.getProcessor();
 		ImageProcessor ip2 = ip.crop();
 		ImagePlus imp2 = imp.createImagePlus();
@@ -136,6 +146,12 @@ public class Duplicator implements PlugIn, TextListener {
  				overlay2.crop(imp.getCurrentSlice(), imp.getCurrentSlice());
  			imp2.setOverlay(overlay2);
  		}
+   		if (Recorder.record) {
+   			if (imp.getStackSize()==1)
+   				Recorder.recordCall("imp2 = imp.duplicate();");
+   			else
+   				Recorder.recordCall("imp2 = imp.crop();");
+   		}
 		return imp2;
 	}
 	
@@ -174,8 +190,8 @@ public class Duplicator implements PlugIn, TextListener {
 			overlay2.crop(firstSlice, lastSlice);
 			imp2.setOverlay(overlay2);
 		}
-   		if (Recorder.record&&isCommand)
-   			Recorder.recordCall("imp = new Duplicator().run(imp, "+firstSlice+", "+lastSlice+");");
+   		if (Recorder.record)
+   			Recorder.recordCall("imp2 = new Duplicator().run(imp, "+firstSlice+", "+lastSlice+");");
 		return imp2;
 	}
 
@@ -232,30 +248,36 @@ public class Duplicator implements PlugIn, TextListener {
 			overlay2.crop(firstC, lastC, firstZ, lastZ, firstT, lastT);
 			imp2.setOverlay(overlay2);
 		}
-   		if (Recorder.record&&isCommand)
-   			Recorder.recordCall("imp = new Duplicator().run(imp, "+firstC+", "+lastC+", "+firstZ+", "+lastZ+", "+firstT+", "+lastT+");");
+   		if (Recorder.record)
+   			Recorder.recordCall("imp2 = new Duplicator().run(imp, "+firstC+", "+lastC+", "+firstZ+", "+lastZ+", "+firstT+", "+lastT+");");
 		return imp2;
 	}
 
-	String showDialog(ImagePlus imp, String title, String prompt, String defaultString) {
+	String showDialog(ImagePlus imp, String dialogTitle, String prompt) {
 		int stackSize = imp.getStackSize();
-		duplicateSubstack = stackSize>1 && (stackSize==imp.getNSlices()||stackSize==imp.getNFrames());
-		GenericDialog gd = new GenericDialog(title);
-		gd.addStringField(prompt, defaultString, duplicateSubstack?15:20);
+		String options = Macro.getOptions();
+		boolean isMacro = options!=null;
+		duplicateStack = stackSize>1 && duplicateStack && !isMacro;
+		legacyMacro = options!=null && (options.contains("duplicate")||!options.contains("use"));
+		String title = getNewTitle();
+		if (title==null) title=defaultTitle;
+		GenericDialog gd = new GenericDialog(dialogTitle);
+		this.gd = gd;
+		gd.addStringField(prompt, title, 15);
 		if (stackSize>1) {
-			boolean duplicate = duplicateStack && !IJ.isMacro();
-			String msg = duplicateSubstack?"Duplicate stack":"Duplicate entire stack";
-			gd.addCheckbox(msg, duplicate||imp.isComposite());
-			if (duplicateSubstack) {
-				gd.setInsets(2, 30, 3);
-				gd.addStringField("Range:", "1-"+stackSize);
+			gd.addCheckbox("Duplicate stack", duplicateStack);
+			gd.setInsets(2, 30, 3);
+			gd.addStringField("Range:", "1-"+stackSize);
+			if (!isMacro) {
+				checkbox = (Checkbox)(gd.getCheckboxes().elementAt(0));
+				checkbox.addItemListener(this);
 				Vector v = gd.getStringFields();
+				titleField = (TextField)v.elementAt(0);
 				rangeField = (TextField)v.elementAt(1);
+				titleField.addTextListener(this);
 				rangeField.addTextListener(this);
-				checkbox = (Checkbox)(gd.getCheckboxes().elementAt(0));
 			}
-		} else
-			duplicateStack = false;
+		}
 		gd.setSmartRecording(true);
 		gd.showDialog();
 		if (gd.wasCanceled())
@@ -263,7 +285,7 @@ public class Duplicator implements PlugIn, TextListener {
 		title = gd.getNextString();
 		if (stackSize>1) {
 			duplicateStack = gd.getNextBoolean();
-			if (duplicateStack && duplicateSubstack) {
+			if (duplicateStack) {
 				String[] range = Tools.split(gd.getNextString(), " -");
 				double d1 = gd.parseDouble(range[0]);
 				double d2 = range.length==2?gd.parseDouble(range[1]):Double.NaN;
@@ -277,6 +299,27 @@ public class Duplicator implements PlugIn, TextListener {
 				last = stackSize;
 			}
 		}
+		if (!isMacro)
+			staticDuplicateStack = duplicateStack;
+		if (Recorder.record && titleField!=null && titleField.getText().equals(sliceLabel))
+			Recorder.recordOption("use");
+		return title;
+	}
+	
+	private String getNewTitle() {
+		if (titleChanged)
+			return null;
+		String title = defaultTitle;
+		if (imp.getStackSize()>1 && !duplicateStack && !legacyMacro && (checkbox==null||!checkbox.getState())) {
+			ImageStack stack = imp.getStack();
+			String label = stack.getShortSliceLabel(imp.getCurrentSlice());
+			if (label!=null && label.length()==0)
+				label = null;
+			if (label!=null) {
+				title = label;
+				sliceLabel = label;
+			}
+		}
 		return title;
 	}
 	
@@ -320,10 +363,12 @@ public class Duplicator implements PlugIn, TextListener {
 		int nSlices = imp.getNSlices();
 		int nFrames = imp.getNFrames();
 		boolean composite = imp.isComposite() && nChannels==imp.getStackSize();
+		String options = Macro.getOptions();
+		boolean isMacro = options!=null;
 		GenericDialog gd = new GenericDialog("Duplicate");
 		gd.addStringField("Title:", newTitle, 15);
 		gd.setInsets(12, 20, 8);
-		gd.addCheckbox("Duplicate hyperstack", (duplicateStack&&!IJ.isMacro())||composite);
+		gd.addCheckbox("Duplicate hyperstack", (duplicateStack&&!isMacro)||composite);
 		int nRangeFields = 0;
 		if (nChannels>1) {
 			gd.setInsets(2, 30, 3);
@@ -340,13 +385,16 @@ public class Duplicator implements PlugIn, TextListener {
 			gd.addStringField("Frames (t):", "1-"+nFrames);
 			nRangeFields++;
 		}
-		Vector v = gd.getStringFields();
-		rangeFields = new TextField[3];
-		for (int i=0; i<nRangeFields; i++) {
-			rangeFields[i] = (TextField)v.elementAt(i+1);
-			rangeFields[i].addTextListener(this);
+		if (!isMacro) {
+			checkbox = (Checkbox)(gd.getCheckboxes().elementAt(0));
+			checkbox.addItemListener(this);
+			Vector v = gd.getStringFields();
+			rangeFields = new TextField[3];
+			for (int i=0; i<nRangeFields; i++) {
+				rangeFields[i] = (TextField)v.elementAt(i+1);
+				rangeFields[i].addTextListener(this);
+			}
 		}
-		checkbox = (Checkbox)(gd.getCheckboxes().elementAt(0));
 		gd.setSmartRecording(true);
 		gd.showDialog();
 		if (gd.wasCanceled())
@@ -386,6 +434,8 @@ public class Duplicator implements PlugIn, TextListener {
 			if (firstT>lastT) {firstT=1; lastT=nFrames;}
 		} else
 			firstT = lastT = 1;
+		if (!isMacro)
+			staticDuplicateStack = duplicateStack;
 		return newTitle;
 	}
 	
@@ -416,7 +466,24 @@ public class Duplicator implements PlugIn, TextListener {
 	}
 
 	public void textValueChanged(TextEvent e) {
-		checkbox.setState(true);
+		if (IJ.debugMode) IJ.log("Duplicator.textValueChanged: "+e);
+		if (e.getSource()==titleField) {
+			if (!titleField.getText().equals(getNewTitle()))
+				titleChanged = true;
+		} else
+			checkbox.setState(true);
 	}
 	
+	public void itemStateChanged(ItemEvent e) {
+		duplicateStack = checkbox.getState();
+		if (titleField!=null) {
+			String title = getNewTitle();
+			if (title!=null && !title.equals(titleField.getText())) {
+				titleField.setText(title);
+				if (gd!=null) gd.setDefaultString(0, title);
+			}
+		}
+	}
+
+	
 }
diff --git a/ij/plugin/FFT.java b/ij/plugin/FFT.java
index 56e57b9..dafc9ce 100644
--- a/ij/plugin/FFT.java
+++ b/ij/plugin/FFT.java
@@ -155,8 +155,10 @@ public class FFT implements  PlugIn, Measurements {
             fht.originalWidth = originalWidth;
             fht.originalHeight = originalHeight;
         }
-        fht.originalBitDepth = imp.getBitDepth();
-        fht.originalColorModel = ip.getColorModel();
+        int bitDepth = imp.getBitDepth();
+        fht.originalBitDepth = bitDepth;
+        if (bitDepth!=24)
+        	fht.originalColorModel = ip.getColorModel();
         return fht;
     }
     
diff --git a/ij/plugin/FITS_Reader.java b/ij/plugin/FITS_Reader.java
index c9af899..465a6f4 100644
--- a/ij/plugin/FITS_Reader.java
+++ b/ij/plugin/FITS_Reader.java
@@ -25,7 +25,7 @@ public class FITS_Reader extends ImagePlus implements PlugIn {
 		catch (IOException e) {}
 		if (fi!=null && fi.width>0 && fi.height>0 && fi.offset>0) {
 			FileOpener fo = new FileOpener(fi);
-			ImagePlus imp = fo.open(false);
+			ImagePlus imp = fo.openImage();
 			if(fi.nImages==1) {
 			  ImageProcessor ip = imp.getProcessor();			   
 			  ip.flipVertical(); // origin is at bottom left corner
diff --git a/ij/plugin/FileInfoVirtualStack.java b/ij/plugin/FileInfoVirtualStack.java
index 06726f3..fa634c0 100644
--- a/ij/plugin/FileInfoVirtualStack.java
+++ b/ij/plugin/FileInfoVirtualStack.java
@@ -102,7 +102,7 @@ public class FileInfoVirtualStack extends VirtualStack implements PlugIn {
 		}
 		nImages = info.length;
 		FileOpener fo = new FileOpener(info[0] );
-		ImagePlus imp = fo.open(false);
+		ImagePlus imp = fo.openImage();
 		if (nImages==1 && fi.fileType==FileInfo.RGB48)
 			return imp;
 		Properties props = fo.decodeDescriptionString(fi);
@@ -177,11 +177,11 @@ public class FileInfoVirtualStack extends VirtualStack implements PlugIn {
 		if (IJ.debugMode) {
 			long t0 = System.currentTimeMillis();
 			FileOpener fo = new FileOpener(info[n-1]);
-			imp = fo.open(false);
+			imp = fo.openImage();
 			IJ.log("FileInfoVirtualStack: "+n+", offset="+info[n-1].getOffset()+", "+(System.currentTimeMillis()-t0)+"ms");
 		} else {
 			FileOpener fo = new FileOpener(info[n-1]);
-			imp = fo.open(false);
+			imp = fo.openImage();
 		}
 		if (imp!=null)
 			return imp.getProcessor();
diff --git a/ij/plugin/FolderOpener.java b/ij/plugin/FolderOpener.java
index b7479df..e466fa1 100644
--- a/ij/plugin/FolderOpener.java
+++ b/ij/plugin/FolderOpener.java
@@ -33,8 +33,17 @@ public class FolderOpener implements PlugIn {
 	/** Opens the images in the specified directory as a stack. Displays
 		directory chooser and options dialogs if the argument is null. */
 	public static ImagePlus open(String path) {
+		return open(path, null);
+	}
+
+	/** Opens the images in the specified directory as a stack. Opens
+		the images as a virtual stack if the 'options' string contains
+		"virtual". Displays directory chooser and options dialogs if the
+		the 'path' argument is null. */
+	public static ImagePlus open(String path, String options) {
 		FolderOpener fo = new FolderOpener();
 		fo.saveImage = true;
+		fo.openAsVirtualStack = options!=null && options.contains("virtual");
 		fo.run(path);
 		return fo.image;
 	}
@@ -212,7 +221,7 @@ public class FolderOpener implements PlugIn {
 					if (info!=null)
 						label += "\n" + info;
 				}
-				if (imp.getCalibration().pixelWidth!=cal.pixelWidth)
+				if (Math.abs(imp.getCalibration().pixelWidth-cal.pixelWidth)>0.0000000001)
 					allSameCalibration = false;
 				ImageStack inputStack = imp.getStack();
 				Overlay overlay2 = imp.getOverlay();
@@ -304,12 +313,6 @@ public class FolderOpener implements PlugIn {
 				}
 				if (cal.pixelWidth!=1.0 && cal.pixelDepth==1.0)
 					cal.pixelDepth = cal.pixelWidth;
-				if (cal.pixelWidth<=0.0001 && cal.getUnit().equals("cm")) {
-					cal.pixelWidth *= 10000.0;
-					cal.pixelHeight *= 10000.0;
-					cal.pixelDepth *= 10000.0;
-					cal.setUnit("um");
-				}
 				imp2.setCalibration(cal);
 			}
 			if (info1!=null && info1.lastIndexOf("7FE0,0010")>0) {
diff --git a/ij/plugin/GelAnalyzer.java b/ij/plugin/GelAnalyzer.java
index 0f8c09e..c95bc63 100644
--- a/ij/plugin/GelAnalyzer.java
+++ b/ij/plugin/GelAnalyzer.java
@@ -25,7 +25,7 @@ public class GelAnalyzer implements PlugIn {
 	static int[] x = new int[MAX_LANES+1];
 	static PlotsCanvas plotsCanvas;
 	static ImageProcessor ipLanes;
-	static ImagePlus  gel;
+	static ImagePlus gel;
 	static int plotHeight;
 	static int options = (int)Prefs.get(OPTIONS, PERCENT+INVERT);
 	static boolean uncalibratedOD = (options&OD)!=0;
@@ -243,7 +243,8 @@ public class GelAnalyzer implements PlugIn {
 	}
 	
 	void updateRoiList(Rectangle rect) {
-			if (gel==null) return;
+			if (gel==null)
+				return;
 			if (overlay==null) {
 				overlay = new Overlay();
 				overlay.drawLabels(true);
@@ -465,6 +466,10 @@ public class GelAnalyzer implements PlugIn {
 		IJ.showMessage("Gel Analyzer", msg);
 	}
 
+	public static ImagePlus getGelImage() {
+		return gel;
+	}
+
 }
 
 
@@ -528,7 +533,7 @@ class PlotsCanvas extends ImageCanvas {
 			counter = 0;
 			return;
 		}
-		ImageStatistics s = imp.getStatistics();
+		ImageStatistics stats = imp.getStatistics();
 		if (counter==0) {
 			rt = ResultsTable.getResultsTable();
 			rt.reset();
@@ -536,10 +541,10 @@ class PlotsCanvas extends ImageCanvas {
 		//IJ.setColumnHeadings(" \tArea");
 		double perimeter = roi.getLength();
 		String error = "";
-		double circularity = 4.0*Math.PI*(s.pixelCount/(perimeter*perimeter));
+		double circularity = 4.0*Math.PI*(stats.pixelCount/(perimeter*perimeter));
 		if (circularity<0.025)
 			error = " (error?)";
-		double area = s.pixelCount+perimeter/2.0; // add perimeter/2 to account area under border
+		double area = stats.pixelCount+perimeter/2.0; // add perimeter/2 to account area under border
 		Calibration cal = imp.getCalibration();
 		area = area*cal.pixelWidth*cal.pixelHeight;
 		rect[counter] = roi.getBounds();
@@ -642,6 +647,6 @@ class PlotsCanvas extends ImageCanvas {
 					 +IJ.d2s(((m-a)/m)*100, 4));
 		}
 	}
-
+	
 }
 
diff --git a/ij/plugin/Hotkeys.java b/ij/plugin/Hotkeys.java
index 64c4301..f0c3824 100644
--- a/ij/plugin/Hotkeys.java
+++ b/ij/plugin/Hotkeys.java
@@ -59,8 +59,14 @@ public class Hotkeys implements PlugIn {
 					}
 				}
 			}
-		} else
+		} else {
 			command = gd.getNextChoice();
+			Hashtable cmds = Menus.getCommands();
+			if (command.contains("[") && cmds!=null && cmds.get(command)==null) {
+				if (cmds.get(command+"]")!=null)
+					command += "]";
+			}
+		}
 		String plugin = "ij.plugin.Hotkeys("+"\""+command+"\")";
 		int err = Menus.installPlugin(plugin,Menus.SHORTCUTS_MENU,"*"+command,shortcut,IJ.getInstance());
 		switch (err) {
diff --git a/ij/plugin/ImageCalculator.java b/ij/plugin/ImageCalculator.java
index 65f7138..8ad4f98 100644
--- a/ij/plugin/ImageCalculator.java
+++ b/ij/plugin/ImageCalculator.java
@@ -43,7 +43,7 @@ public class ImageCalculator implements PlugIn {
 			else
 				titles[i] = "";
 		}
-		GenericDialog gd = new GenericDialog("Image Calculator", IJ.getInstance());
+		GenericDialog gd = new GenericDialog("Image Calculator");
 		String defaultItem;
 		if (title1.equals(""))
 			defaultItem = titles[0];
diff --git a/ij/plugin/ImageInfo.java b/ij/plugin/ImageInfo.java
index b695941..106579a 100644
--- a/ij/plugin/ImageInfo.java
+++ b/ij/plugin/ImageInfo.java
@@ -40,8 +40,10 @@ public class ImageInfo implements PlugIn {
 		s += "ImageJ home: "+IJ.getDir("imagej")+"\n";
 		s += "Java home: "+System.getProperty("java.home")+"\n";
 		s += "Screen size: "+screen.width+"x"+screen.height+"\n";
-		if (IJ.isMacOSX())
-			s += "SetMenuBarCount: "+Menus.setMenuBarCount+"\n";
+		if (IJ.isMacOSX()) {
+			String time = " ("+ImageWindow.setMenuBarTime+"ms)";
+			s += "SetMenuBarCount: "+Menus.setMenuBarCount+time+"\n";
+		}
 		new TextWindow("Info", s, 600, 300);
 	}
 
@@ -241,6 +243,16 @@ public class ImageInfo implements PlugIn {
 				String mode = ((CompositeImage)imp).getModeAsString();
 				s += "  Composite mode: \"" + mode + "\"\n";
 			}
+			if (stack.isVirtual()) {
+				String stackType = "virtual";
+				if (stack instanceof AVI_Reader)
+					stackType += " (AVI Reader)";
+				if (stack instanceof FileInfoVirtualStack)
+					stackType += " (FileInfoVirtualStack)";
+				if (stack instanceof ListVirtualStack)
+					stackType += " (ListVirtualStack)";
+				s += "Stack type: " + stackType+ "\n";
+			}
 		}
 		
 		if (imp.isLocked())
@@ -302,8 +314,10 @@ public class ImageInfo implements PlugIn {
 			Dimension screen = IJ.getScreenSize();
 			s += "Screen location: "+loc.x+","+loc.y+" ("+screen.width+"x"+screen.height+")\n";
 		}
-		if (IJ.isMacOSX())
-			s += "SetMenuBarCount: "+Menus.setMenuBarCount+"\n";
+		if (IJ.isMacOSX()) {
+			String time = " ("+ImageWindow.setMenuBarTime+"ms)";
+			s += "SetMenuBarCount: "+Menus.setMenuBarCount+time+"\n";
+		}
 		
 		String zOrigin = stackSize>1||cal.zOrigin!=0.0?","+d2s(cal.zOrigin):"";
 		String origin = d2s(cal.xOrigin)+","+d2s(cal.yOrigin)+zOrigin;
diff --git a/ij/plugin/ImageJ_Updater.java b/ij/plugin/ImageJ_Updater.java
index 27786ef..28a3749 100644
--- a/ij/plugin/ImageJ_Updater.java
+++ b/ij/plugin/ImageJ_Updater.java
@@ -40,6 +40,10 @@ public class ImageJ_Updater implements PlugIn {
 			return;
 		}
 		String[] list = openUrlAsList(URL+"/jars/list.txt");
+		if (list==null || list.length==0) {
+			error("Error opening "+URL+"/jars/list.txt");
+			return;
+		}
 		int count = list.length + 2;
 		String[] versions = new String[count];
 		String[] urls = new String[count];
diff --git a/ij/plugin/MontageMaker.java b/ij/plugin/MontageMaker.java
index ab1e81f..859aa25 100644
--- a/ij/plugin/MontageMaker.java
+++ b/ij/plugin/MontageMaker.java
@@ -87,19 +87,19 @@ public class MontageMaker implements PlugIn {
 			}
 			saveStackSize = nSlices;
 			
-			GenericDialog gd = new GenericDialog("Make Montage", IJ.getInstance());
+			GenericDialog gd = new GenericDialog("Make Montage");
 			gd.addNumericField("Columns:", columns, 0);
 			gd.addNumericField("Rows:", rows, 0);
-			gd.addNumericField("Scale Factor:", scale, 2);
+			gd.addNumericField("Scale factor:", scale, 2);
 			if (!hyperstack) {
-				gd.addNumericField("First Slice:", first, 0);
-				gd.addNumericField("Last Slice:", last, 0);
+				gd.addNumericField("First slice:", first, 0);
+				gd.addNumericField("Last slice:", last, 0);
 			}
 			gd.addNumericField("Increment:", inc, 0);
-			gd.addNumericField("Border Width:", borderWidth, 0);
-			gd.addNumericField("Font Size:", fontSize, 0);
-			gd.addCheckbox("Label Slices", label);
-			gd.addCheckbox("Use Foreground Color", useForegroundColor);
+			gd.addNumericField("Border width:", borderWidth, 0);
+			gd.addNumericField("Font size:", fontSize, 0);
+			gd.addCheckbox("Label slices", label);
+			gd.addCheckbox("Use foreground color", useForegroundColor);
 			gd.showDialog();
 			if (gd.wasCanceled())
 				return;
@@ -155,10 +155,10 @@ public class MontageMaker implements PlugIn {
 		int nSlices = imp.getStackSize();
 		int width = (int)(stackWidth*scale);
 		int height = (int)(stackHeight*scale);
-		int montageWidth = width*columns;
-		int montageHeight = height*rows;
+		int montageWidth = width*columns + borderWidth*(columns-1);
+		int montageHeight = height*rows + borderWidth*(rows-1);
 		ImageProcessor ip = imp.getProcessor();
-		ImageProcessor montage = ip.createProcessor(montageWidth+borderWidth/2, montageHeight+borderWidth/2);
+		ImageProcessor montage = ip.createProcessor(montageWidth, montageHeight);
 		ImagePlus imp2 = new ImagePlus("Montage", montage);
 		imp2.setCalibration(imp.getCalibration());
 		montage = imp2.getProcessor();
@@ -201,12 +201,12 @@ public class MontageMaker implements PlugIn {
 			}
 			montage.insert(aSlice, x, y);
 			String label = stack.getShortSliceLabel(slice);
-			if (borderWidth>0) drawBorder(montage, x, y, width, height, borderWidth);
-			if (labels) drawLabel(montage, slice, label, x, y, width, height, borderWidth);
-			x += width;
+			if (labels)
+				drawLabel(montage, slice, label, x, y, width, height, borderWidth);
+			x += width + borderWidth;
 			if (x>=montageWidth) {
 				x = 0;
-				y += height;
+				y += height + borderWidth;;
 				if (y>=montageHeight)
 					break;
 			}
@@ -214,8 +214,14 @@ public class MontageMaker implements PlugIn {
 			slice += inc;
 		}
 		if (borderWidth>0) {
-			int w2 = borderWidth/2;
-			drawBorder(montage, w2, w2, montageWidth-w2, montageHeight-w2, borderWidth);
+			for (x=width; x<montageWidth; x+=width+borderWidth) {
+				montage.setRoi(x, 0, borderWidth, montageHeight);
+				montage.fill();
+			}
+			for (y=height; y<montageHeight; y+=height+borderWidth) {
+				montage.setRoi(0, y, montageWidth, borderWidth);
+				montage.fill();
+			}
 		}
 		IJ.showProgress(1.0);
 		Calibration cal = imp2.getCalibration();
@@ -246,15 +252,6 @@ public class MontageMaker implements PlugIn {
 		IJ.error("Make Montage", msg);
 	}
 	
-	void drawBorder(ImageProcessor montage, int x, int y, int width, int height, int borderWidth) {
-		montage.setLineWidth(borderWidth);
-		montage.moveTo(x, y);
-		montage.lineTo(x+width, y);
-		montage.lineTo(x+width, y+height);
-		montage.lineTo(x, y+height);
-		montage.lineTo(x, y);
-	}
-	
 	void drawLabel(ImageProcessor montage, int slice, String label, int x, int y, int width, int height, int borderWidth) {
 		if (label!=null && !label.equals("") && montage.getStringWidth(label)>=width) {
 			do {
diff --git a/ij/plugin/Options.java b/ij/plugin/Options.java
index ec18ebe..1e56656 100644
--- a/ij/plugin/Options.java
+++ b/ij/plugin/Options.java
@@ -29,7 +29,7 @@ public class Options implements PlugIn {
 	// Miscellaneous Options
 	void miscOptions() {
 		String key = IJ.isMacintosh()?"command":"control";
-		GenericDialog gd = new GenericDialog("Miscellaneous Options", IJ.getInstance());
+		GenericDialog gd = new GenericDialog("Miscellaneous Options");
 		gd.addStringField("Divide by zero value:", ""+FloatBlitter.divideByZeroValue, 10);
 		gd.addCheckbox("Use pointer cursor", Prefs.usePointerCursor);
 		gd.addCheckbox("Hide \"Process Stack?\" dialog", IJ.hideProcessStackDialog);
@@ -39,6 +39,8 @@ public class Options implements PlugIn {
 			gd.addCheckbox("Run single instance listener", Prefs.runSocketListener);
 		gd.addCheckbox("Enhanced line tool", Prefs.enhancedLineTool);
 		gd.addCheckbox("Reverse CZT order of \">\" and \"<\"", Prefs.reverseNextPreviousOrder);
+		if (IJ.isMacOSX())
+			gd.addCheckbox("Don't set Mac menu bar", !Prefs.setIJMenuBar);
 		gd.addCheckbox("Debug mode", IJ.debugMode);
 		gd.addHelp(IJ.URL+"/docs/menus/edit.html#misc");
 		gd.showDialog();
@@ -69,6 +71,8 @@ public class Options implements PlugIn {
 			Prefs.runSocketListener = gd.getNextBoolean();
 		Prefs.enhancedLineTool = gd.getNextBoolean();
 		Prefs.reverseNextPreviousOrder = gd.getNextBoolean();
+		if (IJ.isMacOSX())
+			Prefs.setIJMenuBar = !gd.getNextBoolean();
 		IJ.setDebugMode(gd.getNextBoolean());
 	}
 
diff --git a/ij/plugin/OverlayCommands.java b/ij/plugin/OverlayCommands.java
index c495518..4fc8a68 100644
--- a/ij/plugin/OverlayCommands.java
+++ b/ij/plugin/OverlayCommands.java
@@ -81,19 +81,7 @@ public class OverlayCommands implements PlugIn {
 			if (roi.getFillColor()==null)
 				roi.setFillColor(defaultRoi.getFillColor());
 		}
-		boolean setPos = defaultRoi.getPosition()!=0;
-		int stackSize = imp.getStackSize();
-		if (setPos && stackSize>1) {
-			if (imp.isHyperStack()||imp.isComposite()) {
-				boolean compositeMode = imp.isComposite() && ((CompositeImage)imp).getMode()==IJ.COMPOSITE;
-				int channel = !compositeMode||imp.getNChannels()==stackSize?imp.getChannel():0;
-				if (imp.getNSlices()>1)
-					roi.setPosition(channel, imp.getSlice(), 0);
-				else if (imp.getNFrames()>1)
-					roi.setPosition(channel, 0, imp.getFrame());
-			} else
-				roi.setPosition(imp.getCurrentSlice());
-		}
+		setPosition(imp, roi);
 		boolean points = roi instanceof PointRoi && ((PolygonRoi)roi).getNCoordinates()>1;
 		if (IJ.altKeyDown() || (IJ.macroRunning() && Macro.getOptions()!=null)) {
 			RoiProperties rp = new RoiProperties("Add to Overlay", roi);
@@ -110,7 +98,6 @@ public class OverlayCommands implements PlugIn {
 		if (overlay==null || newOverlay)
 			overlay = OverlayLabels.createOverlay();
 		overlay.add(roi);
-		defaultRoi.setPosition(setPos?1:0);
 		imp.setOverlay(overlay);
 		boolean brushRoi = roi.getType()==Roi.COMPOSITE && Toolbar.getToolId()==Toolbar.OVAL && Toolbar.getBrushSize()>0;
 		if (points || (roi instanceof ImageRoi) || (roi instanceof Arrow&&!Prefs.keepArrowSelections) || brushRoi)
@@ -199,13 +186,32 @@ public class OverlayCommands implements PlugIn {
 		if (createImageRoi)
 			imp.setRoi(roi);
 		else {
+			setPosition(imp, roi);
 			Overlay overlayList = imp.getOverlay();
-			if (overlayList==null) overlayList = new Overlay();
+			if (overlayList==null)
+				overlayList = new Overlay();
 			overlayList.add(roi);
 			imp.setOverlay(overlayList);
 			Undo.setup(Undo.OVERLAY_ADDITION, imp);
 		}
 	}
+	
+	private void setPosition(ImagePlus imp, Roi roi) {
+		boolean setPos = defaultRoi.getPosition()!=0;
+		int stackSize = imp.getStackSize();
+		if (setPos && stackSize>1) {
+			if (imp.isHyperStack()||imp.isComposite()) {
+				boolean compositeMode = imp.isComposite() && ((CompositeImage)imp).getMode()==IJ.COMPOSITE;
+				int channel = !compositeMode||imp.getNChannels()==stackSize?imp.getChannel():0;
+				if (imp.getNSlices()>1)
+					roi.setPosition(channel, imp.getSlice(), 0);
+				else if (imp.getNFrames()>1)
+					roi.setPosition(channel, 0, imp.getFrame());
+			} else
+				roi.setPosition(imp.getCurrentSlice());
+		}
+		//IJ.log(roi.getCPosition()+" "+roi.getZPosition()+" "+roi.getTPosition());
+	}
 
 	void hide() {
 		ImagePlus imp = IJ.getImage();
@@ -238,16 +244,14 @@ public class OverlayCommands implements PlugIn {
 
 	void flatten() {
 		ImagePlus imp = IJ.getImage();
-		if (imp.getStackSize()>1 || imp.getBitDepth()==24) {
-			Overlay overlay = imp.getOverlay();
-			Overlay roiManagerOverlay = null;
-			ImageCanvas ic = imp.getCanvas();
-			if (ic!=null)
-				roiManagerOverlay = ic.getShowAllList();
-			if (overlay==null && roiManagerOverlay==null && !imp.isComposite() && !(IJ.macroRunning()&&imp.getStackSize()==1)) {
-				IJ.error("Flatten", "Overlay or multi-channel image required");
-				return;
-			}
+		Overlay overlay = imp.getOverlay();
+		Overlay roiManagerOverlay = null;
+		ImageCanvas ic = imp.getCanvas();
+		if (ic!=null)
+			roiManagerOverlay = ic.getShowAllList();
+		if (imp.getBitDepth()==24 && overlay==null && imp.getRoi()==null && roiManagerOverlay==null && !imp.isComposite() && !IJ.macroRunning()) {
+			IJ.error("Flatten", "Overlay or selection required to flatten RGB image");
+			return;
 		}
 		int flags = IJ.setupDialog(imp, 0);
 		if (flags==PlugInFilter.DONE)
@@ -258,6 +262,10 @@ public class OverlayCommands implements PlugIn {
 				IJ.error("Flatten Stack", "Java 1.6 required to flatten a stack");
 				return;
 			}
+			if (overlay==null && roiManagerOverlay==null && !imp.isComposite()) {
+				IJ.error("Flatten", "Overlay or multi-channel image required");
+				return;
+			}
 			flattenStack(imp);
 			if (Recorder.record)
 				Recorder.recordCall("imp.flattenStack();");
@@ -299,20 +307,9 @@ public class OverlayCommands implements PlugIn {
 			IJ.error("Overlay required");
 			return;
 		}
-		RoiManager rm = RoiManager.getInstance();
-		if (rm==null) {
-			if (Macro.getOptions()!=null && Interpreter.isBatchMode())
-				rm = Interpreter.getBatchModeRoiManager();
-			if (rm==null) {
-				Frame frame = WindowManager.getFrame("ROI Manager");
-				if (frame==null)
-					IJ.run("ROI Manager...");
-				frame = WindowManager.getFrame("ROI Manager");
-				if (frame==null || !(frame instanceof RoiManager))
-					return;
-				rm = (RoiManager)frame;
-			}
-		}
+		RoiManager rm = RoiManager.getInstance2();
+		if (rm==null)
+			rm = new RoiManager();
 		if (overlay.size()>=4 && overlay.get(3).getPosition()!=0)
 			Prefs.showAllSliceOnly = true;
 		rm.runCommand("reset");
@@ -366,6 +363,8 @@ public class OverlayCommands implements PlugIn {
 	public static void listRois(Roi[] rois) {
 		ArrayList list = new ArrayList();
 		for (int i=0; i<rois.length; i++) {
+			if (rois[i]==null)
+				continue;
 			Rectangle r = rois[i].getBounds();
 			String color = Colors.colorToString(rois[i].getStrokeColor());
 			String fill = Colors.colorToString(rois[i].getFillColor());
diff --git a/ij/plugin/OverlayLabels.java b/ij/plugin/OverlayLabels.java
index 5202b14..cec0e82 100644
--- a/ij/plugin/OverlayLabels.java
+++ b/ij/plugin/OverlayLabels.java
@@ -3,6 +3,7 @@ import ij.*;
 import ij.process.*;
 import ij.gui.*;
 import ij.util.Tools;
+import ij.plugin.filter.Analyzer;
 import java.awt.*;
 import java.util.Vector;
 
@@ -84,12 +85,13 @@ public class OverlayLabels implements PlugIn, DialogListener {
 			|| drawBackgrounds!=drawBackgrounds2 || colorChanged || sizeChanged
 			|| bold!=bold2;
 		if (changes) {
-			if (showNames || colorChanged || sizeChanged) {
+			if ((showNames&&!showNames2) || colorChanged || sizeChanged) {
 				showLabels = true;
 				Vector checkboxes = gd.getCheckboxes();
 				((Checkbox)checkboxes.elementAt(0)).setState(true);
 			}
 			overlay.drawLabels(showLabels);
+			Analyzer.drawLabels(showLabels);
 			overlay.drawNames(showNames);
 			overlay.drawBackgrounds(drawBackgrounds);
 			Color color = Colors.getColor(colorName, Color.white);
diff --git a/ij/plugin/PointToolOptions.java b/ij/plugin/PointToolOptions.java
index ca6b071..8f8d52d 100644
--- a/ij/plugin/PointToolOptions.java
+++ b/ij/plugin/PointToolOptions.java
@@ -19,8 +19,8 @@ public class PointToolOptions implements PlugIn, DialogListener {
 	+"<font size=+1>"
 	+"<ul>"
 	+"<li> Alt-click, or control-click, on a point to delete it.<br>"
-	+"<li> Press 'y' (<i>Edit>Selection>Properties</i>) to display<br>the counts in a results table.<br>"
-	+"<li> Press 'm' (<i>Analyze>Measure</i>) to display the<br>point stack positions in the results table.<br>"
+	+"<li> Press 'alt+y' (<i>Edit>Selection>Properties</i> plus<br>alt key) to display the counts in a results table.<br>"
+	+"<li> Press 'm' (<i>Analyze>Measure</i>) to list the counter<br>and stack position associated with each point.<br>"
 	+"<li> Use <i>File>Save As>Tiff</i> or <i>File>Save As>Selection</i><br>to save the points and counts.<br>"
 	+"<li> Hold the shift key down and points will be<br>constrained to a horizontal or vertical line.<br>"
 	+"</ul>"
@@ -37,12 +37,14 @@ public class PointToolOptions implements PlugIn, DialogListener {
 		
 	void showDialog() {
 		String options = IJ.isMacro()?Macro.getOptions():null;
+		boolean legacyMacro = false;
 		if (options!=null) {
 			options = options.replace("selection=", "color=");
 			options = options.replace("marker=", "size=");
 			Macro.setOptions(options);
+			legacyMacro = options.contains("auto-") || options.contains("add");
 		}
-		multipointTool = IJ.getToolName().equals("multipoint");
+		multipointTool = Toolbar.getMultiPointMode() && !legacyMacro;
 		Color sc =Roi.getColor();
 		String sname = Colors.getColorName(sc, "Yellow");
 		Color cc =PointRoi.getDefaultCrossColor();
@@ -112,9 +114,12 @@ public class PointToolOptions implements PlugIn, DialogListener {
 			if (Prefs.pointAutoNextSlice&&!Prefs.pointAddToManager)
 				Prefs.pointAutoMeasure = true;
 		}
+		boolean updateLabels = false;
 		boolean noPointLabels = !gd.getNextBoolean();
-		if (noPointLabels!=Prefs.noPointLabels)
+		if (noPointLabels!=Prefs.noPointLabels) {
 			redraw = true;
+			updateLabels = true;
+		}
 		Prefs.noPointLabels = noPointLabels;
 		if (multipointTool) {
 			boolean showAllPoints = gd.getNextBoolean();
@@ -128,12 +133,31 @@ public class PointToolOptions implements PlugIn, DialogListener {
 			}
 		}
 		if (redraw) {
-     		PointRoi roi = getPointRoi();
-     		if (roi!=null) {
+			ImagePlus imp = null;
+			PointRoi roi = getPointRoi();
+			if (roi!=null) {
 				roi.setShowLabels(!Prefs.noPointLabels);
-				ImagePlus imp = roi.getImage();
-				if (imp!=null) imp.draw();
+				imp = roi.getImage();
+			}
+			if (updateLabels) {
+				imp = WindowManager.getCurrentImage();
+				Overlay overlay = imp!=null?imp.getOverlay():null;
+				int pointRoiCount = 0;
+				if (overlay!=null) {
+					for (int i=0; i<overlay.size(); i++) {
+						Roi r = overlay.get(i);
+						roi = r!=null && (r instanceof PointRoi)?(PointRoi)r:null;
+						if (roi!=null) {
+							roi.setShowLabels(!Prefs.noPointLabels);
+							pointRoiCount++;
+						}
+					}
+					if (pointRoiCount==0)
+						imp = null;
+				}
 			}
+			if (imp!=null)
+				imp.draw();
 		}
 		return true;
     }
diff --git a/ij/plugin/Profiler.java b/ij/plugin/Profiler.java
index fe5d150..82c806e 100644
--- a/ij/plugin/Profiler.java
+++ b/ij/plugin/Profiler.java
@@ -46,7 +46,7 @@ public Plot getPlot() {
 		boolean fixedScale = ymin!=0.0 || ymax!=0.0;
 		boolean wasFixedScale = fixedScale;
 		
-		GenericDialog gd = new GenericDialog("Plot Options", IJ.getInstance());
+		GenericDialog gd = new GenericDialog("Plot Options");
 		gd.addNumericField("Width:", PlotWindow.plotWidth, 0);
 		gd.addNumericField("Height:", PlotWindow.plotHeight, 0);
 		gd.addNumericField("Font Size:", PlotWindow.fontSize, 0);
diff --git a/ij/plugin/Resizer.java b/ij/plugin/Resizer.java
index ce2cfe2..ecfc047 100644
--- a/ij/plugin/Resizer.java
+++ b/ij/plugin/Resizer.java
@@ -72,7 +72,7 @@ public class Resizer implements PlugIn, TextListener, ItemListener  {
 				newWidth = (int)origWidth;
 				newHeight = (int)origHeight;
 			}
-			GenericDialog gd = new GenericDialog("Resize", IJ.getInstance());
+			GenericDialog gd = new GenericDialog("Resize");
 			gd.addNumericField("Width (pixels):", newWidth, 0);
 			gd.addNumericField("Height (pixels):", newHeight, 0);
 			if (imp.isHyperStack()) {
@@ -216,10 +216,7 @@ public class Resizer implements PlugIn, TextListener, ItemListener  {
 			interpolationMethod = interpolationMethod&15;
 			int stackSize = imp.getStackSize();
 			int bitDepth = imp.getBitDepth();
-			if (newDepth<=stackSize/2 && interpolationMethod==ImageProcessor.NONE)
-				imp2 = shrinkZ(imp, newDepth, inPlace);
-			else
-				imp2 = resizeZ(imp, newDepth, interpolationMethod);
+			imp2 = resizeZ(imp, newDepth, interpolationMethod);
 			if (imp2==null)
 				return null;
 			ImageProcessor ip = imp.getProcessor();
@@ -262,8 +259,6 @@ public class Resizer implements PlugIn, TextListener, ItemListener  {
 			slices2 = depth2;
 		double scale = (double)(depth2-1)/slices;
 		if (scaleT) scale = (double)(depth2-1)/frames;
-		if (scale<=0.5 && interpolationMethod==ImageProcessor.NONE)
-			return shrinkHyperstack(imp, depth2, inPlace, scaleT);
 		ImageStack stack1 = imp.getStack();
 		int width = stack1.getWidth();
 		int height = stack1.getHeight();
@@ -332,54 +327,6 @@ public class Resizer implements PlugIn, TextListener, ItemListener  {
 		return imp2;
 	}
 
-	private ImagePlus shrinkHyperstack(ImagePlus imp, int newDepth, boolean inPlace, boolean scaleT) {
-		int channels = imp.getNChannels();
-		int slices = imp.getNSlices();
-		int frames = imp.getNFrames();
-		int factor = (int)Math.round((double)slices/newDepth);
-		if (scaleT) factor = frames/newDepth;
-		int zfactor = scaleT?1:factor;
-		int tfactor = scaleT?factor:1;
-		ImageStack stack = imp.getStack();
-		ImageStack stack2 = new ImageStack(imp.getWidth(), imp.getHeight());
-		boolean virtual = stack.isVirtual();
-		int slices2 = slices/zfactor + ((slices%zfactor)!=0?1:0);
-		int frames2 = frames/tfactor + ((frames%tfactor)!=0?1:0);
-		int n = channels*slices2*frames2;
-		int count = 1;
-		for (int t=1; t<=frames; t+=tfactor) {
-			for (int z=1; z<=slices; z+=zfactor) {
-				for (int c=1; c<=channels; c++) {
-					int i = imp.getStackIndex(c, z, t);
-					IJ.showProgress(i, n);
-					ImageProcessor ip = stack.getProcessor(imp.getStackIndex(c, z, t));
-					if (!inPlace) ip=ip.duplicate();
-					//IJ.log(count++ +"  "+i+" "+c+" "+z+" "+t);
-					stack2.addSlice(stack.getSliceLabel(i), ip);
-				}
-			}
-		}
-		ImagePlus imp2 = new ImagePlus(imp.getTitle(), stack2);
-		imp2.setDimensions(channels, slices2, frames2);
-		IJ.showProgress(1.0);
-		return imp2;
-	}
-
-	private ImagePlus shrinkZ(ImagePlus imp, int newDepth, boolean inPlace) {
-		ImageStack stack = imp.getStack();
-		int factor = imp.getStackSize()/newDepth;
-		boolean virtual = stack.isVirtual();
-		int n = stack.getSize();
-		ImageStack stack2 = new ImageStack(stack.getWidth(), stack.getHeight());
-		for (int i=1; i<=n; i+=factor) {
-			if (virtual) IJ.showProgress(i, n);
-			ImageProcessor ip2 = stack.getProcessor(i);
-			if (!inPlace) ip2 = ip2.duplicate();
-			stack2.addSlice(stack.getSliceLabel(i), ip2);
-		}
-		return new ImagePlus(imp.getTitle(), stack2);
-	}
-
 	private ImagePlus resizeZ(ImagePlus imp, int newDepth, int interpolationMethod) {
 		ImageStack stack1 = imp.getStack();
 		int width = stack1.getWidth();
diff --git a/ij/plugin/RoiEnlarger.java b/ij/plugin/RoiEnlarger.java
index f63b7a1..32ba91e 100644
--- a/ij/plugin/RoiEnlarger.java
+++ b/ij/plugin/RoiEnlarger.java
@@ -64,7 +64,7 @@ public class RoiEnlarger implements PlugIn {
 			return roi;
 		int type = roi.getType();
 		int n = (int)Math.round(pixels);
-		if (type==0 || type==1)
+		if (type==Roi.RECTANGLE || type==Roi.OVAL)
 			return enlargeRectOrOval(roi, n);
 		if (n>255)
 			n = 255;
@@ -88,6 +88,8 @@ public class RoiEnlarger implements PlugIn {
 		Prefs.blackBackground = bb;
 		ip.setThreshold(0, n, ImageProcessor.NO_LUT_UPDATE);
 		Roi roi2 = (new ThresholdToSelection()).convert(ip);
+		if (roi2==null)
+			return roi;
 		roi2.setLocation(bounds.x-n, bounds.y-n);
 		roi2.setStrokeColor(roi.getStrokeColor());
 		if (roi.getStroke()!=null)
@@ -121,14 +123,11 @@ public class RoiEnlarger implements PlugIn {
 		boolean bb = Prefs.blackBackground;
 		Prefs.blackBackground = true;
 		new EDM().toEDM(ip);
-		//ImagePlus imp = new ImagePlus("ip", ip);
-		//Roi roi3 = (Roi)roi.clone();
-		//roi3.setLocation(1, 1);
-		//imp.setRoi(roi3);
-		//imp.show();
 		Prefs.blackBackground = bb;
 		ip.setThreshold(n+1, 255, ImageProcessor.NO_LUT_UPDATE);
 		Roi roi2 = (new ThresholdToSelection()).convert(ip);
+		if (roi2==null)
+			return roi;
 		Rectangle bounds2 = roi2.getBounds();
 		if (bounds2.width<=0 && bounds2.height<=0)
 			return roi;
diff --git a/ij/plugin/Scaler.java b/ij/plugin/Scaler.java
index 31c87f4..6c3c70f 100644
--- a/ij/plugin/Scaler.java
+++ b/ij/plugin/Scaler.java
@@ -84,12 +84,6 @@ public class Scaler implements PlugIn, TextListener, FocusListener {
 		int method = interpolationMethod;
 		if (w==1 || h==1)
 			method = ImageProcessor.NONE;
-		Overlay overlay = imp.getOverlay();
-		if (imp.getHideOverlay())
-			overlay = null;
-		if (overlay!=null)
-			overlay = overlay.duplicate();
-		Overlay overlay2 = new Overlay();
 		for (int i=1; i<=nSlices; i++) {
 			IJ.showStatus("Scale: " + i + "/" + nSlices);
 			ip1 = stack1.getProcessor(i);
@@ -102,28 +96,35 @@ public class Scaler implements PlugIn, TextListener, FocusListener {
 			ip2 = ip1.resize(newWidth, newHeight, averageWhenDownsizing);
 			if (ip2!=null)
 				stack2.addSlice(label, ip2);
-			if (overlay!=null) {
-				Roi roi = overlay.get(i-1);
+			IJ.showProgress(i, nSlices);
+		}
+		imp2.setStack(title, stack2);
+		Calibration cal = imp2.getCalibration();
+		if (cal.scaled()) {
+			cal.pixelWidth *= 1.0/xscale;
+			cal.pixelHeight *= 1.0/yscale;
+		}
+		Overlay overlay = imp.getOverlay();
+		if (imp.getHideOverlay())
+			overlay = null;
+		if (overlay!=null) {
+			overlay = overlay.duplicate();
+			Overlay overlay2 = new Overlay();
+			for (int i=0; i<overlay.size(); i++) {
+				Roi roi = overlay.get(i);
 				Rectangle bounds = roi.getBounds();
 				if (roi instanceof ImageRoi && bounds.x==0 && bounds.y==0) {
 					ImageRoi iroi = (ImageRoi)roi;
 					ImageProcessor processor = iroi.getProcessor();
 					processor.setInterpolationMethod(method);
-					processor =processor.resize(newWidth, newHeight, averageWhenDownsizing);
+					processor = processor.resize(newWidth, newHeight, averageWhenDownsizing);
 					iroi.setProcessor(processor);
 					overlay2.add(iroi);
 				}
 			}
-			IJ.showProgress(i, nSlices);
-		}
-		imp2.setStack(title, stack2);
-		Calibration cal = imp2.getCalibration();
-		if (cal.scaled()) {
-			cal.pixelWidth *= 1.0/xscale;
-			cal.pixelHeight *= 1.0/yscale;
+			if (overlay2.size()>0)
+				imp2.setOverlay(overlay2);
 		}
-		if (overlay2.size()>0)
-			imp2.setOverlay(overlay2);
 		IJ.showProgress(1.0);
 		int[] dim = imp.getDimensions();
 		imp2.setDimensions(dim[2], dim[3], dim[4]);
@@ -286,7 +287,11 @@ public class Scaler implements PlugIn, TextListener, FocusListener {
 		newWidth = (int)Tools.parseDouble(wstr, 0);
 		newHeight = (int)Tools.parseDouble(gd.getNextString(), 0);
 		if (newHeight!=0 && (wstr.equals("-") || wstr.equals("0")))
-				newWidth= (int)(newHeight*(double)r.width/r.height);
+			newWidth = (int)(newHeight * (double)r.width/r.height);
+		else if (newWidth!=0 && newHeight==0)
+			newHeight= (int)(newWidth * (double)r.height/r.width);
+		else if (newHeight!=0 && newWidth==0)
+			newWidth = (int)(newHeight * (double)r.width/r.height);
 		if (newWidth==0 || newHeight==0) {
 			IJ.error("Scaler", "Width or height is 0");
 			return false;
diff --git a/ij/plugin/Selection.java b/ij/plugin/Selection.java
index 948dd72..d5b1dda 100644
--- a/ij/plugin/Selection.java
+++ b/ij/plugin/Selection.java
@@ -289,7 +289,7 @@ public class Selection implements PlugIn, Measurements {
 		imp.setRoi(p);
 	}
 	
-	private void transferProperties(Roi roi1, Roi roi2) {
+	private static void transferProperties(Roi roi1, Roi roi2) {
 		if (roi1==null || roi2==null)
 			return;
 		roi2.setStrokeColor(roi1.getStrokeColor());
@@ -605,11 +605,18 @@ public class Selection implements PlugIn, Measurements {
 		imp.setRoi(s1.xor(s2));
 	}
 	
-	void lineToArea(ImagePlus imp) {
+	private void lineToArea(ImagePlus imp) {
 		Roi roi = imp.getRoi();
 		if (roi==null || !roi.isLine())
 			{IJ.error("Line to Area", "Line selection required"); return;}
 		Undo.setup(Undo.ROI, imp);
+		Roi roi2 = lineToArea(roi);
+		imp.setRoi(roi2);
+		Roi.previousRoi = (Roi)roi.clone();
+	}
+	
+	/** Converts a line selection into an area selection. */
+	public static Roi lineToArea(Roi roi) {
 		Roi roi2 = null;
 		if (roi.getType()==Roi.LINE) {
 			double width = roi.getStrokeWidth();
@@ -620,21 +627,33 @@ public class Selection implements PlugIn, Measurements {
 			roi2 = new PolygonRoi(p, Roi.POLYGON);
 			roi2.setDrawOffset(roi.getDrawOffset());
 		} else {
-			ImageProcessor ip2 = new ByteProcessor(imp.getWidth(), imp.getHeight());
+			roi = (Roi)roi.clone();
+			int lwidth = (int)roi.getStrokeWidth();
+			if (lwidth<5)
+				lwidth = 5;
+			Rectangle bounds = roi.getBounds();
+			int width = bounds.width + lwidth*2;
+			int height = bounds.height + lwidth*2;
+			ImageProcessor ip2 = new ByteProcessor(width, height);
+			roi.setLocation(lwidth, lwidth);
 			ip2.setColor(255);
 			roi.drawPixels(ip2);
-			//new ImagePlus("ip2", ip2.duplicate()).show();
 			ip2.setThreshold(255, 255, ImageProcessor.NO_LUT_UPDATE);
 			ThresholdToSelection tts = new ThresholdToSelection();
 			roi2 = tts.convert(ip2);
+			if (roi2==null)
+				return roi;
+			if (bounds.x==0&&bounds.y==0)
+				roi2.setLocation(0, 0);
+			else
+				roi2.setLocation(bounds.x-lwidth/2, bounds.y-lwidth/2);
 		}
 		transferProperties(roi, roi2);
 		roi2.setStrokeWidth(0);
 		Color c = roi2.getStrokeColor();
 		if (c!=null)  // remove any transparency
 			roi2.setStrokeColor(new Color(c.getRed(),c.getGreen(),c.getBlue()));
-		imp.setRoi(roi2);
-		Roi.previousRoi = (Roi)roi.clone();
+		return roi2;
 	}
 	
 	void areaToLine(ImagePlus imp) {
@@ -711,7 +730,7 @@ public class Selection implements PlugIn, Measurements {
 	}
 	
 	boolean setProperties(String title, Roi roi) {
-		if ((roi instanceof PointRoi) && Toolbar.getMultiPointMode()) {
+		if ((roi instanceof PointRoi) && Toolbar.getMultiPointMode() && IJ.altKeyDown()) {
 			((PointRoi)roi).displayCounts();
 			return true;
 		}
diff --git a/ij/plugin/SimpleCommands.java b/ij/plugin/SimpleCommands.java
index f6fd177..74ac1de 100644
--- a/ij/plugin/SimpleCommands.java
+++ b/ij/plugin/SimpleCommands.java
@@ -172,5 +172,5 @@ public class SimpleCommands implements PlugIn {
 		if (ip==null) return;
 		new ImagePlus("Results Table", ip).show();
 	}
-
+		
 }
diff --git a/ij/plugin/Slicer.java b/ij/plugin/Slicer.java
index eda396a..b47d8f0 100644
--- a/ij/plugin/Slicer.java
+++ b/ij/plugin/Slicer.java
@@ -17,10 +17,15 @@ import java.util.*;
 public class Slicer implements PlugIn, TextListener, ItemListener {
 
 	private static final String[] starts = {"Top", "Left", "Bottom", "Right"};
-	private static String startAt = starts[0];
-	private static boolean rotate;
-	private static boolean flip;
-	private static int sliceCount = 1;
+	private static String startAtS = starts[0];
+	private static boolean rotateS;
+	private static boolean flipS;
+	private static int sliceCountS = 1;
+	
+	private String startAt = starts[0];
+	private boolean rotate;
+	private boolean flip;
+	private int sliceCount = 1;
 	private boolean nointerpolate = Prefs.avoidResliceInterpolation;
 	private double inputZSpacing = 1.0;
 	private double outputZSpacing = 1.0;
@@ -265,12 +270,18 @@ public class Slicer implements PlugIn, TextListener, ItemListener {
 		boolean line = roi!=null && roi.getType()==Roi.LINE;
 		if (line) saveLineInfo(roi);
 		String macroOptions = Macro.getOptions();
-		if (macroOptions!=null) {
+		boolean macroRunning = macroOptions!=null;
+		if (macroRunning) {
 			if (macroOptions.indexOf("input=")!=-1)
 				macroOptions = macroOptions.replaceAll("slice=", "slice_count=");
 			macroOptions = macroOptions.replaceAll("slice=", "output=");
 			Macro.setOptions(macroOptions);
 			nointerpolate = false;
+		} else {
+			startAt = startAtS;
+			rotate = rotateS;
+			flip = flipS;
+			sliceCount = sliceCountS;
 		}
 		GenericDialog gd = new GenericDialog("Reslice");
 		gd.addNumericField("Output spacing ("+units+"):", outputSpacing, 3);
@@ -290,20 +301,18 @@ public class Slicer implements PlugIn, TextListener, ItemListener {
 		gd.setInsets(5, 0, 0);
 		gd.addMessage("Output size: "+getSize(cal.pixelDepth,outputSpacing,outputSlices)+"				");
 		fields = gd.getNumericFields();
-		if (!IJ.macroRunning()) {
+		if (!macroRunning) {
 			for (int i=0; i<fields.size(); i++)
 				((TextField)fields.elementAt(i)).addTextListener(this);
 		}
 		checkboxes = gd.getCheckboxes();
-		if (!IJ.macroRunning())
+		if (!macroRunning)
 			((Checkbox)checkboxes.elementAt(2)).addItemListener(this);
 		message = (Label)gd.getMessage();
-        gd.addHelp(IJ.URL+"/docs/menus/image.html#reslice");
+		gd.addHelp(IJ.URL+"/docs/menus/image.html#reslice");
 		gd.showDialog();
 		if (gd.wasCanceled())
 			return false;
-		//inputZSpacing = gd.getNextNumber();
-		//if (cal.pixelDepth==0.0) cal.pixelDepth = 1.0;
 		outputZSpacing = gd.getNextNumber()/cal.pixelWidth;
 		if (line) {
 			outputSlices = (int)gd.getNextNumber();
@@ -314,8 +323,13 @@ public class Slicer implements PlugIn, TextListener, ItemListener {
 		flip = gd.getNextBoolean();
 		rotate = gd.getNextBoolean();
 		nointerpolate = gd.getNextBoolean();
-		if (!IJ.isMacro())
+		if (!macroRunning) {
 			Prefs.avoidResliceInterpolation = nointerpolate;
+			startAtS = startAt;
+			rotateS = rotate;
+			flipS = flip;
+			sliceCountS = sliceCount;
+		}
 		return true;
 	}
 	
diff --git a/ij/plugin/StackCombiner.java b/ij/plugin/StackCombiner.java
index 91390a3..ad09c7f 100644
--- a/ij/plugin/StackCombiner.java
+++ b/ij/plugin/StackCombiner.java
@@ -20,8 +20,18 @@ public class StackCombiner implements PlugIn {
 	public void run(String arg) {
 		if (!showDialog())
 			return;
-		if (imp1.getType()!=imp2.getType() || imp1.isHyperStack() || imp2.isHyperStack())
-			{error(); return;}
+		if (imp1.getBitDepth()!=imp2.getBitDepth()) {
+			error();
+			return;
+		}
+		int[] dim1 = imp1.getDimensions();
+		int[] dim2 = imp2.getDimensions();
+		if (imp1.isHyperStack() || imp2.isHyperStack()) {
+			if (dim1[2]!=dim2[2] || dim1[3]!=dim2[3] || dim1[4]!=dim2[4]) {
+				IJ.error("StackCombiner", "Hyperstacks must have identical CZT dimensions");	
+				return;
+			}
+		}
 		ImageStack stack1 = imp1.getStack();
 		ImageStack stack2 = imp2.getStack();
 		ImageStack stack3 = vertical?combineVertically(stack1, stack2):combineHorizontally(stack1, stack2);
@@ -29,7 +39,16 @@ public class StackCombiner implements PlugIn {
 		imp1.close();
 		imp2.changes = false;
 		imp2.close();
-		new ImagePlus("Combined Stacks", stack3).show();
+		ImagePlus imp3 = imp1.createImagePlus();
+		imp3.setStack(stack3);
+		if (imp1.isHyperStack())
+			imp3.setDimensions(dim1[2],dim1[3],dim1[4]);
+		if (imp1.isComposite()) {
+			imp3 = new CompositeImage(imp3, imp1.getCompositeMode());
+			imp3.setDimensions(dim1[2],dim1[3],dim1[4]);
+		}
+		imp3.setTitle("Combined Stacks");
+		imp3.show();
 	}
 	
 	public ImageStack combineHorizontally(ImageStack stack1, ImageStack stack2) {
@@ -62,7 +81,7 @@ public class StackCombiner implements PlugIn {
 				ip3.insert(stack2.getProcessor(1),w1,0);
 				stack2.deleteSlice(1);
 			}
-		stack3.addSlice(null, ip3);
+			stack3.addSlice(null, ip3);
 		}
 		return stack3;
 	}
@@ -132,7 +151,7 @@ public class StackCombiner implements PlugIn {
 
 	
 	void error() {
-		IJ.showMessage("StackCombiner", "This command requires two stacks\n"
+		IJ.error("StackCombiner", "This command requires two stacks\n"
 			+"that are the same data type.");
 	}
 
diff --git a/ij/plugin/Startup.java b/ij/plugin/Startup.java
index ebf450d..bc24a23 100644
--- a/ij/plugin/Startup.java
+++ b/ij/plugin/Startup.java
@@ -14,6 +14,7 @@ import java.util.Vector;
 		private static final String[] code = {
 			"[Select from list]",
 			"Black background",
+			"Add to overlay",
 			"Debug mode",
 			"10-bit (0-1023) range",
 			"12-bit (0-4095) range"
@@ -80,10 +81,12 @@ import java.util.Vector;
 		if (item.equals(code[1]))
 			statement = "setOption(\"BlackBackground\", true);\n";
 		else if (item.equals(code[2]))
-			statement = "setOption(\"DebugMode\", true);\n";
+			statement = "setOption(\"Add to overlay\", true);\n";
 		else if (item.equals(code[3]))
-			statement = "call(\"ij.ImagePlus.setDefault16bitRange\", 10);\n";
+			statement = "setOption(\"DebugMode\", true);\n";
 		else if (item.equals(code[4]))
+			statement = "call(\"ij.ImagePlus.setDefault16bitRange\", 10);\n";
+		else if (item.equals(code[5]))
 			statement = "call(\"ij.ImagePlus.setDefault16bitRange\", 12);\n";
 		if (statement!=null) {
 			TextArea ta = gd.getTextArea1();
diff --git a/ij/plugin/SubstackMaker.java b/ij/plugin/SubstackMaker.java
index acbc2c4..311b25f 100644
--- a/ij/plugin/SubstackMaker.java
+++ b/ij/plugin/SubstackMaker.java
@@ -157,8 +157,9 @@ public class SubstackMaker implements PlugIn {
 		ImageStack stack = imp.getStack();
 		ImageStack stack2 = null;
 		Roi roi = imp.getRoi();
+		boolean showProgress = stack.getSize()>400 || stack.isVirtual();
 		for (int i= first, j=0; i<= last; i+=inc) {
-			//IJ.log(first+" "+last+" "+inc+" "+i);
+			if (showProgress) IJ.showProgress(i,last);
 			int currSlice = i-j;
 			ImageProcessor ip2 = stack.getProcessor(currSlice);
 			ip2.setRoi(roi);
diff --git a/ij/plugin/ZAxisProfiler.java b/ij/plugin/ZAxisProfiler.java
index 1109b4d..dffc1ee 100644
--- a/ij/plugin/ZAxisProfiler.java
+++ b/ij/plugin/ZAxisProfiler.java
@@ -8,7 +8,9 @@ import ij.plugin.filter.Analyzer;
 import ij.util.Tools;
 import java.awt.*;
 
-/** Implements the Image/Stack/Plot Z-axis Profile command. */
+/** Implements the Image/Stacks/Plot Z-axis Profile command, 
+	which plots the selection mean gray value versus slice number.
+*/
 public class ZAxisProfiler implements PlugIn, Measurements, PlotMaker {
 	private static String[] choices = {"time", "z-axis"};
 	private static String choice = choices[0];
@@ -17,6 +19,23 @@ public class ZAxisProfiler implements PlugIn, Measurements, PlotMaker {
 	private boolean isPlotMaker;
 	private boolean timeProfile;
 	private boolean firstTime = true;
+	private String options;
+	
+	/** Returns a Plot of the selection mean gray value versus slice number. */
+	public static Plot getPlot(ImagePlus imp) {
+		return getPlot(imp, "time");
+	}
+
+	/** Returns a Plot of the selection mean versus slice number for the
+		specified hyperstack, where 'options' can be "time" or "z-axis". */
+	public static Plot getPlot(ImagePlus imp, String options) {
+		ZAxisProfiler zap = new ZAxisProfiler();
+		zap.imp = imp;
+		zap.options = options;
+		zap.isPlotMaker = true;
+		Plot plot = zap.getPlot();
+		return plot;
+	}
 
 	public void run(String arg) {
 		imp = IJ.getImage();
@@ -24,8 +43,7 @@ public class ZAxisProfiler implements PlugIn, Measurements, PlotMaker {
 			IJ.error("ZAxisProfiler", "This command requires a stack.");
 			return;
 		}
-		Roi roi = imp.getRoi();
-		isPlotMaker = !IJ.macroRunning();
+		isPlotMaker = true;
 		Plot plot = getPlot();
 		if (plot!=null) {
 			if (isPlotMaker)
@@ -133,7 +151,7 @@ public class ZAxisProfiler implements PlugIn, Measurements, PlotMaker {
 		int size = slices;
 		if (firstTime)
 			timeProfile = slices==1 && frames>1;
-		if (slices>1 && frames>1 && (!isPlotMaker ||firstTime)) {
+		if (options==null && slices>1 && frames>1 && (!isPlotMaker ||firstTime)) {
 			showingDialog = true;
 			GenericDialog gd = new GenericDialog("Profiler");
 			gd.addChoice("Profile", choices, choice);
@@ -143,6 +161,8 @@ public class ZAxisProfiler implements PlugIn, Measurements, PlotMaker {
 			choice = gd.getNextChoice();
 			timeProfile = choice.equals(choices[0]);
 		}
+		if (options!=null)
+			timeProfile = frames>1 && !options.contains("z");
 		if (timeProfile)
 			size = frames;
 		else
@@ -158,7 +178,10 @@ public class ZAxisProfiler implements PlugIn, Measurements, PlotMaker {
 				return null;
 		}
 		ImageStack stack = imp.getStack();
+		boolean showProgress = size>400 || stack.isVirtual();
 		for (int i=1; i<=size; i++) {
+			if (showProgress)
+				IJ.showProgress(i,size);
 			int index = 1;
 			if (timeProfile)
 				index = imp.getStackIndex(c, z, i);
@@ -187,6 +210,7 @@ public class ZAxisProfiler implements PlugIn, Measurements, PlotMaker {
 			timeProfile = slices==1 && frames>1;
 		}
 		int size = stack.getSize();
+		boolean showProgress = size>400 || stack.isVirtual();
 		float[] values = new float[size];
 		Calibration cal = imp.getCalibration();
 		Analyzer analyzer = new Analyzer(imp);
@@ -201,6 +225,8 @@ public class ZAxisProfiler implements PlugIn, Measurements, PlotMaker {
 		boolean isLine = roi!=null && roi.isLine();
 		int current = imp.getCurrentSlice();
 		for (int i=1; i<=size; i++) {
+			if (showProgress)
+				IJ.showProgress(i,size);
 			if (showingLabels)
 				imp.setSlice(i);
 			ImageProcessor ip = stack.getProcessor(i);
diff --git a/ij/plugin/ZProjector.java b/ij/plugin/ZProjector.java
index ea846f2..78b5302 100644
--- a/ij/plugin/ZProjector.java
+++ b/ij/plugin/ZProjector.java
@@ -195,9 +195,9 @@ public class ZProjector implements PlugIn {
         	ImageProcessor g = green2.getProcessor();
         	ImageProcessor b = blue2.getProcessor();
         	double max = 0;
-        	double rmax = r.getStatistics().max; if (rmax>max) max=rmax;
-        	double gmax = g.getStatistics().max; if (gmax>max) max=gmax;
-        	double bmax = b.getStatistics().max; if (bmax>max) max=bmax;
+        	double rmax = r.getStats().max; if (rmax>max) max=rmax;
+        	double gmax = g.getStats().max; if (gmax>max) max=gmax;
+        	double bmax = b.getStats().max; if (bmax>max) max=bmax;
         	double scale = 255/max;
         	r.multiply(scale); g.multiply(scale); b.multiply(scale);
         	red2.setProcessor(r.convertToByte(false));
@@ -214,7 +214,7 @@ public class ZProjector implements PlugIn {
 	@param start starting slice to display
 	@param stop last slice */
     protected GenericDialog buildControlDialog(int start, int stop) {
-		GenericDialog gd = new GenericDialog("ZProjection",IJ.getInstance()); 
+		GenericDialog gd = new GenericDialog("ZProjection"); 
 		gd.addNumericField("Start slice:",startSlice,0/*digits*/); 
 		gd.addNumericField("Stop slice:",stopSlice,0/*digits*/);
 		gd.addChoice("Projection type", METHODS, METHODS[method]); 
diff --git a/ij/plugin/filter/Analyzer.java b/ij/plugin/filter/Analyzer.java
index e6551cb..0c48e77 100644
--- a/ij/plugin/filter/Analyzer.java
+++ b/ij/plugin/filter/Analyzer.java
@@ -15,11 +15,13 @@ import ij.macro.Interpreter;
 /** This plugin implements ImageJ's Analyze/Measure and Analyze/Set Measurements commands. */
 public class Analyzer implements PlugInFilter, Measurements {
 	
+	private static boolean drawLabels = true;
 	private String arg;
 	private ImagePlus imp;
 	private ResultsTable rt;
 	private int measurements;
 	private StringBuffer min,max,mean,sd;
+	private boolean disableReset;
 	
 	// Order must agree with order of checkboxes in Set Measurements dialog box
 	private static final int[] list = {AREA,MEAN,STD_DEV,MODE,MIN_MAX,
@@ -83,7 +85,8 @@ public class Analyzer implements PlugInFilter, Measurements {
 		else if (arg.equals("sum"))
 			{summarize(); return DONE;}
 		else if (arg.equals("clear")) {
-			if (IJ.macroRunning()) unsavedMeasurements = false;
+			if (IJ.macroRunning())
+				unsavedMeasurements = false;
 			resetCounter();
 			return DONE;
 		} else
@@ -115,6 +118,8 @@ public class Analyzer implements PlugInFilter, Measurements {
 		Overlay overlay = imp.getOverlay();
 		if (overlay==null)
 			overlay = new Overlay();
+		if (drawLabels)
+			overlay.drawLabels(true);
 		if (!overlay.getDrawNames())
 			overlay.drawNames(true);
 		overlay.setLabelColor(Color.white);
@@ -148,7 +153,7 @@ public class Analyzer implements PlugInFilter, Measurements {
 		if (macroOptions!=null && macroOptions.indexOf("slice ")!=-1)
 			Macro.setOptions(macroOptions.replaceAll("slice ", "stack "));
 
- 		GenericDialog gd = new GenericDialog("Set Measurements", IJ.getInstance());
+ 		GenericDialog gd = new GenericDialog("Set Measurements");
 		String[] labels = new String[18];
 		boolean[] states = new boolean[18];
 		labels[0]="Area"; states[0]=(systemMeasurements&AREA)!=0;
@@ -278,7 +283,7 @@ public class Analyzer implements PlugInFilter, Measurements {
 	
 	boolean reset() {
 		boolean ok = true;
-		if (rt.size()>0)
+		if (rt.size()>0 && !disableReset)
 			ok = resetCounter();
 		if (ok && rt.getColumnHeading(ResultsTable.LAST_HEADING)==null)
 			rt.setDefaultHeadings();
@@ -369,10 +374,11 @@ public class Analyzer implements PlugInFilter, Measurements {
 		ImageStack stack = null;
 		if (imp2.getStackSize()>1)
 			stack = imp2.getStack();
+		PointRoi pointRoi = roi instanceof PointRoi?(PointRoi)roi:null;
 		for (int i=0; i<p.npoints; i++) {
 			int position = 0;
-			if (roi instanceof PointRoi)
-				position = ((PointRoi)roi).getPointPosition(i);
+			if (pointRoi!=null)
+				position = pointRoi.getPointPosition(i);
 			ImageProcessor ip = null;
 			if (stack!=null && position>0 && position<=stack.size())
 				ip = stack.getProcessor(position);
@@ -382,6 +388,17 @@ public class Analyzer implements PlugInFilter, Measurements {
 			ImageStatistics stats = ImageStatistics.getStatistics(ip, measurements, imp2.getCalibration());
 			PointRoi point = new PointRoi(p.xpoints[i], p.ypoints[i]);
 			point.setPosition(position);
+			if (pointRoi!=null) {
+				int[] counters = pointRoi.getCounters();
+				if (counters!=null && i<counters.length) {
+					int counter = counters[i]&0xff;
+					int count = pointRoi.getCount(counter);
+					int[] info = new int[2];
+					info[0] = counter;
+					info[1] = count;
+					point.setCounterInfo(info);
+				}
+			}
 			saveResults(stats, point);
 			if (i!=p.npoints-1) displayResults();
 		}
@@ -486,7 +503,7 @@ public class Analyzer implements PlugInFilter, Measurements {
 			if (imp2!=null) {
 				Calibration cal = imp.getCalibration();
 				stats.xCentroid = cal.getX(stats.xCentroid);
-				stats.yCentroid = cal.getY(stats.yCentroid);
+				stats.yCentroid = cal.getY(stats.yCentroid, imp2.getHeight());
 			}
 		}
 		saveResults(stats, roi);
@@ -573,7 +590,7 @@ public class Analyzer implements PlugInFilter, Measurements {
 				Calibration cal = imp!=null?imp.getCalibration():null;
 				if (cal!=null) {
 					rx = cal.getX(rx);
-					ry = cal.getY(ry);
+					ry = cal.getY(ry, imp.getHeight());
 					rw *= cal.pixelWidth;
 					rh *= cal.pixelHeight;
 				}
@@ -664,8 +681,8 @@ public class Analyzer implements PlugInFilter, Measurements {
 				double angle = ((PolygonRoi)roi).getAngle();
 				if (Prefs.reflexAngle) angle = 360.0-angle;
 				rt.addValue("Angle", angle);
-			} else if (roi.getType()==Roi.POINT)
-				savePoints(roi);
+			} else if (roi instanceof PointRoi)
+				savePoints((PointRoi)roi);
 		}
 		if ((measurements&LIMIT)!=0 && imp!=null && imp.getBitDepth()!=24) {
 			rt.addValue(ResultsTable.MIN_THRESHOLD, stats.lowerThreshold);
@@ -694,7 +711,7 @@ public class Analyzer implements PlugInFilter, Measurements {
 		return (Math.abs(carea/2.0));
 	}
 		
-	void savePoints(Roi roi) {
+	void savePoints(PointRoi roi) {
 		if (imp==null) {
 			rt.addValue("X", 0.0);
 			rt.addValue("Y", 0.0);
@@ -743,6 +760,11 @@ public class Analyzer implements PlugInFilter, Measurements {
 				position = imp.getCurrentSlice();
 			rt.addValue("Slice", position);
 		}
+		int[] info = roi.getCounterInfo();
+		if (info!=null) {
+			rt.addValue("Counter", info[0]);
+			rt.addValue("Count", info[1]);
+		}
 		if (imp.getProperty("FHT")!=null) {
 			double center = imp.getWidth()/2.0;
 			y = imp.getHeight()-y-1;
@@ -822,7 +844,6 @@ public class Analyzer implements PlugInFilter, Measurements {
 	}
 		
 	void incrementCounter() {
-		//counter++;
 		if (rt==null) rt = systemRT;
 		rt.incrementCounter();
 		unsavedMeasurements = true;
@@ -920,9 +941,11 @@ public class Analyzer implements PlugInFilter, Measurements {
 
 	/** Sets the specified system-wide measurement option. */
 	public static void setMeasurement(int option, boolean state) {
-			if (state)
+			if (state) {
 				systemMeasurements |= option;
-			else
+				if ((option&ADD_TO_OVERLAY)!=0)
+					drawLabels = true;
+			} else
 				systemMeasurements &= ~option;
 	}
 
@@ -997,5 +1020,14 @@ public class Analyzer implements PlugInFilter, Measurements {
 		unsavedMeasurements = false;
 	}
 	
+	public static void drawLabels(boolean b) {
+		drawLabels = b;
+	}
+	
+	/** Used by RoiManager.multiMeasure() to suppress save as dialogs. */
+	public void disableReset(boolean b) {
+		disableReset = b;
+	}
+
 }
 	
diff --git a/ij/plugin/filter/Convolver.java b/ij/plugin/filter/Convolver.java
index 696901c..356d4df 100644
--- a/ij/plugin/filter/Convolver.java
+++ b/ij/plugin/filter/Convolver.java
@@ -64,7 +64,7 @@ public class Convolver implements ExtendedPlugInFilter, DialogListener, ActionLi
 	}
 	
 	public int showDialog(ImagePlus imp, String command, PlugInFilterRunner pfr) {
-		gd = new GenericDialog("Convolver...", IJ.getInstance());
+		gd = new GenericDialog("Convolver...");
 		gd.addTextAreas(kernelText, null, 10, 30);
 		gd.addPanel(makeButtonPanel(gd));
 		gd.addCheckbox("Normalize Kernel", normalizeFlag);
diff --git a/ij/plugin/filter/FractalBoxCounter.java b/ij/plugin/filter/FractalBoxCounter.java
index c7f792a..895cdd5 100644
--- a/ij/plugin/filter/FractalBoxCounter.java
+++ b/ij/plugin/filter/FractalBoxCounter.java
@@ -47,7 +47,7 @@ public class FractalBoxCounter implements PlugInFilter {
 
 	public void run(ImageProcessor ip) {
 
-		GenericDialog gd = new GenericDialog("Fractal Box Counter", IJ.getInstance());
+		GenericDialog gd = new GenericDialog("Fractal Box Counter");
 		gd.addStringField("Box Sizes:", sizes, 20);
 		gd.addCheckbox("Black Background", blackBackground);
 
diff --git a/ij/plugin/filter/ImageMath.java b/ij/plugin/filter/ImageMath.java
index d16f0b4..fd1785b 100644
--- a/ij/plugin/filter/ImageMath.java
+++ b/ij/plugin/filter/ImageMath.java
@@ -318,6 +318,21 @@ public class ImageMath implements ExtendedPlugInFilter, DialogListener {
 				}
 			}
 			if (hasGetPixel) System.arraycopy(pixels2, 0, pixels1, 0, w*h);
+		} else if (ip.isSigned16Bit()) {
+			for (int y=r.y; y<(r.y+r.height); y++) {
+				if (showProgress && y%inc==0)
+					IJ.showProgress(y-r.y, r.height);
+				interp.setVariable("y", y);
+				for (int x=r.x; x<(r.x+r.width); x++) {
+					v = ip.getPixelValue(x, y);
+					interp.setVariable("v", v);
+					if (hasX) interp.setVariable("x", x);
+					if (hasA) interp.setVariable("a", getA((h-y-1)-h2, x-w2));
+					if (hasD) interp.setVariable("d", getD(x-w2,y-h2));
+					interp.run(PCStart);
+					ip.putPixelValue(x, y, interp.getVariable("v"));
+				}
+			}
 		} else if (bitDepth==16) {
 			short[] pixels1 = (short[])ip.getPixels();
 			short[] pixels2 = pixels1;
diff --git a/ij/plugin/filter/MaximumFinder.java b/ij/plugin/filter/MaximumFinder.java
index 7d240cf..a14d3f7 100644
--- a/ij/plugin/filter/MaximumFinder.java
+++ b/ij/plugin/filter/MaximumFinder.java
@@ -572,10 +572,10 @@ public class MaximumFinder implements ExtendedPlugInFilter, DialogListener {
                     for (int d=0; d<8; d++) {       //analyze all neighbors (in 8 directions) at the same level
                         int offset2 = offset+dirOffset[d];
                         if ((isInner || isWithin(x, y, d)) && (types[offset2]&LISTED)==0) {
-                        if (isEDM && edmPixels[offset2]<=0) continue;   //ignore the background (non-particles)
+                            if (isEDM && edmPixels[offset2]<=0)
+                                continue;   //ignore the background (non-particles)
                             if ((types[offset2]&PROCESSED)!=0) {
                                 maxPossible = false; //we have reached a point processed previously, thus it is no maximum now
-                                //if(x0<25&&y0<20)IJ.write("x0,y0="+x0+","+y0+":stop at processed neighbor from x,y="+x+","+y+", dir="+d);
                                 break;
                             }
                             int x2 = x+DIR_X_OFFSET[d];
diff --git a/ij/plugin/filter/ParticleAnalyzer.java b/ij/plugin/filter/ParticleAnalyzer.java
index e0e6d5b..663fee2 100644
--- a/ij/plugin/filter/ParticleAnalyzer.java
+++ b/ij/plugin/filter/ParticleAnalyzer.java
@@ -355,8 +355,10 @@ public class ParticleAnalyzer implements PlugInFilter, Measurements {
 		double maxc = minAndMax.length==2?gd.parseDouble(minAndMax[1]):Double.NaN;
 		minCircularity = Double.isNaN(minc)?0.0:minc;
 		maxCircularity = Double.isNaN(maxc)?1.0:maxc;
-		if (minCircularity<0.0 || minCircularity>1.0) minCircularity = 0.0;
-		if (maxCircularity<minCircularity || maxCircularity>1.0) maxCircularity = 1.0;
+		if (minCircularity<0.0) minCircularity = 0.0;
+		if (minCircularity>maxCircularity && maxCircularity==1.0) minCircularity = 0.0;
+		if (minCircularity>maxCircularity) minCircularity = maxCircularity;
+		if (maxCircularity<minCircularity) maxCircularity = minCircularity;
 		if (minCircularity==1.0 && maxCircularity==1.0) minCircularity = 0.0;
 		staticMinCircularity = minCircularity;
 		staticMaxCircularity = maxCircularity;
@@ -866,10 +868,10 @@ public class ParticleAnalyzer implements PlugInFilter, Measurements {
 			}
 		}
 		ImageProcessor mask = ip2.getMask();
-		if (minCircularity>0.0 || maxCircularity<1.0) {
+		if (minCircularity>0.0 || maxCircularity!=1.0) {
 			double perimeter = roi.getLength();
 			double circularity = perimeter==0.0?0.0:4.0*Math.PI*(stats.pixelCount/(perimeter*perimeter));
-			if (circularity>1.0) circularity = 1.0;
+			if (circularity>1.0 && maxCircularity<=1.0) circularity = 1.0;
 			if (circularity<minCircularity || circularity>maxCircularity) include = false;
 		}
 		if (stats.pixelCount>=minSize && stats.pixelCount<=maxSize && include) {
@@ -902,9 +904,14 @@ public class ParticleAnalyzer implements PlugInFilter, Measurements {
 	}
 
 	/** Saves statistics for one particle in a results table. This is
-		a method subclasses may want to override. */
+		a method subclasses can override. */
 	protected void saveResults(ImageStatistics stats, Roi roi) {
 		analyzer.saveResults(stats, roi);
+		if (maxCircularity>1.0 && rt.columnExists("Circ.") && rt.getValue("Circ.", rt.size()-1)==1.0) {
+			double perimeter = roi.getLength();
+			double circularity = perimeter==0.0?0.0:4.0*Math.PI*(stats.pixelCount/(perimeter*perimeter));
+			rt.addValue("Circ.", circularity);
+		}
 		if (recordStarts) {
 			rt.addValue("XStart", stats.xstart);
 			rt.addValue("YStart", stats.ystart);
diff --git a/ij/plugin/filter/Rotator.java b/ij/plugin/filter/Rotator.java
index 4434105..496010e 100644
--- a/ij/plugin/filter/Rotator.java
+++ b/ij/plugin/filter/Rotator.java
@@ -111,7 +111,7 @@ public class Rotator implements ExtendedPlugInFilter, DialogListener {
 				macroOptions = macroOptions+" interpolation=None";
 			Macro.setOptions(macroOptions);
 		}
-		gd = new GenericDialog("Rotate", IJ.getInstance());
+		gd = new GenericDialog("Rotate");
 		gd.addNumericField("Angle (degrees):", angle, (int)angle==angle?1:2);
 		gd.addNumericField("Grid Lines:", gridLines, 0);
 		gd.addChoice("Interpolation:", methods, methods[interpolationMethod]);
diff --git a/ij/plugin/filter/StackLabeler.java b/ij/plugin/filter/StackLabeler.java
index b5e7b43..89b74e6 100644
--- a/ij/plugin/filter/StackLabeler.java
+++ b/ij/plugin/filter/StackLabeler.java
@@ -209,8 +209,9 @@ public class StackLabeler implements ExtendedPlugInFilter, DialogListener {
 			}
 		}
 		int frame = image;
+		int[] pos = new int[]{0, 0, 0};
 		if (imp.isHyperStack()) {
-			int[] pos = imp.convertIndexToPosition(image);
+			pos = imp.convertIndexToPosition(image);
 			if (imp.getNFrames()>1)
 				frame = pos[2];
 			else if (imp.getNSlices()>1)
@@ -232,7 +233,10 @@ public class StackLabeler implements ExtendedPlugInFilter, DialogListener {
 				Roi roi = new TextRoi(xloc, y-yoffset, s, font);
 				roi.setStrokeColor(color);
 				roi.setNonScalable(true);
-				roi.setPosition(image);
+				if (imp.isHyperStack())
+					roi.setPosition(pos[0], pos[1], pos[2]);
+				else
+					roi.setPosition(image);
 				overlay.add(roi);
 			}
 			if (image==imp.getStackSize()||previewing)
diff --git a/ij/plugin/filter/ThresholdToSelection.java b/ij/plugin/filter/ThresholdToSelection.java
index 80b0fb4..ea81655 100644
--- a/ij/plugin/filter/ThresholdToSelection.java
+++ b/ij/plugin/filter/ThresholdToSelection.java
@@ -2,7 +2,7 @@
  * This plugin implements the Edit/Selection/Create Selection command.
  * It is based on a proposal by Tom Larkworthy.
  * Written and public domained in June 2006 by Johannes E. Schindelin
- */
+*/
 package ij.plugin.filter;
 import ij.IJ;
 import ij.ImagePlus;
@@ -29,12 +29,15 @@ public class ThresholdToSelection implements PlugInFilter {
 		image.setRoi(convert(ip));
 	}
 	
+	/** Returns a selection created from the thresholded pixels in the
+		specified image, or null if there are no thresholded pixels. */
 	public static Roi run(ImagePlus imp) {
 		ThresholdToSelection tts = new ThresholdToSelection();
-		tts.image = imp;
 		return tts.convert(imp.getProcessor());
 	}
 	
+	/** Returns a selection created from the thresholded pixels in the
+		specified image, or null if there are no thresholded pixels. */
 	public Roi convert(ImageProcessor ip) {
 		this.ip = ip;
 		min = (float)ip.getMinThreshold();
@@ -290,7 +293,9 @@ public class ThresholdToSelection implements PlugInFilter {
 					IJ.showProgress(y*(PROGRESS_FRACTION_OUTLINING/h));
 			}
 		}
-
+		
+		if (polygons.size()==0)
+			return null;
 		if (showStatus) IJ.showStatus("Converting threshold to selection...");
 		GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
 		progressInc = Math.max(polygons.size()/10, 1);
diff --git a/ij/plugin/frame/Channels.java b/ij/plugin/frame/Channels.java
index c47e62b..1eece16 100644
--- a/ij/plugin/frame/Channels.java
+++ b/ij/plugin/frame/Channels.java
@@ -113,7 +113,7 @@ public class Channels extends PlugInDialog implements PlugIn, ItemListener, Acti
 	}
 	
 	public static void updateChannels() {
-		if (instance!=null && !(IJ.isMacOSX()&&IJ.isJava18()))
+		if (instance!=null)
 			instance.update();
 	}
 	
diff --git a/ij/plugin/frame/ContrastAdjuster.java b/ij/plugin/frame/ContrastAdjuster.java
index 5e0ac53..80bbcde 100644
--- a/ij/plugin/frame/ContrastAdjuster.java
+++ b/ij/plugin/frame/ContrastAdjuster.java
@@ -784,10 +784,7 @@ public class ContrastAdjuster extends PlugInDialog implements Runnable,
 	void autoAdjust(ImagePlus imp, ImageProcessor ip) {
  		if (RGBImage)
 			ip.reset();
-		Calibration cal = imp.getCalibration();
-		imp.setCalibration(null);
-		ImageStatistics stats = imp.getStatistics(); // get uncalibrated stats
-		imp.setCalibration(cal);
+		ImageStatistics stats = imp.getRawStatistics();
 		int limit = stats.pixelCount/10;
 		int[] histogram = stats.histogram;
 		if (autoThreshold<10)
@@ -1021,7 +1018,7 @@ public class ContrastAdjuster extends PlugInDialog implements Runnable,
 			updateScrollBars(null, false);
 			if (RGBImage) doMasking(imp, ip);
 			if (propagate)
-				IJ.runMacroFile("ij.jar:PropagateMinAndMax");
+				propagate(imp);
 			if (Recorder.record) {
 				if (imp.getBitDepth()==32)
 					recordSetMinAndMax(min, max);
diff --git a/ij/plugin/frame/LineWidthAdjuster.java b/ij/plugin/frame/LineWidthAdjuster.java
index 8b5a057..340969e 100644
--- a/ij/plugin/frame/LineWidthAdjuster.java
+++ b/ij/plugin/frame/LineWidthAdjuster.java
@@ -58,7 +58,7 @@ public class LineWidthAdjuster extends PlugInFrame implements PlugIn,
 		
 		c.gridx = 2;
 		c.insets = new Insets(margin, 25, margin, 5);
-		checkbox = new Checkbox("Spline Fit", isSplineFit());
+		checkbox = new Checkbox("Spline fit", isSplineFit());
 		checkbox.addItemListener(this);
 		panel.add(checkbox);
 		
@@ -173,10 +173,15 @@ public class LineWidthAdjuster extends PlugInFrame implements PlugIn,
 			{checkbox.setState(false); return;};;
 		PolygonRoi poly = (PolygonRoi)roi;
 		boolean splineFit = poly.isSplineFit();
-		if (selected && !splineFit)
-			{poly.fitSpline(); imp.draw();}
-		else if (!selected && splineFit)
-			{poly.removeSplineFit(); imp.draw();}
+		if (selected && !splineFit) {
+			poly.fitSpline();
+			Prefs.splineFitLines = true;
+			imp.draw();
+		} else if (!selected && splineFit) {
+			poly.removeSplineFit();
+			Prefs.splineFitLines = false;
+			imp.draw();
+		}
 	}
 	
 	public static void update() {
diff --git a/ij/plugin/frame/PlugInDialog.java b/ij/plugin/frame/PlugInDialog.java
index 71d6ed3..d10b767 100644
--- a/ij/plugin/frame/PlugInDialog.java
+++ b/ij/plugin/frame/PlugInDialog.java
@@ -14,8 +14,10 @@ public class PlugInDialog extends Dialog implements PlugIn, WindowListener, Focu
 		enableEvents(AWTEvent.WINDOW_EVENT_MASK);
 		this.title = title;
 		ImageJ ij = IJ.getInstance();
-		if (IJ.isMacOSX() && ij!=null)
+		if (IJ.isMacOSX() && ij!=null) {
 			ij.toFront(); // needed for keyboard shortcuts to work
+			IJ.wait(250);
+		}
 		addWindowListener(this);
  		addFocusListener(this);
 		if (IJ.isLinux()) setBackground(ImageJ.backgroundColor);
@@ -44,8 +46,11 @@ public class PlugInDialog extends Dialog implements PlugIn, WindowListener, Focu
 		WindowManager.removeWindow(this);
     }
 
-    public void windowActivated(WindowEvent e) {
-        WindowManager.setWindow(this);
+	public void windowActivated(WindowEvent e) {
+		ImageJ ij = IJ.getInstance();
+		if (IJ.isMacOSX() && ij!=null && !ij.isActive() && !(this instanceof ThresholdAdjuster))
+			ij.toFront();
+		WindowManager.setWindow(this);
 	}
 
 	public void focusGained(FocusEvent e) {
diff --git a/ij/plugin/frame/PlugInFrame.java b/ij/plugin/frame/PlugInFrame.java
index 6957e7b..8282cb3 100644
--- a/ij/plugin/frame/PlugInFrame.java
+++ b/ij/plugin/frame/PlugInFrame.java
@@ -43,7 +43,7 @@ public class PlugInFrame extends Frame implements PlugIn, WindowListener, FocusL
     }
 
     public void windowActivated(WindowEvent e) {
-		if (IJ.isMacintosh()) {
+		if (Prefs.setIJMenuBar) {
 			this.setMenuBar(Menus.getMenuBar());
 			Menus.setMenuBarCount++;
 		}
diff --git a/ij/plugin/frame/Recorder.java b/ij/plugin/frame/Recorder.java
index 79c232d..62fb2bd 100644
--- a/ij/plugin/frame/Recorder.java
+++ b/ij/plugin/frame/Recorder.java
@@ -442,6 +442,8 @@ public class Recorder extends PlugInFrame implements PlugIn, ActionListener, Ima
 			if (!bbSet && (name.equals("Make Binary")||name.equals("Convert to Mask")||name.equals("Erode")
 			||name.equals("Dilate")||name.equals("Skeletonize")))
 				setBlackBackground();
+			if (name.equals("Add Shortcut by Name... "))
+				name = "Add Shortcut... ";
 			if (commandOptions!=null) {
 				if (name.equals("Open...") || name.equals("URL...")) {
 					String s = scriptMode?"imp = IJ.openImage":"open";
diff --git a/ij/plugin/frame/RoiManager.java b/ij/plugin/frame/RoiManager.java
index 05504cc..37bb49a 100644
--- a/ij/plugin/frame/RoiManager.java
+++ b/ij/plugin/frame/RoiManager.java
@@ -64,7 +64,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
 	private boolean firstTime = true;
 	private int[] selectedIndexes;
 	private boolean appendResults;
-	private static ResultsTable mmResults;
+	private static ResultsTable mmResults, mmResults2;
 	private int imageID;
 	private boolean allowRecording;
 	private boolean recordShowAll = true;
@@ -78,8 +78,12 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
 			WindowManager.toFront(instance);
 			return;
 		}
-		if (IJ.isMacro() && Interpreter.getBatchModeRoiManager()!=null)
+		if (IJ.isMacro() && Interpreter.getBatchModeRoiManager()!=null) {
+			list = new JList();
+			listModel = new DefaultListModel();
+			list.setModel(listModel);
 			return;
+		}
 		instance = this;
 		list = new JList();
 		showWindow();
@@ -507,7 +511,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
 	boolean delete(boolean replacing) {
 		int count = getCount();
 		if (count==0)
-			return error("The list is empty.");
+			return error("The ROI Manager is empty.");
 		int index[] = getSelectedIndexes();
 		if (index.length==0 || (replacing&&count>1)) {
 			String msg = "Delete all items on the list?";
@@ -998,7 +1002,10 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
 		if (!onePerSlice) {
 			int measurements2 = nSlices>1?measurements|Measurements.SLICE:measurements;
 			ResultsTable rt = new ResultsTable();
+			if (appendResults && mmResults2!=null)
+				rt = mmResults2;
 			Analyzer analyzer = new Analyzer(imp, measurements2, rt);
+			analyzer.disableReset(true);
 			for (int slice=1; slice<=nSlices; slice++) {
 				if (nSlices>1) imp.setSliceWithoutUpdate(slice);
 				for (int i=0; i<indexes.length; i++) {
@@ -1008,6 +1015,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
 						break;
 				}
 			}
+			mmResults2 = (ResultsTable)rt.clone();
 			rt.show("Results");
 			if (nSlices>1)
 				imp.setSlice(currentSlice);
@@ -1377,6 +1385,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
 				if (ip==null)
 					ip = new ByteProcessor(imp.getWidth(), imp.getHeight());
 				roi = convertLineToPolygon(roi, ip);
+				if (roi==null) continue;
 			}
 			if (s1==null) {
 				if (roi instanceof ShapeRoi)
@@ -1775,13 +1784,23 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
 			return new RoiManager();
 	}
 
-	/** Returns a reference to the ROI Manager, or null if it is not open.
+	/** Returns a reference to the ROI Manager, or null if it is not open
+	 * and a batch mode macro is not running. If the ROI Manager 
+	 * is not open and a batch mode macro is running, 
+	 * returns the hidden batch mode RoiManager.
 	 * @see #getRoiManager
 	*/
 	public static RoiManager getInstance() {
-		return (RoiManager)instance;
+		if (instance==null && IJ.isMacro())
+			return Interpreter.getBatchModeRoiManager();
+		else
+			return (RoiManager)instance;
 	}
 	
+	public static RoiManager getRawInstance() {
+		return (RoiManager)instance;
+	}
+
 	/** Returns a reference to the ROI Manager window or to the
 		macro batch mode RoiManager, or null if neither exists. */
 	public static RoiManager getInstance2() {
@@ -1822,7 +1841,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
 	
 	/** Returns the ROI count. */
 	public int getCount() {
-		return listModel.getSize();
+		return listModel!=null?listModel.getSize():0;
 	}
 
 	/** Returns the index of the specified Roi, or -1 if it is not found. */
@@ -2222,7 +2241,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
 	public void close() {
 		super.close();
 		instance = null;
-		mmResults = null;
+		mmResults = mmResults2 = null;
 		Prefs.saveLocation(LOC_KEY, getLocation());
 		if (!showAllCheckbox.getState() || IJ.macroRunning())
 			return;
@@ -2255,7 +2274,7 @@ public class RoiManager extends PlugInFrame implements ActionListener, ItemListe
 			overlay = newOverlay();
 		for (int i=0; i<n; i++) {
 			Roi roi = (Roi)rois[i].clone();
-			if (!Prefs.showAllSliceOnly)
+			if (!Prefs.showAllSliceOnly && !IJ.isMacro())
 				roi.setPosition(0);
 			if (roi.getStrokeWidth()==1)
 				roi.setStrokeWidth(0);
diff --git a/ij/plugin/frame/ThresholdAdjuster.java b/ij/plugin/frame/ThresholdAdjuster.java
index 2e71821..0235f05 100644
--- a/ij/plugin/frame/ThresholdAdjuster.java
+++ b/ij/plugin/frame/ThresholdAdjuster.java
@@ -67,13 +67,13 @@ public class ThresholdAdjuster extends PlugInDialog implements PlugIn, Measureme
 		ImagePlus cimp = WindowManager.getCurrentImage();
 		if (cimp!=null && cimp.getBitDepth()==24) {
 			IJ.error("Threshold Adjuster",
-				"Image>Adjust>Threshold only works with grayscale images.\n"
-				+"What you can do:\n"
-				+"   Image>Type>8-bit (convert to grayscale)\n"
-				+"   Image>Type>RGB Stack (convert to RGB stack)\n"
-				+"   Image>Type>HSB Stack (convert to HSB stack)\n"
-				+"   Image>Color>Split Channels (convert to 3 grayscale images)\n"
-				+"   Image>Adjust>Color Threshold (do color thresholding)\n");
+				"Image>Adjust>Threshold only works with grayscale images.\n \n"
+				+"You can:\n"
+				+"   Convert to grayscale: Image>Type>8-bit\n"
+				+"   Convert to RGB stack: Image>Type>RGB Stack\n"
+				+"   Convert to HSB stack: Image>Type>HSB Stack\n"
+				+"   Convert to 3 grayscale images: Image>Color>Split Channels\n"
+				+"   Do color thresholding: Image>Adjust>Color Threshold\n");
 			return;
 		}
 		if (instance!=null) {
@@ -903,7 +903,7 @@ class ThresholdPlot extends Canvas implements Measurements, MouseListener {
 
 	ImageStatistics setHistogram(ImagePlus imp, boolean entireStack) {
 		if (IJ.debugMode) IJ.log("ThresholdAdjuster:setHistogram: "+entireStack+" "+entireStack2);
-		double mean = entireStack?imp.getProcessor().getStatistics().mean:0.0;
+		double mean = entireStack?imp.getProcessor().getStats().mean:0.0;
 		if (entireStack && stats!=null && imp.getID()==imageID2 
 		&& entireStack==entireStack2 && mean==mean2)
 			return stats;
@@ -946,7 +946,7 @@ class ThresholdPlot extends Canvas implements Measurements, MouseListener {
 		if (roi!=null && !roi.isArea()) roi = null;
 		ip.setRoi(roi);
 		if (stats==null)
-			stats = ImageStatistics.getStatistics(ip, AREA+MIN_MAX+MODE, null);
+			stats = ip.getStats();
 		if (IJ.debugMode) IJ.log("  stats: "+stats);
 		int maxCount2 = 0;
 		histogram = stats.histogram;
diff --git a/ij/process/AutoThresholder.java b/ij/process/AutoThresholder.java
index 8e35d96..1415aa8 100644
--- a/ij/process/AutoThresholder.java
+++ b/ij/process/AutoThresholder.java
@@ -40,6 +40,8 @@ public class AutoThresholder {
 	/** Calculates and returns a threshold using the specified
 		method and 256 bin histogram. */
 	public int getThreshold(Method method, int[] histogram) {
+		if (histogram==null)
+			throw new IllegalArgumentException("Histogram is null");
 		if (histogram.length!=256)
 			throw new IllegalArgumentException("Histogram length not 256");
 		int threshold = 0;
@@ -628,11 +630,9 @@ public class AutoThresholder {
 		int iter =0;
 		int threshold = -1;
 		double [] iHisto = new double [256];
-
 		for (int i=0; i<256; i++)
 			iHisto[i]=(double) data[i];
-
-		double [] tHisto = iHisto;
+		double [] tHisto = new double[iHisto.length] ;
 
 		while (!bimodalTest(iHisto) ) {
 			 //smooth with a 3 point running mean filter
@@ -640,7 +640,7 @@ public class AutoThresholder {
 				tHisto[i]= (iHisto[i-1] + iHisto[i] +iHisto[i+1])/3;
 			tHisto[0] = (iHisto[0]+iHisto[1])/3; //0 outside
 			tHisto[255] = (iHisto[254]+iHisto[255])/3; //0 outside
-			iHisto = tHisto;
+			System.arraycopy(tHisto, 0, iHisto, 0, iHisto.length) ;
 			iter++;
 			if (iter>10000) {
 				threshold = -1;
diff --git a/ij/process/ByteProcessor.java b/ij/process/ByteProcessor.java
index 462e27f..8dabef8 100644
--- a/ij/process/ByteProcessor.java
+++ b/ij/process/ByteProcessor.java
@@ -80,6 +80,7 @@ public class ByteProcessor extends ImageProcessor {
 		pixels = ((DataBufferByte) buffer).getData();
 		width = raster.getWidth();
 		height = raster.getHeight();
+		resetRoi();
 	}
 
 	/** Creates a ByteProcessor from an ImageProcessor. 16-bit and 32-bit
diff --git a/ij/process/ByteStatistics.java b/ij/process/ByteStatistics.java
index 1db63f2..c7fabb2 100644
--- a/ij/process/ByteStatistics.java
+++ b/ij/process/ByteStatistics.java
@@ -35,7 +35,9 @@ public class ByteStatistics extends ImageStatistics {
 		else
 			getRawStatistics(minThreshold,maxThreshold);
 		if ((mOptions&MIN_MAX)!=0) {
-			if (cTable!=null)
+			if (pixelCount==0)
+				min = max = Double.NaN;
+			else if (cTable!=null)
 				getCalibratedMinAndMax(minThreshold, maxThreshold, cTable);
 			else
 				getRawMinAndMax(minThreshold, maxThreshold);
diff --git a/ij/process/FloatProcessor.java b/ij/process/FloatProcessor.java
index a300229..cd0fe50 100644
--- a/ij/process/FloatProcessor.java
+++ b/ij/process/FloatProcessor.java
@@ -76,6 +76,7 @@ public class FloatProcessor extends ImageProcessor {
 				pixels[i++] = (float)array[x][y];
 			}
 		}
+		resetRoi();
 	}
 
 	/**
@@ -731,7 +732,7 @@ public class FloatProcessor extends ImageProcessor {
 	}
 	
 	/** Returns a duplicate of this image. */ 
-	public ImageProcessor duplicate() { 
+	public ImageProcessor duplicate() {
 		ImageProcessor ip2 = createProcessor(width, height); 
 		float[] pixels2 = (float[])ip2.getPixels(); 
 		System.arraycopy(pixels, 0, pixels2, 0, width*height); 
diff --git a/ij/process/FloatStatistics.java b/ij/process/FloatStatistics.java
index 48776ba..5e58f6b 100644
--- a/ij/process/FloatStatistics.java
+++ b/ij/process/FloatStatistics.java
@@ -238,8 +238,13 @@ public class FloatStatistics extends ImageStatistics {
 			for (int x=rx; x<(rx+rw); x++) {
 				if (mask==null||mask[mi++]!=0) {
 					v = pixels[i];
-					if (v>=minThreshold && v<=maxThreshold)
+					if (v>=minThreshold && v<=maxThreshold) {
+						if (count==pixels2.length) {
+							median = Double.NaN;
+							return;
+						}
 						pixels2[count++] = v;
+					}
 				}
 				i++;
 			}
diff --git a/ij/process/ImageProcessor.java b/ij/process/ImageProcessor.java
index 344b897..5f96fb8 100644
--- a/ij/process/ImageProcessor.java
+++ b/ij/process/ImageProcessor.java
@@ -11,6 +11,7 @@ import ij.gui.Roi;
 import ij.gui.ShapeRoi;
 import ij.gui.Overlay;
 import ij.Prefs;
+import ij.measure.Measurements;
 
 /**
 This abstract class is the superclass for classes that process
@@ -539,7 +540,7 @@ public abstract class ImageProcessor implements Cloneable {
 			ip2.setMask(mask);
 			ip2.setRoi(rect);	
 		}
-		ImageStatistics stats = ip2.getStatistics();
+		ImageStatistics stats = ip2.getStats();
 		AutoThresholder thresholder = new AutoThresholder();
 		int threshold = thresholder.getThreshold(method, stats.histogram);
 		double lower, upper;
@@ -586,7 +587,7 @@ public abstract class ImageProcessor implements Cloneable {
 			ip2.setMask(mask);
 			ip2.setRoi(rect);	
 		}
-		ImageStatistics stats = ip2.getStatistics();
+		ImageStatistics stats = ip2.getStats();
 		int[] histogram = stats.histogram;
 		int originalModeCount = histogram[stats.mode];
 		if (method==ISODATA2) {
@@ -1204,6 +1205,7 @@ public abstract class ImageProcessor implements Cloneable {
 		double r = lineWidth/2.0;
 		int xmin=(int)(xcenter-r+0.5), ymin=(int)(ycenter-r+0.5);
 		int xmax=xmin+lineWidth, ymax=ymin+lineWidth;
+		//if (xcenter<clipXMin || ycenter<clipYMin || xcenter>clipXMax || ycenter>clipYMax ) {
 		if (xmin<clipXMin || ymin<clipYMin || xmax>clipXMax || ymax>clipYMax ) {
 			// draw edge dot
 			double r2 = r*r;
@@ -1224,6 +1226,9 @@ public abstract class ImageProcessor implements Cloneable {
 			}
 			setRoi(xmin, ymin, lineWidth, lineWidth);
 			fill(dotMask);
+			roiX=0; roiY=0; roiWidth=width; roiHeight=height;
+			xMin=1; xMax=width-2; yMin=1; yMax=height-2;
+			mask=null;
 		}
 	}
 	
@@ -2162,6 +2167,20 @@ public abstract class ImageProcessor implements Cloneable {
 	*/
 	public abstract int[] getHistogram();
 	
+	/** Returns the histogram of the image or ROI, using the specified number of bins. */
+	public int[] getHistogram(int nBins) {
+		ImageProcessor ip;
+		if (((this instanceof ByteProcessor)||(this instanceof ColorProcessor)) && nBins!=256)
+			ip = convertToShort(false);
+		else
+			ip = this;
+		ip.setHistogramSize(nBins);
+		ip.setHistogramRange(0.0, 0.0);
+		ImageStatistics stats = ImageStatistics.getStatistics(ip);
+		ip.setHistogramSize(256);
+		return stats.histogram;
+	}
+	
 	/** Erodes the image or ROI using a 3x3 maximum filter. Requires 8-bit or RGB image. */
 	public abstract void erode();
 	
@@ -2346,10 +2365,10 @@ public abstract class ImageProcessor implements Cloneable {
 		The clipping rectangle is reset by passing a null argument or by calling resetRoi(). */
 	public void setClipRect(Rectangle clipRect) {
 		if (clipRect==null) {
-			clipXMin=0; 
-			clipXMax=width-1; 
-			clipYMin=0; 
-			clipYMax=height-1; 
+			clipXMin = 0; 
+			clipXMax = width-1; 
+			clipYMin = 0; 
+			clipYMax = height-1; 
 		} else {
 			clipXMin = clipRect.x; 
 			clipXMax = clipRect.x + clipRect.width - 1; 
@@ -2525,22 +2544,38 @@ public abstract class ImageProcessor implements Cloneable {
 		return false;
 	}
 
+	/** Returns 'true' if this is a signed 16-bit image. */
+	public boolean isSigned16Bit() {
+		return false;
+	}
+
 	/* This method is experimental and may be removed. */
 	public static void setUseBicubic(boolean b) {
 		useBicubic = b;
 	}
 	
-	/** Calculates and returns statistics (area, mean, std-dev, mode, min, max,
-	 * centroid, center of mass, 256 bin histogram) for this image or ROI. Use the
-	 * setRoi(Roi) method to limit statistics to a non-rectangular area.
-	 * @see ImageProcessor#setRoi	
+	/** Calculates and returns uncalibrated statistics for this image or ROI,
+	 * including histogram, area, mean, min and max, standard deviation,
+	 * and mode. Use the setRoi(Roi) method to limit statistics to
+	 * a non-rectangular area.
+	 * @see #setRoi	
+	 * @see #getStatistics	
+	 * @see ImageStatistics	
+	*/
+	public ImageStatistics getStats() {
+		return ImageStatistics.getStatistics(this);
+	}
+		
+	/** This method calculates and returns complete uncalibrated statistics for
+	 * this image or ROI but it is up to 70 times slower than getStats().
+	 * @see #setRoi	
+	 * @see #getStats	
 	 * @see ImageStatistics	
 	*/
 	public ImageStatistics getStatistics() {
-		// 127 = AREA+MEAN+STD_DEV+MODE+MIN_MAX+CENTROID+CENTER_OF_MASS
-		return ImageStatistics.getStatistics(this, 127, null);
+		return ImageStatistics.getStatistics(this, Measurements.ALL_STATS, null);
 	}
-	
+
 	/** Blurs the image by convolving with a Gaussian function. */
 	public void blurGaussian(double sigma) {
 		resetRoi();
diff --git a/ij/process/ImageStatistics.java b/ij/process/ImageStatistics.java
index 49c2af0..c836b36 100644
--- a/ij/process/ImageStatistics.java
+++ b/ij/process/ImageStatistics.java
@@ -64,6 +64,12 @@ public class ImageStatistics implements Measurements {
 	EllipseFitter ef;
 
 	
+	/* Get uncalibrated statistics, including histogram, area, mean, 
+		min and max, standard deviation and mode. */
+	public static ImageStatistics getStatistics(ImageProcessor ip) {
+		return getStatistics(ip, AREA+MEAN+STD_DEV+MODE+MIN_MAX+RECT, null);
+	}
+
 	public static ImageStatistics getStatistics(ImageProcessor ip, int mOptions, Calibration cal) {
 		Object pixels = ip.getPixels();
 		if (pixels instanceof byte[])
diff --git a/ij/process/ShortProcessor.java b/ij/process/ShortProcessor.java
index 4cba2c7..123b0b2 100644
--- a/ij/process/ShortProcessor.java
+++ b/ij/process/ShortProcessor.java
@@ -219,11 +219,6 @@ public class ShortProcessor extends ImageProcessor {
 		return snapshotPixels;
 	}
 
-	/* Obsolete. */
-	//public boolean isUnsigned() {
-	//	return true;
-	//}
-
 	/** Returns the smallest displayed pixel value. */
 	public double getMin() {
 		if (!minMaxSet) findMinAndMax();
@@ -453,7 +448,7 @@ public class ShortProcessor extends ImageProcessor {
 		int v1, v2;
 		double range = getMax()-getMin();
 		//boolean resetMinMax = roiWidth==width && roiHeight==height && !(op==FILL);
-		int offset = cTable!=null&&cTable[0]==-32768f?32768:0; // signed images have 32768 offset
+		int offset = isSigned16Bit()?32768:0;
 		int min2 = (int)getMin() - offset;
 		int max2 = (int)getMax() - offset;
 		int fgColor2 = fgColor - offset;
@@ -705,7 +700,7 @@ public class ShortProcessor extends ImageProcessor {
 		double xlimit = width-1.0, xlimit2 = width-1.001;
 		double ylimit = height-1.0, ylimit2 = height-1.001;
 		// zero is 32768 for signed images
-		int background = cTable!=null && cTable[0]==-32768?32768:0; 
+		int background = isSigned16Bit()?32768:0; 
 		
 		if (interpolationMethod==BICUBIC) {
 			for (int y=roiY; y<(roiY + roiHeight); y++) {
@@ -938,7 +933,7 @@ public class ShortProcessor extends ImageProcessor {
 			setValue(bestIndex);
 			setMinAndMax(0.0,255.0);
 		} else if (bestIndex==0 && getMin()>0.0 && (color.getRGB()&0xffffff)==0) {
-			if (cTable!=null&&cTable[0]==-32768f) // signed image
+			if (isSigned16Bit())
 				setValue(32768);
 			else
 				setValue(0.0);
@@ -1157,6 +1152,11 @@ public class ShortProcessor extends ImageProcessor {
 		return 16;
 	}
 
+	/** Returns 'true' if this is a signed 16-bit image. */
+	public boolean isSigned16Bit() {
+		return cTable!=null && cTable[0]==-32768f && cTable[1]==-32767f;
+	}
+
 	/** Not implemented. */
 	public void medianFilter() {}
 	/** Not implemented. */
diff --git a/ij/text/TextCanvas.java b/ij/text/TextCanvas.java
index 6745096..76b1e23 100644
--- a/ij/text/TextCanvas.java
+++ b/ij/text/TextCanvas.java
@@ -32,16 +32,16 @@ class TextCanvas extends Canvas {
 	}
   
 	public void paint(Graphics g) {
-		if(tp==null || g==null) return;
+		if (tp==null || g==null) return;
 		Dimension d = getSize();
 		int iWidth = d.width;
 		int iHeight = d.height;
 		
-		if(iWidth<=0 || iHeight<=0) return;
+		if (iWidth<=0 || iHeight<=0) return;
 		g.setColor(Color.lightGray);
-		if(iImage==null)
+		if (iImage==null)
 			makeImage(iWidth,iHeight);
-		if(tp.iRowHeight==0 || (tp.iColWidth[0]==0&&tp.iRowCount>0)) {
+		if (tp.iRowHeight==0 || (tp.iColWidth[0]==0&&tp.iRowCount>0)) {
 			tp.iRowHeight=fMetrics.getHeight()+2;
 			for(int i=0;i<tp.iColCount;i++)
 				calcAutoWidth(i);
@@ -54,15 +54,15 @@ class TextCanvas extends Canvas {
 			drawColumnLabels(iWidth);
 		int y=tp.iRowHeight+1-tp.iY;
 		int j=0;
-		while(y<tp.iRowHeight+1) {
+		while (y<tp.iRowHeight+1) {
 			j++;
 			y+=tp.iRowHeight;
 		}
 		tp.iFirstRow=j;
 		y=tp.iRowHeight+1;
-		for(;y<iHeight && j<tp.iRowCount;j++,y+=tp.iRowHeight) {
+		for (;y<iHeight && j<tp.iRowCount; j++,y+=tp.iRowHeight) {
 			int x=-tp.iX;
-			for(int i=0;i<tp.iColCount;i++) {
+			for (int i=0;i<tp.iColCount;i++) {
 				int w=tp.iColWidth[i];
 				Color b=Color.white,t=Color.black;
 				if(j>=tp.selStart && j<=tp.selEnd) {
@@ -123,7 +123,7 @@ class TextCanvas extends Canvas {
 		gImage.drawLine(0,0,iWidth,0);
 	}
 	
-	char[] getChars(int column, int row) {
+	synchronized char[] getChars(int column, int row) {
 		if (tp==null || tp.vData==null)
 			return null;
 		if (row>=tp.vData.size())
@@ -132,13 +132,8 @@ class TextCanvas extends Canvas {
 		if (chars.length==0)
 			return null;
 		
-		if (tp.iColCount==1) {
-	    	//for (int i=0; i<chars.length; i++) {
-	    	//	if (chars[i]<' ')
-	    	//		chars[i] = ' ';
-	    	//}
-	    	return chars;
-	    }
+		if (tp.iColCount==1)
+			return chars;
 	    
 	    int start = 0;
 	    int tabs = 0;
diff --git a/ij/text/TextPanel.java b/ij/text/TextPanel.java
index 2cdab01..b392bdb 100644
--- a/ij/text/TextPanel.java
+++ b/ij/text/TextPanel.java
@@ -286,12 +286,17 @@ public class TextPanel extends Panel implements AdjustmentListener,
 	}
 	
 	void handleDoubleClick() {
-		if (selStart<0 || selStart!=selEnd || iColCount!=1) return;
+		boolean overlayList = "Overlay Elements".equals(title);
+		if (selStart<0 || selStart!=selEnd || (iColCount!=1&&!overlayList)) return;
 		boolean doubleClick = System.currentTimeMillis()-mouseDownTime<=DOUBLE_CLICK_THRESHOLD;
 		mouseDownTime = System.currentTimeMillis();
 		if (doubleClick) {
 			char[] chars = (char[])(vData.elementAt(selStart));
 			String s = new String(chars);
+			if (overlayList) {
+				handleDoubleClickInOverlayList(s);
+				return;
+			}
 			int index = s.indexOf(": ");
 			if (index>-1 && !s.endsWith(": "))
 				s = s.substring(index+2); // remove sequence number added by ListFilesRecursively
@@ -304,6 +309,19 @@ public class TextPanel extends Panel implements AdjustmentListener,
 		}
 	}
 	
+	private void handleDoubleClickInOverlayList(String s) {
+		ImagePlus imp = WindowManager.getCurrentImage();
+		if (imp==null)
+			return;
+		Overlay overlay = imp.getOverlay();
+		if (overlay==null)
+			return;
+		String[] columns = s.split("\t");
+		int index = (int)Tools.parseDouble(columns[0]);
+		Roi roi = overlay.get(index);
+		imp.setRoi(roi);
+	}
+	
     /** For better performance, open double-clicked files on 
     	separate thread instead of on event dispatch thread. */
     public void run() {
@@ -745,7 +763,7 @@ public class TextPanel extends Panel implements AdjustmentListener,
 	}
 
 	/** Deletes all the lines. */
-	public void clear() {
+	public synchronized void clear() {
 		if (vData==null) return;
 		vData.removeAllElements();
 		iRowCount = 0;
diff --git a/release-notes.html b/release-notes.html
index f8dd615..5729f94 100644
--- a/release-notes.html
+++ b/release-notes.html
@@ -5,26 +5,46 @@
 </head>
 <body>
 
-<li> <u>1.50i 25 March 2016</u>
+<li> <u>1.51i 16 December 2016</u>
 <ul>
-<li> The ImageJ website
-(<a href="http://imagej.nih.gov/ij">imagej.nih.gov/ij</a>)
-will soon start using encryption incompatible
-with Java so sample images and updates are now downloaded from
-<a href="http://wsr.imagej.net">wsr.imagej.net</a>
-and URLs used to open images and text files 
-are redirected to
-<a href="http://mirror.imagej.net">mirror.imagej.net</a>.
-<li> Thanks to Thorsten Wagner, added the is("global calibration") macro function.
-<li> Thanks to Philippe Carl, added the RoiManager.rename(index,name) method.
-<li> Thanks to Nicolas Cedilnik and Mark Hiner, fixed a bug that could cause an
-exception when saving a virtual stack.
-<li> Thanks to Kees Straatman, fixed a bug that caused the ROI Manager's "Multi Measure"
-command to sometimes not work as expected when the "append" option was used.
-<li> Fixed a bug that caused the "Decimal Places" field in the <i>Analyze>Set Measurements</i>
-dialog to be ignored after the value was set to zero.
-<li> Thanks to Stein Rorvik, fixed a 1.50d regression that caused duplicated images
-to lose their density calibration.
+<li> Thanks to John Brear, the particle analyzer allows particles to
+be selected on circularity values greater than 1.0.
+<li> Thanks to Johan Doornenbal, the <i>Image>Scale</i> command works
+when Width or Height are not given.
+<li> Thanks to Mirekslouf, labeling of point selections in overlays now
+reflects the state of the "Label points" checkbox in the "Point Tool" dialog. 
+<li> Thanks to Bastian Schmidt, added code to the DICOM importer to handle tags of
+type SS (signed 16-bit), UL (unsigned 32-bit) and SL (signed 32-bit).
+<li> Thanks to Michael Schmid, added static ZAxisProfiler.getPlot(ImagePlus) and
+ZAxisProfiler.getPlot(ImagePlus,String) methods, where the string argument can
+be either "time" or "z-axis".
+<li> Added the ImagePlus.getAllStatistics() method and removed
+the median calculation done in the ImagePlus.getStatistics() method
+in previous versions of ImageJ 1.51.
+<li> Thanks to Benjamen Gyori, added the ImageProcessor.getStats() method,
+which is up to 70 times faster than ImageProcessor.getStatistics().
+<li> Added the FolderOpener.open(path,"virtual") method.
+<li> Thanks to Michael Schmid, added static getNumParams() methods
+to the CurveFitter class.
+<li> Thanks to Gabriel Landini, fixed a bug that caused the <i>Image>Duplicate</i>
+command to not be correctly recorded with single images when the recorder
+was not in "Macro" mode.
+<li> Thanks to Gunjan Pandey, fixed a bug that caused plugins that used the
+ROI Manager to fail when they were called from batch mode macros. Note
+that the ROI Manager is not displayed in batch mode macros unless it is opened
+using run("ROI Manager�") prier to entering batch mode.
+<li> Thanks to Olivier Burri, fixed a bug the caused the "Append results" option
+of the ROI Manager's "Multi Measure" command to be ignored if the
+"One row per slice" option was not enabled.
+<li> Fixed a bug that sometimes caused the doCommand("Point Tool...") macro 
+function to display the legacy point tool dialog instead of the non-modal
+multi-point tool dialog.
+<li> Worked around a OS X/Java 8 bug that caused image windows to
+be maximized when moved if a modal GenericDialog was open.
+<li> Thanks to Norbert Vischer, fixed a v1.50 regression that caused the
+<i>Edit>Selection>Properties</i> command to not work as expected
+with multi-point selections. Use the alt+y shortcut to display
+multi-point selection counts.
 </ul>
 
 <a href="http://imagej.nih.gov/ij">Home</a>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/imagej.git



More information about the debian-med-commit mailing list