package greenfoot.guifx;
import bluej.utility.javafx.FXPlatformConsumer;
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.util.Duration;
import threadchecker.OnThread;
import threadchecker.Tag;
| A class for handling the world part of the main GreenfootStage window.
|
@OnThread(value = Tag.FXPlatform, ignoreParent = true)
public class WorldDisplay
extends StackPane{
private final ImageView imageView = new ImageView();
private final AskPaneFX askPane = new AskPaneFX();
private final Rectangle actorHighlight = new Rectangle();
private final Animation actorHighlightAnimation;
public WorldDisplay()
{
Pane highlightPane = new Pane(actorHighlight);
highlightPane.setMouseTransparent(true);
StackPane stackPane = new StackPane(imageView, askPane, highlightPane);
stackPane.getStyleClass().add("world-display-wrapper");
stackPane.setMaxWidth(USE_PREF_SIZE);
stackPane.setMaxHeight(USE_PREF_SIZE);
getChildren().addAll(stackPane);
setMinWidth(200);
setMinHeight(200);
actorHighlight.setVisible(false);
actorHighlight.getStyleClass().add("actor-highlight");
actorHighlight.getStrokeDashArray().setAll(6.0, 10.0);
actorHighlightAnimation = new Timeline(
new KeyFrame(Duration.ZERO,
new KeyValue(actorHighlight.strokeDashOffsetProperty(), 0),
new KeyValue(actorHighlight.strokeProperty(), Color.BLACK)),
new KeyFrame(Duration.seconds(2),
new KeyValue(actorHighlight.strokeProperty(), Color.WHITE, Interpolator.EASE_BOTH)),
new KeyFrame(Duration.seconds(4),
new KeyValue(actorHighlight.strokeDashOffsetProperty(), 16, Interpolator.LINEAR),
new KeyValue(actorHighlight.strokeProperty(), Color.BLACK, Interpolator.EASE_BOTH)));
actorHighlightAnimation.setCycleCount(Animation.INDEFINITE);
}
| Sets the world image. Turns off any greying effect.
|
| Returns true if the world changed size
|
public boolean setImage(Image image)
{
Image oldImage = imageView.getImage();
boolean newSize = oldImage == null || image == null ||
image.getWidth() != oldImage.getWidth() ||
image.getHeight() != oldImage.getHeight();
imageView.setImage(image);
imageView.setEffect(null);
return newSize;
}
| Greys out the world to indicate it isn't in a valid state.
| Turned off by next setImage call.
|
public void greyOutWorld()
{
ColorAdjust grey = new ColorAdjust(0.0, -1.0, -0.1, 0.0);
GaussianBlur blur = new GaussianBlur();
blur.setInput(grey);
imageView.setEffect(blur);
}
| Show the ask panel with the given prompt, and call the given callback once
| the user gives an answer. It is safe to call this method repeatedly for the
| same ask request without disturbing the GUI.
|
@OnThread(Tag.FXPlatform)
public void ensureAsking(String prompt, FXPlatformConsumer<String> withAnswer)
{
imageView.setDisable(true);
greyOutWorld();
askPane.setVisible(true);
askPane.setPrompt(prompt);
askPane.focusTextEntry();
askPane.setWithAnswer(ans -> {
askPane.setVisible(false);
imageView.setDisable(false);
imageView.setEffect(null);
withAnswer.accept(ans);
requestFocus();
});
}
| Is the ask pane currently showing?
|
public boolean isAsking()
{
return askPane.isVisible();
}
| Converts a point in the scene to world coordinates.
|
public Point2D sceneToWorld(Point2D point2D)
{
return imageView.sceneToLocal(point2D);
}
| Converts a point in world coordinates into screen coordinates.
|
public Point2D worldToScreen(Point2D point2D)
{
return imageView.localToScreen(point2D);
}
| Checks if the given point (in world coordinates) lies inside the world or not.
|
public boolean worldContains(Point2D point2D)
{
return imageView.contains(point2D);
}
| Is the world greyed out? (It will be if there has been a call
| to greyOutWorld(), but not yet followed by setImage)
|
public boolean isGreyedOut()
{
return imageView.getEffect() != null;
}
| Returns a rendered image which illustrates a snapshot of the world display.
| @return the rendered image
|
public Image getSnapshot()
{
return imageView.snapshot(null, null);
}
| Get the node containing the actual world image (sans any spacing/border).
|
public Node getImageView()
{
return imageView;
}
| Highlight the given actor bounds with a box overlay.
| @param x The centre X coordinate (in pixels, in the world)
| @param y The centre Y coordinate (in pixels, in the world)
| @param width The width of the image (in pixels)
| @param height The height of the image (in pixels)
| @param rotation The rotation of the actor (in degrees)
|
public void setActorHighlight(int x, int y, int width, int height, int rotation)
{
if (x < -width || x > imageView.getImage().getWidth() + width
|| y < -height || y > imageView.getImage().getHeight() + height
|| width <= 0 || width > imageView.getImage().getWidth()
|| height <=0 || height > imageView.getImage().getHeight())
{
return;
}
actorHighlight.setX(x - width / 2.0);
actorHighlight.setY(y - height / 2.0);
actorHighlight.setWidth(width);
actorHighlight.setHeight(height);
actorHighlight.getTransforms().setAll(new Rotate(rotation, x, y));
actorHighlight.setVisible(true);
actorHighlightAnimation.playFromStart();
}
| Hide the highlight set by setActorHighlight
|
public void clearActorHighlight()
{
actorHighlightAnimation.stop();
actorHighlight.setVisible(false);
}
}
top,
use,
map,
class WorldDisplay
. WorldDisplay
. setImage
. greyOutWorld
. ensureAsking
. isAsking
. sceneToWorld
. worldToScreen
. worldContains
. isGreyedOut
. getSnapshot
. getImageView
. setActorHighlight
. clearActorHighlight
222 neLoCode
+ 24 LoComm