import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javafx.animation.PathTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.geometry.VPos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.Slider;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TitledPane;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Effect;
import javafx.scene.effect.Glow;
import javafx.scene.effect.Reflection;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Shear;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
import javafx.stage.FileChooser;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.util.converter.DoubleStringConverter;
import javax.imageio.ImageIO;
/**
* Demonstrates how three bounds - layoutBounds, boundsInLocal, and boundsInParent - are
* computed for a node. JavaFX 2.2 is required to use this class.
*
* @author Kishori Sharan (www.jdojo.com)
* @version 1.0
*
* <b>@copyright</b> You can use, modify, copy-paste the code for any purpose, in any way you see fit. No restrictions apply.
*/
@SuppressWarnings("deprecation")
public class Main extends Application {
final static int AXIS_LENGTH = 150;
final static int ARROW_LENGTH = 5;
final static int RECTANGLE_WIDTH = 50;
final static int RECTANGLE_HEIGHT = 20;
final static double RECTANGLE_OPACITY = 0.5;
final static Color RECTANGLE_STROKE_COLOR = Color.PURPLE;
final static String RECTANGLE_STROKE_COLOR_STR = "PURPLE";
final static double RECTANGLE_STROKE_WIDTH = 0.0;
final static Color RECTANGLE_FILL_COLOR = Color.DARKGRAY;
final static String RECTANGLE_FILL_COLOR_STR = "DARKGRAY";
Slider xSlider = new Slider(-100, 100, 0);
Slider ySlider = new Slider(-100, 100, 0);
Slider widthSlider = new Slider(10, 200, RECTANGLE_WIDTH);
Slider heightSlider = new Slider(10, 200, RECTANGLE_HEIGHT);
Slider opacitySlider = new Slider(0, 1.0, RECTANGLE_OPACITY);
Slider strokeSlider = new Slider(0.0, 10.0, RECTANGLE_STROKE_WIDTH);
ObservableList<String> colorList =
FXCollections.observableArrayList("BLUE", "DARKBLUE", "DARKGRAY", "DARKRED", "GRAY", "GREEN", "RED", "PURPLE",
"YELLOW", "BLACK");
ChoiceBox<String> rectFillColorChoiceBox = new ChoiceBox<String>(colorList);
ChoiceBox<String> rectStrokeColorChoiceBox = new ChoiceBox<String>(colorList);
Slider translateXSlider = new Slider(-200, 200, 0);
Slider translateYSlider = new Slider(-200, 200, 0);
Slider rotateSlider = new Slider(0, 360, 0);
Slider scaleXSlider = new Slider(0.20, 2.0, 1.0);
Slider scaleYSlider = new Slider(0.20, 2.0, 1.0);
Slider shearXSlider = new Slider(-1.0, 1.0, 0);
Slider shearYSlider = new Slider(-1.0, 1.0, 0);
Label xLabel = new Label("");
Label yLabel = new Label("");
Label widthLabel = new Label("");
Label heightLabel = new Label("");
Label opacityLabel = new Label("");
Label strokeLabel = new Label("");
Label translateXLabel = new Label("");
Label translateYLabel = new Label("");
Label rotateLabel = new Label("");
Label scaleXLabel = new Label("");
Label scaleYLabel = new Label("");
Label shearXLabel = new Label("");
Label shearYLabel = new Label("");
Rectangle mainRect = new Rectangle(0, 0, RECTANGLE_WIDTH, RECTANGLE_HEIGHT);
Rectangle localBoundsRect = new Rectangle();
Rectangle parentBoundsRect = new Rectangle();
Rectangle layoutBoundsRect = new Rectangle();
Line localXAxis = new Line(0, 0, AXIS_LENGTH, 0);
Line localYAxis = new Line(0, 0, 0, AXIS_LENGTH);
Polygon localXArrow =
new Polygon(AXIS_LENGTH, -ARROW_LENGTH, AXIS_LENGTH, ARROW_LENGTH, AXIS_LENGTH + ARROW_LENGTH, 0, AXIS_LENGTH,
-ARROW_LENGTH);
Text localXAxisLabel = new Text("x-axis");
Polygon localYArrow =
new Polygon(0, AXIS_LENGTH + ARROW_LENGTH, -ARROW_LENGTH, AXIS_LENGTH, ARROW_LENGTH, AXIS_LENGTH, 0,
AXIS_LENGTH + ARROW_LENGTH);
Text localYAxisLabel = new Text("y-axis");
Group localXAxisGroup = new Group(localXAxis, localXArrow, localXAxisLabel);
Group localYAxisGroup = new Group(localYAxis, localYArrow, localYAxisLabel);
Line parentXAxis = new Line(0, 0, AXIS_LENGTH, 0);
Line parentYAxis = new Line(0, 0, 0, AXIS_LENGTH);
Polygon parentXArrow =
new Polygon(AXIS_LENGTH, -ARROW_LENGTH, AXIS_LENGTH, ARROW_LENGTH, AXIS_LENGTH + ARROW_LENGTH, 0, AXIS_LENGTH,
-ARROW_LENGTH);
Text parentXAxisLabel = new Text("x-axis");
Polygon parentYArrow =
new Polygon(0, AXIS_LENGTH + ARROW_LENGTH, -ARROW_LENGTH, AXIS_LENGTH, ARROW_LENGTH, AXIS_LENGTH, 0,
AXIS_LENGTH + ARROW_LENGTH);
Text parentYAxisLabel = new Text("y-axis");
Group parentXAxisGroup = new Group(parentXAxis, parentXArrow, parentXAxisLabel);
Group parentYAxisGroup = new Group(parentYAxis, parentYArrow, parentYAxisLabel);
CheckBox layoutCbx = new CheckBox("Show");
CheckBox localCbx = new CheckBox("Show");
CheckBox parentCbx = new CheckBox("Show");
CheckBox layoutAnimateCbx = new CheckBox("Animate");
CheckBox localAnimateCbx = new CheckBox("Animate");
CheckBox parentAnimateCbx = new CheckBox("Animate");
ToggleGroup effectGroup = new ToggleGroup();
RadioButton noneEffect = new RadioButton("None");
RadioButton dropshadowEffect = new RadioButton("DropShadow");
RadioButton reflectionEffect = new RadioButton("Reflection");
RadioButton glowEffect = new RadioButton("Glow");
final Color LOCAL_BOUNDS_RECT_FILL_COLOR = Color.WHITE;
final Color PARENT_BOUNDS_RECT_FILL_COLOR = Color.WHITE;
final Color LAYOUT_BOUNDS_RECT_FILL_COLOR = Color.WHITE;
final Color LOCAL_BOUNDS_RECT_STROKE_COLOR = Color.BLUE;
final Color PARENT_BOUNDS_RECT_STROKE_COLOR = Color.RED;
final Color LAYOUT_BOUNDS_RECT_STROKE_COLOR = Color.BLACK;
final double BOUNDS_STROKE_WIDTH = 2.0;
final double BOUNDS_PATH_CIRCLE_RADIUS = 4.0;
// Animating the bounds bounding boxes
final Circle LOCAL_BOUNDS_PATH_CIRCLE = new Circle(0, 0, BOUNDS_PATH_CIRCLE_RADIUS);
final Circle PARENT_BOUNDS_PATH_CIRCLE = new Circle(0, 0, BOUNDS_PATH_CIRCLE_RADIUS);
final Circle LAYOUT_BOUNDS_PATH_CIRCLE = new Circle(0, 0, BOUNDS_PATH_CIRCLE_RADIUS);
final PathTransition LOCAL_BOUNDS_PATH_TRANSITION = new PathTransition();
final PathTransition PARENT_BOUNDS_PATH_TRANSITION = new PathTransition();
final PathTransition LAYOUT_BOUNDS_PATH_TRANSITION = new PathTransition();
public class BoundsRecord {
private DoubleProperty x = new SimpleDoubleProperty();
private DoubleProperty y = new SimpleDoubleProperty();
private DoubleProperty w = new SimpleDoubleProperty();
private DoubleProperty h = new SimpleDoubleProperty();
private StringProperty boundsType = new SimpleStringProperty();
public BoundsRecord(String boundsType) {
this.boundsType.set(boundsType);
}
public BoundsRecord(String boundsType, Bounds b) {
this.boundsType.set(boundsType);
x.set(b.getMinX());
y.set(b.getMinY());
w.set(b.getWidth());
h.set(b.getHeight());
}
public void update(Bounds b) {
x.set(b.getMinX());
y.set(b.getMinY());
w.set(b.getWidth());
h.set(b.getHeight());
}
public String getBoundsType() {
return boundsType.get();
}
public double getX() {
return x.get();
}
public double getY() {
return y.get();
}
public double getW() {
return w.get();
}
public double getH() {
return h.get();
}
public StringProperty boundsTypeProperty() {
return this.boundsType;
}
public DoubleProperty xProperty() {
return this.x;
}
public DoubleProperty yProperty() {
return this.y;
}
public DoubleProperty wProperty() {
return this.w;
}
public DoubleProperty hProperty() {
return this.h;
}
}
BoundsRecord layoutBoundsData = new BoundsRecord("layoutBounds");
BoundsRecord localBoundsData = new BoundsRecord("boundsInLocal");
BoundsRecord parentBoundsData = new BoundsRecord("boundsInParent");
ObservableList<BoundsRecord> boundsList =
FXCollections.observableArrayList(layoutBoundsData, localBoundsData, parentBoundsData);
private TableView<BoundsRecord> boundsTableView = new TableView<>(boundsList);
private Node boundsLayoutNode;
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void init() {
int axisLabelPos = AXIS_LENGTH + ARROW_LENGTH + 4;
localXAxisLabel.setLayoutX(axisLabelPos);
localXAxisLabel.setTextOrigin(VPos.CENTER);
localYAxisLabel.setLayoutY(axisLabelPos);
localYAxisLabel.setTextOrigin(VPos.CENTER);
parentXAxisLabel.setLayoutX(axisLabelPos);
parentXAxisLabel.setTextOrigin(VPos.CENTER);
parentYAxisLabel.setLayoutY(axisLabelPos);
parentYAxisLabel.setTextOrigin(VPos.CENTER);
String textFont = "-fx-font-size:9;";
localXAxisLabel.setStyle(textFont);
localYAxisLabel.setStyle(textFont);
parentXAxisLabel.setStyle(textFont);
parentYAxisLabel.setStyle(textFont);
mainRect.setFill(RECTANGLE_FILL_COLOR);
rectFillColorChoiceBox.setValue(RECTANGLE_FILL_COLOR_STR);
rectStrokeColorChoiceBox.setValue(RECTANGLE_STROKE_COLOR_STR);
initializeBoundsDetails();
initializeBoundsPathTransition();
// Bind labels to slider values
bindLabelsToSliders();
// Initialize Bounds Table View
initializeBoundsTableView();
}
@Override
public void start(Stage stage) {
BorderPane root = new BorderPane();
Pane parentContainer = new Pane();
parentContainer.setPrefSize(500, 500);
parentContainer.setPickOnBounds(false);
//Pane parent = new Pane();
Group parent = new Group();
boundsLayoutNode = parent;
//parent.setPrefSize(300, 200);
parent.setLayoutX(200);
parent.setLayoutY(200);
parent.setStyle("-fx-background-color:white;");
parent.getChildren().addAll(new Group(localXAxisGroup, localYAxisGroup),
new Group(parentXAxisGroup, parentYAxisGroup), new Group(parentBoundsRect, PARENT_BOUNDS_PATH_CIRCLE),
new Group(localBoundsRect, LOCAL_BOUNDS_PATH_CIRCLE), new Group(layoutBoundsRect, LAYOUT_BOUNDS_PATH_CIRCLE),
new Group(mainRect));
parentContainer.getChildren().addAll(parent);
VBox transformsControls = getTransformationControls();
VBox resultsControls = getResultsControls();
BorderPane nestedPane = new BorderPane();
nestedPane.setCenter(parentContainer);
nestedPane.setBottom(resultsControls);
//nestedPane.setTop(printDataTextArea);
//printDataTextArea.setPrefColumnCount(40);
//printDataTextArea.setPrefRowCount(3);
root.setCenter(nestedPane);
root.setRight(transformsControls);
//root.setBottom(resultsControls);
//root.setCenter(parentContainer);
// Attach event handlers
attachEventHandlers();
Scene scene = new Scene(root); //, 600, 400);
stage.setScene(scene);
stage.setTitle("Bounds of a Node");
Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
stage.setX(visualBounds.getMinX());
stage.setY(visualBounds.getMinY());
stage.setWidth(visualBounds.getWidth());
stage.setHeight(visualBounds.getHeight());
stage.show();
// Make sure everything is in sync
relayout();
}
private void initializeBoundsDetails() {
localBoundsRect.setStroke(LOCAL_BOUNDS_RECT_STROKE_COLOR);
localBoundsRect.setFill(LOCAL_BOUNDS_RECT_FILL_COLOR);
localBoundsRect.setStrokeWidth(BOUNDS_STROKE_WIDTH);
localBoundsRect.setOpacity(0.5);
parentBoundsRect.setStroke(PARENT_BOUNDS_RECT_STROKE_COLOR);
parentBoundsRect.setFill(PARENT_BOUNDS_RECT_FILL_COLOR);
parentBoundsRect.setStrokeWidth(BOUNDS_STROKE_WIDTH);
parentBoundsRect.setOpacity(0.5);
layoutBoundsRect.setStroke(LAYOUT_BOUNDS_RECT_STROKE_COLOR);
layoutBoundsRect.setFill(LAYOUT_BOUNDS_RECT_FILL_COLOR);
layoutBoundsRect.setStrokeWidth(BOUNDS_STROKE_WIDTH);
layoutBoundsRect.setOpacity(0.5);
LOCAL_BOUNDS_PATH_CIRCLE.setFill(LOCAL_BOUNDS_RECT_STROKE_COLOR);
PARENT_BOUNDS_PATH_CIRCLE.setFill(PARENT_BOUNDS_RECT_STROKE_COLOR);
LAYOUT_BOUNDS_PATH_CIRCLE.setFill(LAYOUT_BOUNDS_RECT_STROKE_COLOR);
LOCAL_BOUNDS_PATH_CIRCLE.setVisible(false);
LAYOUT_BOUNDS_PATH_CIRCLE.setVisible(false);
PARENT_BOUNDS_PATH_CIRCLE.setVisible(false);
}
private VBox getResultsControls() {
VBox vBox = new VBox();
vBox.setSpacing(5);
vBox.getChildren().addAll(boundsTableView);
return vBox;
}
private void bindLabelsToSliders() {
xLabel.textProperty().bind(new SimpleStringProperty("x:").concat(xSlider.valueProperty().asString("%.2f")));
yLabel.textProperty().bind(new SimpleStringProperty("y:").concat(ySlider.valueProperty().asString("%.2f")));
widthLabel.textProperty().bind(new SimpleStringProperty("width:").concat(widthSlider.valueProperty().asString("%.2f")));
heightLabel.textProperty().bind(new SimpleStringProperty("height:").concat(heightSlider.valueProperty().asString("%.2f")));
opacityLabel.textProperty().bind(new SimpleStringProperty("opacity:").concat(opacitySlider.valueProperty().asString("%.2f")));
strokeLabel.textProperty().bind(new SimpleStringProperty("stroke:").concat(strokeSlider.valueProperty().asString("%.2f")));
translateXLabel.textProperty().bind(new SimpleStringProperty("TranslateX:").concat(translateXSlider.valueProperty().asString("%.2f")));
translateYLabel.textProperty().bind(new SimpleStringProperty("TranslateY:").concat(translateYSlider.valueProperty().asString("%.2f")));
rotateLabel.textProperty().bind(new SimpleStringProperty("Rotate:").concat(rotateSlider.valueProperty().asString("%.2f")).concat(" deg"));
scaleXLabel.textProperty().bind(new SimpleStringProperty("ScaleX:").concat(scaleXSlider.valueProperty().asString("%.2f")));
scaleYLabel.textProperty().bind(new SimpleStringProperty("ScaleY:").concat(scaleYSlider.valueProperty().asString("%.2f")));
shearXLabel.textProperty().bind(new SimpleStringProperty("ShearX:").concat(shearXSlider.valueProperty().asString("%.2f")));
shearYLabel.textProperty().bind(new SimpleStringProperty("ShearY:").concat(shearYSlider.valueProperty().asString("%.2f")));
}
private VBox getTransformationControls() {
xSlider.setShowTickMarks(true);
xSlider.setShowTickLabels(true);
xSlider.snapToTicksProperty().set(true);
ySlider.setShowTickMarks(true);
ySlider.setShowTickLabels(true);
ySlider.snapToTicksProperty().set(true);
widthSlider.setShowTickMarks(true);
widthSlider.setShowTickLabels(true);
widthSlider.snapToTicksProperty().set(true);
heightSlider.setShowTickMarks(true);
heightSlider.setShowTickLabels(true);
heightSlider.snapToTicksProperty().set(true);
opacitySlider.setShowTickMarks(true);
opacitySlider.setShowTickLabels(true);
opacitySlider.snapToTicksProperty().set(true);
opacitySlider.setMinorTickCount(5);
opacitySlider.setMajorTickUnit(0.20d);
strokeSlider.setShowTickMarks(true);
strokeSlider.setShowTickLabels(true);
strokeSlider.snapToTicksProperty().set(true);
strokeSlider.setMinorTickCount(5);
strokeSlider.setMajorTickUnit(1.0d);
translateXSlider.setShowTickMarks(true);
translateXSlider.setShowTickLabels(true);
translateXSlider.snapToTicksProperty().set(true);
translateYSlider.setShowTickMarks(true);
translateYSlider.setShowTickLabels(true);
translateYSlider.snapToTicksProperty().set(true);
rotateSlider.setShowTickMarks(true);
rotateSlider.setShowTickLabels(true);
rotateSlider.snapToTicksProperty().set(true);
rotateSlider.setMinorTickCount(5);
rotateSlider.setMajorTickUnit(30.0);
scaleXSlider.setShowTickMarks(true);
scaleXSlider.setShowTickLabels(true);
scaleXSlider.setMajorTickUnit(0.2d);
scaleXSlider.setLabelFormatter(new DoubleStringConverter());
scaleXSlider.snapToTicksProperty().set(true);
scaleYSlider.setShowTickMarks(true);
scaleYSlider.setShowTickLabels(true);
scaleYSlider.setMajorTickUnit(0.2d);
scaleYSlider.setLabelFormatter(new DoubleStringConverter());
scaleYSlider.snapToTicksProperty().set(true);
shearXSlider.setShowTickMarks(true);
shearXSlider.setShowTickLabels(true);
shearXSlider.setMajorTickUnit(0.2d);
shearXSlider.setLabelFormatter(new DoubleStringConverter());
shearXSlider.snapToTicksProperty().set(true);
shearYSlider.setShowTickMarks(true);
shearYSlider.setShowTickLabels(true);
shearYSlider.setMajorTickUnit(0.2d);
shearYSlider.setLabelFormatter(new DoubleStringConverter());
shearYSlider.snapToTicksProperty().set(true);
HBox xyBox = new HBox();
xyBox.setSpacing(5);
xyBox.getChildren().addAll(VBoxBuilder.create().children(xLabel, xSlider).build(),
VBoxBuilder.create().children(yLabel, ySlider).build());
HBox whBox = new HBox();
whBox.setSpacing(5);
whBox.getChildren().addAll(VBoxBuilder.create().children(widthLabel, widthSlider).build(),
VBoxBuilder.create().children(heightLabel, heightSlider).build());
HBox colorBox = new HBox();
colorBox.setSpacing(5);
colorBox.getChildren().addAll(VBoxBuilder.create().children(strokeLabel, strokeSlider).build(),
VBoxBuilder.create().children(new Label("Stroke Color"),
rectStrokeColorChoiceBox).build());
HBox opacityBox = new HBox();
opacityBox.setSpacing(5);
opacityBox.getChildren().addAll(VBoxBuilder.create().children(opacityLabel, opacitySlider).build(),
VBoxBuilder.create().children(new Label("Fill Color"),
rectFillColorChoiceBox).build());
HBox translateBox = new HBox();
translateBox.setSpacing(5);
translateBox.getChildren().addAll(VBoxBuilder.create().children(translateXLabel, translateXSlider).build(),
VBoxBuilder.create().children(translateYLabel, translateYSlider).build());
HBox rotateBox = new HBox();
rotateBox.setSpacing(5);
rotateBox.getChildren().addAll(VBoxBuilder.create().children(rotateLabel, rotateSlider).build());
HBox scaleBox = new HBox();
scaleBox.setSpacing(5);
scaleBox.getChildren().addAll(VBoxBuilder.create().children(scaleXLabel, scaleXSlider).build(),
VBoxBuilder.create().children(scaleYLabel, scaleYSlider).build());
HBox shearBox = new HBox();
shearBox.setSpacing(5);
shearBox.getChildren().addAll(VBoxBuilder.create().children(shearXLabel, shearXSlider).build(),
VBoxBuilder.create().children(shearYLabel, shearYSlider).build());
VBox rectangleBox = new VBox();
rectangleBox.getChildren().addAll(xyBox, whBox, colorBox, opacityBox);
TitledPane rectangleProps = new TitledPane("Rectangle", rectangleBox);
VBox transformBox = new VBox();
transformBox.getChildren().addAll(translateBox, rotateBox, scaleBox, shearBox);
TitledPane transformsProps = new TitledPane("Tranformations", transformBox);
TitledPane showBoundsControls = getShowBoundsControls();
TitledPane effectPane = getEffectTitledPane();
Button resetAllButton = new Button("Reset All");
resetAllButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
resetAll();
}
});
Button saveButton = new Button("Save Layout as Image");
saveButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
saveLayoutAsImage();
}
});
Button exitButton = new Button("Exit");
exitButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
Platform.exit();
}
});
/*
Button printButton = new Button("Print");
printButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
String str = getDesc("layoutBounds", mainRect.getLayoutBounds()) +
getDesc("\nboundsInLocal", mainRect.getBoundsInLocal()) +
getDesc("\nboundsInParent", mainRect.getBoundsInParent());
//printDataTextArea.setText(str);
}
private String getDesc(String type, Bounds b) {
String str = type + "[minX=" + b.getMinX() +
", minY=" + b.getMinY() +
", width=" + b.getWidth() +
", height=" + b.getHeight() + "]";
return str;
}
});
*/
HBox buttonBox = new HBox();
buttonBox.setSpacing(10);
buttonBox.getChildren().addAll(resetAllButton, saveButton, exitButton);
VBox vBox = new VBox();
vBox.getChildren().addAll(buttonBox, showBoundsControls, rectangleProps, effectPane, transformsProps);
return vBox;
}
private void saveLayoutAsImage() {
FileChooser fc = new FileChooser();
fc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Portable Network Graphics(*.png)",
Collections.singletonList("*.png")));
File output = fc.showSaveDialog(boundsLayoutNode.getScene().getWindow());
if (output == null) {
return;
}
else {
String fn = output.getName();
if (!fn.toLowerCase().endsWith(".png")) {
output = new File(output.getParent(), fn + ".png");
}
}
try {
WritableImage wImg = boundsLayoutNode.snapshot(null, null);
//WritableImage wImg = mainRect.snapshot(null, null);
BufferedImage bImg = SwingFXUtils.fromFXImage(wImg, null);
ImageIO.write(bImg, "png", output);
}
catch (IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
private void initializeBoundsTableView() {
boundsTableView.setPrefSize(200, 100);
boundsTableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
boundsTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
TableColumn<BoundsRecord, String> boundsTypeCol = new TableColumn<>("Bounds Type");
boundsTypeCol.setCellValueFactory(new PropertyValueFactory<>("boundsType"));
TableColumn<BoundsRecord, Double> xCol = new TableColumn<>("MinX");
xCol.setCellValueFactory(new PropertyValueFactory<>("x"));
TableColumn<BoundsRecord, Double> yCol = new TableColumn<>("MinY");
yCol.setCellValueFactory(new PropertyValueFactory<>("y"));
TableColumn<BoundsRecord, Double> wCol = new TableColumn<>("Width");
wCol.setCellValueFactory(new PropertyValueFactory<>("w"));
TableColumn<BoundsRecord, Double> hCol = new TableColumn<>("Height");
hCol.setCellValueFactory(new PropertyValueFactory<>("h"));
boundsTableView.getColumns().setAll(boundsTypeCol, xCol, yCol, wCol, hCol);
}
private void drawAllAxes() {
// If local and parent coordinate spaces are the same,
// we will draw axes only once
// Transform a non-zero (x, y) point from local to parent.
// If we get the same point back, it means two coordinate spaces are the same
double x = 100; // any value will do
double y = 100; // any value will do
Point2D p = mainRect.localToParent(x, y);
if (p.getY() == y) {
// We do not draw parent x-axis
parentXArrow.setVisible(false);
parentXAxisLabel.setVisible(false);
localXAxisLabel.setText("x-axis (Parent/Untransformed Local)");
drawLocalAxis();
}
else {
this.parentXArrow.setVisible(true);
this.parentXAxisLabel.setVisible(true);
localXAxisLabel.setText("x-axis (Transformed Local)");
parentXAxisLabel.setText("x-axis (Parent/Untransformed Local)");
drawLocalAxis();
drawParentAxis();
}
if (p.getX() == x) {
// We do not draw parent y-axis
parentYArrow.setVisible(false);
parentYAxisLabel.setVisible(false);
localYAxisLabel.setText("y-axis (Parent/Untransformed Local)");
drawLocalAxis();
}
else {
parentYArrow.setVisible(true);
parentYAxisLabel.setVisible(true);
localYAxisLabel.setText("y-axis (Transformed Local)");
parentYAxisLabel.setText("y-axis (Parent/Untransformed Local)");
drawLocalAxis();
drawParentAxis();
}
}
private void drawLocalAxis() {
localYAxisLabel.setLayoutX(-1.0 * localYAxisLabel.layoutBoundsProperty().get().getWidth() / 2.0);
localXAxisGroup.getTransforms().clear();
localYAxisGroup.getTransforms().clear();
List<Transform> t = getTrsnaforms(true, true);
localXAxisGroup.getTransforms().addAll(t);
localYAxisGroup.getTransforms().addAll(t);
}
private void drawParentAxis() {
parentYAxisLabel.setLayoutX(-1.0 * parentYAxisLabel.layoutBoundsProperty().get().getWidth() / 2.0);
}
private void attachEventHandlers() {
ChangeListener<Number> cl = new ChangeListener<Number>() {
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
relayout();
}
};
ChangeListener<String> clStr = new ChangeListener<String>() {
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
relayout();
}
};
xSlider.valueProperty().addListener(cl);
ySlider.valueProperty().addListener(cl);
widthSlider.valueProperty().addListener(cl);
heightSlider.valueProperty().addListener(cl);
strokeSlider.valueProperty().addListener(cl);
rectStrokeColorChoiceBox.valueProperty().addListener(clStr);
opacitySlider.valueProperty().addListener(cl);
rectFillColorChoiceBox.valueProperty().addListener(clStr);
translateXSlider.valueProperty().addListener(cl);
translateYSlider.valueProperty().addListener(cl);
rotateSlider.valueProperty().addListener(cl);
scaleXSlider.valueProperty().addListener(cl);
scaleYSlider.valueProperty().addListener(cl);
shearXSlider.valueProperty().addListener(cl);
shearYSlider.valueProperty().addListener(cl);
}
private void relayout() {
mainRect.getTransforms().clear();
mainRect.setWidth(widthSlider.getValue());
mainRect.setHeight(heightSlider.getValue());
mainRect.setX(xSlider.getValue());
mainRect.setY(ySlider.getValue());
mainRect.getTransforms().addAll(getTrsnaforms(true, true));
mainRect.setEffect(this.getEffect());
mainRect.setStrokeWidth(strokeSlider.getValue());
mainRect.setStroke(RECTANGLE_STROKE_COLOR);
mainRect.setStroke(Color.web(rectStrokeColorChoiceBox.getValue()));
mainRect.setOpacity(opacitySlider.getValue());
mainRect.setFill(Color.web(rectFillColorChoiceBox.getValue()));
drawAllAxes();
displayResults();
showBounds();
restartBoundsTransitions();
}
private void restartBoundsTransitions() {
LAYOUT_BOUNDS_PATH_TRANSITION.stop();
LOCAL_BOUNDS_PATH_TRANSITION.stop();
PARENT_BOUNDS_PATH_TRANSITION.stop();
this.animate();
}
private List<Transform> getTrsnaforms(boolean includeScale, boolean includeShear) {
double tx = translateXSlider.getValue();
double ty = translateYSlider.getValue();
double scaleX = scaleXSlider.getValue();
double scaleY = scaleYSlider.getValue();
double shearX = shearXSlider.getValue();
double shearY = shearYSlider.getValue();
double rotation = rotateSlider.getValue();
List<Transform> list = new ArrayList<Transform>();
list.add(new Translate(tx, ty));
list.add(new Rotate(rotation));
if (includeScale) {
list.add(new Scale(scaleX, scaleY));
}
if (includeShear) {
list.add(new Shear(shearX, shearY));
}
return list;
}
private void showBounds() {
if (layoutCbx.isSelected()) {
Bounds b = mainRect.getLayoutBounds();
layoutBoundsRect.setX(b.getMinX());
layoutBoundsRect.setY(b.getMinY());
layoutBoundsRect.setWidth(b.getWidth());
layoutBoundsRect.setHeight(b.getHeight());
layoutBoundsRect.setVisible(true);
}
else {
layoutBoundsRect.setVisible(false);
}
if (localCbx.isSelected()) {
Bounds b1 = mainRect.getBoundsInLocal();
Bounds b = b1; // mainRect.localToParent(b1);
localBoundsRect.setX(b.getMinX());
localBoundsRect.setY(b.getMinY());
localBoundsRect.setWidth(b.getWidth());
localBoundsRect.setHeight(b.getHeight());
localBoundsRect.setVisible(true);
}
else {
localBoundsRect.setVisible(false);
}
if (parentCbx.isSelected()) {
Bounds b = mainRect.getBoundsInParent();
parentBoundsRect.setX(b.getMinX());
parentBoundsRect.setY(b.getMinY());
parentBoundsRect.setWidth(b.getWidth());
parentBoundsRect.setHeight(b.getHeight());
parentBoundsRect.setVisible(true);
}
else {
parentBoundsRect.setVisible(false);
}
}
private TitledPane getShowBoundsControls() {
ChangeListener<Boolean> cl = new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldValue,
Boolean newValue) {
relayout();
}
};
ChangeListener<Boolean> cl2 = new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldValue,
Boolean newValue) {
animate();
}
};
layoutCbx.selectedProperty().addListener(cl);
localCbx.selectedProperty().addListener(cl);
parentCbx.selectedProperty().addListener(cl);
effectGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
public void changed(ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) {
relayout();
}
});
layoutAnimateCbx.selectedProperty().addListener(cl2);
localAnimateCbx.selectedProperty().addListener(cl2);
parentAnimateCbx.selectedProperty().addListener(cl2);
double w = 20.0;
double h = 10.0;
Rectangle rLayout = new Rectangle(w, h);
rLayout.setFill(LAYOUT_BOUNDS_RECT_FILL_COLOR);
rLayout.setStrokeWidth(BOUNDS_STROKE_WIDTH);
rLayout.setStroke(LAYOUT_BOUNDS_RECT_STROKE_COLOR);
Rectangle rLocal = new Rectangle(w, h);
rLocal.setFill(LOCAL_BOUNDS_RECT_FILL_COLOR);
rLocal.setStrokeWidth(BOUNDS_STROKE_WIDTH);
rLocal.setStroke(LOCAL_BOUNDS_RECT_STROKE_COLOR);
Rectangle rParent = new Rectangle(w, h);
rParent.setFill(PARENT_BOUNDS_RECT_FILL_COLOR);
rParent.setStrokeWidth(BOUNDS_STROKE_WIDTH);
rParent.setStroke(PARENT_BOUNDS_RECT_STROKE_COLOR);
GridPane gp = new GridPane();
gp.addRow(1, rLayout, new Text("Layout Bounds:"), layoutCbx, layoutAnimateCbx);
gp.addRow(2, rLocal, new Text("Local Bounds:"), localCbx, localAnimateCbx);
gp.addRow(3, rParent, new Text("Parent Bounds:"), parentCbx, parentAnimateCbx);
TitledPane titledPane = new TitledPane("Show Bounds", gp);
return titledPane;
}
private TitledPane getEffectTitledPane() {
noneEffect.setToggleGroup(effectGroup);
noneEffect.setSelected(true);
dropshadowEffect.setToggleGroup(effectGroup);
reflectionEffect.setToggleGroup(effectGroup);
glowEffect.setToggleGroup(effectGroup);
HBox hBox = new HBox();
hBox.setPadding(new Insets(5, 5, 5, 5));
hBox.getChildren().addAll(noneEffect, dropshadowEffect, reflectionEffect, glowEffect);
TitledPane effectsPane = new TitledPane("Effect", hBox);
return effectsPane;
}
private void animate() {
if (layoutAnimateCbx.isSelected()) {
LAYOUT_BOUNDS_PATH_CIRCLE.setVisible(true);
playLayoutBoundsPathTransition();
}
else {
LAYOUT_BOUNDS_PATH_CIRCLE.setVisible(false);
LAYOUT_BOUNDS_PATH_TRANSITION.stop();
}
if (localAnimateCbx.isSelected()) {
LOCAL_BOUNDS_PATH_CIRCLE.setVisible(true);
playLocalBoundsPathTransition();
}
else {
LOCAL_BOUNDS_PATH_CIRCLE.setVisible(false);
LOCAL_BOUNDS_PATH_TRANSITION.stop();
}
if (parentAnimateCbx.isSelected()) {
PARENT_BOUNDS_PATH_CIRCLE.setVisible(true);
playParentBoundsPathTransition();
}
else {
PARENT_BOUNDS_PATH_CIRCLE.setVisible(false);
PARENT_BOUNDS_PATH_TRANSITION.stop();
}
}
private void initializeBoundsPathTransition() {
LOCAL_BOUNDS_PATH_TRANSITION.setDuration(Duration.seconds(2));
LOCAL_BOUNDS_PATH_TRANSITION.setNode(LOCAL_BOUNDS_PATH_CIRCLE);
LOCAL_BOUNDS_PATH_TRANSITION.setOrientation(PathTransition.OrientationType.NONE);
LOCAL_BOUNDS_PATH_TRANSITION.setCycleCount(Timeline.INDEFINITE);
PARENT_BOUNDS_PATH_TRANSITION.setDuration(Duration.seconds(2));
PARENT_BOUNDS_PATH_TRANSITION.setNode(PARENT_BOUNDS_PATH_CIRCLE);
PARENT_BOUNDS_PATH_TRANSITION.setOrientation(PathTransition.OrientationType.NONE);
PARENT_BOUNDS_PATH_TRANSITION.setCycleCount(Timeline.INDEFINITE);
LAYOUT_BOUNDS_PATH_TRANSITION.setDuration(Duration.seconds(2));
LAYOUT_BOUNDS_PATH_TRANSITION.setNode(LAYOUT_BOUNDS_PATH_CIRCLE);
LAYOUT_BOUNDS_PATH_TRANSITION.setOrientation(PathTransition.OrientationType.NONE);
LAYOUT_BOUNDS_PATH_TRANSITION.setCycleCount(Timeline.INDEFINITE);
}
private void playLayoutBoundsPathTransition() {
Bounds b = mainRect.getLayoutBounds();
Path path = new Path();
path.getElements().add(new MoveTo(b.getMinX(), b.getMinY()));
path.getElements().add(new LineTo(b.getMaxX(), b.getMinY()));
path.getElements().add(new LineTo(b.getMaxX(), b.getMaxY()));
path.getElements().add(new LineTo(b.getMinX(), b.getMaxY()));
path.getElements().add(new LineTo(b.getMinX(), b.getMinY()));
LAYOUT_BOUNDS_PATH_TRANSITION.setPath(path);
LAYOUT_BOUNDS_PATH_TRANSITION.play();
}
private void playLocalBoundsPathTransition() {
Bounds b = mainRect.getBoundsInLocal();
Path path = new Path();
path.getElements().add(new MoveTo(b.getMinX(), b.getMinY()));
//path.getElements().add(new LineTo(b.getMinX(), b.getMinY()));
path.getElements().add(new LineTo(b.getMaxX(), b.getMinY()));
path.getElements().add(new LineTo(b.getMaxX(), b.getMaxY()));
path.getElements().add(new LineTo(b.getMinX(), b.getMaxY()));
path.getElements().add(new LineTo(b.getMinX(), b.getMinY()));
LOCAL_BOUNDS_PATH_TRANSITION.setPath(path);
LOCAL_BOUNDS_PATH_TRANSITION.play();
}
private void playParentBoundsPathTransition() {
Bounds b = mainRect.getBoundsInParent();
Path path = new Path();
path.getElements().add(new MoveTo(b.getMinX(), b.getMinY()));
path.getElements().add(new LineTo(b.getMaxX(), b.getMinY()));
path.getElements().add(new LineTo(b.getMaxX(), b.getMaxY()));
path.getElements().add(new LineTo(b.getMinX(), b.getMaxY()));
path.getElements().add(new LineTo(b.getMinX(), b.getMinY()));
PARENT_BOUNDS_PATH_TRANSITION.setPath(path);
PARENT_BOUNDS_PATH_TRANSITION.play();
}
private void resetAll() {
xSlider.setValue(0.0);
ySlider.setValue(0.0);
widthSlider.setValue(RECTANGLE_WIDTH);
heightSlider.setValue(RECTANGLE_HEIGHT);
translateXSlider.setValue(0);
translateYSlider.setValue(0);
rotateSlider.setValue(0);
scaleXSlider.setValue(1.0);
scaleYSlider.setValue(1.0);
shearXSlider.setValue(0);
shearYSlider.setValue(0);
strokeSlider.setValue(RECTANGLE_STROKE_WIDTH);
rectStrokeColorChoiceBox.setValue(RECTANGLE_STROKE_COLOR_STR);
opacitySlider.setOpacity(RECTANGLE_OPACITY);
rectFillColorChoiceBox.setValue(RECTANGLE_FILL_COLOR_STR);
layoutAnimateCbx.setSelected(false);
localAnimateCbx.setSelected(false);
parentAnimateCbx.setSelected(false);
layoutCbx.setSelected(false);
localCbx.setSelected(false);
parentCbx.setSelected(false);
noneEffect.setSelected(true);
}
private Effect getEffect() {
Effect effect = null;
if (dropshadowEffect.isSelected()) {
effect = new DropShadow();
}
else if (reflectionEffect.isSelected()) {
effect = new Reflection();
}
else if (glowEffect.isSelected()) {
effect = new Glow();
}
return effect;
}
private void displayResults() {
Bounds layoutBounds = mainRect.getLayoutBounds();
Bounds localBounds = mainRect.getBoundsInLocal();
Bounds parentBounds = mainRect.getBoundsInParent();
layoutBoundsData.update(layoutBounds);
localBoundsData.update(localBounds);
parentBoundsData.update(parentBounds);
}
}