package greenfoot.export;

import bluej.Config;
import bluej.utility.javafx.JavaFXUtil;
import bluej.utility.javafx.UnfocusableScrollPane;
import greenfoot.World;
import greenfoot.core.ExportedProjectProperties;
import greenfoot.core.Simulation;
import greenfoot.core.WorldHandler;
import greenfoot.event.SimulationListener;
import greenfoot.guifx.ControlPanel;
import greenfoot.guifx.ControlPanel.ControlPanelListener;
import greenfoot.guifx.GreenfootStage.State;
import greenfoot.guifx.WorldDisplay;
import greenfoot.platforms.standalone.ActorDelegateStandAlone;
import greenfoot.platforms.standalone.GreenfootUtilDelegateStandAlone;
import greenfoot.platforms.standalone.WorldHandlerDelegateStandAlone;
import greenfoot.sound.SoundFactory;
import greenfoot.util.GreenfootUtil;
import greenfoot.util.StandalonePropStringManager;
import javafx.application.Platform;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.WritableImage;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import threadchecker.OnThread;
import threadchecker.Tag;

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;


| This class can view and run a Greenfoot scenario. It is not possible to | interact with the objects in any way. | | @author Poul Henriksen | @OnThread(Tag.FXPlatform) public class GreenfootScenarioViewer extends BorderPane implements ControlPanelListener, SimulationListener{ private ExportedProjectProperties properties; private Simulation sim; private ControlPanel controls; @OnThread(Tag.Any) private Constructor<?> worldConstructor; private final WorldDisplay worldDisplay = new WorldDisplay(); private boolean updatingSliderFromSimulation = false;
| Initialize the project properties. | public static void initProperties() { Properties p = new Properties(); try { ClassLoader loader = GreenfootScenarioViewer.class.getClassLoader(); InputStream is = loader.getResourceAsStream("standalone.properties"); if (is != null) { p.load(is); } Config.initializeStandalone(new StandalonePropStringManager(p)); if (is != null) { is.close(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void buildGUI(boolean hideControls) { ScrollPane worldViewScroll = new UnfocusableScrollPane(new StackPane(worldDisplay)); JavaFXUtil.expandScrollPaneContent(worldViewScroll); setCenter(worldViewScroll); if (!hideControls){ setBottom(controls); } }
| Called by the browser or applet viewer to inform this JApplet that it has | been loaded into the system. It is always called before the first time | that the start method is called. | public GreenfootScenarioViewer() { initProperties(); final String worldClassName = Config.getPropString("main.class"); final boolean lockScenario = Config.getPropBoolean("scenario.lock"); final boolean hideControls = Config.getPropBoolean("scenario.hideControls", false); try { GreenfootUtil.initialise(new GreenfootUtilDelegateStandAlone()); properties = new ExportedProjectProperties(); ActorDelegateStandAlone.setupAsActorDelegate(); ActorDelegateStandAlone.initProperties(properties); Simulation.initialize(); guiSetup(lockScenario, worldClassName); WorldHandler worldHandler = WorldHandler.getInstance(); Class<?> worldClass = Class.forName(worldClassName); worldConstructor = worldClass.getConstructor(new Class[]{ }); World world = instantiateNewWorld(); if (! worldHandler.checkWorldSet()) { worldHandler.setWorld(world, false); } buildGUI(hideControls); controls.updateState(State.PAUSED, false); JavaFXUtil.onceNotNull(sceneProperty(), scene -> scene.addEventFilter(KeyEvent.ANY, e -> { if (e.getEventType() == KeyEvent.KEY_PRESSED) { worldHandler.getKeyboardManager().keyPressed(e.getCode(), e.getText()); } else if (e.getEventType() == KeyEvent.KEY_RELEASED) { worldHandler.getKeyboardManager().keyReleased(e.getCode(), e.getText()); } else if (e.getEventType() == KeyEvent.KEY_TYPED) { worldHandler.getKeyboardManager().keyTyped(e.getCode(), e.getText()); } })); worldDisplay.addEventFilter(MouseEvent.ANY, e -> { MouseButton button = e.getButton(); if (Config.isMacOS() && button == MouseButton.PRIMARY && e.isControlDown()) { button = MouseButton.SECONDARY; } if (e.getEventType() == MouseEvent.MOUSE_CLICKED) { worldHandler.getMouseManager().mouseClicked((int)e.getX(), (int)e.getY(), button, e.getClickCount()); } else if (e.getEventType() == MouseEvent.MOUSE_MOVED) { worldHandler.getMouseManager().mouseMoved((int)e.getX(), (int)e.getY()); } else if (e.getEventType() == MouseEvent.MOUSE_DRAGGED) { worldHandler.getMouseManager().mouseDragged((int)e.getX(), (int)e.getY(), button); } else if (e.getEventType() == MouseEvent.MOUSE_PRESSED) { worldHandler.getMouseManager().mousePressed((int)e.getX(), (int)e.getY(), button); } else if (e.getEventType() == MouseEvent.MOUSE_RELEASED) { worldHandler.getMouseManager().mouseReleased((int)e.getX(), (int)e.getY(), button); } else if (e.getEventType() == MouseEvent.MOUSE_EXITED) { worldHandler.getMouseManager().mouseExited(); } }); if (hideControls) { Simulation.getInstance().setPaused(false); } } catch (SecurityException | IllegalArgumentException | ClassNotFoundException | NoSuchMethodException e) { e.printStackTrace(); } }
| Perform gui setup; this needs to be done on the Event Dispatch Thread. | @param lockScenario whether the scenario is "locked" (speed slider and actor dragging disabled) |* @param worldClassName the name of the world class to instantiate */ private void guiSetup(boolean lockScenario, String worldClassName) { WorldHandler.initialise(new WorldHandlerDelegateStandAlone(this, lockScenario)); | |WorldHandler worldHandler = WorldHandler.getInstance(); | |sim = Simulation.getInstance(); | |sim.attachWorldHandler(worldHandler); | |controls = new ControlPanel(this, null); | |if (lockScenario) | |{ | |controls.lockControls(); | |} | |// Make sure the SoundCollection is initialized and listens for events | |sim.addSimulationListener(SoundFactory.getInstance().getSoundCollection()); | |sim.addSimulationListener(this); | |try { | |int initialSpeed = properties.getInt("simulation.speed"); sim.setSpeed(initialSpeed); } catch (NumberFormatException nfe) { // If there is no speed info in the properties we don't care... } } /** * Creates a new instance of the world. And initialises with that world. @OnThread(Tag.Any) public World instantiateNewWorld() { try { World world = (World) worldConstructor.newInstance(new Object[]{ }); return world; } catch (IllegalArgumentException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.getCause().printStackTrace(); } return null; } @OnThread(Tag.Simulation) public String ask(final String prompt) { final CompletableFuture<String> answer = new CompletableFuture<>(); Platform.runLater(() -> worldDisplay.ensureAsking(prompt, answer::complete)); try { return answer.get(); } catch (Exception e) { e.printStackTrace(); return null; } } @Override public void act() { Simulation.getInstance().runOnce(); } @Override public void doRunPause() { Simulation.getInstance().togglePaused(); } @Override public void userReset() { Simulation.getInstance().setEnabled(false); WorldHandler.getInstance().discardWorld(); WorldHandler.getInstance().instantiateNewWorld(null); } @Override public void setSpeedFromSlider(int speed) { if (!updatingSliderFromSimulation) { Simulation.getInstance().setSpeed(speed); } }
| Sets the latest world image on the screen. | | @param worldImage A Swing BufferedImage which is copied before returning. | public void setWorldImage(BufferedImage worldImage) { if (worldDisplay.setImage(bufferedImageToFX(worldImage))) { worldDisplay.getScene().getWindow().sizeToScene(); } }
| Directly copies a BufferedImage, which is assumed to have ARGB format, into a JavaFX image. | @param worldImage The BufferedImage to copy from. Must be in ARGB format. | @return The JavaFX image with a copy of the BufferedImage | private static Image bufferedImageToFX(BufferedImage worldImage) { WritableImage fxImage = new WritableImage(worldImage.getWidth(), worldImage.getHeight()); int [] raw = ((DataBufferInt) worldImage.getData().getDataBuffer()).getData(); int offset = 0; for (int y = 0; y < worldImage.getHeight(); y++) { for (int x = 0; x < worldImage.getWidth(); x++) { fxImage.getPixelWriter().setArgb(x, y, raw[offset++]); } } return fxImage; } @Override public @OnThread(Tag.Simulation) void simulationChangedSync(SyncEvent eventType) { if (eventType == SyncEvent.STARTED) { Platform.runLater(() -> { controls.updateState(State.RUNNING, false); }); } } @Override @OnThread(Tag.Any) public void simulationChangedAsync(AsyncEvent eventType) { if (eventType == AsyncEvent.STOPPED) { Platform.runLater(() -> { controls.updateState(State.PAUSED, false); }); } else if (eventType == AsyncEvent.DISABLED) { Platform.runLater(() -> { controls.updateState(State.NO_WORLD, false); }); } else if (eventType == AsyncEvent.CHANGED_SPEED) { Platform.runLater(() -> { updatingSliderFromSimulation = true; controls.setSpeed(Simulation.getInstance().getSpeed()); updatingSliderFromSimulation = false; }); } } }
top, use, map, class GreenfootScenarioViewer

.   initProperties
.   buildGUI
.   GreenfootScenarioViewer
.   instantiateNewWorld
.   ask
.   act
.   doRunPause
.   userReset
.   setSpeedFromSlider
.   setWorldImage
.   bufferedImageToFX
.   simulationChangedSync
.   simulationChangedAsync




388 neLoCode + 27 LoComm