19 package org.sleuthkit.autopsy.contentviewers.imagetagging;
24 import java.beans.PropertyChangeEvent;
25 import java.beans.PropertyChangeListener;
26 import java.beans.PropertyChangeSupport;
27 import javafx.collections.ListChangeListener;
28 import javafx.scene.Cursor;
29 import javafx.scene.Group;
30 import javafx.scene.Node;
31 import javafx.scene.control.Tooltip;
32 import javafx.scene.image.ImageView;
33 import javafx.scene.input.MouseEvent;
34 import javafx.scene.paint.Color;
35 import javafx.scene.shape.Circle;
36 import javafx.scene.shape.Rectangle;
56 private final PropertyChangeSupport
pcs =
new PropertyChangeSupport(
this);
63 this.appTag = contentViewerTag;
71 physicalTag =
new PhysicalTag(details);
74 Boundary dragBoundary = (x, y) -> {
75 double boundingX = image.getX();
76 double boundingY = image.getY();
77 double width = image.getImage().getWidth();
78 double height = image.getImage().getHeight();
86 EditHandle bottomLeft =
new EditHandle(physicalTag)
87 .setPosition(Position.bottom(), Position.left())
88 .setDrag(dragBoundary, Draggable.bottom(), Draggable.left());
90 EditHandle bottomRight =
new EditHandle(physicalTag)
91 .setPosition(Position.bottom(), Position.right())
92 .setDrag(dragBoundary, Draggable.bottom(), Draggable.right());
94 EditHandle topLeft =
new EditHandle(physicalTag)
95 .setPosition(Position.top(), Position.left())
96 .setDrag(dragBoundary, Draggable.top(), Draggable.left());
98 EditHandle topRight =
new EditHandle(physicalTag)
99 .setPosition(Position.top(), Position.right())
100 .setDrag(dragBoundary, Draggable.top(), Draggable.right());
102 EditHandle bottomMiddle =
new EditHandle(physicalTag)
103 .setPosition(Position.bottom(), Position.xMiddle())
104 .setDrag(dragBoundary, Draggable.bottom());
106 EditHandle topMiddle =
new EditHandle(physicalTag)
107 .setPosition(Position.top(), Position.xMiddle())
108 .setDrag(dragBoundary, Draggable.top());
110 EditHandle rightMiddle =
new EditHandle(physicalTag)
111 .setPosition(Position.right(), Position.yMiddle())
112 .setDrag(dragBoundary, Draggable.right());
114 EditHandle leftMiddle =
new EditHandle(physicalTag)
115 .setPosition(Position.left(), Position.yMiddle())
116 .setDrag(dragBoundary, Draggable.left());
119 this.getChildren().addAll(physicalTag, bottomLeft, bottomRight, topLeft,
120 topRight, bottomMiddle, topMiddle, rightMiddle, leftMiddle);
122 Tooltip.install(
this,
new Tooltip(contentViewerTag.
getContentTag()
123 .getName().getDisplayName()));
136 pcs.addPropertyChangeListener(listener);
140 return physicalTag.getWidth();
144 return physicalTag.getHeight();
159 class PhysicalTag
extends Rectangle {
162 this.setStroke(Color.RED);
163 this.setFill(Color.RED.deriveColor(0, 0, 0, 0));
166 setX(details.
getX());
167 setY(details.
getY());
193 class EditHandle
extends Circle {
195 private final PhysicalTag parent;
197 public EditHandle(PhysicalTag parent) {
198 this.setVisible(
false);
201 this.addEventHandler(ImageTagControls.NOT_FOCUSED, event ->
this.setVisible(
false));
202 this.addEventHandler(ImageTagControls.FOCUSED, event ->
this.setVisible(
true));
204 this.setRadius(parent.getStrokeWidth());
205 this.setFill(parent.getStroke());
207 this.setOnDragDetected(event -> {
208 this.getParent().setCursor(Cursor.CLOSED_HAND);
211 this.setOnMouseReleased(event -> {
212 this.getParent().setCursor(Cursor.DEFAULT);
213 pcs.firePropertyChange(
new PropertyChangeEvent(
this,
"Tag Edit", null, parent.getState()));
216 this.parent = parent;
225 public EditHandle setPosition(Position... vals) {
226 for (Position pos : vals) {
227 parent.widthProperty().addListener((obs, oldVal, newVal) -> pos.set(parent,
this));
228 parent.heightProperty().addListener((obs, oldVal, newVal) -> pos.set(parent,
this));
229 pos.set(parent,
this);
241 public EditHandle setDrag(Boundary bounds, Draggable... vals) {
242 this.setOnMouseDragged((event) -> {
243 for (Draggable drag : vals) {
244 drag.perform(parent, event, bounds);
255 static interface Position {
257 void set(PhysicalTag parent, Circle knob);
259 static Position left() {
260 return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty());
263 static Position right() {
264 return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth()));
267 static Position top() {
268 return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty());
271 static Position bottom() {
272 return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight()));
275 static Position xMiddle() {
276 return (parent, knob) -> knob.centerXProperty().bind(parent.xProperty().add(parent.getWidth() / 2));
279 static Position yMiddle() {
280 return (parent, knob) -> knob.centerYProperty().bind(parent.yProperty().add(parent.getHeight() / 2));
288 static interface Boundary {
290 boolean isPointInBounds(
double x,
double y);
297 static interface Draggable {
299 void perform(PhysicalTag parent, MouseEvent event, Boundary b);
301 static Draggable bottom() {
302 return (parent, event, bounds) -> {
303 if (!bounds.isPointInBounds(event.getX(),
event.getY())) {
307 double deltaY =
event.getY() - parent.getY();
309 parent.setHeight(deltaY);
314 static Draggable top() {
315 return (parent, event, bounds) -> {
316 if (!bounds.isPointInBounds(event.getX(),
event.getY())) {
320 double deltaY = parent.getY() + parent.getHeight() -
event.getY();
321 if (deltaY < parent.getY() + parent.getHeight() && deltaY > 0) {
322 parent.setHeight(deltaY);
323 parent.setY(event.getY());
328 static Draggable left() {
329 return (parent, event, bounds) -> {
330 if (!bounds.isPointInBounds(event.getX(),
event.getY())) {
334 double deltaX = parent.getX() + parent.getWidth() -
event.getX();
335 if (deltaX < parent.getX() + parent.getWidth() && deltaX > 0) {
336 parent.setWidth(deltaX);
337 parent.setX(event.getX());
342 static Draggable right() {
343 return (parent, event, bounds) -> {
344 if (!bounds.isPointInBounds(event.getX(),
event.getY())) {
348 double deltaX =
event.getX() - parent.getX();
350 parent.setWidth(deltaX);
final PropertyChangeSupport pcs
ImageTagRegion setHeight(double height)
ImageTagRegion setStrokeThickness(double thickness)
ImageTagRegion setY(double y)
static final EventType< Event > FOCUSED
ImageTagRegion setWidth(double width)
ContentViewerTag< ImageTagRegion > getContentViewerTag()
static final EventType< Event > NOT_FOCUSED
double getStrokeThickness()
ContentTag getContentTag()
final ContentViewerTag< ImageTagRegion > appTag
ImageTag(ContentViewerTag< ImageTagRegion > contentViewerTag, ImageView image)
ImageTagRegion setX(double x)
final PhysicalTag physicalTag
void subscribeToEditEvents(PropertyChangeListener listener)