Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jhotdraw8.draw.tool.TextCreationTool Maven / Gradle / Ivy
/*
* @(#)TextCreationTool.java
* Copyright © 2023 The authors and contributors of JHotDraw. MIT License.
*/
package org.jhotdraw8.draw.tool;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.Cursor;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseEvent;
import org.jspecify.annotations.Nullable;
import org.jhotdraw8.application.resources.Resources;
import org.jhotdraw8.base.util.MathUtil;
import org.jhotdraw8.css.value.CssSize;
import org.jhotdraw8.draw.DrawingEditor;
import org.jhotdraw8.draw.DrawingView;
import org.jhotdraw8.draw.constrain.Constrainer;
import org.jhotdraw8.draw.css.value.CssPoint2D;
import org.jhotdraw8.draw.figure.AnchorableFigure;
import org.jhotdraw8.draw.figure.Figure;
import org.jhotdraw8.draw.figure.Layer;
import org.jhotdraw8.draw.figure.LayerFigure;
import org.jhotdraw8.draw.figure.TextEditableFigure;
import org.jhotdraw8.draw.handle.HandleType;
import org.jhotdraw8.draw.model.DrawingModel;
import java.util.function.Supplier;
import static java.lang.Math.abs;
import static java.lang.Math.max;
/**
* TextCreationTool.
*
* @author Werner Randelshofer
*/
public class TextCreationTool extends AbstractCreationTool {
private double defaultWidth = 100;
private double defaultHeight = 100;
private final TextArea textArea = new TextArea();
private TextEditableFigure.@Nullable TextEditorData editorData;
/**
* The rubber band.
*/
private double x1, y1, x2, y2;
/**
* The minimum size of a created figure (in view coordinates.
*/
private final double minSize = 2;
public TextCreationTool(String name, Resources rsrc, Supplier factory) {
this(name, rsrc, factory, LayerFigure::new);
}
public TextCreationTool(String name, Resources rsrc, Supplier figureFactory, Supplier layerFactory) {
super(name, rsrc, figureFactory, layerFactory);
node.setCursor(Cursor.CROSSHAIR);
textArea.setWrapText(true);
textArea.setOnKeyPressed(keyEvent -> {
if (keyEvent.getCode() == KeyCode.ESCAPE) {
keyEvent.consume();
stopEditing();
}
});
}
public double getDefaultHeight() {
return defaultHeight;
}
public void setDefaultHeight(double defaultHeight) {
this.defaultHeight = defaultHeight;
}
public double getDefaultWidth() {
return defaultWidth;
}
public void setDefaultWidth(double defaultWidth) {
this.defaultWidth = defaultWidth;
}
@Override
protected void stopEditing() {
if (editorData != null) {
node.getChildren().remove(textArea);
DrawingView drawingView = getDrawingView();
if (drawingView != null) {
DrawingModel model = drawingView.getModel();
model.set(editorData.figure(), editorData.textKey(), textArea.getText());
}
editorData = null;
}
createdFigure = null;
}
@Override
protected void onMousePressed(MouseEvent event, DrawingView view) {
event.consume();
if (editorData != null) {
stopEditing();
fireToolDone();
return;
}
x1 = event.getX();
y1 = event.getY();
x2 = x1;
y2 = y1;
createdFigure = createFigure();
Figure parent = createdFigure == null ? null : getOrCreateParent(view, createdFigure);
if (parent == null) {
createdFigure = null;
event.consume();
return;
}
view.setActiveParent(parent);
DrawingModel dm = view.getModel();
dm.addChildTo(createdFigure, parent);
double anchorX = MathUtil.clamp(createdFigure.getNonNull(AnchorableFigure.ANCHOR_X), 0, 1);
double anchorY = MathUtil.clamp(createdFigure.getNonNull(AnchorableFigure.ANCHOR_Y), 0, 1);
CssPoint2D c = view.getConstrainer().constrainPoint(createdFigure, new CssPoint2D(
createdFigure.worldToParent(view.viewToWorld(new Point2D(x1, y1)))));
createdFigure.reshapeInLocal(
anchorX == 0 ? c.getX() : c.getX().subtract(CssSize.of(defaultWidth).multiply(anchorX)),
anchorY == 0 ? c.getY() : c.getY().subtract(CssSize.of(defaultHeight).multiply(anchorY)),
CssSize.of(defaultWidth), CssSize.of(defaultHeight));
}
private void startEditing(TextEditableFigure.TextEditorData data, DrawingView dv) {
dv.getSelectedFigures().clear();
dv.getEditor().setHandleType(HandleType.SELECT);
dv.getSelectedFigures().add(data.figure());
editorData = data;
textArea.setManaged(false);
node.getChildren().add(textArea);
Bounds bounds = dv.worldToView(data.figure().localToWorld(data.boundsInLocal()));
textArea.resizeRelocate(bounds.getMinX(), bounds.getMinY(), max(80, max(textArea.getMinWidth(), bounds.getWidth())),
max(40, max(textArea.getMinHeight(), bounds.getHeight())));
textArea.setText(data.figure().get(editorData.textKey()));
textArea.requestFocus();
}
@Override
protected void onMouseReleased(MouseEvent event, DrawingView dv) {
event.consume();
if (editorData != null) {
return;
}
if (createdFigure != null) {
event.consume();
if (abs(x2 - x1) < minSize && abs(y2 - y1) < minSize) {
CssPoint2D c1 = dv.getConstrainer().constrainPoint(createdFigure, new CssPoint2D(
createdFigure.worldToParent(dv.viewToWorld(x1, y1))));
CssPoint2D c2 = dv.getConstrainer().translatePoint(createdFigure, new CssPoint2D(
createdFigure.worldToParent(dv.viewToWorld(x1
+ defaultWidth, y1 + defaultHeight))), Constrainer.DIRECTION_NEAREST);
if (c2.equals(c1)) {
c2 = dv.getConstrainer().constrainPoint(createdFigure, new CssPoint2D(c1.getX().getConvertedValue() + defaultWidth, c1.getY().getConvertedValue() + defaultHeight));
}
DrawingModel dm = dv.getModel();
dm.reshapeInLocal(createdFigure, c1.getX(), c1.getY(),
c2.getX().subtract(c1.getX()),
c2.getY().subtract(c1.getY()));
}
dv.selectedFiguresProperty().clear();
dv.selectedFiguresProperty().add(createdFigure);
TextEditableFigure.TextEditorData data = ((TextEditableFigure) createdFigure).getTextEditorDataFor(null, null);
createdFigure = null;
if (data != null) {
startEditing(data, dv);
} else {
fireToolDone();
}
}
}
@Override
protected void onMouseDragged(MouseEvent event, DrawingView dv) {
if (editorData != null) {
return;
}
if (createdFigure != null) {
x2 = event.getX();
y2 = event.getY();
CssPoint2D c1 = dv.getConstrainer().constrainPoint(createdFigure, new CssPoint2D(
createdFigure.worldToParent(dv.viewToWorld(x1, y1))));
CssPoint2D c2 = dv.getConstrainer().constrainPoint(createdFigure, new CssPoint2D(
createdFigure.worldToParent(dv.viewToWorld(x2, y2))));
CssSize newWidth = c2.getX().subtract(c1.getX());
CssSize newHeight = c2.getY().subtract(c1.getY());
// shift keeps the aspect ratio
boolean keepAspect = event.isShiftDown();
if (keepAspect) {
double preferredAspectRatio = createdFigure.getPreferredAspectRatio();
double newRatio = newHeight.getConvertedValue() / newWidth.getConvertedValue();
if (newRatio > preferredAspectRatio) {
newHeight = CssSize.of(newWidth.getConvertedValue() * preferredAspectRatio);
} else {
newWidth = CssSize.of(newHeight.getConvertedValue() / preferredAspectRatio);
}
}
DrawingModel dm = dv.getModel();
dm.reshapeInLocal(createdFigure, c1.getX(), c1.getY(), newWidth, newHeight);
}
event.consume();
}
/**
* This implementation is empty.
*/
@Override
public void activate(DrawingEditor editor) {
requestFocus();
super.activate(editor);
}
@Override
public String getHelpText() {
return """
CreationTool
Click on the drawing view. The tool will create a new figure with default size at the clicked location.
Or:
Press and drag the mouse over the drawing view to define the diagonal of a rectangle. The tool will create a new figure that fits into the rectangle.""";
}
}