package greenfoot.guifx;
import bluej.Config;
import bluej.utility.javafx.JavaFXUtil;
import greenfoot.core.Simulation;
import greenfoot.guifx.GreenfootStage.State;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Slider;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.TilePane;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Polyline;
import threadchecker.OnThread;
import threadchecker.Tag;
import java.util.Arrays;
import java.util.List;
| The control panel in GreenfootStage: the act/run/reset buttons,
| speed slider and execution twirler that appear at the bottom
| left of the window.
|
@OnThread(Tag.FXPlatform)
public class ControlPanel
extends GridPane{
private static final String PAUSE_BUTTON_TEXT = Config.getString("controls.pause.button");
private static final String RUN_BUTTON_TEXT = Config.getString("controls.run.button");
private static final String RUN_BUTTON_TOOLTIP_TEXT = Config.getString("controls.run.shortDescription");
private static final String PAUSE_BUTTON_TOOLTIP_TEXT = Config.getString("controls.pause.shortDescription");
private final Node run_icon = makeRunIcon();
private final Node pause_icon = makePauseIcon();
private final Node act_icon = makeActIcon();
private final Node reset_icon = makeResetIcon();
private final Button actButton;
private final Button runPauseButton;
private final Label speedLabel;
private final Slider speedSlider;
private final ControlPanelListener listener;
private final BooleanProperty actDisabled = new SimpleBooleanProperty(true);
private final BooleanProperty resetDisabled = new SimpleBooleanProperty(true);
private final BooleanProperty runDisabled = new SimpleBooleanProperty(true);
private final BooleanProperty pauseDisabled = new SimpleBooleanProperty(true);
private final BooleanBinding runPauseDisabled = runDisabled.and(pauseDisabled);
| Make a new control panel.
|
| @param greenfootStage The GreenfootStage holding this control panel
| @param executionTwirler The execution twirler. This class does nothing
| with it apart from add it to the panel; its state
| is managed by GreenfootStage.
|
public ControlPanel(ControlPanelListener listener, Node executionTwirler)
{
this.listener = listener;
actButton = unfocusableButton(Config.getString("run.once"));
actButton.setTooltip(new Tooltip(Config.getString("controls.runonce.shortDescription")));
actButton.setGraphic(act_icon);
runPauseButton = unfocusableButton(RUN_BUTTON_TEXT);
runPauseButton.setGraphic(run_icon);
runPauseButton.setTooltip(new Tooltip(RUN_BUTTON_TOOLTIP_TEXT));
Button resetButton = unfocusableButton(Config.getString("reset.world"));
resetButton.setTooltip(new Tooltip(Config.getString("controls.reset.shortDescription")));
resetButton.setGraphic(reset_icon);
actButton.disableProperty().bind(actDisabled);
runPauseButton.disableProperty().bind(runPauseDisabled);
resetButton.disableProperty().bind(resetDisabled);
for (Button button : Arrays.asList(actButton, runPauseButton, resetButton))
{
button.setMaxWidth(Double.MAX_VALUE);
}
int min = 0;
int max = Simulation.MAX_SIMULATION_SPEED;
speedSlider = new Slider() {
@Override
@OnThread(Tag.FX)
public void requestFocus()
{
}
};
speedSlider.setValue(min + (max - min) / 2);
speedSlider.setShowTickLabels(false);
speedSlider.setShowTickMarks(true);
speedSlider.setMin(min);
speedSlider.setMax(max);
speedSlider.setMajorTickUnit( max / 2 );
speedSlider.setMinorTickCount(1);
speedSlider.setBlockIncrement(20);
speedSlider.setTooltip(new Tooltip(Config.getString("controls.speedSlider.tooltip")));
speedSlider.setFocusTraversable(false);
speedSlider.setMaxWidth(150.0);
speedSlider.setDisable(true);
actButton.setOnAction(e -> this.listener.act());
runPauseButton.setOnAction(e -> this.listener.doRunPause());
resetButton.setOnAction(e -> this.listener.userReset());
JavaFXUtil.addChangeListenerPlatform(speedSlider.valueProperty(),
newSpeed -> this.listener.setSpeedFromSlider(newSpeed.intValue()));
TilePane controlPanel = new TilePane(actButton, runPauseButton, resetButton);
controlPanel.setPrefColumns(3);
controlPanel.getStyleClass().add("buttons-panel");
controlPanel.setAlignment(Pos.CENTER);
speedLabel = new Label(Config.getString("controls.speed.label"));
speedLabel.setMinWidth(0.0);
speedLabel.setDisable(true);
add(controlPanel, 0, 0);
GridPane speedAndTwirler = new GridPane();
speedAndTwirler.add(speedLabel, 0, 0);
speedAndTwirler.add(speedSlider, 1, 0, 2, 1);
if (executionTwirler != null)
{
speedAndTwirler.add(executionTwirler, 3, 0);
}
speedAndTwirler.getStyleClass().add("speed-panel");
GridPane.setHalignment(speedLabel, HPos.RIGHT);
GridPane.setValignment(speedSlider, VPos.BOTTOM);
GridPane.setMargin(speedSlider, new Insets(8, 0, 0, 0));
speedLabel.setAlignment(Pos.BASELINE_RIGHT);
GridPane.setHgrow(speedLabel, Priority.ALWAYS);
GridPane.setMargin(speedAndTwirler, new Insets(8, 8, 0, 0));
add(speedAndTwirler, 1, 0);
GridPane.setHalignment(speedAndTwirler, HPos.CENTER);
ColumnConstraints leftHalf = new ColumnConstraints();
ColumnConstraints rightHalf = new ColumnConstraints();
leftHalf.setPercentWidth(60);
rightHalf.setPercentWidth(40);
getColumnConstraints().setAll(leftHalf, rightHalf);
getStyleClass().add("control-panel");
}
| Makes a button with the given text, which cannot be focused.
|
private static Button unfocusableButton(String text)
{
return new Button(text) {
@Override
@OnThread(Tag.FX)
public void requestFocus()
{
}
};
}
| Called by GreenfootStage to update the state of our buttons.
|
public void updateState(State newState, boolean atBreakpoint)
{
actDisabled.setValue(newState != State.PAUSED || atBreakpoint);
runDisabled.setValue(newState != State.PAUSED || atBreakpoint);
pauseDisabled.setValue(newState != State.RUNNING || atBreakpoint);
resetDisabled.setValue(newState == State.NO_PROJECT);
speedSlider.setDisable(newState == State.NO_PROJECT);
speedLabel.setDisable(newState == State.NO_PROJECT);
boolean showingPause = newState == State.RUNNING || newState == State.RUNNING_REQUESTED_PAUSE;
if (showingPause)
{
if (!runPauseButton.getText().equals(PAUSE_BUTTON_TEXT))
{
runPauseButton.setGraphic(pause_icon);
runPauseButton.setText(PAUSE_BUTTON_TEXT);
runPauseButton.setTooltip(new Tooltip(PAUSE_BUTTON_TOOLTIP_TEXT));
}
}
else
{
if (!runPauseButton.getText().equals(RUN_BUTTON_TEXT))
{
runPauseButton.setGraphic(run_icon);
runPauseButton.setText(RUN_BUTTON_TEXT);
runPauseButton.setTooltip(new Tooltip(RUN_BUTTON_TOOLTIP_TEXT));
}
}
}
| Change the speed slider's value
|
public void setSpeed(int simSpeed)
{
speedSlider.setValue(simSpeed);
}
| Locks the controls: hides the act button and the speed slider.
|
public void lockControls()
{
actButton.setVisible(false);
speedSlider.setVisible(false);
speedLabel.setVisible(false);
}
| Make the act/run/pause/reset menu items for GreenfootStage.
| They are made here because their disabled state is managed by ControlPanel.
|
public List
top,
use,
map,
class ControlPanel
. ControlPanel
. requestFocus
. unfocusableButton
. requestFocus
. updateState
. setSpeed
. lockControls
. makeMenuItems
. getIcon
top,
use,
map,
interface ControlPanel . ControlPanelListener
. act
. doRunPause
. userReset
. setSpeedFromSlider
. makeActIcon
. makeRunIcon
. makePauseIcon
. makeResetIcon
446 neLoCode
+ 35 LoComm