From 027324cc4fa8e08f9af59aaf5d98c625ba230456 Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Tue, 19 Sep 2017 18:40:01 +1200 Subject: [PATCH 01/14] - Fixed JFXDialog initialised in lobby, raceview, serverlist controller by default. Now, dialog only appears when called. - [WIP] Created keybindingdialog fxml. CSS not yet done. - Removed top most anchorpane on raceview so parent is stackpane like other views. #story[1278] --- .../controllers/LobbyController.java | 12 +- .../controllers/RaceViewController.java | 46 +- .../controllers/ServerListController.java | 15 +- .../visualiser/controllers/ViewManager.java | 71 ++- .../css/dialogs/KeyBindingDialog.css | 0 src/main/resources/views/RaceView.fxml | 452 +++++++++--------- .../views/dialogs/KeyBindingDialog.fxml | 50 ++ 7 files changed, 380 insertions(+), 266 deletions(-) create mode 100644 src/main/resources/css/dialogs/KeyBindingDialog.css create mode 100644 src/main/resources/views/dialogs/KeyBindingDialog.fxml diff --git a/src/main/java/seng302/visualiser/controllers/LobbyController.java b/src/main/java/seng302/visualiser/controllers/LobbyController.java index bbb39f75..36089eca 100644 --- a/src/main/java/seng302/visualiser/controllers/LobbyController.java +++ b/src/main/java/seng302/visualiser/controllers/LobbyController.java @@ -90,16 +90,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 165d0c39..0fab0cdb 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -2,11 +2,17 @@ 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.events.JFXDialogEvent; import com.jfoenix.svg.SVGGlyph; +import com.sun.org.apache.xpath.internal.operations.Bool; import java.io.IOException; import java.util.HashMap; import javafx.application.Platform; import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; import javafx.fxml.FXMLLoader; import javafx.scene.Cursor; import javafx.scene.Node; @@ -14,7 +20,10 @@ import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.SceneAntialiasing; import javafx.scene.image.Image; +import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.Stage; import org.slf4j.Logger; @@ -32,11 +41,6 @@ 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 ViewManager() { @@ -119,6 +123,23 @@ public class ViewManager { //Get the button box HBox btns = (HBox) decorator.getChildren().get(0); + //Create settings button -- [WIP] + JFXButton btnSettings = new JFXButton(); + btnSettings.setText(" Key Bindings"); + btnSettings.setStyle("-fx-text-fill:#fff"); + btnSettings.getStyleClass().add("jfx-decorator-button"); + btnSettings.setCursor(Cursor.HAND); + + btnSettings.setOnMouseClicked(event -> Platform.runLater(() -> { + try { + if (!checkDialogOpened(decorator.getChildren())) { + showKeyBindingDialog(); + } + } catch (IOException e) { + logger.warn("Could not create Key Binding Dialog."); + } + })); + //Create new button JFXButton btnMute = new JFXButton(); btnMute.setText(" Toggle Sound"); @@ -134,9 +155,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", + "M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z", + Color.WHITE); volumeOn.setSize(16, 16); volumeOff.setSize(16, 16); spacer.setSize(40, 16); + keyBindingGlyph.setSize(16,16); // Determine which graphic should go on the button if (Sounds.isMusicMuted() && Sounds.isSoundEffectsMuted()) { @@ -145,9 +170,12 @@ public class ViewManager { btnMute.setGraphic(volumeOn); } + btnSettings.setGraphic(keyBindingGlyph); + // Add Buttons btns.getChildren().add(0, spacer); btns.getChildren().add(0, btnMute); + btns.getChildren().add(0, btnSettings); btnMute.setOnAction((action) -> { Sounds.toggleAllSounds(); if (btnMute.getGraphic().equals(volumeOff)) { @@ -159,6 +187,31 @@ public class ViewManager { } + private Boolean checkDialogOpened(ObservableList nodes) { + for (Node node : nodes) { + if (node instanceof JFXDialog) { + return true; + } else if (node instanceof StackPane) { + return checkDialogOpened(((StackPane) node).getChildren()); + } + } + return false; + } + + private void showKeyBindingDialog() throws IOException { + FXMLLoader dialogContent = new FXMLLoader(getClass().getResource( + "/views/dialogs/KeyBindingDialog.fxml")); + for (Node node : decorator.getChildren()) { + if (node instanceof StackPane) { + JFXDialog dialog = new JFXDialog((StackPane) node, + dialogContent.load(), + DialogTransition.CENTER); + dialog.show(); + Sounds.playButtonClick(); + } + } + } + /** * Determines if a PC has compatibility with the bonjour protocol for server detection. */ @@ -221,6 +274,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 +297,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. */ @@ -286,7 +341,7 @@ public class ViewManager { } }); - while (loader.getController() == null){ + while (loader.getController() == null) { try { Thread.sleep(50); } catch (InterruptedException e) { @@ -296,4 +351,8 @@ public class ViewManager { return loader.getController(); } + + public Stage getStage() { + return stage; + } } diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/views/RaceView.fxml b/src/main/resources/views/RaceView.fxml index fba9bb27..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..34340b05 --- /dev/null +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 03f5f91043bd067a6218d62a4125927200482583 Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Tue, 19 Sep 2017 19:49:36 +1200 Subject: [PATCH 02/14] Done some CSS on keybindingdialog #story[1278] --- .../css/dialogs/KeyBindingDialog.css | 28 ++++++++++ .../views/dialogs/KeyBindingDialog.fxml | 52 +++++++++++++------ 2 files changed, 65 insertions(+), 15 deletions(-) diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css index e69de29b..e5cdc773 100644 --- a/src/main/resources/css/dialogs/KeyBindingDialog.css +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -0,0 +1,28 @@ +#keyBindingDialogHeader { + -fx-font-size: 30px; + -fx-text-fill: -fx-pp-dark-text-color; +} + +JFXButton { + -fx-background-color: -fx-pp-light-text-color; + -fx-text-fill: -fx-pp-theme-color; + -fx-font-size: 17px; + -fx-effect: -fx-pp-dropshadow-dark; +} + +Label { + -fx-font-size: 25px; + -fx-text-fill: -fx-pp-theme-color; + /*-fx-effect: -fx-pp-dropshadow-dark;*/ +} + +JFXButton:hover { + -fx-font-size: 20px; + -fx-background-color: -fx-pp-light-theme-color; +} + +JFXButton:focused { + -fx-font-size: 20px; + -fx-background-color: -fx-pp-theme-color; + -fx-text-fill: -fx-pp-light-text-color; +} \ No newline at end of file diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index 34340b05..fec643fb 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -1,5 +1,6 @@ + @@ -25,21 +26,42 @@ - From 8084a613333f46eb403a665500e828aeb62adf21 Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Tue, 19 Sep 2017 23:41:06 +1200 Subject: [PATCH 03/14] Fix keybinding dialog creating on top of another keybinding dialog. #story[1278] --- .../visualiser/controllers/ViewManager.java | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 0fab0cdb..1388eba9 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -4,25 +4,13 @@ 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.events.JFXDialogEvent; import com.jfoenix.svg.SVGGlyph; -import com.sun.org.apache.xpath.internal.operations.Bool; -import java.io.IOException; -import java.util.HashMap; import javafx.application.Platform; import javafx.collections.ObservableList; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; import javafx.fxml.FXMLLoader; -import javafx.scene.Cursor; -import javafx.scene.Node; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.scene.SceneAntialiasing; +import javafx.scene.*; import javafx.scene.image.Image; -import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.stage.Stage; @@ -33,6 +21,9 @@ import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; +import java.io.IOException; +import java.util.HashMap; + public class ViewManager { private static ViewManager instance; @@ -187,15 +178,22 @@ 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) { - return checkDialogOpened(((StackPane) node).getChildren()); + foundJFXDialog = checkDialogOpened(((StackPane) node).getChildren()); } } - return false; + return foundJFXDialog; } private void showKeyBindingDialog() throws IOException { From a1933c2869403e50a21dc65b4387ca58c6f14dfd Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Wed, 20 Sep 2017 02:42:02 +1200 Subject: [PATCH 04/14] - Created keybindingcontroller which can detect keypress and can save the keybind throughout the app - Changed keybindingglyph to keyboard icon - Fix button hover CSS to change text fill #story[1278] --- .../visualiser/controllers/ViewManager.java | 15 ++- .../dialogs/KeyBindingDialogController.java | 115 ++++++++++++++++++ .../css/dialogs/KeyBindingDialog.css | 1 + .../views/dialogs/KeyBindingDialog.fxml | 19 +-- 4 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 1388eba9..ef1df0bd 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -5,10 +5,16 @@ import com.jfoenix.controls.JFXDecorator; import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialog.DialogTransition; import com.jfoenix.svg.SVGGlyph; +import java.io.IOException; +import java.util.HashMap; import javafx.application.Platform; import javafx.collections.ObservableList; import javafx.fxml.FXMLLoader; -import javafx.scene.*; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.SceneAntialiasing; import javafx.scene.image.Image; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; @@ -21,9 +27,6 @@ import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; -import java.io.IOException; -import java.util.HashMap; - public class ViewManager { private static ViewManager instance; @@ -147,12 +150,12 @@ public class ViewManager { "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", - "M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z", + "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(16,16); + keyBindingGlyph.setSize(24, 16); // Determine which graphic should go on the button if (Sounds.isMusicMuted() && Sounds.isSoundEffectsMuted()) { 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..4c1a8b6d --- /dev/null +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -0,0 +1,115 @@ +package seng302.visualiser.controllers.dialogs; + +import com.jfoenix.controls.JFXButton; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.Label; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; + +import java.net.URL; +import java.util.*; + +public class KeyBindingDialogController implements Initializable { + + //--------FXML BEGIN--------// + @FXML + private Label keyBindingDialogHeader; + @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 END---------// + + private static Map keys; // static button and saved keybinding pair + private List buttons = new ArrayList<>(); + + @Override + public void initialize(URL location, ResourceBundle resources) { + buttons = new ArrayList<>(); + Collections + .addAll(buttons, zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, + downwindBtn); + + initializeKeys(); + initializeButtons(); + } + + /** + * Initialise default button-keybinding pair if not exist, else rebind the existing keybinding + * to the new button which is created when javafx reinitialise a new controller. + */ + private void initializeKeys() { + if (keys == null) { + initializeDefaultKeys(); + } else { + Map tempKey = new LinkedHashMap<>(); + int buttonIndex = 0; + for (JFXButton jfxButton : keys.keySet()) { + tempKey.put(buttons.get(buttonIndex), keys.get(jfxButton)); + buttonIndex++; + } + keys = tempKey; + } + } + + /** + * Initialise default keybinding to a button. + */ + private void initializeDefaultKeys() { + keys = new LinkedHashMap<>(); + keys.put(zoomInbtn, KeyCode.Z); + keys.put(zoomOutBtn, KeyCode.X); + keys.put(vmgBtn, KeyCode.SPACE); + keys.put(sailInOutBtn, KeyCode.SHIFT); + keys.put(tackGybeBtn, KeyCode.ENTER); + keys.put(upwindBtn, KeyCode.PAGE_UP); + keys.put(downwindBtn, KeyCode.PAGE_DOWN); + } + + /** + * Change button text to match current keybinding. Adds focusedProperty and keyPressed listener + * to each buttons. + */ + private void initializeButtons() { + for (JFXButton jfxButton : buttons) { + if (keys.get(jfxButton) != null) { + jfxButton.setText(keys.get(jfxButton).getName()); + } else { + jfxButton.setText(""); + } + jfxButton.focusedProperty().addListener((observable, oldValue, newValue) -> { + jfxButton.setOnKeyPressed(event -> { + event.consume(); + doSomething(event, jfxButton); + }); + }); + } + } + + /** + * HAOMING PLEASE CHANGE THIS DOCSTRING AND THE FUNCTION NAME!!! + * + * @param event BLAH + * @param button BLAH + */ + private void doSomething(KeyEvent event, JFXButton button) { + if (keys.containsValue(event.getCode())) { + keys.replace(button, null); + button.setText(""); + } else { + keys.replace(button, event.getCode()); + button.setText(event.getCode().getName()); + } + } +} diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css index e5cdc773..33a239d3 100644 --- a/src/main/resources/css/dialogs/KeyBindingDialog.css +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -19,6 +19,7 @@ Label { JFXButton:hover { -fx-font-size: 20px; -fx-background-color: -fx-pp-light-theme-color; + -fx-text-fill: -fx-pp-light-text-color; } JFXButton:focused { diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index fec643fb..55a4c44f 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -1,13 +1,18 @@ - - - - - - + + + + + + + + - + From d4d7ddf8e267f1b9dc58fb33526b98ff2b5d4f65 Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Wed, 20 Sep 2017 11:02:13 +1200 Subject: [PATCH 05/14] Keybinding now works in the actual race. A map of keybind is shared between GameClient and KeyBindDialogController. #story[1278] --- .../java/seng302/model/GameClientAction.java | 35 +++++++++++ .../java/seng302/visualiser/GameClient.java | 58 +++++++++++------ .../visualiser/controllers/ViewManager.java | 4 ++ .../dialogs/KeyBindingDialogController.java | 62 +++++++++++++------ 4 files changed, 121 insertions(+), 38 deletions(-) create mode 100644 src/main/java/seng302/model/GameClientAction.java diff --git a/src/main/java/seng302/model/GameClientAction.java b/src/main/java/seng302/model/GameClientAction.java new file mode 100644 index 00000000..21848e74 --- /dev/null +++ b/src/main/java/seng302/model/GameClientAction.java @@ -0,0 +1,35 @@ +package seng302.model; + +import java.util.HashMap; +import java.util.Map; + +public enum GameClientAction { + ZOOM_IN(1), + ZOOM_OUT(2), + VMG(3), + SAILS_STATE(4), + TACK_GYBE(5), + UPWIND(6), + DOWNWIND(7); + + private final int type; + private static final Map intToTypeMap = new HashMap<>(); + + static { + for (GameClientAction type : GameClientAction.values()) { + intToTypeMap.put(type.getValue(), type); + } + } + + GameClientAction(int type) { + this.type = type; + } + + public static GameClientAction getType(int value) { + return intToTypeMap.get(value); + } + + public int getValue() { + return this.type; + } +} diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index 7040d7ee..9019b53e 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -7,6 +7,7 @@ import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TimeZone; @@ -28,6 +29,7 @@ import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.BoatStatus; import seng302.gameServer.messages.YachtEventType; import seng302.model.ClientYacht; +import seng302.model.GameClientAction; import seng302.model.RaceState; import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.parser.MarkRoundingData; @@ -65,6 +67,7 @@ public class GameClient { private RaceViewController raceViewController; private ArrayList finishedBoats = new ArrayList<>(); + private Map keyBind = new HashMap<>(); private ObservableList clientLobbyList = FXCollections.observableArrayList(); @@ -75,6 +78,21 @@ public class GameClient { */ public GameClient(Pane holder) { this.holderPane = holder; + initialiseKeyBind(); + } + + /** + * Initialise default keybind. + */ + private void initialiseKeyBind() { + keyBind = new HashMap<>(); + keyBind.put(GameClientAction.ZOOM_IN, KeyCode.Z); + keyBind.put(GameClientAction.ZOOM_OUT, KeyCode.X); + keyBind.put(GameClientAction.VMG, KeyCode.SPACE); + keyBind.put(GameClientAction.SAILS_STATE, KeyCode.SHIFT); + keyBind.put(GameClientAction.TACK_GYBE, KeyCode.ENTER); + keyBind.put(GameClientAction.UPWIND, KeyCode.PAGE_UP); + keyBind.put(GameClientAction.DOWNWIND, KeyCode.PAGE_DOWN); } /** @@ -373,16 +391,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 (keyBind.get(GameClientAction.VMG) == e.getCode()) { // align with vmg + socketThread.sendBoatAction(BoatAction.VMG); + } else if (keyBind.get(GameClientAction.UPWIND) == e.getCode()) { // upwind + socketThread.sendBoatAction(BoatAction.UPWIND); + } else if (keyBind.get(GameClientAction.DOWNWIND) == e.getCode()) { // downwind + socketThread.sendBoatAction(BoatAction.DOWNWIND); + } else if (keyBind.get(GameClientAction.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 +409,13 @@ 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 - socketThread.sendBoatAction(BoatAction.SAILS_IN); - allBoatsMap.get(socketThread.getClientId()).toggleSail(); - break; - case PAGE_UP: - case PAGE_DOWN: - socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break; + + if (keyBind.get(GameClientAction.SAILS_STATE) == e.getCode()) { // sails in/sails out + socketThread.sendBoatAction(BoatAction.SAILS_IN); + allBoatsMap.get(socketThread.getClientId()).toggleSail(); + } else if (keyBind.get(GameClientAction.UPWIND) == e.getCode() + || keyBind.get(GameClientAction.DOWNWIND) == e.getCode()) { + socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); } } @@ -456,4 +472,8 @@ public class GameClient { public Map getAllBoatsMap() { return allBoatsMap; } + + public Map getKeyBind() { + return keyBind; + } } diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index ef1df0bd..d47da171 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -26,6 +26,7 @@ import seng302.gameServer.ServerAdvertiser; import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; +import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; public class ViewManager { @@ -207,6 +208,9 @@ public class ViewManager { JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(), DialogTransition.CENTER); + KeyBindingDialogController keyBindingDialogController = dialogContent + .getController(); + keyBindingDialogController.init(gameClient.getKeyBind()); dialog.show(); Sounds.playButtonClick(); } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java index 4c1a8b6d..114b2f74 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -9,6 +9,7 @@ import javafx.scene.input.KeyEvent; import java.net.URL; import java.util.*; +import seng302.model.GameClientAction; public class KeyBindingDialogController implements Initializable { @@ -31,11 +32,25 @@ public class KeyBindingDialogController implements Initializable { private JFXButton downwindBtn; //---------FXML END---------// - private static Map keys; // static button and saved keybinding pair + private Map keys; private List buttons = new ArrayList<>(); + private Map keyBind; + private LinkedHashMap buttonAndGameClientActionMap; @Override public void initialize(URL location, ResourceBundle resources) { + } + + /** + * HAOMING HELP!!! CHANGE FUNCTION NAME PLS :)) + * + * Takes in a map from GameClient and initialise button mapping to the keys. + * + * @param keyBind a map with GameClientAction and KeyCode pair to be used in GameClient. + */ + public void init(Map keyBind) { + this.keyBind = keyBind; + buttons = new ArrayList<>(); Collections .addAll(buttons, zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, @@ -50,17 +65,24 @@ public class KeyBindingDialogController implements Initializable { * to the new button which is created when javafx reinitialise a new controller. */ private void initializeKeys() { - if (keys == null) { - initializeDefaultKeys(); - } else { - Map tempKey = new LinkedHashMap<>(); - int buttonIndex = 0; - for (JFXButton jfxButton : keys.keySet()) { - tempKey.put(buttons.get(buttonIndex), keys.get(jfxButton)); - buttonIndex++; - } - keys = tempKey; - } + initButtonAndGameClientActionMap(); + initializeDefaultKeys(); + } + + /** + * HAOMING CHANGE FUNCTION NAME HERE TOO :) OR BETTER, REMOVE THIS FUNCTION + * + * Link buttons and the GameClientAction to be used in accessing keys. + */ + private void initButtonAndGameClientActionMap() { + buttonAndGameClientActionMap = new LinkedHashMap<>(); + buttonAndGameClientActionMap.put(zoomInbtn, GameClientAction.ZOOM_IN); + buttonAndGameClientActionMap.put(zoomOutBtn, GameClientAction.ZOOM_OUT); + buttonAndGameClientActionMap.put(vmgBtn, GameClientAction.VMG); + buttonAndGameClientActionMap.put(sailInOutBtn, GameClientAction.SAILS_STATE); + buttonAndGameClientActionMap.put(tackGybeBtn, GameClientAction.TACK_GYBE); + buttonAndGameClientActionMap.put(upwindBtn, GameClientAction.UPWIND); + buttonAndGameClientActionMap.put(downwindBtn, GameClientAction.DOWNWIND); } /** @@ -68,13 +90,13 @@ public class KeyBindingDialogController implements Initializable { */ private void initializeDefaultKeys() { keys = new LinkedHashMap<>(); - keys.put(zoomInbtn, KeyCode.Z); - keys.put(zoomOutBtn, KeyCode.X); - keys.put(vmgBtn, KeyCode.SPACE); - keys.put(sailInOutBtn, KeyCode.SHIFT); - keys.put(tackGybeBtn, KeyCode.ENTER); - keys.put(upwindBtn, KeyCode.PAGE_UP); - keys.put(downwindBtn, KeyCode.PAGE_DOWN); + keys.put(zoomInbtn, keyBind.get(GameClientAction.ZOOM_IN)); + keys.put(zoomOutBtn, keyBind.get(GameClientAction.ZOOM_OUT)); + keys.put(vmgBtn, keyBind.get(GameClientAction.VMG)); + keys.put(sailInOutBtn, keyBind.get(GameClientAction.SAILS_STATE)); + keys.put(tackGybeBtn, keyBind.get(GameClientAction.TACK_GYBE)); + keys.put(upwindBtn, keyBind.get(GameClientAction.UPWIND)); + keys.put(downwindBtn, keyBind.get(GameClientAction.DOWNWIND)); } /** @@ -106,9 +128,11 @@ public class KeyBindingDialogController implements Initializable { private void doSomething(KeyEvent event, JFXButton button) { if (keys.containsValue(event.getCode())) { keys.replace(button, null); + keyBind.replace(buttonAndGameClientActionMap.get(button), null); button.setText(""); } else { keys.replace(button, event.getCode()); + keyBind.replace(buttonAndGameClientActionMap.get(button), event.getCode()); button.setText(event.getCode().getName()); } } From c20c6fb264ff8e3d12f8fdc7b0cff15fe702d23c Mon Sep 17 00:00:00 2001 From: Haoming Yin Date: Fri, 22 Sep 2017 13:53:36 +1200 Subject: [PATCH 06/14] [WIP] Added new toggle for steer turning mode and submit and reset button (restore the setting to default) - minor fix of UI elements to make the font smaller - centred labels and buttons tags: #story[1246] --- .../css/dialogs/KeyBindingDialog.css | 23 +++-- .../views/dialogs/KeyBindingDialog.fxml | 97 ++++++++++++++----- 2 files changed, 88 insertions(+), 32 deletions(-) diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css index 33a239d3..6f85fd91 100644 --- a/src/main/resources/css/dialogs/KeyBindingDialog.css +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -6,24 +6,35 @@ JFXButton { -fx-background-color: -fx-pp-light-text-color; -fx-text-fill: -fx-pp-theme-color; - -fx-font-size: 17px; - -fx-effect: -fx-pp-dropshadow-dark; + -fx-font-size: 15px; + -fx-effect: -fx-pp-dropshadow-light; } Label { - -fx-font-size: 25px; + -fx-font-size: 20px; -fx-text-fill: -fx-pp-theme-color; - /*-fx-effect: -fx-pp-dropshadow-dark;*/ + -fx-effect: -fx-pp-dropshadow-light; } JFXButton:hover { - -fx-font-size: 20px; + -fx-font-size: 18px; -fx-background-color: -fx-pp-light-theme-color; -fx-text-fill: -fx-pp-light-text-color; } JFXButton:focused { - -fx-font-size: 20px; + -fx-font-size: 18px; -fx-background-color: -fx-pp-theme-color; -fx-text-fill: -fx-pp-light-text-color; +} + +JFXToggleButton { + -jfx-toggle-color: -fx-pp-theme-color; + -fx-text-fill: -fx-pp-theme-color; +} + +#resetBtn, #confirmBtn { + -fx-background-color: -fx-pp-theme-color; + -fx-text-fill: -fx-pp-front-color; + -fx-effect: -fx-pp-dropshadow-light; } \ No newline at end of file diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index 55a4c44f..29eaa1b3 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -2,25 +2,25 @@ + - - - + + - + @@ -29,44 +29,89 @@ + From 957821f1f2d272b0ab19c052ccee733c6a06c0cb Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Sat, 23 Sep 2017 01:39:26 +1200 Subject: [PATCH 07/14] [WIP] Created a snackbar for notification. Currently used for keybinding success/fail. Need to show red if fails. #story[1278] --- .../visualiser/controllers/ViewManager.java | 26 ++++++++++++++++++- .../dialogs/KeyBindingDialogController.java | 22 +++++++++++++--- src/main/resources/css/Master.css | 15 +++++++++++ .../views/dialogs/KeyBindingDialog.fxml | 25 +++++++++--------- 4 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 60e181ae..13fcdd3f 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -4,6 +4,7 @@ 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; @@ -37,6 +38,7 @@ public class ViewManager { private ObservableList playerList; private Logger logger = LoggerFactory.getLogger(ViewManager.class); private Stage stage; + private JFXSnackbar jfxSnackbar; private ViewManager() { properties = new HashMap<>(); @@ -98,6 +100,10 @@ public class ViewManager { gameClient.stopGame(); System.exit(0); }); + + jfxSnackbar = new JFXSnackbar(); + decorator.getChildren().add(jfxSnackbar); + jfxSnackbar.registerSnackbarContainer(decorator); } /** @@ -210,13 +216,22 @@ public class ViewManager { DialogTransition.CENTER); KeyBindingDialogController keyBindingDialogController = dialogContent .getController(); - keyBindingDialogController.init(gameClient.getKeyBind()); + keyBindingDialogController.init(gameClient.getKeyBind(), this); dialog.show(); Sounds.playButtonClick(); } } } + /** + * Show a snackbar at the bottom of the app for 1 second. + * + * @param snackbarText text to be displayed. + */ + public void showSnackbar(String snackbarText) { + jfxSnackbar.show(snackbarText, 1000); + } + /** * Determines if a PC has compatibility with the bonjour protocol for server detection. */ @@ -362,4 +377,13 @@ public class ViewManager { public Stage getStage() { return stage; } + + /** + * Getter to return snackbar object. + * + * @return snackbar object. + */ + public JFXSnackbar getJfxSnackbar() { + return jfxSnackbar; + } } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java index 114b2f74..62be7b1f 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -1,20 +1,28 @@ package seng302.visualiser.controllers.dialogs; import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXDialogLayout; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Label; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; - -import java.net.URL; -import java.util.*; import seng302.model.GameClientAction; +import seng302.visualiser.controllers.ViewManager; public class KeyBindingDialogController implements Initializable { //--------FXML BEGIN--------// @FXML + private JFXDialogLayout keyBindDialog; + @FXML private Label keyBindingDialogHeader; @FXML private JFXButton zoomInbtn; @@ -32,6 +40,8 @@ public class KeyBindingDialogController implements Initializable { private JFXButton downwindBtn; //---------FXML END---------// + private ViewManager viewManager; // added viewManager to access snackbar. To be removed. + private Map keys; private List buttons = new ArrayList<>(); private Map keyBind; @@ -48,8 +58,9 @@ public class KeyBindingDialogController implements Initializable { * * @param keyBind a map with GameClientAction and KeyCode pair to be used in GameClient. */ - public void init(Map keyBind) { + public void init(Map keyBind, ViewManager viewManager) { this.keyBind = keyBind; + this.viewManager = viewManager; buttons = new ArrayList<>(); Collections @@ -130,10 +141,13 @@ public class KeyBindingDialogController implements Initializable { keys.replace(button, null); keyBind.replace(buttonAndGameClientActionMap.get(button), null); button.setText(""); + viewManager + .showSnackbar(button.getId() + " can't be set to " + event.getCode().getName()); } else { keys.replace(button, event.getCode()); keyBind.replace(buttonAndGameClientActionMap.get(button), event.getCode()); button.setText(event.getCode().getName()); + viewManager.showSnackbar(button.getId() + " is set to " + event.getCode().getName()); } } } diff --git a/src/main/resources/css/Master.css b/src/main/resources/css/Master.css index 8636a88a..c1d97ddd 100644 --- a/src/main/resources/css/Master.css +++ b/src/main/resources/css/Master.css @@ -99,4 +99,19 @@ .slider .track { -fx-background-color: -fx-pp-dark-text-color; +} + +.jfx-snackbar-content { + -fx-background-color: WHITE; + -fx-padding: 0 5 0 5; + -fx-spacing: 0 5 0 5; + -fx-font-size: 18px; +} + +.jfx-snackbar-toast { + -fx-text-fill: -fx-pp-theme-color; +} + +.jfx-snackbar-action { + -fx-text-fill: #ff4081; } \ No newline at end of file diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index 29eaa1b3..f22f17dc 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -9,9 +9,10 @@ - @@ -68,31 +69,31 @@ - - - - - - - From 4011295b8b97c658f9e8c3886e08c804eb3775cb Mon Sep 17 00:00:00 2001 From: Haoming Yin Date: Sat, 23 Sep 2017 17:52:48 +1200 Subject: [PATCH 08/14] Slightly optimised code style and add more functionality - optimised UI - check conflicts when change key bind if the key has already been in use - abstract keybind as a separate singleton class so all class can access it - [WIP] turning mode is need to be finished #story[1245] --- src/main/java/seng302/model/GameKeyBind.java | 78 +++++++++ .../{GameClientAction.java => KeyAction.java} | 10 +- .../java/seng302/visualiser/GameClient.java | 40 ++--- .../visualiser/controllers/ViewManager.java | 16 +- .../dialogs/KeyBindingDialogController.java | 163 ++++++++---------- .../css/dialogs/KeyBindingDialog.css | 26 +-- .../views/dialogs/KeyBindingDialog.fxml | 55 +++--- 7 files changed, 200 insertions(+), 188 deletions(-) create mode 100644 src/main/java/seng302/model/GameKeyBind.java rename src/main/java/seng302/model/{GameClientAction.java => KeyAction.java} (61%) diff --git a/src/main/java/seng302/model/GameKeyBind.java b/src/main/java/seng302/model/GameKeyBind.java new file mode 100644 index 00000000..e400e6b5 --- /dev/null +++ b/src/main/java/seng302/model/GameKeyBind.java @@ -0,0 +1,78 @@ +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); + for (int i = 0; i < 7; 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/GameClientAction.java b/src/main/java/seng302/model/KeyAction.java similarity index 61% rename from src/main/java/seng302/model/GameClientAction.java rename to src/main/java/seng302/model/KeyAction.java index 21848e74..1b8c2fa1 100644 --- a/src/main/java/seng302/model/GameClientAction.java +++ b/src/main/java/seng302/model/KeyAction.java @@ -3,7 +3,7 @@ package seng302.model; import java.util.HashMap; import java.util.Map; -public enum GameClientAction { +public enum KeyAction { ZOOM_IN(1), ZOOM_OUT(2), VMG(3), @@ -13,19 +13,19 @@ public enum GameClientAction { DOWNWIND(7); private final int type; - private static final Map intToTypeMap = new HashMap<>(); + private static final Map intToTypeMap = new HashMap<>(); static { - for (GameClientAction type : GameClientAction.values()) { + for (KeyAction type : KeyAction.values()) { intToTypeMap.put(type.getValue(), type); } } - GameClientAction(int type) { + KeyAction(int type) { this.type = type; } - public static GameClientAction getType(int value) { + public static KeyAction getType(int value) { return intToTypeMap.get(value); } diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index 9019b53e..d6227d98 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -7,7 +7,6 @@ import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collections; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TimeZone; @@ -29,7 +28,8 @@ import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.BoatStatus; import seng302.gameServer.messages.YachtEventType; import seng302.model.ClientYacht; -import seng302.model.GameClientAction; +import seng302.model.GameKeyBind; +import seng302.model.KeyAction; import seng302.model.RaceState; import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.parser.MarkRoundingData; @@ -67,7 +67,8 @@ public class GameClient { private RaceViewController raceViewController; private ArrayList finishedBoats = new ArrayList<>(); - private Map keyBind = new HashMap<>(); + + private GameKeyBind gameKeyBind; // all the key binding setting. private ObservableList clientLobbyList = FXCollections.observableArrayList(); @@ -78,21 +79,7 @@ public class GameClient { */ public GameClient(Pane holder) { this.holderPane = holder; - initialiseKeyBind(); - } - - /** - * Initialise default keybind. - */ - private void initialiseKeyBind() { - keyBind = new HashMap<>(); - keyBind.put(GameClientAction.ZOOM_IN, KeyCode.Z); - keyBind.put(GameClientAction.ZOOM_OUT, KeyCode.X); - keyBind.put(GameClientAction.VMG, KeyCode.SPACE); - keyBind.put(GameClientAction.SAILS_STATE, KeyCode.SHIFT); - keyBind.put(GameClientAction.TACK_GYBE, KeyCode.ENTER); - keyBind.put(GameClientAction.UPWIND, KeyCode.PAGE_UP); - keyBind.put(GameClientAction.DOWNWIND, KeyCode.PAGE_DOWN); + this.gameKeyBind = GameKeyBind.getInstance(); } /** @@ -392,13 +379,13 @@ public class GameClient { return; } - if (keyBind.get(GameClientAction.VMG) == e.getCode()) { // align with vmg + if (gameKeyBind.getKeyCode(KeyAction.VMG) == e.getCode()) { // align with vmg socketThread.sendBoatAction(BoatAction.VMG); - } else if (keyBind.get(GameClientAction.UPWIND) == e.getCode()) { // upwind + } else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode()) { // upwind socketThread.sendBoatAction(BoatAction.UPWIND); - } else if (keyBind.get(GameClientAction.DOWNWIND) == e.getCode()) { // downwind + } else if (gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { // downwind socketThread.sendBoatAction(BoatAction.DOWNWIND); - } else if (keyBind.get(GameClientAction.TACK_GYBE) == e.getCode()) { // tack/gybe + } 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); } @@ -410,11 +397,11 @@ public class GameClient { return; } - if (keyBind.get(GameClientAction.SAILS_STATE) == e.getCode()) { // sails in/sails out + if (gameKeyBind.getKeyCode(KeyAction.SAILS_STATE) == e.getCode()) { // sails in/sails out socketThread.sendBoatAction(BoatAction.SAILS_IN); allBoatsMap.get(socketThread.getClientId()).toggleSail(); - } else if (keyBind.get(GameClientAction.UPWIND) == e.getCode() - || keyBind.get(GameClientAction.DOWNWIND) == e.getCode()) { + } else if (gameKeyBind.getKeyCode(KeyAction.UPWIND) == e.getCode() + || gameKeyBind.getKeyCode(KeyAction.DOWNWIND) == e.getCode()) { socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); } } @@ -473,7 +460,4 @@ public class GameClient { return allBoatsMap; } - public Map getKeyBind() { - return keyBind; - } } diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 13fcdd3f..49f76953 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -27,7 +27,6 @@ import seng302.gameServer.ServerAdvertiser; import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; -import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; public class ViewManager { @@ -137,7 +136,7 @@ public class ViewManager { showKeyBindingDialog(); } } catch (IOException e) { - logger.warn("Could not create Key Binding Dialog."); + logger.warn("Something went wrong when opening key bind dialog"); } })); @@ -214,9 +213,6 @@ public class ViewManager { JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(), DialogTransition.CENTER); - KeyBindingDialogController keyBindingDialogController = dialogContent - .getController(); - keyBindingDialogController.init(gameClient.getKeyBind(), this); dialog.show(); Sounds.playButtonClick(); } @@ -229,7 +225,7 @@ public class ViewManager { * @param snackbarText text to be displayed. */ public void showSnackbar(String snackbarText) { - jfxSnackbar.show(snackbarText, 1000); + jfxSnackbar.show(snackbarText, 1500); } /** @@ -378,12 +374,4 @@ public class ViewManager { return stage; } - /** - * Getter to return snackbar object. - * - * @return snackbar object. - */ - public JFXSnackbar getJfxSnackbar() { - return jfxSnackbar; - } } diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java index 62be7b1f..8621fd5b 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -2,19 +2,21 @@ package seng302.visualiser.controllers.dialogs; import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXDialogLayout; +import com.jfoenix.controls.JFXToggleButton; import java.net.URL; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedHashMap; +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.KeyCode; import javafx.scene.input.KeyEvent; -import seng302.model.GameClientAction; +import seng302.model.GameKeyBind; +import seng302.model.KeyAction; import seng302.visualiser.controllers.ViewManager; public class KeyBindingDialogController implements Initializable { @@ -38,116 +40,87 @@ public class KeyBindingDialogController implements Initializable { private JFXButton upwindBtn; @FXML private JFXButton downwindBtn; + @FXML + private JFXButton resetBtn; + @FXML + private JFXButton confirmBtn; + @FXML + private JFXToggleButton turningToggle; //---------FXML END---------// - private ViewManager viewManager; // added viewManager to access snackbar. To be removed. - - private Map keys; + private GameKeyBind gameKeyBind; private List buttons = new ArrayList<>(); - private Map keyBind; - private LinkedHashMap buttonAndGameClientActionMap; + private Map buttonActionMap; @Override public void initialize(URL location, ResourceBundle resources) { - } - - /** - * HAOMING HELP!!! CHANGE FUNCTION NAME PLS :)) - * - * Takes in a map from GameClient and initialise button mapping to the keys. - * - * @param keyBind a map with GameClientAction and KeyCode pair to be used in GameClient. - */ - public void init(Map keyBind, ViewManager viewManager) { - this.keyBind = keyBind; - this.viewManager = viewManager; - + gameKeyBind = GameKeyBind.getInstance(); buttons = new ArrayList<>(); - Collections - .addAll(buttons, zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, - downwindBtn); + Collections.addAll(buttons, + zoomInbtn, zoomOutBtn, vmgBtn, sailInOutBtn, tackGybeBtn, upwindBtn, downwindBtn); + bindButtonWithAction(); + loadKeyBind(); - initializeKeys(); - initializeButtons(); + buttons.forEach(button -> { + button.setOnMouseEntered(event -> mouseEnter(button)); + button.setOnMousePressed(event -> buttonPressed(button)); + button.setOnMouseExited(event -> mouseExit(button)); + button.setOnKeyPressed(event -> keyPressed(event, button)); + }); + + resetBtn.setOnMouseClicked(event -> { + gameKeyBind.setToDefault(); + loadKeyBind(); + }); } /** - * Initialise default button-keybinding pair if not exist, else rebind the existing keybinding - * to the new button which is created when javafx reinitialise a new controller. + * Set buttons' label according to GameKeyBind settings */ - private void initializeKeys() { - initButtonAndGameClientActionMap(); - initializeDefaultKeys(); + private void loadKeyBind() { + buttons.forEach( + button -> button + .setText(gameKeyBind.getKeyCode(buttonActionMap.get(button)).getName())); } - /** - * HAOMING CHANGE FUNCTION NAME HERE TOO :) OR BETTER, REMOVE THIS FUNCTION - * - * Link buttons and the GameClientAction to be used in accessing keys. - */ - private void initButtonAndGameClientActionMap() { - buttonAndGameClientActionMap = new LinkedHashMap<>(); - buttonAndGameClientActionMap.put(zoomInbtn, GameClientAction.ZOOM_IN); - buttonAndGameClientActionMap.put(zoomOutBtn, GameClientAction.ZOOM_OUT); - buttonAndGameClientActionMap.put(vmgBtn, GameClientAction.VMG); - buttonAndGameClientActionMap.put(sailInOutBtn, GameClientAction.SAILS_STATE); - buttonAndGameClientActionMap.put(tackGybeBtn, GameClientAction.TACK_GYBE); - buttonAndGameClientActionMap.put(upwindBtn, GameClientAction.UPWIND); - buttonAndGameClientActionMap.put(downwindBtn, GameClientAction.DOWNWIND); - } - - /** - * Initialise default keybinding to a button. - */ - private void initializeDefaultKeys() { - keys = new LinkedHashMap<>(); - keys.put(zoomInbtn, keyBind.get(GameClientAction.ZOOM_IN)); - keys.put(zoomOutBtn, keyBind.get(GameClientAction.ZOOM_OUT)); - keys.put(vmgBtn, keyBind.get(GameClientAction.VMG)); - keys.put(sailInOutBtn, keyBind.get(GameClientAction.SAILS_STATE)); - keys.put(tackGybeBtn, keyBind.get(GameClientAction.TACK_GYBE)); - keys.put(upwindBtn, keyBind.get(GameClientAction.UPWIND)); - keys.put(downwindBtn, keyBind.get(GameClientAction.DOWNWIND)); - } - - /** - * Change button text to match current keybinding. Adds focusedProperty and keyPressed listener - * to each buttons. - */ - private void initializeButtons() { - for (JFXButton jfxButton : buttons) { - if (keys.get(jfxButton) != null) { - jfxButton.setText(keys.get(jfxButton).getName()); - } else { - jfxButton.setText(""); - } - jfxButton.focusedProperty().addListener((observable, oldValue, newValue) -> { - jfxButton.setOnKeyPressed(event -> { - event.consume(); - doSomething(event, jfxButton); - }); - }); + private void bindButtonWithAction() { + buttonActionMap = new HashMap<>(); + for (int i = 0; i < 7; i++) { + buttonActionMap.put(buttons.get(i), KeyAction.getType(i + 1)); } } - /** - * HAOMING PLEASE CHANGE THIS DOCSTRING AND THE FUNCTION NAME!!! - * - * @param event BLAH - * @param button BLAH - */ - private void doSomething(KeyEvent event, JFXButton button) { - if (keys.containsValue(event.getCode())) { - keys.replace(button, null); - keyBind.replace(buttonAndGameClientActionMap.get(button), null); - button.setText(""); - viewManager - .showSnackbar(button.getId() + " can't be set to " + event.getCode().getName()); + private void showSnackBar(String message) { + ViewManager.getInstance().showSnackbar(message); + } + + 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;"); + } + + private void buttonPressed(Button button) { + button.setText("PRESS KEY..."); + } + + 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;"); + } + + private void keyPressed(KeyEvent event, Button button) { + KeyAction buttonAction = buttonActionMap.get(button); + if (gameKeyBind.bindKeyToAction(event.getCode(), buttonAction)) { + showSnackBar(button.getId() + " is set to " + event.getCode().getName()); + button.setText(gameKeyBind.getKeyCode(buttonAction).getName()); } else { - keys.replace(button, event.getCode()); - keyBind.replace(buttonAndGameClientActionMap.get(button), event.getCode()); - button.setText(event.getCode().getName()); - viewManager.showSnackbar(button.getId() + " is set to " + event.getCode().getName()); + showSnackBar(event.getCode().getName() + " is already in use"); } + event.consume(); } } diff --git a/src/main/resources/css/dialogs/KeyBindingDialog.css b/src/main/resources/css/dialogs/KeyBindingDialog.css index 6f85fd91..51c147f1 100644 --- a/src/main/resources/css/dialogs/KeyBindingDialog.css +++ b/src/main/resources/css/dialogs/KeyBindingDialog.css @@ -1,40 +1,32 @@ #keyBindingDialogHeader { - -fx-font-size: 30px; + -fx-font-size: 27px; -fx-text-fill: -fx-pp-dark-text-color; } JFXButton { -fx-background-color: -fx-pp-light-text-color; -fx-text-fill: -fx-pp-theme-color; - -fx-font-size: 15px; - -fx-effect: -fx-pp-dropshadow-light; + -fx-font-size: 13px; } Label { - -fx-font-size: 20px; + -fx-font-size: 15px; -fx-text-fill: -fx-pp-theme-color; -fx-effect: -fx-pp-dropshadow-light; } -JFXButton:hover { - -fx-font-size: 18px; - -fx-background-color: -fx-pp-light-theme-color; - -fx-text-fill: -fx-pp-light-text-color; -} - -JFXButton:focused { - -fx-font-size: 18px; - -fx-background-color: -fx-pp-theme-color; - -fx-text-fill: -fx-pp-light-text-color; -} - JFXToggleButton { -jfx-toggle-color: -fx-pp-theme-color; -fx-text-fill: -fx-pp-theme-color; } -#resetBtn, #confirmBtn { +#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; } \ No newline at end of file diff --git a/src/main/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index f22f17dc..9d7c503a 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -9,10 +9,9 @@ - @@ -21,16 +20,17 @@ - - - - - - - - - + + + + + + + + + - + - + maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="45.0" + prefWidth="150.0" text="RESET" GridPane.columnSpan="2" GridPane.halignment="CENTER" + GridPane.rowIndex="9" GridPane.valignment="CENTER"/> From 066557584f3cc7f0d5dd380ab4a3e3d00ec2d621 Mon Sep 17 00:00:00 2001 From: Haoming Yin Date: Sat, 23 Sep 2017 19:37:13 +1200 Subject: [PATCH 09/14] Implemented turning mode toggle - when the mode is toggled, a boat action package will be sent to notify server to change the boat's turning mode - turning mode toggle is now fully functional #story[1245] --- .../java/seng302/gameServer/GameState.java | 37 +++++++-- .../gameServer/messages/BoatAction.java | 4 +- src/main/java/seng302/model/GameKeyBind.java | 4 +- src/main/java/seng302/model/ServerYacht.java | 81 +++++++++++-------- .../java/seng302/visualiser/GameClient.java | 7 ++ .../visualiser/controllers/ViewManager.java | 13 +-- .../dialogs/KeyBindingDialogController.java | 60 ++++++++++++-- .../views/dialogs/KeyBindingDialog.fxml | 8 +- 8 files changed, 152 insertions(+), 62 deletions(-) diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index 8ff2556c..5e8992ad 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/model/GameKeyBind.java b/src/main/java/seng302/model/GameKeyBind.java index e400e6b5..1c765adc 100644 --- a/src/main/java/seng302/model/GameKeyBind.java +++ b/src/main/java/seng302/model/GameKeyBind.java @@ -10,7 +10,7 @@ public class GameKeyBind { private static GameKeyBind instance; private Map keyToActionMap; private Map actionToKeyMap; - private boolean continuouslyTurning; + private Boolean continuouslyTurning; private GameKeyBind() { @@ -71,7 +71,7 @@ public class GameKeyBind { continuouslyTurning = !continuouslyTurning; } - public boolean isContinuouslyTurning() { + public Boolean isContinuouslyTurning() { return continuouslyTurning; } diff --git a/src/main/java/seng302/model/ServerYacht.java b/src/main/java/seng302/model/ServerYacht.java index e7d936ca..7dce048c 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; @@ -8,10 +9,6 @@ import seng302.gameServer.messages.BoatStatus; import seng302.model.mark.Mark; import seng302.model.token.TokenType; import seng302.utilities.GeoUtility; - -import java.util.HashMap; -import java.util.Observable; -import java.util.Observer; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; /** @@ -57,6 +54,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) { @@ -81,6 +80,8 @@ public class ServerYacht { this.hasEnteredRoundingZone = false; this.hasPassedLine = false; this.hasPassedThroughGate = false; + + this.continuouslyTurning = false; } @@ -188,44 +189,52 @@ public class ServerYacht { public void turnUpwind() { disableAutoPilot(); Double normalizedHeading = normalizeHeading(); - if (normalizedHeading == 0) { - if (lastHeading < 180) { - adjustHeading(-TURN_STEP); - } else { - adjustHeading(TURN_STEP); - } - } else if (normalizedHeading == 180) { - if (lastHeading < 180) { - adjustHeading(TURN_STEP); - } else { - adjustHeading(-TURN_STEP); - } - } else if (normalizedHeading < 180) { - adjustHeading(-TURN_STEP); - } else { + if (continuouslyTurning) { adjustHeading(TURN_STEP); + } else { + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(-TURN_STEP); + } else { + adjustHeading(TURN_STEP); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(TURN_STEP); + } else { + adjustHeading(-TURN_STEP); + } + } else if (normalizedHeading < 180) { + adjustHeading(-TURN_STEP); + } else { + adjustHeading(TURN_STEP); + } } } public void turnDownwind() { disableAutoPilot(); Double normalizedHeading = normalizeHeading(); - if (normalizedHeading == 0) { - if (lastHeading < 180) { - adjustHeading(TURN_STEP); - } else { - adjustHeading(-TURN_STEP); - } - } else if (normalizedHeading == 180) { - if (lastHeading < 180) { - adjustHeading(-TURN_STEP); - } else { - adjustHeading(TURN_STEP); - } - } else if (normalizedHeading < 180) { - adjustHeading(TURN_STEP); - } else { + if (continuouslyTurning) { adjustHeading(-TURN_STEP); + } else { + if (normalizedHeading == 0) { + if (lastHeading < 180) { + adjustHeading(TURN_STEP); + } else { + adjustHeading(-TURN_STEP); + } + } else if (normalizedHeading == 180) { + if (lastHeading < 180) { + adjustHeading(-TURN_STEP); + } else { + adjustHeading(TURN_STEP); + } + } else if (normalizedHeading < 180) { + adjustHeading(TURN_STEP); + } else { + adjustHeading(-TURN_STEP); + } } } @@ -429,4 +438,8 @@ public class ServerYacht { public BoatMeshType getBoatType() { return boatType; } + + public void setContinuouslyTurning(Boolean continuouslyTurning) { + this.continuouslyTurning = continuouslyTurning; + } } diff --git a/src/main/java/seng302/visualiser/GameClient.java b/src/main/java/seng302/visualiser/GameClient.java index d6227d98..72da551e 100644 --- a/src/main/java/seng302/visualiser/GameClient.java +++ b/src/main/java/seng302/visualiser/GameClient.java @@ -460,4 +460,11 @@ public class GameClient { return allBoatsMap; } + public void sendToggleTurningModePacket() { + if (gameKeyBind.isContinuouslyTurning()) { + socketThread.sendBoatAction(BoatAction.CONTINUOUSLY_TURNING); + } else { + socketThread.sendBoatAction(BoatAction.DEFAULT_TURNING); + } + } } diff --git a/src/main/java/seng302/visualiser/controllers/ViewManager.java b/src/main/java/seng302/visualiser/controllers/ViewManager.java index 49f76953..603e2295 100644 --- a/src/main/java/seng302/visualiser/controllers/ViewManager.java +++ b/src/main/java/seng302/visualiser/controllers/ViewManager.java @@ -27,6 +27,7 @@ import seng302.gameServer.ServerAdvertiser; import seng302.utilities.BonjourInstallChecker; import seng302.utilities.Sounds; import seng302.visualiser.GameClient; +import seng302.visualiser.controllers.dialogs.KeyBindingDialogController; public class ViewManager { @@ -213,6 +214,9 @@ public class ViewManager { JFXDialog dialog = new JFXDialog((StackPane) node, dialogContent.load(), DialogTransition.CENTER); + KeyBindingDialogController keyBindingDialogController = dialogContent + .getController(); + keyBindingDialogController.setGameClient(this.gameClient); dialog.show(); Sounds.playButtonClick(); } @@ -338,15 +342,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"); diff --git a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java index 8621fd5b..7a372d4a 100644 --- a/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java +++ b/src/main/java/seng302/visualiser/controllers/dialogs/KeyBindingDialogController.java @@ -1,7 +1,6 @@ package seng302.visualiser.controllers.dialogs; import com.jfoenix.controls.JFXButton; -import com.jfoenix.controls.JFXDialogLayout; import com.jfoenix.controls.JFXToggleButton; import java.net.URL; import java.util.ArrayList; @@ -17,16 +16,13 @@ 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 JFXDialogLayout keyBindDialog; - @FXML - private Label keyBindingDialogHeader; - @FXML private JFXButton zoomInbtn; @FXML private JFXButton zoomOutBtn; @@ -43,7 +39,9 @@ public class KeyBindingDialogController implements Initializable { @FXML private JFXButton resetBtn; @FXML - private JFXButton confirmBtn; + private Label upwindLabel; + @FXML + private Label downwindLabel; @FXML private JFXToggleButton turningToggle; //---------FXML END---------// @@ -51,6 +49,7 @@ public class KeyBindingDialogController implements Initializable { 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) { @@ -68,6 +67,8 @@ public class KeyBindingDialogController implements Initializable { button.setOnKeyPressed(event -> keyPressed(event, button)); }); + turningToggle.setOnMouseClicked(event -> toggleTurningMode()); + resetBtn.setOnMouseClicked(event -> { gameKeyBind.setToDefault(); loadKeyBind(); @@ -81,8 +82,19 @@ public class KeyBindingDialogController implements Initializable { 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 < 7; i++) { @@ -90,10 +102,17 @@ public class KeyBindingDialogController implements Initializable { } } + /** + * Prompt success / failure message for reassigning key action + */ private void showSnackBar(String message) { ViewManager.getInstance().showSnackbar(message); } + /** + * 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;" @@ -101,10 +120,20 @@ public class KeyBindingDialogController implements Initializable { + "-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("" @@ -113,6 +142,12 @@ public class KeyBindingDialogController implements Initializable { + "-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) { KeyAction buttonAction = buttonActionMap.get(button); if (gameKeyBind.bindKeyToAction(event.getCode(), buttonAction)) { @@ -123,4 +158,17 @@ public class KeyBindingDialogController implements Initializable { } event.consume(); } + + /** + * 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/resources/views/dialogs/KeyBindingDialog.fxml b/src/main/resources/views/dialogs/KeyBindingDialog.fxml index 9d7c503a..44c2cfbf 100644 --- a/src/main/resources/views/dialogs/KeyBindingDialog.fxml +++ b/src/main/resources/views/dialogs/KeyBindingDialog.fxml @@ -59,13 +59,13 @@ -