use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.
the class QuPathGUI method setViewerPopupMenu.
private void setViewerPopupMenu(final QuPathViewerPlus viewer) {
final ContextMenu popup = new ContextMenu();
MenuItem miAddRow = new MenuItem("Add row");
miAddRow.setOnAction(e -> viewerManager.addRow(viewer));
MenuItem miAddColumn = new MenuItem("Add column");
miAddColumn.setOnAction(e -> viewerManager.addColumn(viewer));
MenuItem miRemoveRow = new MenuItem("Remove row");
miRemoveRow.setOnAction(e -> viewerManager.removeViewerRow(viewer));
MenuItem miRemoveColumn = new MenuItem("Remove column");
miRemoveColumn.setOnAction(e -> viewerManager.removeViewerColumn(viewer));
MenuItem miCloseViewer = new MenuItem("Close viewer");
miCloseViewer.setOnAction(e -> {
viewerManager.closeViewer(viewer);
// viewerManager.removeViewer(viewer);
});
MenuItem miResizeGrid = new MenuItem("Reset grid size");
miResizeGrid.setOnAction(e -> {
viewerManager.resetGridSize();
});
MenuItem miToggleSync = ActionTools.createCheckMenuItem(defaultActions.TOGGLE_SYNCHRONIZE_VIEWERS, null);
MenuItem miMatchResolutions = ActionTools.createMenuItem(defaultActions.MATCH_VIEWER_RESOLUTIONS);
Menu menuMultiview = MenuTools.createMenu("Multi-view", miToggleSync, miMatchResolutions, miCloseViewer, null, miResizeGrid, null, // null,
miAddRow, miAddColumn, null, miRemoveRow, miRemoveColumn);
Menu menuView = MenuTools.createMenu("Display", ActionTools.createCheckMenuItem(defaultActions.SHOW_ANALYSIS_PANE, null), defaultActions.BRIGHTNESS_CONTRAST, null, ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 0.25), "400%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 1), "100%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 2), "50%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 10), "10%"), ActionTools.createAction(() -> Commands.setViewerDownsample(viewer, 100), "1%"));
ToggleGroup groupTools = new ToggleGroup();
Menu menuTools = MenuTools.createMenu("Set tool", ActionTools.createCheckMenuItem(defaultActions.MOVE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.RECTANGLE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.ELLIPSE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.LINE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.POLYGON_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.POLYLINE_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.BRUSH_TOOL, groupTools), ActionTools.createCheckMenuItem(defaultActions.POINTS_TOOL, groupTools), null, ActionTools.createCheckMenuItem(defaultActions.SELECTION_MODE));
// Handle awkward 'TMA core missing' option
CheckMenuItem miTMAValid = new CheckMenuItem("Set core valid");
miTMAValid.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), false));
CheckMenuItem miTMAMissing = new CheckMenuItem("Set core missing");
miTMAMissing.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), true));
Menu menuTMA = new Menu("TMA");
MenuTools.addMenuItems(menuTMA, miTMAValid, miTMAMissing, null, defaultActions.TMA_ADD_NOTE, null, MenuTools.createMenu("Add", createImageDataAction(imageData -> TMACommands.promptToAddRowBeforeSelected(imageData), "Add TMA row before"), createImageDataAction(imageData -> TMACommands.promptToAddRowAfterSelected(imageData), "Add TMA row after"), createImageDataAction(imageData -> TMACommands.promptToAddColumnBeforeSelected(imageData), "Add TMA column before"), createImageDataAction(imageData -> TMACommands.promptToAddColumnAfterSelected(imageData), "Add TMA column after")), MenuTools.createMenu("Remove", createImageDataAction(imageData -> TMACommands.promptToDeleteTMAGridRow(imageData), "Remove TMA row"), createImageDataAction(imageData -> TMACommands.promptToDeleteTMAGridColumn(imageData), "column")));
// Create an empty placeholder menu
Menu menuSetClass = MenuTools.createMenu("Set class");
// CheckMenuItem miTMAValid = new CheckMenuItem("Set core valid");
// miTMAValid.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), false));
// CheckMenuItem miTMAMissing = new CheckMenuItem("Set core missing");
// miTMAMissing.setOnAction(e -> setTMACoreMissing(viewer.getHierarchy(), true));
Menu menuCells = MenuTools.createMenu("Cells", ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_BOUNDARIES_AND_NUCLEI, null), ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_NUCLEI, null), ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_BOUNDARIES, null), ActionTools.createCheckMenuItem(defaultActions.SHOW_CELL_CENTROIDS, null));
MenuItem miClearSelectedObjects = new MenuItem("Delete object");
miClearSelectedObjects.setOnAction(e -> {
PathObjectHierarchy hierarchy = viewer.getHierarchy();
if (hierarchy == null)
return;
if (hierarchy.getSelectionModel().singleSelection()) {
GuiTools.promptToRemoveSelectedObject(hierarchy.getSelectionModel().getSelectedObject(), hierarchy);
} else {
GuiTools.promptToClearAllSelectedObjects(viewer.getImageData());
}
});
// Create a standard annotations menu
Menu menuAnnotations = GuiTools.populateAnnotationsMenu(this, new Menu("Annotations"));
SeparatorMenuItem topSeparator = new SeparatorMenuItem();
popup.setOnShowing(e -> {
// Check if we have any cells
ImageData<?> imageData = viewer.getImageData();
if (imageData == null)
menuCells.setVisible(false);
else
menuCells.setVisible(!imageData.getHierarchy().getDetectionObjects().isEmpty());
// Check what to show for TMA cores or annotations
Collection<PathObject> selectedObjects = viewer.getAllSelectedObjects();
PathObject pathObject = viewer.getSelectedObject();
menuTMA.setVisible(false);
if (pathObject instanceof TMACoreObject) {
boolean isMissing = ((TMACoreObject) pathObject).isMissing();
miTMAValid.setSelected(!isMissing);
miTMAMissing.setSelected(isMissing);
menuTMA.setVisible(true);
}
// Add clear objects option if we have more than one non-TMA object
if (imageData == null || imageData.getHierarchy().getSelectionModel().noSelection() || imageData.getHierarchy().getSelectionModel().getSelectedObject() instanceof TMACoreObject)
miClearSelectedObjects.setVisible(false);
else {
if (imageData.getHierarchy().getSelectionModel().singleSelection()) {
miClearSelectedObjects.setText("Delete object");
miClearSelectedObjects.setVisible(true);
} else {
miClearSelectedObjects.setText("Delete objects");
miClearSelectedObjects.setVisible(true);
}
}
boolean hasAnnotations = pathObject instanceof PathAnnotationObject || (!selectedObjects.isEmpty() && selectedObjects.stream().allMatch(p -> p.isAnnotation()));
updateSetAnnotationPathClassMenu(menuSetClass, viewer);
menuAnnotations.setVisible(hasAnnotations);
topSeparator.setVisible(hasAnnotations || pathObject instanceof TMACoreObject);
// Occasionally, the newly-visible top part of a popup menu can have the wrong size?
popup.setWidth(popup.getPrefWidth());
});
// popup.add(menuClassify);
popup.getItems().addAll(miClearSelectedObjects, menuTMA, menuSetClass, menuAnnotations, topSeparator, menuMultiview, menuCells, menuView, menuTools);
popup.setAutoHide(true);
// Enable circle pop-up for quick classification on right-click
CirclePopupMenu circlePopup = new CirclePopupMenu(viewer.getView(), null);
viewer.getView().addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
if ((e.isPopupTrigger() || e.isSecondaryButtonDown()) && e.isShiftDown() && !getAvailablePathClasses().isEmpty()) {
circlePopup.setAnimationDuration(Duration.millis(200));
updateSetAnnotationPathClassMenu(circlePopup, viewer);
circlePopup.show(e.getScreenX(), e.getScreenY());
e.consume();
return;
} else if (circlePopup.isShown())
circlePopup.hide();
if (e.isPopupTrigger() || e.isSecondaryButtonDown()) {
popup.show(viewer.getView().getScene().getWindow(), e.getScreenX(), e.getScreenY());
e.consume();
}
});
// // It's necessary to make the Window the owner, since otherwise the context menu does not disappear when clicking elsewhere on the viewer
// viewer.getView().setOnContextMenuRequested(e -> {
// popup.show(viewer.getView().getScene().getWindow(), e.getScreenX(), e.getScreenY());
// // popup.show(viewer.getView(), e.getScreenX(), e.getScreenY());
// });
}
use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.
the class GuiTools method promptToSetActiveAnnotationProperties.
/**
* Prompt the user to set properties for the currently-selected annotation(s).
*
* @param hierarchy current hierarchy
* @return true if changes to annotation properties were made, false otherwise.
*/
public static boolean promptToSetActiveAnnotationProperties(final PathObjectHierarchy hierarchy) {
PathObject currentObject = hierarchy.getSelectionModel().getSelectedObject();
if (currentObject == null || !currentObject.isAnnotation())
return false;
ROI roi = currentObject.getROI();
if (roi == null)
return false;
Collection<PathAnnotationObject> otherAnnotations = hierarchy.getSelectionModel().getSelectedObjects().stream().filter(p -> p.isAnnotation() && p != currentObject).map(p -> (PathAnnotationObject) p).collect(Collectors.toList());
if (promptToSetAnnotationProperties((PathAnnotationObject) currentObject, otherAnnotations)) {
hierarchy.fireObjectsChangedEvent(null, Collections.singleton(currentObject));
// Ensure the object is still selected
hierarchy.getSelectionModel().setSelectedObject(currentObject);
return true;
}
return false;
}
use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.
the class GuiTools method setSelectedAnnotationLock.
/**
* Set selected TMA cores to have the specified 'locked' status.
*
* @param hierarchy
* @param setToLocked
*/
private static void setSelectedAnnotationLock(final PathObjectHierarchy hierarchy, final boolean setToLocked) {
if (hierarchy == null)
return;
PathObject pathObject = hierarchy.getSelectionModel().getSelectedObject();
List<PathObject> changed = new ArrayList<>();
if (pathObject instanceof PathAnnotationObject) {
PathAnnotationObject annotation = (PathAnnotationObject) pathObject;
annotation.setLocked(setToLocked);
changed.add(annotation);
// Update any other selected cores to have the same status
for (PathObject pathObject2 : hierarchy.getSelectionModel().getSelectedObjects()) {
if (pathObject2 instanceof PathAnnotationObject) {
annotation = (PathAnnotationObject) pathObject2;
if (annotation.isLocked() != setToLocked) {
annotation.setLocked(setToLocked);
changed.add(annotation);
}
}
}
}
if (!changed.isEmpty())
hierarchy.fireObjectsChangedEvent(GuiTools.class, changed);
}
use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.
the class IJExtension method extractOverlay.
/**
* Extract an ImageJ overlay for the specified region.
* @param hierarchy
* @param request
* @param options options to control which objects are being displayed
* @param filter optional additional filter used to determine which objects will be included (may be used in combination with options)
* @return
*/
public static Overlay extractOverlay(PathObjectHierarchy hierarchy, RegionRequest request, OverlayOptions options, Predicate<PathObject> filter) {
Overlay overlay = new Overlay();
double downsample = request.getDownsample();
double xOrigin = -request.getX() / downsample;
double yOrigin = -request.getY() / downsample;
// TODO: Permit filling/unfilling ROIs
for (PathObject child : hierarchy.getObjectsForRegion(PathObject.class, request, null)) {
if (filter != null && !filter.test(child))
continue;
if (child.hasROI()) {
// Check if this is displayed - skip it not
if (options != null && ((child instanceof PathDetectionObject && !options.getShowDetections()) || (child instanceof PathAnnotationObject && !options.getShowAnnotations()) || (child instanceof TMACoreObject && !options.getShowTMAGrid())))
continue;
boolean isCell = child instanceof PathCellObject;
Color color = ColorToolsAwt.getCachedColor(ColorToolsFX.getDisplayedColorARGB(child));
if (!(isCell && (options == null || !options.getShowCellBoundaries()))) {
Roi roi = IJTools.convertToIJRoi(child.getROI(), xOrigin, yOrigin, downsample);
roi.setStrokeColor(color);
roi.setName(child.getDisplayedName());
// roi.setStrokeWidth(2);
overlay.add(roi);
}
if (isCell && (options == null || options.getShowCellNuclei())) {
ROI nucleus = ((PathCellObject) child).getNucleusROI();
if (nucleus == null)
continue;
Roi roi = IJTools.convertToIJRoi(((PathCellObject) child).getNucleusROI(), xOrigin, yOrigin, downsample);
roi.setStrokeColor(color);
roi.setName(child.getDisplayedName() + " - nucleus");
overlay.add(roi);
}
}
}
return overlay;
}
use of qupath.lib.objects.PathAnnotationObject in project qupath by qupath.
the class AbstractPathROITool method commitObjectToHierarchy.
/**
* When drawing an object is complete, add it to the hierarchy - or whatever else is required.
*
* @param e
* @param pathObject
*/
void commitObjectToHierarchy(MouseEvent e, PathObject pathObject) {
if (pathObject == null)
return;
var viewer = getViewer();
PathObjectHierarchy hierarchy = viewer.getHierarchy();
var currentROI = pathObject.getROI();
// If we are in selection mode, try to get objects to select
if (PathPrefs.selectionModeProperty().get()) {
var pathClass = PathPrefs.autoSetAnnotationClassProperty().get();
var toSelect = hierarchy.getObjectsForROI(null, currentROI);
if (!toSelect.isEmpty() && pathClass != null) {
boolean retainIntensityClass = !(PathClassTools.isPositiveOrGradedIntensityClass(pathClass) || PathClassTools.isNegativeClass(pathClass));
var reclassified = toSelect.stream().filter(p -> p.getPathClass() != pathClass).map(p -> new Reclassifier(p, pathClass, retainIntensityClass)).filter(r -> r.apply()).map(r -> r.getPathObject()).collect(Collectors.toList());
if (!reclassified.isEmpty()) {
hierarchy.fireObjectClassificationsChangedEvent(this, reclassified);
}
}
if (pathObject.getParent() != null)
hierarchy.removeObject(pathObject, true);
// viewer.getHierarchy().fireHierarchyChangedEvent(this);
if (toSelect.isEmpty())
viewer.setSelectedObject(null);
else if (e.isShiftDown()) {
hierarchy.getSelectionModel().deselectObject(pathObject);
hierarchy.getSelectionModel().selectObjects(toSelect);
} else
hierarchy.getSelectionModel().setSelectedObjects(toSelect, null);
} else {
if (!requestParentClipping(e)) {
if (currentROI.isEmpty()) {
pathObject = null;
} else
// Ensure object is within the hierarchy
hierarchy.addPathObject(pathObject);
} else {
ROI roiNew = refineROIByParent(pathObject.getROI());
if (roiNew.isEmpty()) {
hierarchy.removeObject(pathObject, true);
pathObject = null;
} else {
((PathAnnotationObject) pathObject).setROI(roiNew);
hierarchy.addPathObjectBelowParent(getCurrentParent(), pathObject, true);
}
}
if (pathObject != null)
viewer.setSelectedObject(pathObject);
else
viewer.getHierarchy().getSelectionModel().clearSelection();
}
var editor = viewer.getROIEditor();
editor.ensureHandlesUpdated();
editor.resetActiveHandle();
if (preferReturnToMove()) {
var qupath = QuPathGUI.getInstance();
if (qupath != null)
qupath.setSelectedTool(PathTools.MOVE);
}
}
Aggregations