package ij.gui;
import ij.*;
import ij.plugin.Colors;
import ij.io.RoiDecoder;
import ij.process.FloatPolygon;
import ij.measure.*;
import ij.util.Tools;
import ij.plugin.filter.Analyzer;
import ij.text.TextWindow;
import java.awt.*;
import java.util.*;
public class RoiProperties {
private ImagePlus imp;
private Roi roi;
private Overlay overlay;
private String title;
private boolean showName = true;
private boolean showListCoordinates;
private boolean addToOverlay;
private boolean overlayOptions;
private boolean setPositions;
private boolean listCoordinates;
private boolean listProperties;
private boolean showPointCounts;
private static final String[] justNames = {"Left", "Center", "Right"};
private int nProperties;
public RoiProperties(String title, Roi roi) {
if (roi==null)
throw new IllegalArgumentException("ROI is null");
this.title = title;
showName = title.startsWith("Prop");
showListCoordinates = showName && title.endsWith(" ");
nProperties = showListCoordinates?roi.getPropertyCount():0;
addToOverlay = title.equals("Add to Overlay");
overlayOptions = title.equals("Overlay Options");
if (overlayOptions) {
imp = WindowManager.getCurrentImage();
overlay = imp!=null?imp.getOverlay():null;
setPositions = roi.getPosition()!=0;
}
this.roi = roi;
}
private String decodeColor(Color color, Color defaultColor) {
if (color==null)
color = defaultColor;
String str = "#"+Integer.toHexString(color.getRGB());
if (str.length()==9 && str.startsWith("#ff"))
str = "#"+str.substring(3);
String lc = Colors.hexToColor(str);
if (lc!=null) str = lc;
return str;
}
public boolean showDialog() {
String name= roi.getName();
boolean isRange = name!=null && name.startsWith("range:");
String nameLabel = isRange?"Range:":"Name:";
if (isRange) name = name.substring(7);
if (name==null) name = "";
if (!isRange && (roi instanceof ImageRoi) && !overlayOptions)
return showImageDialog(name);
Color strokeColor = roi.getStrokeColor();
Color fillColor = roi.getFillColor();
double strokeWidth = roi.getStrokeWidth();
boolean isText = roi instanceof TextRoi;
boolean isLine = roi.isLine();
boolean isPoint = roi instanceof PointRoi;
int justification = TextRoi.LEFT;
double angle = 0.0;
boolean antialias = true;
if (isText) {
TextRoi troi = (TextRoi)roi;
Font font = troi.getCurrentFont();
strokeWidth = font.getSize();
angle = troi.getAngle();
justification = troi.getJustification();
antialias = troi.getAntialiased();
}
String position = ""+roi.getPosition();
if (roi.hasHyperStackPosition())
position = roi.getCPosition() +","+roi.getZPosition()+","+ roi.getTPosition();
if (position.equals("0"))
position = "none";
String linec = Colors.colorToString(strokeColor);
String fillc = Colors.colorToString(fillColor);
if (IJ.isMacro()) {
fillc = "none";
setPositions = false;
}
int digits = (int)strokeWidth==strokeWidth?0:1;
GenericDialog gd = new GenericDialog(title);
if (showName) {
gd.addStringField(nameLabel, name, 15);
gd.addStringField("Position:", position);
}
if (isText) {
gd.addStringField("Stroke color:", linec);
gd.addNumericField("Font size:", strokeWidth, digits, 4, "points");
digits = (int)angle==angle?0:1;
gd.addNumericField("Angle:", angle, digits, 4, "degrees");
gd.setInsets(0, 0, 0);
gd.addChoice("Justification:", justNames, justNames[justification]);
} else {
if (isPoint)
gd.addStringField("Stroke (point) color:", linec);
else {
gd.addStringField("Stroke color:", linec);
gd.addNumericField("Width:", strokeWidth, digits);
}
}
if (!isLine) {
if (isPoint) {
int index = ((PointRoi)roi).getPointType();
gd.addChoice("Point type:", PointRoi.types, PointRoi.types[index]);
index = ((PointRoi)roi).getSize();
gd.addChoice("Size:", PointRoi.sizes, PointRoi.sizes[index]);
} else {
gd.addMessage("");
gd.addStringField("Fill color:", fillc);
}
}
if (addToOverlay)
gd.addCheckbox("New overlay", false);
if (overlayOptions) {
gd.addCheckbox("Set stack positions", setPositions);
if (overlay!=null) {
int size = overlay.size();
gd.setInsets(15,20,0);
if (imp!=null && imp.getHideOverlay())
gd.addMessage("Current overlay is hidden", null, Color.darkGray);
else
gd.addMessage("Current overlay has "+size+" element"+(size>1?"s":""), null, Color.darkGray);
gd.setInsets(0,30,0);
gd.addCheckbox("Apply", false);
gd.setInsets(0,30,0);
gd.addCheckbox("Show labels", overlay.getDrawLabels());
gd.setInsets(0,30,0);
gd.addCheckbox("Hide", imp!=null?imp.getHideOverlay():false);
} else
gd.addMessage("No overlay", null, Color.darkGray);
}
if (isText)
gd.addCheckbox("Antialiased text", antialias);
if (showListCoordinates) {
if ((roi instanceof PointRoi) && Toolbar.getMultiPointMode())
showPointCounts = true;
int n = roi.getFloatPolygon().npoints;
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 {
gd.setInsets(5,20,0);
gd.addMessage("No properties");
}
}
if (showName && "".equals(name) && "none".equals(position) && "none".equals(fillc))
gd.setSmartRecording(true);
gd.showDialog();
if (gd.wasCanceled())
return false;
String position2 = "";
if (showName) {
name = gd.getNextString();
if (!isRange) roi.setName(name.length()>0?name:null);
position2 = gd.getNextString();
}
linec = gd.getNextString();
if (!isPoint)
strokeWidth = gd.getNextNumber();
if (isText) {
angle = gd.getNextNumber();
justification = gd.getNextChoiceIndex();
}
if (!isLine) {
if (isPoint) {
int index = gd.getNextChoiceIndex();
((PointRoi)roi).setPointType(index);
index = gd.getNextChoiceIndex();
((PointRoi)roi).setSize(index);
} else
fillc = gd.getNextString();
}
boolean applyToOverlay = false;
boolean newOverlay = addToOverlay?gd.getNextBoolean():false;
if (overlayOptions) {
setPositions = gd.getNextBoolean();
if (overlay!=null) {
applyToOverlay = gd.getNextBoolean();
boolean labels = gd.getNextBoolean();
boolean hideOverlay = gd.getNextBoolean();
if (hideOverlay && imp!=null) {
if (!imp.getHideOverlay())
imp.setHideOverlay(true);
} else {
overlay.drawLabels(labels);
Analyzer.drawLabels(labels);
overlay.drawBackgrounds(true);
if (imp.getHideOverlay())
imp.setHideOverlay(false);
if (!applyToOverlay && imp!=null)
imp.draw();
}
}
roi.setPosition(setPositions?1:0);
}
if (isText)
antialias = gd.getNextBoolean();
if (showListCoordinates) {
listCoordinates = gd.getNextBoolean();
if (nProperties>0)
listProperties = gd.getNextBoolean();
}
strokeColor = Colors.decode(linec, null);
fillColor = Colors.decode(fillc, null);
if (isText) {
TextRoi troi = (TextRoi)roi;
Font font = troi.getCurrentFont();
if ((int)strokeWidth!=font.getSize()) {
font = new Font(font.getName(), font.getStyle(), (int)strokeWidth);
troi.setCurrentFont(font);
}
troi.setAngle(angle);
if (justification!=troi.getJustification())
troi.setJustification(justification);
troi.setAntialiased(antialias);
} else
roi.setStrokeWidth((float)strokeWidth);
if (showName)
setPosition(roi, position, position2);
roi.setStrokeColor(strokeColor);
roi.setFillColor(fillColor);
if (newOverlay) roi.setName("new-overlay");
if (applyToOverlay) {
if (imp==null || overlay==null)
return true;
Roi[] rois = overlay.toArray();
for (int i=0; i<rois.length; i++) {
rois[i].setStrokeColor(strokeColor);
rois[i].setStrokeWidth((float)strokeWidth);
rois[i].setFillColor(fillColor);
}
imp.draw();
imp.getProcessor(); }
if (listCoordinates) {
if (showPointCounts && (roi instanceof PointRoi))
((PointRoi)roi).displayCounts();
else
listCoordinates(roi);
}
if (listProperties && nProperties>0)
listProperties(roi);
return true;
}
private void setPosition(Roi roi, String pos1, String pos2) {
if (pos1.equals(pos2))
return;
if (pos2.equals("none") || pos2.equals("0")) {
roi.setPosition(0);
return;
}
String[] positions = Tools.split(pos2, " ,");
if (positions.length==1) {
double stackPos = Tools.parseDouble(positions[0]);
if (!Double.isNaN(stackPos))
roi.setPosition((int)stackPos);
return;
}
if (positions.length==3) {
int[] pos = new int[3];
for (int i=0; i<3; i++) {
double dpos = Tools.parseDouble(positions[i]);
if (Double.isNaN(dpos))
return;
else
pos[i] = (int)dpos;
}
roi.setPosition(pos[0], pos[1], pos[2]);
return;
}
}
public boolean showImageDialog(String name) {
GenericDialog gd = new GenericDialog(title);
gd.addStringField("Name:", name, 15);
gd.addNumericField("Opacity (0-100%):", ((ImageRoi)roi).getOpacity()*100.0, 0);
if (addToOverlay)
gd.addCheckbox("New Overlay", false);
gd.showDialog();
if (gd.wasCanceled()) return false;
name = gd.getNextString();
roi.setName(name.length()>0?name:null);
double opacity = gd.getNextNumber()/100.0;
((ImageRoi)roi).setOpacity(opacity);
boolean newOverlay = addToOverlay?gd.getNextBoolean():false;
if (newOverlay) roi.setName("new-overlay");
return true;
}
void listCoordinates(Roi roi) {
if (roi==null) return;
boolean allIntegers = true;
FloatPolygon fp = roi.getFloatPolygon();
ImagePlus imp = roi.getImage();
String title = "Coordinates";
if (imp!=null) {
Calibration cal = imp.getCalibration();
if (cal.pixelWidth!=1.0 || cal.pixelHeight!=1.0) {
for (int i=0; i<fp.npoints; i++) {
fp.xpoints[i] *= cal.pixelWidth;
fp.ypoints[i] *= cal.pixelHeight;
}
allIntegers = false;
}
title = imp.getTitle();
}
if (allIntegers) {
for (int i=0; i<fp.npoints; i++) {
if ((int)fp.xpoints[i]!=fp.xpoints[i] || (int)fp.ypoints[i]!=fp.ypoints[i]) {
allIntegers = false;
break;
}
}
}
ResultsTable rt = new ResultsTable();
rt.setPrecision(allIntegers?0:Analyzer.getPrecision());
for (int i=0; i<fp.npoints; i++) {
rt.incrementCounter();
rt.addValue("X", fp.xpoints[i]);
rt.addValue("Y", fp.ypoints[i]);
}
rt.showRowNumbers(false);
rt.show("XY_"+title);
}
void listProperties(Roi roi) {
String props = roi.getProperties();
if (props==null) return;
props = props.replaceAll(": ", "\t");
new TextWindow("Properties", "Key\tValue", props, 300, 300);
}
}