diff --git a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java index d43f22eb..d19a4f5d 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/KeyBindingsController.java @@ -2,14 +2,20 @@ package visualiser.Controllers; import javafx.application.Platform; import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Parent; +import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ListView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.AnchorPane; +import javafx.stage.Modality; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; import visualiser.gameController.Keys.ControlKey; import visualiser.gameController.Keys.KeyFactory; - +import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -26,8 +32,9 @@ public class KeyBindingsController { private @FXML ListView lstKey; private @FXML ListView lstDescription; private @FXML AnchorPane anchor; - private Button currentButton = null; + private Button currentButton = null; // last button clicked private KeyFactory newKeyFactory; + private Boolean changed = false; // keybindings have been modified public void initialize(){ // create new key factory to modify, keeping the existing one safe @@ -96,14 +103,14 @@ public class KeyBindingsController { */ public KeyFactory copyExistingFactory(){ newKeyFactory = new KeyFactory(); - Map newKeyState = newKeyFactory.getKeyState(); Map oldKeyState = keyFactory.getKeyState(); - newKeyState = new HashMap<>(); // clear default keys + Map newKeyState = new HashMap<>(); // copy over commands and their keys for (Map.Entry entry : oldKeyState.entrySet()){ newKeyState.put(entry.getKey(), entry.getValue()); } + newKeyFactory.setKeyState(newKeyState); return newKeyFactory; } @@ -137,14 +144,20 @@ public class KeyBindingsController { currentButton.getId()); // remove current button selection currentButton = null; + changed = true; btnCancel.requestFocus(); } event.consume(); }); } + /** + * Cancel and exits the key bindings menu. Changes are not forced to be + * saved or fixed if invalid, and instead are defaulted back to the last + * successful saved state. + */ public void cancel(){ - System.out.println("cancel clicked"); + ((Stage)btnCancel.getScene().getWindow()).close(); } /** @@ -157,13 +170,76 @@ public class KeyBindingsController { newKeyFactory = new KeyFactory(); initializeTable(); populateTable(); + changed = true; } /** * Replace existing {@link KeyFactory} with the modified key bindings. */ public void save(){ - keyFactory = newKeyFactory; + if (isFactoryValid()) { + keyFactory = newKeyFactory; + newKeyFactory = new KeyFactory(); + changed = false; + loadNotification("Key bindings were successfully saved.", false); + } else { + loadNotification("One or more key bindings are missing. " + + "Failed to save.", true); + } + } + + /** + * Checks the {@link KeyFactory} being modified is valid and that no + * commands are missing a key binding. + * @return True if valid, false if invalid + */ + public Boolean isFactoryValid(){ + for (Map.Entry entry : newKeyFactory.getKeyState().entrySet + ()) { + if (entry.getKey().toString()==entry.getValue().toString()){ + return false; + } + } + return true; + } + + /** + * Method used to stop a user from exiting key bindings without saving + * their changes to the {@link KeyFactory}. + * @param we {@link WindowEvent} close request to be consumed if settings + * have not been successfully saved. + */ + public void onExit(WindowEvent we){ + // if modified KeyFactory hasn't been saved + if (keyFactory!=newKeyFactory && changed==true){ + loadNotification("Please cancel or save your changes before exiting" + + ".", true); + we.consume(); + } + } + + /** + * Loads a popup window giving confirmation/warning of user activity. + * @param message the message to be displayed to the user + * @param warning true if the message to be displayed is due to user error + */ + public void loadNotification(String message, Boolean warning){ + Parent root = null; + FXMLLoader loader = new FXMLLoader(getClass().getResource + ("/visualiser/scenes/notification.fxml")); + try { + root = loader.load(); + } catch (IOException e) { + e.printStackTrace(); + } + NotificationController controller = loader.getController(); + Stage stage = new Stage(); + stage.setScene(new Scene(root)); + stage.centerOnScreen(); + stage.initModality(Modality.APPLICATION_MODAL); + stage.show(); + // displays given message in the window + controller.setMessage(message, warning); } } diff --git a/racevisionGame/src/main/java/visualiser/Controllers/NotificationController.java b/racevisionGame/src/main/java/visualiser/Controllers/NotificationController.java new file mode 100644 index 00000000..d122ec80 --- /dev/null +++ b/racevisionGame/src/main/java/visualiser/Controllers/NotificationController.java @@ -0,0 +1,35 @@ +package visualiser.Controllers; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.paint.Color; +import javafx.scene.text.Text; +import javafx.stage.Stage; + +/** + * Controller for a popup notification regarding user activity. + */ +public class NotificationController { + private @FXML Label lblDescription; + private @FXML Text txtMessage; + + /** + * Closes the popup window once clicked. + */ + public void ok(){ + ((Stage)lblDescription.getScene().getWindow()).close(); + } + + /** + * Displays the appropriate popup notification. + * @param message message for the user + * @param warning if true warning text shown, if false success text shown + */ + public void setMessage(String message, Boolean warning){ + lblDescription.setText(message); + if (!warning){ + txtMessage.setText("Success!"); + txtMessage.setFill(Color.GREEN); + } + } +} diff --git a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java index 94fff748..21e3dcc7 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/TitleController.java @@ -1,5 +1,6 @@ package visualiser.Controllers; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; @@ -9,6 +10,7 @@ import javafx.scene.control.RadioButton; import javafx.scene.layout.AnchorPane; import javafx.stage.Modality; import javafx.stage.Stage; +import javafx.stage.WindowEvent; import visualiser.app.App; import java.io.IOException; @@ -88,6 +90,22 @@ public class TitleController extends Controller { * Called when control button is pressed. New pop up window displaying controls */ public void controlBtnPressed(){ + +// Parent root2 = loader2.load(); +// KeyBindingsController controller = loader2.getController(); +// Stage stage2 = new Stage(); +// stage2.setScene(new Scene(root2)); +// stage2.centerOnScreen(); +// stage2.initModality(Modality.APPLICATION_MODAL); +// stage2.show(); +// stage2.setOnCloseRequest(new EventHandler() { +// public void handle(WindowEvent we) { +// if (we.getEventType() == WindowEvent.WINDOW_CLOSE_REQUEST) { +// controller.onExit(we); +// } +// } +// }); + FXMLLoader loader = new FXMLLoader(); loader.setLocation(getClass().getResource("/visualiser/scenes/keyBindings.fxml")); Parent layout; @@ -100,6 +118,14 @@ public class TitleController extends Controller { popupStage.initModality(Modality.WINDOW_MODAL); popupStage.setScene(scene); popupStage.showAndWait(); + KeyBindingsController controller = loader.getController(); + popupStage.setOnCloseRequest(new EventHandler() { + public void handle(WindowEvent we) { + if (we.getEventType() == WindowEvent.WINDOW_CLOSE_REQUEST) { + controller.onExit(we); + } + } + }); } catch (Exception e){ e.printStackTrace(); } diff --git a/racevisionGame/src/main/java/visualiser/gameController/Keys/KeyFactory.java b/racevisionGame/src/main/java/visualiser/gameController/Keys/KeyFactory.java index d896f6c6..ecf0b1af 100644 --- a/racevisionGame/src/main/java/visualiser/gameController/Keys/KeyFactory.java +++ b/racevisionGame/src/main/java/visualiser/gameController/Keys/KeyFactory.java @@ -39,6 +39,10 @@ public class KeyFactory { return keyState; } + public void setKeyState(Map keyState) { + this.keyState = keyState; + } + /** * Update the key bound to a particular command in the keystate. * @param newKey the new key value for the command diff --git a/racevisionGame/src/main/resources/css/keyBindings.css b/racevisionGame/src/main/resources/css/keyBindings.css index a1dc8242..a572116e 100644 --- a/racevisionGame/src/main/resources/css/keyBindings.css +++ b/racevisionGame/src/main/resources/css/keyBindings.css @@ -23,6 +23,7 @@ -fx-text-fill: #242d35; -fx-font-size: 12px; -fx-font-family: "Courier New"; + -fx-border-color: #a9c8ff; } .button:focused { @@ -32,4 +33,13 @@ #anchor { -fx-background-color: #fdfac3; +} +#menu{ + -fx-background-color: linear-gradient(#acdeff 50%, #a9c8ff 100%); + -fx-background-radius: 4px; + -fx-border-radius: 4px; + -fx-text-fill: #242d35; + -fx-font-size: 12px; + -fx-font-family: "Verdana"; + -fx-border-color: #a9c8ff; } \ No newline at end of file diff --git a/racevisionGame/src/main/resources/visualiser/scenes/keyBindings.fxml b/racevisionGame/src/main/resources/visualiser/scenes/keyBindings.fxml index 6ce15890..40217567 100644 --- a/racevisionGame/src/main/resources/visualiser/scenes/keyBindings.fxml +++ b/racevisionGame/src/main/resources/visualiser/scenes/keyBindings.fxml @@ -13,11 +13,12 @@ -