Skip to content

Instantly share code, notes, and snippets.

@skrb
Created December 27, 2011 10:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skrb/1523258 to your computer and use it in GitHub Desktop.
Save skrb/1523258 to your computer and use it in GitHub Desktop.
FXEyes
package net.javainthebox.fxeyes;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Point2D;
import javafx.scene.Parent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Ellipse;
public class Eyes extends Parent {
private static final double MINIMAM_STROKE = 1.0;
private static final double SIZE_RATIO = 10.0;
// Eye Position
private DoubleProperty locationX = new SimpleDoubleProperty();
private DoubleProperty locationY = new SimpleDoubleProperty();
private DoubleProperty width = new SimpleDoubleProperty();
private DoubleProperty height = new SimpleDoubleProperty();
// Left Back Eye Position
private DoubleProperty leftX = new SimpleDoubleProperty();
private DoubleProperty leftY = new SimpleDoubleProperty();
// Right Back Eye Position
private DoubleProperty rightX = new SimpleDoubleProperty();
private DoubleProperty rightY = new SimpleDoubleProperty();
// Eye Stroke Width is determined by scene size.
private DoubleBinding strokeWidth = new DoubleBinding() {
{
super.bind(width, height);
}
@Override
protected double computeValue() {
// Strok Width is dicided by screen size.
double stroke;
if (width.get() < height.get()) {
stroke = width.get() / SIZE_RATIO;
} else {
stroke = height.get() / SIZE_RATIO;
}
return (stroke < MINIMAM_STROKE) ? MINIMAM_STROKE : stroke;
}
};
public Eyes() {
createEyes();
}
public DoubleProperty locationXProperty() {
return locationX;
}
public DoubleProperty locationYProperty() {
return locationY;
}
public DoubleProperty widthProperty() {
return width;
}
public DoubleProperty heightProperty() {
return height;
}
public void setMouseLocation(double mouseX, double mouseY) {
double x = mouseX - locationX.get();
double y = -mouseY + locationY.get() + height.get();
double cx = width.get() / 4;
double cy = height.get() / 2;
// Update Left Black Eye Position
Point2D left = calculateEyePosition(x, y, cx, cy);
leftX.set(left.getX());
leftY.set(left.getY());
// Update Right Black Eye Position
cx = width.get() / 4 * 3;
Point2D right = calculateEyePosition(x, y, cx, cy);
rightX.set(right.getX());
rightY.set(right.getY());
}
private Point2D calculateEyePosition(double x, double y, double cx, double cy) {
double theta = Math.atan2(y - cy, x - cx);
double hr = width.get() / 4 - 2 * strokeWidth.get();
double eyeX;
double eyeY;
if (Math.abs(x - cx) > Math.abs(hr * Math.cos(theta))) {
eyeX = cx + hr * Math.cos(theta);
} else {
eyeX = x;
}
double vr = height.get() / 2 - 2 * strokeWidth.get();
if (Math.abs(y - cy) > Math.abs(vr * Math.sin(theta))) {
eyeY = height.get() - cy - vr * Math.sin(theta);
} else {
eyeY = height.get() - y;
}
return new Point2D(eyeX, eyeY);
}
private void createEyes() {
// Left Eye
Ellipse left = new Ellipse();
left.centerXProperty().bind(width.divide(4.0));
left.centerYProperty().bind(height.divide(2.0));
left.radiusXProperty().bind(width.divide(4.0).subtract(strokeWidth.divide(2.0)));
left.radiusYProperty().bind(height.divide(2.0).subtract(strokeWidth.divide(2.0)));
left.setStroke(Color.BLACK);
left.strokeWidthProperty().bind(strokeWidth);
left.setFill(Color.WHITE);
getChildren().add(left);
// Left Black Eye
Circle leftBlackEye = new Circle();
leftBlackEye.centerXProperty().bind(leftX);
leftBlackEye.centerYProperty().bind(leftY);
leftBlackEye.radiusProperty().bind(strokeWidth);
leftBlackEye.setFill(Color.BLACK);
getChildren().add(leftBlackEye);
// Right Eye
Ellipse right = new Ellipse();
right.centerXProperty().bind(width.divide(4.0).multiply(3.0));
right.centerYProperty().bind(height.divide(2.0));
right.radiusXProperty().bind(width.divide(4.0).subtract(strokeWidth.divide(2.0)));
right.radiusYProperty().bind(height.divide(2.0).subtract(strokeWidth.divide(2.0)));
right.setStroke(Color.BLACK);
right.strokeWidthProperty().bind(strokeWidth);
right.setFill(Color.WHITE);
getChildren().add(right);
// Left Black Eye
Circle rightBlackEye = new Circle();
rightBlackEye.centerXProperty().bind(rightX);
rightBlackEye.centerYProperty().bind(rightY);
rightBlackEye.radiusProperty().bind(strokeWidth);
rightBlackEye.setFill(Color.BLACK);
getChildren().add(rightBlackEye);
}
}
package net.javainthebox.fxeyes;
import java.awt.MouseInfo;
import java.awt.PointerInfo;
import java.awt.event.ActionListener;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.WindowEvent;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class FXEyes extends Application {
private final static double INIT_X = 200.0;
private final static double INIT_Y = 200.0;
private final static double INIT_WIDTH = 200.0;
private final static double INIT_HEIGHT = 200.0;
private final static String DECORATE = "Decorate";
private final static String UNDECORATE = "Undecorate";
private Stage stage;
private Scene scene;
private Eyes eyes;
private ContextMenu menu;
private MenuItem styleItem;
// for drag stage
private double dx;
private double dy;
private Timer timer;
@Override
public void start(Stage stage) {
this.stage = stage;
initMenu();
initStage(StageStyle.TRANSPARENT, 200, 200, INIT_WIDTH, INIT_HEIGHT);
startSwingEDT();
}
private void initStage(StageStyle style, double x, double y, double width, double height) {
stage.setTitle("FXEyes");
stage.setX(x);
stage.setY(y);
stage.initStyle(style);
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent event) {
terminateSwingEDT();
}
});
Group root = new Group();
scene = new Scene(root, width, height);
scene.setFill(null);
root.getChildren().add(new Label(""));
eyes = new Eyes();
eyes.widthProperty().bind(scene.widthProperty());
eyes.heightProperty().bind(scene.heightProperty());
eyes.locationXProperty().bind(stage.xProperty());
eyes.locationYProperty().bind(stage.yProperty());
eyes.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.getButton() == MouseButton.SECONDARY) {
menu.show(eyes, event.getScreenX(), event.getScreenY());
}
}
});
eyes.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
dx = event.getSceneX() + scene.getX();
dy = event.getSceneY() + scene.getY();
}
});
eyes.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
FXEyes.this.stage.setX(event.getScreenX() - dx);
FXEyes.this.stage.setY(event.getScreenY() - dy);
}
});
root.getChildren().add(eyes);
stage.setScene(scene);
stage.show();
}
private void initMenu() {
menu = new ContextMenu();
styleItem = new MenuItem(DECORATE);
styleItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
// Creating new stage with same size and same position.
double x = stage.getX() + scene.getX();
double y = stage.getY() + scene.getY();
double width = scene.getWidth();
double height = scene.getHeight();
StageStyle style = stage.getStyle();
stage.close();
stage = new Stage();
if (style == StageStyle.TRANSPARENT) {
initStage(StageStyle.DECORATED, x, y, width, height);
styleItem.setText(UNDECORATE);
} else {
initStage(StageStyle.TRANSPARENT, x, y, width, height);
styleItem.setText(DECORATE);
}
}
});
menu.getItems().add(styleItem);
MenuItem exitItem = new MenuItem("Exit");
exitItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
// Stop JavaFX EDT
Platform.exit();
// Stop Swing EDT
terminateSwingEDT();
}
});
menu.getItems().add(exitItem);
}
private void startSwingEDT() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
timer = new Timer(50, new ActionListener() {
@Override
public void actionPerformed(java.awt.event.ActionEvent event) {
final PointerInfo info = MouseInfo.getPointerInfo();
Platform.runLater(new Runnable() {
@Override
public void run() {
eyes.setMouseLocation(info.getLocation().getX() - scene.getX(),
info.getLocation().getY() - scene.getY());
}
});
}
});
timer.start();
}
});
}
private void terminateSwingEDT() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
timer.stop();
}
});
}
public static void main(String[] args) {
Application.launch(args);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment