Skip to content
Commits on Source (9)
imagej (1.52r-1) unstable; urgency=medium
* Team upload
* Correct sorting of Java alternatives in Wrapper script
* Avoid dpkg-architecture in wrapper script which is not necessarily
installed on users machine and use dpkg --print-architecture instead
Closes: #931268
* Standards-Version: 4.4.1
* Fix day-of-week for changelog entries 1.39q-2.
-- Andreas Tille <tille@debian.org> Wed, 04 Dec 2019 14:35:53 +0100
imagej (1.52p-1) unstable; urgency=medium
* Team upload.
......@@ -432,7 +444,7 @@ imagej (1.39q-2) unstable; urgency=high
* New man page.
-- Paolo Ariano <paolo.ariano@unito.it> Fri, 06 Mar 2008 15:29:56 +0100
-- Paolo Ariano <paolo.ariano@unito.it> Thu, 06 Mar 2008 15:29:56 +0100
imagej (1.39q-1) unstable; urgency=low
......
......@@ -9,7 +9,7 @@ Build-Depends-Indep: ant,
default-jdk-headless,
javahelper,
maven-repo-helper
Standards-Version: 4.4.0
Standards-Version: 4.4.1
Vcs-Browser: https://salsa.debian.org/med-team/imagej
Vcs-Git: https://salsa.debian.org/med-team/imagej.git
Homepage: https://imagej.nih.gov/ij
......
......@@ -29,7 +29,7 @@ shopt -s extglob # allow extended pattern matching
if [ -z "$JAVA_HOME" ] ; then
# This does not work see #505315
JAVA_HOME=`/usr/sbin/update-java-alternatives -l | grep openjdk | grep $(dpkg-architecture -q DEB_TARGET_ARCH) | sort | tail -1 | tr -s ' ' | cut -d' ' -f 3`
JAVA_HOME=`/usr/sbin/update-java-alternatives -l | grep openjdk | grep $(dpkg --print-architecture) | sort -u -k2 | tail -1 | tr -s ' ' | cut -d' ' -f 3`
# Reverted to old version - see #558222 (Andreas Tille)
# JAVA_HOME=$(dirname $(dirname $(dirname $(readlink /etc/alternatives/java))))
# Also suggested by From: JR Coding <jr.coding@googlemail.com>; To: 740439@bugs.debian.org
......
......@@ -17,23 +17,23 @@ public class Executer implements Runnable {
private static String previousCommand;
private static CommandListener listener;
private static Vector listeners = new Vector();
private String command;
private Thread thread;
/** Create an Executer to run the specified menu command
in this thread using the active image. */
public Executer(String cmd) {
command = cmd;
}
/** Create an Executer that runs the specified menu
/** Create an Executer that runs the specified menu
command in a separate thread using the specified image,
or using the active image if 'imp' is null. */
public Executer(String cmd, ImagePlus imp) {
if (cmd.startsWith("Repeat")) {
command = previousCommand;
IJ.setKeyUp(KeyEvent.VK_SHIFT);
IJ.setKeyUp(KeyEvent.VK_SHIFT);
} else {
command = cmd;
if (!(cmd.equals("Undo")||cmd.equals("Close")))
......@@ -117,7 +117,7 @@ public class Executer implements Runnable {
WindowManager.setTempCurrentImage(null);
}
}
void runCommand(String cmd) {
Hashtable table = Menus.getCommands();
String className = (String)table.get(cmd);
......@@ -131,6 +131,17 @@ public class Executer implements Runnable {
className = className.substring(0, argStart);
}
}
if (Prefs.nonBlockingFilterDialogs) {
// we have the plugin class name, let us see whether it is allowed to run it
ImagePlus imp = WindowManager.getCurrentImage();
boolean imageLocked = imp!=null && imp.isLockedByAnotherThread();
if (imageLocked && !allowedWithLockedImage(className)) {
IJ.beep();
IJ.showStatus("\""+cmd + "\" blocked because \"" + imp.getTitle() + "\" is locked");
return;
}
}
// run the plugin
if (IJ.shiftKeyDown() && className.startsWith("ij.plugin.Macro_Runner") && !Menus.getShortcuts().contains("*"+cmd))
IJ.open(IJ.getDirectory("plugins")+arg);
else
......@@ -159,7 +170,17 @@ public class Executer implements Runnable {
IJ.error("Unrecognized command: \"" + cmd+"\"");
}
}
}
}
/** If the foreground image is locked during a filter operation with NonBlockingGenericDialog,
* the following plugins are allowed */
boolean allowedWithLockedImage(String className) {
return className.equals("ij.plugin.Zoom") ||
className.equals("ij.plugin.frame.ContrastAdjuster") ||
className.equals("ij.plugin.SimpleCommands") || //includes Plugins>Utiltites>Reset (needed to reset a locked image)
className.equals("ij.plugin.WindowOrganizer") ||
className.equals("ij.plugin.URLOpener");
}
/** Opens a .lut file from the ImageJ/luts directory and returns 'true' if successful. */
public static boolean loadLut(String name) {
......@@ -182,7 +203,7 @@ public class Executer implements Runnable {
return false;
}
/** Opens a file from the File/Open Recent menu
/** Opens a file from the File/Open Recent menu
and returns 'true' if successful. */
boolean openRecent(String cmd) {
Menu menu = Menus.getOpenRecentMenu();
......@@ -201,17 +222,17 @@ public class Executer implements Runnable {
public static String getCommand() {
return previousCommand;
}
/** Adds the specified command listener. */
public static void addCommandListener(CommandListener listener) {
listeners.addElement(listener);
}
/** Removes the specified command listener. */
public static void removeCommandListener(CommandListener listener) {
listeners.removeElement(listener);
}
public static int getListenerCount() {
return listeners.size();
}
......
......@@ -24,6 +24,7 @@ import java.net.*;
import javax.net.ssl.*;
import java.security.cert.*;
import java.security.KeyStore;
import java.nio.ByteBuffer;
/** This class consists of static utility methods. */
......@@ -564,9 +565,52 @@ public class IJ {
'row1' and 'row2' must be in the range 0-Analyzer.getCounter()-1. */
public static void deleteRows(int row1, int row2) {
ResultsTable rt = Analyzer.getResultsTable();
int tableSize = rt.size();
rt.deleteRows(row1, row2);
ImagePlus imp = WindowManager.getCurrentImage();
if (imp!=null)
Overlay.updateTableOverlay(imp, row1, row2, tableSize);
rt.show("Results");
}
/** Returns a measurement result, where 'measurement' is "Area",
* "Mean", "StdDev", "Mode", "Min", "Max", "X", "Y", "XM", "YM",
* "Perim.", "BX", "BY", "Width", "Height", "Major", "Minor", "Angle",
* "Circ.", "Feret", "IntDen", "Median", "Skew", "Kurt", "%Area",
* "RawIntDen", "Ch", "Slice", "Frame", "FeretX", "FeretY",
* "FeretAngle", "MinFeret", "AR", "Round", "Solidity", "MinThr"
* or "MaxThr". Add " raw" to the argument to disable calibration,
* for example IJ.getValue("Mean raw"). Add " limit" to enable
* the "limit to threshold" option.
*/
public static double getValue(ImagePlus imp, String measurement) {
String options = "";
int index = measurement.indexOf(" ");
if (index>0) {
if (index<measurement.length()-1)
options = measurement.substring(index+1, measurement.length());
measurement = measurement.substring(0, index);
}
int measurements = Measurements.ALL_STATS + Measurements.SLICE;
if (options.contains("limit"))
measurements += Measurements.LIMIT;
Calibration cal = null;
if (options.contains("raw")) {
cal = imp.getCalibration();
imp.setCalibration(null);
}
ImageStatistics stats = imp.getStatistics(measurements);
ResultsTable rt = new ResultsTable();
Analyzer analyzer = new Analyzer(imp, measurements, rt);
analyzer.saveResults(stats, imp.getRoi());
double value = Double.NaN;
try {
value = rt.getValue(measurement, 0);
} catch (Exception e) {};
if (cal!=null)
imp.setCalibration(cal);
return value;
}
/** Returns a reference to the "Results" window TextPanel.
Opens the "Results" window if it is currently not open.
......@@ -894,6 +938,14 @@ public class IJ {
return str;
}
/** Pad 's' with leading zeros to the specified number of digits. */
public static String pad(String s, int digits) {
String str = ""+s;
while (str.length()<digits)
str = "0"+str;
return str;
}
/** Adds the specified class to a Vector to keep it from being garbage
collected, which would cause the classes static fields to be reset.
Probably not needed with Java 1.2 or later. */
......@@ -1644,8 +1696,8 @@ public class IJ {
return ImageJ.VERSION+build;
}
/** Returns the path to the home ("user.home"), startup, ImageJ, plugins, macros,
luts, temp, current or image directory if <code>title</code> is "home", "startup",
/** Returns the path to the home ("user.home"), downloads, startup, ImageJ, plugins, macros,
luts, temp, current or image directory if <code>title</code> is "home", "downloads", "startup",
"imagej", "plugins", "macros", "luts", "temp", "current", "default", "image", otherwise,
displays a dialog and returns the path to the directory selected by the user.
Returns null if the specified directory is not found or the user
......@@ -1665,6 +1717,8 @@ public class IJ {
return null;
} else if (title2.equals("home"))
return System.getProperty("user.home") + File.separator;
else if (title2.equals("downloads"))
return System.getProperty("user.home")+File.separator+"Downloads"+File.separator;
else if (title2.equals("startup"))
return Prefs.getImageJDir();
else if (title2.equals("imagej"))
......@@ -2062,6 +2116,34 @@ public class IJ {
}
return str;
}
public static ByteBuffer openAsByteBuffer(String path) {
if (path==null || path.equals("")) {
OpenDialog od = new OpenDialog("Open as ByteBuffer", "");
String directory = od.getDirectory();
String name = od.getFileName();
if (name==null) return null;
path = directory + name;
}
File file = new File(path);
if (!file.exists()) {
error("OpenAsByteBuffer", "File not found");
return null;
}
int len = (int)file.length();
byte[] buffer = new byte[len];
try {
InputStream in = new BufferedInputStream(new FileInputStream(path));
DataInputStream dis = new DataInputStream(in);
dis.readFully(buffer);
dis.close();
}
catch (Exception e) {
error("OpenAsByteBuffer", e.getMessage());
return null;
}
return ByteBuffer.wrap(buffer);
}
/** Creates a new image.
* @param title image name
......
......@@ -77,8 +77,8 @@ 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.52p";
public static final String BUILD = ""; //61
public static final String VERSION = "1.52r";
public static final String BUILD = ""; //57
public static Color backgroundColor = new Color(237,237,237);
/** SansSerif, 12-point, plain font. */
public static final Font SansSerif12 = new Font("SansSerif", Font.PLAIN, 12);
......@@ -265,6 +265,8 @@ public class ImageJ extends Frame implements ActionListener,
props.put("proxySet", "true");
props.put("http.proxyHost", server);
props.put("http.proxyPort", ""+port);
props.put("https.proxyHost", server);
props.put("https.proxyPort", ""+port);
}
//new ProxySettings().logProperties();
}
......@@ -281,7 +283,8 @@ public class ImageJ extends Frame implements ActionListener,
int ijY = Prefs.getInt(IJ_Y,-99);
Rectangle maxBounds = GUI.getMaxWindowBounds();
//System.out.println("getPreferredLoc1: "+ijX+" "+ijY+" "+maxBounds);
if (ijX>=maxBounds.x && ijY>=maxBounds.y && ijX<(maxBounds.x+maxBounds.width-75))
if (ijX>=maxBounds.x && ijY>=maxBounds.y && ijX<(maxBounds.x+maxBounds.width-75)
&& ijY<(maxBounds.y+maxBounds.height-75))
return new Point(ijX, ijY);
Dimension tbsize = toolbar.getPreferredSize();
int ijWidth = tbsize.width+10;
......
This diff is collapsed.
......@@ -1231,13 +1231,6 @@ public class Menus {
else if (stack.isLab())
type = LAB_STACK;
}
if (type==ImagePlus.GRAY8) {
ImageProcessor ip = imp.getProcessor();
if (ip!=null && ip.getMinThreshold()==ImageProcessor.NO_THRESHOLD && ip.isColorLut() && !ip.isPseudoColorLut()) {
type = ImagePlus.COLOR_256;
imp.setType(ImagePlus.COLOR_256);
}
}
switch (type) {
case ImagePlus.GRAY8:
gray8Item.setState(true);
......
......@@ -57,7 +57,8 @@ public class Prefs {
SUBPIXEL_RESOLUTION=1<<2, ENHANCED_LINE_TOOL=1<<3, SKIP_RAW_DIALOG=1<<4,
REVERSE_NEXT_PREVIOUS_ORDER=1<<5, AUTO_RUN_EXAMPLES=1<<6, SHOW_ALL_POINTS=1<<7,
DO_NOT_SAVE_WINDOW_LOCS=1<<8, JFILE_CHOOSER_CHANGED=1<<9,
CANCEL_BUTTON_ON_RIGHT=1<<10, IGNORE_RESCALE_SLOPE=1<<11;
CANCEL_BUTTON_ON_RIGHT=1<<10, IGNORE_RESCALE_SLOPE=1<<11,
NON_BLOCKING_DIALOGS=1<<12;
public static final String OPTIONS2 = "prefs.options2";
/** file.separator system property */
......@@ -183,6 +184,8 @@ public class Prefs {
public static boolean dialogCancelButtonOnRight;
/** Support TRANSFORM Undo in macros */
public static boolean supportMacroUndo;
/** Use NonBlockingGenericDialogs in filters */
public static boolean nonBlockingFilterDialogs;
static boolean commandLineMacro;
static Properties ijPrefs = new Properties();
......@@ -525,7 +528,7 @@ public class Prefs {
jFileChooserSettingChanged = (options2&JFILE_CHOOSER_CHANGED)!=0;
dialogCancelButtonOnRight = (options2&CANCEL_BUTTON_ON_RIGHT)!=0;
ignoreRescaleSlope = (options2&IGNORE_RESCALE_SLOPE)!=0;
;
nonBlockingFilterDialogs = (options2&NON_BLOCKING_DIALOGS)!=0;
}
static void saveOptions(Properties prefs) {
......@@ -555,7 +558,8 @@ public class Prefs {
+ (doNotSaveWindowLocations?DO_NOT_SAVE_WINDOW_LOCS:0)
+ (jFileChooserSettingChanged?JFILE_CHOOSER_CHANGED:0)
+ (dialogCancelButtonOnRight?CANCEL_BUTTON_ON_RIGHT:0)
+ (ignoreRescaleSlope?IGNORE_RESCALE_SLOPE:0);
+ (ignoreRescaleSlope?IGNORE_RESCALE_SLOPE:0)
+ (nonBlockingFilterDialogs?NON_BLOCKING_DIALOGS:0);
prefs.put(OPTIONS2, Integer.toString(options2));
}
......
......@@ -27,9 +27,18 @@ public class VirtualStack extends ImageStack {
super(width, height);
}
/** Creates an empty virtual stack. */
/** Creates an empty virtual stack.
* @param width image width
* @param height image height
* @param cm ColorModel or null
* @param path file path of directory containing the images
* @see #addSlice(String)
* @see <a href="http://wsr.imagej.net/macros/js/OpenAsVirtualStack.js">OpenAsVirtualStack.js</a>
*/
public VirtualStack(int width, int height, ColorModel cm, String path) {
super(width, height, cm);
if (path.length()>0 && !(path.endsWith(File.separator)||path.endsWith("/")))
path = path + "/";
this.path = path;
names = new String[INITIAL_SIZE];
labels = new String[INITIAL_SIZE];
......@@ -50,12 +59,18 @@ public class VirtualStack extends ImageStack {
bitDepth = 8;
}
/** Adds an image to the end of the stack. */
public void addSlice(String name) {
if (name==null)
throw new IllegalArgumentException("'name' is null!");
/** Adds an image to the end of the stack. The argument
* can be a full file path (e.g., "C:/Users/wayne/dir1/image.tif")
* if the 'path' argument in the constructor is "". File names
* that start with '.' are ignored.
*/
public void addSlice(String fileName) {
if (fileName==null)
throw new IllegalArgumentException("'fileName' is null!");
if (fileName.startsWith("."))
return;
nSlices++;
//IJ.log("addSlice: "+nSlices+" "+name);
//IJ.log("addSlice: "+nSlices+" "+fileName);
if (nSlices==names.length) {
String[] tmp = new String[nSlices*2];
System.arraycopy(names, 0, tmp, 0, nSlices);
......@@ -64,7 +79,7 @@ public class VirtualStack extends ImageStack {
System.arraycopy(labels, 0, tmp, 0, nSlices);
labels = tmp;
}
names[nSlices-1] = name;
names[nSlices-1] = fileName;
}
/** Does nothing. */
......@@ -123,7 +138,7 @@ public class VirtualStack extends ImageStack {
Opener opener = new Opener();
opener.setSilentMode(true);
IJ.redirectErrorMessages(true);
ImagePlus imp = opener.openImage(path, names[n-1]);
ImagePlus imp = opener.openImage(path+names[n-1]);
IJ.redirectErrorMessages(false);
ImageProcessor ip = null;
int depthThisImage = 0;
......
......@@ -80,6 +80,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
private static GenericDialog instance;
private boolean firstPaint = true;
private boolean fontSizeSet;
private boolean showDialogCalled;
/** Creates a new GenericDialog with the specified title. Uses the current image
......@@ -120,6 +121,17 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
addWindowListener(this);
}
/** Adds a numeric field. The first word of the label must be
unique or command recording will not work.
* @param label the label
* @param defaultValue value to be initially displayed
*/
public void addNumericField(String label, double defaultValue) {
int decimalPlaces = (int)defaultValue==defaultValue?0:3;
int columnWidth = decimalPlaces==3?8:6;
addNumericField(label, defaultValue, decimalPlaces, columnWidth, null);
}
/** Adds a numeric field. The first word of the label must be
unique or command recording will not work.
* @param label the label
......@@ -210,7 +222,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
labels = new Hashtable();
if (label.length()>0)
label = Macro.trimKey(label.trim());
if (hasLabel(label)) { // not a unique label?
if (label.length()>0 && hasLabel(label)) { // not a unique label?
label += "_0";
for (int n=1; hasLabel(label); n++) { // while still not a unique label
label = label.substring(0, label.lastIndexOf('_')); //remove counter
......@@ -241,6 +253,8 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
* @param columns width of the text field. If columns is 8 or more, additional items may be added to this line with addToSameRow()
*/
public void addStringField(String label, String defaultText, int columns) {
if (addToSameRow && label.equals("_"))
label = "";
String label2 = label;
if (label2.indexOf('_')!=-1)
label2 = label2.replace('_', ' ');
......@@ -628,13 +642,15 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
}
addSlider( label, minValue, maxValue, defaultValue, scale, digits);
}
/** This vesion of addSlider() adds a 'stepSize' argument.<br>
* Example: http://wsr.imagej.net/macros/SliderDemo.txt
*/
public void addSlider(String label, double minValue, double maxValue, double defaultValue, double stepSize) {
if ( stepSize <= 0 ) stepSize = 1;
int digits = digits(stepSize);
int digits = digits(stepSize);
if (digits==1 && "Angle:".equals(label))
digits = 2;
double scale = 1.0 / Math.abs( stepSize );
if ( scale <= 0 ) scale = 1;
if ( defaultValue < minValue ) defaultValue = minValue;
......@@ -644,7 +660,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
defaultValue *= scale;
addSlider(label, minValue, maxValue, defaultValue, scale, digits);
}
private int digits( double d ) {
if ( d == (int) d ) return 0;
String s = Double.toString(d);
......@@ -656,6 +672,9 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
int columns = 4 + digits - 2;
if ( columns < 4 ) columns = 4;
if (minValue<0.0) columns++;
String mv = IJ.d2s(maxValue,0);
if (mv.length()>4 && digits==0)
columns += mv.length()-4;
String label2 = label;
if (label2.indexOf('_')!=-1)
label2 = label2.replace('_', ' ');
......@@ -676,12 +695,14 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
slider = new Vector(5);
sliderIndexes = new Vector(5);
sliderScales = new Vector(5);
sliderDigits = new Vector(5);
sliderDigits = new Vector(5);
}
Scrollbar s = new Scrollbar(Scrollbar.HORIZONTAL, (int)defaultValue, 1, (int)minValue, (int)maxValue+1);
slider.addElement(s);
s.addAdjustmentListener(this);
s.setUnitIncrement(1);
if (IJ.isMacOSX())
s.addKeyListener(this);
if (numberField==null) {
numberField = new Vector(5);
......@@ -789,7 +810,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
* addMessage, addPanel, and before the showDialog() method
* (in the latter case, the buttons appear to the right of the previous item).
* Note that addMessage (and addStringField, if its column width is more than 8) use
* the remaining width, so it must be the last item of a row.
* the remaining width, so it must be the last item of a row.
*/
public void addToSameRow() {
addToSameRow = true;
......@@ -884,12 +905,12 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
/** Returns the contents of the next numeric field,
or NaN if the field does not contain a number. */
public double getNextNumber() {
public double getNextNumber() {
if (numberField==null)
return -1.0;
TextField tf = (TextField)numberField.elementAt(nfIndex);
String theText = tf.getText();
String label=null;
String label=null;
if (macro) {
label = (String)labels.get((Object)tf);
theText = Macro.getValue(macroOptions, label, theText);
......@@ -920,7 +941,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
+" Key: \""+label.toLowerCase(Locale.US)+"\"\n"
+" Value or variable name: \""+theText+"\"");
}
}
}
}
}
if (recorderOn && !skipRecording) {
......@@ -995,8 +1016,8 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
return "";
TextField tf = (TextField)(stringField.elementAt(sfIndex));
theText = tf.getText();
String label = labels!=null?(String)labels.get((Object)tf):"";
if (macro) {
String label = (String)labels.get((Object)tf);
theText = Macro.getValue(macroOptions, label, theText);
if (theText!=null && (theText.startsWith("&")||label.toLowerCase(Locale.US).startsWith(theText))) {
// Is the value a macro variable?
......@@ -1006,7 +1027,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
if (s!=null) theText = s;
}
}
if (recorderOn) {
if (recorderOn && !label.equals("")) {
String s = theText;
if (s!=null&&s.length()>=3&&Character.isLetter(s.charAt(0))&&s.charAt(1)==':'&&s.charAt(2)=='\\')
s = s.replaceAll("\\\\", "/"); // replace "\" with "/" in Windows file paths
......@@ -1184,6 +1205,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
/** Displays this dialog box. */
public void showDialog() {
showDialogCalled = true;
if (macro) {
dispose();
recorderOn = Recorder.record && Recorder.recordInMacros;
......@@ -1232,7 +1254,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
c.insets = new Insets(15, 0, 0, 0);
add(buttons, c);
if (IJ.isMacOSX()&&IJ.isJava18())
instance = this;
instance = this;
Font font = getFont();
if (IJ.debugMode) IJ.log("GenericDialog font: "+fontSizeSet+" "+font);
if (!fontSizeSet && font!=null && Prefs.getGuiScale()!=1.0) {
......@@ -1242,13 +1264,25 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
pack();
setup();
if (centerDialog)
GUI.centerOnImageJScreen(this);
GUI.centerOnImageJScreen(this);
setVisible(true);
recorderOn = Recorder.record;
IJ.wait(25);
}
/* For plugins that read their input only via dialogItemChanged, call it at least once */
if (!(this instanceof NonBlockingGenericDialog))
finalizeRecording();
resetCounters();
}
@Override
public void show() {
super.show();
if (!showDialogCalled)
IJ.error("GenericDialog Error", "show() called instead of showDialog()");
}
/** For plugins that read their input only via dialogItemChanged, call it at least once, then stop recording */
void finalizeRecording() {
if (!wasCanceled && dialogListeners!=null && dialogListeners.size()>0) {
resetCounters();
((DialogListener)dialogListeners.elementAt(0)).dialogItemChanged(this,null);
......@@ -1256,7 +1290,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
}
resetCounters();
}
@Override
public void setFont(Font font) {
super.setFont(!fontSizeSet&&Prefs.getGuiScale()!=1.0?font.deriveFont((float)(font.getSize()*Prefs.getGuiScale())):font);
......@@ -1426,8 +1460,28 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
}
public void keyPressed(KeyEvent e) {
Component component = e.getComponent();
int keyCode = e.getKeyCode();
IJ.setKeyDown(keyCode);
if ((component instanceof Scrollbar) && (keyCode==KeyEvent.VK_LEFT||keyCode==KeyEvent.VK_RIGHT)) {
Scrollbar sb = (Scrollbar)component;
int value = sb.getValue();
if (keyCode==KeyEvent.VK_RIGHT)
sb.setValue(value+1);
else
sb.setValue(value-1);
for (int i=0; i<slider.size(); i++) {
if (sb==slider.elementAt(i)) {
int index = ((Integer)sliderIndexes.get(i)).intValue();
TextField tf = (TextField)numberField.elementAt(index);
double scale = ((Double)sliderScales.get(i)).doubleValue();
int digits = ((Integer)sliderDigits.get(i)).intValue();
tf.setText(""+IJ.d2s(sb.getValue()/scale,digits));
}
}
notifyListeners(e);
return;
}
if (keyCode==KeyEvent.VK_ENTER && textArea1==null && okay!=null && okay.isEnabled()) {
wasOKed = true;
if (IJ.isMacOSX())
......@@ -1526,7 +1580,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
}
public void paint(Graphics g) {
super.paint(g);
super.paint(g);
if (firstPaint && IJ.isMacOSX() && IJ.isJava18()) { // fix for incompletely drawn dialogs on Macs
EventQueue.invokeLater(new Runnable() {
public void run() {
......@@ -1555,7 +1609,7 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
}
void showHelp() {
if (helpURL.startsWith("<html>")) {
if (helpURL.startsWith("<html>")) {
if (this instanceof NonBlockingGenericDialog)
new HTMLDialog("", helpURL, false); // non blocking
else
......@@ -1585,5 +1639,5 @@ FocusListener, ItemListener, KeyListener, AdjustmentListener, WindowListener {
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
}
......@@ -394,6 +394,8 @@ public class ImageWindow extends Frame implements FocusListener, WindowListener,
msg = "Save changes to\n" + "\"" + name + "\"?";
else
msg = "Save changes to \"" + name + "\"?";
if (imp.isLocked())
msg += "\nWARNING: This image is locked.\nProbably, processing is unfinished (slow or still previewing).";
toFront();
YesNoCancelDialog d = new YesNoCancelDialog(this, "ImageJ", msg);
if (d.cancelPressed())
......
......@@ -6,7 +6,9 @@ import java.awt.EventQueue;
/** This is an extension of GenericDialog that is non-modal.
* @author Johannes Schindelin
*/
public class NonBlockingGenericDialog extends GenericDialog {
public class NonBlockingGenericDialog extends GenericDialog implements ImageListener {
ImagePlus imp; //when non-null, this dialog gets closed when the image is closed
public NonBlockingGenericDialog(String title) {
super(title, null);
......@@ -52,5 +54,38 @@ public class NonBlockingGenericDialog extends GenericDialog {
super.dispose();
WindowManager.removeWindow(this);
}
/** Returns a new NonBlockingGenericDialog with given title, unless
* java is running in headless mode; then a GenericDialog will be
* returned (headless mode does not support the NonBlockingGenericDialog).
* @param title Dialog title
* @param imp The image associated with this dialog
*/
public static GenericDialog newDialog(String title, ImagePlus imp) {
if (Prefs.nonBlockingFilterDialogs && imp!=null && imp.getWindow()!=null) {
NonBlockingGenericDialog gd = new NonBlockingGenericDialog(title);
gd.imp = imp;
imp.addImageListener(gd);
ImageWindow win = imp.getWindow();
//if (win!=null) win.addWindowListener(gd);
return gd;
} else
return new GenericDialog(title);
}
public void imageClosed(ImagePlus imp) {
if (imp == this.imp)
super.windowClosing(null); // sets wasCanceled=true and does dispose()
}
public void imageOpened(ImagePlus imp) {}
public void imageUpdated(ImagePlus imp) {}
/** Put the dialog into the foreground when the image we work on gets into the foreground */
public void windowActivated(WindowEvent e) {
if ((e.getWindow() instanceof ImageWindow) && e.getOppositeWindow()!=this)
toFront();
}
}
......@@ -387,9 +387,10 @@ public class OvalRoi extends Roi {
}
public ImageProcessor getMask() {
if (cachedMask!=null && cachedMask.getPixels()!=null)
return cachedMask;
ImageProcessor mask = new ByteProcessor(width, height);
ImageProcessor mask = cachedMask;
if (mask!=null && mask.getPixels()!=null && mask.getWidth()==width && mask.getHeight()==height)
return mask;
mask = new ByteProcessor(width, height);
double a=width/2.0, b=height/2.0;
double a2=a*a, b2=b*b;
a -= 0.5; b -= 0.5;
......
......@@ -411,4 +411,37 @@ public class Overlay {
return "Overlay[size="+size()+" "+(scalableLabels?"scale":"")+" "+Colors.colorToString(getLabelColor())+"]";
}
/** Updates overlays created by the particle analyzer
after rows are deleted from the Results table. */
public static void updateTableOverlay(ImagePlus imp, int first, int last, int tableSize) {
if (imp==null)
return;
Overlay overlay = imp.getOverlay();
if (overlay==null)
return;
if (overlay.size()!=tableSize)
return;
if (first<0)
first = 0;
if (last>tableSize-1)
last = tableSize-1;
if (first>last)
return;
String name1 = overlay.get(0).getName();
String name2 = overlay.get(overlay.size()-1).getName();
if (!"1".equals(name1) || !(""+tableSize).equals(name2))
return;
int count = last-first+1;
if (overlay.size()==count && !IJ.isMacro()) {
if (count==1 || IJ.showMessageWithCancel("ImageJ", "Delete "+overlay.size()+" element overlay? "))
imp.setOverlay(null);
return;
}
for (int i=0; i<count; i++)
overlay.remove(first);
for (int i=first; i<overlay.size(); i++)
overlay.get(i).setName(""+(i+1));
imp.draw();
}
}
This diff is collapsed.
This diff is collapsed.
......@@ -76,7 +76,7 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
private Button list, data, more, live;
private PopupMenu dataPopupMenu, morePopupMenu;
private static final int NUM_MENU_ITEMS = 18; //how many menu items we have in total
private static final int NUM_MENU_ITEMS = 20; //how many menu items we have in total
private MenuItem[] menuItems = new MenuItem[NUM_MENU_ITEMS];
private Label coordinates;
private static String defaultDirectory = null;
......@@ -92,9 +92,13 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
private Thread bgThread; // thread for plotting (in the background)
private boolean doUpdate; // tells the background thread to update
private Roi[] rangeArrowRois; // these constitute the arrow overlays for changing the range
private Roi[] rangeArrowRois; // the overlays (arrows etc) for changing the range. Note: #10-15 must correspond to PlotDialog.dialogType!
private boolean rangeArrowsVisible;
private int activeRangeArrow = -1;
private static Color inactiveRangeArrowColor = Color.GRAY;
private static Color inactiveRangeRectColor = new Color(0x20404040, true); //transparent gray
private static Color activeRangeArrowColor = Color.RED;
private static Color activeRangeRectColor = new Color(0x18ff0000, true); //transparent red
// static initializer
static {
......@@ -257,7 +261,7 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
else
imp.updateAndDraw();
if (listValues)
showList();
showList(/*useLabels=*/false);
else
ic.requestFocus(); //have focus on the canvas, not the button, so that pressing the space bar allows panning
}
......@@ -304,10 +308,10 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
}
/** Names for popupMenu items. Update NUM_MENU_ITEMS at the top when adding new ones! */
private static int SAVE=0, COPY=1, COPY_ALL=2, ADD_FROM_TABLE=3, ADD_FROM_PLOT=4, ADD_FIT=5, //data menu
SET_RANGE=6, PREV_RANGE=7, RESET_RANGE=8, FIT_RANGE=9, //the rest is in the more menu
ZOOM_SELECTION=10, AXIS_OPTIONS=11, LEGEND=12, STYLE=13, RESET_PLOT=14,
FREEZE=15, HI_RESOLUTION=16, PROFILE_PLOT_OPTIONS=17;
private static int SAVE=0, COPY=1, COPY_ALL=2, LIST_SIMPLE=3, ADD_FROM_TABLE=4, ADD_FROM_PLOT=5, ADD_FIT=6, //data menu
SET_RANGE=7, PREV_RANGE=8, RESET_RANGE=9, FIT_RANGE=10, //the rest is in the more menu
ZOOM_SELECTION=11, AXIS_OPTIONS=12, LEGEND=13, STYLE=14, TEMPLATE=15, RESET_PLOT=16,
FREEZE=17, HI_RESOLUTION=18, PROFILE_PLOT_OPTIONS=19;
//the following commands are disabled when the plot is frozen
private static int[] DISABLED_WHEN_FROZEN = new int[]{ADD_FROM_TABLE, ADD_FROM_PLOT, ADD_FIT,
SET_RANGE, PREV_RANGE, RESET_RANGE, FIT_RANGE, ZOOM_SELECTION, AXIS_OPTIONS, LEGEND, STYLE, RESET_PLOT};
......@@ -319,6 +323,7 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
menuItems[SAVE] = addPopupItem(dataPopupMenu, "Save Data...");
menuItems[COPY] = addPopupItem(dataPopupMenu, "Copy 1st Data Set");
menuItems[COPY_ALL] = addPopupItem(dataPopupMenu, "Copy All Data");
menuItems[LIST_SIMPLE] = addPopupItem(dataPopupMenu, "List (Simple Headings)");
dataPopupMenu.addSeparator();
menuItems[ADD_FROM_TABLE] = addPopupItem(dataPopupMenu, "Add from Table...");
menuItems[ADD_FROM_PLOT] = addPopupItem(dataPopupMenu, "Add from Plot...");
......@@ -339,6 +344,7 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
menuItems[AXIS_OPTIONS] = addPopupItem(morePopupMenu, "Axis Options...");
menuItems[LEGEND] = addPopupItem(morePopupMenu, "Legend...");
menuItems[STYLE] = addPopupItem(morePopupMenu, "Contents Style...");
menuItems[TEMPLATE] = addPopupItem(morePopupMenu, "Use Template...");
menuItems[RESET_PLOT] = addPopupItem(morePopupMenu, "Reset Format");
menuItems[FREEZE] = addPopupItem(morePopupMenu, "Freeze Plot", true);
menuItems[HI_RESOLUTION] = addPopupItem(morePopupMenu, "High-Resolution Plot...");
......@@ -371,7 +377,7 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
if (b==live)
toggleLiveProfiling();
else if (b==list)
showList();
showList(/*useLabels=*/true);
else if (b==data) {
enableDisableMenuItems();
dataPopupMenu.show((Component)b, 1, 1);
......@@ -384,6 +390,8 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
copyToClipboard(false);
else if (b==menuItems[COPY_ALL])
copyToClipboard(true);
else if (b==menuItems[LIST_SIMPLE])
showList(/*useLabels=*/false);
else if (b==menuItems[ADD_FROM_TABLE])
new PlotContentsDialog(plot, PlotContentsDialog.ADD_FROM_TABLE).showDialog(this);
else if (b==menuItems[ADD_FROM_PLOT])
......@@ -407,6 +415,8 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
new PlotDialog(plot, PlotDialog.LEGEND).showDialog(this);
else if (b==menuItems[STYLE])
new PlotContentsDialog(plot, PlotContentsDialog.STYLE).showDialog(this);
else if (b==menuItems[TEMPLATE])
new PlotDialog(plot, PlotDialog.TEMPLATE).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));
......@@ -443,50 +453,57 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
/**
* Updates the X and Y values when the mouse is moved and, if appropriate,
* shows/hides the overlay with the triangular buttons for changing the axis
* range limits Overrides mouseMoved() in ImageWindow.
* range limits.
* Overrides mouseMoved() in ImageWindow.
*
* @see ij.gui.ImageWindow#mouseMoved
*/
public void mouseMoved(int x, int y) {
super.mouseMoved(x, y);
if (plot == null)
return;
if (coordinates != null) { //coordinate readout
String coords = plot.getCoordinates(x, y) + blankLabel;
coordinates.setText(coords.substring(0, blankLabel.length()));
}
public void mouseMoved(int x, int y) {
super.mouseMoved(x, y);
if (plot == null)
return;
if (coordinates != null) { //coordinate readout
String coords = plot.getCoordinates(x, y) + blankLabel;
coordinates.setText(coords.substring(0, blankLabel.length()));
}
//arrows for modifying the plot range
if (plot==null) return;
if (x < plot.leftMargin || y > plot.topMargin + plot.frameHeight) {
if (!rangeArrowsVisible && !plot.isFrozen())
showRangeArrows();
if (activeRangeArrow == 8) //it's the 'R' icon
coordinates.setText("Reset Range");
else if (activeRangeArrow == 9) //it's the 'F' icon
coordinates.setText("Full Range (Fit All)");
else if (activeRangeArrow >= 10) //space between arrow-pairs
coordinates.setText("Set limit...");
if (activeRangeArrow >= 0 && !rangeArrowRois[activeRangeArrow].contains(x, y)) {
if(activeRangeArrow>=10) //numerical box
rangeArrowRois[activeRangeArrow].setFillColor(new Color(235, 235, 235));
else //arrow
rangeArrowRois[activeRangeArrow].setFillColor(Color.GRAY);
ic.repaint(); //de-highlight arrow where cursor has moved out
activeRangeArrow = -1;
}
if (activeRangeArrow < 0) { //highlight arrow below cursor (if any)
int i = getRangeArrowIndex(x, y);
if (i >= 0) { //we have an arrow at cursor position
rangeArrowRois[i].setFillColor(Color.RED);
activeRangeArrow = i;
ic.repaint();
}
}
} else if (rangeArrowsVisible)
hideRangeArrows();
}
//arrows and other symbols for modifying the plot range
if (x < plot.leftMargin || y > plot.topMargin + plot.frameHeight) {
if (!rangeArrowsVisible && !plot.isFrozen())
showRangeArrows();
if (activeRangeArrow < 0) //mouse is not on one of the symbols, ignore (nothing to display)
{}
else if (activeRangeArrow < 8) //mouse over an arrow: 0,3,4,7 for increase, 1,2,5,6 for decrease
coordinates.setText(((activeRangeArrow+1)&0x02) != 0 ? "Decrease Range" : "Increase Range");
else if (activeRangeArrow == 8) //it's the 'R' icon
coordinates.setText("Reset Range");
else if (activeRangeArrow == 9) //it's the 'F' icon
coordinates.setText("Full Range (Fit All)");
else if (activeRangeArrow >= 10 &&
activeRangeArrow < 14) //space between arrow-pairs for single number
coordinates.setText("Set limit...");
else if (activeRangeArrow >= 14)
coordinates.setText("Axis Range & Options...");
boolean repaint = false;
if (activeRangeArrow >= 0 && !rangeArrowRois[activeRangeArrow].contains(x, y)) {
rangeArrowRois[activeRangeArrow].setFillColor(
activeRangeArrow < 10 ? inactiveRangeArrowColor : inactiveRangeRectColor);
repaint = true; //de-highlight arrow where cursor has moved out
activeRangeArrow = -1;
}
if (activeRangeArrow < 0) { //no currently highlighted arrow, do we have a new one?
int i = getRangeArrowIndex(x, y);
if (i >= 0) { //we have an arrow or symbol at cursor position
rangeArrowRois[i].setFillColor(
i < 14 ? activeRangeArrowColor : activeRangeRectColor);
activeRangeArrow = i;
repaint = true;
}
}
if (repaint) ic.repaint();
} else if (rangeArrowsVisible)
hideRangeArrows();
}
/** Called by PlotCanvas */
void mouseExited(MouseEvent e) {
......@@ -504,7 +521,7 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
int amount = e.getScrollAmount();
if (e.getX() < plot.leftMargin || e.getX() > plot.leftMargin + plot.frameWidth)//n__
return;
if (e.getY() < plot.topMargin || e.getY() > plot.topMargin + plot.frameHeight)
if (e.getY() < plot.topMargin || e.getY() > plot.topMargin + plot.frameHeight)
return;
boolean ctrl = (e.getModifiers()&Event.CTRL_MASK)!=0;
if (amount<1) amount=1;
......@@ -523,14 +540,14 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
}
/**
* Creates an overlay with triangular buttons for changing the axis range
* Creates an overlay with triangular buttons and othr symbols for changing the axis range
* limits and shows it
*/
void showRangeArrows() {
if (imp == null)
return;
hideRangeArrows(); //in case we have old arrows from a different plot size or so
rangeArrowRois = new Roi[4 * 2 + 2 + 4]; //4 arrows per axis, plus 'Reset' and 'Fit All' icons, plus 4 numerical input boxes
rangeArrowRois = new Roi[4 * 2 + 2 + 4 + 2]; //4 arrows per axis, + 'Reset' and 'Fit All' icons, + 4 numerical input boxes + 2 axes
int i = 0;
int height = imp.getHeight();
int arrowH = plot.topMargin < 14 ? 6 : 8; //height of arrows and distance between them; base is twice that value
......@@ -560,18 +577,27 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
rangeArrowRois[11] = new Roi(plot.leftMargin + plot.frameWidth - arrowH/2 + 1, height - 5 * arrowH / 2, arrowH - 2, arrowH * 2);//numerical box right
rangeArrowRois[12] = new Roi(arrowH / 2, plot.topMargin + plot.frameHeight - arrowH/2 + 1, arrowH * 2, arrowH -2);//numerical box bottom
rangeArrowRois[13] = new Roi(arrowH / 2, plot.topMargin - arrowH/2 + 1, arrowH * 2, arrowH - 2 );//numerical box top
int topMargin = plot.topMargin;
int bottomMargin = topMargin + plot.frameHeight;
int leftMargin = plot.leftMargin;
int rightMargin = plot.leftMargin + plot.frameWidth;
rangeArrowRois[14] = new Roi(leftMargin, bottomMargin+2, // area to click for x axis options
rightMargin - leftMargin + 1, 2*arrowH);
rangeArrowRois[15] = new Roi(leftMargin-2*arrowH-2, topMargin, // area to click for y axis options
2*arrowH, bottomMargin - topMargin + 1);
Overlay ovly = imp.getOverlay();
if (ovly == null)
ovly = new Overlay();
for (Roi roi : rangeArrowRois) {
if (roi instanceof PolygonRoi)
roi.setFillColor(Color.GRAY);
if (roi instanceof PolygonRoi)
roi.setFillColor(inactiveRangeArrowColor);
else if (roi instanceof TextRoi) {
roi.setStrokeColor(Color.WHITE);
roi.setFillColor(Color.GRAY);
roi.setFillColor(inactiveRangeArrowColor);
} else
roi.setFillColor(new Color(235, 235, 235));
roi.setFillColor(inactiveRangeRectColor); //transparent gray for single number boxes and axis range
ovly.add(roi);
}
imp.setOverlay(ovly);
......@@ -590,9 +616,13 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
activeRangeArrow = -1;
}
/** Returns the index of the range arrow at cursor position x,y, or -1 of none.
* Index numbers start with 0 at the 'down' arrow of the lower side of the x axis
* and end with the up arrow at the upper side of the y axis. */
/** Returns the index of the range-modifying symbol or axis at the
* cursor position x,y, or -1 of none.
* Index numbers for arrows start with 0 at the 'down' arrow of the
* lower side of the x axis and end with 7 the up arrow at the upper
* side of the y axis. Numbers 8 & 9 are for "Reset Range" and "Fit All";
* numbers 10-13 for a dialog to set a single limit, and 14-15 for the axis options. */
int getRangeArrowIndex(int x, int y) {
if (!rangeArrowsVisible) return -1;
for (int i=0; i<rangeArrowRois.length; i++)
......@@ -603,8 +633,8 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
/** Shows the data of the backing plot in a Textwindow with columns */
void showList(){
ResultsTable rt = plot.getResultsTable(saveXValues);
void showList(boolean useLabels){
ResultsTable rt = plot.getResultsTable(saveXValues, useLabels);
if (rt==null) return;
rt.show("Plot Values");
if (autoClose) {
......@@ -613,7 +643,8 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
}
}
/** Returns the plot values as a ResultsTable. */
/** Returns the plot values with simple headings (X, Y, Y1 etc, not the labels) as a ResultsTable.
* Use plot.getResultsTableWithLabels for a table with data set labels as column headings */
public ResultsTable getResultsTable() {
return plot.getResultsTable(saveXValues);
}
......@@ -641,7 +672,7 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
String directory = sd.getDirectory();
IJ.wait(250); // give system time to redraw ImageJ window
IJ.showStatus("Saving plot values...");
ResultsTable rt = getResultsTable();
ResultsTable rt = plot.getResultsTable(/*writeFirstXColumn=*/saveXValues, /*useLabels=*/true);
try {
rt.saveAs(directory+name);
} catch (IOException e) {
......@@ -667,7 +698,7 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
PrintWriter pw = new PrintWriter(aw); //uses platform's line termination characters
if (writeAllColumns) {
ResultsTable rt = plot.getResultsTable(true);
ResultsTable rt = plot.getResultsTableWithLabels();
if (!Prefs.dontSaveHeaders) {
String headings = rt.getColumnHeadings();
pw.println(headings);
......@@ -818,7 +849,8 @@ public class PlotWindow extends ImageWindow implements ActionListener, ItemListe
IJ.wait(50); //delay to make sure the roi has been updated
Plot plot = plotMaker!=null?plotMaker.getPlot():null;
if (doUpdate && plot!=null && plot.getNumPlotObjects()>0) {
plot.useTemplate(this.plot, this.plot.templateFlags);
plot.useTemplate(this.plot, this.plot.templateFlags | Plot.COPY_SIZE | Plot.COPY_LABELS | Plot.COPY_AXIS_STYLE |
Plot.COPY_CONTENTS_STYLE | Plot.COPY_LEGEND | Plot.COPY_EXTRA_OBJECTS);
plot.setPlotMaker(plotMaker);
this.plot = plot;
((PlotCanvas)ic).setPlot(plot);
......
......@@ -17,15 +17,16 @@ import java.awt.geom.*;
* @see <a href="http://wsr.imagej.net/macros/js/PointProperties.js">PointProperties.js</a>
*/
public class PointRoi extends PolygonRoi {
public static final String[] sizes = {"Tiny", "Small", "Medium", "Large", "Extra Large"};
public static final String[] sizes = {"Tiny", "Small", "Medium", "Large", "Extra Large", "XXL", "XXXL"};
public static final String[] types = {"Hybrid", "Cross", "Dot", "Circle"};
private static final String TYPE_KEY = "point.type";
private static final String SIZE_KEY = "point.size";
private static final String CROSS_COLOR_KEY = "point.cross.color";
private static final int TINY=1, SMALL=3, MEDIUM=5, LARGE=7, EXTRA_LARGE=11;
private static final int TINY=1, SMALL=3, MEDIUM=5, LARGE=7, EXTRA_LARGE=11, XXL=17, XXXL=25;
private static final int HYBRID=0, CROSS=1, CROSSHAIR=1, DOT=2, CIRCLE=3;
private static final BasicStroke twoPixelsWide = new BasicStroke(2);
private static final BasicStroke threePixelsWide = new BasicStroke(3);
private static final BasicStroke fivePixelsWide = new BasicStroke(5);
private static int defaultType = HYBRID;
private static int defaultSize = SMALL;
private static Font font;
......@@ -129,7 +130,7 @@ public class PointRoi extends PolygonRoi {
size = defaultSize;
showLabels = !Prefs.noPointLabels;
if (imp!=null) {
int r = 10;
int r = 10 + size;
double mag = ic!=null?ic.getMagnification():1;
if (mag<1)
r = (int)(r/mag);
......@@ -156,6 +157,8 @@ public class PointRoi extends PolygonRoi {
else if (options.contains("medium")) size=MEDIUM;
else if (options.contains("extra")) size=EXTRA_LARGE;
else if (options.contains("large")) size=LARGE;
else if (options.contains("xxxl")) size=XXXL;
else if (options.contains("xxl")) size=XXL;
if (options.contains("cross")) type=CROSS;
else if (options.contains("dot")) type=DOT;
else if (options.contains("circle")) type=CIRCLE;
......@@ -198,10 +201,10 @@ public class PointRoi extends PolygonRoi {
updatePolygon();
if (showLabels && nPoints>1) {
fontSize = 8;
fontSize += convertSizeToIndex(size);
if (fontSize>18)
fontSize = 18;
double scale = size>=XXL?2:1.5;
fontSize += scale*convertSizeToIndex(size);
fontSize = (int)Math.round(fontSize);
//IJ.log("fontSize: "+fontSize+" "+scale);
font = new Font("SansSerif", Font.PLAIN, fontSize);
g.setFont(font);
if (fontSize>9)
......@@ -254,7 +257,9 @@ public class PointRoi extends PolygonRoi {
g.setColor(color);
colorSet = true;
}
if (size>LARGE)
if (size>XXL)
g2d.setStroke(fivePixelsWide);
else if (size>LARGE)
g2d.setStroke(threePixelsWide);
g.drawLine(x-(size+2), y, x+size+2, y);
g.drawLine(x, y-(size+2), x, y+size+2);
......@@ -278,16 +283,20 @@ public class PointRoi extends PolygonRoi {
g.fillRect(x-size2, y-size2, size, size);
}
if (showLabels && nPoints>1) {
int offset = (int)Math.round(0.4);
if (offset<1) offset=1;
offset++;
int xoffset = 2;
if (size==LARGE) xoffset=3;
if (size==EXTRA_LARGE) xoffset=4;
if (size==XXL) xoffset=5;
if (size==XXXL) xoffset=7;
int yoffset = xoffset;
if (size>=LARGE) yoffset=yoffset-1;
if (nCounters==1) {
if (!colorSet)
g.setColor(color);
g.drawString(""+n, x+offset, y+offset+fontSize);
g.drawString(""+n, x+xoffset, y+yoffset+fontSize);
} else if (counters!=null) {
g.setColor(getColor(counters[n-1]));
g.drawString(""+counters[n-1], x+offset, y+offset+fontSize);
g.drawString(""+counters[n-1], x+xoffset, y+yoffset+fontSize);
}
}
if ((size>TINY||type==DOT) && (type==HYBRID||type==DOT)) {
......@@ -551,6 +560,8 @@ public class PointRoi extends PolygonRoi {
case MEDIUM: return 2;
case LARGE: return 3;
case EXTRA_LARGE: return 4;
case XXL: return 5;
case XXXL: return 6;
}
return 1;
}
......@@ -562,6 +573,8 @@ public class PointRoi extends PolygonRoi {
case 2: return MEDIUM;
case 3: return LARGE;
case 4: return EXTRA_LARGE;
case 5: return XXL;
case 6: return XXXL;
}
return SMALL;
}
......
......@@ -672,7 +672,7 @@ public class PolygonRoi extends Roi {
if (yClipMax>ymax2) ymax2 = yClipMax;
xClipMin=xmin; yClipMin=ymin; xClipMax=xmax; yClipMax=ymax;
double mag = ic.getMagnification();
int handleSize = type==POINT?HANDLE_SIZE+12:HANDLE_SIZE;
int handleSize = type==POINT?HANDLE_SIZE+25:HANDLE_SIZE;
double strokeWidth = getStrokeWidth();
if (strokeWidth<1.0) strokeWidth=1.0;
if (handleSize<strokeWidth && isLine())
......@@ -1070,14 +1070,21 @@ public class PolygonRoi extends Roi {
samePoint = (xpf[nPoints-2]==xpf[nPoints-1] && ypf[nPoints-2]==ypf[nPoints-1]);
else
samePoint = (xp[nPoints-2]==xp[nPoints-1] && yp[nPoints-2]==yp[nPoints-1]);
boolean doubleClick = (System.currentTimeMillis()-mouseUpTime)<=250;
Rectangle biggerStartBox = new Rectangle(ic.screenXD(startXD)-5, ic.screenYD(startYD)-5, 10, 10);
if (nPoints>2 && (biggerStartBox.contains(sx, sy)
|| (ic.offScreenXD(sx)==startXD && ic.offScreenYD(sy)==startYD)
|| (samePoint && (System.currentTimeMillis()-mouseUpTime)<=500))) {
nPoints--;
addOffset();
finishPolygon();
return;
|| (samePoint && doubleClick))) {
boolean okayToFinish = true;
if (type==POLYGON && samePoint && doubleClick && nPoints>25) {
okayToFinish = IJ.showMessageWithCancel("Polygon Tool", "Complete the selection?");
}
if (okayToFinish) {
nPoints--;
addOffset();
finishPolygon();
return;
}
} else if (!samePoint) {
mouseUpTime = System.currentTimeMillis();
if (type==ANGLE && nPoints==3) {
......