diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 4efb1d23..4bb27f72 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -1,12 +1,35 @@ package seng302.gameServer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; import javafx.scene.paint.Color; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.InputSource; -import seng302.gameServer.messages.*; -import seng302.model.*; +import seng302.gameServer.messages.BoatAction; +import seng302.gameServer.messages.BoatStatus; +import seng302.gameServer.messages.ChatterMessage; +import seng302.gameServer.messages.CustomizeRequestType; +import seng302.gameServer.messages.MarkRoundingMessage; +import seng302.gameServer.messages.MarkType; +import seng302.gameServer.messages.Message; +import seng302.gameServer.messages.RoundingBoatStatus; +import seng302.gameServer.messages.YachtEventCodeMessage; +import seng302.gameServer.messages.YachtEventType; +import seng302.model.GeoPoint; +import seng302.model.Limit; +import seng302.model.Player; +import seng302.model.PolarTable; +import seng302.model.ServerYacht; import seng302.model.mark.CompoundMark; import seng302.model.mark.Mark; import seng302.model.mark.MarkOrder; @@ -14,10 +37,6 @@ import seng302.model.token.Token; import seng302.model.token.TokenType; import seng302.utilities.GeoUtility; import seng302.utilities.XMLParser; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.util.*; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** @@ -272,6 +291,12 @@ public class GameState implements Runnable { case DOWNWIND: playerYacht.turnDownwind(); break; + case CONTINUOUSLY_TURNING: + playerYacht.setContinuouslyTurning(true); + break; + case DEFAULT_TURNING: + playerYacht.setContinuouslyTurning(false); + break; } } diff --git a/src/main/java/seng302/gameServer/messages/BoatAction.java b/src/main/java/seng302/gameServer/messages/BoatAction.java index 9003958a..9bd2131f 100644 --- a/src/main/java/seng302/gameServer/messages/BoatAction.java +++ b/src/main/java/seng302/gameServer/messages/BoatAction.java @@ -14,7 +14,9 @@ public enum BoatAction { TACK_GYBE(4), UPWIND(5), DOWNWIND(6), - MAINTAIN_HEADING(7); + MAINTAIN_HEADING(7), + CONTINUOUSLY_TURNING(8), + DEFAULT_TURNING(9); private final int type; private static final Map intToTypeMap = new HashMap<>(); diff --git a/src/main/java/seng302/gameServer/messages/BoatActionMessage.java b/src/main/java/seng302/gameServer/messages/BoatActionMessage.java index 419bf72e..8fa78195 100644 --- a/src/main/java/seng302/gameServer/messages/BoatActionMessage.java +++ b/src/main/java/seng302/gameServer/messages/BoatActionMessage.java @@ -5,19 +5,19 @@ package seng302.gameServer.messages; */ public class BoatActionMessage extends Message{ private final MessageType MESSAGE_TYPE = MessageType.BOAT_ACTION; - private final int MESSAGE_SIZE = 1; + private final int MESSAGE_SIZE = 5; private BoatAction actionType; - public BoatActionMessage(BoatAction actionType) { + public BoatActionMessage(BoatAction actionType, int sourceId) { this.actionType = actionType; - setHeader(new Header(MessageType.BOAT_ACTION, 0, (short) 1)); // the second variable is the source id + setHeader(new Header(MessageType.BOAT_ACTION, sourceId, (short) MESSAGE_SIZE)); // the second variable is the source id allocateBuffer(); writeHeaderToBuffer(); // Write message fields putInt(actionType.getValue(), 1); + putInt(sourceId, 4); writeCRC(); rewind(); - } @Override diff --git a/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java b/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java index c7b2a1db..6a8e76ad 100644 --- a/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java +++ b/src/main/java/seng302/gameServer/messages/RegistrationRequestMessage.java @@ -4,8 +4,8 @@ package seng302.gameServer.messages; public class RegistrationRequestMessage extends Message { private static int MESSAGE_LENGTH = 2; - public RegistrationRequestMessage(ClientType type){ - setHeader(new Header(MessageType.REGISTRATION_REQUEST, 1, (short) getSize())); + public RegistrationRequestMessage(ClientType type, int clientID){ + setHeader(new Header(MessageType.REGISTRATION_REQUEST, clientID, (short) getSize())); allocateBuffer(); writeHeaderToBuffer(); diff --git a/src/main/java/seng302/model/GameKeyBind.java b/src/main/java/seng302/model/GameKeyBind.java new file mode 100644 index 00000000..c25f6202 --- /dev/null +++ b/src/main/java/seng302/model/GameKeyBind.java @@ -0,0 +1,83 @@ +package seng302.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import javafx.scene.input.KeyCode; + +public class GameKeyBind { + + private static GameKeyBind instance; + private Map keyToActionMap; + private Map actionToKeyMap; + private Boolean continuouslyTurning; + + + private GameKeyBind() { + setToDefault(); + } + + public void setToDefault() { + actionToKeyMap = new HashMap<>(); + keyToActionMap = new HashMap<>(); + continuouslyTurning = false; + // default key bindings + ArrayList keys = new ArrayList<>(); + keys.add(KeyCode.Z); + keys.add(KeyCode.X); + keys.add(KeyCode.SPACE); + keys.add(KeyCode.SHIFT); + keys.add(KeyCode.ENTER); + keys.add(KeyCode.PAGE_UP); + keys.add(KeyCode.PAGE_DOWN); + 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)); + keyToActionMap.put(keys.get(i), KeyAction.getType(i + 1)); + } + } + + public static GameKeyBind getInstance() { + if (instance == null) { + instance = new GameKeyBind(); + } + return instance; + } + + public KeyCode getKeyCode(KeyAction keyAction) { + return instance.actionToKeyMap.get(keyAction); + } + + /** + * Binds a key to a key action + * + * @return true if successfully bind + */ + public boolean bindKeyToAction(KeyCode keyCode, KeyAction keyAction) { + if (instance.keyToActionMap.containsKey(keyCode)) { + // if the key has been bound to other action, return false + return false; + } else { + instance.keyToActionMap.put(keyCode, keyAction); // add key -> action + KeyCode oldKeyCode = instance.actionToKeyMap + .get(keyAction); // get old key for the action + instance.keyToActionMap.remove(oldKeyCode); // remove the old key -> action + instance.actionToKeyMap + .replace(keyAction, keyCode); // replace the old key by the newer one + return true; + } + } + + public void toggleTurningMode() { + continuouslyTurning = !continuouslyTurning; + } + + public Boolean isContinuouslyTurning() { + return continuouslyTurning; + } + +} diff --git a/src/main/java/seng302/model/KeyAction.java b/src/main/java/seng302/model/KeyAction.java new file mode 100644 index 00000000..51509027 --- /dev/null +++ b/src/main/java/seng302/model/KeyAction.java @@ -0,0 +1,40 @@ +package seng302.model; + +import java.util.HashMap; +import java.util.Map; + +public enum KeyAction { + ZOOM_IN(1), + ZOOM_OUT(2), + VMG(3), + SAILS_STATE(4), + TACK_GYBE(5), + UPWIND(6), + DOWNWIND(7), + VIEW(8), + RIGHT(9), + LEFT(10), + FORWARD(11), + BACKWARD(12); + + private final int type; + private static final Map intToTypeMap = new HashMap<>(); + + static { + for (KeyAction type : KeyAction.values()) { + intToTypeMap.put(type.getValue(), type); + } + } + + KeyAction(int type) { + this.type = type; + } + + public static KeyAction getType(int value) { + return intToTypeMap.get(value); + } + + public int getValue() { + return this.type; + } +} diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index 37065649..5822b248 100644 --- a/src/main/java/seng302/model/ServerYacht.java +++ b/src/main/java/seng302/model/ServerYacht.java @@ -1,5 +1,6 @@ package seng302.model; +import java.util.HashMap; import javafx.scene.paint.Color; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -10,12 +11,6 @@ import seng302.model.token.TokenType; import seng302.utilities.GeoUtility; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; -import java.util.HashMap; -import java.util.Objects; -import java.util.Observable; -import java.util.Observer; -import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; - /** * Yacht class for the racing boat.

Class created to store more variables (eg. boat statuses) * compared to the XMLParser boat class, also done outside Boat class because some old variables are @@ -61,6 +56,8 @@ public class ServerYacht { private TokenType powerUp; private Long powerUpStartTime; + //turning mode + private Boolean continuouslyTurning; public ServerYacht(BoatMeshType boatType, Integer sourceId, String hullID, String shortName, String boatName, String country) { @@ -85,6 +82,8 @@ public class ServerYacht { this.hasEnteredRoundingZone = false; this.hasPassedLine = false; this.hasPassedThroughGate = false; + + this.continuouslyTurning = false; } @@ -192,44 +191,52 @@ public class ServerYacht { public void turnUpwind() { disableAutoPilot(); Double normalizedHeading = normalizeHeading(); - if (normalizedHeading == 0) { - if (lastHeading < 180) { - adjustHeading(-turnStep); - } else { - adjustHeading(turnStep); - } - } else if (normalizedHeading == 180) { - if (lastHeading < 180) { - adjustHeading(turnStep); - } else { - adjustHeading(-turnStep); - } - } else if (normalizedHeading < 180) { - adjustHeading(-turnStep); - } else { + if (continuouslyTurning) { adjustHeading(turnStep); + } else { + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(-turnStep); + } else { + adjustHeading(turnStep); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(turnStep); + } else { + adjustHeading(-turnStep); + } + } else if (normalizedHeading < 180) { + adjustHeading(-turnStep); + } else { + adjustHeading(turnStep); + } } } public void turnDownwind() { disableAutoPilot(); Double normalizedHeading = normalizeHeading(); - if (normalizedHeading == 0) { - if (lastHeading < 180) { - adjustHeading(turnStep); - } else { - adjustHeading(-turnStep); - } - } else if (normalizedHeading == 180) { - if (lastHeading < 180) { - adjustHeading(-turnStep); - } else { - adjustHeading(turnStep); - } - } else if (normalizedHeading < 180) { - adjustHeading(turnStep); - } else { + if (continuouslyTurning) { adjustHeading(-turnStep); + } else { + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(turnStep); + } else { + adjustHeading(-turnStep); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(-turnStep); + } else { + adjustHeading(turnStep); + } + } else if (normalizedHeading < 180) { + adjustHeading(turnStep); + } else { + adjustHeading(-turnStep); + } } } @@ -445,4 +452,8 @@ public class ServerYacht { public BoatMeshType getBoatType() { return boatType; } + + public void setContinuouslyTurning(Boolean continuouslyTurning) { + this.continuouslyTurning = continuouslyTurning; + } } diff --git a/src/main/java/seng302/utilities/XMLParser.java b/src/main/java/seng302/utilities/XMLParser.java index 71da1248..912708df 100644 --- a/src/main/java/seng302/utilities/XMLParser.java +++ b/src/main/java/seng302/utilities/XMLParser.java @@ -4,12 +4,14 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import javafx.scene.paint.Color; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import seng302.model.ClientYacht; +import seng302.model.Colors; import seng302.model.Limit; import seng302.model.mark.CompoundMark; import seng302.model.mark.Corner; @@ -139,14 +141,26 @@ public class XMLParser { Node currentBoat = boatsList.item(i); if (currentBoat.getNodeName().equals("Boat")) { // Boat boat = new Boat(currentBoat); + BoatMeshType boatMeshType; + try { + boatMeshType = BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type")); + } catch (IllegalArgumentException e){ + boatMeshType = BoatMeshType.DINGHY; + } + Color color; + try { + color = Color.web(getNodeAttributeString(currentBoat, "Color")); + } catch (NullPointerException npe) { + color = Colors.getColor(new Random().nextInt(8)); + } ClientYacht yacht = new ClientYacht( - BoatMeshType.valueOf(XMLParser.getNodeAttributeString(currentBoat, "Type")), + boatMeshType, XMLParser.getNodeAttributeInt(currentBoat, "SourceID"), XMLParser.getNodeAttributeString(currentBoat, "HullNum"), XMLParser.getNodeAttributeString(currentBoat, "ShortName"), XMLParser.getNodeAttributeString(currentBoat, "BoatName"), XMLParser.getNodeAttributeString(currentBoat, "Country")); - yacht.setColour(Color.web(getNodeAttributeString(currentBoat, "Color"))); + yacht.setColour(color); competingBoats.put(yacht.getSourceId(), yacht); } } @@ -195,17 +209,20 @@ public class XMLParser { */ private static List extractTokens(Element docEle) { List tokens = new ArrayList<>(); - NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes(); - for (int i = 0; i < tokenList.getLength(); i++) { - Node tokenNode = tokenList.item(i); - if (tokenNode.getNodeName().equals("Token")) { - String tokenType = getNodeAttributeString(tokenNode, "TokenType"); - Double lat = getNodeAttributeDouble(tokenNode, "TargetLat"); - Double lng = getNodeAttributeDouble(tokenNode, "TargetLng"); - tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng)); + try { + NodeList tokenList = docEle.getElementsByTagName("Tokens").item(0).getChildNodes(); + for (int i = 0; i < tokenList.getLength(); i++) { + Node tokenNode = tokenList.item(i); + if (tokenNode.getNodeName().equals("Token")) { + String tokenType = getNodeAttributeString(tokenNode, "TokenType"); + Double lat = getNodeAttributeDouble(tokenNode, "TargetLat"); + Double lng = getNodeAttributeDouble(tokenNode, "TargetLng"); + tokens.add(new Token(TokenType.valueOf(tokenType), lat, lng)); + } } + } catch (NullPointerException npe) { + return new ArrayList<>(); } - return tokens; } diff --git a/src/main/java/seng302/visualiser/ClientToServerThread.java b/src/main/java/seng302/visualiser/ClientToServerThread.java index e53aed22..fe32ed85 100644 --- a/src/main/java/seng302/visualiser/ClientToServerThread.java +++ b/src/main/java/seng302/visualiser/ClientToServerThread.java @@ -175,7 +175,7 @@ public class ClientToServerThread implements Runnable { * Sends a request to the server asking for a source ID */ private void sendRegistrationRequest() { - RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER); + RegistrationRequestMessage requestMessage = new RegistrationRequestMessage(ClientType.PLAYER, clientId); try { os.write(requestMessage.getBuffer()); @@ -193,7 +193,6 @@ public class ClientToServerThread implements Runnable { private void processRegistrationResponse(StreamPacket packet){ int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 3)); int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5)); - RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode); if (status.equals(RegistrationResponseStatus.SUCCESS_PLAYING)){ @@ -243,7 +242,7 @@ public class ClientToServerThread implements Runnable { new TimerTask() { @Override public void run() { - sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND)); + sendBoatActionMessage(new BoatActionMessage(BoatAction.DOWNWIND, clientId)); } }, 0, PACKET_SENDING_INTERVAL_MS ); @@ -256,14 +255,14 @@ public class ClientToServerThread implements Runnable { new TimerTask() { @Override public void run() { - sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND)); + sendBoatActionMessage(new BoatActionMessage(BoatAction.UPWIND, clientId)); } }, 0, PACKET_SENDING_INTERVAL_MS ); } break; default: - sendBoatActionMessage(new BoatActionMessage(actionType)); + sendBoatActionMessage(new BoatActionMessage(actionType, clientId)); break; } } diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index 7040d7ee..9d64b50d 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -14,8 +14,6 @@ import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXMLLoader; -import javafx.scene.control.Alert; -import javafx.scene.control.Alert.AlertType; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.Pane; @@ -28,6 +26,8 @@ import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.BoatStatus; import seng302.gameServer.messages.YachtEventType; import seng302.model.ClientYacht; +import seng302.model.GameKeyBind; +import seng302.model.KeyAction; import seng302.model.RaceState; import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.parser.MarkRoundingData; @@ -44,6 +44,7 @@ import seng302.utilities.XMLParser; import seng302.visualiser.controllers.LobbyController; import seng302.visualiser.controllers.RaceViewController; 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 @@ -66,6 +67,8 @@ public class GameClient { private ArrayList finishedBoats = new ArrayList<>(); + private GameKeyBind gameKeyBind; // all the key binding setting. + private ObservableList clientLobbyList = FXCollections.observableArrayList(); /** @@ -75,6 +78,7 @@ public class GameClient { */ public GameClient(Pane holder) { this.holderPane = holder; + this.gameKeyBind = GameKeyBind.getInstance(); } /** @@ -164,10 +168,12 @@ public class GameClient { private void showConnectionError (String message) { Platform.runLater(() -> { - Alert alert = new Alert(AlertType.ERROR); - alert.setHeaderText("Connection Error"); - alert.setContentText(message); - alert.showAndWait(); + PopupDialogController controller = ViewManager.getInstance().showPopupDialog(); + controller.setHeader("Oops"); + controller.setContent(message); + controller.setOptionButtonText("GO HOME"); + controller + .setOptionButtonEventHandler(event -> ViewManager.getInstance().goToStartView()); }); } @@ -373,16 +379,16 @@ public class GameClient { } return; } - switch (e.getCode()) { - case SPACE: // align with vmg - socketThread.sendBoatAction(BoatAction.VMG); break; - case PAGE_UP: // upwind - socketThread.sendBoatAction(BoatAction.UPWIND); break; - case PAGE_DOWN: // downwind - socketThread.sendBoatAction(BoatAction.DOWNWIND); break; - case ENTER: // tack/gybe - // if chat box is active take whatever is in there and send it to server - socketThread.sendBoatAction(BoatAction.TACK_GYBE); break; + + if (gameKeyBind.getKeyCode(KeyAction.VMG) == e.getCode()) { // align with vmg + socketThread.sendBoatAction(BoatAction.VMG); + } else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()) { // upwind + socketThread.sendBoatAction(BoatAction.UPWIND); + } else if (gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { // downwind + socketThread.sendBoatAction(BoatAction.DOWNWIND); + } else if (gameKeyBind.getKeyCode(KeyAction.TACK_GYBE) == e.getCode()) { // tack/gybe + // if chat box is active take whatever is in there and send it to server + socketThread.sendBoatAction(BoatAction.TACK_GYBE); } } @@ -391,15 +397,17 @@ public class GameClient { if (raceView.isChatInputFocused()) { return; } - switch (e.getCode()) { - //TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet) - case SHIFT: // sails in/sails out + + if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out + if (allBoatsMap.get(socketThread.getClientId()).getSailIn()) { + socketThread.sendBoatAction(BoatAction.SAILS_OUT); + } else { socketThread.sendBoatAction(BoatAction.SAILS_IN); - allBoatsMap.get(socketThread.getClientId()).toggleSail(); - break; - case PAGE_UP: - case PAGE_DOWN: - socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break; + } + allBoatsMap.get(socketThread.getClientId()).toggleSail(); + } else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode() + || gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { + socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); } } @@ -456,4 +464,14 @@ public class GameClient { public Map getAllBoatsMap() { return allBoatsMap; } + + public void sendToggleTurningModePacket() { + if (socketThread != null) { + if (gameKeyBind.isContinuouslyTurning()) { + socketThread.sendBoatAction(BoatAction.CONTINUOUSLY_TURNING); + } else { + socketThread.sendBoatAction(BoatAction.DEFAULT_TURNING); + } + } + } } diff --git a/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java b/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java index 7eb9b4fd..86e39ead 100644 --- a/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java +++ b/src/main/java/seng302/visualiser/controllers/FinishScreenViewController.java @@ -88,7 +88,6 @@ public class FinishScreenViewController implements Initializable { public void switchToStartScreenView() { Sounds.playButtonClick(); - //TODO merge fix setContentPane("/views/StartScreenView.fxml"); } diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index aa8430b8..2079dc14 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -91,16 +91,16 @@ public class LobbyController implements Initializable { ViewManager.getInstance().getPlayerList().setAll(ViewManager.getInstance().getPlayerList().sorted()); }); + customizeButton.setOnMouseReleased(event -> { + customizationDialog = createCustomizeDialog(); + Sounds.playButtonClick(); + customizationDialog.show(); + }); + Platform.runLater(() -> { Integer playerId = ViewManager.getInstance().getGameClient().getServerThread().getClientId(); playersColor = Colors.getColor(playerId - 1); - customizationDialog = createCustomizeDialog(); - - customizeButton.setOnMouseReleased(event -> { - Sounds.playButtonClick(); - customizationDialog.show(); - }); }); leaveLobbyButton.setOnMouseEntered(e -> Sounds.playHoverSound()); diff --git a/src/main/java/seng302/visualiser/controllers/RaceViewController.java b/src/main/java/seng302/visualiser/controllers/RaceViewController.java index 2ac06dfb..3d011a0d 100644 --- a/src/main/java/seng302/visualiser/controllers/RaceViewController.java +++ b/src/main/java/seng302/visualiser/controllers/RaceViewController.java @@ -87,7 +87,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel @FXML private Label timerLabel; @FXML - private StackPane contentAnchorPane; + private StackPane contentStackPane; private GridPane contentGridPane; @FXML @@ -134,8 +134,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Sounds.stopMusic(); Sounds.playRaceMusic(); - finishScreenDialog = createFinishDialog(); - // Load a default important annotation state //importantAnnotations = new ImportantAnnotationsState(); @@ -180,9 +178,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // chatHistory.textProperty().addListener((obs, oldValue, newValue) -> { // chatHistory.setScrollTop(Double.MAX_VALUE); // }); - rvAnchorPane.setOnMouseClicked((event) -> - rvAnchorPane.requestFocus() - ); + + contentStackPane.setOnMouseClicked(event -> { + contentStackPane.requestFocus(); + }); //Makes the chat history non transparent when clicked on chatInput.focusedProperty().addListener(new ChangeListener() { @@ -200,26 +199,27 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel public void showFinishDialog(ArrayList finishedBoats) { raceState.setRaceStarted(false); - finishDialogController.setFinishedBoats(finishedBoats); - finishScreenDialog.show(); + createFinishDialog(finishedBoats); } - private JFXDialog createFinishDialog() { + /** + * Create finishScreenDialog and set up finishDialogController. + */ + private void createFinishDialog(ArrayList finishedBoats) { FXMLLoader dialog = new FXMLLoader( getClass().getResource("/views/dialogs/RaceFinishDialog.fxml")); - JFXDialog finishScreenDialog = null; - - try { - finishScreenDialog = new JFXDialog(contentAnchorPane, dialog.load(), - JFXDialog.DialogTransition.CENTER); - } catch (IOException e) { - e.printStackTrace(); - } - - finishDialogController = dialog.getController(); - - return finishScreenDialog; + Platform.runLater(() -> { + try { + finishScreenDialog = new JFXDialog(contentStackPane, dialog.load(), + JFXDialog.DialogTransition.CENTER); + finishDialogController = dialog.getController(); + finishDialogController.setFinishedBoats(finishedBoats); + finishScreenDialog.show(); + } catch (IOException e) { + e.printStackTrace(); + } + }); } public void loadRace ( @@ -245,7 +245,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel gameView = new GameView3D(); // gameView.setFrameRateFXText(fpsDisplay); Platform.runLater(() -> { - contentAnchorPane.getChildren().add(0, gameView.getAssets()); + contentStackPane.getChildren().add(0, gameView.getAssets()); ((SubScene) gameView.getAssets()).widthProperty() .bind(ViewManager.getInstance().getStage().widthProperty()); ((SubScene) gameView.getAssets()).heightProperty() @@ -805,7 +805,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel public String readChatInput() { String chat = chatInput.getText(); chatInput.clear(); - rvAnchorPane.requestFocus(); + contentStackPane.requestFocus(); return chat; } diff --git a/src/main/java/seng302/visualiser/controllers/ServerListController.java b/src/main/java/seng302/visualiser/controllers/ServerListController.java index 3d457bd4..c6dc4325 100644 --- a/src/main/java/seng302/visualiser/controllers/ServerListController.java +++ b/src/main/java/seng302/visualiser/controllers/ServerListController.java @@ -112,16 +112,23 @@ public class ServerListController implements Initializable, ServerListenerDelega serverListVBox.getChildren().add(noServersFound); // Set up dialog for server creation + serverListHostButton.setOnAction(action -> { + showServerCreationDialog(); + }); + } + + /** + * Shows Server Creation Dialog when "Host" button is clicked. + */ + private void showServerCreationDialog() { Platform.runLater(() -> { FXMLLoader dialogContent = new FXMLLoader(getClass().getResource( "/views/dialogs/ServerCreationDialog.fxml")); try { JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(), DialogTransition.CENTER); - serverListHostButton.setOnAction(action -> { - dialog.show(); - Sounds.playButtonClick(); - }); + dialog.show(); + Sounds.playButtonClick(); } catch (IOException e) { logger.warn("Could not create Server Creation Dialog."); } diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 8e966813..5e3d6748 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -2,6 +2,9 @@ package seng302.visualiser.controllers; import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXDecorator; +import com.jfoenix.controls.JFXDialog; +import com.jfoenix.controls.JFXDialog.DialogTransition; +import com.jfoenix.controls.JFXSnackbar; import com.jfoenix.svg.SVGGlyph; import java.io.IOException; import java.util.HashMap; @@ -15,6 +18,7 @@ import javafx.scene.Scene; import javafx.scene.SceneAntialiasing; import javafx.scene.image.Image; import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.Stage; import org.slf4j.Logger; @@ -23,6 +27,8 @@ import seng302.gameServer.ServerAdvertiser; import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; +import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; +import seng302.visualiser.controllers.dialogs.PopupDialogController; public class ViewManager { @@ -32,12 +38,9 @@ public class ViewManager { private HashMap properties; //TODO is this the best way to do this?? private ObservableList playerList; private Logger logger = LoggerFactory.getLogger(ViewManager.class); - - public Stage getStage() { - return stage; - } - private Stage stage; + private JFXSnackbar jfxSnackbar; + private JFXDialog keyBindingDialog; private ViewManager() { properties = new HashMap<>(); @@ -99,6 +102,8 @@ public class ViewManager { gameClient.stopGame(); System.exit(0); }); + + jfxSnackbar = new JFXSnackbar(decorator); } /** @@ -119,12 +124,31 @@ public class ViewManager { //Get the button box HBox btns = (HBox) decorator.getChildren().get(0); + //Create settings button -- [WIP] + JFXButton btnKeyBinding = new JFXButton(); + btnKeyBinding.setText(" Key Bindings"); + btnKeyBinding.setStyle("-fx-text-fill:#fff"); + btnKeyBinding.getStyleClass().add("jfx-decorator-button"); + btnKeyBinding.setCursor(Cursor.HAND); + btnKeyBinding.setFocusTraversable(false); + + btnKeyBinding.setOnMouseClicked(event -> Platform.runLater(() -> { + try { + if (!checkDialogOpened(decorator.getChildren())) { + showKeyBindingDialog(); + } + } catch (IOException e) { + logger.warn("Something went wrong when opening key bind dialog"); + } + })); + //Create new button JFXButton btnMute = new JFXButton(); btnMute.setText(" Toggle Sound"); btnMute.setStyle("-fx-text-fill:#fff"); btnMute.getStyleClass().add("jfx-decorator-button"); btnMute.setCursor(Cursor.HAND); + btnMute.setFocusTraversable(false); //Create Graphics SVGGlyph spacer = new SVGGlyph(0, "SPACER", "", Color.WHITE); @@ -134,9 +158,13 @@ public class ViewManager { SVGGlyph volumeOff = new SVGGlyph(0, "VOLUME_ON", "M13.5,9 C13.5,7.2 12.5,5.7 11,5 L11,7.2 L13.5,9.7 L13.5,9 L13.5,9 Z M16,9 C16,9.9 15.8,10.8 15.5,11.6 L17,13.1 C17.7,11.9 18,10.4 18,8.9 C18,4.6 15,1 11,0.1 L11,2.2 C13.9,3.2 16,5.8 16,9 L16,9 Z M1.3,0 L0,1.3 L4.7,6 L0,6 L0,12 L4,12 L9,17 L9,10.3 L13.3,14.6 C12.6,15.1 11.9,15.5 11,15.8 L11,17.9 C12.4,17.6 13.6,17 14.7,16.1 L16.7,18.1 L18,16.8 L9,7.8 L1.3,0 L1.3,0 Z M9,1 L6.9,3.1 L9,5.2 L9,1 L9,1 Z", Color.WHITE); + SVGGlyph keyBindingGlyph = new SVGGlyph(0, "KEY_BINDING", + "M20 5H4c-1.1 0-1.99.9-1.99 2L2 17c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm-9 3h2v2h-2V8zm0 3h2v2h-2v-2zM8 8h2v2H8V8zm0 3h2v2H8v-2zm-1 2H5v-2h2v2zm0-3H5V8h2v2zm9 7H8v-2h8v2zm0-4h-2v-2h2v2zm0-3h-2V8h2v2zm3 3h-2v-2h2v2zm0-3h-2V8h2v2z", + Color.WHITE); volumeOn.setSize(16, 16); volumeOff.setSize(16, 16); spacer.setSize(40, 16); + keyBindingGlyph.setSize(24, 16); // Determine which graphic should go on the button if (Sounds.isMusicMuted() && Sounds.isSoundEffectsMuted()) { @@ -145,9 +173,12 @@ public class ViewManager { btnMute.setGraphic(volumeOn); } + btnKeyBinding.setGraphic(keyBindingGlyph); + // Add Buttons btns.getChildren().add(0, spacer); btns.getChildren().add(0, btnMute); + btns.getChildren().add(0, btnKeyBinding); btnMute.setOnAction((action) -> { Sounds.toggleAllSounds(); if (btnMute.getGraphic().equals(volumeOff)) { @@ -159,6 +190,83 @@ public class ViewManager { } + /** + * Recursively find JFXDialog given a starting node. Will traverse children of StackPane. + * + * @param nodes children nodes to be check. + * @return true if node contains JFXDialog. + */ + private Boolean checkDialogOpened(ObservableList nodes) { + boolean foundJFXDialog = false; + for (Node node : nodes) { + if (node instanceof JFXDialog) { + return true; + } else if (node instanceof StackPane) { + foundJFXDialog = checkDialogOpened(((StackPane) node).getChildren()); + } + } + return foundJFXDialog; + } + + private void showKeyBindingDialog() throws IOException { + FXMLLoader dialogContent = new FXMLLoader(getClass().getResource( + "/views/dialogs/KeyBindingDialog.fxml")); + for (Node node : decorator.getChildren()) { + if (node instanceof StackPane) { + keyBindingDialog = new JFXDialog((StackPane) node, + dialogContent.load(), + DialogTransition.CENTER); + + KeyBindingDialogController keyBindingDialogController = dialogContent + .getController(); + keyBindingDialogController.setGameClient(this.gameClient); + keyBindingDialog.show(); + Sounds.playButtonClick(); + } + } + } + + public void closeKeyBindingDialog() { + 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. + * + * @param snackbarText text to be displayed. + */ + public void showSnackbar(String snackbarText, boolean isWarning) { + if (isWarning) { + decorator.getStylesheets() + .add(getClass().getResource("/css/dialogs/Snackbar.css").toExternalForm()); + } else { + if (decorator.getStylesheets().size() > 1) { + decorator.getStylesheets().remove(1); + } + } + jfxSnackbar.show(snackbarText, 1500); + } + /** * Determines if a PC has compatibility with the bonjour protocol for server detection. */ @@ -221,6 +329,7 @@ public class ViewManager { /** * Change the view to the Lobby Screen + * * @param disableReadyButton Boolean value so that clients can't try start a game. * @return A LobbyController object for the Lobby Screen. */ @@ -243,6 +352,7 @@ public class ViewManager { /** * Sets up the view for the race. Creating a new decorator and destroying the old one. + * * @return A RaceViewController for the race view screen. */ @@ -267,15 +377,6 @@ public class ViewManager { scene.setOnKeyPressed(gameClient::keyPressed); scene.setOnKeyReleased(gameClient::keyReleased); - // uncomment to make it full screen -// Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds(); -// stage.setX(visualBounds.getMinX()); -// stage.setY(visualBounds.getMinY()); -// stage.setWidth(visualBounds.getWidth()); -// stage.setHeight(visualBounds.getHeight()); -// stage.setMaximized(true); -// stage.setFullScreen(true); - stage.setMinHeight(500); stage.setMinWidth(800); stage.setTitle("Party Parrots At Sea"); @@ -288,7 +389,7 @@ public class ViewManager { } }); - while (loader.getController() == null){ + while (loader.getController() == null) { try { Thread.sleep(50); } catch (InterruptedException e) { @@ -298,4 +399,9 @@ public class ViewManager { return loader.getController(); } + + public Stage getStage() { + return stage; + } + } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java new file mode 100644 index 00000000..c650bc59 --- /dev/null +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -0,0 +1,197 @@ +package seng302.visualiser.controllers.dialogs; + +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXToggleButton; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.input.KeyEvent; +import seng302.model.GameKeyBind; +import seng302.model.KeyAction; +import seng302.visualiser.GameClient; +import seng302.visualiser.controllers.ViewManager; + +public class KeyBindingDialogController implements Initializable { + + //--------FXML BEGIN--------// + @FXML + private Label keyBindingDialogHeader; + @FXML + private Label closeLabel; + @FXML + private JFXButton zoomInbtn; + @FXML + private JFXButton zoomOutBtn; + @FXML + private JFXButton vmgBtn; + @FXML + private JFXButton sailInOutBtn; + @FXML + private JFXButton tackGybeBtn; + @FXML + private JFXButton upwindBtn; + @FXML + private JFXButton downwindBtn; + @FXML + private JFXButton resetBtn; + @FXML + private Label upwindLabel; + @FXML + private Label downwindLabel; + @FXML + 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---------// + + private GameKeyBind gameKeyBind; + private List buttons = new ArrayList<>(); + private Map buttonActionMap; + private GameClient gameClient; // to send turning mode packet + + @Override + public void initialize(URL location, ResourceBundle resources) { + gameKeyBind = GameKeyBind.getInstance(); + buttons = new ArrayList<>(); + Collections.addAll(buttons, + zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn, + viewButton, + rightButton, leftButton, forwardButton, backwardButton); + bindButtonWithAction(); + loadKeyBind(); + + buttons.forEach(button -> { + button.setOnMouseEntered(event -> mouseEnter(button)); + button.setOnMousePressed(event -> buttonPressed(button)); + button.setOnMouseExited(event -> mouseExit(button)); + button.setOnKeyPressed(event -> keyPressed(event, button)); + }); + + turningToggle.setOnMouseClicked(event -> toggleTurningMode()); + + resetBtn.setOnMouseClicked(event -> { + gameKeyBind.setToDefault(); + loadKeyBind(); + }); + + closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog()); + + keyBindingDialogHeader.setFocusTraversable(true); + keyBindingDialogHeader.requestFocus(); + } + + /** + * Set buttons' label according to GameKeyBind settings + */ + private void loadKeyBind() { + buttons.forEach( + button -> button + .setText(gameKeyBind.getKeyCode(buttonActionMap.get(button)).getName())); + turningToggle.setSelected(gameKeyBind.isContinuouslyTurning()); + if (gameKeyBind.isContinuouslyTurning()) { + upwindLabel.setText("ClOCKWISE TURNING"); + downwindLabel.setText("ANTICLOCKWISE TURNING"); + } else { + upwindLabel.setText("UPWIND"); + downwindLabel.setText("DOWNWIND"); + } + } + + /** + * Bind buttons with specific action in a map. + */ + private void bindButtonWithAction() { + buttonActionMap = new HashMap<>(); + for (int i = 0; i < 12; i++) { + buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1)); + } + } + + /** + * Prompt success / failure message for reassigning key action + */ + private void showSnackBar(String message, Boolean isWarning) { + ViewManager.getInstance().showSnackbar(message, isWarning); + } + + /** + * When a mouse enters the button, the color and font size should change to highlight + * @param button + */ + private void mouseEnter(Button button) { + button.setStyle("" + + "-fx-background-color: -fx-pp-theme-color;" + + "-fx-text-fill: -fx-pp-front-color;" + + "-fx-font-size: 15;"); + } + + /** + * Prompt "press key..." to inform users assign a new key bind by pressing a key + * @param button + */ + private void buttonPressed(Button button) { + button.setText("PRESS KEY..."); + } + + + /** + * When mouse leaves the button, return the button to the normal state in terms of text, + * color and font size + * @param button + */ + private void mouseExit(Button button) { + button.setText(GameKeyBind.getInstance().getKeyCode(buttonActionMap.get(button)).getName()); + button.setStyle("" + + "-fx-background-color: -fx-pp-front-color; " + + "-fx-text-fill: -fx-pp-theme-color; " + + "-fx-font-size: 13;"); + } + + /** + * When a key is pressed, check if the new binding conflicts to any existed settings, if not + * assign the selected action with the new key binding to GameKeyBind. + * @param event + * @param button + */ + private void keyPressed(KeyEvent event, Button button) { + event.consume(); + KeyAction buttonAction = buttonActionMap.get(button); + if (gameKeyBind.bindKeyToAction(event.getCode(), buttonAction)) { + showSnackBar(button.getId() + " is set to " + event.getCode().getName(), false); + button.setText(gameKeyBind.getKeyCode(buttonAction).getName()); + } else { + loadKeyBind(); + showSnackBar(event.getCode().getName() + " is already in use", true); + } + } + + /** + * When the turning mode is toggled, update gameKeyBind and send out packet to notify the server + */ + private void toggleTurningMode() { + gameKeyBind.toggleTurningMode(); + gameClient.sendToggleTurningModePacket(); + loadKeyBind(); + } + + public void setGameClient(GameClient gameClient) { + this.gameClient = gameClient; + } + +} diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/PopupDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/PopupDialogController.java new file mode 100644 index 00000000..6d294e50 --- /dev/null +++ b/src/main/java/seng302/visualiser/controllers/dialogs/PopupDialogController.java @@ -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 eventHandler) { + this.optionButton.setOnMouseClicked(eventHandler); + } + + public void setPopupDialog(JFXDialog popupDialog) { + this.popupDialog = popupDialog; + this.closeLabel.setOnMouseClicked(event -> this.popupDialog.close()); + } +} diff --git a/src/main/resources/css/Master.css b/src/main/resources/css/Master.css index 8636a88a..478d7cf0 100644 --- a/src/main/resources/css/Master.css +++ b/src/main/resources/css/Master.css @@ -44,8 +44,18 @@ -fx-border-color: -fx-decorator-color; -fx-border-width: 0 4 4 4; } + +.jfx-decorator-button { + -fx-focus-traversable: false; /* so decorator button will not be focused */ +} + /********* customised scroll bar for scroll pane ***********/ +.scroll-pane { + -fx-focus-traversable: false; + -fx-border-style: none; +} + /* The main scrollbar **track** CSS class */ .scroll-bar:horizontal .track, .scroll-bar:vertical .track { @@ -99,4 +109,16 @@ .slider .track { -fx-background-color: -fx-pp-dark-text-color; +} + +.jfx-snackbar-content { + -fx-background-color: -fx-pp-front-color; + -fx-padding: 0 5 0 5; + -fx-spacing: 0 5 0 5; + -fx-font-size: 15; +} + +.jfx-snackbar-toast { + -fx-text-fill: -fx-pp-theme-color; + -fx-font-size: 15; } \ No newline at end of file diff --git a/src/main/resources/css/RaceView.css b/src/main/resources/css/RaceView.css index 11e8f285..f38216c8 100644 --- a/src/main/resources/css/RaceView.css +++ b/src/main/resources/css/RaceView.css @@ -48,6 +48,7 @@ GridPane .timer * { -fx-text-fill: -fx-pp-theme-color; -fx-font-size: 13px; -fx-pref-height: 35px; + -fx-focus-traversable: false; } #chatSend:hover { diff --git a/src/main/resources/css/StartScreenView.css b/src/main/resources/css/StartScreenView.css index 04338028..bffc296f 100644 --- a/src/main/resources/css/StartScreenView.css +++ b/src/main/resources/css/StartScreenView.css @@ -2,6 +2,7 @@ -fx-font-size: 20px; -fx-text-fill: -fx-pp-light-text-color; -fx-background-color: -fx-pp-theme-color; + -fx-focus-traversable: false; } .jfx-rippler { diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css new file mode 100644 index 00000000..6c7bff26 --- /dev/null +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -0,0 +1,59 @@ +#keyBindingDialogHeader { + -fx-font-size: 27px; + -fx-text-fill: -fx-pp-dark-text-color; +} + +#closeLabel { + -fx-font-size: 30; + -fx-text-fill: -fx-pp-dark-text-color; +} + +#closeLabel:hover { + -fx-text-fill: red; + -fx-font-size: 33px; +} + +.sectionLabel { + -fx-text-fill: -fx-pp-dark-text-color; + -fx-font-size: 20px; +} + +JFXButton { + -fx-background-color: -fx-pp-light-text-color; + -fx-text-fill: -fx-pp-theme-color; + -fx-font-size: 13px; +} + +Label { + -fx-font-size: 15px; + -fx-text-fill: -fx-pp-theme-color; + -fx-effect: -fx-pp-dropshadow-light; +} + +JFXToggleButton { + -jfx-toggle-color: -fx-pp-theme-color; + -fx-text-fill: -fx-pp-theme-color; +} + +#resetBtn { + -fx-background-color: -fx-pp-theme-color; + -fx-text-fill: -fx-pp-front-color; + -fx-effect: -fx-pp-dropshadow-light; + -fx-font-size: 18; +} + +#resetBtn:hover { + -fx-font-size: 20; +} + +.jfx-snackbar-content { + -fx-background-color: #323232; +} + +.jfx-snackbar-toast { + -fx-text-fill: WHITE; +} + +.jfx-snackbar-action { + -fx-text-fill: #ff4081; +} \ No newline at end of file diff --git a/src/main/resources/css/dialogs/Popup.css b/src/main/resources/css/dialogs/Popup.css new file mode 100644 index 00000000..d0dd364b --- /dev/null +++ b/src/main/resources/css/dialogs/Popup.css @@ -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; +} \ No newline at end of file diff --git a/src/main/resources/css/dialogs/Snackbar.css b/src/main/resources/css/dialogs/Snackbar.css new file mode 100644 index 00000000..0fbe23b2 --- /dev/null +++ b/src/main/resources/css/dialogs/Snackbar.css @@ -0,0 +1,4 @@ +/* a separate file to dynamically change snackbar's color */ +.jfx-snackbar-toast { + -fx-text-fill: red !important; +} \ No newline at end of file diff --git a/src/main/resources/views/RaceView.fxml b/src/main/resources/views/RaceView.fxml index a2c22e09..879b2f22 100644 --- a/src/main/resources/views/RaceView.fxml +++ b/src/main/resources/views/RaceView.fxml @@ -14,234 +14,232 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml new file mode 100644 index 00000000..7fcf2e7f --- /dev/null +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/views/dialogs/PopupDialog.fxml b/src/main/resources/views/dialogs/PopupDialog.fxml new file mode 100644 index 00000000..00574bc4 --- /dev/null +++ b/src/main/resources/views/dialogs/PopupDialog.fxml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +