Merge branch 'develop' into story1275_host_customization

# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
This commit is contained in:
Calum
2017-09-26 23:37:59 +13:00
20 changed files with 935 additions and 199 deletions
+27 -1
View File
@@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Timer;
import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.property.ReadOnlyIntegerProperty; import javafx.beans.property.ReadOnlyIntegerProperty;
@@ -16,6 +17,7 @@ import javafx.scene.paint.Color;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
/** /**
* Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses) * Yacht class for the racing boat. <p> Class created to store more variables (eg. boat statuses)
@@ -57,12 +59,17 @@ public class ClientYacht extends Observable {
private Integer boatStatus; private Integer boatStatus;
private Double currentVelocity; private Double currentVelocity;
Timer t;
private BoatObject boatObject;
private List<YachtLocationListener> locationListeners = new ArrayList<>(); private List<YachtLocationListener> locationListeners = new ArrayList<>();
private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>(); private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>();
private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper(); private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper();
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper(); private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper(); private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper(); private ReadOnlyIntegerWrapper placingProperty = new ReadOnlyIntegerWrapper();
private ReadOnlyDoubleWrapper headingProperty = new ReadOnlyDoubleWrapper();
private Color colour; private Color colour;
public ClientYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName, public ClientYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName,
@@ -75,6 +82,7 @@ public class ClientYacht extends Observable {
this.country = country; this.country = country;
this.location = new GeoPoint(57.670341, 11.826856); this.location = new GeoPoint(57.670341, 11.826856);
this.heading = 120.0; //In degrees this.heading = 120.0; //In degrees
this.headingProperty.set(this.heading);
this.currentVelocity = 0d; this.currentVelocity = 0d;
this.boatStatus = 1; this.boatStatus = 1;
this.colour = Color.rgb(0, 0, 0, 1.0); this.colour = Color.rgb(0, 0, 0, 1.0);
@@ -222,6 +230,7 @@ public class ClientYacht extends Observable {
public void setHeading(Double heading) { public void setHeading(Double heading) {
this.heading = heading; this.heading = heading;
setHeadingProperty();
} }
@Override @Override
@@ -250,10 +259,10 @@ public class ClientYacht extends Observable {
this.colour = colour; this.colour = colour;
} }
public void updateLocation(double lat, double lng, double heading, double velocity) { public void updateLocation(double lat, double lng, double heading, double velocity) {
setLocation(lat, lng); setLocation(lat, lng);
this.heading = heading; this.heading = heading;
setHeadingProperty();
this.currentVelocity = velocity; this.currentVelocity = velocity;
updateVelocityProperty(velocity); updateVelocityProperty(velocity);
for (YachtLocationListener yll : locationListeners) { for (YachtLocationListener yll : locationListeners) {
@@ -261,6 +270,10 @@ public class ClientYacht extends Observable {
} }
} }
private void setHeadingProperty() {
headingProperty.set(heading);
}
public void addLocationListener(YachtLocationListener listener) { public void addLocationListener(YachtLocationListener listener) {
locationListeners.add(listener); locationListeners.add(listener);
} }
@@ -289,4 +302,17 @@ public class ClientYacht extends Observable {
public Double getCurrentVelocity() { public Double getCurrentVelocity() {
return currentVelocity; return currentVelocity;
} }
public void setBoatObject(BoatObject newBoatObject) {
this.boatObject = newBoatObject;
}
public BoatObject getBoatObject() {
return this.boatObject;
}
public ReadOnlyDoubleWrapper getHeadingProperty() {
return headingProperty;
}
} }
+10 -1
View File
@@ -30,7 +30,12 @@ public class GameKeyBind {
keys.add(KeyCode.ENTER); keys.add(KeyCode.ENTER);
keys.add(KeyCode.PAGE_UP); keys.add(KeyCode.PAGE_UP);
keys.add(KeyCode.PAGE_DOWN); keys.add(KeyCode.PAGE_DOWN);
for (int i = 0; i < 7; i++) { keys.add(KeyCode.F1);
keys.add(KeyCode.D);
keys.add(KeyCode.A);
keys.add(KeyCode.W);
keys.add(KeyCode.S);
for (int i = 0; i < 12; i++) {
actionToKeyMap.put(KeyAction.getType(i + 1), keys.get(i)); actionToKeyMap.put(KeyAction.getType(i + 1), keys.get(i));
keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1)); keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1));
} }
@@ -47,6 +52,10 @@ public class GameKeyBind {
return instance.actionToKeyMap.get(keyAction); return instance.actionToKeyMap.get(keyAction);
} }
public KeyAction getKeyAction(KeyCode keyCode) {
return instance.keyToActionMap.get(keyCode);
}
/** /**
* Binds a key to a key action * Binds a key to a key action
* *
+6 -1
View File
@@ -10,7 +10,12 @@ public enum KeyAction {
SAILS_STATE(4), SAILS_STATE(4),
TACK_GYBE(5), TACK_GYBE(5),
UPWIND(6), UPWIND(6),
DOWNWIND(7); DOWNWIND(7),
VIEW(8),
RIGHT(9),
LEFT(10),
FORWARD(11),
BACKWARD(12);
private final int type; private final int type;
private static final Map<Integer, KeyAction> intToTypeMap = new HashMap<>(); private static final Map<Integer, KeyAction> intToTypeMap = new HashMap<>();
+6 -5
View File
@@ -156,11 +156,11 @@ public class ServerYacht {
/** /**
* Enables the boats auto pilot feature, which will move the boat towards a given heading. * Enables the boats auto pilot feature, which will move the boat towards a given heading.
* *
* @param thisHeading The heading to move the boat towards. * @param newHeading The heading to move the boat towards.
*/ */
private void setAutoPilot(Double thisHeading) { private void setAutoPilot(Double newHeading) {
isAuto = true; isAuto = true;
autoHeading = thisHeading; autoHeading = newHeading;
} }
/** /**
@@ -178,8 +178,9 @@ public class ServerYacht {
if (isAuto) { if (isAuto) {
turnTowardsHeading(autoHeading); turnTowardsHeading(autoHeading);
if (Math.abs(heading - autoHeading) if (Math.abs(heading - autoHeading)
<= turnStep) { //Cancel when within 1 turn step of target. <= turnStep*1.5) {
isAuto = false; isAuto = false;
setHeading(autoHeading);
} }
} }
} }
@@ -265,7 +266,7 @@ public class ServerYacht {
// Take optimal heading and turn into a boat heading rather than a wind heading. // Take optimal heading and turn into a boat heading rather than a wind heading.
optimalHeading = optimalHeading =
optimalHeading + GameState.getWindDirection(); (optimalHeading + GameState.getWindDirection()) % 360;
setAutoPilot(optimalHeading); setAutoPilot(optimalHeading);
} }
@@ -14,8 +14,6 @@ import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
@@ -46,6 +44,7 @@ import seng302.utilities.XMLParser;
import seng302.visualiser.controllers.LobbyController; import seng302.visualiser.controllers.LobbyController;
import seng302.visualiser.controllers.RaceViewController; import seng302.visualiser.controllers.RaceViewController;
import seng302.visualiser.controllers.ViewManager; import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.controllers.dialogs.PopupDialogController;
/** /**
* This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated * This class is a client side instance of a yacht racing game in JavaFX. The game is instantiated
@@ -171,10 +170,12 @@ public class GameClient {
private void showConnectionError (String message) { private void showConnectionError (String message) {
Platform.runLater(() -> { Platform.runLater(() -> {
Alert alert = new Alert(AlertType.ERROR); PopupDialogController controller = ViewManager.getInstance().showPopupDialog();
alert.setHeaderText("Connection Error"); controller.setHeader("Oops");
alert.setContentText(message); controller.setContent(message);
alert.showAndWait(); controller.setOptionButtonText("GO HOME");
controller
.setOptionButtonEventHandler(event -> ViewManager.getInstance().goToStartView());
}); });
} }
@@ -1,6 +1,8 @@
package seng302.visualiser; package seng302.visualiser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -8,6 +10,7 @@ import javafx.animation.AnimationTimer;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.geometry.Point3D; import javafx.geometry.Point3D;
import javafx.scene.Camera;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.PerspectiveCamera; import javafx.scene.PerspectiveCamera;
@@ -20,6 +23,9 @@ import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate; import javafx.scene.transform.Translate;
import seng302.gameServer.messages.RoundingSide; import seng302.gameServer.messages.RoundingSide;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.GameKeyBind;
import seng302.model.GeoPoint;
import seng302.model.KeyAction;
import seng302.model.Limit; import seng302.model.Limit;
import seng302.model.ScaledPoint; import seng302.model.ScaledPoint;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
@@ -28,6 +34,11 @@ import seng302.model.mark.Mark;
import seng302.model.token.Token; import seng302.model.token.Token;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.cameras.ChaseCamera;
import seng302.visualiser.cameras.IsometricCamera;
import seng302.visualiser.cameras.RaceCamera;
import seng302.visualiser.cameras.TopDownCamera;
import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.fxObjects.MarkArrowFactory; import seng302.visualiser.fxObjects.MarkArrowFactory;
import seng302.visualiser.fxObjects.assets_3D.BoatObject; import seng302.visualiser.fxObjects.assets_3D.BoatObject;
import seng302.visualiser.fxObjects.assets_3D.Marker3D; import seng302.visualiser.fxObjects.assets_3D.Marker3D;
@@ -37,18 +48,19 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
/** /**
* Collection of animated3D assets that displays a race. * Collection of animated3D assets that displays a race.
*/ */
public class GameView3D extends GameView{ public class GameView3D extends GameView{
private final double FOV = 60; private final double FOV = 60;
private final double DEFAULT_CAMERA_DEPTH = -125;
private final double DEFAULT_CAMERA_X = 0; private final double DEFAULT_CAMERA_X = 0;
private final double DEFAULT_CAMERA_Y = 100; private final double DEFAULT_CAMERA_Y = 100;
private Group root3D; private Group root3D;
private SubScene view; private SubScene view;
private PerspectiveCamera camera;
private Group raceBorder = new Group(); private Group raceBorder = new Group();
// Cameras
private PerspectiveCamera isometricCam;
private PerspectiveCamera topDownCam;
private PerspectiveCamera chaseCam;
/* Note that if either of these is null then values for it have not been added and the other /* Note that if either of these is null then values for it have not been added and the other
should be used as the limits of the map. */ should be used as the limits of the map. */
@@ -63,21 +75,22 @@ public class GameView3D extends GameView{
private Double windDir; private Double windDir;
public GameView3D () { public GameView3D () {
canvasWidth = canvasHeight = 220; isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y);
camera = new PerspectiveCamera(true); topDownCam = new TopDownCamera();
camera.getTransforms().addAll( chaseCam = new ChaseCamera();
new Translate(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y, DEFAULT_CAMERA_DEPTH)
); for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) {
camera.setFarClip(600); pc.setFarClip(600);
camera.setNearClip(0.1); pc.setNearClip(0.1);
camera.setFieldOfView(FOV); pc.setFieldOfView(FOV);
}
gameObjects = new Group(); gameObjects = new Group();
root3D = new Group(camera, gameObjects); root3D = new Group(isometricCam, gameObjects);
view = new SubScene( view = new SubScene(
root3D, 1000, 1000, true, SceneAntialiasing.BALANCED root3D, 1000, 1000, true, SceneAntialiasing.BALANCED
); );
view.setCamera(camera); view.setCamera(isometricCam);
camera.getTransforms().add(new Rotate(30, new Point3D(1,0,0)));
gameObjects.getChildren().addAll( gameObjects.getChildren().addAll(
ModelFactory.importModel(ModelType.OCEAN).getAssets(), ModelFactory.importModel(ModelType.OCEAN).getAssets(),
@@ -88,6 +101,8 @@ public class GameView3D extends GameView{
scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement); scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement);
} }
}); });
} }
@Override @Override
@@ -245,40 +260,45 @@ public class GameView3D extends GameView{
} }
public void cameraMovement(KeyEvent event) { public void cameraMovement(KeyEvent event) {
switch (event.getCode()) { GameKeyBind keyBinds = GameKeyBind.getInstance();
case NUMPAD8: KeyAction keyPressed = keyBinds.getKeyAction(event.getCode());
camera.getTransforms().addAll(new Rotate(0.5, new Point3D(1,0,0))); switch (keyPressed) {
case ZOOM_IN:
((RaceCamera) view.getCamera()).zoomIn();
break; break;
case NUMPAD2: case ZOOM_OUT:
camera.getTransforms().addAll(new Rotate(-0.5, new Point3D(1,0,0))); ((RaceCamera) view.getCamera()).zoomOut();
break; break;
case NUMPAD4: case FORWARD:
camera.getTransforms().addAll(new Rotate(-0.5, new Point3D(0,1,0))); ((RaceCamera) view.getCamera()).panUp();
break; break;
case NUMPAD6: case BACKWARD:
camera.getTransforms().addAll(new Rotate(0.5, new Point3D(0,1,0))); ((RaceCamera) view.getCamera()).panDown();
break; break;
case Z: case LEFT:
camera.getTransforms().addAll(new Translate(0, 0, 1.5)); ((RaceCamera) view.getCamera()).panLeft();
break; break;
case X: case RIGHT:
camera.getTransforms().addAll(new Translate(0, 0, -1.5)); ((RaceCamera) view.getCamera()).panRight();
break; break;
case W: case VIEW:
camera.getTransforms().addAll(new Translate(0, -1, 0)); toggleCamera();
break;
case S:
camera.getTransforms().addAll(new Translate(0, 1, 0));
break;
case A:
camera.getTransforms().addAll(new Translate(-1, 0, 0));
break;
case D:
camera.getTransforms().addAll(new Translate(1, 0, 0));
break; break;
} }
} }
private void toggleCamera() {
Camera currCamera = view.getCamera();
if (currCamera.equals(isometricCam)) {
view.setCamera(topDownCam);
} else if (currCamera.equals(topDownCam)) {
view.setCamera(chaseCam);
} else {
view.setCamera(isometricCam);
}
}
/** /**
* Draws all the boats. * Draws all the boats.
* @param yachts The yachts to set in the race * @param yachts The yachts to set in the race
@@ -299,6 +319,12 @@ public class GameView3D extends GameView{
Point2D p2d = scaledPoint.findScaledXY(lat, lon); Point2D p2d = scaledPoint.findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir); bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
}); });
if (clientYacht.getSourceId().equals(
ViewManager.getInstance().getGameClient().getServerThread().getClientId())) {
((ChaseCamera) chaseCam).setPlayerBoat(newBoat);
((TopDownCamera) topDownCam).setPlayerBoat(newBoat);
}
} }
Platform.runLater(() -> { Platform.runLater(() -> {
gameObjects.getChildren().addAll(wakes); gameObjects.getChildren().addAll(wakes);
@@ -0,0 +1,130 @@
package seng302.visualiser.cameras;
import java.util.Arrays;
import javafx.beans.property.DoubleProperty;
import javafx.collections.ObservableList;
import javafx.geometry.Point3D;
import javafx.scene.PerspectiveCamera;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
public class ChaseCamera extends PerspectiveCamera implements RaceCamera {
private final Double VERTICAL_PAN_LIMIT = 20.0;
private final Double NEAR_ZOOM_LIMIT = -15.0;
private final Double FAR_ZOOM_LIMIT = -125.0;
private final Double ZOOM_STEP = 2.5;
private final Double PAN_STEP = 2.5;
private ObservableList<Transform> transforms;
private BoatObject playerBoat;
private Double zoomFactor;
private Double horizontalPan;
private Double verticalPan;
public ChaseCamera() {
super(true);
transforms = this.getTransforms();
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
this.horizontalPan = 0.0;
this.verticalPan = 0.0;
}
/**
* Sets a player boat object to observe and update the camera with.
*
* @param playerBoat The player boat to be observed.
*/
public void setPlayerBoat(BoatObject playerBoat) {
this.playerBoat = playerBoat;
for (DoubleProperty o : Arrays
.asList(playerBoat.getRotationProperty(), playerBoat.layoutYProperty(),
playerBoat.layoutXProperty())) {
o.addListener((obs, oldVal, newVal) -> repositionCamera());
}
}
/**
* Moves the camera to a new position after some change (Zooming or Panning)
*/
private void repositionCamera() {
transforms.clear();
transforms.addAll(
new Translate(playerBoat.getLayoutX(), playerBoat.getLayoutY(), 0),
new Rotate(playerBoat.getRotationProperty().getValue() + horizontalPan,
new Point3D(0, 0, 1)),
new Rotate(60 + verticalPan, new Point3D(1, 0, 0)),
new Translate(0, 0, zoomFactor)
);
}
/**
* Adjusts the zoom amount (camera depth) by some adjustment value
* @param adjustment the adjustment to be made to the camera
*/
private void adjustZoomFactor(Double adjustment) {
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
zoomFactor = zoomFactor + adjustment;
repositionCamera();
}
}
/**
* Adjusts the Vertical Panning of the Camera
* @param adjustment the adjustment to be made to the camera
*/
private void adjustVerticalPan(Double adjustment) {
if (verticalPan + adjustment >= -VERTICAL_PAN_LIMIT
&& verticalPan + adjustment <= VERTICAL_PAN_LIMIT) {
verticalPan += adjustment;
repositionCamera();
}
}
/**
* Adjusts the Horizontal Panning of the Camera.
* @param adjustment the adjustment to be made to the camera
*/
private void adjustHorizontalPan(Double adjustment) {
this.horizontalPan += adjustment;
repositionCamera();
}
@Override
public void zoomIn() {
adjustZoomFactor(ZOOM_STEP);
}
@Override
public void zoomOut() {
adjustZoomFactor(-ZOOM_STEP);
}
@Override
public void panLeft() {
adjustHorizontalPan(-PAN_STEP);
}
@Override
public void panRight() {
adjustHorizontalPan(PAN_STEP);
}
@Override
public void panUp() {
adjustVerticalPan(-PAN_STEP);
}
@Override
public void panDown() {
adjustVerticalPan(PAN_STEP);
}
}
@@ -0,0 +1,113 @@
package seng302.visualiser.cameras;
import javafx.collections.ObservableList;
import javafx.geometry.Point3D;
import javafx.scene.PerspectiveCamera;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
public class IsometricCamera extends PerspectiveCamera implements RaceCamera {
private final Double MIN_X = -120.0;
private final Double MAX_X = 125.0;
private final Double MIN_Y = 40.0;
private final Double MAX_Y = 170.0;
private final Double PAN_LIMIT = 160.0;
private final Double NEAR_ZOOM_LIMIT = -50.0;
private final Double FAR_ZOOM_LIMIT = -160.0;
private Double horizontalPan;
private Double verticalPan;
private Double zoomFactor;
private ObservableList<Transform> transforms;
public IsometricCamera(Double cameraStartX, Double cameraStartY) {
super(true);
transforms = this.getTransforms();
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
horizontalPan = cameraStartX;
verticalPan = cameraStartY;
updateCamera();
}
/**
* Moves the camera to a new position after some change (Zooming or Panning)
*/
private void updateCamera() {
transforms.clear();
transforms.addAll(
new Translate(horizontalPan, verticalPan, zoomFactor),
new Rotate(30, new Point3D(1, 0, 0))
);
}
/**
* Adjusts the zoom amount (camera depth) by some adjustment value
*
* @param adjustment the adjustment to be made to the camera
*/
private void adjustZoomFactor(Double adjustment) {
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
zoomFactor = zoomFactor + adjustment;
updateCamera();
}
}
/**
* Adjusts the Vertical Panning of the Camera
* @param adjustment the adjustment to be made to the camera
*/
private void adjustVerticalPan(Double adjustment) {
if (verticalPan + adjustment >= MIN_Y && verticalPan + adjustment <= MAX_Y) {
verticalPan += adjustment;
updateCamera();
}
}
/**
* Adjusts the Horizontal Panning of the Camera.
* @param adjustment the adjustment to be made to the camera
*/
private void adjustHorizontalPan(Double adjustment) {
if (horizontalPan + adjustment >= MIN_X && horizontalPan + adjustment <= MIN_Y) {
this.horizontalPan += adjustment;
updateCamera();
}
}
@Override
public void zoomIn() {
adjustZoomFactor(-2.5);
}
@Override
public void zoomOut() {
adjustZoomFactor(2.5);
}
@Override
public void panLeft() {
adjustHorizontalPan(-2.5);
}
@Override
public void panRight() {
adjustHorizontalPan(2.5);
}
@Override
public void panUp() {
adjustVerticalPan(-2.5);
}
@Override
public void panDown() {
adjustVerticalPan(2.5);
}
}
@@ -0,0 +1,18 @@
package seng302.visualiser.cameras;
public interface RaceCamera {
void zoomIn();
void zoomOut();
void panLeft();
void panRight();
void panUp();
void panDown();
}
@@ -0,0 +1,123 @@
package seng302.visualiser.cameras;
import java.util.Arrays;
import javafx.beans.property.DoubleProperty;
import javafx.collections.ObservableList;
import javafx.scene.PerspectiveCamera;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;
import seng302.visualiser.fxObjects.assets_3D.BoatObject;
public class TopDownCamera extends PerspectiveCamera implements RaceCamera {
private final Double PAN_LIMIT = 30.0;
private final Double NEAR_ZOOM_LIMIT = -30.0;
private final Double FAR_ZOOM_LIMIT = -130.0;
private final Double ZOOM_STEP = 2.5;
private ObservableList<Transform> transforms;
private BoatObject playerBoat;
private Double zoomFactor;
private Double horizontalPan;
private Double verticalPan;
public TopDownCamera() {
super(true);
transforms = this.getTransforms();
zoomFactor = (FAR_ZOOM_LIMIT + NEAR_ZOOM_LIMIT) / 2.0;
horizontalPan = 0.0;
verticalPan = 0.0;
}
/**
* Sets a player boat object to observe and update the camera with.
*
* @param playerBoat The player boat to be observed.
*/
public void setPlayerBoat(BoatObject playerBoat) {
this.playerBoat = playerBoat;
for (DoubleProperty o : Arrays
.asList(playerBoat.layoutXProperty(), playerBoat.layoutYProperty())) {
o.addListener((obs, oldVal, newVal) -> updateCamera());
}
}
/**
* Moves the camera to a new position after some change (Zooming or Panning)
*/
private void updateCamera() {
transforms.clear();
transforms.addAll(
new Translate(playerBoat.getLayoutX() + horizontalPan,
playerBoat.getLayoutY() + verticalPan, zoomFactor)
);
}
/**
* Adjusts the zoom amount (camera depth) by some adjustment value
* @param adjustment the adjustment to be made to the camera
*/
private void adjustZoomFactor(Double adjustment) {
if (zoomFactor + adjustment < NEAR_ZOOM_LIMIT && zoomFactor + adjustment > FAR_ZOOM_LIMIT) {
zoomFactor = zoomFactor + adjustment;
updateCamera();
}
}
/**
* Adjusts the Vertical Panning of the Camera
* @param adjustment the adjustment to be made to the camera
*/
private void adjustVerticalPan(Double adjustment) {
if (verticalPan + adjustment >= -PAN_LIMIT && verticalPan + adjustment <= PAN_LIMIT) {
verticalPan += adjustment;
updateCamera();
}
}
/**
* Adjusts the Horizontal Panning of the Camera.
* @param adjustment the adjustment to be made to the camera
*/
private void adjustHorizontalPan(Double adjustment) {
if (horizontalPan + adjustment >= -PAN_LIMIT && horizontalPan + adjustment <= PAN_LIMIT) {
horizontalPan += adjustment;
updateCamera();
}
}
@Override
public void zoomIn() {
adjustZoomFactor(ZOOM_STEP);
}
@Override
public void zoomOut() {
adjustZoomFactor(-ZOOM_STEP);
}
@Override
public void panLeft() {
adjustHorizontalPan(-1.0);
}
@Override
public void panRight() {
adjustHorizontalPan(1.0);
}
@Override
public void panUp() {
adjustVerticalPan(-1.0);
}
@Override
public void panDown() {
adjustVerticalPan(1.0);
}
}
@@ -28,6 +28,7 @@ import seng302.utilities.BonjourInstallChecker;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.GameClient; import seng302.visualiser.GameClient;
import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; import seng302.visualiser.controllers.dialogs.KeyBindingDialogController;
import seng302.visualiser.controllers.dialogs.PopupDialogController;
public class ViewManager { public class ViewManager {
@@ -220,6 +221,7 @@ public class ViewManager {
.getController(); .getController();
keyBindingDialogController.setGameClient(this.gameClient); keyBindingDialogController.setGameClient(this.gameClient);
keyBindingDialog.show(); keyBindingDialog.show();
decorator.requestFocus();
Sounds.playButtonClick(); Sounds.playButtonClick();
} }
} }
@@ -229,6 +231,26 @@ public class ViewManager {
keyBindingDialog.close(); keyBindingDialog.close();
} }
public PopupDialogController showPopupDialog() {
FXMLLoader dialogContent = new FXMLLoader(
getClass().getResource("/views/dialogs/PopupDialog.fxml"));
for (Node node : decorator.getChildren()) {
if (node instanceof StackPane) {
try {
JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(),
DialogTransition.CENTER);
PopupDialogController popupDialogController = dialogContent.getController();
popupDialogController.setPopupDialog(dialog);
dialog.show();
return popupDialogController;
} catch (IOException e) {
logger.error("Cannot load Popup dialog");
}
}
}
return null;
}
/** /**
* Show a snackbar at the bottom of the app for 1 second. * Show a snackbar at the bottom of the app for 1 second.
* *
@@ -48,6 +48,16 @@ public class KeyBindingDialogController implements Initializable {
private Label downwindLabel; private Label downwindLabel;
@FXML @FXML
private JFXToggleButton turningToggle; private JFXToggleButton turningToggle;
@FXML
private JFXButton viewButton;
@FXML
private JFXButton rightButton;
@FXML
private JFXButton leftButton;
@FXML
private JFXButton forwardButton;
@FXML
private JFXButton backwardButton;
//---------FXML END---------// //---------FXML END---------//
private GameKeyBind gameKeyBind; private GameKeyBind gameKeyBind;
@@ -60,7 +70,8 @@ public class KeyBindingDialogController implements Initializable {
gameKeyBind = GameKeyBind.getInstance(); gameKeyBind = GameKeyBind.getInstance();
buttons = new ArrayList<>(); buttons = new ArrayList<>();
Collections.addAll(buttons, Collections.addAll(buttons,
zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn); zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn,
viewButton, rightButton, leftButton, forwardButton, backwardButton);
bindButtonWithAction(); bindButtonWithAction();
loadKeyBind(); loadKeyBind();
@@ -79,9 +90,6 @@ public class KeyBindingDialogController implements Initializable {
}); });
closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog()); closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
keyBindingDialogHeader.setFocusTraversable(true);
keyBindingDialogHeader.requestFocus();
} }
/** /**
@@ -106,7 +114,7 @@ public class KeyBindingDialogController implements Initializable {
*/ */
private void bindButtonWithAction() { private void bindButtonWithAction() {
buttonActionMap = new HashMap<>(); buttonActionMap = new HashMap<>();
for (int i = 0; i < 7; i++) { for (int i = 0; i < 12; i++) {
buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1)); buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1));
} }
} }
@@ -149,6 +157,7 @@ public class KeyBindingDialogController implements Initializable {
+ "-fx-background-color: -fx-pp-front-color; " + "-fx-background-color: -fx-pp-front-color; "
+ "-fx-text-fill: -fx-pp-theme-color; " + "-fx-text-fill: -fx-pp-theme-color; "
+ "-fx-font-size: 13;"); + "-fx-font-size: 13;");
keyBindingDialogHeader.requestFocus();
} }
/** /**
@@ -0,0 +1,56 @@
package seng302.visualiser.controllers.dialogs;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
public class PopupDialogController implements Initializable {
@FXML
private Label headerLabel;
@FXML
private Label contentLabel;
@FXML
private Label closeLabel;
@FXML
private JFXButton optionButton;
@FXML
private JFXDialog popupDialog;
@Override
public void initialize(URL location, ResourceBundle resources) {
}
public void setContent(String content) {
this.contentLabel.setText(content);
}
public void setHeader(String header) {
this.headerLabel.setText(header);
}
public void setOptionButton(JFXButton jfxButton) {
this.optionButton = jfxButton;
}
public void setOptionButtonText(String text) {
this.optionButton.setText(text);
}
public void setOptionButtonEventHandler(EventHandler<? super MouseEvent> eventHandler) {
this.optionButton.setOnMouseClicked(eventHandler);
}
public void setPopupDialog(JFXDialog popupDialog) {
this.popupDialog = popupDialog;
this.closeLabel.setOnMouseClicked(event -> this.popupDialog.close());
}
}
@@ -3,6 +3,7 @@ package seng302.visualiser.fxObjects.assets_3D;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.geometry.Point3D; import javafx.geometry.Point3D;
import javafx.scene.Group; import javafx.scene.Group;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
@@ -30,12 +31,15 @@ public class BoatObject extends Group {
private Boolean isSelected = false; private Boolean isSelected = false;
private Rotate rotation = new Rotate(0, new Point3D(0,0,1)); private Rotate rotation = new Rotate(0, new Point3D(0,0,1));
private ReadOnlyDoubleWrapper rotationProperty;
private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>(); private List<SelectedBoatListener> selectedBoatListenerListeners = new ArrayList<>();
/** /**
* Creates a BoatGroup with the default triangular boat polygon. * Creates a BoatGroup with the default triangular boat polygon.
*/ */
public BoatObject(BoatMeshType boatMeshType) { public BoatObject(BoatMeshType boatMeshType) {
rotationProperty = new ReadOnlyDoubleWrapper(0.0);
boatAssets = ModelFactory.boatGameView(boatMeshType, colour); boatAssets = ModelFactory.boatGameView(boatMeshType, colour);
boatAssets.hideSail(); boatAssets.hideSail();
boatAssets.getAssets().getTransforms().addAll( boatAssets.getAssets().getTransforms().addAll(
@@ -83,6 +87,7 @@ public class BoatObject extends Group {
private void rotateTo(double heading, boolean sailsIn, double windDir) { private void rotateTo(double heading, boolean sailsIn, double windDir) {
rotationProperty.set(heading);
rotation.setAngle(heading); rotation.setAngle(heading);
wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1))); wake.getTransforms().setAll(new Rotate(heading, new Point3D(0,0,1)));
if (sailsIn) { if (sailsIn) {
@@ -130,4 +135,8 @@ public class BoatObject extends Group {
public void addSelectedBoatListener(SelectedBoatListener sbl) { public void addSelectedBoatListener(SelectedBoatListener sbl) {
selectedBoatListenerListeners.add(sbl); selectedBoatListenerListeners.add(sbl);
} }
public ReadOnlyDoubleWrapper getRotationProperty() {
return rotationProperty;
}
} }
+5
View File
@@ -51,6 +51,11 @@
/********* customised scroll bar for scroll pane ***********/ /********* customised scroll bar for scroll pane ***********/
.scroll-pane {
-fx-focus-traversable: false;
-fx-border-style: none;
}
/* The main scrollbar **track** CSS class */ /* The main scrollbar **track** CSS class */
.scroll-bar:horizontal .track, .scroll-bar:horizontal .track,
.scroll-bar:vertical .track { .scroll-bar:vertical .track {
@@ -9,8 +9,13 @@
} }
#closeLabel:hover { #closeLabel:hover {
-fx-text-fill: -fx-pp-theme-color; -fx-text-fill: red;
-fx-font-size: 33; -fx-font-size: 33px;
}
.sectionLabel {
-fx-text-fill: -fx-pp-dark-text-color;
-fx-font-size: 20px;
} }
JFXButton { JFXButton {
+33
View File
@@ -0,0 +1,33 @@
#headerLabel {
-fx-font-size: 20px;
-fx-text-fill: -fx-pp-dark-text-color;
}
#closeLabel {
-fx-font-size: 22px;
-fx-text-fill: -fx-pp-dark-text-color;
}
#closeLabel:hover {
-fx-font-size: 24px;
-fx-text-fill: red;
}
#contentLabel {
-fx-font-size: 22px;
-fx-text-fill: -fx-pp-dark-text-color;
}
#optionButton {
-fx-background-color: -fx-pp-theme-color;
-fx-text-fill: -fx-pp-light-text-color;
-fx-font-size: 18px;
-fx-effect: -fx-pp-dropshadow-light;
-fx-max-height: 55;
-fx-focus-traversable: false;
}
#optionButton:hover {
-fx-font-size: 20px !important;
-fx-background-color: -fx-pp-light-theme-color;
}
+37 -48
View File
@@ -7,17 +7,16 @@
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?> <?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?> <?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?> <?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?> <?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<StackPane fx:id="contentStackPane" maxHeight="1.7976931348623157E308" <StackPane fx:id="contentStackPane" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0"
prefHeight="800.0" prefWidth="1200.0" prefWidth="1200.0" style="-fx-background-color: skyblue;" xmlns="http://javafx.com/javafx/8.0.111"
style="-fx-background-color: skyblue;" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.RaceViewController"> fx:controller="seng302.visualiser.controllers.RaceViewController">
<children> <children>
@@ -38,17 +37,15 @@
valignment="BOTTOM" vgrow="SOMETIMES"/> valignment="BOTTOM" vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0" <GridPane id="timerGrid" fx:id="timerGrid" prefWidth="192.0" styleClass="timer">
styleClass="timer">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="50.0" minWidth="50.0"
prefWidth="50.0"/> prefWidth="50.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="135.0" minWidth="135.0"
minWidth="135.0" prefWidth="135.0"/> prefWidth="135.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<opaqueInsets> <opaqueInsets>
<Insets/> <Insets/>
@@ -80,25 +77,20 @@
</GridPane> </GridPane>
<GridPane GridPane.columnIndex="2"> <GridPane GridPane.columnIndex="2">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
prefWidth="100.0"/> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"
prefWidth="100.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
</GridPane> </GridPane>
<GridPane fx:id="chatGridPane" GridPane.columnIndex="2" <GridPane fx:id="chatGridPane" GridPane.columnIndex="2" GridPane.rowIndex="2">
GridPane.rowIndex="2">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="390.0" minWidth="390.0"
minWidth="390.0" prefWidth="390.0"/> prefWidth="390.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" <RowConstraints maxHeight="1.7976931348623157E308" vgrow="SOMETIMES"/>
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" <RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
@@ -121,22 +113,21 @@
minWidth="90.0" prefWidth="90.0"/> minWidth="90.0" prefWidth="90.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="50.0" minHeight="50.0" <RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0"
prefHeight="50.0" valignment="CENTER" vgrow="SOMETIMES"/> valignment="CENTER" vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<JFXButton fx:id="chatSend" alignment="CENTER" <JFXButton fx:id="chatSend" alignment="CENTER" buttonType="RAISED"
buttonType="RAISED" maxHeight="-Infinity" focusTraversable="false" maxHeight="-Infinity"
maxWidth="1.7976931348623157E308" minHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="35.0" text="SEND" minWidth="-Infinity" prefHeight="35.0" text="SEND"
GridPane.columnIndex="1"> GridPane.columnIndex="1">
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" left="10.0" right="10.0" <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
top="10.0"/>
</GridPane.margin> </GridPane.margin>
</JFXButton> </JFXButton>
<JFXTextField fx:id="chatInput" maxHeight="35.0" <JFXTextField fx:id="chatInput" focusTraversable="false"
minHeight="-Infinity" prefHeight="35.0"> maxHeight="35.0" minHeight="-Infinity" prefHeight="35.0">
<GridPane.margin> <GridPane.margin>
<Insets bottom="10.0" left="20.0" right="10.0"/> <Insets bottom="10.0" left="20.0" right="10.0"/>
</GridPane.margin> </GridPane.margin>
@@ -158,29 +149,27 @@
prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER" prefHeight="150.0" prefWidth="240.0" GridPane.halignment="CENTER"
GridPane.rowIndex="2" GridPane.valignment="BOTTOM"> GridPane.rowIndex="2" GridPane.valignment="BOTTOM">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="110.0" minWidth="110.0"
minWidth="110.0" prefWidth="110.0"/> prefWidth="110.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" <ColumnConstraints hgrow="SOMETIMES" maxWidth="132.0" minWidth="10.0"
minWidth="10.0"
prefWidth="132.0"/> prefWidth="132.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="120.0" minHeight="120.0" <RowConstraints maxHeight="120.0" minHeight="120.0" prefHeight="120.0"
prefHeight="120.0" vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" <RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<Label fx:id="positionLabel" text="Position:" <Label fx:id="positionLabel" text="Position:" GridPane.columnIndex="1"
GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.halignment="LEFT" GridPane.rowSpan="2" GridPane.valignment="TOP">
GridPane.rowSpan="2" GridPane.valignment="TOP">
<padding> <padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/> <Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</padding> </padding>
</Label> </Label>
<Label fx:id="boatSpeedLabel" text="Boat Speed:" <Label fx:id="boatSpeedLabel" text="Boat Speed:" GridPane.columnIndex="1"
GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.halignment="LEFT" GridPane.rowSpan="2"
GridPane.rowSpan="2" GridPane.valignment="CENTER"> GridPane.valignment="CENTER">
<opaqueInsets> <opaqueInsets>
<Insets/> <Insets/>
</opaqueInsets> </opaqueInsets>
@@ -189,8 +178,8 @@
</padding> </padding>
</Label> </Label>
<Label fx:id="boatHeadingLabel" text="Boat Heading:" <Label fx:id="boatHeadingLabel" text="Boat Heading:"
GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowSpan="2"
GridPane.rowSpan="2" GridPane.valignment="BOTTOM"> GridPane.valignment="BOTTOM">
<padding> <padding>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/> <Insets bottom="5.0" left="10.0" right="5.0" top="5.0"/>
</padding> </padding>
@@ -203,12 +192,12 @@
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="120.0" minHeight="120.0" <RowConstraints maxHeight="120.0" minHeight="120.0"
prefHeight="120.0" vgrow="SOMETIMES"/> prefHeight="120.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="30.0" minHeight="30.0" <RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0"
prefHeight="30.0" vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<ImageView fx:id="windImageView" fitHeight="92.0" <ImageView fx:id="windImageView" fitHeight="92.0" fitWidth="109.0"
fitWidth="109.0" pickOnBounds="true" preserveRatio="true" pickOnBounds="true" preserveRatio="true"
GridPane.halignment="CENTER" GridPane.rowSpan="2" GridPane.halignment="CENTER" GridPane.rowSpan="2"
GridPane.valignment="CENTER"/> GridPane.valignment="CENTER"/>
<Label fx:id="windSpeedLabel" text="0.0 Knots" <Label fx:id="windSpeedLabel" text="0.0 Knots"
@@ -6,117 +6,226 @@
<?import java.net.URL?> <?import java.net.URL?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<JFXDialogLayout fx:id="keyBindDialog" maxHeight="-Infinity" maxWidth="-Infinity" <JFXDialogLayout fx:id="keyBindDialog" maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity" prefHeight="580.0" prefWidth="500.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="580.0" prefWidth="500.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.KeyBindingDialogController"> fx:controller="seng302.visualiser.controllers.dialogs.KeyBindingDialogController">
<stylesheets>
<URL value="@../../css/dialogs/KeyBindingDialog.css"/>
<URL value="@../../css/Master.css"/>
</stylesheets>
<children> <children>
<GridPane> <GridPane>
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0"/> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0"/>
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints maxHeight="60.0" minHeight="60.0" prefHeight="60.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="60.0"
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/> <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="60.0"
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="70.0"
vgrow="SOMETIMES"/> vgrow="SOMETIMES"/>
</rowConstraints> </rowConstraints>
<children> <children>
<Label fx:id="keyBindingDialogHeader" text="CUSTOM KEYBIND" GridPane.columnSpan="2" GridPane.halignment="CENTER" GridPane.valignment="CENTER" /> <ScrollPane prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="1">
<Label text="ZOOM IN" GridPane.halignment="CENTER" GridPane.rowIndex="1" <content>
GridPane.valignment="CENTER"> <StackPane prefHeight="150.0" prefWidth="200.0">
<children>
<GridPane>
<children>
<JFXButton fx:id="viewButton" buttonType="RAISED"
minHeight="35.0" prefWidth="120.0" text="F1"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="14" GridPane.valignment="CENTER"/>
<Label text="VIEW ASPECT" GridPane.halignment="CENTER"
GridPane.rowIndex="14" GridPane.valignment="CENTER"/>
<JFXButton fx:id="rightButton" buttonType="RAISED"
minHeight="35.0" prefWidth="120.0" text="D"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="13" GridPane.valignment="CENTER"/>
<Label text="RIGHT" GridPane.halignment="CENTER"
GridPane.rowIndex="13" GridPane.valignment="CENTER"/>
<JFXButton fx:id="leftButton" buttonType="RAISED"
minHeight="35.0" prefWidth="120.0" text="A"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="12" GridPane.valignment="CENTER"/>
<Label text="LEFT" GridPane.halignment="CENTER"
GridPane.rowIndex="12" GridPane.valignment="CENTER"/>
<JFXButton fx:id="forwardButton" buttonType="RAISED"
minHeight="35.0" prefWidth="120.0" text="W"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="10" GridPane.valignment="CENTER"/>
<Label text="FORWARD" GridPane.halignment="CENTER"
GridPane.rowIndex="10" GridPane.valignment="CENTER"/>
<JFXButton fx:id="backwardButton" buttonType="RAISED"
minHeight="35.0" prefWidth="120.0" text="S"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="11" GridPane.valignment="CENTER"/>
<Label text="BACKWARD" GridPane.halignment="CENTER"
GridPane.rowIndex="11" GridPane.valignment="CENTER"/>
<Label text="ZOOM IN" GridPane.halignment="CENTER"
GridPane.rowIndex="1" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets/>
</GridPane.margin></Label> </GridPane.margin>
<Label text="ZOOM OUT" GridPane.halignment="CENTER" GridPane.rowIndex="2" </Label>
GridPane.valignment="CENTER"> <Label text="ZOOM OUT" GridPane.halignment="CENTER"
GridPane.rowIndex="2" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets/>
</GridPane.margin></Label> </GridPane.margin>
<Label text="VMG" GridPane.halignment="CENTER" GridPane.rowIndex="3" </Label>
GridPane.valignment="CENTER"> <Label text="VMG" GridPane.halignment="CENTER"
GridPane.rowIndex="3" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets/>
</GridPane.margin></Label> </GridPane.margin>
<Label text="SAILS IN/OUT" GridPane.halignment="CENTER" GridPane.rowIndex="4" </Label>
GridPane.valignment="CENTER"> <Label text="SAILS IN/OUT" GridPane.halignment="CENTER"
GridPane.rowIndex="4" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets/>
</GridPane.margin></Label> </GridPane.margin>
<Label text="TACK/GYBE" GridPane.halignment="CENTER" GridPane.rowIndex="5" </Label>
GridPane.valignment="CENTER"> <Label text="TACK/GYBE" GridPane.halignment="CENTER"
GridPane.rowIndex="5" GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets/>
</GridPane.margin></Label> </GridPane.margin>
<Label fx:id="upwindLabel" text="UPWIND" GridPane.halignment="CENTER" </Label>
GridPane.rowIndex="6" GridPane.valignment="CENTER"> <Label fx:id="upwindLabel" text="UPWIND"
<GridPane.margin> GridPane.halignment="CENTER" GridPane.rowIndex="6"
<Insets/>
</GridPane.margin></Label>
<Label fx:id="downwindLabel" text="DOWNWIND" GridPane.halignment="CENTER"
GridPane.rowIndex="7" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin></Label>
<JFXButton id="ZOOM IN" fx:id="zoomInbtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" text="Z"
GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1"
GridPane.valignment="CENTER"/>
<JFXButton id="ZOOM OUT" fx:id="zoomOutBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0" text="X"
GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2"
GridPane.valignment="CENTER"/>
<JFXButton id="VMG" fx:id="vmgBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
text="SPACE" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="3" GridPane.valignment="CENTER"/>
<JFXButton id="SAILS IN/OUT" fx:id="sailInOutBtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
prefWidth="120.0" text="SHIFT" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="4" GridPane.valignment="CENTER"/>
<JFXButton id="TACK/GYBE" fx:id="tackGybeBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
text="ENTER" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="5" GridPane.valignment="CENTER"/>
<JFXButton id="UPWIND" fx:id="upwindBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
text="PAGE_UP" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="6" GridPane.valignment="CENTER"/>
<JFXButton id="DOWNWIND" fx:id="downwindBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity" prefWidth="120.0"
text="PAGE_DOWN" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="7" GridPane.valignment="CENTER"/>
<JFXToggleButton fx:id="turningToggle" minHeight="-Infinity" prefHeight="35.0"
text="OFF / ON" GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="8"/>
<Label text="CONTINUOUSLY TURNING" GridPane.halignment="CENTER" GridPane.rowIndex="8"
GridPane.valignment="CENTER"> GridPane.valignment="CENTER">
<GridPane.margin> <GridPane.margin>
<Insets/> <Insets/>
</GridPane.margin> </GridPane.margin>
</Label> </Label>
<Label fx:id="downwindLabel" text="DOWNWIND"
GridPane.halignment="CENTER" GridPane.rowIndex="7"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin>
</Label>
<JFXButton id="ZOOM IN" fx:id="zoomInbtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
minWidth="-Infinity" prefWidth="120.0" text="Z"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="1" GridPane.valignment="CENTER"/>
<JFXButton id="ZOOM OUT" fx:id="zoomOutBtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
minWidth="-Infinity" prefWidth="120.0" text="X"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="2" GridPane.valignment="CENTER"/>
<JFXButton id="VMG" fx:id="vmgBtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
minWidth="-Infinity" prefWidth="120.0" text="SPACE"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="3" GridPane.valignment="CENTER"/>
<JFXButton id="SAILS IN/OUT" fx:id="sailInOutBtn"
buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
prefWidth="120.0" text="SHIFT" GridPane.columnIndex="1"
GridPane.halignment="CENTER" GridPane.rowIndex="4"
GridPane.valignment="CENTER"/>
<JFXButton id="TACK/GYBE" fx:id="tackGybeBtn"
buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
prefWidth="120.0" text="ENTER" GridPane.columnIndex="1"
GridPane.halignment="CENTER" GridPane.rowIndex="5"
GridPane.valignment="CENTER"/>
<JFXButton id="UPWIND" fx:id="upwindBtn" buttonType="RAISED"
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="35.0"
minWidth="-Infinity" prefWidth="120.0" text="PAGE_UP"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="6" GridPane.valignment="CENTER"/>
<JFXButton id="DOWNWIND" fx:id="downwindBtn"
buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="35.0" minWidth="-Infinity"
prefWidth="120.0" text="PAGE_DOWN" GridPane.columnIndex="1"
GridPane.halignment="CENTER" GridPane.rowIndex="7"
GridPane.valignment="CENTER"/>
<JFXToggleButton fx:id="turningToggle" minHeight="-Infinity"
prefHeight="35.0" text="OFF / ON" GridPane.columnIndex="1"
GridPane.halignment="CENTER" GridPane.rowIndex="8"/>
<Label text="CONTINUOUSLY TURNING" GridPane.halignment="CENTER"
GridPane.rowIndex="8" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin>
</Label>
<Label styleClass="sectionLabel" text="BOAT ACTIONS"
GridPane.columnSpan="2" GridPane.halignment="CENTER"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="50.0"/>
</GridPane.margin>
</Label>
<Label styleClass="sectionLabel" text="CAMERA SETTINGS"
GridPane.columnSpan="2" GridPane.halignment="CENTER"
GridPane.rowIndex="9" GridPane.valignment="CENTER">
<GridPane.margin>
<Insets left="50.0"/>
</GridPane.margin>
</Label>
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
minWidth="-Infinity" prefWidth="250.0"/>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="-Infinity"
minWidth="-Infinity" prefWidth="150.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
<RowConstraints maxHeight="50.0" minHeight="50.0"
prefHeight="50.0" vgrow="SOMETIMES"/>
</rowConstraints>
</GridPane>
</children>
</StackPane>
</content>
</ScrollPane>
<Label fx:id="keyBindingDialogHeader" text="CUSTOM KEYBINDING" GridPane.columnSpan="2"
GridPane.halignment="CENTER" GridPane.valignment="CENTER"/>
<Label fx:id="closeLabel" text="✖" GridPane.halignment="RIGHT"
GridPane.valignment="TOP"/>
<JFXButton fx:id="resetBtn" buttonType="RAISED" maxHeight="-Infinity" <JFXButton fx:id="resetBtn" buttonType="RAISED" maxHeight="-Infinity"
maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0"
prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER" prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER"
GridPane.rowIndex="9" GridPane.valignment="CENTER"/> GridPane.rowIndex="2" GridPane.valignment="CENTER"/>
<Label fx:id="closeLabel" text="✖" translateY="-5.0" GridPane.columnIndex="1"
GridPane.halignment="RIGHT" GridPane.valignment="TOP"/>
</children> </children>
</GridPane> </GridPane>
</children> </children>
<stylesheets>
<URL value="@../../css/dialogs/KeyBindingDialog.css" />
<URL value="@../../css/Master.css" />
</stylesheets>
</JFXDialogLayout> </JFXDialogLayout>
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXDialogLayout?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefWidth="550.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="seng302.visualiser.controllers.dialogs.PopupDialogController">
<children>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="1.7976931348623157E308"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="-Infinity" minHeight="30.0" prefHeight="30.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="80.0"
prefHeight="80.0" vgrow="SOMETIMES"/>
<RowConstraints minHeight="50.0" prefHeight="50.0" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<JFXButton fx:id="optionButton" buttonType="RAISED" prefHeight="55.0"
prefWidth="150.0" GridPane.halignment="RIGHT" GridPane.rowIndex="2"
GridPane.valignment="CENTER">
<GridPane.margin>
<Insets/>
</GridPane.margin>
</JFXButton>
<Label fx:id="contentLabel" text="Popup content goes here ..."
GridPane.rowIndex="1"/>
<Label fx:id="headerLabel" text="Popup header"/>
<Label fx:id="closeLabel" text="✖" translateY="-10.0" GridPane.halignment="RIGHT"/>
</children>
</GridPane>
</children>
<stylesheets>
<URL value="@../../css/dialogs/Popup.css"/>
<URL value="@../../css/Master.css"/>
</stylesheets>
</JFXDialogLayout>