From 4011295b8b97c658f9e8c3886e08c804eb3775cb Mon Sep 17 00:00:00 2001 From: Haoming Yin Date: Sat, 23 Sep 2017 17:52:48 +1200 Subject: [PATCH] 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"/>