use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.
the class AnnotationPane method selectedPathObjectChanged.
@Override
public void selectedPathObjectChanged(final PathObject pathObjectSelected, final PathObject previousObject, Collection<PathObject> allSelected) {
if (!Platform.isFxApplicationThread()) {
// Platform.runLater(() -> selectedPathObjectChanged(pathObjectSelected, previousObject, allSelected));
return;
}
if (suppressSelectionChanges || disableUpdates.get())
return;
suppressSelectionChanges = true;
if (synchronizePrimarySelectionOnly) {
try {
var listSelectionModel = listAnnotations.getSelectionModel();
listSelectionModel.clearSelection();
if (pathObjectSelected != null && pathObjectSelected.isAnnotation()) {
listSelectionModel.select(pathObjectSelected);
listAnnotations.scrollTo(pathObjectSelected);
}
return;
} finally {
suppressSelectionChanges = false;
}
}
try {
var hierarchySelected = new TreeSet<>(DefaultPathObjectComparator.getInstance());
hierarchySelected.addAll(allSelected);
// Determine the objects to select
MultipleSelectionModel<PathObject> model = listAnnotations.getSelectionModel();
List<PathObject> selected = new ArrayList<>();
for (PathObject pathObject : hierarchySelected) {
if (pathObject == null)
logger.warn("Selected object is null!");
else if (pathObject.isAnnotation())
selected.add(pathObject);
}
if (selected.isEmpty()) {
if (!model.isEmpty())
model.clearSelection();
return;
}
// Check if we're making changes
List<PathObject> currentlySelected = model.getSelectedItems();
if (selected.size() == currentlySelected.size() && (hierarchySelected.containsAll(currentlySelected))) {
listAnnotations.refresh();
return;
}
// System.err.println(listAnnotations.getItems().size());
if (hierarchySelected.containsAll(listAnnotations.getItems())) {
model.selectAll();
return;
}
// System.err.println("Setting " + currentlySelected + " to " + selected);
int[] inds = new int[selected.size()];
int i = 0;
model.clearSelection();
boolean firstInd = true;
for (PathObject temp : selected) {
int idx = listAnnotations.getItems().indexOf(temp);
if (idx >= 0 && firstInd) {
Arrays.fill(inds, idx);
firstInd = false;
}
inds[i] = idx;
i++;
}
if (inds.length == 1 && pathObjectSelected instanceof PathAnnotationObject)
listAnnotations.scrollTo(pathObjectSelected);
if (firstInd) {
suppressSelectionChanges = false;
return;
}
if (inds.length == 1)
model.select(inds[0]);
else if (inds.length > 1)
model.selectIndices(inds[0], inds);
} finally {
suppressSelectionChanges = false;
}
}
use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.
the class BrushTool method mousePressed.
@Override
public void mousePressed(MouseEvent e) {
// super.mousePressed(e);
if (!e.isPrimaryButtonDown() || e.isConsumed()) {
return;
}
ensureCursorType(getRequestedCursor());
var viewer = getViewer();
PathObjectHierarchy hierarchy = viewer.getHierarchy();
if (hierarchy == null)
return;
PathObject currentObject = viewer.getSelectedObject();
// Determine if we are creating a new object
// boolean createNew = currentObject == null || e.getClickCount() > 1;// || (!currentObject.getROI().contains(p.getX(), p.getY()) && !e.isAltDown());
Point2D p = mouseLocationToImage(e, false, requestPixelSnapping());
double xx = p.getX();
double yy = p.getY();
if (xx < 0 || yy < 0 || xx >= viewer.getServerWidth() || yy >= viewer.getServerHeight())
return;
// boolean createNew = currentObject == null || !(currentObject instanceof PathAnnotationObject) || (currentObject.hasChildren()) || (PathPrefs.getBrushCreateNewObjects() && !ROIHelpers.areaContains(currentObject.getROI(), p.getX(), p.getY()) && !isSubtractMode(e));
boolean createNew = currentObject == null || PathPrefs.selectionModeProperty().get() || !(currentObject instanceof PathAnnotationObject) || (!currentObject.isEditable()) || currentObject.getROI().getZ() != viewer.getZPosition() || currentObject.getROI().getT() != viewer.getTPosition() || (!e.isShiftDown() && PathPrefs.brushCreateNewObjectsProperty().get() && !RoiTools.areaContains(currentObject.getROI(), p.getX(), p.getY()) && !isSubtractMode(e));
if (isSubtractMode(e))
createNew = false;
// See if, rather than creating something, we can instead reactivate a current object
boolean multipleClicks = e.getClickCount() > 1;
if (!PathPrefs.selectionModeProperty().get() && (multipleClicks || (createNew && !e.isShiftDown()))) {
// See if, rather than creating something, we can instead reactivate a current object
if (multipleClicks) {
PathObject objectSelectable = getSelectableObject(p.getX(), p.getY(), e.getClickCount() - 1);
if (objectSelectable != null && objectSelectable.isEditable() && objectSelectable.hasROI() && objectSelectable.getROI().isArea()) {
createNew = false;
viewer.setSelectedObject(objectSelectable);
currentObject = objectSelectable;
} else if (createNew) {
viewer.setSelectedObject(null);
currentObject = null;
}
} else if (!PathPrefs.selectionModeProperty().get()) {
List<PathObject> listSelectable = getSelectableObjectList(p.getX(), p.getY());
PathObject objectSelectable = null;
for (int i = listSelectable.size() - 1; i >= 0; i--) {
PathObject temp = listSelectable.get(i);
if (temp.isEditable() && temp instanceof PathAnnotationObject && temp.hasROI() && temp.getROI().isArea()) {
// temp.getROI() instanceof AreaROI) {
objectSelectable = temp;
break;
}
}
if (objectSelectable != null) {
createNew = false;
viewer.setSelectedObject(objectSelectable);
currentObject = objectSelectable;
} else if (createNew) {
viewer.setSelectedObject(null);
currentObject = null;
}
}
}
// Can only modify annotations
if (!createNew && !(currentObject != null && currentObject.isAnnotation() && currentObject.isEditable() && RoiTools.isShapeROI(currentObject.getROI())))
return;
// Get the parent, in case we need to constrain the shape
// PathObject parent = null;
// if (currentObject != null) {
// parent = currentObject.getParent();
// }
// var currentObject2 = currentObject;
// if (parent == null || parent.isDetection()) {
// parent = getSelectableObjectList(p.getX(), p.getY())
// .stream()
// .filter(o -> !o.isDetection() && o != currentObject2)
// .findFirst()
// .orElseGet(() -> null);
// }
// setConstrainedAreaParent(hierarchy, parent, currentObject);
setConstrainedAreaParent(hierarchy, xx, yy, Collections.singleton(currentObject));
// Need to remove the object from the hierarchy while editing it
if (!createNew && currentObject != null) {
hierarchy.removeObjectWithoutUpdate(currentObject, true);
}
ROI shapeROI = createNew ? null : currentObject.getROI();
if (createNew) {
// Reset this
creatingTiledROI = false;
this.currentObject = createNewAnnotation(e, p.getX(), p.getY());
viewer.getROIEditor().setROI(null);
} else {
this.currentObject = getUpdatedObject(e, shapeROI, currentObject, -1);
viewer.setSelectedObject(this.currentObject);
// Avoids handles appearing?
viewer.getROIEditor().setROI(null);
}
lastPoint = p;
}
use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.
the class Commands method promptToSimplifySelectedAnnotations.
/**
* Show a prompt to selected annotations in a hierarchy.
* @param imageData the current image data
* @param altitudeThreshold default altitude value for simplification
*/
public static void promptToSimplifySelectedAnnotations(ImageData<?> imageData, double altitudeThreshold) {
PathObjectHierarchy hierarchy = imageData.getHierarchy();
List<PathObject> pathObjects = hierarchy.getSelectionModel().getSelectedObjects().stream().filter(p -> p.isAnnotation() && p.hasROI() && p.isEditable() && !p.getROI().isPoint()).collect(Collectors.toList());
if (pathObjects.isEmpty()) {
Dialogs.showErrorMessage("Simplify annotations", "No unlocked shape annotations selected!");
return;
}
String input = Dialogs.showInputDialog("Simplify shape", "Set altitude threshold in pixels.\nHigher values give simpler shapes.", Double.toString(altitudeThreshold));
if (input == null || !(input instanceof String) || ((String) input).trim().length() == 0)
return;
try {
altitudeThreshold = Double.parseDouble(((String) input).trim());
} catch (NumberFormatException e) {
logger.error("Could not parse altitude threshold from {}", input);
return;
}
if (altitudeThreshold <= 0) {
Dialogs.showErrorMessage("Simplify shape", "Amplitude threshold should be greater than zero!");
return;
}
long startTime = System.currentTimeMillis();
for (var pathObject : pathObjects) {
ROI pathROI = pathObject.getROI();
if (pathROI instanceof PolygonROI) {
PolygonROI polygonROI = (PolygonROI) pathROI;
pathROI = ShapeSimplifier.simplifyPolygon(polygonROI, altitudeThreshold);
} else {
pathROI = ShapeSimplifier.simplifyShape(pathROI, altitudeThreshold);
}
((PathAnnotationObject) pathObject).setROI(pathROI);
}
long endTime = System.currentTimeMillis();
logger.debug("Shapes simplified in " + (endTime - startTime) + " ms");
hierarchy.fireObjectsChangedEvent(hierarchy, pathObjects);
}
use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.
the class GuiTools method promptToSetAnnotationProperties.
private static boolean promptToSetAnnotationProperties(final PathAnnotationObject annotation, Collection<PathAnnotationObject> otherAnnotations) {
GridPane panel = new GridPane();
panel.setVgap(5);
panel.setHgap(5);
TextField textField = new TextField();
if (annotation.getName() != null)
textField.setText(annotation.getName());
textField.setPrefColumnCount(20);
// Post focus request to run later, after dialog displayed
Platform.runLater(() -> textField.requestFocus());
panel.add(new Label("Name "), 0, 0);
panel.add(textField, 1, 0);
boolean promptForColor = true;
ColorPicker colorPicker = null;
var originalColor = ColorToolsFX.getDisplayedColor(annotation);
// Track if the user changed anything, so that we don't set the color unnecessarily
var colorChanged = new SimpleBooleanProperty(false);
if (promptForColor) {
colorPicker = new ColorPicker(originalColor);
// If we don't touch the color picker, don't set the color (because it might be the default)
colorPicker.valueProperty().addListener((v, o, n) -> colorChanged.set(true));
panel.add(new Label("Color "), 0, 1);
panel.add(colorPicker, 1, 1);
colorPicker.prefWidthProperty().bind(textField.widthProperty());
}
Label labDescription = new Label("Description");
TextArea textAreaDescription = new TextArea(annotation.getDescription());
textAreaDescription.setPrefRowCount(3);
textAreaDescription.setPrefColumnCount(25);
labDescription.setLabelFor(textAreaDescription);
panel.add(labDescription, 0, 2);
panel.add(textAreaDescription, 1, 2);
CheckBox cbLocked = new CheckBox("");
cbLocked.setSelected(annotation.isLocked());
Label labelLocked = new Label("Locked");
panel.add(labelLocked, 0, 3);
labelLocked.setLabelFor(cbLocked);
panel.add(cbLocked, 1, 3);
CheckBox cbAll = new CheckBox("");
boolean hasOthers = otherAnnotations != null && !otherAnnotations.isEmpty();
cbAll.setSelected(hasOthers);
Label labelApplyToAll = new Label("Apply to all");
cbAll.setTooltip(new Tooltip("Apply properties to all " + (otherAnnotations.size() + 1) + " selected annotations"));
if (hasOthers) {
panel.add(labelApplyToAll, 0, 4);
labelApplyToAll.setLabelFor(cbAll);
panel.add(cbAll, 1, 4);
}
if (!Dialogs.showConfirmDialog("Set annotation properties", panel))
return false;
List<PathAnnotationObject> toChange = new ArrayList<>();
toChange.add(annotation);
if (cbAll.isSelected())
toChange.addAll(otherAnnotations);
String name = textField.getText().trim();
for (var temp : toChange) {
if (name.length() > 0)
temp.setName(name);
else
temp.setName(null);
if (promptForColor && colorChanged.get())
temp.setColorRGB(ColorToolsFX.getARGB(colorPicker.getValue()));
// Set the description only if we have to
String description = textAreaDescription.getText();
if (description == null || description.isEmpty())
temp.setDescription(null);
else
temp.setDescription(description);
temp.setLocked(cbLocked.isSelected());
}
return true;
}
Aggregations